@siafoundation/sia-storage 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ import {
3
3
  parseStreamPath,
4
4
  requestReply,
5
5
  streamErrorMessage
6
- } from "./chunk-YOMDUMYW.js";
6
+ } from "./chunk-WOQD3MPG.js";
7
7
 
8
8
  // src/stream-worker.ts
9
9
  import wasmInit, {
@@ -93,7 +93,31 @@ function serveStreams(scope, connect, supportsDownloads) {
93
93
  const sources = /* @__PURE__ */ new Map();
94
94
  const sessions = /* @__PURE__ */ new Map();
95
95
  const released = /* @__PURE__ */ new Set();
96
+ const active = /* @__PURE__ */ new Map();
96
97
  const key = (clientId, id) => JSON.stringify([clientId, id]);
98
+ function tellStreaming(client, streaming) {
99
+ try {
100
+ client.postMessage({
101
+ type: "sia-streaming",
102
+ active: streaming
103
+ });
104
+ } catch {
105
+ }
106
+ }
107
+ function hold(client, lifetime) {
108
+ const count = (active.get(client.id) ?? 0) + 1;
109
+ active.set(client.id, count);
110
+ if (count === 1) tellStreaming(client, true);
111
+ void lifetime.then(() => {
112
+ const left = active.get(client.id) - 1;
113
+ if (left > 0) {
114
+ active.set(client.id, left);
115
+ return;
116
+ }
117
+ active.delete(client.id);
118
+ tellStreaming(client, false);
119
+ });
120
+ }
97
121
  function idle(session) {
98
122
  clearTimeout(session.timer);
99
123
  if (!session.closed && session.jobs.size === 0) {
@@ -272,6 +296,7 @@ function serveStreams(scope, connect, supportsDownloads) {
272
296
  try {
273
297
  const client = await scope.clients.get(clientId);
274
298
  if (!client || request.signal.aborted) return errorResponse(404);
299
+ hold(client, job.lifetime);
275
300
  const source = getSource(client, token);
276
301
  job.source = source;
277
302
  source.requests.add(job.abort);
@@ -346,6 +371,8 @@ function serveStreams(scope, connect, supportsDownloads) {
346
371
  released.add(sessionKey);
347
372
  const session = sessions.get(sessionKey);
348
373
  if (session) event.waitUntil(disposeSession(session));
374
+ } else if (data?.type === "sia-keep-alive" && !active.has(clientId)) {
375
+ tellStreaming(source, false);
349
376
  }
350
377
  });
351
378
  scope.addEventListener("fetch", (event) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stream-worker.ts","../src/stream/response.ts","../src/stream/worker.ts"],"sourcesContent":["/**\n * The worker side of streaming, for sites that already run a service worker.\n *\n * A page has only one service worker, so a site with its own calls\n * `installStreams(self)` in it and passes that worker's URL to\n * `enableStreaming`. Every other site serves the prebuilt `sia-storage-sw.js`,\n * which is this function with the WebAssembly built in.\n */\nimport wasmInit, {\n AppKey,\n Builder,\n type InitInput,\n PinnedObject,\n SharedSdk,\n} from '../wasm/sia_storage_wasm.js'\nimport type { Connection } from './stream/protocol'\nimport { serveStreams, type StreamScope, type StreamSdk } from './stream/worker'\n\nexport type { StreamScope }\n\nexport type InstallStreamsOptions = {\n /**\n * The SDK's WebAssembly, as a URL, bytes or compiled module. Only needed\n * when the worker's bundler does not emit `sia_storage_wasm_bg.wasm`.\n */\n wasm?: InitInput\n}\n\nexport function installStreams(\n scope: StreamScope,\n options: InstallStreamsOptions = {},\n) {\n let ready: Promise<unknown> | undefined\n serveStreams(\n scope,\n async (connection) => {\n ready ??= wasmInit(\n options.wasm === undefined ? undefined : { module_or_path: options.wasm },\n )\n await ready\n return connection.kind === 'shared'\n ? connectShared(connection)\n : connectApp(connection)\n },\n // Downloads from hosts need WebTransport, which some browsers leave out\n // of service workers. The page then reads objects itself.\n typeof WebTransport === 'function',\n )\n}\n\nasync function connectShared({\n indexerUrl,\n seed,\n sealKey,\n}: Extract<Connection, { kind: 'shared' }>): Promise<StreamSdk> {\n // Built before connecting, so a key that fails to load cannot leave a\n // connected SDK behind with nothing to free it.\n const key = sealKey === undefined ? undefined : new AppKey(fromHex(sealKey))\n let sdk: SharedSdk\n try {\n sdk = await SharedSdk.connect(indexerUrl, seed)\n } catch (error) {\n key?.free()\n throw error\n }\n return {\n // The page sealed the object it already had with the share's random key.\n // Opening that saves a round trip to the indexer before every stream's\n // first byte.\n object: async ({ objectId, sealed }) =>\n key && sealed ? PinnedObject.open(key, sealed) : sdk.object(objectId),\n download: (object, options) => sdk.download(object, options),\n free: () => {\n sdk.free()\n key?.free()\n },\n }\n}\n\nasync function connectApp({\n indexerUrl,\n appKey,\n appMeta,\n}: Extract<Connection, { kind: 'app' }>): Promise<StreamSdk> {\n const key = new AppKey(fromHex(appKey))\n const builder = new Builder(indexerUrl, appMeta)\n try {\n const sdk = await builder.connected(key)\n if (!sdk) throw new Error('The app key is not registered with the indexer.')\n return {\n // The page sent the object sealed with this key, so no lookup is needed.\n object: async ({ sealed }) => PinnedObject.open(key, sealed!),\n download: (object, options) => sdk.download(object, options),\n free: () => {\n sdk.free()\n key.free()\n },\n }\n } catch (error) {\n key.free()\n throw error\n } finally {\n builder.free()\n }\n}\n\n// Uint8Array.fromHex is too new for some browsers that run service workers.\nfunction fromHex(hex: string) {\n return Uint8Array.from(hex.match(/../g) ?? [], (byte) => parseInt(byte, 16))\n}\n","// File bytes come from whoever owns the share, so the browser must never cache\n// them or run them as this origin's content.\nconst PROTECTIVE_HEADERS = {\n 'Cache-Control': 'no-store',\n 'X-Content-Type-Options': 'nosniff',\n 'Content-Security-Policy': \"sandbox; default-src 'none'\",\n 'Referrer-Policy': 'no-referrer',\n}\n\nexport type ByteRange = {\n status: 200 | 206 | 416\n offset: number\n length: number\n}\n\nexport function parseRange(range: string | null, size: number): ByteRange {\n if (!Number.isSafeInteger(size) || size < 0) {\n throw new RangeError('Invalid file size')\n }\n if (range === null) return { status: 200, offset: 0, length: size }\n\n const invalid: ByteRange = { status: 416, offset: 0, length: 0 }\n const match = /^bytes=(\\d*)-(\\d*)$/i.exec(range.trim())\n if (!match || (!match[1] && !match[2]) || size === 0) return invalid\n // Both groups always participate in a match, possibly as empty strings.\n const start = match[1]!\n const end = match[2]!\n\n // Range numerals are not limited to JS's safe integers. Compare before converting.\n const total = BigInt(size)\n let first: bigint\n let last: bigint\n if (!start) {\n const suffix = BigInt(end)\n if (suffix === 0n) return invalid\n first = suffix >= total ? 0n : total - suffix\n last = total - 1n\n } else {\n first = BigInt(start)\n last = end ? BigInt(end) : total - 1n\n if (first >= total || last < first) return invalid\n if (last >= total) last = total - 1n\n }\n return {\n status: 206,\n offset: Number(first),\n length: Number(last - first + 1n),\n }\n}\n\nexport function contentDisposition(name: string, download: boolean) {\n // TextEncoder replaces lone surrogates without requiring toWellFormed(),\n // which older browsers with module service workers do not implement.\n const wellFormed = new TextDecoder().decode(new TextEncoder().encode(name))\n const filename =\n wellFormed\n // Filenames must not contain header controls or path separators.\n // eslint-disable-next-line no-control-regex\n .replace(/[\\u0000-\\u001f\\u007f/\\\\]/g, '_')\n .trim() || 'download'\n const fallback = filename.replace(/[^\\u0020-\\u007e]|[\";]/g, '_')\n const encoded = encodeURIComponent(filename).replace(\n /[!'()*]/g,\n (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`,\n )\n return `${download ? 'attachment' : 'inline'}; filename=\"${fallback}\"; filename*=UTF-8''${encoded}`\n}\n\nexport function responseHeaders(\n metadata: { name: string; mime: string; size: number },\n range: ByteRange,\n download: boolean,\n) {\n // Only use a media type, never arbitrary header syntax from shared metadata.\n const mime = (metadata.mime.split(';', 1)[0] ?? '').trim()\n const headers = new Headers({\n 'Accept-Ranges': 'bytes',\n 'Content-Length': String(range.length),\n 'Content-Type': /^[\\w!#$&^.+-]+\\/[\\w!#$&^.+-]+$/.test(mime)\n ? mime\n : 'application/octet-stream',\n 'Content-Disposition': contentDisposition(metadata.name, download),\n ...PROTECTIVE_HEADERS,\n })\n if (range.status === 206) {\n headers.set(\n 'Content-Range',\n `bytes ${range.offset}-${range.offset + range.length - 1}/${metadata.size}`,\n )\n } else if (range.status === 416) {\n headers.set('Content-Range', `bytes */${metadata.size}`)\n }\n return headers\n}\n\nexport function errorResponse(status: number) {\n const headers = new Headers(PROTECTIVE_HEADERS)\n if (status === 405) headers.set('Allow', 'GET, HEAD')\n return new Response(null, { status, headers })\n}\n","import type {\n PinnedObject,\n ShardProgress,\n} from '../../wasm/sia_storage_wasm.js'\nimport { streamErrorMessage } from './errors'\nimport {\n type ClientReply,\n isSourceReply,\n type PageMessage,\n parseStreamPath,\n requestReply,\n type Connection,\n type SourceDetails,\n type StreamEvent,\n type StreamStatus,\n type WorkerMessage,\n} from './protocol'\nimport {\n type ByteRange,\n errorResponse,\n parseRange,\n responseHeaders,\n} from './response'\n\nconst SOURCE_TIMEOUT = 5_000\nconst IDLE_TIMEOUT = 5 * 60_000\n// How long bytes and shard reports for one URL collect before they are sent,\n// so a stream costs a few messages a second rather than one per chunk.\nconst REPORT_INTERVAL = 100\n\n/** An object as the page describes it. See `SourceDetails`. */\nexport type ObjectRef = Pick<SourceDetails, 'objectId' | 'sealed'>\n\n/** A connected SDK of either kind, as the worker uses it. */\nexport type StreamSdk = {\n object(ref: ObjectRef): Promise<PinnedObject>\n download(\n object: PinnedObject,\n options: {\n offset: number\n length: number\n onShardDownloaded?: (progress: ShardProgress) => void\n },\n ): ReadableStream\n free(): void\n}\n\n// The parts of ServiceWorkerGlobalScope this module uses, written out so it\n// type-checks alongside page code, whose DOM types conflict with the service\n// worker ones. A real ServiceWorkerGlobalScope satisfies them.\ntype StreamClient = { id: string; postMessage(message: unknown, transfer?: Transferable[]): void }\ntype WaitUntil = { waitUntil(promise: Promise<unknown>): void }\ntype StreamFetchEvent = { request: Request; respondWith(response: Promise<Response>): void }\ntype StreamMessageEvent = WaitUntil & {\n data: unknown\n source: unknown\n ports: readonly MessagePort[]\n}\nexport type StreamScope = {\n location: { origin: string }\n skipWaiting(): Promise<void>\n clients: {\n get(id: string): Promise<StreamClient | undefined>\n claim(): Promise<void>\n }\n addEventListener(type: 'install' | 'activate', listener: (event: WaitUntil) => void): void\n addEventListener(type: 'message', listener: (event: StreamMessageEvent) => void): void\n addEventListener(type: 'fetch', listener: (event: StreamFetchEvent) => void): void\n}\ntype Metadata = Pick<\n SourceDetails,\n 'objectId' | 'sealed' | 'name' | 'mime' | 'size'\n>\ntype Chunks = ReadableStreamDefaultReader<Uint8Array>\n\n/** One page's open share, and the SDK the worker connects for it on first use. */\ntype Session = {\n key: string\n connection: Connection\n sources: Set<Source>\n objects: Map<string, Promise<PinnedObject>>\n // One `Job.lifetime` per request in flight.\n jobs: Set<Promise<void>>\n closed: boolean\n timer?: ReturnType<typeof setTimeout>\n sdk?: Promise<StreamSdk>\n}\n\n/** One stream token, resolved to its file by asking the page that made it. */\ntype Source = {\n key: string\n client: StreamClient\n closed: boolean\n // The `abort` of each job serving this token.\n requests: Set<() => void>\n ready: Promise<Metadata>\n setup: AbortController\n session?: Session\n // Set when the page asked for status and progress messages.\n reporter?: Reporter\n // Requests for this URL past their HEAD and range checks and not yet\n // settled. Its status is `idle` while this is zero.\n reading: number\n}\n\n/** One HTTP request for a stream URL, from the first await to its last byte. */\ntype Job = {\n closed: boolean\n lifetime: Promise<void>\n source?: Source\n session?: Session\n range?: ByteRange\n // Counted in `source.reading` until the job settles.\n reading?: boolean\n // A warm-up read, which reports nothing to the page.\n quiet?: boolean\n reader?: Chunks\n controller?: ReadableStreamDefaultController<Uint8Array>\n finish(cancel?: boolean): void\n abort(): void\n fail(error: unknown): void\n}\n\n// The control port carries credentials and metadata only. Bytes never leave\n// this worker, since each response consumes the SDK's own stream with native\n// backpressure.\nexport function serveStreams(\n scope: StreamScope,\n connect: (connection: Connection) => Promise<StreamSdk>,\n supportsDownloads: boolean,\n) {\n const sources = new Map<string, Source>()\n const sessions = new Map<string, Session>()\n // Released session keys. A page reply already in flight when its share is\n // released must not bring the session back.\n const released = new Set<string>()\n const key = (clientId: string, id: string) => JSON.stringify([clientId, id])\n\n function idle(session: Session) {\n clearTimeout(session.timer)\n if (!session.closed && session.jobs.size === 0) {\n session.timer = setTimeout(\n () => void disposeSession(session),\n IDLE_TIMEOUT,\n )\n }\n }\n\n function sessionFor(clientId: string, details: SourceDetails) {\n const sessionKey = key(clientId, details.session)\n let session = sessions.get(sessionKey)\n if (!session) {\n session = {\n key: sessionKey,\n connection: details.connection,\n sources: new Set(),\n objects: new Map(),\n jobs: new Set(),\n closed: false,\n }\n sessions.set(sessionKey, session)\n }\n return session\n }\n\n async function disposeSession(session: Session) {\n if (session.closed) return\n session.closed = true\n sessions.delete(session.key)\n clearTimeout(session.timer)\n for (const source of session.sources) dropSource(source)\n // Do not free wasm handles while a connect, lookup or cancellation uses them.\n await Promise.allSettled(session.jobs)\n await Promise.allSettled(\n [...session.objects.values()].map(async (object) =>\n (await object).free(),\n ),\n )\n try {\n ;(await session.sdk)?.free()\n } catch {\n // Connection failures are reported by the request, not during disposal.\n }\n }\n\n // A failed connect or lookup is forgotten, so the next request retries it\n // instead of failing with the cached error.\n function sdkFor(session: Session) {\n if (session.sdk) return session.sdk\n const { connection } = session\n const connecting = Promise.resolve().then(() => connect(connection))\n session.sdk = connecting\n connecting.catch(() => {\n if (session.sdk === connecting) delete session.sdk\n })\n return connecting\n }\n\n function objectFor(session: Session, sdk: StreamSdk, ref: ObjectRef) {\n const { objectId } = ref\n const cached = session.objects.get(objectId)\n if (cached) return cached\n const lookup = Promise.resolve().then(() => sdk.object(ref))\n session.objects.set(objectId, lookup)\n lookup.catch(() => {\n if (session.objects.get(objectId) === lookup) {\n session.objects.delete(objectId)\n }\n })\n return lookup\n }\n\n function getSource(client: StreamClient, token: string) {\n const sourceKey = key(client.id, token)\n const cached = sources.get(sourceKey)\n if (cached) return cached\n const setup = new AbortController()\n const request = { type: 'sia-source', token } satisfies WorkerMessage\n const ready = requestReply(client, request, {\n timeout: SOURCE_TIMEOUT,\n signal: setup.signal,\n }).then((reply) => {\n if (!isSourceReply(reply)) {\n throw new Error('Shared file source unavailable.')\n }\n if (source.closed || released.has(key(client.id, reply.session))) {\n throw new DOMException('Released', 'AbortError')\n }\n const session = sessionFor(client.id, reply)\n source.session = session\n session.sources.add(source)\n if (reply.events?.length) {\n source.reporter = createReporter(client, token, reply.events)\n }\n idle(session)\n // Keep credentials in the session record, never in response metadata.\n const { objectId, sealed, name, mime, size } = reply\n return { objectId, sealed, name, mime, size }\n })\n const source: Source = {\n key: sourceKey,\n client,\n closed: false,\n requests: new Set(),\n ready,\n setup,\n reading: 0,\n }\n sources.set(sourceKey, source)\n return source\n }\n\n function dropSource(source: Source) {\n if (source.closed) return\n source.closed = true\n sources.delete(source.key)\n source.reporter?.stop()\n source.setup.abort(new DOMException('Released', 'AbortError'))\n for (const cancel of source.requests) cancel()\n source.session?.sources.delete(source)\n }\n\n /**\n * Tracks one request until it settles, whichever way that happens: its last\n * byte, the page aborting it, its source being released, or an SDK failure.\n */\n function startJob(request: Request, token: string): Job {\n let complete = () => {}\n // Kept out of event.waitUntil. Chromium kills a worker whose event runs\n // past 5 minutes, which would end any download still running at that mark.\n const lifetime = new Promise<void>((resolve) => {\n complete = resolve\n })\n const job: Job = {\n closed: false,\n lifetime,\n finish(cancel = false) {\n if (job.closed) return\n job.closed = true\n request.signal.removeEventListener('abort', job.abort)\n const { reader } = job\n const cancellation =\n cancel && reader ? reader.cancel().catch(() => {}) : undefined\n void Promise.resolve(cancellation).finally(() => {\n reader?.releaseLock()\n const { source } = job\n source?.requests.delete(job.abort)\n if (source && job.reading && --source.reading === 0) {\n source.reporter?.status('idle')\n }\n job.session?.jobs.delete(lifetime)\n if (job.session) idle(job.session)\n complete()\n })\n },\n abort() {\n if (job.closed) return\n job.controller?.error(new DOMException('Aborted', 'AbortError'))\n job.finish(true)\n },\n fail(error) {\n if (job.closed) return\n const message = streamErrorMessage(error)\n const aborted = error instanceof Error && error.name === 'AbortError'\n const { source, range } = job\n // A warm-up is invisible to the page, failures included. The play\n // that follows connects again and reports its own failure.\n if (!aborted && !job.quiet && source && !source.closed) {\n // Diagnostics go only to the owning page. Never log SDK objects here.\n try {\n source.client.postMessage({\n type: 'sia-stream-error',\n token,\n message,\n ...(range && { offset: range.offset, length: range.length }),\n } satisfies WorkerMessage)\n } catch {\n // The owning tab may already be gone.\n }\n }\n job.controller?.error(new Error(message))\n job.finish(true)\n },\n }\n return job\n }\n\n async function serve(\n request: Request,\n clientId: string,\n token: string,\n { download, warm }: { download: boolean; warm: boolean },\n ): Promise<Response> {\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n return errorResponse(405)\n }\n if (!supportsDownloads) return errorResponse(503)\n const job = startJob(request, token)\n job.quiet = warm\n try {\n const client = await scope.clients.get(clientId)\n if (!client || request.signal.aborted) return errorResponse(404)\n const source = getSource(client, token)\n job.source = source\n source.requests.add(job.abort)\n request.signal.addEventListener('abort', job.abort, { once: true })\n const metadata = await source.ready\n if (job.closed) return errorResponse(502)\n // Set by `ready` before it resolves.\n const session = source.session!\n job.session = session\n session.jobs.add(job.lifetime)\n clearTimeout(session.timer)\n const range = parseRange(\n request.method === 'HEAD' ? null : request.headers.get('range'),\n metadata.size,\n )\n job.range = range\n const headers = responseHeaders(metadata, range, download)\n if (request.method === 'HEAD' || range.status === 416) {\n job.finish()\n return new Response(null, { status: range.status, headers })\n }\n // A warm-up is invisible to the page, so a player that warms a file\n // does not see it go connecting and downloading before Play.\n const reporter = warm ? undefined : source.reporter\n job.reading = !warm\n // A read that starts while another is already downloading leaves the\n // status at `downloading`.\n if (!warm && ++source.reading === 1) reporter?.status('connecting')\n // A zero-byte file reports connecting then idle, as a read in the page\n // does, without starting an SDK download.\n if (range.length === 0) {\n job.finish()\n return new Response(null, { status: range.status, headers })\n }\n const sdk = await sdkFor(session)\n if (job.closed) return errorResponse(502)\n const object = await objectFor(session, sdk, metadata)\n if (job.closed) return errorResponse(502)\n const chunks: Chunks = sdk\n .download(object, {\n offset: range.offset,\n length: range.length,\n ...(reporter?.wants.shards && {\n onShardDownloaded: (progress) => reporter.shard(progress),\n }),\n })\n .getReader()\n job.reader = chunks\n return new Response(rangeBody(job, chunks, range.length), {\n status: range.status,\n headers,\n })\n } catch (error) {\n job.fail(error)\n if (job.source && !job.source.session) dropSource(job.source)\n return errorResponse(502)\n }\n }\n\n scope.addEventListener('install', (event) =>\n event.waitUntil(scope.skipWaiting()),\n )\n scope.addEventListener('activate', (event) =>\n event.waitUntil(scope.clients.claim()),\n )\n scope.addEventListener('message', (event) => {\n const source = event.source as Partial<StreamClient> | null\n const clientId = typeof source?.id === 'string' ? source.id : undefined\n if (!clientId) return\n const data = event.data as PageMessage | undefined\n if (data?.type === 'sia-client') {\n const reply: ClientReply = { clientId, supported: supportsDownloads }\n event.ports[0]?.postMessage(reply)\n event.ports[0]?.close()\n } else if (data?.type === 'sia-release' && typeof data.token === 'string') {\n // The session outlives its last source until IDLE_TIMEOUT, so moving to\n // the next file reuses the connected SDK.\n const source = sources.get(key(clientId, data.token))\n if (source) dropSource(source)\n } else if (\n data?.type === 'sia-release-share' &&\n typeof data.session === 'string'\n ) {\n const sessionKey = key(clientId, data.session)\n released.add(sessionKey)\n const session = sessions.get(sessionKey)\n if (session) event.waitUntil(disposeSession(session))\n }\n })\n scope.addEventListener('fetch', (event) => {\n const url = new URL(event.request.url)\n if (url.origin !== scope.location.origin) return\n const stream = parseStreamPath(url.pathname)\n if (!stream) return\n const download = url.searchParams.get('download') === '1'\n const warm = url.searchParams.get('warm') === '1'\n event.respondWith(\n serve(event.request, stream.clientId, stream.token, { download, warm }),\n )\n })\n}\n\n/**\n * Exactly `length` bytes from `chunks`, or an error if the SDK stream ends\n * early or runs over. Each pull reads one chunk, so backpressure reaches the SDK.\n */\nfunction rangeBody(job: Job, chunks: Chunks, length: number) {\n let remaining = length\n return new ReadableStream<Uint8Array>(\n {\n start(controller) {\n job.controller = controller\n },\n async pull(controller) {\n try {\n const { done, value } = await chunks.read()\n if (job.closed) return\n if (done) {\n if (remaining !== 0) {\n throw new Error(\n 'Shared file stream ended before all bytes arrived.',\n )\n }\n controller.close()\n job.finish()\n return\n }\n remaining -= value.byteLength\n if (remaining < 0) {\n throw new Error('Shared file stream exceeded the requested length.')\n }\n controller.enqueue(value)\n const reporter = job.quiet ? undefined : job.source?.reporter\n reporter?.status('downloading')\n reporter?.bytes(value.byteLength)\n if (remaining === 0) {\n controller.close()\n job.finish(true)\n }\n } catch (error) {\n job.fail(error)\n }\n },\n cancel() {\n job.finish(true)\n return job.lifetime\n },\n },\n { highWaterMark: 0 },\n )\n}\n\ntype Reporter = {\n wants: { shards: boolean }\n status(status: StreamStatus): void\n bytes(count: number): void\n shard(progress: ShardProgress): void\n stop(): void\n}\n\n/**\n * Status and progress messages for one stream URL, sent to the page that made\n * it. Statuses go at once and only when they change. Bytes and shards collect\n * for REPORT_INTERVAL. After `stop`, every call does nothing, since the SDK\n * can still report a shard from a download being cancelled.\n */\nfunction createReporter(\n client: StreamClient,\n token: string,\n events: StreamEvent[],\n): Reporter {\n const wants = {\n status: events.includes('status'),\n progress: events.includes('progress'),\n shards: events.includes('shards'),\n }\n let stopped = false\n let current: StreamStatus | undefined\n let bytes = 0\n let shards: ShardProgress[] = []\n let timer: ReturnType<typeof setTimeout> | undefined\n\n function post(message: WorkerMessage) {\n try {\n client.postMessage(message)\n } catch {\n // The owning tab may already be gone.\n }\n }\n function flush() {\n clearTimeout(timer)\n timer = undefined\n if (stopped || (bytes === 0 && shards.length === 0)) return\n post({ type: 'sia-stream-progress', token, bytes, shards })\n bytes = 0\n shards = []\n }\n function schedule() {\n timer ??= setTimeout(flush, REPORT_INTERVAL)\n }\n function status(next: StreamStatus) {\n if (stopped || next === current) return\n flush()\n current = next\n if (wants.status) post({ type: 'sia-stream-status', token, status: next })\n }\n\n return {\n wants,\n status,\n bytes(count) {\n if (stopped || !wants.progress) return\n bytes += count\n schedule()\n },\n shard({ hostKey, shardSize, shardIndex, slabIndex, elapsedMs }) {\n if (stopped) return\n // Copied field by field, so only plain data crosses to the page.\n shards.push({ hostKey, shardSize, shardIndex, slabIndex, elapsedMs })\n schedule()\n },\n stop() {\n stopped = true\n clearTimeout(timer)\n timer = undefined\n shards = []\n },\n }\n}\n"],"mappings":"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","names":["source"]}
1
+ {"version":3,"sources":["../src/stream-worker.ts","../src/stream/response.ts","../src/stream/worker.ts"],"sourcesContent":["/**\n * The worker side of streaming, for sites that already run a service worker.\n *\n * A page has only one service worker, so a site with its own calls\n * `installStreams(self)` in it and passes that worker's URL to\n * `enableStreaming`. Every other site serves the prebuilt `sia-storage-sw.js`,\n * which is this function with the WebAssembly built in.\n */\nimport wasmInit, {\n AppKey,\n Builder,\n type InitInput,\n PinnedObject,\n SharedSdk,\n} from '../wasm/sia_storage_wasm.js'\nimport type { Connection } from './stream/protocol'\nimport { serveStreams, type StreamScope, type StreamSdk } from './stream/worker'\n\nexport type { StreamScope }\n\nexport type InstallStreamsOptions = {\n /**\n * The SDK's WebAssembly, as a URL, bytes or compiled module. Only needed\n * when the worker's bundler does not emit `sia_storage_wasm_bg.wasm`.\n */\n wasm?: InitInput\n}\n\nexport function installStreams(\n scope: StreamScope,\n options: InstallStreamsOptions = {},\n) {\n let ready: Promise<unknown> | undefined\n serveStreams(\n scope,\n async (connection) => {\n ready ??= wasmInit(\n options.wasm === undefined ? undefined : { module_or_path: options.wasm },\n )\n await ready\n return connection.kind === 'shared'\n ? connectShared(connection)\n : connectApp(connection)\n },\n // Downloads from hosts need WebTransport, which some browsers leave out\n // of service workers. The page then reads objects itself.\n typeof WebTransport === 'function',\n )\n}\n\nasync function connectShared({\n indexerUrl,\n seed,\n sealKey,\n}: Extract<Connection, { kind: 'shared' }>): Promise<StreamSdk> {\n // Built before connecting, so a key that fails to load cannot leave a\n // connected SDK behind with nothing to free it.\n const key = sealKey === undefined ? undefined : new AppKey(fromHex(sealKey))\n let sdk: SharedSdk\n try {\n sdk = await SharedSdk.connect(indexerUrl, seed)\n } catch (error) {\n key?.free()\n throw error\n }\n return {\n // The page sealed the object it already had with the share's random key.\n // Opening that saves a round trip to the indexer before every stream's\n // first byte.\n object: async ({ objectId, sealed }) =>\n key && sealed ? PinnedObject.open(key, sealed) : sdk.object(objectId),\n download: (object, options) => sdk.download(object, options),\n free: () => {\n sdk.free()\n key?.free()\n },\n }\n}\n\nasync function connectApp({\n indexerUrl,\n appKey,\n appMeta,\n}: Extract<Connection, { kind: 'app' }>): Promise<StreamSdk> {\n const key = new AppKey(fromHex(appKey))\n const builder = new Builder(indexerUrl, appMeta)\n try {\n const sdk = await builder.connected(key)\n if (!sdk) throw new Error('The app key is not registered with the indexer.')\n return {\n // The page sent the object sealed with this key, so no lookup is needed.\n object: async ({ sealed }) => PinnedObject.open(key, sealed!),\n download: (object, options) => sdk.download(object, options),\n free: () => {\n sdk.free()\n key.free()\n },\n }\n } catch (error) {\n key.free()\n throw error\n } finally {\n builder.free()\n }\n}\n\n// Uint8Array.fromHex is too new for some browsers that run service workers.\nfunction fromHex(hex: string) {\n return Uint8Array.from(hex.match(/../g) ?? [], (byte) => parseInt(byte, 16))\n}\n","// File bytes come from whoever owns the share, so the browser must never cache\n// them or run them as this origin's content.\nconst PROTECTIVE_HEADERS = {\n 'Cache-Control': 'no-store',\n 'X-Content-Type-Options': 'nosniff',\n 'Content-Security-Policy': \"sandbox; default-src 'none'\",\n 'Referrer-Policy': 'no-referrer',\n}\n\nexport type ByteRange = {\n status: 200 | 206 | 416\n offset: number\n length: number\n}\n\nexport function parseRange(range: string | null, size: number): ByteRange {\n if (!Number.isSafeInteger(size) || size < 0) {\n throw new RangeError('Invalid file size')\n }\n if (range === null) return { status: 200, offset: 0, length: size }\n\n const invalid: ByteRange = { status: 416, offset: 0, length: 0 }\n const match = /^bytes=(\\d*)-(\\d*)$/i.exec(range.trim())\n if (!match || (!match[1] && !match[2]) || size === 0) return invalid\n // Both groups always participate in a match, possibly as empty strings.\n const start = match[1]!\n const end = match[2]!\n\n // Range numerals are not limited to JS's safe integers. Compare before converting.\n const total = BigInt(size)\n let first: bigint\n let last: bigint\n if (!start) {\n const suffix = BigInt(end)\n if (suffix === 0n) return invalid\n first = suffix >= total ? 0n : total - suffix\n last = total - 1n\n } else {\n first = BigInt(start)\n last = end ? BigInt(end) : total - 1n\n if (first >= total || last < first) return invalid\n if (last >= total) last = total - 1n\n }\n return {\n status: 206,\n offset: Number(first),\n length: Number(last - first + 1n),\n }\n}\n\nexport function contentDisposition(name: string, download: boolean) {\n // TextEncoder replaces lone surrogates without requiring toWellFormed(),\n // which older browsers with module service workers do not implement.\n const wellFormed = new TextDecoder().decode(new TextEncoder().encode(name))\n const filename =\n wellFormed\n // Filenames must not contain header controls or path separators.\n // eslint-disable-next-line no-control-regex\n .replace(/[\\u0000-\\u001f\\u007f/\\\\]/g, '_')\n .trim() || 'download'\n const fallback = filename.replace(/[^\\u0020-\\u007e]|[\";]/g, '_')\n const encoded = encodeURIComponent(filename).replace(\n /[!'()*]/g,\n (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`,\n )\n return `${download ? 'attachment' : 'inline'}; filename=\"${fallback}\"; filename*=UTF-8''${encoded}`\n}\n\nexport function responseHeaders(\n metadata: { name: string; mime: string; size: number },\n range: ByteRange,\n download: boolean,\n) {\n // Only use a media type, never arbitrary header syntax from shared metadata.\n const mime = (metadata.mime.split(';', 1)[0] ?? '').trim()\n const headers = new Headers({\n 'Accept-Ranges': 'bytes',\n 'Content-Length': String(range.length),\n 'Content-Type': /^[\\w!#$&^.+-]+\\/[\\w!#$&^.+-]+$/.test(mime)\n ? mime\n : 'application/octet-stream',\n 'Content-Disposition': contentDisposition(metadata.name, download),\n ...PROTECTIVE_HEADERS,\n })\n if (range.status === 206) {\n headers.set(\n 'Content-Range',\n `bytes ${range.offset}-${range.offset + range.length - 1}/${metadata.size}`,\n )\n } else if (range.status === 416) {\n headers.set('Content-Range', `bytes */${metadata.size}`)\n }\n return headers\n}\n\nexport function errorResponse(status: number) {\n const headers = new Headers(PROTECTIVE_HEADERS)\n if (status === 405) headers.set('Allow', 'GET, HEAD')\n return new Response(null, { status, headers })\n}\n","import type {\n PinnedObject,\n ShardProgress,\n} from '../../wasm/sia_storage_wasm.js'\nimport { streamErrorMessage } from './errors'\nimport {\n type ClientReply,\n isSourceReply,\n type PageMessage,\n parseStreamPath,\n requestReply,\n type Connection,\n type SourceDetails,\n type StreamEvent,\n type StreamStatus,\n type WorkerMessage,\n} from './protocol'\nimport {\n type ByteRange,\n errorResponse,\n parseRange,\n responseHeaders,\n} from './response'\n\nconst SOURCE_TIMEOUT = 5_000\nconst IDLE_TIMEOUT = 5 * 60_000\n// How long bytes and shard reports for one URL collect before they are sent,\n// so a stream costs a few messages a second rather than one per chunk.\nconst REPORT_INTERVAL = 100\n\n/** An object as the page describes it. See `SourceDetails`. */\nexport type ObjectRef = Pick<SourceDetails, 'objectId' | 'sealed'>\n\n/** A connected SDK of either kind, as the worker uses it. */\nexport type StreamSdk = {\n object(ref: ObjectRef): Promise<PinnedObject>\n download(\n object: PinnedObject,\n options: {\n offset: number\n length: number\n onShardDownloaded?: (progress: ShardProgress) => void\n },\n ): ReadableStream\n free(): void\n}\n\n// The parts of ServiceWorkerGlobalScope this module uses, written out so it\n// type-checks alongside page code, whose DOM types conflict with the service\n// worker ones. A real ServiceWorkerGlobalScope satisfies them.\ntype StreamClient = { id: string; postMessage(message: unknown, transfer?: Transferable[]): void }\ntype WaitUntil = { waitUntil(promise: Promise<unknown>): void }\ntype StreamFetchEvent = { request: Request; respondWith(response: Promise<Response>): void }\ntype StreamMessageEvent = WaitUntil & {\n data: unknown\n source: unknown\n ports: readonly MessagePort[]\n}\nexport type StreamScope = {\n location: { origin: string }\n skipWaiting(): Promise<void>\n clients: {\n get(id: string): Promise<StreamClient | undefined>\n claim(): Promise<void>\n }\n addEventListener(type: 'install' | 'activate', listener: (event: WaitUntil) => void): void\n addEventListener(type: 'message', listener: (event: StreamMessageEvent) => void): void\n addEventListener(type: 'fetch', listener: (event: StreamFetchEvent) => void): void\n}\ntype Metadata = Pick<\n SourceDetails,\n 'objectId' | 'sealed' | 'name' | 'mime' | 'size'\n>\ntype Chunks = ReadableStreamDefaultReader<Uint8Array>\n\n/** One page's open share, and the SDK the worker connects for it on first use. */\ntype Session = {\n key: string\n connection: Connection\n sources: Set<Source>\n objects: Map<string, Promise<PinnedObject>>\n // One `Job.lifetime` per request in flight.\n jobs: Set<Promise<void>>\n closed: boolean\n timer?: ReturnType<typeof setTimeout>\n sdk?: Promise<StreamSdk>\n}\n\n/** One stream token, resolved to its file by asking the page that made it. */\ntype Source = {\n key: string\n client: StreamClient\n closed: boolean\n // The `abort` of each job serving this token.\n requests: Set<() => void>\n ready: Promise<Metadata>\n setup: AbortController\n session?: Session\n // Set when the page asked for status and progress messages.\n reporter?: Reporter\n // Requests for this URL past their HEAD and range checks and not yet\n // settled. Its status is `idle` while this is zero.\n reading: number\n}\n\n/** One HTTP request for a stream URL, from the first await to its last byte. */\ntype Job = {\n closed: boolean\n lifetime: Promise<void>\n source?: Source\n session?: Session\n range?: ByteRange\n // Counted in `source.reading` until the job settles.\n reading?: boolean\n // A warm-up read, which reports nothing to the page.\n quiet?: boolean\n reader?: Chunks\n controller?: ReadableStreamDefaultController<Uint8Array>\n finish(cancel?: boolean): void\n abort(): void\n fail(error: unknown): void\n}\n\n// The control port carries credentials and metadata only. Bytes never leave\n// this worker, since each response consumes the SDK's own stream with native\n// backpressure.\nexport function serveStreams(\n scope: StreamScope,\n connect: (connection: Connection) => Promise<StreamSdk>,\n supportsDownloads: boolean,\n) {\n const sources = new Map<string, Source>()\n const sessions = new Map<string, Session>()\n // Released session keys. A page reply already in flight when its share is\n // released must not bring the session back.\n const released = new Set<string>()\n // Requests in flight per page, by client id. See `hold`.\n const active = new Map<string, number>()\n const key = (clientId: string, id: string) => JSON.stringify([clientId, id])\n\n function tellStreaming(client: StreamClient, streaming: boolean) {\n try {\n client.postMessage({\n type: 'sia-streaming',\n active: streaming,\n } satisfies WorkerMessage)\n } catch {\n // The owning tab may already be gone.\n }\n }\n\n /**\n * Counts a request against its page until `lifetime` settles. Firefox stops\n * a worker 30 seconds after the last event it received, even mid-response,\n * and saves a download cut off that way as if it were complete. While a page\n * has a request here it sends keep-alive messages, and each one restarts\n * that timer.\n */\n function hold(client: StreamClient, lifetime: Promise<void>) {\n const count = (active.get(client.id) ?? 0) + 1\n active.set(client.id, count)\n if (count === 1) tellStreaming(client, true)\n void lifetime.then(() => {\n const left = active.get(client.id)! - 1\n if (left > 0) {\n active.set(client.id, left)\n return\n }\n active.delete(client.id)\n tellStreaming(client, false)\n })\n }\n\n function idle(session: Session) {\n clearTimeout(session.timer)\n if (!session.closed && session.jobs.size === 0) {\n session.timer = setTimeout(\n () => void disposeSession(session),\n IDLE_TIMEOUT,\n )\n }\n }\n\n function sessionFor(clientId: string, details: SourceDetails) {\n const sessionKey = key(clientId, details.session)\n let session = sessions.get(sessionKey)\n if (!session) {\n session = {\n key: sessionKey,\n connection: details.connection,\n sources: new Set(),\n objects: new Map(),\n jobs: new Set(),\n closed: false,\n }\n sessions.set(sessionKey, session)\n }\n return session\n }\n\n async function disposeSession(session: Session) {\n if (session.closed) return\n session.closed = true\n sessions.delete(session.key)\n clearTimeout(session.timer)\n for (const source of session.sources) dropSource(source)\n // Do not free wasm handles while a connect, lookup or cancellation uses them.\n await Promise.allSettled(session.jobs)\n await Promise.allSettled(\n [...session.objects.values()].map(async (object) =>\n (await object).free(),\n ),\n )\n try {\n ;(await session.sdk)?.free()\n } catch {\n // Connection failures are reported by the request, not during disposal.\n }\n }\n\n // A failed connect or lookup is forgotten, so the next request retries it\n // instead of failing with the cached error.\n function sdkFor(session: Session) {\n if (session.sdk) return session.sdk\n const { connection } = session\n const connecting = Promise.resolve().then(() => connect(connection))\n session.sdk = connecting\n connecting.catch(() => {\n if (session.sdk === connecting) delete session.sdk\n })\n return connecting\n }\n\n function objectFor(session: Session, sdk: StreamSdk, ref: ObjectRef) {\n const { objectId } = ref\n const cached = session.objects.get(objectId)\n if (cached) return cached\n const lookup = Promise.resolve().then(() => sdk.object(ref))\n session.objects.set(objectId, lookup)\n lookup.catch(() => {\n if (session.objects.get(objectId) === lookup) {\n session.objects.delete(objectId)\n }\n })\n return lookup\n }\n\n function getSource(client: StreamClient, token: string) {\n const sourceKey = key(client.id, token)\n const cached = sources.get(sourceKey)\n if (cached) return cached\n const setup = new AbortController()\n const request = { type: 'sia-source', token } satisfies WorkerMessage\n const ready = requestReply(client, request, {\n timeout: SOURCE_TIMEOUT,\n signal: setup.signal,\n }).then((reply) => {\n if (!isSourceReply(reply)) {\n throw new Error('Shared file source unavailable.')\n }\n if (source.closed || released.has(key(client.id, reply.session))) {\n throw new DOMException('Released', 'AbortError')\n }\n const session = sessionFor(client.id, reply)\n source.session = session\n session.sources.add(source)\n if (reply.events?.length) {\n source.reporter = createReporter(client, token, reply.events)\n }\n idle(session)\n // Keep credentials in the session record, never in response metadata.\n const { objectId, sealed, name, mime, size } = reply\n return { objectId, sealed, name, mime, size }\n })\n const source: Source = {\n key: sourceKey,\n client,\n closed: false,\n requests: new Set(),\n ready,\n setup,\n reading: 0,\n }\n sources.set(sourceKey, source)\n return source\n }\n\n function dropSource(source: Source) {\n if (source.closed) return\n source.closed = true\n sources.delete(source.key)\n source.reporter?.stop()\n source.setup.abort(new DOMException('Released', 'AbortError'))\n for (const cancel of source.requests) cancel()\n source.session?.sources.delete(source)\n }\n\n /**\n * Tracks one request until it settles, whichever way that happens: its last\n * byte, the page aborting it, its source being released, or an SDK failure.\n */\n function startJob(request: Request, token: string): Job {\n let complete = () => {}\n // Kept out of event.waitUntil. Chromium kills a worker whose event runs\n // past 5 minutes, which would end any download still running at that mark.\n // The page's keep-alive messages, started by `hold`, keep Firefox's worker\n // running instead.\n const lifetime = new Promise<void>((resolve) => {\n complete = resolve\n })\n const job: Job = {\n closed: false,\n lifetime,\n finish(cancel = false) {\n if (job.closed) return\n job.closed = true\n request.signal.removeEventListener('abort', job.abort)\n const { reader } = job\n const cancellation =\n cancel && reader ? reader.cancel().catch(() => {}) : undefined\n void Promise.resolve(cancellation).finally(() => {\n reader?.releaseLock()\n const { source } = job\n source?.requests.delete(job.abort)\n if (source && job.reading && --source.reading === 0) {\n source.reporter?.status('idle')\n }\n job.session?.jobs.delete(lifetime)\n if (job.session) idle(job.session)\n complete()\n })\n },\n abort() {\n if (job.closed) return\n job.controller?.error(new DOMException('Aborted', 'AbortError'))\n job.finish(true)\n },\n fail(error) {\n if (job.closed) return\n const message = streamErrorMessage(error)\n const aborted = error instanceof Error && error.name === 'AbortError'\n const { source, range } = job\n // A warm-up is invisible to the page, failures included. The play\n // that follows connects again and reports its own failure.\n if (!aborted && !job.quiet && source && !source.closed) {\n // Diagnostics go only to the owning page. Never log SDK objects here.\n try {\n source.client.postMessage({\n type: 'sia-stream-error',\n token,\n message,\n ...(range && { offset: range.offset, length: range.length }),\n } satisfies WorkerMessage)\n } catch {\n // The owning tab may already be gone.\n }\n }\n job.controller?.error(new Error(message))\n job.finish(true)\n },\n }\n return job\n }\n\n async function serve(\n request: Request,\n clientId: string,\n token: string,\n { download, warm }: { download: boolean; warm: boolean },\n ): Promise<Response> {\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n return errorResponse(405)\n }\n if (!supportsDownloads) return errorResponse(503)\n const job = startJob(request, token)\n job.quiet = warm\n try {\n const client = await scope.clients.get(clientId)\n if (!client || request.signal.aborted) return errorResponse(404)\n hold(client, job.lifetime)\n const source = getSource(client, token)\n job.source = source\n source.requests.add(job.abort)\n request.signal.addEventListener('abort', job.abort, { once: true })\n const metadata = await source.ready\n if (job.closed) return errorResponse(502)\n // Set by `ready` before it resolves.\n const session = source.session!\n job.session = session\n session.jobs.add(job.lifetime)\n clearTimeout(session.timer)\n const range = parseRange(\n request.method === 'HEAD' ? null : request.headers.get('range'),\n metadata.size,\n )\n job.range = range\n const headers = responseHeaders(metadata, range, download)\n if (request.method === 'HEAD' || range.status === 416) {\n job.finish()\n return new Response(null, { status: range.status, headers })\n }\n // A warm-up is invisible to the page, so a player that warms a file\n // does not see it go connecting and downloading before Play.\n const reporter = warm ? undefined : source.reporter\n job.reading = !warm\n // A read that starts while another is already downloading leaves the\n // status at `downloading`.\n if (!warm && ++source.reading === 1) reporter?.status('connecting')\n // A zero-byte file reports connecting then idle, as a read in the page\n // does, without starting an SDK download.\n if (range.length === 0) {\n job.finish()\n return new Response(null, { status: range.status, headers })\n }\n const sdk = await sdkFor(session)\n if (job.closed) return errorResponse(502)\n const object = await objectFor(session, sdk, metadata)\n if (job.closed) return errorResponse(502)\n const chunks: Chunks = sdk\n .download(object, {\n offset: range.offset,\n length: range.length,\n ...(reporter?.wants.shards && {\n onShardDownloaded: (progress) => reporter.shard(progress),\n }),\n })\n .getReader()\n job.reader = chunks\n return new Response(rangeBody(job, chunks, range.length), {\n status: range.status,\n headers,\n })\n } catch (error) {\n job.fail(error)\n if (job.source && !job.source.session) dropSource(job.source)\n return errorResponse(502)\n }\n }\n\n scope.addEventListener('install', (event) =>\n event.waitUntil(scope.skipWaiting()),\n )\n scope.addEventListener('activate', (event) =>\n event.waitUntil(scope.clients.claim()),\n )\n scope.addEventListener('message', (event) => {\n const source = event.source as Partial<StreamClient> | null\n const clientId = typeof source?.id === 'string' ? source.id : undefined\n if (!clientId) return\n const data = event.data as PageMessage | undefined\n if (data?.type === 'sia-client') {\n const reply: ClientReply = { clientId, supported: supportsDownloads }\n event.ports[0]?.postMessage(reply)\n event.ports[0]?.close()\n } else if (data?.type === 'sia-release' && typeof data.token === 'string') {\n // The session outlives its last source until IDLE_TIMEOUT, so moving to\n // the next file reuses the connected SDK.\n const source = sources.get(key(clientId, data.token))\n if (source) dropSource(source)\n } else if (\n data?.type === 'sia-release-share' &&\n typeof data.session === 'string'\n ) {\n const sessionKey = key(clientId, data.session)\n released.add(sessionKey)\n const session = sessions.get(sessionKey)\n if (session) event.waitUntil(disposeSession(session))\n } else if (data?.type === 'sia-keep-alive' && !active.has(clientId)) {\n // A worker stopped mid-stream never sent the page `active: false`, so the\n // one that answers this keep-alive does.\n tellStreaming(source as StreamClient, false)\n }\n })\n scope.addEventListener('fetch', (event) => {\n const url = new URL(event.request.url)\n if (url.origin !== scope.location.origin) return\n const stream = parseStreamPath(url.pathname)\n if (!stream) return\n const download = url.searchParams.get('download') === '1'\n const warm = url.searchParams.get('warm') === '1'\n event.respondWith(\n serve(event.request, stream.clientId, stream.token, { download, warm }),\n )\n })\n}\n\n/**\n * Exactly `length` bytes from `chunks`, or an error if the SDK stream ends\n * early or runs over. Each pull reads one chunk, so backpressure reaches the SDK.\n */\nfunction rangeBody(job: Job, chunks: Chunks, length: number) {\n let remaining = length\n return new ReadableStream<Uint8Array>(\n {\n start(controller) {\n job.controller = controller\n },\n async pull(controller) {\n try {\n const { done, value } = await chunks.read()\n if (job.closed) return\n if (done) {\n if (remaining !== 0) {\n throw new Error(\n 'Shared file stream ended before all bytes arrived.',\n )\n }\n controller.close()\n job.finish()\n return\n }\n remaining -= value.byteLength\n if (remaining < 0) {\n throw new Error('Shared file stream exceeded the requested length.')\n }\n controller.enqueue(value)\n const reporter = job.quiet ? undefined : job.source?.reporter\n reporter?.status('downloading')\n reporter?.bytes(value.byteLength)\n if (remaining === 0) {\n controller.close()\n job.finish(true)\n }\n } catch (error) {\n job.fail(error)\n }\n },\n cancel() {\n job.finish(true)\n return job.lifetime\n },\n },\n { highWaterMark: 0 },\n )\n}\n\ntype Reporter = {\n wants: { shards: boolean }\n status(status: StreamStatus): void\n bytes(count: number): void\n shard(progress: ShardProgress): void\n stop(): void\n}\n\n/**\n * Status and progress messages for one stream URL, sent to the page that made\n * it. Statuses go at once and only when they change. Bytes and shards collect\n * for REPORT_INTERVAL. After `stop`, every call does nothing, since the SDK\n * can still report a shard from a download being cancelled.\n */\nfunction createReporter(\n client: StreamClient,\n token: string,\n events: StreamEvent[],\n): Reporter {\n const wants = {\n status: events.includes('status'),\n progress: events.includes('progress'),\n shards: events.includes('shards'),\n }\n let stopped = false\n let current: StreamStatus | undefined\n let bytes = 0\n let shards: ShardProgress[] = []\n let timer: ReturnType<typeof setTimeout> | undefined\n\n function post(message: WorkerMessage) {\n try {\n client.postMessage(message)\n } catch {\n // The owning tab may already be gone.\n }\n }\n function flush() {\n clearTimeout(timer)\n timer = undefined\n if (stopped || (bytes === 0 && shards.length === 0)) return\n post({ type: 'sia-stream-progress', token, bytes, shards })\n bytes = 0\n shards = []\n }\n function schedule() {\n timer ??= setTimeout(flush, REPORT_INTERVAL)\n }\n function status(next: StreamStatus) {\n if (stopped || next === current) return\n flush()\n current = next\n if (wants.status) post({ type: 'sia-stream-status', token, status: next })\n }\n\n return {\n wants,\n status,\n bytes(count) {\n if (stopped || !wants.progress) return\n bytes += count\n schedule()\n },\n shard({ hostKey, shardSize, shardIndex, slabIndex, elapsedMs }) {\n if (stopped) return\n // Copied field by field, so only plain data crosses to the page.\n shards.push({ hostKey, shardSize, shardIndex, slabIndex, elapsedMs })\n schedule()\n },\n stop() {\n stopped = true\n clearTimeout(timer)\n timer = undefined\n shards = []\n },\n }\n}\n"],"mappings":"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","names":["source"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siafoundation/sia-storage",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -72,10 +72,10 @@
72
72
  "typescript": "5.9.3"
73
73
  },
74
74
  "optionalDependencies": {
75
- "@siafoundation/sia-storage-darwin-arm64": "0.1.4",
76
- "@siafoundation/sia-storage-darwin-x64": "0.1.4",
77
- "@siafoundation/sia-storage-linux-x64-gnu": "0.1.4",
78
- "@siafoundation/sia-storage-linux-arm64-gnu": "0.1.4",
79
- "@siafoundation/sia-storage-win32-x64-msvc": "0.1.4"
75
+ "@siafoundation/sia-storage-darwin-arm64": "0.1.5",
76
+ "@siafoundation/sia-storage-darwin-x64": "0.1.5",
77
+ "@siafoundation/sia-storage-linux-x64-gnu": "0.1.5",
78
+ "@siafoundation/sia-storage-linux-arm64-gnu": "0.1.5",
79
+ "@siafoundation/sia-storage-win32-x64-msvc": "0.1.5"
80
80
  }
81
81
  }
@@ -817,13 +817,13 @@ export interface InitOutput {
817
817
  readonly intounderlyingsink_write: (a: number, b: any) => any;
818
818
  readonly intounderlyingsource_cancel: (a: number) => void;
819
819
  readonly intounderlyingsource_pull: (a: number, b: any) => any;
820
- readonly wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_: (a: number, b: number, c: any) => [number, number];
821
- readonly wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_: (a: number, b: number, c: any) => [number, number];
822
- readonly wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__3: (a: number, b: number, c: any) => [number, number];
823
- readonly wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__4: (a: number, b: number, c: any) => [number, number];
824
- readonly wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void;
825
- readonly wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue______true_: (a: number, b: number, c: any) => void;
826
- readonly wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke_______true_: (a: number, b: number) => void;
820
+ readonly wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_: (a: number, b: number, c: any) => [number, number];
821
+ readonly wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_: (a: number, b: number, c: any) => [number, number];
822
+ readonly wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__3: (a: number, b: number, c: any) => [number, number];
823
+ readonly wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__4: (a: number, b: number, c: any) => [number, number];
824
+ readonly wasm_bindgen_63576b009277873___convert__closures_____invoke___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void;
825
+ readonly wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue______true_: (a: number, b: number, c: any) => void;
826
+ readonly wasm_bindgen_63576b009277873___convert__closures_____invoke_______true_: (a: number, b: number) => void;
827
827
  readonly __wbindgen_malloc: (a: number, b: number) => number;
828
828
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
829
829
  readonly __wbindgen_exn_store: (a: number) => void;
@@ -1717,7 +1717,7 @@ function __wbg_get_imports() {
1717
1717
  const a = state0.a;
1718
1718
  state0.a = 0;
1719
1719
  try {
1720
- return wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined_______true_(a, state0.b, arg0, arg1);
1720
+ return wasm_bindgen_63576b009277873___convert__closures_____invoke___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined_______true_(a, state0.b, arg0, arg1);
1721
1721
  } finally {
1722
1722
  state0.a = a;
1723
1723
  }
@@ -1755,7 +1755,7 @@ function __wbg_get_imports() {
1755
1755
  const a = state0.a;
1756
1756
  state0.a = 0;
1757
1757
  try {
1758
- return wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined_______true_(a, state0.b, arg0, arg1);
1758
+ return wasm_bindgen_63576b009277873___convert__closures_____invoke___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined_______true_(a, state0.b, arg0, arg1);
1759
1759
  } finally {
1760
1760
  state0.a = a;
1761
1761
  }
@@ -1986,32 +1986,32 @@ function __wbg_get_imports() {
1986
1986
  },
1987
1987
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
1988
1988
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1022, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
1989
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_);
1989
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_);
1990
1990
  return ret;
1991
1991
  },
1992
1992
  __wbindgen_cast_0000000000000002: function(arg0, arg1) {
1993
1993
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 481, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
1994
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue______true_);
1994
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue______true_);
1995
1995
  return ret;
1996
1996
  },
1997
1997
  __wbindgen_cast_0000000000000003: function(arg0, arg1) {
1998
1998
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 539, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
1999
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_);
1999
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_);
2000
2000
  return ret;
2001
2001
  },
2002
2002
  __wbindgen_cast_0000000000000004: function(arg0, arg1) {
2003
2003
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("WebTransportBidirectionalStream")], shim_idx: 539, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
2004
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__3);
2004
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__3);
2005
2005
  return ret;
2006
2006
  },
