chore: initialize from frontend template 4dc033c

This commit is contained in:
DongHyeonka
2026-08-13 18:23:26 +09:00
commit 40107eec84
897 changed files with 234824 additions and 0 deletions
@@ -0,0 +1,331 @@
import { expect, test } from "../support/browser/strict-browser-test.ts";
test("selects, inspects, streams, and previews a real browser File", async ({
page,
}) => {
await page.goto("/");
await page.evaluate(async () => {
const modulePath =
"/src/adapters/browser-files/index.ts";
const {
createBrowserFileRuntime,
browserFilePolicyReference,
} = await import(/* @vite-ignore */ modulePath);
const input = document.createElement("input");
input.id = "capability-file-input";
input.type = "file";
const label = document.createElement("label");
label.htmlFor = input.id;
label.textContent = "PNG file";
const button = document.createElement("button");
button.type = "button";
button.textContent = "Choose test file";
document.body.append(label, input, button);
const filePolicy = browserFilePolicyReference(
"avatar",
"select-inspect-preview-png",
);
const runtime = createBrowserFileRuntime({
input,
policies: [
{
reference: filePolicy,
selection: {
policyId: "avatar-v1",
purpose: "avatar",
classification: "PERSONAL",
multiple: false,
maxCount: 1,
maxFileBytes: 1024,
maxTotalBytes: 1024,
allowEmpty: false,
accept: [
{
mediaType: "image/png",
extensions: [".png"],
},
],
},
inspection: {
policyId: "png-signature-v1",
maxInspectionBytes: 16,
acceptedSignatures: [
{
mediaType: "image/png",
extensions: [".png"],
patterns: [
{
offset: 0,
bytes: [137, 80, 78, 71, 13, 10, 26, 10],
},
],
},
],
},
preview: {
allowedMediaTypes: ["image/png"],
maxPreviewBytes: 1024,
},
},
],
limits: {
hardMaxPreviewBytes: 1024,
hardMaxObjectUrlBytes: 1024,
hardMaxTransferBytes: 4096,
},
download: {
host: Object.freeze({ handoff() {} }),
browserManagedCapabilities: {
resolve() {
return {
ok: false as const,
error: {
code: "POLICY_REJECTED" as const,
operation: "DOWNLOAD" as const,
retryable: false,
recovery: "NONE" as const,
},
};
},
},
},
});
const state = globalThis as typeof globalThis & {
__browserFileResult?: Promise<unknown>;
};
button.addEventListener("click", () => {
state.__browserFileResult = (async () => {
const selected = await runtime.baselinePicker.select({
policy: filePolicy,
});
if (
!selected.ok ||
selected.value.kind !== "SELECTED" ||
selected.value.files.length !== 1
) {
runtime.dispose();
return selected;
}
const candidate = selected.value.files[0]!;
const signal = new AbortController().signal;
const inspected = await runtime.content.inspect({
ref: candidate.ref,
policy: filePolicy,
signal,
});
const range = await runtime.content.readRange({
ref: candidate.ref,
offset: 1,
length: 4,
signal,
});
const opened = await runtime.content.openSource({
ref: candidate.ref,
signal,
});
const streamed: number[] = [];
if (opened.ok) {
for await (const chunk of opened.value.stream(signal)) {
if (chunk.ok) streamed.push(...chunk.value);
}
}
const verificationReceipt = inspected.ok
? inspected.value.verificationReceipt
: null;
if (!verificationReceipt) {
runtime.dispose();
return inspected;
}
const preview = await runtime.previews.create({
ref: candidate.ref,
verificationReceipt,
policy: filePolicy,
maxPreviewBytes: 1024,
signal,
});
let previewBytes: number[] = [];
let previewProtocol: string | null = null;
if (preview.ok) {
previewProtocol = new URL(preview.value.url).protocol;
previewBytes = Array.from(
new Uint8Array(await (await fetch(preview.value.url)).arrayBuffer()),
);
preview.value.release();
}
runtime.baselinePicker.release(candidate.ref);
runtime.dispose();
return {
selected,
inspected,
range: range.ok ? Array.from(range.value) : range,
streamed,
preview: preview.ok ? { ok: true } : preview,
previewBytes,
previewProtocol,
};
})();
});
});
const chooserPromise = page.waitForEvent("filechooser");
await page.getByRole("button", { name: "Choose test file" }).click();
const chooser = await chooserPromise;
const bytes = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10, 1, 2, 3, 4]);
await chooser.setFiles({
name: "sample.png",
mimeType: "image/png",
buffer: bytes,
});
const result = await page.evaluate(async () => {
const state = globalThis as typeof globalThis & {
__browserFileResult?: Promise<unknown>;
};
return await state.__browserFileResult;
});
expect(result).toMatchObject({
selected: {
ok: true,
value: {
kind: "SELECTED",
files: [{ sizeBytes: bytes.byteLength, source: "NATIVE_INPUT" }],
},
},
inspected: {
ok: true,
value: {
byteLength: bytes.byteLength,
detectedMediaType: "image/png",
signature: "MATCHED",
},
},
range: [80, 78, 71, 13],
streamed: Array.from(bytes),
preview: { ok: true },
previewBytes: Array.from(bytes),
previewProtocol: "blob:",
});
});
test("hands a bounded generated Blob to the real browser download path", async ({
page,
}) => {
await page.goto("/");
await page.evaluate(async () => {
const modulePath = "/src/adapters/browser-files/index.ts";
const {
createBrowserFileRuntime,
createAnchorDownloadHost,
browserFilePolicyReference,
} = await import(/* @vite-ignore */ modulePath);
const input = document.createElement("input");
input.type = "file";
input.id = "unused-download-input";
const label = document.createElement("label");
label.htmlFor = input.id;
label.textContent = "Unused file control";
const button = document.createElement("button");
button.type = "button";
button.textContent = "Download generated file";
document.body.append(label, input, button);
const downloadPolicy = browserFilePolicyReference(
"generated-export",
"bounded-object-url-bin",
);
const runtime = createBrowserFileRuntime({
input,
policies: [
{
reference: downloadPolicy,
download: {
strategy: "BOUNDED_OBJECT_URL",
mediaType: "application/octet-stream",
safeExtension: ".bin",
maxTransferBytes: 1024,
maxBufferedBytes: 1024,
integrity: "OPTIONAL",
},
},
],
limits: {
hardMaxPreviewBytes: 1024,
hardMaxObjectUrlBytes: 1024,
hardMaxTransferBytes: 4096,
},
download: {
host: createAnchorDownloadHost(document),
browserManagedCapabilities: {
resolve() {
return {
ok: false as const,
error: {
code: "POLICY_REJECTED" as const,
operation: "DOWNLOAD" as const,
retryable: false,
recovery: "NONE" as const,
},
};
},
},
},
});
const state = globalThis as typeof globalThis & {
__browserDownloadResult?: Promise<unknown>;
};
button.addEventListener("click", () => {
state.__browserDownloadResult = runtime.downloads
.deliver({
policy: downloadPolicy,
source: {
kind: "GENERATED",
bytes: {
byteLength: 5,
async *stream() {
yield {
ok: true as const,
value: new Uint8Array([1, 2]),
};
yield {
ok: true as const,
value: new Uint8Array([3, 4, 5]),
};
},
},
},
suggestedFileName: "report",
maxTransferBytes: 1024,
maxBufferedBytes: 1024,
signal: new AbortController().signal,
onProgress() {},
})
.finally(() => runtime.dispose());
});
});
const downloadPromise = page.waitForEvent("download");
await page
.getByRole("button", { name: "Download generated file" })
.click();
const download = await downloadPromise;
const stream = await download.createReadStream();
const chunks: Buffer[] = [];
for await (const chunk of stream) {
chunks.push(Buffer.from(chunk));
}
const result = await page.evaluate(async () => {
const state = globalThis as typeof globalThis & {
__browserDownloadResult?: Promise<unknown>;
};
return await state.__browserDownloadResult;
});
expect(download.suggestedFilename()).toBe("report.bin");
expect(Buffer.concat(chunks)).toEqual(Buffer.from([1, 2, 3, 4, 5]));
expect(result).toMatchObject({
ok: true,
value: {
kind: "BROWSER_HANDOFF",
},
});
});
@@ -0,0 +1,290 @@
import {
expect,
test,
type Page,
} from "../support/browser/strict-browser-test.ts";
const TOPIC = "sample-topic-alpha";
const TOPIC_VERSION = 1;
const STATE_KEY = "__crossContextInvalidationCapability";
const STORAGE_PULSE_KEY =
"ca-frontend:cache-invalidation:v1:pulse";
type BrowserTransportMode = "BROADCAST" | "STORAGE";
type BrowserDeliverySnapshot = Readonly<{
ordering: string;
sequence: number;
topic: string;
transport: string;
}>;
type BrowserRuntimeSnapshot = Readonly<{
status: string;
deliveries: readonly BrowserDeliverySnapshot[];
pulseRetained: boolean;
}>;
async function installRuntime(
page: Page,
mode: BrowserTransportMode,
cacheEpoch: string,
): Promise<string> {
return await page.evaluate(
async ({
currentCacheEpoch,
currentMode,
stateKey,
topic,
topicVersion,
}) => {
const modulePath =
"/src/adapters/cross-context-invalidation/index.ts";
const { createBrowserCrossContextInvalidationFromHost } =
(await import(
/* @vite-ignore */ modulePath
)) as typeof import("../../src/adapters/cross-context-invalidation/index.ts");
const host: Record<string, unknown> =
currentMode === "BROADCAST"
? (globalThis as unknown as Record<string, unknown>)
: {
crypto: globalThis.crypto,
localStorage: globalThis.localStorage,
addEventListener:
globalThis.addEventListener.bind(globalThis),
removeEventListener:
globalThis.removeEventListener.bind(globalThis),
};
const runtime = createBrowserCrossContextInvalidationFromHost({
host,
cacheEpoch: currentCacheEpoch,
topics: [{ topic, topicVersion }],
});
if (!runtime) {
throw new Error(
"Cross-context invalidation runtime is unavailable.",
);
}
const deliveries: BrowserDeliverySnapshot[] = [];
runtime.subscribe((delivery) => {
deliveries.push({
ordering: delivery.ordering,
sequence: delivery.event.sequence,
topic: delivery.event.topic,
transport: delivery.transport,
});
});
Reflect.set(globalThis, stateKey, { deliveries, runtime });
return runtime.getStatus();
},
{
currentCacheEpoch: cacheEpoch,
currentMode: mode,
stateKey: STATE_KEY,
topic: TOPIC,
topicVersion: TOPIC_VERSION,
},
);
}
async function publish(page: Page) {
return await page.evaluate(
({ stateKey, topic, topicVersion }) => {
const state = Reflect.get(globalThis, stateKey) as
| {
runtime: {
publish(input: {
topic: string;
topicVersion: number;
}): unknown;
};
}
| undefined;
if (!state) throw new Error("Capability runtime is not installed.");
return state.runtime.publish({ topic, topicVersion });
},
{
stateKey: STATE_KEY,
topic: TOPIC,
topicVersion: TOPIC_VERSION,
},
);
}
async function snapshot(page: Page): Promise<BrowserRuntimeSnapshot> {
return await page.evaluate(
({ pulseKey, stateKey }) => {
const state = Reflect.get(globalThis, stateKey) as
| {
deliveries: BrowserDeliverySnapshot[];
runtime: { getStatus(): string };
}
| undefined;
if (!state) throw new Error("Capability runtime is not installed.");
return {
status: state.runtime.getStatus(),
deliveries: structuredClone(state.deliveries),
pulseRetained: localStorage.getItem(pulseKey) !== null,
};
},
{ pulseKey: STORAGE_PULSE_KEY, stateKey: STATE_KEY },
);
}
async function closeRuntime(page: Page): Promise<string | null> {
return await page.evaluate((stateKey) => {
const state = Reflect.get(globalThis, stateKey) as
| { runtime: { close(): void; getStatus(): string } }
| undefined;
if (!state) return null;
state.runtime.close();
return state.runtime.getStatus();
}, STATE_KEY);
}
async function disposeRuntime(page: Page): Promise<void> {
await page.evaluate(
({ pulseKey, stateKey }) => {
const state = Reflect.get(globalThis, stateKey) as
| { runtime: { close(): void } }
| undefined;
state?.runtime.close();
localStorage.removeItem(pulseKey);
Reflect.deleteProperty(globalThis, stateKey);
},
{ pulseKey: STORAGE_PULSE_KEY, stateKey: STATE_KEY },
);
}
test("delivers invalidation through native BroadcastChannel and cleans the receiver", async ({
page,
}) => {
const secondPage = await page.context().newPage();
const cacheEpoch = `browser.primary.${Date.now()}`;
try {
await Promise.all([page.goto("/"), secondPage.goto("/")]);
await page.evaluate(
(pulseKey) => localStorage.removeItem(pulseKey),
STORAGE_PULSE_KEY,
);
const statuses = await Promise.all([
installRuntime(page, "BROADCAST", cacheEpoch),
installRuntime(secondPage, "BROADCAST", cacheEpoch),
]);
expect(statuses).toEqual([
"ACTIVE_BROADCAST",
"ACTIVE_BROADCAST",
]);
expect(await publish(page)).toEqual({
ok: true,
transport: "BROADCAST",
});
await expect
.poll(async () => (await snapshot(secondPage)).deliveries)
.toEqual([
{
ordering: "NEXT",
sequence: 1,
topic: TOPIC,
transport: "BROADCAST",
},
]);
expect((await snapshot(page)).deliveries).toEqual([]);
expect(await closeRuntime(secondPage)).toBe("CLOSED");
expect(await publish(page)).toEqual({
ok: true,
transport: "BROADCAST",
});
await page.waitForTimeout(100);
expect(await snapshot(secondPage)).toEqual({
status: "CLOSED",
deliveries: [
{
ordering: "NEXT",
sequence: 1,
topic: TOPIC,
transport: "BROADCAST",
},
],
pulseRetained: false,
});
} finally {
await Promise.allSettled([
disposeRuntime(page),
disposeRuntime(secondPage),
]);
await secondPage.close();
}
});
test("falls back to native localStorage events and removes the pulse during cleanup", async ({
page,
}) => {
const secondPage = await page.context().newPage();
const cacheEpoch = `browser.fallback.${Date.now()}`;
try {
await Promise.all([page.goto("/"), secondPage.goto("/")]);
await page.evaluate(
(pulseKey) => localStorage.removeItem(pulseKey),
STORAGE_PULSE_KEY,
);
const statuses = await Promise.all([
installRuntime(page, "STORAGE", cacheEpoch),
installRuntime(secondPage, "STORAGE", cacheEpoch),
]);
expect(statuses).toEqual([
"ACTIVE_STORAGE_FALLBACK",
"ACTIVE_STORAGE_FALLBACK",
]);
expect(await publish(page)).toEqual({
ok: true,
transport: "STORAGE",
});
await expect
.poll(async () => (await snapshot(secondPage)).deliveries)
.toEqual([
{
ordering: "NEXT",
sequence: 1,
topic: TOPIC,
transport: "STORAGE",
},
]);
expect(await snapshot(page)).toMatchObject({
deliveries: [],
pulseRetained: false,
});
expect(await snapshot(secondPage)).toMatchObject({
pulseRetained: false,
});
expect(await closeRuntime(secondPage)).toBe("CLOSED");
expect(await publish(page)).toEqual({
ok: true,
transport: "STORAGE",
});
await page.waitForTimeout(100);
expect(await snapshot(secondPage)).toEqual({
status: "CLOSED",
deliveries: [
{
ordering: "NEXT",
sequence: 1,
topic: TOPIC,
transport: "STORAGE",
},
],
pulseRetained: false,
});
} finally {
await Promise.allSettled([
disposeRuntime(page),
disposeRuntime(secondPage),
]);
await secondPage.close();
}
});
@@ -0,0 +1,182 @@
import { expect, test } from "../support/browser/strict-browser-test.ts";
const PNG_1X1 = Buffer.from(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
"base64",
);
test("fetches and decodes an allowlisted public immutable CDN image", async ({
page,
}) => {
const cdnRequests: string[] = [];
await page.route("https://images.example.test/**", async (route) => {
cdnRequests.push(route.request().url());
await route.fulfill({
status: 200,
body: PNG_1X1,
headers: {
"access-control-allow-origin": "*",
"cache-control":
"public, max-age=31536000, s-maxage=31536000, immutable",
"content-length": String(PNG_1X1.byteLength),
"content-type": "image/png",
vary: "Accept-Encoding",
},
});
});
await page.goto("/");
const result = await page.evaluate(async () => {
const modulePath =
"/src/adapters/browser-transfer/image-cdn/index.ts";
const {
ImageCdnPolicyRegistry,
createBrowserImageProbe,
createImageCdnRuntime,
imageCdnPresetReference,
} = (await import(
/* @vite-ignore */ modulePath
)) as typeof import("../../src/adapters/browser-transfer/image-cdn/index.ts");
const preset = imageCdnPresetReference(
"browser-probe",
"verify-public-cdn-image",
);
const policies = new ImageCdnPolicyRegistry({
applicationOrigin: "https://app.example.test",
origins: [
{
originKey: "browser-images",
origin: "https://images.example.test",
assetPathPrefix: "/v1/assets/",
minimumPublicMaxAgeSeconds: 31_536_000,
},
],
presets: [
{
reference: preset,
bindingId: "browser-probe-v1",
width: 1,
height: 1,
fit: "cover",
dprs: [1],
responsiveWidths: [1],
quality: 90,
formats: ["png"],
sizes: "1px",
loading: "eager",
decoding: "async",
fetchPriority: "high",
referrerPolicy: "no-referrer",
probeMode: "PRIMARY_REQUIRED",
allowUpscale: false,
maxTransformedPixels: 1,
maxDecodedBytes: 4,
maxEncodedBytes: 128,
},
],
hardLimits: {
maxIntrinsicWidth: 1,
maxIntrinsicHeight: 1,
maxSourcePixels: 1,
maxCssDimension: 1,
maxDpr: 1,
maxQuality: 90,
maxCandidateCount: 1,
maxTransformedPixels: 1,
maxDecodedBytes: 4,
maxEncodedBytes: 128,
maxUrlLength: 2_048,
maxCapabilityLifetimeMs: 60_000,
maxClockSkewMs: 1_000,
minCapabilityRemainingMs: 1_000,
maxPresetBindingsPerCapability: 1,
maxConcurrentCapabilityVerifications: 1,
allowedSourceMediaTypes: ["image/png"],
formatQualityCeilings: { png: 90 },
},
capability: {
issuer: "browser-image-bff",
acceptedKeyIds: ["browser-image-key-v1"],
},
});
const runtime = createImageCdnRuntime({
policies,
probe: createBrowserImageProbe(),
});
const accepted = runtime.assets.acceptPublicImmutable({
kind: "ALLOWLISTED_PUBLIC",
originKey: "browser-images",
assetId: "asset_1x1",
revision: "revision_1",
mediaType: "image/png",
contentKind: "RASTER_STATIC",
intrinsicWidth: 1,
intrinsicHeight: 1,
});
if (!accepted.ok) {
runtime.close();
return {
accepted,
resolved: null,
};
}
const resolved = await runtime.presentation.resolve({
asset: accepted.value,
preset,
signal: new AbortController().signal,
});
runtime.close();
return {
accepted: { ok: true as const },
resolved,
};
});
expect(result.accepted).toEqual({ ok: true });
expect(result.resolved).toMatchObject({
ok: true,
value: {
width: 1,
height: 1,
fallbackMediaType: "image/png",
srcSet: expect.stringMatching(/ 1w$/u),
sources: [],
loading: "eager",
decoding: "async",
fetchPriority: "high",
referrerPolicy: "no-referrer",
crossOrigin: "anonymous",
delivery: {
class: "PUBLIC_IMMUTABLE",
assetVersion: "revision_1",
browserCache: "PUBLIC_IMMUTABLE",
sharedCache: "PUBLIC_IMMUTABLE",
purge: "REVISION_ROLLOVER",
expiresAtEpochMs: null,
},
decodeBudget: {
maximumCandidatePixels: 1,
maximumDecodedBytes: 4,
maximumEncodedBytes: 128,
},
},
});
if (!result.resolved?.ok) return;
const imageUrl = new URL(result.resolved.value.src);
expect(imageUrl.origin).toBe("https://images.example.test");
expect(imageUrl.pathname).toBe(
"/v1/assets/asset_1x1/revision_1",
);
expect(Object.fromEntries(imageUrl.searchParams)).toEqual({
dpr: "1",
fit: "cover",
format: "png",
height: "1",
preset: "browser-probe-v1",
quality: "90",
width: "1",
});
expect(cdnRequests).toEqual([result.resolved.value.src]);
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,221 @@
import { expect, test } from "../support/browser/strict-browser-test.ts";
test("runs put, open, remove and reconcile through a native DedicatedWorker, OPFS and IndexedDB", async ({
page,
}) => {
await page.goto("/");
const result = await page.evaluate(async () => {
const runtimeModulePath =
"/src/adapters/storage/opfs/browser-opfs-runtime.ts";
const policyModulePath =
"/src/adapters/storage/opfs/opfs-policy.ts";
const journalModulePath =
"/src/adapters/storage/opfs/indexeddb-opfs-journal.ts";
const {
createBrowserOpfsRuntime,
inspectBrowserOpfsSupport,
} = (await import(
/* @vite-ignore */ runtimeModulePath
)) as typeof import("../../src/adapters/storage/opfs/browser-opfs-runtime.ts");
const {
DEFAULT_OPFS_RUNTIME_POLICY,
resolveOpfsRuntimePolicy,
} = (await import(
/* @vite-ignore */ policyModulePath
)) as typeof import("../../src/adapters/storage/opfs/opfs-policy.ts");
const { opfsJournalDatabaseName } = (await import(
/* @vite-ignore */ journalModulePath
)) as typeof import("../../src/adapters/storage/opfs/indexeddb-opfs-journal.ts");
const policy = resolveOpfsRuntimePolicy();
const support = inspectBrowserOpfsSupport(policy);
if (!support.ok) {
return {
nativeSupport: false as const,
capabilities: support,
};
}
const suffix = crypto.randomUUID().replaceAll("-", "");
const scope = {
namespace: "durable-objects",
authorityToken: `authority_${suffix}`,
namespaceToken: `namespace_${suffix}`,
partitionToken: `partition_${suffix}`,
} as const;
const storagePolicy = {
owner: "browser-capability",
namespace: scope.namespace,
classification: "PERSONAL",
authority: "LOCAL_FIRST",
accountScope: "OPAQUE_PARTITION",
retention: { kind: "EXPLICIT_DELETE" },
softBudgetBytes: 1024 * 1024,
hardBudgetBytes: 2 * 1024 * 1024,
evictionPriority: "USER_AUTHORED",
logoutAction: "EXPORT_THEN_PURGE",
accountDeletionAction: "PURGE_PARTITION",
pressureAction: "RETAIN",
unavailableFallback: "EXPORT_REQUIRED",
} as const;
const runtime = createBrowserOpfsRuntime({
workerUrl: new URL(
"/tests/browser-capabilities/opfs-test.worker.ts",
location.href,
),
workerName: `opfs-capability-${suffix}`,
scope,
storagePolicy,
policy,
});
const bytes = new Uint8Array([3, 1, 4, 1, 5, 9]);
let capabilities: unknown;
let put: unknown;
let opened:
| Awaited<ReturnType<typeof runtime.objects.open>>
| undefined;
let readBytes: number[] = [];
let removed: unknown;
let afterRemove: unknown;
let reconciled: unknown;
try {
capabilities = await runtime.objects.capabilities();
put = await runtime.objects.put({
objectId: "object_browser_12345678",
expectedGeneration: null,
mediaType: "application/octet-stream",
source: {
byteLength: bytes.byteLength,
async *stream(signal: AbortSignal) {
if (signal.aborted) {
yield {
ok: false as const,
error: {
code: "ABORTED" as const,
operation: "OBJECT_WRITE" as const,
retryable: false,
recovery: "NONE" as const,
},
};
return;
}
yield { ok: true as const, value: Uint8Array.from(bytes) };
},
},
});
opened = await runtime.objects.open({
objectId: "object_browser_12345678",
});
if (
opened &&
typeof opened === "object" &&
"ok" in opened &&
opened.ok
) {
for await (const chunk of opened.value.source.stream(
new AbortController().signal,
)) {
if (!chunk.ok) throw new Error(chunk.error.code);
readBytes.push(...chunk.value);
}
}
removed = await runtime.objects.remove({
objectId: "object_browser_12345678",
expectedGeneration: 1,
});
afterRemove = await runtime.objects.open({
objectId: "object_browser_12345678",
});
reconciled = await runtime.maintenance.reconcile({
budgetMs: 5_000,
maxTransactions: 100,
});
} finally {
runtime.close();
}
const deletion = await new Promise<string>((resolve) => {
const request = indexedDB.deleteDatabase(
opfsJournalDatabaseName(scope.authorityToken),
);
request.onsuccess = () => resolve("DELETED");
request.onerror = () =>
resolve(request.error?.name ?? "UNKNOWN_ERROR");
request.onblocked = () => resolve("BLOCKED");
});
let opfsCleanup = "ABSENT";
try {
const originRoot = await navigator.storage.getDirectory();
const runtimeRoot = await originRoot.getDirectoryHandle(
DEFAULT_OPFS_RUNTIME_POLICY.rootDirectoryName,
);
const authorities = await runtimeRoot.getDirectoryHandle(
"authorities",
);
await authorities.removeEntry(scope.authorityToken, {
recursive: true,
});
opfsCleanup = "DELETED";
} catch (error) {
if (!(error instanceof DOMException) || error.name !== "NotFoundError") {
throw error;
}
}
return {
nativeSupport: true as const,
capabilities,
put,
opened:
opened &&
typeof opened === "object" &&
"ok" in opened &&
opened.ok
? {
ok: true,
generation: opened.value.descriptor.generation,
}
: opened,
readBytes,
removed,
afterRemove,
reconciled,
deletion,
opfsCleanup,
};
});
if (!result.nativeSupport) {
expect(result.capabilities).toMatchObject({
ok: false,
error: { code: "UNSUPPORTED" },
});
return;
}
expect(result.capabilities).toMatchObject({
ok: true,
value: {
available: true,
dedicatedWorkerRequired: true,
crossContextMutationLockAvailable: true,
},
});
expect(result.put).toMatchObject({
ok: true,
value: { generation: 1, byteLength: 6 },
});
expect(result.opened).toEqual({ ok: true, generation: 1 });
expect(result.readBytes).toEqual([3, 1, 4, 1, 5, 9]);
expect(result.removed).toEqual({ ok: true });
expect(result.afterRemove).toMatchObject({
ok: false,
error: { code: "NOT_FOUND" },
});
expect(result.reconciled).toMatchObject({
ok: true,
value: {
inspectedTransactions: 0,
orphanGcStatus: "COMPLETED",
},
});
expect(result.deletion).toBe("DELETED");
expect(["DELETED", "ABSENT"]).toContain(result.opfsCleanup);
});
@@ -0,0 +1,13 @@
import {
startBrowserOpfsDedicatedWorker,
type OpfsWorkerMessageHost,
} from "../../src/adapters/storage/opfs/opfs-worker-runtime.ts";
void startBrowserOpfsDedicatedWorker(
self as unknown as OpfsWorkerMessageHost,
{
storageManager: navigator.storage,
lockManager: navigator.locks,
crypto,
},
);
@@ -0,0 +1,366 @@
import { createHash } from "node:crypto";
import { expect, test } from "../support/browser/strict-browser-test.ts";
const RESOURCE_ID = "browser-artifact-1";
const OBJECT_ORIGIN = "https://objects.example.test";
const OBJECT_PATH = "/files/browser-artifact-1";
const OBJECT_HREF =
`${OBJECT_ORIGIN}${OBJECT_PATH}?sig=opaque-browser-signature`;
const DOWNLOAD_BYTES = Buffer.from([
0x10, 0x20, 0x30, 0x40, 0x50,
0x60, 0x70, 0x80, 0x90, 0xa0,
]);
const DOWNLOAD_SHA256 = createHash("sha256")
.update(DOWNLOAD_BYTES)
.digest("hex");
test("issues an opaque capability and streams a verified object into the writable save path", async ({
page,
}) => {
const bffRequests: unknown[] = [];
const objectRequests: Readonly<{
url: string;
method: string;
accept: string | undefined;
cookie: string | undefined;
}>[] = [];
await page.route("**/api/download-capability", async (route) => {
bffRequests.push(route.request().postDataJSON());
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
capabilityReceipt: "browser-download-capability-1",
method: "GET",
binding: {
kind: "DOWNLOAD",
resourceId: RESOURCE_ID,
},
href: OBJECT_HREF,
origin: OBJECT_ORIGIN,
path: OBJECT_PATH,
allowedQueryParameters: ["sig"],
requestHeaders: [
{
name: "accept",
value: "application/octet-stream",
},
],
requiredResponseHeaders: [
{
name: "x-policy-version",
value: "v1",
},
],
digestRequestHeader: null,
digestResponseHeader: "x-content-sha256",
receiptResponseHeader: null,
expectedStatus: 200,
expectedResponseByteLength: null,
mediaType: "application/octet-stream",
byteLength: DOWNLOAD_BYTES.byteLength,
maxBytes: 64,
expectedSha256: DOWNLOAD_SHA256,
expiresAtEpochMs: Date.now() + 5 * 60_000,
singleUse: true,
}),
});
});
await page.route(`${OBJECT_ORIGIN}/**`, async (route) => {
const headers = route.request().headers();
objectRequests.push({
url: route.request().url(),
method: route.request().method(),
accept: headers.accept,
cookie: headers.cookie,
});
await route.fulfill({
status: 200,
body: DOWNLOAD_BYTES,
headers: {
"access-control-allow-origin": "*",
"access-control-expose-headers":
"content-length, x-content-sha256, x-policy-version",
"content-length": String(DOWNLOAD_BYTES.byteLength),
"content-type": "application/octet-stream",
"x-content-sha256": DOWNLOAD_SHA256,
"x-policy-version": "v1",
},
});
});
await page.goto("/");
const result = await page.evaluate(
async ({ resourceId }) => {
const vaultModulePath =
"/src/adapters/browser-transfer/presigned/presigned-capability-vault.ts";
const providerModulePath =
"/src/adapters/browser-transfer/presigned/presigned-capability-http-provider.ts";
const executorModulePath =
"/src/adapters/browser-transfer/presigned/presigned-transfer-executor.ts";
const policyModulePath =
"/src/adapters/browser-files/browser-file-policy-registry.ts";
const deliveryModulePath =
"/src/adapters/browser-files/download-delivery-adapter.ts";
const [
{
createPresignedCapabilityVault,
createSingleUsePresignedReplayGuard,
},
{ createPresignedCapabilityHttpProvider },
{ createPresignedTransferExecutor },
{
BrowserFilePolicyRegistry,
browserFilePolicyReference,
},
{ createDownloadDeliveryAdapter },
] = await Promise.all([
import(
/* @vite-ignore */ vaultModulePath
) as Promise<
typeof import("../../src/adapters/browser-transfer/presigned/presigned-capability-vault.ts")
>,
import(
/* @vite-ignore */ providerModulePath
) as Promise<
typeof import("../../src/adapters/browser-transfer/presigned/presigned-capability-http-provider.ts")
>,
import(
/* @vite-ignore */ executorModulePath
) as Promise<
typeof import("../../src/adapters/browser-transfer/presigned/presigned-transfer-executor.ts")
>,
import(
/* @vite-ignore */ policyModulePath
) as Promise<
typeof import("../../src/adapters/browser-files/browser-file-policy-registry.ts")
>,
import(
/* @vite-ignore */ deliveryModulePath
) as Promise<
typeof import("../../src/adapters/browser-files/download-delivery-adapter.ts")
>,
]);
const vault = createPresignedCapabilityVault({
maxActiveCapabilities: 4,
});
const provider = createPresignedCapabilityHttpProvider({
endpoint: `${location.origin}/api/download-capability`,
vault,
allowedDataOrigins: ["https://objects.example.test"],
allowedDataPathPrefixes: ["/files/"],
allowedQueryParameters: ["sig"],
allowedRequestHeaders: ["accept"],
allowedResponseHeaders: [
"x-content-sha256",
"x-policy-version",
],
hardMaxTransferBytes: 64,
hardMaxUploadResponseBytes: 1_024,
maxCapabilityTtlMs: 10 * 60_000,
minimumRemainingLifetimeMs: 30_000,
timeoutMs: 5_000,
allowInsecureLocalhost: true,
});
const executor = createPresignedTransferExecutor({
vault,
replayGuard: createSingleUsePresignedReplayGuard(),
hardMaxTransferBytes: 64,
hardMaxChunkBytes: 3,
hardMaxUploadResponseBytes: 1_024,
minimumRemainingLifetimeMs: 30_000,
timeoutMs: 5_000,
});
const signal = new AbortController().signal;
const issued = await provider.issueDownload({
resourceId,
signal,
});
if (!issued.ok) {
vault.dispose();
return {
issued,
delivery: null,
capabilityKeys: [],
capabilityBindingKeys: [],
written: [],
writeChunkSizes: [],
writableClosed: false,
writableAborted: false,
progressPhases: [],
};
}
const downloadPolicy = browserFilePolicyReference(
"browser-presigned-download",
"save-verified-artifact",
);
const policies = new BrowserFilePolicyRegistry({
profiles: [
{
reference: downloadPolicy,
download: {
strategy: "PROMPT_AND_STREAM",
mediaType: "application/octet-stream",
safeExtension: ".bin",
maxTransferBytes: 64,
maxBufferedBytes: 8,
integrity: "REQUIRED",
},
},
],
hardLimits: {
maxInspectionBytes: 64,
maxRetainedFileBytes: 64,
maxPreviewBytes: 64,
maxObjectUrlBytes: 64,
maxTransferBytes: 64,
},
});
const written: number[] = [];
const writeChunkSizes: number[] = [];
let writableClosed = false;
let writableAborted = false;
const downloads = createDownloadDeliveryAdapter({
host: {
handoff() {
throw new TypeError(
"Writable delivery must not use browser handoff.",
);
},
},
policies,
hardMaxObjectUrlBytes: 64,
hardMaxTransferBytes: 64,
browserManagedCapabilities: {
resolve() {
throw new TypeError(
"Browser-managed capability is not used.",
);
},
},
openAuthorizedSource:
executor.downloadSources.open.bind(
executor.downloadSources,
),
showSaveFilePicker: async () => ({
async createWritable() {
return new WritableStream<Uint8Array>({
write(chunk) {
writeChunkSizes.push(chunk.byteLength);
written.push(...chunk);
},
close() {
writableClosed = true;
},
abort() {
writableAborted = true;
},
});
},
}),
createTransferId: () => "transfer:browser-presigned",
progressMinIntervalMs: 0,
userActivation: { isActive: true },
});
const progressPhases: string[] = [];
const capabilityKeys = Object.keys(issued.value).sort();
const capabilityBindingKeys = Object.keys(
issued.value.binding,
).sort();
const delivery = await downloads.deliver({
policy: downloadPolicy,
source: {
kind: "AUTHORIZED_STREAM_RESOURCE",
resourceId,
capability: issued.value,
},
suggestedFileName: "browser-artifact.bin",
signal,
onProgress(progress) {
progressPhases.push(progress.phase);
},
});
downloads.dispose();
vault.dispose();
return {
issued: {
ok: true as const,
exposedHref: "href" in issued.value,
exposedRequestHeaders: "requestHeaders" in issued.value,
},
delivery,
capabilityKeys,
capabilityBindingKeys,
written,
writeChunkSizes,
writableClosed,
writableAborted,
progressPhases,
};
},
{ resourceId: RESOURCE_ID },
);
expect(bffRequests).toEqual([
{
method: "GET",
binding: {
kind: "DOWNLOAD",
resourceId: RESOURCE_ID,
},
},
]);
expect(objectRequests).toEqual([
{
url: OBJECT_HREF,
method: "GET",
accept: "application/octet-stream",
cookie: undefined,
},
]);
expect(result.issued).toEqual({
ok: true,
exposedHref: false,
exposedRequestHeaders: false,
});
expect(result.capabilityKeys).toEqual([
"binding",
"byteLength",
"capabilityReceipt",
"expectedSha256",
"expiresAtEpochMs",
"maxBytes",
"mediaType",
"method",
]);
expect(result.capabilityBindingKeys).toEqual([
"kind",
"resourceId",
]);
expect(result.delivery).toEqual({
ok: true,
value: {
kind: "SAVED",
transferId: "transfer:browser-presigned",
bytesWritten: DOWNLOAD_BYTES.byteLength,
integrity: "VERIFIED",
},
});
expect(result.written).toEqual([...DOWNLOAD_BYTES]);
expect(result.writeChunkSizes).toEqual([3, 3, 3, 1]);
expect(result.writableClosed).toBe(true);
expect(result.writableAborted).toBe(false);
expect(result.progressPhases).toEqual([
"PREPARING",
"TRANSFERRING",
"TRANSFERRING",
"TRANSFERRING",
"TRANSFERRING",
"VERIFYING",
"FINALIZING",
]);
});
@@ -0,0 +1,312 @@
import { expect, test } from "../support/browser/strict-browser-test.ts";
test("keeps A active across a failed B stage, activates B with A rollback, and cleans only owned stale caches", async ({
page,
}) => {
await page.goto("/");
const result = await page.evaluate(async () => {
const adapterModulePath =
"/src/adapters/cache-storage/public-response-cache-adapter.ts";
const policyModulePath =
"/src/adapters/cache-storage/public-cache-policy.ts";
const {
computePublicCacheManifestDigestHex,
createPublicCacheWebLock,
createPublicResponseCacheAdapter,
} = (await import(
/* @vite-ignore */ adapterModulePath
)) as typeof import("../../src/adapters/cache-storage/public-response-cache-adapter.ts");
const { createDefaultPublicCachePolicy } = (await import(
/* @vite-ignore */ policyModulePath
)) as typeof import("../../src/adapters/cache-storage/public-cache-policy.ts");
const suffix = crypto.randomUUID().replaceAll("-", "");
const releaseAId = `browser-a-${suffix.slice(0, 20)}`;
const releaseBId = `browser-b-${suffix.slice(0, 20)}`;
const unrelatedName = `unrelated-${suffix}`;
const policy = {
...createDefaultPublicCachePolicy(location.origin),
ownedCachePrefix: `cap-${suffix.slice(0, 24)}:`,
mutationLockName: `cap-${suffix}:mutation`,
};
const payloads = {
[`${location.origin}/cache-${suffix}-a.js`]: {
bytes: new TextEncoder().encode("verified-release-a"),
contentType: "application/javascript",
},
[`${location.origin}/cache-${suffix}-b.js`]: {
bytes: new TextEncoder().encode("verified-release-b"),
contentType: "application/javascript",
},
[`${location.origin}/cache-${suffix}-b.css`]: {
bytes: new TextEncoder().encode(".release-b{display:block}"),
contentType: "text/css",
},
} as const;
const [aUrl, bUrl, bSecondUrl] = Object.keys(payloads);
const digestHex = async (bytes: Uint8Array): Promise<string> => {
const digest = await crypto.subtle.digest(
"SHA-256",
Uint8Array.from(bytes),
);
return Array.from(
new Uint8Array(digest),
(byte) => byte.toString(16).padStart(2, "0"),
).join("");
};
const asset = async (absoluteUrl: string) => {
const payload = payloads[absoluteUrl as keyof typeof payloads];
return {
absoluteUrl,
expectedByteLength: payload.bytes.byteLength,
expectedContentType: payload.contentType,
integrity: {
algorithm: "SHA-256" as const,
digestHex: await digestHex(payload.bytes),
},
};
};
const assetsA = [await asset(aUrl!)];
const assetsB = [
await asset(bUrl!),
await asset(bSecondUrl!),
];
const manifestA = {
releaseRegistryId: releaseAId,
assets: assetsA,
manifestDigestHex:
await computePublicCacheManifestDigestHex(
crypto,
releaseAId,
assetsA,
policy,
),
};
const manifestB = {
releaseRegistryId: releaseBId,
assets: assetsB,
manifestDigestHex:
await computePublicCacheManifestDigestHex(
crypto,
releaseBId,
assetsB,
policy,
),
};
let corruptSecondBAsset = true;
const adapter = createPublicResponseCacheAdapter({
cacheStorage: caches,
crypto,
mutationLock: createPublicCacheWebLock(
navigator.locks,
policy.mutationLockName,
),
policy,
fetcher: async (request) => {
if (request.signal.aborted) {
throw new DOMException("Aborted.", "AbortError");
}
const payload =
payloads[request.url as keyof typeof payloads];
if (!payload) throw new TypeError("Unexpected cache URL.");
const responseBytes =
corruptSecondBAsset && request.url === bSecondUrl
? new Uint8Array(payload.bytes.byteLength)
: Uint8Array.from(payload.bytes);
return new Response(responseBytes, {
status: 200,
headers: {
"cache-control":
"public, max-age=31536000, immutable",
"content-type": payload.contentType,
"x-account-id": "must-not-persist",
},
});
},
});
const readActive = async (absoluteUrl: string) => {
const matched = await adapter.responses.matchActiveExact({
absoluteUrl,
});
if (!matched.ok || !matched.value) return matched;
const streamed: number[] = [];
for await (const chunk of matched.value.body.stream(
new AbortController().signal,
)) {
if (!chunk.ok) return chunk;
streamed.push(...chunk.value);
}
return {
ok: true as const,
streamed,
headerNames: matched.value.headers.map(([name]) => name),
};
};
try {
const stageA = await adapter.admin.stageRelease(manifestA);
const activateA = await adapter.admin.activateRelease(
manifestA.releaseRegistryId,
manifestA.manifestDigestHex,
);
const matchedABeforeFailedB = await readActive(aUrl!);
const failedStageB =
await adapter.admin.stageRelease(manifestB);
const afterFailedB = await adapter.admin.inspect();
const matchedAAfterFailedB = await readActive(aUrl!);
corruptSecondBAsset = false;
const stageB = await adapter.admin.stageRelease(manifestB);
const activateB = await adapter.admin.activateRelease(
manifestB.releaseRegistryId,
manifestB.manifestDigestHex,
);
const matchedB = await readActive(bUrl!);
const afterActivateB = await adapter.admin.inspect();
const releaseBCacheName = (await caches.keys()).find((name) =>
name.startsWith(
`${policy.ownedCachePrefix}release:${releaseBId}:`,
),
);
if (!releaseBCacheName) {
throw new Error("B release cache not found.");
}
const releaseBCache = await caches.open(releaseBCacheName);
await releaseBCache.put(
new Request(bUrl!),
new Response(new Uint8Array([0]), {
status: 200,
headers: {
"cache-control": "public",
"content-type": "application/javascript",
},
}),
);
const poisoned = await adapter.responses.matchActiveExact({
absoluteUrl: bUrl!,
});
await caches.open(`${policy.ownedCachePrefix}stale`);
await caches.open(unrelatedName);
const cleanup = await adapter.admin.cleanupOwned();
const names = await caches.keys();
return {
stageA,
activateA,
matchedABeforeFailedB,
failedStageB,
afterFailedB,
matchedAAfterFailedB,
stageB,
activateB,
matchedB,
afterActivateB,
poisoned,
cleanup,
unrelatedPreserved: names.includes(unrelatedName),
activeBPreserved: names.some((name) =>
name.startsWith(
`${policy.ownedCachePrefix}release:${releaseBId}:`,
),
),
rollbackAPreserved: names.some((name) =>
name.startsWith(
`${policy.ownedCachePrefix}release:${releaseAId}:`,
),
),
remainingOwnedCount: names.filter((name) =>
name.startsWith(policy.ownedCachePrefix),
).length,
expectedABytes: [...payloads[aUrl! as keyof typeof payloads].bytes],
expectedBBytes: [...payloads[bUrl! as keyof typeof payloads].bytes],
};
} finally {
for (const name of await caches.keys()) {
if (
name.startsWith(policy.ownedCachePrefix) ||
name === unrelatedName
) {
await caches.delete(name);
}
}
}
});
expect(result.stageA).toMatchObject({
ok: true,
value: { entryCount: 1 },
});
expect(result.activateA).toMatchObject({ ok: true });
expect(result.matchedABeforeFailedB).toMatchObject({
ok: true,
streamed: result.expectedABytes,
});
expect(result.failedStageB).toMatchObject({
ok: false,
error: { code: "INTEGRITY_FAILED" },
});
expect(result.afterFailedB).toMatchObject({
ok: true,
value: {
activeReleaseRegistryId: expect.stringMatching(/^browser-a-/u),
releaseCandidates: [
expect.objectContaining({
releaseRegistryId: expect.stringMatching(/^browser-a-/u),
verified: true,
}),
],
},
});
expect(result.matchedAAfterFailedB).toMatchObject({
ok: true,
streamed: result.expectedABytes,
});
expect(result.stageB).toMatchObject({
ok: true,
value: { entryCount: 2 },
});
expect(result.activateB).toMatchObject({ ok: true });
expect(result.matchedB).toMatchObject({
ok: true,
streamed: result.expectedBBytes,
});
expect(
(
result.matchedB as Readonly<{
headerNames: readonly string[];
}>
).headerNames,
).not.toContain("x-account-id");
expect(result.afterActivateB).toMatchObject({
ok: true,
value: {
activeReleaseRegistryId: expect.stringMatching(/^browser-b-/u),
releaseCandidates: expect.arrayContaining([
expect.objectContaining({
releaseRegistryId: expect.stringMatching(/^browser-a-/u),
verified: true,
}),
expect.objectContaining({
releaseRegistryId: expect.stringMatching(/^browser-b-/u),
verified: true,
}),
]),
},
});
expect(result.poisoned).toMatchObject({
ok: false,
error: { code: "INTEGRITY_FAILED" },
});
expect(result.cleanup).toMatchObject({
ok: true,
value: { deletedOwnedCaches: 1, retainedOwnedCaches: 3 },
});
expect(result.unrelatedPreserved).toBe(true);
expect(result.activeBPreserved).toBe(true);
expect(result.rollbackAPreserved).toBe(true);
expect(result.remainingOwnedCount).toBe(3);
});
@@ -0,0 +1,519 @@
import { createHash } from "node:crypto";
import type { Route } from "@playwright/test";
import { expect, test } from "../support/browser/strict-browser-test.ts";
const PAGE_ORIGIN = "http://127.0.0.1:4174";
const API_ORIGIN = "https://upload-api.example.test";
const OBJECT_ORIGIN = "https://upload-objects.example.test";
const SESSION_ID = "session_browser_01";
const RESOURCE_ID = "resource_browser_01";
const UPLOAD_PROTOCOL = "PRESIGNED_MULTIPART_V1";
type JsonRecord = Readonly<Record<string, unknown>>;
function corsHeaders(): Record<string, string> {
return {
"access-control-allow-credentials": "true",
"access-control-allow-headers": "content-type",
"access-control-allow-methods": "POST, OPTIONS",
"access-control-allow-origin": PAGE_ORIGIN,
};
}
async function fulfillJson(
route: Route,
status: number,
value: unknown,
): Promise<void> {
const body = JSON.stringify(value);
await route.fulfill({
status,
body,
headers: {
...corsHeaders(),
"content-length": String(Buffer.byteLength(body)),
"content-type": "application/json; charset=utf-8",
},
});
}
test("uploads three presigned parts through native IndexedDB, Web Locks and fetch", async ({
page,
}) => {
let session: JsonRecord | null = null;
const acceptedParts = new Map<number, JsonRecord>();
const issuedParts = new Map<number, JsonRecord>();
const controlRequests: Readonly<{
path: string;
body: JsonRecord;
}>[] = [];
const uploadedBodies: Readonly<{
partNumber: number;
bytes: number[];
checksum: string | undefined;
}>[] = [];
let completedParts: readonly JsonRecord[] = [];
await page.route(`${API_ORIGIN}/**`, async (route) => {
if (route.request().method() === "OPTIONS") {
await route.fulfill({ status: 204, headers: corsHeaders() });
return;
}
const path = new URL(route.request().url()).pathname;
const body = route.request().postDataJSON() as JsonRecord;
controlRequests.push({ path, body });
if (path === "/uploads/create") {
const fingerprint = body.fingerprint as JsonRecord;
session = {
protocol: UPLOAD_PROTOCOL,
sessionId: SESSION_ID,
requestBindingSha256: body.requestBindingSha256,
fingerprint,
partSizeBytes: body.requestedPartSizeBytes,
partCount: fingerprint.partCount,
maxConcurrency: 1,
expiresAtEpochMs: Date.now() + 5 * 60_000,
};
await fulfillJson(route, 201, session);
return;
}
if (path === "/uploads/status") {
if (!session) {
await fulfillJson(route, 404, { state: "NOT_FOUND" });
return;
}
await fulfillJson(route, 200, {
state: "ACTIVE",
session,
acceptedParts: [...acceptedParts.values()].sort(
(left, right) =>
Number(left.partNumber) - Number(right.partNumber),
),
});
return;
}
if (path === "/uploads/complete") {
completedParts = body.orderedParts as readonly JsonRecord[];
await fulfillJson(route, 200, {
state: "QUARANTINED",
protocol: UPLOAD_PROTOCOL,
sessionId: body.sessionId,
requestBindingSha256: body.requestBindingSha256,
fingerprint: body.fingerprint,
resourceId: RESOURCE_ID,
});
return;
}
if (path === "/uploads/abort") {
await fulfillJson(route, 200, { state: "ABORTED" });
return;
}
if (path === "/uploads/part-capability") {
const binding = body.binding as JsonRecord;
const partNumber = Number(binding.partNumber);
const descriptor = {
partNumber,
offset: binding.offset,
byteLength: body.byteLength,
checksumSha256: body.expectedSha256,
};
issuedParts.set(partNumber, descriptor);
const objectPath =
`/uploads/${SESSION_ID}/parts/${String(partNumber)}`;
await fulfillJson(route, 200, {
capabilityReceipt: `browser-part-capability-${String(partNumber)}`,
method: "PUT",
binding,
href:
`${OBJECT_ORIGIN}${objectPath}?sig=opaque-${String(partNumber)}`,
origin: OBJECT_ORIGIN,
path: objectPath,
allowedQueryParameters: ["sig"],
requestHeaders: [
{
name: "content-type",
value: body.mediaType,
},
{
name: "x-checksum-sha256",
value: body.expectedSha256,
},
],
requiredResponseHeaders: [
{
name: "x-policy-version",
value: "v1",
},
],
digestRequestHeader: "x-checksum-sha256",
digestResponseHeader: null,
receiptResponseHeader: "etag",
expectedResponseByteLength: 0,
expectedStatus: 204,
mediaType: body.mediaType,
byteLength: body.byteLength,
maxBytes: body.byteLength,
expectedSha256: body.expectedSha256,
expiresAtEpochMs:
Number(session?.expiresAtEpochMs) - 10_000,
singleUse: true,
});
return;
}
await route.fulfill({ status: 404, headers: corsHeaders() });
});
await page.route(`${OBJECT_ORIGIN}/**`, async (route) => {
if (route.request().method() === "OPTIONS") {
await route.fulfill({
status: 204,
headers: {
"access-control-allow-headers":
"content-type, x-checksum-sha256",
"access-control-allow-methods": "PUT, OPTIONS",
"access-control-allow-origin": "*",
},
});
return;
}
const match = new URL(route.request().url()).pathname.match(
/\/parts\/([1-9][0-9]*)$/u,
);
const partNumber = Number(match?.[1]);
const body = route.request().postDataBuffer();
if (!body || !Number.isSafeInteger(partNumber)) {
await route.fulfill({ status: 400 });
return;
}
const checksum = route.request().headers()["x-checksum-sha256"];
const actualChecksum = createHash("sha256")
.update(body)
.digest("hex");
const descriptor = issuedParts.get(partNumber);
if (
!descriptor ||
checksum !== actualChecksum ||
descriptor.checksumSha256 !== actualChecksum ||
descriptor.byteLength !== body.byteLength
) {
await route.fulfill({ status: 422 });
return;
}
const receiptToken = `etag-part-${String(partNumber)}`;
acceptedParts.set(partNumber, {
...descriptor,
receiptToken,
});
uploadedBodies.push({
partNumber,
bytes: [...body],
checksum,
});
await route.fulfill({
status: 204,
headers: {
"access-control-allow-origin": "*",
"access-control-expose-headers": "etag, x-policy-version",
etag: `"${receiptToken}"`,
"x-policy-version": "v1",
},
});
});
await page.goto("/");
const result = await page.evaluate(
async ({ apiOrigin, objectOrigin }) => {
const vaultModulePath =
"/src/adapters/browser-transfer/presigned/presigned-capability-vault.ts";
const providerModulePath =
"/src/adapters/browser-transfer/presigned/presigned-capability-http-provider.ts";
const executorModulePath =
"/src/adapters/browser-transfer/presigned/presigned-transfer-executor.ts";
const fetchTransportModulePath =
"/src/adapters/browser-transfer/resumable-upload/fetch-json-transport.ts";
const controlPlaneModulePath =
"/src/adapters/browser-transfer/resumable-upload/http-control-plane-adapter.ts";
const checkpointModulePath =
"/src/adapters/browser-transfer/resumable-upload/indexeddb-checkpoint-store.ts";
const partExecutorModulePath =
"/src/adapters/browser-transfer/resumable-upload/presigned-upload-part-executor.ts";
const uploadRuntimeModulePath =
"/src/adapters/browser-transfer/resumable-upload/resumable-upload-runtime.ts";
const cancellationModulePath =
"/src/adapters/browser-transfer/resumable-upload/upload-cancellation-channel.ts";
const lockModulePath =
"/src/adapters/browser-transfer/resumable-upload/upload-mutation-lock.ts";
const [
{
createPresignedCapabilityVault,
createSingleUsePresignedReplayGuard,
},
{ createPresignedCapabilityHttpProvider },
{ createPresignedTransferExecutor },
{ createResumableUploadFetchJsonTransport },
{ createResumableUploadHttpControlPlane },
{ createIndexedDbResumableUploadCheckpointRuntime },
{ createPresignedUploadPartExecutor },
{ createResumableUploadRuntime },
{ createBrowserUploadCancellationChannel },
{ createResumableUploadWebLock },
] = await Promise.all([
import(/* @vite-ignore */ vaultModulePath),
import(/* @vite-ignore */ providerModulePath),
import(/* @vite-ignore */ executorModulePath),
import(/* @vite-ignore */ fetchTransportModulePath),
import(/* @vite-ignore */ controlPlaneModulePath),
import(/* @vite-ignore */ checkpointModulePath),
import(/* @vite-ignore */ partExecutorModulePath),
import(/* @vite-ignore */ uploadRuntimeModulePath),
import(/* @vite-ignore */ cancellationModulePath),
import(/* @vite-ignore */ lockModulePath),
]);
const suffix = crypto.randomUUID().replaceAll("-", "");
const uploadKey = `upload_browser_${suffix}`;
const checkpointRuntime =
createIndexedDbResumableUploadCheckpointRuntime({
scope: {
authorityToken: `authority_${suffix}`,
namespaceToken: `namespace_${suffix}`,
partitionToken: `partition_${suffix}`,
},
blockedTimeoutMs: 2_000,
});
const vault = createPresignedCapabilityVault({
maxActiveCapabilities: 8,
});
const capabilityProvider =
createPresignedCapabilityHttpProvider({
endpoint: `${apiOrigin}/uploads/part-capability`,
vault,
allowedDataOrigins: [objectOrigin],
allowedDataPathPrefixes: ["/uploads/"],
allowedQueryParameters: ["sig"],
allowedRequestHeaders: [
"content-type",
"x-checksum-sha256",
],
allowedResponseHeaders: ["etag", "x-policy-version"],
hardMaxTransferBytes: 8,
hardMaxUploadResponseBytes: 1_024,
maxCapabilityTtlMs: 10 * 60_000,
minimumRemainingLifetimeMs: 30_000,
timeoutMs: 5_000,
controlPlaneCredentials: "include",
});
const transferExecutor = createPresignedTransferExecutor({
vault,
replayGuard: createSingleUsePresignedReplayGuard(),
hardMaxTransferBytes: 8,
hardMaxChunkBytes: 2,
hardMaxUploadResponseBytes: 1_024,
minimumRemainingLifetimeMs: 30_000,
timeoutMs: 5_000,
});
const transport = createResumableUploadFetchJsonTransport({
endpoints: {
CREATE_SESSION: `${apiOrigin}/uploads/create`,
GET_STATUS: `${apiOrigin}/uploads/status`,
COMPLETE: `${apiOrigin}/uploads/complete`,
ABORT: `${apiOrigin}/uploads/abort`,
},
allowedOrigins: [apiOrigin],
credentials: "include",
timeoutMs: 5_000,
maxRequestBytes: 64 * 1024,
maxResponseBytes: 64 * 1024,
maxRetryAfterMs: 1_000,
});
const controlPlane = createResumableUploadHttpControlPlane({
transport,
partCapabilities: capabilityProvider,
});
const cancellationChannelName =
`browser-upload-cancel-${suffix}`;
const crossContextCancellation =
createBrowserUploadCancellationChannel({
channelName: cancellationChannelName,
});
const cancellationPeer =
createBrowserUploadCancellationChannel({
channelName: cancellationChannelName,
});
const runtime = createResumableUploadRuntime({
controlPlane,
partExecutor: createPresignedUploadPartExecutor(
transferExecutor.uploadParts,
),
checkpoints: checkpointRuntime.store,
mutationLock: createResumableUploadWebLock(
navigator.locks,
"browser-resumable-upload",
),
...(crossContextCancellation
? { crossContextCancellation }
: {}),
crypto,
policy: {
partSizeBytes: 2,
maxFileBytes: 6,
maxPartCount: 3,
maxConcurrency: 2,
maxInFlightBytes: 16,
partBufferCopyFactor: 4,
maxSourceChunkBytes: 2,
maxRetries: 1,
retryBaseDelayMs: 1,
retryMaxDelayMs: 5,
maxRetryAfterMs: 1_000,
capabilityRefreshSkewMs: 1_000,
maxSessionLifetimeMs: 10 * 60_000,
providerAttemptTimeoutMs: 10_000,
},
});
const bytes = new Uint8Array([1, 2, 3, 4, 5]);
const progress: string[] = [];
let upload: unknown;
let checkpoint: unknown;
let deletion: unknown;
let cancellationDelivered = false;
try {
if (crossContextCancellation && cancellationPeer) {
cancellationDelivered = await new Promise<boolean>(
(resolve) => {
const timer = setTimeout(() => resolve(false), 2_000);
const release = cancellationPeer.subscribe((key: string) => {
if (key !== `upload_probe_${suffix}`) return;
clearTimeout(timer);
release();
resolve(true);
});
if (
!crossContextCancellation.publish(
`upload_probe_${suffix}`,
)
) {
clearTimeout(timer);
release();
resolve(false);
}
},
);
}
upload = await runtime.upload({
uploadKey,
purpose: "browser_attachment",
mediaType: "application/octet-stream",
source: {
kind: "RANGE_READER",
reader: {
byteLength: bytes.byteLength,
async readRange(input: {
offset: number;
length: number;
signal: AbortSignal;
}) {
return input.signal.aborted
? {
ok: false as const,
error: {
code: "ABORTED" as const,
operation: "FILE_READ" as const,
retryable: false,
recovery: "NONE" as const,
},
}
: {
ok: true as const,
value: bytes.slice(
input.offset,
input.offset + input.length,
),
};
},
},
},
signal: new AbortController().signal,
onProgress(value: { phase: string }) {
progress.push(value.phase);
},
});
checkpoint = await checkpointRuntime.store.read(uploadKey);
} finally {
runtime.close();
cancellationPeer?.close();
deletion =
await checkpointRuntime.admin.deletePartition();
vault.dispose();
}
return {
upload,
checkpoint,
deletion,
progress,
webLocksAvailable: Boolean(navigator.locks),
broadcastCancellationAvailable:
Boolean(crossContextCancellation),
cancellationDelivered,
};
},
{ apiOrigin: API_ORIGIN, objectOrigin: OBJECT_ORIGIN },
);
expect(result.webLocksAvailable).toBe(true);
expect(result.broadcastCancellationAvailable).toBe(true);
expect(result.cancellationDelivered).toBe(true);
expect(result.upload).toMatchObject({
ok: true,
value: {
state: "QUARANTINED",
resourceId: RESOURCE_ID,
byteLength: 5,
replayed: false,
},
});
expect(result.checkpoint).toEqual({ ok: true, value: null });
expect(result.deletion).toEqual({
ok: true,
value: { state: "DELETED" },
});
expect(
uploadedBodies
.slice()
.sort((left, right) => left.partNumber - right.partNumber)
.map(({ partNumber, bytes }) => ({ partNumber, bytes })),
).toEqual([
{ partNumber: 1, bytes: [1, 2] },
{ partNumber: 2, bytes: [3, 4] },
{ partNumber: 3, bytes: [5] },
]);
expect(completedParts.map((part) => part.partNumber)).toEqual([
1, 2, 3,
]);
expect(completedParts.map((part) => part.receiptToken)).toEqual([
"etag-part-1",
"etag-part-2",
"etag-part-3",
]);
expect(controlRequests.map((request) => request.path)).toEqual([
"/uploads/create",
"/uploads/status",
"/uploads/part-capability",
"/uploads/part-capability",
"/uploads/part-capability",
"/uploads/status",
"/uploads/complete",
]);
expect(JSON.stringify(controlRequests)).not.toContain("?sig=");
expect(JSON.stringify(controlRequests)).not.toContain(OBJECT_ORIGIN);
});
@@ -0,0 +1,29 @@
import { expect, test } from "../support/browser/strict-browser-test.ts";
test("executes the storage durability adapter against the real browser StorageManager", async ({
page,
}) => {
await page.goto("/");
const result = await page.evaluate(async () => {
const modulePath =
"/src/adapters/browser-file-storage/storage-manager-adapter.ts";
const { createStorageDurabilityAdapter } = await import(
/* @vite-ignore */ modulePath
);
const adapter = createStorageDurabilityAdapter(navigator.storage);
return adapter.inspect();
});
expect(result.ok).toBe(true);
if (result.ok) {
expect(["UNKNOWN", "NORMAL", "PRESSURE", "CRITICAL"]).toContain(
result.value.pressure,
);
expect(
result.value.usageBytes === null || result.value.usageBytes >= 0,
).toBe(true);
expect(
result.value.quotaBytes === null || result.value.quotaBytes >= 0,
).toBe(true);
}
});