2007
2007
  __wbindgen_cast_0000000000000005: function(arg0, arg1) {
2008
2008
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 539, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
2009
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__4);
2009
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__4);
2010
2010
  return ret;
2011
2011
  },
2012
2012
  __wbindgen_cast_0000000000000006: function(arg0, arg1) {
2013
2013
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 829, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
2014
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke_______true_);
2014
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_63576b009277873___convert__closures_____invoke_______true_);
2015
2015
  return ret;
2016
2016
  },
2017
2017
  __wbindgen_cast_0000000000000007: function(arg0) {
@@ -2073,44 +2073,44 @@ function __wbg_get_imports() {
2073
2073
  };
2074
2074
  }
2075
2075
 
2076
- function wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke_______true_(arg0, arg1) {
2077
- wasm.wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke_______true_(arg0, arg1);
2076
+ function wasm_bindgen_63576b009277873___convert__closures_____invoke_______true_(arg0, arg1) {
2077
+ wasm.wasm_bindgen_63576b009277873___convert__closures_____invoke_______true_(arg0, arg1);
2078
2078
  }
2079
2079
 
2080
- function wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue______true_(arg0, arg1, arg2) {
2081
- wasm.wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue______true_(arg0, arg1, arg2);
2080
+ function wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue______true_(arg0, arg1, arg2) {
2081
+ wasm.wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue______true_(arg0, arg1, arg2);
2082
2082
  }
2083
2083
 
2084
- function wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_(arg0, arg1, arg2) {
2085
- const ret = wasm.wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_(arg0, arg1, arg2);
2084
+ function wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_(arg0, arg1, arg2) {
2085
+ const ret = wasm.wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_(arg0, arg1, arg2);
2086
2086
  if (ret[1]) {
2087
2087
  throw takeFromExternrefTable0(ret[0]);
2088
2088
  }
2089
2089
  }
2090
2090
 
2091
- function wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_(arg0, arg1, arg2) {
2092
- const ret = wasm.wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_(arg0, arg1, arg2);
2091
+ function wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_(arg0, arg1, arg2) {
2092
+ const ret = wasm.wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_(arg0, arg1, arg2);
2093
2093
  if (ret[1]) {
2094
2094
  throw takeFromExternrefTable0(ret[0]);
2095
2095
  }
2096
2096
  }
2097
2097
 
2098
- function wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__3(arg0, arg1, arg2) {
2099
- const ret = wasm.wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__3(arg0, arg1, arg2);
2098
+ function wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__3(arg0, arg1, arg2) {
2099
+ const ret = wasm.wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__3(arg0, arg1, arg2);
2100
2100
  if (ret[1]) {
2101
2101
  throw takeFromExternrefTable0(ret[0]);
2102
2102
  }
2103
2103
  }
2104
2104
 
2105
- function wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__4(arg0, arg1, arg2) {
2106
- const ret = wasm.wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__4(arg0, arg1, arg2);
2105
+ function wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__4(arg0, arg1, arg2) {
2106
+ const ret = wasm.wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__4(arg0, arg1, arg2);
2107
2107
  if (ret[1]) {
2108
2108
  throw takeFromExternrefTable0(ret[0]);
2109
2109
  }
2110
2110
  }
2111
2111
 
2112
- function wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined_______true_(arg0, arg1, arg2, arg3) {
2113
- wasm.wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined_______true_(arg0, arg1, arg2, arg3);
2112
+ function wasm_bindgen_63576b009277873___convert__closures_____invoke___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined_______true_(arg0, arg1, arg2, arg3) {
2113
+ wasm.wasm_bindgen_63576b009277873___convert__closures_____invoke___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined_______true_(arg0, arg1, arg2, arg3);
2114
2114
  }
2115
2115
 
2116
2116
 
Binary file
@@ -105,13 +105,13 @@ export const intounderlyingsink_close: (a: number) => any;
105
105
  export const intounderlyingsink_write: (a: number, b: any) => any;
106
106
  export const intounderlyingsource_cancel: (a: number) => void;
107
107
  export const intounderlyingsource_pull: (a: number, b: any) => any;
108
- export const wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_: (a: number, b: number, c: any) => [number, number];
109
- export const wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true_: (a: number, b: number, c: any) => [number, number];
110
- export const wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__3: (a: number, b: number, c: any) => [number, number];
111
- export const wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___sys__Undefined__core_608f92abc48d28da___result__Result_____wasm_bindgen_a939ac12ad536d64___JsError___true__4: (a: number, b: number, c: any) => [number, number];
112
- export const wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined___js_sys_32e95d01f2c64d55___Function_fn_wasm_bindgen_a939ac12ad536d64___JsValue_____wasm_bindgen_a939ac12ad536d64___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void;
113
- export const wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke___wasm_bindgen_a939ac12ad536d64___JsValue______true_: (a: number, b: number, c: any) => void;
114
- export const wasm_bindgen_a939ac12ad536d64___convert__closures_____invoke_______true_: (a: number, b: number) => void;
108
+ export const wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_: (a: number, b: number, c: any) => [number, number];
109
+ export const wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true_: (a: number, b: number, c: any) => [number, number];
110
+ export const wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__3: (a: number, b: number, c: any) => [number, number];
111
+ export const wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___sys__Undefined__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_63576b009277873___JsError___true__4: (a: number, b: number, c: any) => [number, number];
112
+ export const wasm_bindgen_63576b009277873___convert__closures_____invoke___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined___js_sys_eaf17bee0f0de45e___Function_fn_wasm_bindgen_63576b009277873___JsValue_____wasm_bindgen_63576b009277873___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void;
113
+ export const wasm_bindgen_63576b009277873___convert__closures_____invoke___wasm_bindgen_63576b009277873___JsValue______true_: (a: number, b: number, c: any) => void;
114
+ export const wasm_bindgen_63576b009277873___convert__closures_____invoke_______true_: (a: number, b: number) => void;
115
115
  export const __wbindgen_malloc: (a: number, b: number) => number;
116
116
  export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
117
117
  export const __wbindgen_exn_store: (a: number) => void;
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/stream/errors.ts","../src/stream/protocol.ts"],"sourcesContent":["/** Only sanitized strings cross the diagnostic boundary, never raw SDK objects. */\nexport function streamErrorMessage(error: unknown): string {\n const message =\n error instanceof Error\n ? error.message\n : typeof error === 'string'\n ? error\n : 'Unknown streaming failure'\n return message\n .replace(/\\b(?:https?|wss?|sia):\\/\\/[^\\s\"'<>]+/gi, '[URL redacted]')\n .replace(/(?:bearer\\s+)[^\\s,;]+/gi, 'Bearer [redacted]')\n .replace(\n /((?:seed|share|token|key|authorization)\\s*[=:]\\s*)[^\\s,;]+/gi,\n '$1[redacted]',\n )\n .replace(/[a-f0-9]{64,}/gi, '[redacted]')\n .replace(/[\\r\\n\\t]/g, ' ')\n .slice(0, 1000)\n}\n\nexport function reportStreamError(\n error: unknown,\n name: string,\n range: { offset: number; length: number } | undefined,\n) {\n const message = streamErrorMessage(error)\n // One string rather than an object, so it reads the same in every console.\n const bytes = range\n ? ` bytes ${range.offset}-${range.offset + range.length - 1}`\n : ''\n console.error(`[Sia stream] ${streamErrorMessage(name)}${bytes}: ${message}`)\n return message\n}\n","/**\n * Messages between a page and its streaming service worker.\n *\n * Stream URLs carry only the page's client id and a random token. When the\n * worker meets a token it does not know, it asks the page that made it for the\n * file and the share's credentials. The page and a worker can come from\n * different deployed versions, so the worker checks the page's reply before\n * using it.\n */\nimport type {\n AppMetadata,\n SealedObject,\n ShardProgress,\n} from '../../wasm/sia_storage_wasm.js'\n\n/**\n * What a stream URL is doing. `connecting` is a request waiting for its first\n * bytes, which on the URL's first request includes the worker connecting its\n * SDK and finding the object. `downloading` means bytes are arriving. `idle`\n * means no request for the URL is in flight, after the last one finished, was\n * cancelled or failed.\n */\nexport type StreamStatus = 'connecting' | 'downloading' | 'idle'\n\n/** The reports a page can ask for, one per callback it was given. */\nexport type StreamEvent = 'status' | 'progress' | 'shards'\nconst STREAM_EVENTS: readonly unknown[] = ['status', 'progress', 'shards']\n\n/**\n * What the worker connects its own SDK with. A `SharedSdk` reconnects from its\n * sharing key's seed, and an `Sdk` from its app key, as hex, and app metadata.\n * A `SharedSdk`'s `sealKey` is the hex of the random key the page seals its\n * objects with. A page from before it existed sends none.\n */\nexport type Connection =\n | { kind: 'shared'; indexerUrl: string; seed: string; sealKey?: string }\n | { kind: 'app'; indexerUrl: string; appKey: string; appMeta: AppMetadata }\n\nexport type SourceDetails = {\n // One per opened SDK, so the worker can release it as a whole.\n session: string\n connection: Connection\n objectId: string\n // The object, sealed with its app key or the share's `sealKey`, so the\n // worker can open it without a lookup. Without it the worker looks the\n // object up by `objectId`.\n sealed?: SealedObject\n name: string\n mime: string\n size: number\n // The reports the page wants for this URL. The worker sends no others, and\n // asks the SDK for shard reports only when `shards` is here.\n events?: StreamEvent[]\n}\n\n/** Page to worker. */\nexport type PageMessage =\n | { type: 'sia-client' }\n | { type: 'sia-release'; token: string }\n | { type: 'sia-release-share'; session: string }\n\n/** Worker to page. */\nexport type WorkerMessage =\n | { type: 'sia-source'; token: string }\n | {\n type: 'sia-stream-error'\n token: string\n message: string\n offset?: number\n length?: number\n }\n | { type: 'sia-stream-status'; token: string; status: StreamStatus }\n | {\n type: 'sia-stream-progress'\n token: string\n // Bytes served since the previous progress message.\n bytes: number\n shards: ShardProgress[]\n }\n\n/** The worker's answer to `sia-client`. */\nexport type ClientReply = { clientId: string; supported: boolean }\n\n/** The page's answer to `sia-source`. */\nexport type SourceReply =\n | ({ type: 'source' } & SourceDetails)\n | { type: 'error' }\n\n// Stream URLs sit under the worker's scope, so a download's navigation, which\n// only a worker whose scope covers the URL can answer, reaches it on sites\n// served from a sub-path too.\nconst STREAM_PATH = /\\/__sia_stream__\\/([^/]+)\\/([^/]+)\\/[^/]+$/\n\n/** `scope` is the worker registration's scope URL, which ends in a slash. */\nexport function streamPath(scope: string, clientId: string, token: string) {\n return `${scope}__sia_stream__/${clientId}/${token}/file`\n}\n\nexport function parseStreamPath(pathname: string) {\n const match = STREAM_PATH.exec(pathname)\n return match ? { clientId: match[1]!, token: match[2]! } : undefined\n}\n\ntype Fields = Record<string, unknown> | null | undefined\n\nconst strings = (data: Fields, fields: string[]) =>\n fields.every((field) => typeof data?.[field] === 'string')\n\n/** Checked on both sides, so bad metadata fails in `openStreams`, not per request. */\nexport function isAppMetadata(value: unknown): value is AppMetadata {\n return strings(value as Fields, ['appId', 'name', 'description', 'serviceUrl'])\n}\n\n// 32 bytes as hex, which is what the worker builds an AppKey from.\nconst isKeyHex = (value: unknown) =>\n typeof value === 'string' && /^[0-9a-f]{64}$/i.test(value)\n\nfunction isConnection(value: unknown): value is Connection {\n const data = value as Fields\n if (data?.kind === 'shared') {\n return (\n strings(data, ['indexerUrl', 'seed']) &&\n (data.sealKey === undefined || isKeyHex(data.sealKey))\n )\n }\n return (\n data?.kind === 'app' &&\n strings(data, ['indexerUrl', 'appKey']) &&\n isAppMetadata(data.appMeta)\n )\n}\n\nexport function isSourceReply(\n reply: unknown,\n): reply is { type: 'source' } & SourceDetails {\n const data = reply as Fields\n return (\n data?.type === 'source' &&\n strings(data, ['session', 'objectId', 'name', 'mime']) &&\n isConnection(data.connection) &&\n (data.connection.kind === 'shared' ||\n (typeof data.sealed === 'object' && data.sealed !== null)) &&\n Number.isSafeInteger(data.size) &&\n (data.size as number) >= 0 &&\n (data.events === undefined ||\n (Array.isArray(data.events) &&\n data.events.every((event) => STREAM_EVENTS.includes(event))))\n )\n}\n\n/**\n * Posts `message` with a reply port and resolves with the first reply. Rejects\n * after `timeout` ms, or when `signal` aborts.\n */\nexport function requestReply(\n target: { postMessage(message: unknown, transfer: Transferable[]): void },\n message: unknown,\n { timeout, signal }: { timeout?: number; signal?: AbortSignal },\n): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const { port1, port2 } = new MessageChannel()\n const timer =\n timeout === undefined\n ? undefined\n : setTimeout(\n () => settle(() => reject(new Error('No reply in time.'))),\n timeout,\n )\n const abort = () => settle(() => reject(signal?.reason))\n function settle(outcome: () => void) {\n clearTimeout(timer)\n signal?.removeEventListener('abort', abort)\n port1.close()\n port2.close()\n outcome()\n }\n if (signal?.aborted) return abort()\n signal?.addEventListener('abort', abort, { once: true })\n port1.onmessage = ({ data }) => settle(() => resolve(data))\n port1.onmessageerror = () =>\n settle(() => reject(new Error('Unreadable reply.')))\n try {\n target.postMessage(message, [port2])\n } catch (error) {\n settle(() => reject(error))\n }\n })\n}\n"],"mappings":"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","names":[]}