@prisma/composer-prisma-cloud 0.1.0-dev.10 → 0.1.0-dev.12
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.
- package/dist/control.d.mts +1 -1
- package/dist/control.mjs +122 -5
- package/dist/control.mjs.map +1 -1
- package/dist/cron/index.mjs +10 -2
- package/dist/cron/index.mjs.map +1 -1
- package/dist/cron/scheduler-entrypoint.mjs +10 -0
- package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
- package/dist/cron/scheduler-service.mjs +10 -2
- package/dist/cron/scheduler-service.mjs.map +1 -1
- package/dist/index.d.mts +40 -1
- package/dist/index.mjs +41 -1
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.mjs +10 -2
- package/dist/storage/index.mjs.map +1 -1
- package/dist/storage/storage-entrypoint.mjs +10 -0
- package/dist/storage/storage-entrypoint.mjs.map +1 -1
- package/dist/storage/storage-service.mjs +10 -2
- package/dist/storage/storage-service.mjs.map +1 -1
- package/dist/streams/index.mjs +10 -2
- package/dist/streams/index.mjs.map +1 -1
- package/dist/streams/streams-entrypoint.mjs +10 -0
- package/dist/streams/streams-entrypoint.mjs.map +1 -1
- package/dist/streams/streams-service.mjs +10 -2
- package/dist/streams/streams-service.mjs.map +1 -1
- package/package.json +14 -14
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streams-service.mjs","names":[],"sources":["../../../../1-prisma-cloud/1-extensions/target/dist/serializer-CX4VYdf_.mjs","../../../../1-prisma-cloud/1-extensions/target/dist/provisioned-edges-DIQAR4q4.mjs","../../../../1-prisma-cloud/1-extensions/target/dist/index.mjs","../../../../1-prisma-cloud/2-shared-modules/storage/dist/storage-service-BQdOiMsW.mjs","../../../../1-prisma-cloud/2-shared-modules/streams/dist/streams-service-Br5Tj3AY.mjs"],"sourcesContent":["import { secretSource } from \"@internal/core\";\nimport { blindCast } from \"@internal/foundation/casts\";\n//#region src/secret.ts\n/**\n* Brands the payload `envSecret` builds. Core's `secretSource()` is a public\n* SPI, so a user could bypass `envSecret` and bind a raw `secretSource('x')`;\n* the brand lets `secretName` reject such a source (or another target's) with a\n* clear error instead of reading an absent `.name`.\n*/\nconst PRISMA_CLOUD_SECRET_SOURCE = blindCast(Symbol.for(\"prisma:prisma-cloud-secret-source\"));\nconst RESERVED_SECRET_PREFIX = \"COMPOSER_\";\nconst POISONED_SECRET_NAMES = /* @__PURE__ */ new Set([\"DATABASE_URL\", \"DATABASE_URL_POOLED\"]);\n/**\n* Binds a secret slot to a named Prisma Cloud platform env var (ADR-0029). The\n* value is provisioned out-of-band; only the name is carried. The name may not\n* use the framework's reserved `COMPOSER_` prefix or the poisoned\n* `DATABASE_URL(_POOLED)` keys.\n*/\nfunction envSecret(name) {\n\tif (typeof name !== \"string\" || name.length === 0) throw new Error(\"envSecret() requires a non-empty platform env-var name, e.g. envSecret('STRIPE_SECRET_KEY').\");\n\tif (name.startsWith(RESERVED_SECRET_PREFIX)) throw new Error(`envSecret name \"${name}\" may not start with \"${RESERVED_SECRET_PREFIX}\" — that prefix is reserved for the framework's own generated config keys.`);\n\tif (POISONED_SECRET_NAMES.has(name)) throw new Error(`envSecret name \"${name}\" is reserved — ${[...POISONED_SECRET_NAMES].join(\" and \")} are poisoned at project provision and cannot back a secret.`);\n\treturn secretSource({\n\t\t[PRISMA_CLOUD_SECRET_SOURCE]: true,\n\t\tname\n\t});\n}\n/** True only for a payload that `envSecret` built — i.e. one carrying the brand. */\nfunction isEnvSecretPayload(payload) {\n\treturn typeof payload === \"object\" && payload !== null && blindCast(payload)[PRISMA_CLOUD_SECRET_SOURCE] === true;\n}\n/**\n* Reads the Prisma Cloud env-var name back out of a secret binding's opaque\n* source. A source not built by `envSecret` (a raw `secretSource(...)` or\n* another target's source) carries no name — reject it here. `secretName` runs\n* in preflight before any provisioning, so a foreign source fails early and\n* clearly rather than producing a broken deploy with an undefined name.\n*/\nfunction secretName(binding) {\n\tconst payload = binding.source.payload;\n\tif (!isEnvSecretPayload(payload)) throw new Error(`secret slot \"${binding.slot}\" of service \"${binding.serviceAddress}\" is bound to a source not created by envSecret() — bind secrets with envSecret('NAME') from @prisma/composer-prisma-cloud.`);\n\treturn payload.name;\n}\n//#endregion\n//#region src/serializer.ts\n/**\n* Walks a node's own params, then each dependency input's connection params —\n* the same enumeration order `configOf` uses, but carrying the raw\n* `ConfigParam` (with its `serialize`/`deserialize`) instead of a pure-data\n* projection.\n*/\nfunction paramEntries(node) {\n\tconst entries = [];\n\tfor (const [input, value] of Object.entries(node.inputs)) {\n\t\tif (typeof value !== \"object\" || value === null) continue;\n\t\tconst params = blindCast(value).connection.params;\n\t\tfor (const [name, param] of Object.entries(params)) entries.push({\n\t\t\towner: { input },\n\t\t\tname,\n\t\t\tparam\n\t\t});\n\t}\n\tfor (const [name, param] of Object.entries(node.params)) entries.push({\n\t\towner: \"service\",\n\t\tname,\n\t\tparam\n\t});\n\treturn entries;\n}\nconst configKey = (address, d) => {\n\tconst segments = address.split(\".\").filter((s) => s.length > 0);\n\tconst owner = d.owner === \"service\" ? [] : [d.owner.input];\n\treturn [\n\t\t\"COMPOSER\",\n\t\t...segments,\n\t\t...owner,\n\t\td.name\n\t].join(\"_\").toUpperCase();\n};\n/**\n* Typed value → its stored string. Service-own literals are JSON-encoded; a\n* dependency-input value is a provisioning ref at deploy (and a resolved\n* string at boot) and passes through untouched — LANDMINE: JSON-encoding it\n* would break the ordering edge Alchemy resolves through it.\n*/\nfunction encode(owner, value) {\n\treturn owner === \"service\" ? JSON.stringify(value) : blindCast(value);\n}\n/** Reverses `encode`: JSON-parse a service-own value, take a dependency-input value raw. */\nfunction decode(owner, raw) {\n\treturn owner === \"service\" ? JSON.parse(raw) : raw;\n}\nconst PARAM_POINTER_PREFIX = \"@composer-param-pointer:\";\n/** True iff `raw` is a param pointer row (as opposed to a JSON-encoded literal). */\nconst isParamPointerRow = (raw) => raw.startsWith(PARAM_POINTER_PREFIX);\n/** Builds a param pointer row's stored value from the platform var NAME it points to. */\nconst encodeParamPointer = (name) => `${PARAM_POINTER_PREFIX}${name}`;\n/** Reverses `encodeParamPointer`: the platform var NAME a pointer row points to. */\nconst decodeParamPointer = (raw) => raw.slice(24);\nfunction coerce(raw, d, key) {\n\tif (!(raw !== void 0 && raw !== \"\")) {\n\t\tif (d.param.default !== void 0) return d.param.default;\n\t\tif (d.param.optional === true) return void 0;\n\t\tthrow new Error(`missing required config param \"${d.name}\" (env ${key})`);\n\t}\n\tif (d.owner === \"service\" && isParamPointerRow(raw)) return coerceEnvSourcedParam(raw, d, key);\n\ttry {\n\t\treturn standardValidateSync(d.param.schema, decode(d.owner, raw));\n\t} catch (cause) {\n\t\tconst message = cause instanceof Error ? cause.message : String(cause);\n\t\tthrow new Error(`invalid value for config param \"${d.name}\" (env ${key}): ${message}`);\n\t}\n}\n/**\n* Boot resolution for an env-sourced param: double-lookup (pointer → platform\n* var), then the param's own schema on the raw string — no JSON decode, and\n* no redaction (it's config, not a secret). An UNSET platform var is a loud\n* boot failure naming both the param and the platform var; an EMPTY string is\n* not special-cased here — it reaches the schema like any other value, so it\n* passes iff the schema accepts it (deliberately unlike a literal param's own\n* \"\"-means-absent rule, and unlike a secret's non-empty requirement).\n*/\nfunction coerceEnvSourcedParam(raw, d, key) {\n\tconst platformVar = decodeParamPointer(raw);\n\tconst value = process.env[platformVar];\n\tif (value === void 0) throw new Error(`env-sourced config param \"${d.name}\" (env ${key} → ${platformVar}) is unset: the platform variable \"${platformVar}\" was not injected — the deploy did not provision it.`);\n\ttry {\n\t\treturn standardValidateSync(d.param.schema, value);\n\t} catch (cause) {\n\t\tconst message = cause instanceof Error ? cause.message : String(cause);\n\t\tthrow new Error(`invalid value for env-sourced config param \"${d.name}\" (env ${key} → ${platformVar}): ${message}`);\n\t}\n}\n/**\n* Boot: read each declared param from env by its key, reverse the param's own\n* serialization (missing/invalid fails loudly), assemble the typed Config.\n* Secrets ride a separate channel (deserializeSecrets), not this one.\n*/\nconst deserialize = (node, address) => {\n\tconst service = {};\n\tconst inputs = {};\n\tfor (const d of paramEntries(node)) {\n\t\tconst key = configKey(address, d);\n\t\tconst value = coerce(process.env[key], d, key);\n\t\tif (d.owner === \"service\") service[d.name] = value;\n\t\telse {\n\t\t\tlet bucket = inputs[d.owner.input];\n\t\t\tif (bucket === void 0) {\n\t\t\t\tbucket = {};\n\t\t\t\tinputs[d.owner.input] = bucket;\n\t\t\t}\n\t\t\tbucket[d.name] = value;\n\t\t}\n\t}\n\treturn {\n\t\tservice,\n\t\tinputs\n\t};\n};\n/**\n* run()'s setup step: write the resolved config to the environment under\n* address-free keys (configKey(\"\", d) + each serialize suffix), which load()\n* reads back with no address. Uses env, not a module variable, because a\n* framework may fork worker processes that inherit env but not memory.\n* Writes only these keys; nothing else is touched.\n*/\nconst stash = (node, config) => {\n\tfor (const d of paramEntries(node)) {\n\t\tconst value = d.owner === \"service\" ? config.service[d.name] : config.inputs[d.owner.input]?.[d.name];\n\t\tif (value === void 0) continue;\n\t\tprocess.env[configKey(\"\", d)] = encode(d.owner, value);\n\t}\n};\n/** The pointer-row key for a secret slot: COMPOSER_<addr>_<slot> (secrets are service-level). */\nconst secretKey = (address, slot) => configKey(address, {\n\towner: \"service\",\n\tname: slot\n});\n/**\n* Deploy: the pointer rows for a node's secret slots — each slot's key mapped to\n* the platform NAME the root bound it to (looked up in `graph.secrets`). Never a\n* value. A declared slot with no binding is a Load-invariant violation (Load\n* binds every slot), surfaced loudly here rather than written as a blank row.\n*/\nfunction secretPointerRows(node, address, bindings) {\n\tconst rows = [];\n\tfor (const slot of Object.keys(node.secretSlots)) {\n\t\tconst binding = bindings.find((b) => b.serviceAddress === address && b.slot === slot);\n\t\tif (binding === void 0) throw new Error(`secret slot \"${slot}\" of \"${address}\" has no bound platform name — Load should have bound it (ADR-0029).`);\n\t\trows.push({\n\t\t\tkey: secretKey(address, slot),\n\t\t\tname: secretName(binding)\n\t\t});\n\t}\n\treturn rows;\n}\n/**\n* Boot: resolve every secret slot to its value by double-lookup — read the\n* pointer key (the platform NAME), then read that platform var. A missing\n* pointer or a missing/empty platform value is a loud failure naming both keys.\n* Returns a plain Record for core's `hydrateSecrets` to box.\n*/\nconst deserializeSecrets = (node, address) => {\n\tconst values = {};\n\tfor (const slot of Object.keys(node.secretSlots)) {\n\t\tconst key = secretKey(address, slot);\n\t\tconst name = process.env[key];\n\t\tif (name === void 0 || name === \"\") throw new Error(`missing secret pointer for slot \"${slot}\" (env ${key}) — the deploy did not write it.`);\n\t\tconst value = process.env[name];\n\t\tif (value === void 0 || value === \"\") throw new Error(`secret \"${slot}\" is not provisioned (env ${key} → ${name}): the platform var \"${name}\" is unset or empty.`);\n\t\tvalues[slot] = value;\n\t}\n\treturn values;\n};\n/**\n* run()'s setup step for secrets: re-emit each slot's pointer NAME under its\n* address-free key, so the address-free `deserializeSecrets` double-looks-up\n* identically. Never the value — the value stays only in the platform var.\n*/\nconst stashSecrets = (node, address) => {\n\tfor (const slot of Object.keys(node.secretSlots)) {\n\t\tconst name = process.env[secretKey(address, slot)];\n\t\tif (name === void 0) continue;\n\t\tprocess.env[secretKey(\"\", slot)] = name;\n\t}\n};\n/**\n* Boot: for each reserved provider param, read its address-scoped row through\n* the same `coerce` a declared param uses (JSON-decode, schema-validate), and\n* re-emit it address-free — `stash`'s counterpart for this separate\n* declaration space. A param is declared optional here unconditionally: an\n* absent row means \"never provisioned\" (local dev, tests, a provider with no\n* registered value for this deploy), never a boot failure, so nothing is\n* stashed and the runtime reader that owns this slot falls back to its own\n* pass-through behavior.\n*/\nfunction stashProviderParams(entries, address) {\n\tfor (const entry of entries) {\n\t\tconst d = {\n\t\t\towner: \"service\",\n\t\t\tname: entry.name,\n\t\t\tparam: {\n\t\t\t\tschema: entry.schema,\n\t\t\t\toptional: true\n\t\t\t}\n\t\t};\n\t\tconst key = configKey(address, d);\n\t\tconst value = coerce(process.env[key], d, key);\n\t\tif (value === void 0) continue;\n\t\tprocess.env[configKey(\"\", d)] = encode(\"service\", value);\n\t}\n}\n/** Synchronous Standard Schema validation — see the matching note in core's `config.ts`. */\nfunction standardValidateSync(schema, value) {\n\tconst result = schema[\"~standard\"].validate(value);\n\tif (result instanceof Promise) throw new Error(\"config param schema validation must be synchronous — async Standard Schema validators are not supported for config params\");\n\tif (result.issues !== void 0) throw new Error(`config param validation failed: ${result.issues.map((issue) => issue.message).join(\"; \")}`);\n\treturn result.value;\n}\n//#endregion\nexport { encodeParamPointer as a, stash as c, envSecret as d, secretName as f, encode as i, stashProviderParams as l, deserialize as n, paramEntries as o, deserializeSecrets as r, secretPointerRows as s, configKey as t, stashSecrets as u };\n\n//# sourceMappingURL=serializer-CX4VYdf_.mjs.map","import { t as configKey } from \"./serializer-CX4VYdf_.mjs\";\nimport { isParamSource, paramSource, provisionNeed } from \"@internal/core\";\nimport { blindCast } from \"@internal/foundation/casts\";\nimport { RPC_PEER_KEY } from \"@internal/service-rpc\";\nimport { type } from \"arktype\";\n//#region src/service-keys.ts\n/**\n* RPC's reserved provider param (ADR-0030/ADR-0031): the declaration —\n* name + schema + brand — for the accepted-keys set a provider stores, shared\n* by `control.ts` (which registers the deploy-side `value(refs)` that mints\n* and aggregates it — see its `rpcAcceptedKeysValue`) and `compute.ts` (which\n* validates and stashes it at boot), so writer and reader cannot drift.\n* Finding the edges themselves is `provisioned-edges.ts`'s generic,\n* brand-blind scan — RPC is not special-cased anywhere in this target.\n*\n* This module is reachable from the RUNTIME/authoring side — it must never\n* import `@internal/lowering` or `effect`, or those tokens leak into a user\n* service's bundle (the deploy-side `value(refs)` lives in control.ts, the\n* control-plane-only entry).\n*/\n/**\n* The reserved provider param for RPC's accepted-keys set: the var name is\n* `RPC_ACCEPTED_KEYS`, derived through `configKey` at both ends\n* (`configKey(address, …)` at deploy, `configKey('', …)` at boot — the\n* address-free form is `@internal/service-rpc`'s `RPC_ACCEPTED_KEYS_ENV`). `brand` is\n* `RPC_PEER_KEY`, the same brand `perBindingToken()`'s need carries — control.ts\n* looks its `value(refs)` up by this field.\n*/\nconst RPC_ACCEPTED_KEYS_PARAM = {\n\tname: \"RPC_ACCEPTED_KEYS\",\n\tschema: type(\"string[]\"),\n\tbrand: RPC_PEER_KEY\n};\n//#endregion\n//#region src/streams-keys.ts\n/** ADR-0031's need brand for the streams module's bearer key — control.ts registers the provisioner under this. */\nconst STREAMS_API_KEY = Symbol.for(\"prisma:streams/api-key\");\n/**\n* The provisioning need `durableStreams()`'s `apiKey` param declares: an\n* unguessable value the target mints ONCE PER PROVIDER (not per edge) —\n* `@prisma/streams-server` authenticates a single `API_KEY`, so every\n* consumer of one streams module must present the same value. Per-provider\n* cardinality is provisioner policy (ADR-0031), invisible to core.\n*/\nconst streamsApiKeyNeed = () => provisionNeed(STREAMS_API_KEY);\n/**\n* The reserved provider param for the streams bearer key: the var name is\n* `STREAMS_API_KEY`. `brand` is `STREAMS_API_KEY` itself (the same symbol\n* `streamsApiKeyNeed()`'s need carries) — control.ts looks its `value(refs)`\n* up by this field.\n*/\nconst STREAMS_API_KEY_PARAM = {\n\tname: \"STREAMS_API_KEY\",\n\tschema: type(\"string\"),\n\tbrand: STREAMS_API_KEY\n};\n/** The address-free name compute.ts re-stashes to and the streams entrypoint reads. */\nconst STREAMS_API_KEY_ENV = configKey(\"\", {\n\towner: \"service\",\n\tname: STREAMS_API_KEY_PARAM.name\n});\n//#endregion\n//#region src/provider-params.ts\nconst RESERVED_PROVIDER_PARAMS = [RPC_ACCEPTED_KEYS_PARAM, STREAMS_API_KEY_PARAM];\n//#endregion\n//#region src/param.ts\n/**\n* Brands the payload `envParam` builds. Core's `paramSource()` is a public\n* SPI, so a user could bypass `envParam` and bind a raw `paramSource('x')`;\n* the brand lets `paramName` reject such a source (or another target's) with\n* a clear error instead of reading an absent `.name`.\n*/\nconst PRISMA_CLOUD_PARAM_SOURCE = blindCast(Symbol.for(\"prisma:prisma-cloud-param-source\"));\nconst RESERVED_PARAM_PREFIX = \"COMPOSER_\";\nconst POISONED_PARAM_NAMES = /* @__PURE__ */ new Set([\"DATABASE_URL\", \"DATABASE_URL_POOLED\"]);\n/**\n* Binds a param slot to a named Prisma Cloud platform env var — the non-secret\n* sibling of `envSecret` (spec: env-sourced config params). The platform\n* injects the value into the running instance per stage; the param's own\n* schema validates it at boot, unredacted. The name may not use the\n* framework's reserved `COMPOSER_` prefix or the poisoned\n* `DATABASE_URL(_POOLED)` keys — same parity as `envSecret`.\n*/\nfunction envParam(name) {\n\tif (typeof name !== \"string\" || name.length === 0) throw new Error(\"envParam() requires a non-empty platform env-var name, e.g. envParam('APP_ORIGIN').\");\n\tif (name.startsWith(RESERVED_PARAM_PREFIX)) throw new Error(`envParam name \"${name}\" may not start with \"${RESERVED_PARAM_PREFIX}\" — that prefix is reserved for the framework's own generated config keys.`);\n\tif (POISONED_PARAM_NAMES.has(name)) throw new Error(`envParam name \"${name}\" is reserved — ${[...POISONED_PARAM_NAMES].join(\" and \")} are poisoned at project provision and cannot back a param.`);\n\treturn paramSource({\n\t\t[PRISMA_CLOUD_PARAM_SOURCE]: true,\n\t\tname\n\t});\n}\n/** True only for a payload that `envParam` built — i.e. one carrying the brand. */\nfunction isEnvParamPayload(payload) {\n\treturn typeof payload === \"object\" && payload !== null && blindCast(payload)[PRISMA_CLOUD_PARAM_SOURCE] === true;\n}\n/** True iff a resolved param value is an env-sourced pointer this target built (as opposed to a literal, or a foreign/raw `ParamSource`). */\nfunction isEnvParamSource(value) {\n\treturn isParamSource(value) && isEnvParamPayload(value.payload);\n}\n/**\n* Reads the Prisma Cloud env-var name back out of a param binding's opaque\n* source. A source not built by `envParam` (a raw `paramSource(...)` or\n* another target's source) carries no name — reject it here. `paramName` runs\n* in preflight and at serialize before any value ever crosses the wire, so a\n* foreign source fails early and clearly rather than producing a broken\n* deploy with an undefined name.\n*/\nfunction paramName(binding) {\n\tconst { binding: bound } = binding;\n\tif (!isEnvParamSource(bound)) throw new Error(`param slot \"${binding.slot}\" of service \"${binding.serviceAddress}\" is bound to a source not created by envParam() — bind env-sourced params with envParam('NAME') from @prisma/composer-prisma-cloud.`);\n\treturn bound.payload.name;\n}\n/**\n* Finds the manifest entry for one service param slot. `serialize` calls this\n* only after confirming `buildConfig` resolved the slot to a `ParamSource`\n* (`isParamSource(value)`), so a miss here means `graph.params` and the\n* resolved `Config` have drifted — a Load invariant violation, surfaced\n* loudly rather than producing a pointer row with an undefined name.\n*/\nfunction paramBindingFor(bindings, serviceAddress, slot) {\n\tconst binding = bindings.find((b) => b.serviceAddress === serviceAddress && b.slot === slot);\n\tif (binding === void 0) throw new Error(`param slot \"${slot}\" of \"${serviceAddress}\" resolved to a source but has no bound entry in the manifest — Load should have recorded it.`);\n\treturn binding;\n}\n//#endregion\n//#region src/provisioned-edges.ts\n/**\n* Every provisioned edge in the graph. Core resolves and mints these (one\n* value per edge, keyed by `edgeId`); this scan is how the target finds them\n* again when it gathers a provider's inbound values.\n*/\nfunction provisionedEdges(graph) {\n\tconst edges = [];\n\tfor (const edge of graph.edges) {\n\t\tif (edge.kind !== \"dependency\") continue;\n\t\tconst consumer = graph.nodes.find((n) => n.id === edge.to)?.node;\n\t\tif (consumer === void 0 || consumer.kind !== \"service\") continue;\n\t\tconst slot = consumer.inputs[edge.input];\n\t\tif (slot === void 0) continue;\n\t\tfor (const param of Object.values(slot.connection.params)) {\n\t\t\tconst brand = param.provision?.brand;\n\t\t\tif (brand === void 0) continue;\n\t\t\tedges.push({\n\t\t\t\tedgeId: `${edge.to}.${edge.input}`,\n\t\t\t\tconsumerAddress: edge.to,\n\t\t\t\tinput: edge.input,\n\t\t\t\tproviderAddress: edge.from,\n\t\t\t\tbrand\n\t\t\t});\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn edges;\n}\n//#endregion\nexport { paramName as a, STREAMS_API_KEY_ENV as c, paramBindingFor as i, streamsApiKeyNeed as l, envParam as n, RESERVED_PROVIDER_PARAMS as o, isEnvParamSource as r, STREAMS_API_KEY as s, provisionedEdges as t };\n\n//# sourceMappingURL=provisioned-edges-DIQAR4q4.mjs.map","import { a as paramName, c as STREAMS_API_KEY_ENV, l as streamsApiKeyNeed, n as envParam, o as RESERVED_PROVIDER_PARAMS, s as STREAMS_API_KEY, t as provisionedEdges } from \"./provisioned-edges-DIQAR4q4.mjs\";\nimport { c as stash, d as envSecret, f as secretName, l as stashProviderParams, n as deserialize, r as deserializeSecrets, t as configKey, u as stashSecrets } from \"./serializer-CX4VYdf_.mjs\";\nimport { dependency, hydrateSecrets, hydrateSync, number, resource, service, string } from \"@internal/core\";\nimport { blindCast } from \"@internal/foundation/casts\";\n//#region src/compute.ts\nconst reservedParams = { port: number({ default: 3e3 }) };\n/**\n* A Prisma Compute service — declarations only (deps + params + build + the\n* ports it exposes), no descriptor. `params` merges with the reserved\n* `ReservedParams` (`port`); a user param whose name collides with a reserved\n* one fails at authoring, the same way a colliding dependency name does.\n* Returns the extension's runnable/loadable node:\n* · run(address, boot) — the process controller: deserialize the platform\n* environment (keyed off `address`, the extension's ONE env read) into a\n* typed Config, re-emit it under address-free process-local stash keys,\n* then call boot() to start the app's entry.\n* · load() / config() — called from inside the app's entry: read the stash;\n* load() hydrates + memoizes the deps, config() returns the typed params.\n* Separate accessors so a dep and a param never share a namespace (ADR-0021).\n*\n* `service()`'s underlying node carries `extension: '@prisma/composer-prisma-cloud'` —\n* the control-plane registry key `prisma-composer deploy` resolves through the\n* app's `prisma-composer.config.ts` (ADR-0017). This module loads nothing at\n* deploy time; nodes are pure data.\n*/\nconst compute = (def) => {\n\tconst userParams = def.params ?? blindCast({});\n\tfor (const reserved of Object.keys(reservedParams)) {\n\t\tif (reserved in def.deps) throw new Error(`compute(): dependency \"${reserved}\" collides with the reserved service param of the same name — rename the dependency.`);\n\t\tif (reserved in userParams) throw new Error(`compute(): param \"${reserved}\" collides with the reserved service param of the same name — rename the param.`);\n\t}\n\tconst params = blindCast({\n\t\t...userParams,\n\t\t...reservedParams\n\t});\n\tconst node = service({\n\t\tname: def.name,\n\t\textension: \"@prisma/composer-prisma-cloud\",\n\t\ttype: \"compute\",\n\t\tinputs: def.deps,\n\t\tparams,\n\t\t...def.secrets !== void 0 ? { secrets: def.secrets } : {},\n\t\tbuild: def.build,\n\t\t...def.expose !== void 0 ? { expose: def.expose } : {}\n\t});\n\tlet resolved;\n\tlet loadedDeps;\n\tlet loadedParams;\n\tlet loadedSecrets;\n\tfunction processConfig() {\n\t\tif (resolved === void 0) resolved = deserialize(node, \"\");\n\t\treturn resolved;\n\t}\n\tconst runnable = {\n\t\t...node,\n\t\tasync run(address, boot) {\n\t\t\tconst config = deserialize(node, address);\n\t\t\tstash(node, config);\n\t\t\tstashProviderParams(RESERVED_PROVIDER_PARAMS, address);\n\t\t\tstashSecrets(node, address);\n\t\t\tconst port = config.service[\"port\"];\n\t\t\tif (typeof port === \"number\") process.env[\"PORT\"] = String(port);\n\t\t\treturn boot();\n\t\t},\n\t\tload() {\n\t\t\tif (loadedDeps === void 0) loadedDeps = blindCast(hydrateSync(node, processConfig()));\n\t\t\treturn loadedDeps;\n\t\t},\n\t\tconfig() {\n\t\t\tif (loadedParams === void 0) loadedParams = blindCast(processConfig().service);\n\t\t\treturn loadedParams;\n\t\t},\n\t\tsecrets() {\n\t\t\tif (loadedSecrets === void 0) loadedSecrets = blindCast(hydrateSecrets(node, deserializeSecrets(node, \"\")));\n\t\t\treturn loadedSecrets;\n\t\t}\n\t};\n\treturn Object.freeze(blindCast(runnable));\n};\n//#endregion\n//#region src/http.ts\nconst defaultHttpClient = (cfg) => ({\n\turl: cfg.url,\n\tfetch: (path, init) => fetch(new URL(path, cfg.url), init)\n});\n/**\n* A service-to-service dependency. Its binding (what `load()` returns) is a\n* derived HttpClient — a thin URL-anchored fetch wrapper (fetch is standard\n* across runtimes — no driver, no runtime coupling). http() is a\n* protocol-owned kind: the framework owns the transport, so the client is\n* kind-canonical and derived from the contract, with no user client in the\n* declaration (ADR-0015). The typed generated client arrives with the\n* interface primitive (a later extension point).\n*/\nconst http = (opts) => dependency({\n\tname: opts.name,\n\ttype: \"http\",\n\tconnection: {\n\t\tparams: { url: string() },\n\t\thydrate: (v) => defaultHttpClient({ url: v.url })\n\t}\n});\n//#endregion\n//#region src/postgres.ts\n/**\n* The contract a Postgres provides — and the contract its consumers require.\n* `satisfies` compares KIND, not identity: an extension module can be duplicated\n* across a workspace (same rationale as the Symbol.for node brand), and every\n* duplicate's contract must still satisfy. `__cmp` is the connection config a\n* postgres offers; core never inspects it.\n*/\nconst postgresContract = Object.freeze({\n\tkind: \"postgres\",\n\t__cmp: { url: \"\" },\n\tsatisfies: (required) => required.kind === \"postgres\"\n});\nfunction postgres(opts) {\n\tif (opts?.name !== void 0) return resource({\n\t\tname: opts.name,\n\t\textension: \"@prisma/composer-prisma-cloud\",\n\t\tprovides: postgresContract\n\t});\n\treturn dependency({\n\t\ttype: \"postgres\",\n\t\tconnection: {\n\t\t\tparams: { url: string() },\n\t\t\thydrate: (v) => v\n\t\t},\n\t\trequired: postgresContract\n\t});\n}\n//#endregion\n//#region src/s3-credentials.ts\n/**\n* The contract the `s3-credentials` resource provides — a minted SigV4 key\n* pair. `satisfies` compares KIND only (mirrors `postgresContract`); `__cmp` is\n* the config the resource offers, which core never inspects.\n*/\nconst credentialsContract = Object.freeze({\n\tkind: \"credentials\",\n\t__cmp: {\n\t\taccessKeyId: \"\",\n\t\tsecretAccessKey: \"\"\n\t},\n\tsatisfies: (required) => required.kind === \"credentials\"\n});\nfunction s3Credentials(opts) {\n\tif (opts?.name !== void 0) return resource({\n\t\tname: opts.name,\n\t\textension: \"@prisma/composer-prisma-cloud\",\n\t\tprovides: credentialsContract\n\t});\n\treturn dependency({\n\t\ttype: \"credentials\",\n\t\tconnection: {\n\t\t\tparams: {\n\t\t\t\taccessKeyId: string(),\n\t\t\t\tsecretAccessKey: string()\n\t\t\t},\n\t\t\thydrate: (v) => v\n\t\t},\n\t\trequired: credentialsContract\n\t});\n}\n//#endregion\n//#region src/s3-store.ts\n/**\n* The storage service authoring factory — a `compute` service routed to the\n* `s3-store` lowering instead of `compute`'s. It is exactly `compute`'s\n* runnable (run/load/config, deps, params, build, expose) with the routing\n* `type` overridden to `'s3-store'`: nothing at runtime keys off `type` (the\n* serializer keys off the deployment address and each param's owner/name, and\n* `load`/`config` off deps/params), so only the deploy-time descriptor lookup\n* sees the override and routes to the extended-output lowering (§ 5). The\n* return type is compute's exactly (including the reserved `port` param). The\n* storage module (D4b) calls this with its `db`/`credentials` deps, a `bucket`\n* param, and `expose: { store: s3Contract }`.\n*/\nfunction s3StoreService(def) {\n\tconst node = compute(def);\n\treturn Object.freeze(blindCast({\n\t\t...node,\n\t\ttype: \"s3-store\"\n\t}));\n}\n//#endregion\nexport { STREAMS_API_KEY, STREAMS_API_KEY_ENV, compute, configKey, credentialsContract, envParam, envSecret, http, paramName, postgres, postgresContract, provisionedEdges, s3Credentials, s3StoreService, secretName, streamsApiKeyNeed };\n\n//# sourceMappingURL=index.mjs.map","import { dependency, string } from \"@internal/core\";\nimport { postgres, s3Credentials, s3StoreService } from \"@internal/prisma-cloud\";\nimport node from \"@internal/node\";\n//#region src/contract.ts\nconst s3Contract = Object.freeze({\n\tkind: \"s3\",\n\t__cmp: {\n\t\turl: \"\",\n\t\tbucket: \"\",\n\t\taccessKeyId: \"\",\n\t\tsecretAccessKey: \"\"\n\t},\n\tsatisfies: (required) => required.kind === \"s3\"\n});\n/**\n* A consumer's dependency on an S3-compatible store. No `region` in the\n* binding — the server accepts whatever region string the client signed.\n*/\nfunction s3() {\n\treturn dependency({\n\t\ttype: \"s3\",\n\t\tconnection: {\n\t\t\tparams: {\n\t\t\t\turl: string(),\n\t\t\t\tbucket: string(),\n\t\t\t\taccessKeyId: string(),\n\t\t\t\tsecretAccessKey: string()\n\t\t\t},\n\t\t\thydrate: (v) => v\n\t\t},\n\t\trequired: s3Contract\n\t});\n}\n//#endregion\n//#region src/exports/storage-service.ts\n/**\n* The storage service node (like cron's `scheduler.ts` + `scheduler-service.ts`\n* combined): `storageService` builds the `s3-store` service — a Postgres `db`\n* dependency, a minted `credentials` dependency, a `bucket` param, and the\n* `store` port exposing `s3Contract`. The deploy bootstrap runs the\n* default-exported bare node (`main.run(address, boot)`); the real bucket comes\n* from serialized config at runtime, so the default's `bucket` is only a\n* placeholder — exactly like `scheduler-service.ts` default-exports\n* `cronScheduler({ jobs: [] })`.\n*/\nfunction storageService(opts) {\n\treturn s3StoreService({\n\t\tname: \"storage\",\n\t\tdeps: {\n\t\t\tdb: postgres(),\n\t\t\tcredentials: s3Credentials()\n\t\t},\n\t\tparams: { bucket: string({ default: opts.bucket }) },\n\t\tbuild: node({\n\t\t\tmodule: new URL(\"./storage-service.mjs\", import.meta.url).href,\n\t\t\tentry: \"./storage-entrypoint.mjs\"\n\t\t}),\n\t\texpose: { store: s3Contract }\n\t});\n}\nvar storage_service_default = storageService({ bucket: \"storage\" });\n//#endregion\nexport { s3Contract as i, storage_service_default as n, s3 as r, storageService as t };\n\n//# sourceMappingURL=storage-service-BQdOiMsW.mjs.map","import { dependency, string } from \"@internal/core\";\nimport { compute, streamsApiKeyNeed } from \"@internal/prisma-cloud\";\nimport { s3 } from \"@internal/storage\";\nimport node from \"@internal/node\";\n//#region \\0rolldown/runtime.js\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);\nvar __copyProps = (to, from, except, desc) => {\n\tif (from && typeof from === \"object\" || typeof from === \"function\") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {\n\t\tkey = keys[i];\n\t\tif (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {\n\t\t\tget: ((k) => from[k]).bind(null, key),\n\t\t\tenumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable\n\t\t});\n\t}\n\treturn to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", {\n\tvalue: mod,\n\tenumerable: true\n}) : target, mod));\n//#endregion\n//#region ../../../../node_modules/reusify/reusify.js\nvar require_reusify = /* @__PURE__ */ __commonJSMin(((exports, module) => {\n\tfunction reusify(Constructor) {\n\t\tvar head = new Constructor();\n\t\tvar tail = head;\n\t\tfunction get() {\n\t\t\tvar current = head;\n\t\t\tif (current.next) head = current.next;\n\t\t\telse {\n\t\t\t\thead = new Constructor();\n\t\t\t\ttail = head;\n\t\t\t}\n\t\t\tcurrent.next = null;\n\t\t\treturn current;\n\t\t}\n\t\tfunction release(obj) {\n\t\t\ttail.next = obj;\n\t\t\ttail = obj;\n\t\t}\n\t\treturn {\n\t\t\tget,\n\t\t\trelease\n\t\t};\n\t}\n\tmodule.exports = reusify;\n}));\n//#endregion\n//#region ../../../../node_modules/@durable-streams/client/dist/index.js\nvar import_queue = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {\n\tvar reusify = require_reusify();\n\tfunction fastqueue(context, worker, _concurrency) {\n\t\tif (typeof context === \"function\") {\n\t\t\t_concurrency = worker;\n\t\t\tworker = context;\n\t\t\tcontext = null;\n\t\t}\n\t\tif (!(_concurrency >= 1)) throw new Error(\"fastqueue concurrency must be equal to or greater than 1\");\n\t\tvar cache = reusify(Task);\n\t\tvar queueHead = null;\n\t\tvar queueTail = null;\n\t\tvar _running = 0;\n\t\tvar errorHandler = null;\n\t\tvar self = {\n\t\t\tpush,\n\t\t\tdrain: noop,\n\t\t\tsaturated: noop,\n\t\t\tpause,\n\t\t\tpaused: false,\n\t\t\tget concurrency() {\n\t\t\t\treturn _concurrency;\n\t\t\t},\n\t\t\tset concurrency(value) {\n\t\t\t\tif (!(value >= 1)) throw new Error(\"fastqueue concurrency must be equal to or greater than 1\");\n\t\t\t\t_concurrency = value;\n\t\t\t\tif (self.paused) return;\n\t\t\t\tfor (; queueHead && _running < _concurrency;) {\n\t\t\t\t\t_running++;\n\t\t\t\t\trelease();\n\t\t\t\t}\n\t\t\t},\n\t\t\trunning,\n\t\t\tresume,\n\t\t\tidle,\n\t\t\tlength,\n\t\t\tgetQueue,\n\t\t\tunshift,\n\t\t\tempty: noop,\n\t\t\tkill,\n\t\t\tkillAndDrain,\n\t\t\terror,\n\t\t\tabort\n\t\t};\n\t\treturn self;\n\t\tfunction running() {\n\t\t\treturn _running;\n\t\t}\n\t\tfunction pause() {\n\t\t\tself.paused = true;\n\t\t}\n\t\tfunction length() {\n\t\t\tvar current = queueHead;\n\t\t\tvar counter = 0;\n\t\t\twhile (current) {\n\t\t\t\tcurrent = current.next;\n\t\t\t\tcounter++;\n\t\t\t}\n\t\t\treturn counter;\n\t\t}\n\t\tfunction getQueue() {\n\t\t\tvar current = queueHead;\n\t\t\tvar tasks = [];\n\t\t\twhile (current) {\n\t\t\t\ttasks.push(current.value);\n\t\t\t\tcurrent = current.next;\n\t\t\t}\n\t\t\treturn tasks;\n\t\t}\n\t\tfunction resume() {\n\t\t\tif (!self.paused) return;\n\t\t\tself.paused = false;\n\t\t\tif (queueHead === null) {\n\t\t\t\t_running++;\n\t\t\t\trelease();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (; queueHead && _running < _concurrency;) {\n\t\t\t\t_running++;\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t\tfunction idle() {\n\t\t\treturn _running === 0 && self.length() === 0;\n\t\t}\n\t\tfunction push(value, done) {\n\t\t\tvar current = cache.get();\n\t\t\tcurrent.context = context;\n\t\t\tcurrent.release = release;\n\t\t\tcurrent.value = value;\n\t\t\tcurrent.callback = done || noop;\n\t\t\tcurrent.errorHandler = errorHandler;\n\t\t\tif (_running >= _concurrency || self.paused) if (queueTail) {\n\t\t\t\tqueueTail.next = current;\n\t\t\t\tqueueTail = current;\n\t\t\t} else {\n\t\t\t\tqueueHead = current;\n\t\t\t\tqueueTail = current;\n\t\t\t\tself.saturated();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_running++;\n\t\t\t\tworker.call(context, current.value, current.worked);\n\t\t\t}\n\t\t}\n\t\tfunction unshift(value, done) {\n\t\t\tvar current = cache.get();\n\t\t\tcurrent.context = context;\n\t\t\tcurrent.release = release;\n\t\t\tcurrent.value = value;\n\t\t\tcurrent.callback = done || noop;\n\t\t\tcurrent.errorHandler = errorHandler;\n\t\t\tif (_running >= _concurrency || self.paused) if (queueHead) {\n\t\t\t\tcurrent.next = queueHead;\n\t\t\t\tqueueHead = current;\n\t\t\t} else {\n\t\t\t\tqueueHead = current;\n\t\t\t\tqueueTail = current;\n\t\t\t\tself.saturated();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_running++;\n\t\t\t\tworker.call(context, current.value, current.worked);\n\t\t\t}\n\t\t}\n\t\tfunction release(holder) {\n\t\t\tif (holder) cache.release(holder);\n\t\t\tvar next = queueHead;\n\t\t\tif (next && _running <= _concurrency) if (!self.paused) {\n\t\t\t\tif (queueTail === queueHead) queueTail = null;\n\t\t\t\tqueueHead = next.next;\n\t\t\t\tnext.next = null;\n\t\t\t\tworker.call(context, next.value, next.worked);\n\t\t\t\tif (queueTail === null) self.empty();\n\t\t\t} else _running--;\n\t\t\telse if (--_running === 0) self.drain();\n\t\t}\n\t\tfunction kill() {\n\t\t\tqueueHead = null;\n\t\t\tqueueTail = null;\n\t\t\tself.drain = noop;\n\t\t}\n\t\tfunction killAndDrain() {\n\t\t\tqueueHead = null;\n\t\t\tqueueTail = null;\n\t\t\tself.drain();\n\t\t\tself.drain = noop;\n\t\t}\n\t\tfunction abort() {\n\t\t\tvar current = queueHead;\n\t\t\tqueueHead = null;\n\t\t\tqueueTail = null;\n\t\t\twhile (current) {\n\t\t\t\tvar next = current.next;\n\t\t\t\tvar callback = current.callback;\n\t\t\t\tvar errorHandler = current.errorHandler;\n\t\t\t\tvar val = current.value;\n\t\t\t\tvar context = current.context;\n\t\t\t\tcurrent.value = null;\n\t\t\t\tcurrent.callback = noop;\n\t\t\t\tcurrent.errorHandler = null;\n\t\t\t\tif (errorHandler) errorHandler(/* @__PURE__ */ new Error(\"abort\"), val);\n\t\t\t\tcallback.call(context, /* @__PURE__ */ new Error(\"abort\"));\n\t\t\t\tcurrent.release(current);\n\t\t\t\tcurrent = next;\n\t\t\t}\n\t\t\tself.drain = noop;\n\t\t}\n\t\tfunction error(handler) {\n\t\t\terrorHandler = handler;\n\t\t}\n\t}\n\tfunction noop() {}\n\tfunction Task() {\n\t\tthis.value = null;\n\t\tthis.callback = noop;\n\t\tthis.next = null;\n\t\tthis.release = noop;\n\t\tthis.context = null;\n\t\tthis.errorHandler = null;\n\t\tvar self = this;\n\t\tthis.worked = function worked(err, result) {\n\t\t\tvar callback = self.callback;\n\t\t\tvar errorHandler = self.errorHandler;\n\t\t\tvar val = self.value;\n\t\t\tself.value = null;\n\t\t\tself.callback = noop;\n\t\t\tif (self.errorHandler) errorHandler(err, val);\n\t\t\tcallback.call(self.context, err, result);\n\t\t\tself.release(self);\n\t\t};\n\t}\n\tfunction queueAsPromised(context, worker, _concurrency) {\n\t\tif (typeof context === \"function\") {\n\t\t\t_concurrency = worker;\n\t\t\tworker = context;\n\t\t\tcontext = null;\n\t\t}\n\t\tfunction asyncWrapper(arg, cb) {\n\t\t\tworker.call(this, arg).then(function(res) {\n\t\t\t\tcb(null, res);\n\t\t\t}, cb);\n\t\t}\n\t\tvar queue = fastqueue(context, asyncWrapper, _concurrency);\n\t\tvar pushCb = queue.push;\n\t\tvar unshiftCb = queue.unshift;\n\t\tqueue.push = push;\n\t\tqueue.unshift = unshift;\n\t\tqueue.drained = drained;\n\t\treturn queue;\n\t\tfunction push(value) {\n\t\t\tvar p = new Promise(function(resolve, reject) {\n\t\t\t\tpushCb(value, function(err, result) {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tresolve(result);\n\t\t\t\t});\n\t\t\t});\n\t\t\tp.catch(noop);\n\t\t\treturn p;\n\t\t}\n\t\tfunction unshift(value) {\n\t\t\tvar p = new Promise(function(resolve, reject) {\n\t\t\t\tunshiftCb(value, function(err, result) {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tresolve(result);\n\t\t\t\t});\n\t\t\t});\n\t\t\tp.catch(noop);\n\t\t\treturn p;\n\t\t}\n\t\tfunction drained() {\n\t\t\treturn new Promise(function(resolve) {\n\t\t\t\tprocess.nextTick(function() {\n\t\t\t\t\tif (queue.idle()) resolve();\n\t\t\t\t\telse {\n\t\t\t\t\t\tvar previousDrain = queue.drain;\n\t\t\t\t\t\tqueue.drain = function() {\n\t\t\t\t\t\t\tif (typeof previousDrain === \"function\") previousDrain();\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\tqueue.drain = previousDrain;\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\tmodule.exports = fastqueue;\n\tmodule.exports.promise = queueAsPromised;\n})))(), 1);\n/**\n* Durable Streams Protocol Constants\n*\n* Header and query parameter names following the Electric Durable Stream Protocol.\n*/\n/**\n* Response header containing the next offset to read from.\n* Offsets are opaque tokens - clients MUST NOT interpret the format.\n*/\nconst STREAM_OFFSET_HEADER = `Stream-Next-Offset`;\n/**\n* Response header for cursor (used for CDN collapsing).\n* Echo this value in subsequent long-poll requests.\n*/\nconst STREAM_CURSOR_HEADER = `Stream-Cursor`;\n/**\n* Presence header indicating response ends at current end of stream.\n* When present (any value), indicates up-to-date.\n*/\nconst STREAM_UP_TO_DATE_HEADER = `Stream-Up-To-Date`;\n/**\n* Response/request header indicating stream is closed (EOF).\n* When present with value \"true\", the stream is permanently closed.\n*/\nconst STREAM_CLOSED_HEADER = `Stream-Closed`;\n/**\n* Request header for writer coordination sequence.\n* Monotonic, lexicographic. If lower than last appended seq -> 409 Conflict.\n*/\nconst STREAM_SEQ_HEADER = `Stream-Seq`;\n/**\n* Request header for stream TTL in seconds (on create).\n*/\nconst STREAM_TTL_HEADER = `Stream-TTL`;\n/**\n* Request header for absolute stream expiry time (RFC3339, on create).\n*/\nconst STREAM_EXPIRES_AT_HEADER = `Stream-Expires-At`;\n/**\n* Request header for producer ID (client-supplied stable identifier).\n*/\nconst PRODUCER_ID_HEADER = `Producer-Id`;\n/**\n* Request/response header for producer epoch.\n* Client-declared, server-validated monotonically increasing.\n*/\nconst PRODUCER_EPOCH_HEADER = `Producer-Epoch`;\n/**\n* Request header for producer sequence number.\n* Monotonically increasing per epoch, per-batch (not per-message).\n*/\nconst PRODUCER_SEQ_HEADER = `Producer-Seq`;\n/**\n* Response header indicating expected sequence number on 409 Conflict.\n*/\nconst PRODUCER_EXPECTED_SEQ_HEADER = `Producer-Expected-Seq`;\n/**\n* Response header indicating received sequence number on 409 Conflict.\n*/\nconst PRODUCER_RECEIVED_SEQ_HEADER = `Producer-Received-Seq`;\n/**\n* Query parameter for starting offset.\n*/\nconst OFFSET_QUERY_PARAM = `offset`;\n/**\n* Query parameter for live mode.\n* Values: \"long-poll\", \"sse\"\n*/\nconst LIVE_QUERY_PARAM = `live`;\n/**\n* Response header indicating SSE data encoding (e.g., base64 for binary streams).\n*/\nconst STREAM_SSE_DATA_ENCODING_HEADER = `stream-sse-data-encoding`;\n/**\n* Error thrown for transport/network errors.\n* Following the @electric-sql/client FetchError pattern.\n*/\nvar FetchError = class FetchError extends Error {\n\tstatus;\n\ttext;\n\tjson;\n\theaders;\n\tconstructor(status, text, json, headers, url, message) {\n\t\tsuper(message || `HTTP Error ${status} at ${url}: ${text ?? JSON.stringify(json)}`);\n\t\tthis.url = url;\n\t\tthis.name = `FetchError`;\n\t\tthis.status = status;\n\t\tthis.text = text;\n\t\tthis.json = json;\n\t\tthis.headers = headers;\n\t}\n\tstatic async fromResponse(response, url) {\n\t\tconst status = response.status;\n\t\tconst headers = Object.fromEntries([...response.headers.entries()]);\n\t\tlet text = void 0;\n\t\tlet json = void 0;\n\t\tconst contentType = response.headers.get(`content-type`);\n\t\tif (!response.bodyUsed && response.body !== null) if (contentType && contentType.includes(`application/json`)) try {\n\t\t\tjson = await response.json();\n\t\t} catch {\n\t\t\ttext = await response.text();\n\t\t}\n\t\telse text = await response.text();\n\t\treturn new FetchError(status, text, json, headers, url);\n\t}\n};\n/**\n* Error thrown when a fetch operation is aborted during backoff.\n*/\nvar FetchBackoffAbortError = class extends Error {\n\tconstructor() {\n\t\tsuper(`Fetch with backoff aborted`);\n\t\tthis.name = `FetchBackoffAbortError`;\n\t}\n};\n/**\n* Protocol-level error for Durable Streams operations.\n* Provides structured error handling with error codes.\n*/\nvar DurableStreamError = class DurableStreamError extends Error {\n\t/**\n\t* HTTP status code, if applicable.\n\t*/\n\tstatus;\n\t/**\n\t* Structured error code for programmatic handling.\n\t*/\n\tcode;\n\t/**\n\t* Additional error details (e.g., raw response body).\n\t*/\n\tdetails;\n\tconstructor(message, code, status, details) {\n\t\tsuper(message);\n\t\tthis.name = `DurableStreamError`;\n\t\tthis.code = code;\n\t\tthis.status = status;\n\t\tthis.details = details;\n\t}\n\t/**\n\t* Create a DurableStreamError from an HTTP response.\n\t*/\n\tstatic async fromResponse(response, url) {\n\t\tconst status = response.status;\n\t\tlet details;\n\t\tconst contentType = response.headers.get(`content-type`);\n\t\tif (!response.bodyUsed && response.body !== null) if (contentType && contentType.includes(`application/json`)) try {\n\t\t\tdetails = await response.json();\n\t\t} catch {\n\t\t\tdetails = await response.text();\n\t\t}\n\t\telse details = await response.text();\n\t\tconst code = statusToCode(status);\n\t\tconst message = `Durable stream error at ${url}: ${response.statusText || status}`;\n\t\treturn new DurableStreamError(message, code, status, details);\n\t}\n\t/**\n\t* Create a DurableStreamError from a FetchError.\n\t*/\n\tstatic fromFetchError(error) {\n\t\tconst code = statusToCode(error.status);\n\t\treturn new DurableStreamError(error.message, code, error.status, error.json ?? error.text);\n\t}\n};\n/**\n* Map HTTP status codes to DurableStreamErrorCode.\n*/\nfunction statusToCode(status) {\n\tswitch (status) {\n\t\tcase 400: return `BAD_REQUEST`;\n\t\tcase 401: return `UNAUTHORIZED`;\n\t\tcase 403: return `FORBIDDEN`;\n\t\tcase 404: return `NOT_FOUND`;\n\t\tcase 409: return `CONFLICT_SEQ`;\n\t\tcase 429: return `RATE_LIMITED`;\n\t\tcase 503: return `BUSY`;\n\t\tdefault: return `UNKNOWN`;\n\t}\n}\n/**\n* Error thrown when stream URL is missing.\n*/\nvar MissingStreamUrlError = class extends Error {\n\tconstructor() {\n\t\tsuper(`Invalid stream options: missing required url parameter`);\n\t\tthis.name = `MissingStreamUrlError`;\n\t}\n};\n/**\n* Error thrown when attempting to append to a closed stream.\n*/\nvar StreamClosedError = class extends DurableStreamError {\n\tcode = `STREAM_CLOSED`;\n\tstatus = 409;\n\tstreamClosed = true;\n\t/**\n\t* The final offset of the stream, if available from the response.\n\t*/\n\tfinalOffset;\n\tconstructor(url, finalOffset) {\n\t\tsuper(`Cannot append to closed stream`, `STREAM_CLOSED`, 409, url);\n\t\tthis.name = `StreamClosedError`;\n\t\tthis.finalOffset = finalOffset;\n\t}\n};\n/**\n* Error thrown when signal option is invalid.\n*/\nvar InvalidSignalError = class extends Error {\n\tconstructor() {\n\t\tsuper(`Invalid signal option. It must be an instance of AbortSignal.`);\n\t\tthis.name = `InvalidSignalError`;\n\t}\n};\n/**\n* HTTP status codes that should be retried.\n*/\nconst HTTP_RETRY_STATUS_CODES = [429, 503];\n/**\n* Default backoff options.\n*/\nconst BackoffDefaults = {\n\tinitialDelay: 100,\n\tmaxDelay: 6e4,\n\tmultiplier: 1.3,\n\tmaxRetries: Infinity\n};\n/**\n* Parse Retry-After header value and return delay in milliseconds.\n* Supports both delta-seconds format and HTTP-date format.\n* Returns 0 if header is not present or invalid.\n*/\nfunction parseRetryAfterHeader(retryAfter) {\n\tif (!retryAfter) return 0;\n\tconst retryAfterSec = Number(retryAfter);\n\tif (Number.isFinite(retryAfterSec) && retryAfterSec > 0) return retryAfterSec * 1e3;\n\tconst retryDate = Date.parse(retryAfter);\n\tif (!isNaN(retryDate)) {\n\t\tconst deltaMs = retryDate - Date.now();\n\t\treturn Math.max(0, Math.min(deltaMs, 36e5));\n\t}\n\treturn 0;\n}\n/**\n* Creates a fetch client that retries failed requests with exponential backoff.\n*\n* @param fetchClient - The base fetch client to wrap\n* @param backoffOptions - Options for retry behavior\n* @returns A fetch function with automatic retry\n*/\nfunction createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {\n\tconst { initialDelay, maxDelay, multiplier, debug = false, onFailedAttempt, maxRetries = Infinity } = backoffOptions;\n\treturn async (...args) => {\n\t\tconst url = args[0];\n\t\tconst options = args[1];\n\t\tlet delay = initialDelay;\n\t\tlet attempt = 0;\n\t\twhile (true) try {\n\t\t\tconst result = await fetchClient(...args);\n\t\t\tif (result.ok) return result;\n\t\t\tthrow await FetchError.fromResponse(result, url.toString());\n\t\t} catch (e) {\n\t\t\tonFailedAttempt?.();\n\t\t\tif (options?.signal?.aborted) throw new FetchBackoffAbortError();\n\t\t\telse if (e instanceof FetchError && !HTTP_RETRY_STATUS_CODES.includes(e.status) && e.status >= 400 && e.status < 500) throw e;\n\t\t\telse {\n\t\t\t\tattempt++;\n\t\t\t\tif (attempt > maxRetries) {\n\t\t\t\t\tif (debug) console.log(`Max retries reached (${attempt}/${maxRetries}), giving up`);\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t\tconst serverMinimumMs = e instanceof FetchError ? parseRetryAfterHeader(e.headers[`retry-after`]) : 0;\n\t\t\t\tconst jitter = Math.random() * delay;\n\t\t\t\tconst clientBackoffMs = Math.min(jitter, maxDelay);\n\t\t\t\tconst waitMs = Math.max(serverMinimumMs, clientBackoffMs);\n\t\t\t\tif (debug) console.log(`Retry attempt #${attempt} after ${waitMs}ms (${serverMinimumMs > 0 ? `server+client` : `client`}, serverMin=${serverMinimumMs}ms, clientBackoff=${clientBackoffMs}ms)`);\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, waitMs));\n\t\t\t\tdelay = Math.min(delay * multiplier, maxDelay);\n\t\t\t}\n\t\t}\n\t};\n}\n/**\n* Status codes where we shouldn't try to read the body.\n*/\nconst NO_BODY_STATUS_CODES = [\n\t201,\n\t204,\n\t205\n];\n/**\n* Creates a fetch client that ensures the response body is fully consumed.\n* This prevents issues with connection pooling when bodies aren't read.\n*\n* Uses arrayBuffer() instead of text() to preserve binary data integrity.\n*\n* @param fetchClient - The base fetch client to wrap\n* @returns A fetch function that consumes response bodies\n*/\nfunction createFetchWithConsumedBody(fetchClient) {\n\treturn async (...args) => {\n\t\tconst url = args[0];\n\t\tconst res = await fetchClient(...args);\n\t\ttry {\n\t\t\tif (res.status < 200 || NO_BODY_STATUS_CODES.includes(res.status)) return res;\n\t\t\tconst buf = await res.arrayBuffer();\n\t\t\treturn new Response(buf, {\n\t\t\t\tstatus: res.status,\n\t\t\t\tstatusText: res.statusText,\n\t\t\t\theaders: res.headers\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tif (args[1]?.signal?.aborted) throw new FetchBackoffAbortError();\n\t\t\tthrow new FetchError(res.status, void 0, void 0, Object.fromEntries([...res.headers.entries()]), url.toString(), err instanceof Error ? err.message : typeof err === `string` ? err : `failed to read body`);\n\t\t}\n\t};\n}\n/**\n* Check if a value has Symbol.asyncIterator defined.\n*/\nfunction hasAsyncIterator(stream$1) {\n\treturn typeof Symbol !== `undefined` && typeof Symbol.asyncIterator === `symbol` && typeof stream$1[Symbol.asyncIterator] === `function`;\n}\n/**\n* Define [Symbol.asyncIterator] and .values() on a ReadableStream instance.\n*\n* Uses getReader().read() to implement spec-consistent iteration.\n* On completion or early exit (break/return/throw), releases lock and cancels as appropriate.\n*\n* **Iterator behavior notes:**\n* - `return(value?)` accepts an optional cancellation reason passed to `reader.cancel()`\n* - `return()` always resolves with `{ done: true, value: undefined }` regardless of the\n* input value. This matches `for await...of` semantics where the return value is ignored.\n* Manual iteration users should be aware of this behavior.\n*/\nfunction defineAsyncIterator(stream$1) {\n\tif (typeof Symbol === `undefined` || typeof Symbol.asyncIterator !== `symbol`) return;\n\tif (typeof stream$1[Symbol.asyncIterator] === `function`) return;\n\tconst createIterator = function() {\n\t\tconst reader = this.getReader();\n\t\tlet finished = false;\n\t\tlet pendingReads = 0;\n\t\treturn {\n\t\t\tasync next() {\n\t\t\t\tif (finished) return {\n\t\t\t\t\tdone: true,\n\t\t\t\t\tvalue: void 0\n\t\t\t\t};\n\t\t\t\tpendingReads++;\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = await reader.read();\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tfinished = true;\n\t\t\t\t\t\treader.releaseLock();\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tdone: true,\n\t\t\t\t\t\t\tvalue: void 0\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdone: false,\n\t\t\t\t\t\tvalue\n\t\t\t\t\t};\n\t\t\t\t} catch (err) {\n\t\t\t\t\tfinished = true;\n\t\t\t\t\ttry {\n\t\t\t\t\t\treader.releaseLock();\n\t\t\t\t\t} catch {}\n\t\t\t\t\tthrow err;\n\t\t\t\t} finally {\n\t\t\t\t\tpendingReads--;\n\t\t\t\t}\n\t\t\t},\n\t\t\tasync return(value) {\n\t\t\t\tif (pendingReads > 0) throw new TypeError(`Cannot close a readable stream reader when it has pending read requests`);\n\t\t\t\tfinished = true;\n\t\t\t\tconst cancelPromise = reader.cancel(value);\n\t\t\t\treader.releaseLock();\n\t\t\t\tawait cancelPromise;\n\t\t\t\treturn {\n\t\t\t\t\tdone: true,\n\t\t\t\t\tvalue: void 0\n\t\t\t\t};\n\t\t\t},\n\t\t\tasync throw(err) {\n\t\t\t\tif (pendingReads > 0) throw new TypeError(`Cannot close a readable stream reader when it has pending read requests`);\n\t\t\t\tfinished = true;\n\t\t\t\tconst cancelPromise = reader.cancel(err);\n\t\t\t\treader.releaseLock();\n\t\t\t\tawait cancelPromise;\n\t\t\t\tthrow err;\n\t\t\t},\n\t\t\t[Symbol.asyncIterator]() {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t};\n\t};\n\ttry {\n\t\tObject.defineProperty(stream$1, Symbol.asyncIterator, {\n\t\t\tconfigurable: true,\n\t\t\twritable: true,\n\t\t\tvalue: createIterator\n\t\t});\n\t} catch {\n\t\treturn;\n\t}\n\ttry {\n\t\tObject.defineProperty(stream$1, `values`, {\n\t\t\tconfigurable: true,\n\t\t\twritable: true,\n\t\t\tvalue: createIterator\n\t\t});\n\t} catch {}\n}\n/**\n* Ensure a ReadableStream is async-iterable.\n*\n* If the stream already has [Symbol.asyncIterator] defined (native or polyfilled),\n* it is returned as-is. Otherwise, [Symbol.asyncIterator] is defined on the\n* stream instance (not the prototype).\n*\n* The returned value is the same ReadableStream instance, so:\n* - `stream instanceof ReadableStream` remains true\n* - Any code relying on native branding/internal slots continues to work\n*\n* @example\n* ```typescript\n* const stream = someApiReturningReadableStream();\n* const iterableStream = asAsyncIterableReadableStream(stream);\n*\n* // Now works on Safari/iOS:\n* for await (const chunk of iterableStream) {\n* console.log(chunk);\n* }\n* ```\n*/\nfunction asAsyncIterableReadableStream(stream$1) {\n\tif (!hasAsyncIterator(stream$1)) defineAsyncIterator(stream$1);\n\treturn stream$1;\n}\n/**\n* Parse SSE events from a ReadableStream<Uint8Array>.\n* Yields parsed events as they arrive.\n*/\nasync function* parseSSEStream(stream$1, signal) {\n\tconst reader = stream$1.getReader();\n\tconst decoder = new TextDecoder();\n\tlet buffer = ``;\n\tlet currentEvent = { data: [] };\n\ttry {\n\t\twhile (true) {\n\t\t\tif (signal?.aborted) break;\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\tbuffer = buffer.replace(/\\r\\n/g, `\\n`).replace(/\\r/g, `\\n`);\n\t\t\tconst lines = buffer.split(`\\n`);\n\t\t\tbuffer = lines.pop() ?? ``;\n\t\t\tfor (const line of lines) if (line === ``) {\n\t\t\t\tif (currentEvent.type && currentEvent.data.length > 0) {\n\t\t\t\t\tconst dataStr = currentEvent.data.join(`\\n`);\n\t\t\t\t\tif (currentEvent.type === `data`) yield {\n\t\t\t\t\t\ttype: `data`,\n\t\t\t\t\t\tdata: dataStr\n\t\t\t\t\t};\n\t\t\t\t\telse if (currentEvent.type === `control`) try {\n\t\t\t\t\t\tconst control = JSON.parse(dataStr);\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: `control`,\n\t\t\t\t\t\t\tstreamNextOffset: control.streamNextOffset,\n\t\t\t\t\t\t\tstreamCursor: control.streamCursor,\n\t\t\t\t\t\t\tupToDate: control.upToDate,\n\t\t\t\t\t\t\tstreamClosed: control.streamClosed\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst preview = dataStr.length > 100 ? dataStr.slice(0, 100) + `...` : dataStr;\n\t\t\t\t\t\tthrow new DurableStreamError(`Failed to parse SSE control event: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcurrentEvent = { data: [] };\n\t\t\t} else if (line.startsWith(`event:`)) {\n\t\t\t\tconst eventType = line.slice(6);\n\t\t\t\tcurrentEvent.type = eventType.startsWith(` `) ? eventType.slice(1) : eventType;\n\t\t\t} else if (line.startsWith(`data:`)) {\n\t\t\t\tconst content = line.slice(5);\n\t\t\t\tcurrentEvent.data.push(content.startsWith(` `) ? content.slice(1) : content);\n\t\t\t}\n\t\t}\n\t\tconst remaining = decoder.decode();\n\t\tif (remaining) buffer += remaining;\n\t\tif (buffer && currentEvent.type && currentEvent.data.length > 0) {\n\t\t\tconst dataStr = currentEvent.data.join(`\\n`);\n\t\t\tif (currentEvent.type === `data`) yield {\n\t\t\t\ttype: `data`,\n\t\t\t\tdata: dataStr\n\t\t\t};\n\t\t\telse if (currentEvent.type === `control`) try {\n\t\t\t\tconst control = JSON.parse(dataStr);\n\t\t\t\tyield {\n\t\t\t\t\ttype: `control`,\n\t\t\t\t\tstreamNextOffset: control.streamNextOffset,\n\t\t\t\t\tstreamCursor: control.streamCursor,\n\t\t\t\t\tupToDate: control.upToDate,\n\t\t\t\t\tstreamClosed: control.streamClosed\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst preview = dataStr.length > 100 ? dataStr.slice(0, 100) + `...` : dataStr;\n\t\t\t\tthrow new DurableStreamError(`Failed to parse SSE control event: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t}\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n}\n/**\n* Abstract base class for stream response state.\n* All state transitions return new immutable state objects.\n*/\nvar StreamResponseState = class {\n\tshouldContinueLive(stopAfterUpToDate, liveMode) {\n\t\tif (stopAfterUpToDate && this.upToDate) return false;\n\t\tif (liveMode === false) return false;\n\t\tif (this.streamClosed) return false;\n\t\treturn true;\n\t}\n};\n/**\n* State for long-poll mode. shouldUseSse() returns false.\n*/\nvar LongPollState = class LongPollState extends StreamResponseState {\n\toffset;\n\tcursor;\n\tupToDate;\n\tstreamClosed;\n\tconstructor(fields) {\n\t\tsuper();\n\t\tthis.offset = fields.offset;\n\t\tthis.cursor = fields.cursor;\n\t\tthis.upToDate = fields.upToDate;\n\t\tthis.streamClosed = fields.streamClosed;\n\t}\n\tshouldUseSse() {\n\t\treturn false;\n\t}\n\twithResponseMetadata(update) {\n\t\treturn new LongPollState({\n\t\t\toffset: update.offset ?? this.offset,\n\t\t\tcursor: update.cursor ?? this.cursor,\n\t\t\tupToDate: update.upToDate,\n\t\t\tstreamClosed: this.streamClosed || update.streamClosed\n\t\t});\n\t}\n\twithSSEControl(event) {\n\t\tconst streamClosed = this.streamClosed || (event.streamClosed ?? false);\n\t\treturn new LongPollState({\n\t\t\toffset: event.streamNextOffset,\n\t\t\tcursor: event.streamCursor || this.cursor,\n\t\t\tupToDate: event.streamClosed ?? false ? true : event.upToDate ?? this.upToDate,\n\t\t\tstreamClosed\n\t\t});\n\t}\n\tpause() {\n\t\treturn new PausedState(this);\n\t}\n};\n/**\n* State for SSE mode. shouldUseSse() returns true.\n* Tracks SSE connection resilience (short connection detection).\n*/\nvar SSEState = class SSEState extends StreamResponseState {\n\toffset;\n\tcursor;\n\tupToDate;\n\tstreamClosed;\n\tconsecutiveShortConnections;\n\tconnectionStartTime;\n\tconstructor(fields) {\n\t\tsuper();\n\t\tthis.offset = fields.offset;\n\t\tthis.cursor = fields.cursor;\n\t\tthis.upToDate = fields.upToDate;\n\t\tthis.streamClosed = fields.streamClosed;\n\t\tthis.consecutiveShortConnections = fields.consecutiveShortConnections ?? 0;\n\t\tthis.connectionStartTime = fields.connectionStartTime;\n\t}\n\tshouldUseSse() {\n\t\treturn true;\n\t}\n\twithResponseMetadata(update) {\n\t\treturn new SSEState({\n\t\t\toffset: update.offset ?? this.offset,\n\t\t\tcursor: update.cursor ?? this.cursor,\n\t\t\tupToDate: update.upToDate,\n\t\t\tstreamClosed: this.streamClosed || update.streamClosed,\n\t\t\tconsecutiveShortConnections: this.consecutiveShortConnections,\n\t\t\tconnectionStartTime: this.connectionStartTime\n\t\t});\n\t}\n\twithSSEControl(event) {\n\t\tconst streamClosed = this.streamClosed || (event.streamClosed ?? false);\n\t\treturn new SSEState({\n\t\t\toffset: event.streamNextOffset,\n\t\t\tcursor: event.streamCursor || this.cursor,\n\t\t\tupToDate: event.streamClosed ?? false ? true : event.upToDate ?? this.upToDate,\n\t\t\tstreamClosed,\n\t\t\tconsecutiveShortConnections: this.consecutiveShortConnections,\n\t\t\tconnectionStartTime: this.connectionStartTime\n\t\t});\n\t}\n\tstartConnection(now) {\n\t\treturn new SSEState({\n\t\t\toffset: this.offset,\n\t\t\tcursor: this.cursor,\n\t\t\tupToDate: this.upToDate,\n\t\t\tstreamClosed: this.streamClosed,\n\t\t\tconsecutiveShortConnections: this.consecutiveShortConnections,\n\t\t\tconnectionStartTime: now\n\t\t});\n\t}\n\thandleConnectionEnd(now, wasAborted, config) {\n\t\tif (this.connectionStartTime === void 0) return {\n\t\t\taction: `healthy`,\n\t\t\tstate: this\n\t\t};\n\t\tconst duration = now - this.connectionStartTime;\n\t\tif (duration < config.minConnectionDuration && !wasAborted) {\n\t\t\tconst newCount = this.consecutiveShortConnections + 1;\n\t\t\tif (newCount >= config.maxShortConnections) return {\n\t\t\t\taction: `fallback`,\n\t\t\t\tstate: new LongPollState({\n\t\t\t\t\toffset: this.offset,\n\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\tupToDate: this.upToDate,\n\t\t\t\t\tstreamClosed: this.streamClosed\n\t\t\t\t})\n\t\t\t};\n\t\t\treturn {\n\t\t\t\taction: `reconnect`,\n\t\t\t\tstate: new SSEState({\n\t\t\t\t\toffset: this.offset,\n\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\tupToDate: this.upToDate,\n\t\t\t\t\tstreamClosed: this.streamClosed,\n\t\t\t\t\tconsecutiveShortConnections: newCount,\n\t\t\t\t\tconnectionStartTime: this.connectionStartTime\n\t\t\t\t}),\n\t\t\t\tbackoffAttempt: newCount\n\t\t\t};\n\t\t}\n\t\tif (duration >= config.minConnectionDuration) return {\n\t\t\taction: `healthy`,\n\t\t\tstate: new SSEState({\n\t\t\t\toffset: this.offset,\n\t\t\t\tcursor: this.cursor,\n\t\t\t\tupToDate: this.upToDate,\n\t\t\t\tstreamClosed: this.streamClosed,\n\t\t\t\tconsecutiveShortConnections: 0,\n\t\t\t\tconnectionStartTime: this.connectionStartTime\n\t\t\t})\n\t\t};\n\t\treturn {\n\t\t\taction: `healthy`,\n\t\t\tstate: this\n\t\t};\n\t}\n\tpause() {\n\t\treturn new PausedState(this);\n\t}\n};\n/**\n* Paused state wrapper. Delegates all sync field access to the inner state.\n* resume() returns the wrapped state unchanged (identity preserved).\n*/\nvar PausedState = class PausedState extends StreamResponseState {\n\t#inner;\n\tconstructor(inner) {\n\t\tsuper();\n\t\tthis.#inner = inner;\n\t}\n\tget offset() {\n\t\treturn this.#inner.offset;\n\t}\n\tget cursor() {\n\t\treturn this.#inner.cursor;\n\t}\n\tget upToDate() {\n\t\treturn this.#inner.upToDate;\n\t}\n\tget streamClosed() {\n\t\treturn this.#inner.streamClosed;\n\t}\n\tshouldUseSse() {\n\t\treturn this.#inner.shouldUseSse();\n\t}\n\twithResponseMetadata(update) {\n\t\tconst newInner = this.#inner.withResponseMetadata(update);\n\t\treturn new PausedState(newInner);\n\t}\n\twithSSEControl(event) {\n\t\tconst newInner = this.#inner.withSSEControl(event);\n\t\treturn new PausedState(newInner);\n\t}\n\tpause() {\n\t\treturn this;\n\t}\n\tresume() {\n\t\treturn {\n\t\t\tstate: this.#inner,\n\t\t\tjustResumed: true\n\t\t};\n\t}\n};\n/**\n* Constant used as abort reason when pausing the stream due to visibility change.\n*/\nconst PAUSE_STREAM = `PAUSE_STREAM`;\n/**\n* Implementation of the StreamResponse interface.\n*/\nvar StreamResponseImpl = class {\n\turl;\n\tcontentType;\n\tlive;\n\tstartOffset;\n\t#headers;\n\t#status;\n\t#statusText;\n\t#ok;\n\t#isLoading;\n\t#syncState;\n\t#isJsonMode;\n\t#abortController;\n\t#fetchNext;\n\t#startSSE;\n\t#closedResolve;\n\t#closedReject;\n\t#closed;\n\t#stopAfterUpToDate = false;\n\t#consumptionMethod = null;\n\t#state = `active`;\n\t#requestAbortController;\n\t#unsubscribeFromVisibilityChanges;\n\t#pausePromise;\n\t#pauseResolve;\n\t#sseResilience;\n\t#encoding;\n\t#responseStream;\n\tconstructor(config) {\n\t\tthis.url = config.url;\n\t\tthis.contentType = config.contentType;\n\t\tthis.live = config.live;\n\t\tthis.startOffset = config.startOffset;\n\t\tconst syncFields = {\n\t\t\toffset: config.initialOffset,\n\t\t\tcursor: config.initialCursor,\n\t\t\tupToDate: config.initialUpToDate,\n\t\t\tstreamClosed: config.initialStreamClosed\n\t\t};\n\t\tthis.#syncState = config.startSSE ? new SSEState(syncFields) : new LongPollState(syncFields);\n\t\tthis.#headers = config.firstResponse.headers;\n\t\tthis.#status = config.firstResponse.status;\n\t\tthis.#statusText = config.firstResponse.statusText;\n\t\tthis.#ok = config.firstResponse.ok;\n\t\tthis.#isLoading = false;\n\t\tthis.#isJsonMode = config.isJsonMode;\n\t\tthis.#abortController = config.abortController;\n\t\tthis.#fetchNext = config.fetchNext;\n\t\tthis.#startSSE = config.startSSE;\n\t\tthis.#sseResilience = {\n\t\t\tminConnectionDuration: config.sseResilience?.minConnectionDuration ?? 1e3,\n\t\t\tmaxShortConnections: config.sseResilience?.maxShortConnections ?? 3,\n\t\t\tbackoffBaseDelay: config.sseResilience?.backoffBaseDelay ?? 100,\n\t\t\tbackoffMaxDelay: config.sseResilience?.backoffMaxDelay ?? 5e3,\n\t\t\tlogWarnings: config.sseResilience?.logWarnings ?? true\n\t\t};\n\t\tthis.#encoding = config.encoding;\n\t\tthis.#closed = new Promise((resolve, reject) => {\n\t\t\tthis.#closedResolve = resolve;\n\t\t\tthis.#closedReject = reject;\n\t\t});\n\t\tthis.#responseStream = this.#createResponseStream(config.firstResponse);\n\t\tthis.#abortController.signal.addEventListener(`abort`, () => {\n\t\t\tthis.#requestAbortController?.abort(this.#abortController.signal.reason);\n\t\t\tthis.#pauseResolve?.();\n\t\t\tthis.#pausePromise = void 0;\n\t\t\tthis.#pauseResolve = void 0;\n\t\t}, { once: true });\n\t\tthis.#subscribeToVisibilityChanges();\n\t}\n\t/**\n\t* Subscribe to document visibility changes to pause/resume syncing.\n\t* When the page is hidden, we pause to save battery and bandwidth.\n\t* When visible again, we resume syncing.\n\t*/\n\t#subscribeToVisibilityChanges() {\n\t\tif (typeof document === `object` && typeof document.hidden === `boolean` && typeof document.addEventListener === `function`) {\n\t\t\tconst visibilityHandler = () => {\n\t\t\t\tif (document.hidden) this.#pause();\n\t\t\t\telse this.#resume();\n\t\t\t};\n\t\t\tdocument.addEventListener(`visibilitychange`, visibilityHandler);\n\t\t\tthis.#unsubscribeFromVisibilityChanges = () => {\n\t\t\t\tif (typeof document === `object`) document.removeEventListener(`visibilitychange`, visibilityHandler);\n\t\t\t};\n\t\t\tif (document.hidden) this.#pause();\n\t\t}\n\t}\n\t/**\n\t* Pause the stream when page becomes hidden.\n\t* Aborts any in-flight request to free resources.\n\t* Creates a promise that pull() will await while paused.\n\t*/\n\t#pause() {\n\t\tif (this.#state === `active`) {\n\t\t\tthis.#state = `pause-requested`;\n\t\t\tthis.#syncState = this.#syncState.pause();\n\t\t\tthis.#pausePromise = new Promise((resolve) => {\n\t\t\t\tthis.#pauseResolve = resolve;\n\t\t\t});\n\t\t\tthis.#requestAbortController?.abort(PAUSE_STREAM);\n\t\t}\n\t}\n\t/**\n\t* Resume the stream when page becomes visible.\n\t* Resolves the pause promise to unblock pull().\n\t*/\n\t#resume() {\n\t\tif (this.#state === `paused` || this.#state === `pause-requested`) {\n\t\t\tif (this.#abortController.signal.aborted) return;\n\t\t\tif (this.#syncState instanceof PausedState) this.#syncState = this.#syncState.resume().state;\n\t\t\tthis.#state = `active`;\n\t\t\tthis.#pauseResolve?.();\n\t\t\tthis.#pausePromise = void 0;\n\t\t\tthis.#pauseResolve = void 0;\n\t\t}\n\t}\n\tget headers() {\n\t\treturn this.#headers;\n\t}\n\tget status() {\n\t\treturn this.#status;\n\t}\n\tget statusText() {\n\t\treturn this.#statusText;\n\t}\n\tget ok() {\n\t\treturn this.#ok;\n\t}\n\tget isLoading() {\n\t\treturn this.#isLoading;\n\t}\n\tget offset() {\n\t\treturn this.#syncState.offset;\n\t}\n\tget cursor() {\n\t\treturn this.#syncState.cursor;\n\t}\n\tget upToDate() {\n\t\treturn this.#syncState.upToDate;\n\t}\n\tget streamClosed() {\n\t\treturn this.#syncState.streamClosed;\n\t}\n\t#ensureJsonMode() {\n\t\tif (!this.#isJsonMode) throw new DurableStreamError(`JSON methods are only valid for JSON-mode streams. Content-Type is \"${this.contentType}\" and json hint was not set.`, `BAD_REQUEST`);\n\t}\n\t#markClosed() {\n\t\tthis.#unsubscribeFromVisibilityChanges?.();\n\t\tthis.#closedResolve();\n\t}\n\t#markError(err) {\n\t\tthis.#unsubscribeFromVisibilityChanges?.();\n\t\tthis.#closedReject(err);\n\t}\n\t/**\n\t* Ensure only one consumption method is used per StreamResponse.\n\t* Throws if any consumption method was already called.\n\t*/\n\t#ensureNoConsumption(method) {\n\t\tif (this.#consumptionMethod !== null) throw new DurableStreamError(`Cannot call ${method}() - this StreamResponse is already being consumed via ${this.#consumptionMethod}()`, `ALREADY_CONSUMED`);\n\t\tthis.#consumptionMethod = method;\n\t}\n\t/**\n\t* Determine if we should continue with live updates based on live mode\n\t* and whether we've received upToDate or streamClosed.\n\t*/\n\t#shouldContinueLive() {\n\t\treturn this.#syncState.shouldContinueLive(this.#stopAfterUpToDate, this.live);\n\t}\n\t/**\n\t* Update state from response headers.\n\t*/\n\t#updateStateFromResponse(response) {\n\t\tthis.#syncState = this.#syncState.withResponseMetadata({\n\t\t\toffset: response.headers.get(STREAM_OFFSET_HEADER) || void 0,\n\t\t\tcursor: response.headers.get(STREAM_CURSOR_HEADER) || void 0,\n\t\t\tupToDate: response.headers.has(STREAM_UP_TO_DATE_HEADER),\n\t\t\tstreamClosed: response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`\n\t\t});\n\t\tthis.#headers = response.headers;\n\t\tthis.#status = response.status;\n\t\tthis.#statusText = response.statusText;\n\t\tthis.#ok = response.ok;\n\t}\n\t/**\n\t* Update instance state from an SSE control event.\n\t*/\n\t#updateStateFromSSEControl(controlEvent) {\n\t\tthis.#syncState = this.#syncState.withSSEControl(controlEvent);\n\t}\n\t#updateEncodingFromSSEResponse(response) {\n\t\tthis.#encoding = response.headers.get(STREAM_SSE_DATA_ENCODING_HEADER) === `base64` ? `base64` : void 0;\n\t}\n\t/**\n\t* Mark the start of an SSE connection for duration tracking.\n\t* If the state is not SSEState (e.g., auto-detected SSE from content-type),\n\t* transitions to SSEState first.\n\t*/\n\t#markSSEConnectionStart() {\n\t\tif (!(this.#syncState instanceof SSEState)) this.#syncState = new SSEState({\n\t\t\toffset: this.#syncState.offset,\n\t\t\tcursor: this.#syncState.cursor,\n\t\t\tupToDate: this.#syncState.upToDate,\n\t\t\tstreamClosed: this.#syncState.streamClosed\n\t\t});\n\t\tthis.#syncState = this.#syncState.startConnection(Date.now());\n\t}\n\t/**\n\t* Try to reconnect SSE and return the new iterator, or null if reconnection\n\t* is not possible or fails.\n\t*/\n\tasync #trySSEReconnect() {\n\t\tif (!this.#syncState.shouldUseSse()) return null;\n\t\tif (!this.#shouldContinueLive() || !this.#startSSE) return null;\n\t\tconst result = this.#syncState.handleConnectionEnd(Date.now(), this.#abortController.signal.aborted, this.#sseResilience);\n\t\tthis.#syncState = result.state;\n\t\tif (result.action === `fallback`) {\n\t\t\tif (this.#sseResilience.logWarnings) console.warn(\"[Durable Streams] SSE connections are closing immediately (possibly due to proxy buffering or misconfiguration). Falling back to long polling. Your proxy must support streaming SSE responses (not buffer the complete response). Configuration: Nginx add 'X-Accel-Buffering: no', Caddy add 'flush_interval -1' to reverse_proxy.\");\n\t\t\treturn null;\n\t\t}\n\t\tif (result.action === `reconnect`) {\n\t\t\tconst maxDelay = Math.min(this.#sseResilience.backoffMaxDelay, this.#sseResilience.backoffBaseDelay * Math.pow(2, result.backoffAttempt));\n\t\t\tconst delayMs = Math.floor(Math.random() * maxDelay);\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, delayMs));\n\t\t}\n\t\tthis.#markSSEConnectionStart();\n\t\tthis.#requestAbortController = new AbortController();\n\t\tconst newSSEResponse = await this.#startSSE(this.offset, this.cursor, this.#requestAbortController.signal);\n\t\tthis.#updateEncodingFromSSEResponse(newSSEResponse);\n\t\tif (newSSEResponse.body) return parseSSEStream(newSSEResponse.body, this.#requestAbortController.signal);\n\t\treturn null;\n\t}\n\t/**\n\t* Process SSE events from the iterator.\n\t* Returns an object indicating the result:\n\t* - { type: 'response', response, newIterator? } - yield this response\n\t* - { type: 'closed' } - stream should be closed\n\t* - { type: 'error', error } - an error occurred\n\t* - { type: 'continue', newIterator? } - continue processing (control-only event)\n\t*/\n\tasync #processSSEEvents(sseEventIterator) {\n\t\tconst { done, value: event } = await sseEventIterator.next();\n\t\tif (done) {\n\t\t\ttry {\n\t\t\t\tconst newIterator = await this.#trySSEReconnect();\n\t\t\t\tif (newIterator) return {\n\t\t\t\t\ttype: `continue`,\n\t\t\t\t\tnewIterator\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: `error`,\n\t\t\t\t\terror: err instanceof Error ? err : /* @__PURE__ */ new Error(`SSE reconnection failed`)\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { type: `closed` };\n\t\t}\n\t\tif (event.type === `data`) return this.#processSSEDataEvent(event.data, sseEventIterator);\n\t\tthis.#updateStateFromSSEControl(event);\n\t\tif (event.upToDate) return {\n\t\t\ttype: `response`,\n\t\t\tresponse: createSSESyntheticResponse(``, event.streamNextOffset, event.streamCursor, true, event.streamClosed ?? false, this.contentType, this.#encoding)\n\t\t};\n\t\treturn { type: `continue` };\n\t}\n\t/**\n\t* Process an SSE data event by waiting for its corresponding control event.\n\t* In SSE protocol, control events come AFTER data events.\n\t* Multiple data events may arrive before a single control event - we buffer them.\n\t*\n\t* For base64 mode, each data event is independently base64 encoded, so we\n\t* collect them as an array and decode each separately.\n\t*/\n\tasync #processSSEDataEvent(pendingData, sseEventIterator) {\n\t\tconst bufferedDataParts = [pendingData];\n\t\twhile (true) {\n\t\t\tconst { done: controlDone, value: controlEvent } = await sseEventIterator.next();\n\t\t\tif (controlDone) {\n\t\t\t\tconst response = createSSESyntheticResponseFromParts(bufferedDataParts, this.offset, this.cursor, this.upToDate, this.streamClosed, this.contentType, this.#encoding, this.#isJsonMode);\n\t\t\t\ttry {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: `response`,\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\tnewIterator: await this.#trySSEReconnect() ?? void 0\n\t\t\t\t\t};\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: `error`,\n\t\t\t\t\t\terror: err instanceof Error ? err : /* @__PURE__ */ new Error(`SSE reconnection failed`)\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (controlEvent.type === `control`) {\n\t\t\t\tthis.#updateStateFromSSEControl(controlEvent);\n\t\t\t\treturn {\n\t\t\t\t\ttype: `response`,\n\t\t\t\t\tresponse: createSSESyntheticResponseFromParts(bufferedDataParts, controlEvent.streamNextOffset, controlEvent.streamCursor, controlEvent.upToDate ?? false, controlEvent.streamClosed ?? false, this.contentType, this.#encoding, this.#isJsonMode)\n\t\t\t\t};\n\t\t\t}\n\t\t\tbufferedDataParts.push(controlEvent.data);\n\t\t}\n\t}\n\t/**\n\t* Create the core ReadableStream<Response> that yields responses.\n\t* This is consumed once - all consumption methods use this same stream.\n\t*\n\t* For long-poll mode: yields actual Response objects.\n\t* For SSE mode: yields synthetic Response objects created from SSE data events.\n\t*/\n\t#createResponseStream(firstResponse) {\n\t\tlet firstResponseYielded = false;\n\t\tlet sseEventIterator = null;\n\t\treturn new ReadableStream({\n\t\t\tpull: async (controller) => {\n\t\t\t\ttry {\n\t\t\t\t\tif (!firstResponseYielded) {\n\t\t\t\t\t\tfirstResponseYielded = true;\n\t\t\t\t\t\tif ((firstResponse.headers.get(`content-type`)?.includes(`text/event-stream`) ?? false) && firstResponse.body) {\n\t\t\t\t\t\t\tthis.#markSSEConnectionStart();\n\t\t\t\t\t\t\tthis.#updateEncodingFromSSEResponse(firstResponse);\n\t\t\t\t\t\t\tthis.#requestAbortController = new AbortController();\n\t\t\t\t\t\t\tsseEventIterator = parseSSEStream(firstResponse.body, this.#requestAbortController.signal);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontroller.enqueue(firstResponse);\n\t\t\t\t\t\t\tif (this.upToDate && !this.#shouldContinueLive()) {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!sseEventIterator && this.upToDate && this.#startSSE && this.#shouldContinueLive()) {\n\t\t\t\t\t\tif (this.#state === `pause-requested` || this.#state === `paused`) {\n\t\t\t\t\t\t\tthis.#state = `paused`;\n\t\t\t\t\t\t\tif (this.#pausePromise) await this.#pausePromise;\n\t\t\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.#markSSEConnectionStart();\n\t\t\t\t\t\tthis.#requestAbortController = new AbortController();\n\t\t\t\t\t\tconst sseResponse = await this.#startSSE(this.offset, this.cursor, this.#requestAbortController.signal);\n\t\t\t\t\t\tthis.#updateEncodingFromSSEResponse(sseResponse);\n\t\t\t\t\t\tif (sseResponse.body) sseEventIterator = parseSSEStream(sseResponse.body, this.#requestAbortController.signal);\n\t\t\t\t\t}\n\t\t\t\t\tif (sseEventIterator) {\n\t\t\t\t\t\tif (this.#state === `pause-requested` || this.#state === `paused`) {\n\t\t\t\t\t\t\tthis.#state = `paused`;\n\t\t\t\t\t\t\tif (this.#pausePromise) await this.#pausePromise;\n\t\t\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst newIterator = await this.#trySSEReconnect();\n\t\t\t\t\t\t\tif (newIterator) sseEventIterator = newIterator;\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true) {\n\t\t\t\t\t\t\tconst result = await this.#processSSEEvents(sseEventIterator);\n\t\t\t\t\t\t\tswitch (result.type) {\n\t\t\t\t\t\t\t\tcase `response`:\n\t\t\t\t\t\t\t\t\tif (result.newIterator) sseEventIterator = result.newIterator;\n\t\t\t\t\t\t\t\t\tcontroller.enqueue(result.response);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tcase `closed`:\n\t\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tcase `error`:\n\t\t\t\t\t\t\t\t\tthis.#markError(result.error);\n\t\t\t\t\t\t\t\t\tcontroller.error(result.error);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tcase `continue`:\n\t\t\t\t\t\t\t\t\tif (result.newIterator) sseEventIterator = result.newIterator;\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (this.#shouldContinueLive()) {\n\t\t\t\t\t\tlet resumingFromPause = false;\n\t\t\t\t\t\tif (this.#state === `pause-requested` || this.#state === `paused`) {\n\t\t\t\t\t\t\tthis.#state = `paused`;\n\t\t\t\t\t\t\tif (this.#pausePromise) await this.#pausePromise;\n\t\t\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresumingFromPause = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.#requestAbortController = new AbortController();\n\t\t\t\t\t\tconst response = await this.#fetchNext(this.offset, this.cursor, this.#requestAbortController.signal, this.upToDate, resumingFromPause);\n\t\t\t\t\t\tthis.#updateStateFromResponse(response);\n\t\t\t\t\t\tcontroller.enqueue(response);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\tcontroller.close();\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (this.#requestAbortController?.signal.aborted && this.#requestAbortController.signal.reason === PAUSE_STREAM) {\n\t\t\t\t\t\tif (this.#state === `pause-requested`) this.#state = `paused`;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#markError(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t\t\tcontroller.error(err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\tthis.#abortController.abort();\n\t\t\t\tthis.#unsubscribeFromVisibilityChanges?.();\n\t\t\t\tthis.#markClosed();\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Get the response stream reader. Can only be called once.\n\t*/\n\t#getResponseReader() {\n\t\treturn this.#responseStream.getReader();\n\t}\n\tasync body() {\n\t\tthis.#ensureNoConsumption(`body`);\n\t\tthis.#stopAfterUpToDate = true;\n\t\tconst reader = this.#getResponseReader();\n\t\tconst blobs = [];\n\t\ttry {\n\t\t\tlet result = await reader.read();\n\t\t\twhile (!result.done) {\n\t\t\t\tconst wasUpToDate = this.upToDate;\n\t\t\t\tconst blob = await result.value.blob();\n\t\t\t\tif (blob.size > 0) blobs.push(blob);\n\t\t\t\tif (wasUpToDate) break;\n\t\t\t\tresult = await reader.read();\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tthis.#markClosed();\n\t\tif (blobs.length === 0) return /* @__PURE__ */ new Uint8Array(0);\n\t\tif (blobs.length === 1) return new Uint8Array(await blobs[0].arrayBuffer());\n\t\tconst combined = new Blob(blobs);\n\t\treturn new Uint8Array(await combined.arrayBuffer());\n\t}\n\tasync json() {\n\t\tthis.#ensureNoConsumption(`json`);\n\t\tthis.#ensureJsonMode();\n\t\tthis.#stopAfterUpToDate = true;\n\t\tconst reader = this.#getResponseReader();\n\t\tconst items = [];\n\t\ttry {\n\t\t\tlet result = await reader.read();\n\t\t\twhile (!result.done) {\n\t\t\t\tconst wasUpToDate = this.upToDate;\n\t\t\t\tconst content = (await result.value.text()).trim() || `[]`;\n\t\t\t\tlet parsed;\n\t\t\t\ttry {\n\t\t\t\t\tparsed = JSON.parse(content);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst preview = content.length > 100 ? content.slice(0, 100) + `...` : content;\n\t\t\t\t\tthrow new DurableStreamError(`Failed to parse JSON response: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(parsed)) items.push(...parsed);\n\t\t\t\telse items.push(parsed);\n\t\t\t\tif (wasUpToDate) break;\n\t\t\t\tresult = await reader.read();\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tthis.#markClosed();\n\t\treturn items;\n\t}\n\tasync text() {\n\t\tthis.#ensureNoConsumption(`text`);\n\t\tthis.#stopAfterUpToDate = true;\n\t\tconst reader = this.#getResponseReader();\n\t\tconst parts = [];\n\t\ttry {\n\t\t\tlet result = await reader.read();\n\t\t\twhile (!result.done) {\n\t\t\t\tconst wasUpToDate = this.upToDate;\n\t\t\t\tconst text = await result.value.text();\n\t\t\t\tif (text) parts.push(text);\n\t\t\t\tif (wasUpToDate) break;\n\t\t\t\tresult = await reader.read();\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tthis.#markClosed();\n\t\treturn parts.join(``);\n\t}\n\t/**\n\t* Internal helper to create the body stream without consumption check.\n\t* Used by both bodyStream() and textStream().\n\t*/\n\t#createBodyStreamInternal() {\n\t\tconst { readable, writable } = new TransformStream();\n\t\tconst reader = this.#getResponseReader();\n\t\tconst pipeBodyStream = async () => {\n\t\t\ttry {\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tconst wasUpToDate = this.upToDate;\n\t\t\t\t\tconst body = result.value.body;\n\t\t\t\t\tif (body) await body.pipeTo(writable, {\n\t\t\t\t\t\tpreventClose: true,\n\t\t\t\t\t\tpreventAbort: true,\n\t\t\t\t\t\tpreventCancel: true\n\t\t\t\t\t});\n\t\t\t\t\tif (wasUpToDate && !this.#shouldContinueLive()) break;\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tawait writable.close();\n\t\t\t\tthis.#markClosed();\n\t\t\t} catch (err) {\n\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait writable.close();\n\t\t\t\t\t} catch {}\n\t\t\t\t\tthis.#markClosed();\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait writable.abort(err);\n\t\t\t\t\t} catch {}\n\t\t\t\t\tthis.#markError(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t};\n\t\tpipeBodyStream();\n\t\treturn readable;\n\t}\n\tbodyStream() {\n\t\tthis.#ensureNoConsumption(`bodyStream`);\n\t\treturn asAsyncIterableReadableStream(this.#createBodyStreamInternal());\n\t}\n\tjsonStream() {\n\t\tthis.#ensureNoConsumption(`jsonStream`);\n\t\tthis.#ensureJsonMode();\n\t\tconst reader = this.#getResponseReader();\n\t\tlet pendingItems = [];\n\t\treturn asAsyncIterableReadableStream(new ReadableStream({\n\t\t\tpull: async (controller) => {\n\t\t\t\tif (pendingItems.length > 0) {\n\t\t\t\t\tcontroller.enqueue(pendingItems.shift());\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tconst content = (await result.value.text()).trim() || `[]`;\n\t\t\t\t\tlet parsed;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tparsed = JSON.parse(content);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst preview = content.length > 100 ? content.slice(0, 100) + `...` : content;\n\t\t\t\t\t\tthrow new DurableStreamError(`Failed to parse JSON response: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t\t\t}\n\t\t\t\t\tpendingItems = Array.isArray(parsed) ? parsed : [parsed];\n\t\t\t\t\tif (pendingItems.length > 0) {\n\t\t\t\t\t\tcontroller.enqueue(pendingItems.shift());\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tthis.#markClosed();\n\t\t\t\tcontroller.close();\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\treader.releaseLock();\n\t\t\t\tthis.cancel();\n\t\t\t}\n\t\t}));\n\t}\n\ttextStream() {\n\t\tthis.#ensureNoConsumption(`textStream`);\n\t\tconst decoder = new TextDecoder();\n\t\treturn asAsyncIterableReadableStream(this.#createBodyStreamInternal().pipeThrough(new TransformStream({\n\t\t\ttransform(chunk, controller) {\n\t\t\t\tcontroller.enqueue(decoder.decode(chunk, { stream: true }));\n\t\t\t},\n\t\t\tflush(controller) {\n\t\t\t\tconst remaining = decoder.decode();\n\t\t\t\tif (remaining) controller.enqueue(remaining);\n\t\t\t}\n\t\t})));\n\t}\n\tsubscribeJson(subscriber) {\n\t\tthis.#ensureNoConsumption(`subscribeJson`);\n\t\tthis.#ensureJsonMode();\n\t\tconst abortController = new AbortController();\n\t\tconst reader = this.#getResponseReader();\n\t\tconst consumeJsonSubscription = async () => {\n\t\t\ttry {\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tif (abortController.signal.aborted) break;\n\t\t\t\t\tconst response = result.value;\n\t\t\t\t\tconst { offset, cursor, upToDate, streamClosed } = getMetadataFromResponse(response, this.offset, this.cursor, this.streamClosed);\n\t\t\t\t\tconst content = (await response.text()).trim() || `[]`;\n\t\t\t\t\tlet parsed;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tparsed = JSON.parse(content);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst preview = content.length > 100 ? content.slice(0, 100) + `...` : content;\n\t\t\t\t\t\tthrow new DurableStreamError(`Failed to parse JSON response: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t\t\t}\n\t\t\t\t\tawait subscriber({\n\t\t\t\t\t\titems: Array.isArray(parsed) ? parsed : [parsed],\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\tupToDate,\n\t\t\t\t\t\tstreamClosed\n\t\t\t\t\t});\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tthis.#markClosed();\n\t\t\t} catch (e) {\n\t\t\t\tconst isAborted = abortController.signal.aborted;\n\t\t\t\tconst isBodyError = e instanceof TypeError && String(e).includes(`Body`);\n\t\t\t\tif (!isAborted && !isBodyError) this.#markError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\telse this.#markClosed();\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t};\n\t\tconsumeJsonSubscription();\n\t\treturn () => {\n\t\t\tabortController.abort();\n\t\t\tthis.cancel();\n\t\t};\n\t}\n\tsubscribeBytes(subscriber) {\n\t\tthis.#ensureNoConsumption(`subscribeBytes`);\n\t\tconst abortController = new AbortController();\n\t\tconst reader = this.#getResponseReader();\n\t\tconst consumeBytesSubscription = async () => {\n\t\t\ttry {\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tif (abortController.signal.aborted) break;\n\t\t\t\t\tconst response = result.value;\n\t\t\t\t\tconst { offset, cursor, upToDate, streamClosed } = getMetadataFromResponse(response, this.offset, this.cursor, this.streamClosed);\n\t\t\t\t\tconst buffer = await response.arrayBuffer();\n\t\t\t\t\tawait subscriber({\n\t\t\t\t\t\tdata: new Uint8Array(buffer),\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\tupToDate,\n\t\t\t\t\t\tstreamClosed\n\t\t\t\t\t});\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tthis.#markClosed();\n\t\t\t} catch (e) {\n\t\t\t\tconst isAborted = abortController.signal.aborted;\n\t\t\t\tconst isBodyError = e instanceof TypeError && String(e).includes(`Body`);\n\t\t\t\tif (!isAborted && !isBodyError) this.#markError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\telse this.#markClosed();\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t};\n\t\tconsumeBytesSubscription();\n\t\treturn () => {\n\t\t\tabortController.abort();\n\t\t\tthis.cancel();\n\t\t};\n\t}\n\tsubscribeText(subscriber) {\n\t\tthis.#ensureNoConsumption(`subscribeText`);\n\t\tconst abortController = new AbortController();\n\t\tconst reader = this.#getResponseReader();\n\t\tconst consumeTextSubscription = async () => {\n\t\t\ttry {\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tif (abortController.signal.aborted) break;\n\t\t\t\t\tconst response = result.value;\n\t\t\t\t\tconst { offset, cursor, upToDate, streamClosed } = getMetadataFromResponse(response, this.offset, this.cursor, this.streamClosed);\n\t\t\t\t\tawait subscriber({\n\t\t\t\t\t\ttext: await response.text(),\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\tupToDate,\n\t\t\t\t\t\tstreamClosed\n\t\t\t\t\t});\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tthis.#markClosed();\n\t\t\t} catch (e) {\n\t\t\t\tconst isAborted = abortController.signal.aborted;\n\t\t\t\tconst isBodyError = e instanceof TypeError && String(e).includes(`Body`);\n\t\t\t\tif (!isAborted && !isBodyError) this.#markError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\telse this.#markClosed();\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t};\n\t\tconsumeTextSubscription();\n\t\treturn () => {\n\t\t\tabortController.abort();\n\t\t\tthis.cancel();\n\t\t};\n\t}\n\tcancel(reason) {\n\t\tthis.#abortController.abort(reason);\n\t\tthis.#unsubscribeFromVisibilityChanges?.();\n\t\tthis.#markClosed();\n\t}\n\tget closed() {\n\t\treturn this.#closed;\n\t}\n};\n/**\n* Extract stream metadata from Response headers.\n* Falls back to the provided defaults when headers are absent.\n*/\nfunction getMetadataFromResponse(response, fallbackOffset, fallbackCursor, fallbackStreamClosed) {\n\tconst offset = response.headers.get(STREAM_OFFSET_HEADER);\n\tconst cursor = response.headers.get(STREAM_CURSOR_HEADER);\n\tconst upToDate = response.headers.has(STREAM_UP_TO_DATE_HEADER);\n\tconst streamClosed = response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`;\n\treturn {\n\t\toffset: offset ?? fallbackOffset,\n\t\tcursor: cursor ?? fallbackCursor,\n\t\tupToDate,\n\t\tstreamClosed: streamClosed || fallbackStreamClosed\n\t};\n}\n/**\n* Decode base64 string to Uint8Array.\n* Per protocol: concatenate data lines, remove \\n and \\r, then decode.\n*/\nfunction decodeBase64(base64Str) {\n\tconst cleaned = base64Str.replace(/[\\n\\r]/g, ``);\n\tif (cleaned.length === 0) return /* @__PURE__ */ new Uint8Array(0);\n\tif (cleaned.length % 4 !== 0) throw new DurableStreamError(`Invalid base64 data: length ${cleaned.length} is not a multiple of 4`, `PARSE_ERROR`);\n\ttry {\n\t\tif (typeof Buffer !== `undefined`) return new Uint8Array(Buffer.from(cleaned, `base64`));\n\t\telse {\n\t\t\tconst binaryStr = atob(cleaned);\n\t\t\tconst bytes = new Uint8Array(binaryStr.length);\n\t\t\tfor (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);\n\t\t\treturn bytes;\n\t\t}\n\t} catch (err) {\n\t\tthrow new DurableStreamError(`Failed to decode base64 data: ${err instanceof Error ? err.message : String(err)}`, `PARSE_ERROR`);\n\t}\n}\n/**\n* Create a synthetic Response from SSE data with proper headers.\n* Includes offset/cursor/upToDate/streamClosed in headers so subscribers can read them.\n*/\nfunction createSSESyntheticResponse(data, offset, cursor, upToDate, streamClosed, contentType, encoding) {\n\treturn createSSESyntheticResponseFromParts([data], offset, cursor, upToDate, streamClosed, contentType, encoding);\n}\n/**\n* Create a synthetic Response from multiple SSE data parts.\n* For base64 mode, each part is independently encoded, so we decode each\n* separately and concatenate the binary results.\n* For text mode, parts are simply concatenated as strings.\n*/\nfunction createSSESyntheticResponseFromParts(dataParts, offset, cursor, upToDate, streamClosed, contentType, encoding, isJsonMode) {\n\tconst headers = {\n\t\t\"content-type\": contentType ?? `application/json`,\n\t\t[STREAM_OFFSET_HEADER]: String(offset)\n\t};\n\tif (cursor) headers[STREAM_CURSOR_HEADER] = cursor;\n\tif (upToDate) headers[STREAM_UP_TO_DATE_HEADER] = `true`;\n\tif (streamClosed) headers[STREAM_CLOSED_HEADER] = `true`;\n\tlet body;\n\tif (encoding === `base64`) {\n\t\tconst decodedParts = dataParts.filter((part) => part.length > 0).map((part) => decodeBase64(part));\n\t\tif (decodedParts.length === 0) body = /* @__PURE__ */ new ArrayBuffer(0);\n\t\telse if (decodedParts.length === 1) {\n\t\t\tconst decoded = decodedParts[0];\n\t\t\tbody = decoded.buffer.slice(decoded.byteOffset, decoded.byteOffset + decoded.byteLength);\n\t\t} else {\n\t\t\tconst totalLength = decodedParts.reduce((sum, part) => sum + part.length, 0);\n\t\t\tconst combined = new Uint8Array(totalLength);\n\t\t\tlet offset$1 = 0;\n\t\t\tfor (const part of decodedParts) {\n\t\t\t\tcombined.set(part, offset$1);\n\t\t\t\toffset$1 += part.length;\n\t\t\t}\n\t\t\tbody = combined.buffer;\n\t\t}\n\t} else if (isJsonMode) {\n\t\tconst mergedParts = [];\n\t\tfor (const part of dataParts) {\n\t\t\tconst trimmed = part.trim();\n\t\t\tif (trimmed.length === 0) continue;\n\t\t\tif (trimmed.startsWith(`[`) && trimmed.endsWith(`]`)) {\n\t\t\t\tconst inner = trimmed.slice(1, -1).trim();\n\t\t\t\tif (inner.length > 0) mergedParts.push(inner);\n\t\t\t} else mergedParts.push(trimmed);\n\t\t}\n\t\tbody = `[${mergedParts.join(`,`)}]`;\n\t} else body = dataParts.join(``);\n\treturn new Response(body, {\n\t\tstatus: 200,\n\t\theaders\n\t});\n}\n/**\n* Resolve headers from HeadersRecord (supports async functions).\n* Unified implementation used by both stream() and DurableStream.\n*/\nasync function resolveHeaders(headers) {\n\tconst resolved = {};\n\tif (!headers) return resolved;\n\tfor (const [key, value] of Object.entries(headers)) if (typeof value === `function`) resolved[key] = await value();\n\telse resolved[key] = value;\n\treturn resolved;\n}\n/**\n* Handle error responses from the server.\n* Throws appropriate DurableStreamError based on status code.\n*/\nasync function handleErrorResponse(response, url, context) {\n\tconst status = response.status;\n\tif (status === 404) throw new DurableStreamError(`Stream not found: ${url}`, `NOT_FOUND`, 404);\n\tif (status === 409) {\n\t\tif (response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`) throw new StreamClosedError(url, response.headers.get(STREAM_OFFSET_HEADER) ?? void 0);\n\t\tthrow new DurableStreamError(context?.operation === `create` ? `Stream already exists: ${url}` : `Sequence conflict: seq is lower than last appended`, context?.operation === `create` ? `CONFLICT_EXISTS` : `CONFLICT_SEQ`, 409);\n\t}\n\tif (status === 400) throw new DurableStreamError(`Bad request (possibly content-type mismatch)`, `BAD_REQUEST`, 400);\n\tthrow await DurableStreamError.fromResponse(response, url);\n}\n/**\n* Resolve params from ParamsRecord (supports async functions).\n*/\nasync function resolveParams(params) {\n\tconst resolved = {};\n\tif (!params) return resolved;\n\tfor (const [key, value] of Object.entries(params)) if (value !== void 0) if (typeof value === `function`) resolved[key] = await value();\n\telse resolved[key] = value;\n\treturn resolved;\n}\nconst warnedOrigins = /* @__PURE__ */ new Set();\n/**\n* Safely read NODE_ENV without triggering \"process is not defined\" errors.\n* Works in both browser and Node.js environments.\n*/\nfunction getNodeEnvSafely() {\n\tif (typeof process === `undefined`) return void 0;\n\treturn process.env?.NODE_ENV;\n}\n/**\n* Check if we're in a browser environment.\n*/\nfunction isBrowserEnvironment() {\n\treturn typeof globalThis.window !== `undefined`;\n}\n/**\n* Get window.location.href safely, returning undefined if not available.\n*/\nfunction getWindowLocationHref() {\n\tif (typeof globalThis.window !== `undefined` && typeof globalThis.window.location !== `undefined`) return globalThis.window.location.href;\n}\n/**\n* Resolve a URL string, handling relative URLs in browser environments.\n* Returns undefined if the URL cannot be parsed.\n*/\nfunction resolveUrlMaybe(urlString) {\n\ttry {\n\t\treturn new URL(urlString);\n\t} catch {\n\t\tconst base = getWindowLocationHref();\n\t\tif (base) try {\n\t\t\treturn new URL(urlString, base);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\treturn;\n\t}\n}\n/**\n* Warn if using HTTP (not HTTPS) URL in a browser environment.\n* HTTP typically limits browsers to ~6 concurrent connections per origin under HTTP/1.1,\n* which can cause slow streams and app freezes with multiple active streams.\n*\n* Features:\n* - Warns only once per origin to prevent log spam\n* - Handles relative URLs by resolving against window.location.href\n* - Safe to call in Node.js environments (no-op)\n* - Skips warning during tests (NODE_ENV=test)\n*/\nfunction warnIfUsingHttpInBrowser(url, warnOnHttp) {\n\tif (warnOnHttp === false) return;\n\tif (getNodeEnvSafely() === `test`) return;\n\tif (!isBrowserEnvironment() || typeof console === `undefined` || typeof console.warn !== `function`) return;\n\tconst parsedUrl = resolveUrlMaybe(url instanceof URL ? url.toString() : url);\n\tif (!parsedUrl) return;\n\tif (parsedUrl.protocol === `http:`) {\n\t\tif (!warnedOrigins.has(parsedUrl.origin)) {\n\t\t\twarnedOrigins.add(parsedUrl.origin);\n\t\t\tconsole.warn(\"[DurableStream] Using HTTP (not HTTPS) typically limits browsers to ~6 concurrent connections per origin under HTTP/1.1. This can cause slow streams and app freezes with multiple active streams. Use HTTPS for HTTP/2 support. See https://electric-sql.com/r/electric-http2 for more information.\");\n\t\t}\n\t}\n}\n/**\n* Create a streaming session to read from a durable stream.\n*\n* This is a fetch-like API:\n* - The promise resolves after the first network request succeeds\n* - It rejects for auth/404/other protocol errors\n* - Returns a StreamResponse for consuming the data\n*\n* @example\n* ```typescript\n* // Catch-up JSON:\n* const res = await stream<{ message: string }>({\n* url,\n* auth,\n* offset: \"0\",\n* live: false,\n* })\n* const items = await res.json()\n*\n* // Live JSON:\n* const live = await stream<{ message: string }>({\n* url,\n* auth,\n* offset: savedOffset,\n* live: true,\n* })\n* live.subscribeJson(async (batch) => {\n* for (const item of batch.items) {\n* handle(item)\n* }\n* })\n* ```\n*/\nasync function stream(options) {\n\tif (!options.url) throw new DurableStreamError(`Invalid stream options: missing required url parameter`, `BAD_REQUEST`);\n\tlet currentHeaders = options.headers;\n\tlet currentParams = options.params;\n\twhile (true) try {\n\t\treturn await streamInternal({\n\t\t\t...options,\n\t\t\theaders: currentHeaders,\n\t\t\tparams: currentParams\n\t\t});\n\t} catch (err) {\n\t\tif (options.onError) {\n\t\t\tconst retryOpts = await options.onError(err instanceof Error ? err : new Error(String(err)));\n\t\t\tif (retryOpts === void 0) throw err;\n\t\t\tif (retryOpts.params) currentParams = {\n\t\t\t\t...currentParams,\n\t\t\t\t...retryOpts.params\n\t\t\t};\n\t\t\tif (retryOpts.headers) currentHeaders = {\n\t\t\t\t...currentHeaders,\n\t\t\t\t...retryOpts.headers\n\t\t\t};\n\t\t\tcontinue;\n\t\t}\n\t\tthrow err;\n\t}\n}\n/**\n* Internal implementation of stream that doesn't handle onError retries.\n*/\nasync function streamInternal(options) {\n\tconst url = options.url instanceof URL ? options.url.toString() : options.url;\n\twarnIfUsingHttpInBrowser(url, options.warnOnHttp);\n\tconst fetchUrl = new URL(url);\n\tconst startOffset = options.offset ?? `-1`;\n\tfetchUrl.searchParams.set(OFFSET_QUERY_PARAM, startOffset);\n\tconst live = options.live ?? true;\n\tconst params = await resolveParams(options.params);\n\tfor (const [key, value] of Object.entries(params)) fetchUrl.searchParams.set(key, value);\n\tconst headers = await resolveHeaders(options.headers);\n\tconst abortController = new AbortController();\n\tif (options.signal) options.signal.addEventListener(`abort`, () => abortController.abort(options.signal?.reason), { once: true });\n\tconst fetchClient = createFetchWithBackoff(options.fetch ?? ((...args) => fetch(...args)), options.backoffOptions ?? BackoffDefaults);\n\tlet firstResponse;\n\ttry {\n\t\tfirstResponse = await fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `GET`,\n\t\t\theaders,\n\t\t\tsignal: abortController.signal\n\t\t});\n\t} catch (err) {\n\t\tif (err instanceof FetchBackoffAbortError) throw new DurableStreamError(`Stream request was aborted`, `UNKNOWN`);\n\t\tthrow err;\n\t}\n\tconst contentType = firstResponse.headers.get(`content-type`) ?? void 0;\n\tconst initialOffset = firstResponse.headers.get(STREAM_OFFSET_HEADER) ?? startOffset;\n\tconst initialCursor = firstResponse.headers.get(STREAM_CURSOR_HEADER) ?? void 0;\n\tconst initialUpToDate = firstResponse.headers.has(STREAM_UP_TO_DATE_HEADER);\n\tconst initialStreamClosed = firstResponse.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`;\n\tconst isJsonMode = options.json === true || (contentType?.includes(`application/json`) ?? false);\n\tconst encoding = firstResponse.headers.get(STREAM_SSE_DATA_ENCODING_HEADER) === `base64` ? `base64` : void 0;\n\tconst fetchNext = async (offset, cursor, signal, upToDate, resumingFromPause) => {\n\t\tconst nextUrl = new URL(url);\n\t\tnextUrl.searchParams.set(OFFSET_QUERY_PARAM, offset);\n\t\tif (upToDate && !resumingFromPause) {\n\t\t\tif (live === true || live === `long-poll`) nextUrl.searchParams.set(LIVE_QUERY_PARAM, `long-poll`);\n\t\t}\n\t\tif (cursor) nextUrl.searchParams.set(`cursor`, cursor);\n\t\tconst nextParams = await resolveParams(options.params);\n\t\tfor (const [key, value] of Object.entries(nextParams)) nextUrl.searchParams.set(key, value);\n\t\tconst nextHeaders = await resolveHeaders(options.headers);\n\t\tconst response = await fetchClient(nextUrl.toString(), {\n\t\t\tmethod: `GET`,\n\t\t\theaders: nextHeaders,\n\t\t\tsignal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, url);\n\t\treturn response;\n\t};\n\treturn new StreamResponseImpl({\n\t\turl,\n\t\tcontentType,\n\t\tlive,\n\t\tstartOffset,\n\t\tisJsonMode,\n\t\tinitialOffset,\n\t\tinitialCursor,\n\t\tinitialUpToDate,\n\t\tinitialStreamClosed,\n\t\tfirstResponse,\n\t\tabortController,\n\t\tfetchNext,\n\t\tstartSSE: live === `sse` ? async (offset, cursor, signal) => {\n\t\t\tconst sseUrl = new URL(url);\n\t\t\tsseUrl.searchParams.set(OFFSET_QUERY_PARAM, offset);\n\t\t\tsseUrl.searchParams.set(LIVE_QUERY_PARAM, `sse`);\n\t\t\tif (cursor) sseUrl.searchParams.set(`cursor`, cursor);\n\t\t\tconst sseParams = await resolveParams(options.params);\n\t\t\tfor (const [key, value] of Object.entries(sseParams)) sseUrl.searchParams.set(key, value);\n\t\t\tconst sseHeaders = await resolveHeaders(options.headers);\n\t\t\tconst response = await fetchClient(sseUrl.toString(), {\n\t\t\t\tmethod: `GET`,\n\t\t\t\theaders: sseHeaders,\n\t\t\t\tsignal\n\t\t\t});\n\t\t\tif (!response.ok) await handleErrorResponse(response, url);\n\t\t\treturn response;\n\t\t} : void 0,\n\t\tsseResilience: options.sseResilience,\n\t\tencoding\n\t});\n}\n/**\n* Error thrown when a producer's epoch is stale (zombie fencing).\n*/\nvar StaleEpochError = class extends Error {\n\t/**\n\t* The current epoch on the server.\n\t*/\n\tcurrentEpoch;\n\tconstructor(currentEpoch) {\n\t\tsuper(`Producer epoch is stale. Current server epoch: ${currentEpoch}. Call restart() or create a new producer with a higher epoch.`);\n\t\tthis.name = `StaleEpochError`;\n\t\tthis.currentEpoch = currentEpoch;\n\t}\n};\n/**\n* Error thrown when an unrecoverable sequence gap is detected.\n*\n* With maxInFlight > 1, HTTP requests can arrive out of order at the server,\n* causing temporary 409 responses. The client automatically handles these\n* by waiting for earlier sequences to complete, then retrying.\n*\n* This error is only thrown when the gap cannot be resolved (e.g., the\n* expected sequence is >= our sequence, indicating a true protocol violation).\n*/\nvar SequenceGapError = class extends Error {\n\texpectedSeq;\n\treceivedSeq;\n\tconstructor(expectedSeq, receivedSeq) {\n\t\tsuper(`Producer sequence gap: expected ${expectedSeq}, received ${receivedSeq}`);\n\t\tthis.name = `SequenceGapError`;\n\t\tthis.expectedSeq = expectedSeq;\n\t\tthis.receivedSeq = receivedSeq;\n\t}\n};\n/**\n* Normalize content-type by extracting the media type (before any semicolon).\n*/\nfunction normalizeContentType$1(contentType) {\n\tif (!contentType) return ``;\n\treturn contentType.split(`;`)[0].trim().toLowerCase();\n}\n/**\n* An idempotent producer for exactly-once writes to a durable stream.\n*\n* Features:\n* - Fire-and-forget: append() returns immediately, batches in background\n* - Exactly-once: server deduplicates using (producerId, epoch, seq)\n* - Batching: multiple appends batched into single HTTP request\n* - Pipelining: up to maxInFlight concurrent batches\n* - Zombie fencing: stale producers rejected via epoch validation\n*\n* @example\n* ```typescript\n* const stream = new DurableStream({ url: \"https://...\" });\n* const producer = new IdempotentProducer(stream, \"order-service-1\", {\n* epoch: 0,\n* autoClaim: true,\n* });\n*\n* // Fire-and-forget writes (synchronous, returns immediately)\n* producer.append(\"message 1\");\n* producer.append(\"message 2\");\n*\n* // Ensure all messages are delivered before shutdown\n* await producer.flush();\n* await producer.close();\n* ```\n*/\nvar IdempotentProducer = class {\n\t#stream;\n\t#producerId;\n\t#epoch;\n\t#nextSeq = 0;\n\t#autoClaim;\n\t#maxBatchBytes;\n\t#lingerMs;\n\t#fetchClient;\n\t#headers;\n\t#signal;\n\t#onError;\n\t#pendingBatch = [];\n\t#batchBytes = 0;\n\t#lingerTimeout = null;\n\t#queue;\n\t#maxInFlight;\n\t#deferredEnqueues = /* @__PURE__ */ new Set();\n\t#closed = false;\n\t#closeResult = null;\n\t#pendingFinalMessage;\n\t#lastSuccessfulOffset;\n\t#epochClaimed;\n\t#seqState = /* @__PURE__ */ new Map();\n\t/**\n\t* Create an idempotent producer for a stream.\n\t*\n\t* @param stream - The DurableStream to write to\n\t* @param producerId - Stable identifier for this producer (e.g., \"order-service-1\")\n\t* @param opts - Producer options\n\t*/\n\tconstructor(stream$1, producerId, opts) {\n\t\tconst epoch = opts?.epoch ?? 0;\n\t\tconst maxBatchBytes = opts?.maxBatchBytes ?? 1024 * 1024;\n\t\tconst maxInFlight = opts?.maxInFlight ?? 5;\n\t\tconst lingerMs = opts?.lingerMs ?? 5;\n\t\tif (epoch < 0) throw new Error(`epoch must be >= 0`);\n\t\tif (maxBatchBytes <= 0) throw new Error(`maxBatchBytes must be > 0`);\n\t\tif (maxInFlight <= 0) throw new Error(`maxInFlight must be > 0`);\n\t\tif (lingerMs < 0) throw new Error(`lingerMs must be >= 0`);\n\t\tthis.#stream = stream$1;\n\t\tthis.#producerId = producerId;\n\t\tthis.#epoch = epoch;\n\t\tthis.#autoClaim = opts?.autoClaim ?? false;\n\t\tthis.#maxBatchBytes = maxBatchBytes;\n\t\tthis.#lingerMs = lingerMs;\n\t\tthis.#signal = opts?.signal;\n\t\tthis.#headers = opts?.headers;\n\t\tthis.#onError = opts?.onError;\n\t\tthis.#fetchClient = opts?.fetch ?? ((...args) => fetch(...args));\n\t\tthis.#maxInFlight = maxInFlight;\n\t\tthis.#epochClaimed = !this.#autoClaim;\n\t\tthis.#queue = import_queue.default.promise(this.#batchWorker.bind(this), this.#maxInFlight);\n\t\tif (this.#signal) this.#signal.addEventListener(`abort`, () => {\n\t\t\tthis.#rejectPendingBatch(new DurableStreamError(`Producer aborted`, `ALREADY_CLOSED`, void 0, void 0));\n\t\t}, { once: true });\n\t}\n\t/**\n\t* Append data to the stream.\n\t*\n\t* This is fire-and-forget: returns immediately after adding to the batch.\n\t* The message is batched and sent when:\n\t* - maxBatchBytes is reached\n\t* - lingerMs elapses\n\t* - flush() is called\n\t*\n\t* Errors are reported via onError callback if configured. Use flush() to\n\t* wait for all pending messages to be sent.\n\t*\n\t* For JSON streams, pass pre-serialized JSON strings.\n\t* For byte streams, pass string or Uint8Array.\n\t*\n\t* @param body - Data to append (string or Uint8Array)\n\t*\n\t* @example\n\t* ```typescript\n\t* // JSON stream\n\t* producer.append(JSON.stringify({ message: \"hello\" }));\n\t*\n\t* // Byte stream\n\t* producer.append(\"raw text data\");\n\t* producer.append(new Uint8Array([1, 2, 3]));\n\t* ```\n\t*/\n\tappend(body) {\n\t\tif (this.#closed) throw new DurableStreamError(`Producer is closed`, `ALREADY_CLOSED`, void 0, void 0);\n\t\tlet bytes;\n\t\tif (typeof body === `string`) bytes = new TextEncoder().encode(body);\n\t\telse if (body instanceof Uint8Array) bytes = body;\n\t\telse throw new DurableStreamError(`append() requires string or Uint8Array. For objects, use JSON.stringify().`, `BAD_REQUEST`, 400, void 0);\n\t\tthis.#pendingBatch.push({ body: bytes });\n\t\tthis.#batchBytes += bytes.length;\n\t\tif (this.#batchBytes >= this.#maxBatchBytes) this.#enqueuePendingBatch();\n\t\telse if (!this.#lingerTimeout) this.#lingerTimeout = setTimeout(() => {\n\t\t\tthis.#lingerTimeout = null;\n\t\t\tif (this.#pendingBatch.length > 0) this.#enqueuePendingBatch();\n\t\t}, this.#lingerMs);\n\t}\n\t/**\n\t* Send any pending batch immediately and wait for all in-flight batches.\n\t*\n\t* Call this before shutdown to ensure all messages are delivered.\n\t*/\n\tasync flush() {\n\t\tif (this.#lingerTimeout) {\n\t\t\tclearTimeout(this.#lingerTimeout);\n\t\t\tthis.#lingerTimeout = null;\n\t\t}\n\t\tif (this.#pendingBatch.length > 0) this.#enqueuePendingBatch();\n\t\tdo {\n\t\t\tawait this.#queue.drained();\n\t\t\tawait Promise.all(this.#deferredEnqueues);\n\t\t} while (this.#deferredEnqueues.size > 0 || this.inFlightCount > 0);\n\t}\n\t/**\n\t* Stop the producer without closing the underlying stream.\n\t*\n\t* Use this when you want to:\n\t* - Hand off writing to another producer\n\t* - Keep the stream open for future writes\n\t* - Stop this producer but not signal EOF to readers\n\t*\n\t* Flushes any pending messages before detaching.\n\t* After calling detach(), further append() calls will throw.\n\t*/\n\tasync detach() {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\ttry {\n\t\t\tawait this.flush();\n\t\t} catch {}\n\t}\n\t/**\n\t* Flush pending messages and close the underlying stream (EOF).\n\t*\n\t* This is the typical way to end a producer session. It:\n\t* 1. Flushes all pending messages\n\t* 2. Optionally appends a final message\n\t* 3. Closes the stream (no further appends permitted)\n\t*\n\t* **Idempotent**: Unlike `DurableStream.close({ body })`, this method is\n\t* idempotent even with a final message because it uses producer headers\n\t* for deduplication. Safe to retry on network failures.\n\t*\n\t* @param finalMessage - Optional final message to append atomically with close\n\t* @returns CloseResult with the final offset\n\t*/\n\tasync close(finalMessage) {\n\t\tif (this.#closed) {\n\t\t\tif (this.#closeResult) return this.#closeResult;\n\t\t\tawait this.flush();\n\t\t\tconst result$1 = await this.#doClose(this.#pendingFinalMessage);\n\t\t\tthis.#closeResult = result$1;\n\t\t\treturn result$1;\n\t\t}\n\t\tthis.#closed = true;\n\t\tthis.#pendingFinalMessage = finalMessage;\n\t\tawait this.flush();\n\t\tconst result = await this.#doClose(finalMessage);\n\t\tthis.#closeResult = result;\n\t\treturn result;\n\t}\n\t/**\n\t* Actually close the stream with optional final message.\n\t* Uses producer headers for idempotency.\n\t*/\n\tasync #doClose(finalMessage) {\n\t\tconst contentType = this.#stream.contentType ?? `application/octet-stream`;\n\t\tconst isJson = normalizeContentType$1(contentType) === `application/json`;\n\t\tlet body;\n\t\tif (finalMessage !== void 0) {\n\t\t\tconst bodyBytes = typeof finalMessage === `string` ? new TextEncoder().encode(finalMessage) : finalMessage;\n\t\t\tif (isJson) body = `[${new TextDecoder().decode(bodyBytes)}]`;\n\t\t\telse body = bodyBytes;\n\t\t}\n\t\tconst seqForThisRequest = this.#nextSeq;\n\t\tconst headers = await this.#buildHeaders({\n\t\t\t\"content-type\": contentType,\n\t\t\t[PRODUCER_ID_HEADER]: this.#producerId,\n\t\t\t[PRODUCER_EPOCH_HEADER]: this.#epoch.toString(),\n\t\t\t[PRODUCER_SEQ_HEADER]: seqForThisRequest.toString(),\n\t\t\t[STREAM_CLOSED_HEADER]: `true`\n\t\t});\n\t\tconst response = await this.#fetchClient(this.#stream.url, {\n\t\t\tmethod: `POST`,\n\t\t\theaders,\n\t\t\tbody,\n\t\t\tsignal: this.#signal\n\t\t});\n\t\tif (response.status === 204) {\n\t\t\tthis.#nextSeq = seqForThisRequest + 1;\n\t\t\tconst finalOffset = response.headers.get(STREAM_OFFSET_HEADER) ?? ``;\n\t\t\tthis.#recordSuccessfulOffset(finalOffset);\n\t\t\treturn { finalOffset };\n\t\t}\n\t\tif (response.status === 200) {\n\t\t\tthis.#nextSeq = seqForThisRequest + 1;\n\t\t\tconst finalOffset = response.headers.get(STREAM_OFFSET_HEADER) ?? ``;\n\t\t\tthis.#recordSuccessfulOffset(finalOffset);\n\t\t\treturn { finalOffset };\n\t\t}\n\t\tif (response.status === 403) {\n\t\t\tconst currentEpochStr = response.headers.get(PRODUCER_EPOCH_HEADER);\n\t\t\tconst currentEpoch = currentEpochStr ? parseInt(currentEpochStr, 10) : this.#epoch;\n\t\t\tif (this.#autoClaim) {\n\t\t\t\tconst newEpoch = currentEpoch + 1;\n\t\t\t\tthis.#epoch = newEpoch;\n\t\t\t\tthis.#nextSeq = 0;\n\t\t\t\treturn this.#doClose(finalMessage);\n\t\t\t}\n\t\t\tthrow new StaleEpochError(currentEpoch);\n\t\t}\n\t\tthrow await FetchError.fromResponse(response, this.#stream.url);\n\t}\n\t/**\n\t* Increment epoch and reset sequence.\n\t*\n\t* Call this when restarting the producer to establish a new session.\n\t* Flushes any pending messages first.\n\t*/\n\tasync restart() {\n\t\tawait this.flush();\n\t\tthis.#epoch++;\n\t\tthis.#nextSeq = 0;\n\t}\n\t/**\n\t* Current epoch for this producer.\n\t*/\n\tget epoch() {\n\t\treturn this.#epoch;\n\t}\n\t/**\n\t* Next sequence number to be assigned.\n\t*/\n\tget nextSeq() {\n\t\treturn this.#nextSeq;\n\t}\n\t/**\n\t* Number of messages in the current pending batch.\n\t*/\n\tget pendingCount() {\n\t\treturn this.#pendingBatch.length;\n\t}\n\t/**\n\t* Number of batches currently in flight.\n\t*/\n\tget inFlightCount() {\n\t\treturn this.#queue.length() + this.#queue.running();\n\t}\n\t/**\n\t* The greatest non-empty stream offset returned by a successful producer\n\t* append or close request.\n\t*/\n\tget lastSuccessfulOffset() {\n\t\treturn this.#lastSuccessfulOffset;\n\t}\n\t/**\n\t* Enqueue the current pending batch for processing.\n\t*/\n\t#enqueuePendingBatch() {\n\t\tif (this.#pendingBatch.length === 0) return;\n\t\tconst batch = this.#pendingBatch;\n\t\tthis.#pendingBatch = [];\n\t\tthis.#batchBytes = 0;\n\t\tif (this.#autoClaim && !this.#epochClaimed && this.inFlightCount > 0) {\n\t\t\tconst deferred = this.#queue.drained().then(() => {\n\t\t\t\tthis.#pushBatch(batch);\n\t\t\t}).finally(() => {\n\t\t\t\tthis.#deferredEnqueues.delete(deferred);\n\t\t\t});\n\t\t\tthis.#deferredEnqueues.add(deferred);\n\t\t\tdeferred.catch(() => {});\n\t\t} else this.#pushBatch(batch);\n\t}\n\t#pushBatch(batch) {\n\t\tconst seq = this.#nextSeq;\n\t\tthis.#nextSeq++;\n\t\tthis.#queue.push({\n\t\t\tbatch,\n\t\t\tseq\n\t\t}).catch(() => {});\n\t}\n\t/**\n\t* Batch worker - processes batches via fastq.\n\t*/\n\tasync #batchWorker(task) {\n\t\tconst { batch, seq } = task;\n\t\tconst epoch = this.#epoch;\n\t\ttry {\n\t\t\tconst result = await this.#doSendBatch(batch, seq, epoch);\n\t\t\tthis.#recordSuccessfulOffset(result.offset);\n\t\t\tif (!this.#epochClaimed) this.#epochClaimed = true;\n\t\t\tthis.#signalSeqComplete(epoch, seq, void 0);\n\t\t} catch (error) {\n\t\t\tthis.#signalSeqComplete(epoch, seq, error);\n\t\t\tif (this.#onError) this.#onError(error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\t#recordSuccessfulOffset(offset) {\n\t\tif (offset && (!this.#lastSuccessfulOffset || offset > this.#lastSuccessfulOffset)) this.#lastSuccessfulOffset = offset;\n\t}\n\t/**\n\t* Signal that a sequence has completed (success or failure).\n\t*/\n\t#signalSeqComplete(epoch, seq, error) {\n\t\tlet epochMap = this.#seqState.get(epoch);\n\t\tif (!epochMap) {\n\t\t\tepochMap = /* @__PURE__ */ new Map();\n\t\t\tthis.#seqState.set(epoch, epochMap);\n\t\t}\n\t\tconst state = epochMap.get(seq);\n\t\tif (state) {\n\t\t\tstate.resolved = true;\n\t\t\tstate.error = error;\n\t\t\tfor (const waiter of state.waiters) waiter(error);\n\t\t\tstate.waiters = [];\n\t\t} else epochMap.set(seq, {\n\t\t\tresolved: true,\n\t\t\terror,\n\t\t\twaiters: []\n\t\t});\n\t\tconst cleanupThreshold = seq - this.#maxInFlight * 3;\n\t\tif (cleanupThreshold > 0) {\n\t\t\tfor (const oldSeq of epochMap.keys()) if (oldSeq < cleanupThreshold) epochMap.delete(oldSeq);\n\t\t}\n\t}\n\t/**\n\t* Wait for a specific sequence to complete.\n\t* Returns immediately if already completed.\n\t* Throws if the sequence failed.\n\t*/\n\t#waitForSeq(epoch, seq) {\n\t\tlet epochMap = this.#seqState.get(epoch);\n\t\tif (!epochMap) {\n\t\t\tepochMap = /* @__PURE__ */ new Map();\n\t\t\tthis.#seqState.set(epoch, epochMap);\n\t\t}\n\t\tconst state = epochMap.get(seq);\n\t\tif (state?.resolved) {\n\t\t\tif (state.error) return Promise.reject(state.error);\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst waiter = (err) => {\n\t\t\t\tif (err) reject(err);\n\t\t\t\telse resolve();\n\t\t\t};\n\t\t\tif (state) state.waiters.push(waiter);\n\t\t\telse epochMap.set(seq, {\n\t\t\t\tresolved: false,\n\t\t\t\twaiters: [waiter]\n\t\t\t});\n\t\t});\n\t}\n\t/**\n\t* Actually send the batch to the server.\n\t* Handles auto-claim retry on 403 (stale epoch) if autoClaim is enabled.\n\t* Does NOT implement general retry/backoff for network errors or 5xx responses.\n\t*/\n\tasync #doSendBatch(batch, seq, epoch) {\n\t\tconst contentType = this.#stream.contentType ?? `application/octet-stream`;\n\t\tconst isJson = normalizeContentType$1(contentType) === `application/json`;\n\t\tlet batchedBody;\n\t\tif (isJson) batchedBody = `[${batch.map((e) => new TextDecoder().decode(e.body)).join(`,`)}]`;\n\t\telse {\n\t\t\tconst totalSize = batch.reduce((sum, e) => sum + e.body.length, 0);\n\t\t\tconst concatenated = new Uint8Array(totalSize);\n\t\t\tlet offset = 0;\n\t\t\tfor (const entry of batch) {\n\t\t\t\tconcatenated.set(entry.body, offset);\n\t\t\t\toffset += entry.body.length;\n\t\t\t}\n\t\t\tbatchedBody = concatenated;\n\t\t}\n\t\tconst url = this.#stream.url;\n\t\tconst headers = await this.#buildHeaders({\n\t\t\t\"content-type\": contentType,\n\t\t\t[PRODUCER_ID_HEADER]: this.#producerId,\n\t\t\t[PRODUCER_EPOCH_HEADER]: epoch.toString(),\n\t\t\t[PRODUCER_SEQ_HEADER]: seq.toString()\n\t\t});\n\t\tconst response = await this.#fetchClient(url, {\n\t\t\tmethod: `POST`,\n\t\t\theaders,\n\t\t\tbody: batchedBody,\n\t\t\tsignal: this.#signal\n\t\t});\n\t\tif (response.status === 204) return {\n\t\t\toffset: ``,\n\t\t\tduplicate: true\n\t\t};\n\t\tif (response.status === 200) return {\n\t\t\toffset: response.headers.get(STREAM_OFFSET_HEADER) ?? ``,\n\t\t\tduplicate: false\n\t\t};\n\t\tif (response.status === 403) {\n\t\t\tconst currentEpochStr = response.headers.get(PRODUCER_EPOCH_HEADER);\n\t\t\tconst currentEpoch = currentEpochStr ? parseInt(currentEpochStr, 10) : epoch;\n\t\t\tif (this.#autoClaim) {\n\t\t\t\tconst newEpoch = currentEpoch + 1;\n\t\t\t\tthis.#epoch = newEpoch;\n\t\t\t\tthis.#nextSeq = 1;\n\t\t\t\treturn this.#doSendBatch(batch, 0, newEpoch);\n\t\t\t}\n\t\t\tthrow new StaleEpochError(currentEpoch);\n\t\t}\n\t\tif (response.status === 409) {\n\t\t\tconst expectedSeqStr = response.headers.get(PRODUCER_EXPECTED_SEQ_HEADER);\n\t\t\tconst expectedSeq = expectedSeqStr ? parseInt(expectedSeqStr, 10) : 0;\n\t\t\tif (expectedSeq < seq) {\n\t\t\t\tconst waitPromises = [];\n\t\t\t\tfor (let s = expectedSeq; s < seq; s++) waitPromises.push(this.#waitForSeq(epoch, s));\n\t\t\t\tawait Promise.all(waitPromises);\n\t\t\t\treturn this.#doSendBatch(batch, seq, epoch);\n\t\t\t}\n\t\t\tconst receivedSeqStr = response.headers.get(PRODUCER_RECEIVED_SEQ_HEADER);\n\t\t\tthrow new SequenceGapError(expectedSeq, receivedSeqStr ? parseInt(receivedSeqStr, 10) : seq);\n\t\t}\n\t\tif (response.status === 400) throw await DurableStreamError.fromResponse(response, url);\n\t\tthrow await FetchError.fromResponse(response, url);\n\t}\n\tasync #buildHeaders(protocolHeaders) {\n\t\tconst streamHeaders = await this.#stream.resolveHeaders();\n\t\tconst producerHeaders = await resolveHeaders(this.#headers);\n\t\treturn {\n\t\t\t...streamHeaders,\n\t\t\t...producerHeaders,\n\t\t\t...protocolHeaders\n\t\t};\n\t}\n\t/**\n\t* Clear pending batch and report error.\n\t*/\n\t#rejectPendingBatch(error) {\n\t\tif (this.#onError && this.#pendingBatch.length > 0) this.#onError(error);\n\t\tthis.#pendingBatch = [];\n\t\tthis.#batchBytes = 0;\n\t\tif (this.#lingerTimeout) {\n\t\t\tclearTimeout(this.#lingerTimeout);\n\t\t\tthis.#lingerTimeout = null;\n\t\t}\n\t}\n};\n/**\n* Normalize content-type by extracting the media type (before any semicolon).\n* Handles cases like \"application/json; charset=utf-8\".\n*/\nfunction normalizeContentType(contentType) {\n\tif (!contentType) return ``;\n\treturn contentType.split(`;`)[0].trim().toLowerCase();\n}\n/**\n* Check if a value is a Promise or Promise-like (thenable).\n*/\nfunction isPromiseLike(value) {\n\treturn value != null && typeof value.then === `function`;\n}\n/**\n* A handle to a remote durable stream for read/write operations.\n*\n* This is a lightweight, reusable handle - not a persistent connection.\n* It does not automatically start reading or listening.\n* Create sessions as needed via stream().\n*\n* @example\n* ```typescript\n* // Create a new stream\n* const stream = await DurableStream.create({\n* url: \"https://streams.example.com/my-stream\",\n* headers: { Authorization: \"Bearer my-token\" },\n* contentType: \"application/json\"\n* });\n*\n* // Single write\n* await stream.append(JSON.stringify({ message: \"hello\" }));\n*\n* // Read with the new API\n* const res = await stream.stream<{ message: string }>();\n* res.subscribeJson(async (batch) => {\n* for (const item of batch.items) {\n* console.log(item.message);\n* }\n* });\n* ```\n*/\nvar DurableStream = class DurableStream {\n\t/**\n\t* The URL of the durable stream.\n\t*/\n\turl;\n\t/**\n\t* The content type of the stream (populated after connect/head/read).\n\t*/\n\tcontentType;\n\t#options;\n\t#fetchClient;\n\t#baseFetchClient;\n\t#onError;\n\t#batchingEnabled;\n\t#queue;\n\t#buffer = [];\n\t/**\n\t* Create a cold handle to a stream.\n\t* No network IO is performed by the constructor.\n\t*/\n\tconstructor(opts) {\n\t\tvalidateOptions(opts);\n\t\tconst urlStr = opts.url instanceof URL ? opts.url.toString() : opts.url;\n\t\tthis.url = urlStr;\n\t\tthis.#options = {\n\t\t\t...opts,\n\t\t\turl: urlStr\n\t\t};\n\t\tthis.#onError = opts.onError;\n\t\tif (opts.contentType) this.contentType = opts.contentType;\n\t\tthis.#batchingEnabled = opts.batching !== false;\n\t\tif (this.#batchingEnabled) this.#queue = import_queue.default.promise(this.#batchWorker.bind(this), 1);\n\t\tthis.#baseFetchClient = opts.fetch ?? ((...args) => fetch(...args));\n\t\tconst backOffOpts = { ...opts.backoffOptions ?? BackoffDefaults };\n\t\tconst fetchWithBackoffClient = createFetchWithBackoff(this.#baseFetchClient, backOffOpts);\n\t\tthis.#fetchClient = createFetchWithConsumedBody(fetchWithBackoffClient);\n\t}\n\t/**\n\t* Create a new stream (create-only PUT) and return a handle.\n\t* Fails with DurableStreamError(code=\"CONFLICT_EXISTS\") if it already exists.\n\t*/\n\tstatic async create(opts) {\n\t\tconst stream$1 = new DurableStream(opts);\n\t\tawait stream$1.create({\n\t\t\tcontentType: opts.contentType,\n\t\t\tttlSeconds: opts.ttlSeconds,\n\t\t\texpiresAt: opts.expiresAt,\n\t\t\tbody: opts.body,\n\t\t\tclosed: opts.closed\n\t\t});\n\t\treturn stream$1;\n\t}\n\t/**\n\t* Validate that a stream exists and fetch metadata via HEAD.\n\t* Returns a handle with contentType populated (if sent by server).\n\t*\n\t* **Important**: This only performs a HEAD request for validation - it does\n\t* NOT open a session or start reading data. To read from the stream, call\n\t* `stream()` on the returned handle.\n\t*\n\t* @example\n\t* ```typescript\n\t* // Validate stream exists before reading\n\t* const handle = await DurableStream.connect({ url })\n\t* const res = await handle.stream() // Now actually read\n\t* ```\n\t*/\n\tstatic async connect(opts) {\n\t\tconst stream$1 = new DurableStream(opts);\n\t\tawait stream$1.head();\n\t\treturn stream$1;\n\t}\n\t/**\n\t* HEAD metadata for a stream without creating a handle.\n\t*/\n\tstatic async head(opts) {\n\t\treturn new DurableStream(opts).head();\n\t}\n\t/**\n\t* Delete a stream without creating a handle.\n\t*/\n\tstatic async delete(opts) {\n\t\treturn new DurableStream(opts).delete();\n\t}\n\t/**\n\t* HEAD metadata for this stream.\n\t*/\n\tasync head(opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst response = await this.#baseFetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `HEAD`,\n\t\t\theaders: requestHeaders,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tif (response.status === 404) return { exists: false };\n\t\t\tawait handleErrorResponse(response, this.url);\n\t\t}\n\t\tconst contentType = response.headers.get(`content-type`) ?? void 0;\n\t\tconst offset = response.headers.get(STREAM_OFFSET_HEADER) ?? void 0;\n\t\tconst etag = response.headers.get(`etag`) ?? void 0;\n\t\tconst cacheControl = response.headers.get(`cache-control`) ?? void 0;\n\t\tconst streamClosed = response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`;\n\t\tif (contentType) this.contentType = contentType;\n\t\treturn {\n\t\t\texists: true,\n\t\t\tcontentType,\n\t\t\toffset,\n\t\t\tetag,\n\t\t\tcacheControl,\n\t\t\tstreamClosed\n\t\t};\n\t}\n\t/**\n\t* Create this stream (create-only PUT) using the URL/auth from the handle.\n\t*/\n\tasync create(opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = opts?.contentType ?? this.#options.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\tif (opts?.ttlSeconds !== void 0) requestHeaders[STREAM_TTL_HEADER] = String(opts.ttlSeconds);\n\t\tif (opts?.expiresAt) requestHeaders[STREAM_EXPIRES_AT_HEADER] = opts.expiresAt;\n\t\tif (opts?.closed) requestHeaders[STREAM_CLOSED_HEADER] = `true`;\n\t\tconst body = encodeBody(opts?.body);\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `PUT`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody,\n\t\t\tsignal: this.#options.signal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url, { operation: `create` });\n\t\tconst responseContentType = response.headers.get(`content-type`);\n\t\tif (responseContentType) this.contentType = responseContentType;\n\t\telse if (contentType) this.contentType = contentType;\n\t\treturn this;\n\t}\n\t/**\n\t* Delete this stream.\n\t*/\n\tasync delete(opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `DELETE`,\n\t\t\theaders: requestHeaders,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t}\n\t/**\n\t* Close the stream, optionally with a final message.\n\t*\n\t* After closing:\n\t* - No further appends are permitted (server returns 409)\n\t* - Readers can observe the closed state and treat it as EOF\n\t* - The stream's data remains fully readable\n\t*\n\t* Closing is:\n\t* - **Durable**: The closed state is persisted\n\t* - **Monotonic**: Once closed, a stream cannot be reopened\n\t*\n\t* **Idempotency:**\n\t* - `close()` without body: Idempotent — safe to call multiple times\n\t* - `close({ body })` with body: NOT idempotent — throws `StreamClosedError`\n\t* if stream is already closed (use `IdempotentProducer.close()` for\n\t* idempotent close-with-body semantics)\n\t*\n\t* @returns CloseResult with the final offset\n\t* @throws StreamClosedError if called with body on an already-closed stream\n\t*/\n\tasync close(opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = opts?.contentType ?? this.#options.contentType ?? this.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\trequestHeaders[STREAM_CLOSED_HEADER] = `true`;\n\t\tlet body;\n\t\tif (opts?.body !== void 0) if (normalizeContentType(contentType) === `application/json`) body = `[${typeof opts.body === `string` ? opts.body : new TextDecoder().decode(opts.body)}]`;\n\t\telse body = typeof opts.body === `string` ? opts.body : opts.body;\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `POST`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (response.status === 409) {\n\t\t\tif (response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`) {\n\t\t\t\tconst finalOffset$1 = response.headers.get(STREAM_OFFSET_HEADER) ?? void 0;\n\t\t\t\tthrow new StreamClosedError(this.url, finalOffset$1);\n\t\t\t}\n\t\t}\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t\treturn { finalOffset: response.headers.get(STREAM_OFFSET_HEADER) ?? `` };\n\t}\n\t/**\n\t* Append a single payload to the stream.\n\t*\n\t* Batching: when batching is enabled (default), append() calls that overlap\n\t* in time (e.g. fired without awaiting each one) are coalesced into a\n\t* single POST while a prior POST is in flight. If every call is awaited\n\t* before the next is issued, no batching happens — each call becomes its\n\t* own roundtrip. For tight loops driving an async iterable (e.g. LLM\n\t* token streams), prefer `appendStream()` / `writable()` which pipe the\n\t* source over a single POST, or fire `append()` calls without awaiting\n\t* each one and await the last promise (and `close()`) at the end.\n\t*\n\t* - `body` must be string or Uint8Array.\n\t* - For JSON streams, pass pre-serialized JSON strings.\n\t* - `body` may also be a Promise that resolves to string or Uint8Array.\n\t* - Strings are encoded as UTF-8.\n\t* - `seq` (if provided) is sent as stream-seq (writer coordination).\n\t*\n\t* @example\n\t* ```typescript\n\t* // JSON stream - pass pre-serialized JSON (single write)\n\t* await stream.append(JSON.stringify({ message: \"hello\" }));\n\t*\n\t* // Byte stream\n\t* await stream.append(\"raw text data\");\n\t* await stream.append(new Uint8Array([1, 2, 3]));\n\t*\n\t* // Promise value - awaited before buffering\n\t* await stream.append(fetchData());\n\t*\n\t* // High-frequency writes from an async iterable - fire-and-track-last\n\t* let last: Promise<void> = Promise.resolve();\n\t* for await (const chunk of source) {\n\t* last = stream.append(JSON.stringify(chunk));\n\t* }\n\t* await last;\n\t* await stream.close();\n\t* ```\n\t*/\n\tasync append(body, opts) {\n\t\tconst resolvedBody = isPromiseLike(body) ? await body : body;\n\t\tif (this.#batchingEnabled && this.#queue) return this.#appendWithBatching(resolvedBody, opts);\n\t\treturn this.#appendDirect(resolvedBody, opts);\n\t}\n\t/**\n\t* Direct append without batching (used when batching is disabled).\n\t*/\n\tasync #appendDirect(body, opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = opts?.contentType ?? this.#options.contentType ?? this.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\tif (opts?.seq) requestHeaders[STREAM_SEQ_HEADER] = opts.seq;\n\t\tconst isJson = normalizeContentType(contentType) === `application/json`;\n\t\tlet encodedBody;\n\t\tif (isJson) encodedBody = `[${typeof body === `string` ? body : new TextDecoder().decode(body)}]`;\n\t\telse if (typeof body === `string`) encodedBody = body;\n\t\telse encodedBody = body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength);\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `POST`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody: encodedBody,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t}\n\t/**\n\t* Append with batching - buffers messages and sends them in batches.\n\t*/\n\tasync #appendWithBatching(body, opts) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.#buffer.push({\n\t\t\t\tdata: body,\n\t\t\t\tseq: opts?.seq,\n\t\t\t\tcontentType: opts?.contentType,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tresolve,\n\t\t\t\treject\n\t\t\t});\n\t\t\tif (this.#queue.idle()) {\n\t\t\t\tconst batch = this.#buffer.splice(0);\n\t\t\t\tthis.#queue.push(batch).catch((err) => {\n\t\t\t\t\tfor (const msg of batch) msg.reject(err);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Batch worker - processes batches of messages.\n\t*/\n\tasync #batchWorker(batch) {\n\t\ttry {\n\t\t\tawait this.#sendBatch(batch);\n\t\t\tfor (const msg of batch) msg.resolve();\n\t\t\tif (this.#buffer.length > 0) {\n\t\t\t\tconst nextBatch = this.#buffer.splice(0);\n\t\t\t\tthis.#queue.push(nextBatch).catch((err) => {\n\t\t\t\t\tfor (const msg of nextBatch) msg.reject(err);\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfor (const msg of batch) msg.reject(error);\n\t\t\tfor (const msg of this.#buffer) msg.reject(error);\n\t\t\tthis.#buffer = [];\n\t\t\tthrow error;\n\t\t}\n\t}\n\t/**\n\t* Send a batch of messages as a single POST request.\n\t*/\n\tasync #sendBatch(batch) {\n\t\tif (batch.length === 0) return;\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = batch[0]?.contentType ?? this.#options.contentType ?? this.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\tlet highestSeq;\n\t\tfor (let i = batch.length - 1; i >= 0; i--) if (batch[i].seq !== void 0) {\n\t\t\thighestSeq = batch[i].seq;\n\t\t\tbreak;\n\t\t}\n\t\tif (highestSeq) requestHeaders[STREAM_SEQ_HEADER] = highestSeq;\n\t\tconst isJson = normalizeContentType(contentType) === `application/json`;\n\t\tlet batchedBody;\n\t\tif (isJson) batchedBody = `[${batch.map((m) => typeof m.data === `string` ? m.data : new TextDecoder().decode(m.data)).join(`,`)}]`;\n\t\telse {\n\t\t\tconst hasUint8Array = batch.some((m) => m.data instanceof Uint8Array);\n\t\t\tconst hasString = batch.some((m) => typeof m.data === `string`);\n\t\t\tif (hasUint8Array && !hasString) {\n\t\t\t\tconst chunks = batch.map((m) => m.data);\n\t\t\t\tconst totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n\t\t\t\tconst combined = new Uint8Array(totalLength);\n\t\t\t\tlet offset = 0;\n\t\t\t\tfor (const chunk of chunks) {\n\t\t\t\t\tcombined.set(chunk, offset);\n\t\t\t\t\toffset += chunk.length;\n\t\t\t\t}\n\t\t\t\tbatchedBody = combined;\n\t\t\t} else if (hasString && !hasUint8Array) batchedBody = batch.map((m) => m.data).join(``);\n\t\t\telse {\n\t\t\t\tconst encoder = new TextEncoder();\n\t\t\t\tconst chunks = batch.map((m) => typeof m.data === `string` ? encoder.encode(m.data) : m.data);\n\t\t\t\tconst totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n\t\t\t\tconst combined = new Uint8Array(totalLength);\n\t\t\t\tlet offset = 0;\n\t\t\t\tfor (const chunk of chunks) {\n\t\t\t\t\tcombined.set(chunk, offset);\n\t\t\t\t\toffset += chunk.length;\n\t\t\t\t}\n\t\t\t\tbatchedBody = combined;\n\t\t\t}\n\t\t}\n\t\tconst signals = [];\n\t\tif (this.#options.signal) signals.push(this.#options.signal);\n\t\tfor (const msg of batch) if (msg.signal) signals.push(msg.signal);\n\t\tconst combinedSignal = signals.length > 0 ? AbortSignal.any(signals) : void 0;\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `POST`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody: batchedBody,\n\t\t\tsignal: combinedSignal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t}\n\t/**\n\t* Append a streaming body to the stream.\n\t*\n\t* Supports piping from any ReadableStream or async iterable:\n\t* - `source` yields Uint8Array or string chunks.\n\t* - Strings are encoded as UTF-8; no delimiters are added.\n\t* - Internally uses chunked transfer or HTTP/2 streaming.\n\t*\n\t* @example\n\t* ```typescript\n\t* // Pipe from a ReadableStream\n\t* const readable = new ReadableStream({\n\t* start(controller) {\n\t* controller.enqueue(\"chunk 1\");\n\t* controller.enqueue(\"chunk 2\");\n\t* controller.close();\n\t* }\n\t* });\n\t* await stream.appendStream(readable);\n\t*\n\t* // Pipe from an async generator\n\t* async function* generate() {\n\t* yield \"line 1\\n\";\n\t* yield \"line 2\\n\";\n\t* }\n\t* await stream.appendStream(generate());\n\t*\n\t* // Pipe from fetch response body\n\t* const response = await fetch(\"https://example.com/data\");\n\t* await stream.appendStream(response.body!);\n\t* ```\n\t*/\n\tasync appendStream(source, opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = opts?.contentType ?? this.#options.contentType ?? this.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\tif (opts?.seq) requestHeaders[STREAM_SEQ_HEADER] = opts.seq;\n\t\tconst body = toReadableStream(source);\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `POST`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody,\n\t\t\tduplex: `half`,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t}\n\t/**\n\t* Create a writable stream that pipes data to this durable stream.\n\t*\n\t* Returns a WritableStream that can be used with `pipeTo()` or\n\t* `pipeThrough()` from any ReadableStream source.\n\t*\n\t* Uses IdempotentProducer internally for:\n\t* - Automatic batching (controlled by lingerMs, maxBatchBytes)\n\t* - Exactly-once delivery semantics\n\t* - Streaming writes (doesn't buffer entire content in memory)\n\t*\n\t* @example\n\t* ```typescript\n\t* // Pipe from fetch response\n\t* const response = await fetch(\"https://example.com/data\");\n\t* await response.body!.pipeTo(stream.writable());\n\t*\n\t* // Pipe through a transform\n\t* const readable = someStream.pipeThrough(new TextEncoderStream());\n\t* await readable.pipeTo(stream.writable());\n\t*\n\t* // With custom producer options\n\t* await source.pipeTo(stream.writable({\n\t* producerId: \"my-producer\",\n\t* lingerMs: 10,\n\t* maxBatchBytes: 64 * 1024,\n\t* }));\n\t* ```\n\t*/\n\twritable(opts) {\n\t\tconst producerId = opts?.producerId ?? `writable-${crypto.randomUUID().slice(0, 8)}`;\n\t\tlet writeError = null;\n\t\tconst producer = new IdempotentProducer(this, producerId, {\n\t\t\tautoClaim: true,\n\t\t\theaders: opts?.headers,\n\t\t\tlingerMs: opts?.lingerMs,\n\t\t\tmaxBatchBytes: opts?.maxBatchBytes,\n\t\t\tonError: (error) => {\n\t\t\t\tif (!writeError) writeError = error;\n\t\t\t\topts?.onError?.(error);\n\t\t\t},\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\treturn new WritableStream({\n\t\t\twrite(chunk) {\n\t\t\t\tproducer.append(chunk);\n\t\t\t},\n\t\t\tasync close() {\n\t\t\t\tawait producer.close();\n\t\t\t\tif (writeError) throw writeError;\n\t\t\t},\n\t\t\tabort(_reason) {\n\t\t\t\tproducer.detach().catch((err) => {\n\t\t\t\t\topts?.onError?.(err);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Start a fetch-like streaming session against this handle's URL/headers/params.\n\t* The first request is made inside this method; it resolves when we have\n\t* a valid first response, or rejects on errors.\n\t*\n\t* Call-specific headers and params are merged with handle-level ones,\n\t* with call-specific values taking precedence.\n\t*\n\t* @example\n\t* ```typescript\n\t* const handle = await DurableStream.connect({\n\t* url,\n\t* headers: { Authorization: `Bearer ${token}` }\n\t* });\n\t* const res = await handle.stream<{ message: string }>();\n\t*\n\t* // Accumulate all JSON items\n\t* const items = await res.json();\n\t*\n\t* // Or stream live with ReadableStream\n\t* const reader = res.jsonStream().getReader();\n\t* let result = await reader.read();\n\t* while (!result.done) {\n\t* console.log(result.value);\n\t* result = await reader.read();\n\t* }\n\t*\n\t* // Or use subscriber for backpressure-aware consumption\n\t* res.subscribeJson(async (batch) => {\n\t* for (const item of batch.items) {\n\t* console.log(item);\n\t* }\n\t* });\n\t* ```\n\t*/\n\tasync stream(options) {\n\t\tconst mergedHeaders = {\n\t\t\t...this.#options.headers,\n\t\t\t...options?.headers\n\t\t};\n\t\tconst mergedParams = {\n\t\t\t...this.#options.params,\n\t\t\t...options?.params\n\t\t};\n\t\treturn stream({\n\t\t\turl: this.url,\n\t\t\theaders: mergedHeaders,\n\t\t\tparams: mergedParams,\n\t\t\tsignal: options?.signal ?? this.#options.signal,\n\t\t\tfetch: this.#options.fetch,\n\t\t\tbackoffOptions: this.#options.backoffOptions,\n\t\t\toffset: options?.offset,\n\t\t\tlive: options?.live,\n\t\t\tjson: options?.json,\n\t\t\tonError: options?.onError ?? this.#onError,\n\t\t\twarnOnHttp: options?.warnOnHttp ?? this.#options.warnOnHttp\n\t\t});\n\t}\n\t/**\n\t* Resolve the stream's configured headers.\n\t* Used by IdempotentProducer to merge auth headers into its requests.\n\t* @internal\n\t*/\n\tasync resolveHeaders() {\n\t\treturn resolveHeaders(this.#options.headers);\n\t}\n\t/**\n\t* Build request headers and URL.\n\t*/\n\tasync #buildRequest() {\n\t\tconst requestHeaders = await resolveHeaders(this.#options.headers);\n\t\tconst fetchUrl = new URL(this.url);\n\t\tconst params = await resolveParams(this.#options.params);\n\t\tfor (const [key, value] of Object.entries(params)) fetchUrl.searchParams.set(key, value);\n\t\treturn {\n\t\t\trequestHeaders,\n\t\t\tfetchUrl\n\t\t};\n\t}\n};\n/**\n* Encode a body value to the appropriate format.\n* Strings are encoded as UTF-8.\n* Objects are JSON-serialized.\n*/\nfunction encodeBody(body) {\n\tif (body === void 0) return void 0;\n\tif (typeof body === `string`) return new TextEncoder().encode(body);\n\tif (body instanceof Uint8Array) return body;\n\tif (body instanceof Blob || body instanceof FormData || body instanceof ReadableStream || body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return body;\n\treturn new TextEncoder().encode(JSON.stringify(body));\n}\n/**\n* Convert an async iterable to a ReadableStream.\n*/\nfunction toReadableStream(source) {\n\tif (source instanceof ReadableStream) return source.pipeThrough(new TransformStream({ transform(chunk, controller) {\n\t\tif (typeof chunk === `string`) controller.enqueue(new TextEncoder().encode(chunk));\n\t\telse controller.enqueue(chunk);\n\t} }));\n\tconst encoder = new TextEncoder();\n\tconst iterator = source[Symbol.asyncIterator]();\n\treturn new ReadableStream({\n\t\tasync pull(controller) {\n\t\t\ttry {\n\t\t\t\tconst { done, value } = await iterator.next();\n\t\t\t\tif (done) controller.close();\n\t\t\t\telse if (typeof value === `string`) controller.enqueue(encoder.encode(value));\n\t\t\t\telse controller.enqueue(value);\n\t\t\t} catch (e) {\n\t\t\t\tcontroller.error(e);\n\t\t\t}\n\t\t},\n\t\tcancel() {\n\t\t\titerator.return?.();\n\t\t}\n\t});\n}\n/**\n* Validate stream options.\n*/\nfunction validateOptions(options) {\n\tif (!options.url) throw new MissingStreamUrlError();\n\tif (options.signal && !(options.signal instanceof AbortSignal)) throw new InvalidSignalError();\n\twarnIfUsingHttpInBrowser(options.url, options.warnOnHttp);\n}\n//#endregion\n//#region src/client.ts\n/**\n* The streams client a consumer's `durableStreams()` binding hydrates to —\n* the RPC parity: RPC users don't hand-roll request encoding (`rpc()` hydrates\n* through `makeClient`), and streams users don't hand-roll the Durable Streams\n* protocol. All protocol knowledge lives here: the URL layout, the bearer\n* scheme, JSON-array append framing, opaque offsets, and the long-poll dance\n* — plus the stream lifecycle (ensure-create, the proven-safe 404 heal) that\n* used to live in application code. The wire client is\n* `@durable-streams/client` (ElectricSQL's canonical protocol client,\n* Apache-2.0); this wrapper narrows it to what the module contract promises\n* and adds the platform compensations, each annotated with the ticket it\n* stands in for.\n*\n* Two classes: `StreamsClient` holds the transport (base URL, bearer header,\n* the per-stream write handles a batched append needs) and hands out one\n* `StreamHandle` per stream name, memoized so its ensure-create state\n* survives repeat calls. `StreamHandle` holds one stream's name and\n* ensure-create memo, and is what a consumer actually calls `append`/`read`/\n* `tail` on — no call site names a stream twice.\n*\n* Exported standalone (and via the umbrella) so local dev and tests can wrap\n* the stand-in's URL without a deployed binding:\n*\n* const client = new StreamsClient({ url: standIn.url, apiKey: 'unused' });\n* await client.stream('log').append({ n: 1 });\n*/\nconst JSON_CONTENT_TYPE = \"application/json\";\n/**\n* PRO-219: a scale-to-zero streams service can reset the first connection\n* while its instance boots (~3.5–8s observed), so IDEMPOTENT operations ride\n* it out with a bounded backoff. The wire client retries any failure except\n* a 4xx other than 429 — thrown network errors and 5xx statuses included —\n* so a real protocol error (401, 404, 409) surfaces on the first try. The\n* bound is ATTEMPTS, not wall-clock: each wait is jittered up to the current\n* delay, and a server Retry-After acts as a per-wait floor (capped upstream\n* at 1h). Appends never get any of this (see `StreamsClient.append`). Remove\n* when CI's \"Cold-start canary (PRO-217)\" goes clean — it exists to flag\n* exactly that.\n*/\nconst IDEMPOTENT_BACKOFF = {\n\t...BackoffDefaults,\n\tinitialDelay: 250,\n\tmaxDelay: 5e3,\n\tmultiplier: 2,\n\tmaxRetries: 5\n};\n/** The wire client retries network errors by default — appends must not be (no idempotency key). */\nconst NO_RETRY_BACKOFF = {\n\t...BackoffDefaults,\n\tmaxRetries: 0\n};\nconst DEFAULT_TAIL_TIMEOUT_MS = 2e4;\nfunction isAlreadyExists(error) {\n\treturn error instanceof DurableStreamError && error.status === 409;\n}\n/**\n* Whether a client operation failed because the stream does not exist — the\n* one failure that provably applied NOTHING, so re-creating the stream and\n* re-running the operation is safe even for an append. Deliberately exactly\n* that: ambiguous failures (socket closes, 502/504) never match. Not\n* exported — its only consumer is `StreamHandle`'s own heal, so no app code\n* needs the wire client's error shape.\n*/\nfunction isStreamNotFound(error) {\n\treturn (error instanceof FetchError || error instanceof DurableStreamError) && error.status === 404;\n}\nfunction streamUrl(base, name) {\n\treturn `${base}/v1/stream/${encodeURIComponent(name)}`;\n}\n/**\n* The transport a consumer's `durableStreams()` binding hydrates to (bare\n* form) — holds the base URL, the bearer header, and the per-stream write\n* handles a batched append needs. `stream(name)` is the client's whole\n* public surface: a dynamic streams consumer names a stream by calling it,\n* never by any other method here.\n*/\nvar StreamsClient = class {\n\tbase;\n\theaders;\n\twriters = /* @__PURE__ */ new Map();\n\thandles = /* @__PURE__ */ new Map();\n\tconstructor(config) {\n\t\tthis.base = config.url.replace(/\\/$/, \"\");\n\t\tthis.headers = { authorization: `Bearer ${config.apiKey}` };\n\t}\n\t/** One handle per stream name, memoized so its ensure-create state survives repeat calls. */\n\tstream(name) {\n\t\tlet handle = this.handles.get(name);\n\t\tif (handle === void 0) {\n\t\t\thandle = new StreamHandle(name, this);\n\t\t\tthis.handles.set(name, handle);\n\t\t}\n\t\treturn handle;\n\t}\n\twriter(name) {\n\t\tlet handle = this.writers.get(name);\n\t\tif (handle === void 0) {\n\t\t\thandle = new DurableStream({\n\t\t\t\turl: streamUrl(this.base, name),\n\t\t\t\theaders: this.headers,\n\t\t\t\tcontentType: JSON_CONTENT_TYPE,\n\t\t\t\tbatching: false,\n\t\t\t\tbackoffOptions: NO_RETRY_BACKOFF\n\t\t\t});\n\t\t\tthis.writers.set(name, handle);\n\t\t}\n\t\treturn handle;\n\t}\n\t/** Creates the stream (idempotent: an existing stream of any content type is success). Used by `StreamHandle`'s ensure-create. */\n\tasync create(name) {\n\t\tconst handle = new DurableStream({\n\t\t\turl: streamUrl(this.base, name),\n\t\t\theaders: this.headers,\n\t\t\tcontentType: JSON_CONTENT_TYPE,\n\t\t\tbackoffOptions: IDEMPOTENT_BACKOFF\n\t\t});\n\t\ttry {\n\t\t\tawait handle.create();\n\t\t} catch (error) {\n\t\t\tif (!isAlreadyExists(error)) throw error;\n\t\t}\n\t}\n\t/**\n\t* Appends one JSON event. NEVER retried beyond `StreamHandle`'s one-shot\n\t* 404 heal: the protocol has no idempotency key, so a failed request is\n\t* indistinguishable from one that applied — the caller retries, because\n\t* only it knows whether a duplicate is acceptable.\n\t*/\n\tasync append(name, event) {\n\t\tawait this.writer(name).append(JSON.stringify(event));\n\t}\n\t/** Reads the stream from `offset` (default: the beginning) to the current head. */\n\tasync read(name, opts) {\n\t\tconst res = await stream({\n\t\t\turl: streamUrl(this.base, name),\n\t\t\theaders: this.headers,\n\t\t\toffset: opts?.offset ?? \"-1\",\n\t\t\tlive: false,\n\t\t\tjson: true,\n\t\t\tbackoffOptions: IDEMPOTENT_BACKOFF\n\t\t});\n\t\treturn {\n\t\t\tevents: await res.json(),\n\t\t\tnextOffset: res.offset\n\t\t};\n\t}\n\t/**\n\t* Waits for the next live delivery after `offset` (default: the current\n\t* head), via long-poll — SSE cannot traverse the Compute ingress (PRO-218).\n\t* Resolves with the delivered events, or `timedOut: true` after `timeoutMs`\n\t* (default 20s) with nothing new.\n\t*/\n\tasync tail(name, opts) {\n\t\tconst abort = new AbortController();\n\t\tconst onCallerAbort = () => abort.abort();\n\t\topts?.signal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\t\tconst timer = setTimeout(() => abort.abort(), opts?.timeoutMs ?? DEFAULT_TAIL_TIMEOUT_MS);\n\t\ttry {\n\t\t\tconst res = await stream({\n\t\t\t\turl: streamUrl(this.base, name),\n\t\t\t\theaders: this.headers,\n\t\t\t\toffset: opts?.offset ?? \"now\",\n\t\t\t\tlive: \"long-poll\",\n\t\t\t\tjson: true,\n\t\t\t\tbackoffOptions: IDEMPOTENT_BACKOFF,\n\t\t\t\tsignal: abort.signal\n\t\t\t});\n\t\t\treturn await new Promise((resolve, reject) => {\n\t\t\t\tabort.signal.addEventListener(\"abort\", () => resolve({\n\t\t\t\t\tevents: [],\n\t\t\t\t\tnextOffset: res.offset,\n\t\t\t\t\ttimedOut: true\n\t\t\t\t}), { once: true });\n\t\t\t\ttry {\n\t\t\t\t\tres.subscribeJson((batch) => {\n\t\t\t\t\t\tif (batch.items.length === 0) return;\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tevents: batch.items,\n\t\t\t\t\t\t\tnextOffset: batch.offset,\n\t\t\t\t\t\t\ttimedOut: false\n\t\t\t\t\t\t});\n\t\t\t\t\t\tabort.abort();\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\treject(error);\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (abort.signal.aborted) return {\n\t\t\t\tevents: [],\n\t\t\t\tnextOffset: opts?.offset ?? \"now\",\n\t\t\t\ttimedOut: true\n\t\t\t};\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t\topts?.signal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t}\n\t}\n};\n/**\n* One stream's handle — the name and the ensure-create memo. Everything a\n* `durableStreams(contract)` handle or a `durableStreams()` client's\n* `stream(name)` result exposes; no call site passes a name again.\n*\n* Owns the lifecycle the app used to hand-roll: the first operation creates\n* the stream (memoized here; upstream create is already ensure-style, so a\n* racing second instance is harmless — using a stream is sufficient to\n* create it), and a 404 on any operation heals by dropping the memo,\n* re-creating, and retrying that operation once. A 404 is generated INSTEAD\n* OF a write at every layer, so it proves nothing was applied — retrying\n* once cannot duplicate an event, even an append. Ambiguous failures (socket\n* closes, 502/504) never match `isStreamNotFound` and surface raw.\n*/\nvar StreamHandle = class {\n\tname;\n\ttransport;\n\tensured;\n\tconstructor(name, transport) {\n\t\tthis.name = name;\n\t\tthis.transport = transport;\n\t}\n\tensureCreate() {\n\t\tif (this.ensured === void 0) this.ensured = this.transport.create(this.name).catch((error) => {\n\t\t\tthis.ensured = void 0;\n\t\t\tthrow error;\n\t\t});\n\t\treturn this.ensured;\n\t}\n\tasync withHeal(op) {\n\t\tawait this.ensureCreate();\n\t\ttry {\n\t\t\treturn await op();\n\t\t} catch (error) {\n\t\t\tif (!isStreamNotFound(error)) throw error;\n\t\t\tthis.ensured = void 0;\n\t\t\tawait this.ensureCreate();\n\t\t\treturn op();\n\t\t}\n\t}\n\t/**\n\t* Appends one JSON event. NEVER retried beyond the one-shot 404 heal above:\n\t* the protocol has no idempotency key, so a failed request is\n\t* indistinguishable from one that applied — the caller retries, because\n\t* only it knows whether a duplicate is acceptable.\n\t*/\n\tappend(event) {\n\t\treturn this.withHeal(() => this.transport.append(this.name, event));\n\t}\n\t/** Reads the stream from `offset` (default: the beginning) to the current head. */\n\tread(opts) {\n\t\treturn this.withHeal(() => this.transport.read(this.name, opts));\n\t}\n\t/**\n\t* Waits for the next live delivery after `offset` (default: the current\n\t* head), via long-poll. Resolves with the delivered events, or\n\t* `timedOut: true` after `timeoutMs` (default 20s) with nothing new.\n\t*/\n\ttail(opts) {\n\t\treturn this.withHeal(() => this.transport.tail(this.name, opts));\n\t}\n};\n//#endregion\n//#region src/contract.ts\n/** Declares an untyped stream in a `streamsContract` def map. */\nfunction streamDef() {\n\treturn Object.freeze({ kind: \"stream-def\" });\n}\n/**\n* Names the streams a contract transports, each with an optional def:\n* `streamsContract({ jobs: streamDef(), audit: streamDef() })`. The\n* `durableStreams(contract)` dependency built from it hydrates to one handle\n* per declared name.\n*/\nfunction streamsContract(defs) {\n\treturn Object.freeze({\n\t\tkind: \"streams\",\n\t\t__cmp: defs,\n\t\tsatisfies: (required) => required.kind === \"streams\"\n\t});\n}\n/**\n* The `streams()` module's own exposed port: a general streams provider,\n* satisfied by kind alone — the `postgresContract` pattern. The module\n* cannot know its eventual consumers' stream names (different consumers of\n* one module each name their own), and the server genuinely serves any\n* stream, so what a consumer requires of its provider is only \"is a streams\n* provider\". That is exactly what this wide type says, and the empty def\n* map is a legitimate `StreamDefs` value — a placeholder nobody reads, like\n* postgres's `{ url: '' }`. Consumers keep their literal handle typing from\n* `durableStreams(contract)`'s generic parameter, which is independent of\n* the wiring-compatibility type here.\n*/\nconst streamsProviderContract = Object.freeze({\n\tkind: \"streams\",\n\t__cmp: {},\n\tsatisfies: (required) => required.kind === \"streams\"\n});\nconst connectionParams = {\n\turl: string(),\n\tapiKey: string({ provision: streamsApiKeyNeed() })\n};\nfunction durableStreams(contract) {\n\treturn dependency({\n\t\ttype: \"streams\",\n\t\tconnection: {\n\t\t\tparams: connectionParams,\n\t\t\thydrate: (v) => {\n\t\t\t\tconst client = new StreamsClient(v);\n\t\t\t\tif (contract === void 0) return client;\n\t\t\t\tconst handles = {};\n\t\t\t\tfor (const name of Object.keys(contract.__cmp)) handles[name] = client.stream(name);\n\t\t\t\treturn handles;\n\t\t\t}\n\t\t},\n\t\trequired: contract ?? streamsProviderContract\n\t});\n}\n//#endregion\n//#region src/exports/streams-service.ts\n/**\n* The streams service node: a plain `compute` service — the contract binding's\n* `url` is a producer output compute's deploy already carries, and its\n* `apiKey` is minted by the target's registered provisioner (ADR-0031), so\n* nothing is left for a bespoke lowering to extend. It declares the `store`\n* dependency (`s3()`, the storage module's port) and the `streams` expose; the\n* bearer key reaches this service through the target's reserved provider\n* param, not through a dependency. The deploy bootstrap runs the\n* default-exported bare node; the real wiring arrives through serialized\n* config at runtime — exactly like `storage-service.ts`.\n*/\nfunction streamsService() {\n\treturn compute({\n\t\tname: \"streams\",\n\t\tdeps: { store: s3() },\n\t\tbuild: node({\n\t\t\tmodule: new URL(\"./streams-service.mjs\", import.meta.url).href,\n\t\t\tentry: \"./streams-entrypoint.mjs\"\n\t\t}),\n\t\texpose: { streams: streamsProviderContract }\n\t});\n}\nvar streams_service_default = streamsService();\n//#endregion\nexport { streamsContract as a, StreamsClient as c, streamDef as i, streams_service_default as n, streamsProviderContract as o, durableStreams as r, StreamHandle as s, streamsService as t };\n\n//# sourceMappingURL=streams-service-Br5Tj3AY.mjs.map"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"streams-service.mjs","names":[],"sources":["../../../../1-prisma-cloud/1-extensions/target/dist/serializer-CX4VYdf_.mjs","../../../../1-prisma-cloud/1-extensions/target/dist/provisioned-edges-DIQAR4q4.mjs","../../../../1-prisma-cloud/1-extensions/target/dist/index.mjs","../../../../1-prisma-cloud/2-shared-modules/storage/dist/storage-service-BQdOiMsW.mjs","../../../../1-prisma-cloud/2-shared-modules/streams/dist/streams-service-Br5Tj3AY.mjs"],"sourcesContent":["import { secretSource } from \"@internal/core\";\nimport { blindCast } from \"@internal/foundation/casts\";\n//#region src/secret.ts\n/**\n* Brands the payload `envSecret` builds. Core's `secretSource()` is a public\n* SPI, so a user could bypass `envSecret` and bind a raw `secretSource('x')`;\n* the brand lets `secretName` reject such a source (or another target's) with a\n* clear error instead of reading an absent `.name`.\n*/\nconst PRISMA_CLOUD_SECRET_SOURCE = blindCast(Symbol.for(\"prisma:prisma-cloud-secret-source\"));\nconst RESERVED_SECRET_PREFIX = \"COMPOSER_\";\nconst POISONED_SECRET_NAMES = /* @__PURE__ */ new Set([\"DATABASE_URL\", \"DATABASE_URL_POOLED\"]);\n/**\n* Binds a secret slot to a named Prisma Cloud platform env var (ADR-0029). The\n* value is provisioned out-of-band; only the name is carried. The name may not\n* use the framework's reserved `COMPOSER_` prefix or the poisoned\n* `DATABASE_URL(_POOLED)` keys.\n*/\nfunction envSecret(name) {\n\tif (typeof name !== \"string\" || name.length === 0) throw new Error(\"envSecret() requires a non-empty platform env-var name, e.g. envSecret('STRIPE_SECRET_KEY').\");\n\tif (name.startsWith(RESERVED_SECRET_PREFIX)) throw new Error(`envSecret name \"${name}\" may not start with \"${RESERVED_SECRET_PREFIX}\" — that prefix is reserved for the framework's own generated config keys.`);\n\tif (POISONED_SECRET_NAMES.has(name)) throw new Error(`envSecret name \"${name}\" is reserved — ${[...POISONED_SECRET_NAMES].join(\" and \")} are poisoned at project provision and cannot back a secret.`);\n\treturn secretSource({\n\t\t[PRISMA_CLOUD_SECRET_SOURCE]: true,\n\t\tname\n\t});\n}\n/** True only for a payload that `envSecret` built — i.e. one carrying the brand. */\nfunction isEnvSecretPayload(payload) {\n\treturn typeof payload === \"object\" && payload !== null && blindCast(payload)[PRISMA_CLOUD_SECRET_SOURCE] === true;\n}\n/**\n* Reads the Prisma Cloud env-var name back out of a secret binding's opaque\n* source. A source not built by `envSecret` (a raw `secretSource(...)` or\n* another target's source) carries no name — reject it here. `secretName` runs\n* in preflight before any provisioning, so a foreign source fails early and\n* clearly rather than producing a broken deploy with an undefined name.\n*/\nfunction secretName(binding) {\n\tconst payload = binding.source.payload;\n\tif (!isEnvSecretPayload(payload)) throw new Error(`secret slot \"${binding.slot}\" of service \"${binding.serviceAddress}\" is bound to a source not created by envSecret() — bind secrets with envSecret('NAME') from @prisma/composer-prisma-cloud.`);\n\treturn payload.name;\n}\n//#endregion\n//#region src/serializer.ts\n/**\n* Walks a node's own params, then each dependency input's connection params —\n* the same enumeration order `configOf` uses, but carrying the raw\n* `ConfigParam` (with its `serialize`/`deserialize`) instead of a pure-data\n* projection.\n*/\nfunction paramEntries(node) {\n\tconst entries = [];\n\tfor (const [input, value] of Object.entries(node.inputs)) {\n\t\tif (typeof value !== \"object\" || value === null) continue;\n\t\tconst params = blindCast(value).connection.params;\n\t\tfor (const [name, param] of Object.entries(params)) entries.push({\n\t\t\towner: { input },\n\t\t\tname,\n\t\t\tparam\n\t\t});\n\t}\n\tfor (const [name, param] of Object.entries(node.params)) entries.push({\n\t\towner: \"service\",\n\t\tname,\n\t\tparam\n\t});\n\treturn entries;\n}\nconst configKey = (address, d) => {\n\tconst segments = address.split(\".\").filter((s) => s.length > 0);\n\tconst owner = d.owner === \"service\" ? [] : [d.owner.input];\n\treturn [\n\t\t\"COMPOSER\",\n\t\t...segments,\n\t\t...owner,\n\t\td.name\n\t].join(\"_\").toUpperCase();\n};\n/**\n* Typed value → its stored string. Service-own literals are JSON-encoded; a\n* dependency-input value is a provisioning ref at deploy (and a resolved\n* string at boot) and passes through untouched — LANDMINE: JSON-encoding it\n* would break the ordering edge Alchemy resolves through it.\n*/\nfunction encode(owner, value) {\n\treturn owner === \"service\" ? JSON.stringify(value) : blindCast(value);\n}\n/** Reverses `encode`: JSON-parse a service-own value, take a dependency-input value raw. */\nfunction decode(owner, raw) {\n\treturn owner === \"service\" ? JSON.parse(raw) : raw;\n}\nconst PARAM_POINTER_PREFIX = \"@composer-param-pointer:\";\n/** True iff `raw` is a param pointer row (as opposed to a JSON-encoded literal). */\nconst isParamPointerRow = (raw) => raw.startsWith(PARAM_POINTER_PREFIX);\n/** Builds a param pointer row's stored value from the platform var NAME it points to. */\nconst encodeParamPointer = (name) => `${PARAM_POINTER_PREFIX}${name}`;\n/** Reverses `encodeParamPointer`: the platform var NAME a pointer row points to. */\nconst decodeParamPointer = (raw) => raw.slice(24);\nfunction coerce(raw, d, key) {\n\tif (!(raw !== void 0 && raw !== \"\")) {\n\t\tif (d.param.default !== void 0) return d.param.default;\n\t\tif (d.param.optional === true) return void 0;\n\t\tthrow new Error(`missing required config param \"${d.name}\" (env ${key})`);\n\t}\n\tif (d.owner === \"service\" && isParamPointerRow(raw)) return coerceEnvSourcedParam(raw, d, key);\n\ttry {\n\t\treturn standardValidateSync(d.param.schema, decode(d.owner, raw));\n\t} catch (cause) {\n\t\tconst message = cause instanceof Error ? cause.message : String(cause);\n\t\tthrow new Error(`invalid value for config param \"${d.name}\" (env ${key}): ${message}`);\n\t}\n}\n/**\n* Boot resolution for an env-sourced param: double-lookup (pointer → platform\n* var), then the param's own schema on the raw string — no JSON decode, and\n* no redaction (it's config, not a secret). An UNSET platform var is a loud\n* boot failure naming both the param and the platform var; an EMPTY string is\n* not special-cased here — it reaches the schema like any other value, so it\n* passes iff the schema accepts it (deliberately unlike a literal param's own\n* \"\"-means-absent rule, and unlike a secret's non-empty requirement).\n*/\nfunction coerceEnvSourcedParam(raw, d, key) {\n\tconst platformVar = decodeParamPointer(raw);\n\tconst value = process.env[platformVar];\n\tif (value === void 0) throw new Error(`env-sourced config param \"${d.name}\" (env ${key} → ${platformVar}) is unset: the platform variable \"${platformVar}\" was not injected — the deploy did not provision it.`);\n\ttry {\n\t\treturn standardValidateSync(d.param.schema, value);\n\t} catch (cause) {\n\t\tconst message = cause instanceof Error ? cause.message : String(cause);\n\t\tthrow new Error(`invalid value for env-sourced config param \"${d.name}\" (env ${key} → ${platformVar}): ${message}`);\n\t}\n}\n/**\n* Boot: read each declared param from env by its key, reverse the param's own\n* serialization (missing/invalid fails loudly), assemble the typed Config.\n* Secrets ride a separate channel (deserializeSecrets), not this one.\n*/\nconst deserialize = (node, address) => {\n\tconst service = {};\n\tconst inputs = {};\n\tfor (const d of paramEntries(node)) {\n\t\tconst key = configKey(address, d);\n\t\tconst value = coerce(process.env[key], d, key);\n\t\tif (d.owner === \"service\") service[d.name] = value;\n\t\telse {\n\t\t\tlet bucket = inputs[d.owner.input];\n\t\t\tif (bucket === void 0) {\n\t\t\t\tbucket = {};\n\t\t\t\tinputs[d.owner.input] = bucket;\n\t\t\t}\n\t\t\tbucket[d.name] = value;\n\t\t}\n\t}\n\treturn {\n\t\tservice,\n\t\tinputs\n\t};\n};\n/**\n* run()'s setup step: write the resolved config to the environment under\n* address-free keys (configKey(\"\", d) + each serialize suffix), which load()\n* reads back with no address. Uses env, not a module variable, because a\n* framework may fork worker processes that inherit env but not memory.\n* Writes only these keys; nothing else is touched.\n*/\nconst stash = (node, config) => {\n\tfor (const d of paramEntries(node)) {\n\t\tconst value = d.owner === \"service\" ? config.service[d.name] : config.inputs[d.owner.input]?.[d.name];\n\t\tif (value === void 0) continue;\n\t\tprocess.env[configKey(\"\", d)] = encode(d.owner, value);\n\t}\n};\n/** The pointer-row key for a secret slot: COMPOSER_<addr>_<slot> (secrets are service-level). */\nconst secretKey = (address, slot) => configKey(address, {\n\towner: \"service\",\n\tname: slot\n});\n/**\n* Deploy: the pointer rows for a node's secret slots — each slot's key mapped to\n* the platform NAME the root bound it to (looked up in `graph.secrets`). Never a\n* value. A declared slot with no binding is a Load-invariant violation (Load\n* binds every slot), surfaced loudly here rather than written as a blank row.\n*/\nfunction secretPointerRows(node, address, bindings) {\n\tconst rows = [];\n\tfor (const slot of Object.keys(node.secretSlots)) {\n\t\tconst binding = bindings.find((b) => b.serviceAddress === address && b.slot === slot);\n\t\tif (binding === void 0) throw new Error(`secret slot \"${slot}\" of \"${address}\" has no bound platform name — Load should have bound it (ADR-0029).`);\n\t\trows.push({\n\t\t\tkey: secretKey(address, slot),\n\t\t\tname: secretName(binding)\n\t\t});\n\t}\n\treturn rows;\n}\n/**\n* Boot: resolve every secret slot to its value by double-lookup — read the\n* pointer key (the platform NAME), then read that platform var. A missing\n* pointer or a missing/empty platform value is a loud failure naming both keys.\n* Returns a plain Record for core's `hydrateSecrets` to box.\n*/\nconst deserializeSecrets = (node, address) => {\n\tconst values = {};\n\tfor (const slot of Object.keys(node.secretSlots)) {\n\t\tconst key = secretKey(address, slot);\n\t\tconst name = process.env[key];\n\t\tif (name === void 0 || name === \"\") throw new Error(`missing secret pointer for slot \"${slot}\" (env ${key}) — the deploy did not write it.`);\n\t\tconst value = process.env[name];\n\t\tif (value === void 0 || value === \"\") throw new Error(`secret \"${slot}\" is not provisioned (env ${key} → ${name}): the platform var \"${name}\" is unset or empty.`);\n\t\tvalues[slot] = value;\n\t}\n\treturn values;\n};\n/**\n* run()'s setup step for secrets: re-emit each slot's pointer NAME under its\n* address-free key, so the address-free `deserializeSecrets` double-looks-up\n* identically. Never the value — the value stays only in the platform var.\n*/\nconst stashSecrets = (node, address) => {\n\tfor (const slot of Object.keys(node.secretSlots)) {\n\t\tconst name = process.env[secretKey(address, slot)];\n\t\tif (name === void 0) continue;\n\t\tprocess.env[secretKey(\"\", slot)] = name;\n\t}\n};\n/**\n* Boot: for each reserved provider param, read its address-scoped row through\n* the same `coerce` a declared param uses (JSON-decode, schema-validate), and\n* re-emit it address-free — `stash`'s counterpart for this separate\n* declaration space. A param is declared optional here unconditionally: an\n* absent row means \"never provisioned\" (local dev, tests, a provider with no\n* registered value for this deploy), never a boot failure, so nothing is\n* stashed and the runtime reader that owns this slot falls back to its own\n* pass-through behavior.\n*/\nfunction stashProviderParams(entries, address) {\n\tfor (const entry of entries) {\n\t\tconst d = {\n\t\t\towner: \"service\",\n\t\t\tname: entry.name,\n\t\t\tparam: {\n\t\t\t\tschema: entry.schema,\n\t\t\t\toptional: true\n\t\t\t}\n\t\t};\n\t\tconst key = configKey(address, d);\n\t\tconst value = coerce(process.env[key], d, key);\n\t\tif (value === void 0) continue;\n\t\tprocess.env[configKey(\"\", d)] = encode(\"service\", value);\n\t}\n}\n/** Synchronous Standard Schema validation — see the matching note in core's `config.ts`. */\nfunction standardValidateSync(schema, value) {\n\tconst result = schema[\"~standard\"].validate(value);\n\tif (result instanceof Promise) throw new Error(\"config param schema validation must be synchronous — async Standard Schema validators are not supported for config params\");\n\tif (result.issues !== void 0) throw new Error(`config param validation failed: ${result.issues.map((issue) => issue.message).join(\"; \")}`);\n\treturn result.value;\n}\n//#endregion\nexport { encodeParamPointer as a, stash as c, envSecret as d, secretName as f, encode as i, stashProviderParams as l, deserialize as n, paramEntries as o, deserializeSecrets as r, secretPointerRows as s, configKey as t, stashSecrets as u };\n\n//# sourceMappingURL=serializer-CX4VYdf_.mjs.map","import { t as configKey } from \"./serializer-CX4VYdf_.mjs\";\nimport { isParamSource, paramSource, provisionNeed } from \"@internal/core\";\nimport { blindCast } from \"@internal/foundation/casts\";\nimport { RPC_PEER_KEY } from \"@internal/service-rpc\";\nimport { type } from \"arktype\";\n//#region src/service-keys.ts\n/**\n* RPC's reserved provider param (ADR-0030/ADR-0031): the declaration —\n* name + schema + brand — for the accepted-keys set a provider stores, shared\n* by `control.ts` (which registers the deploy-side `value(refs)` that mints\n* and aggregates it — see its `rpcAcceptedKeysValue`) and `compute.ts` (which\n* validates and stashes it at boot), so writer and reader cannot drift.\n* Finding the edges themselves is `provisioned-edges.ts`'s generic,\n* brand-blind scan — RPC is not special-cased anywhere in this target.\n*\n* This module is reachable from the RUNTIME/authoring side — it must never\n* import `@internal/lowering` or `effect`, or those tokens leak into a user\n* service's bundle (the deploy-side `value(refs)` lives in control.ts, the\n* control-plane-only entry).\n*/\n/**\n* The reserved provider param for RPC's accepted-keys set: the var name is\n* `RPC_ACCEPTED_KEYS`, derived through `configKey` at both ends\n* (`configKey(address, …)` at deploy, `configKey('', …)` at boot — the\n* address-free form is `@internal/service-rpc`'s `RPC_ACCEPTED_KEYS_ENV`). `brand` is\n* `RPC_PEER_KEY`, the same brand `perBindingToken()`'s need carries — control.ts\n* looks its `value(refs)` up by this field.\n*/\nconst RPC_ACCEPTED_KEYS_PARAM = {\n\tname: \"RPC_ACCEPTED_KEYS\",\n\tschema: type(\"string[]\"),\n\tbrand: RPC_PEER_KEY\n};\n//#endregion\n//#region src/streams-keys.ts\n/** ADR-0031's need brand for the streams module's bearer key — control.ts registers the provisioner under this. */\nconst STREAMS_API_KEY = Symbol.for(\"prisma:streams/api-key\");\n/**\n* The provisioning need `durableStreams()`'s `apiKey` param declares: an\n* unguessable value the target mints ONCE PER PROVIDER (not per edge) —\n* `@prisma/streams-server` authenticates a single `API_KEY`, so every\n* consumer of one streams module must present the same value. Per-provider\n* cardinality is provisioner policy (ADR-0031), invisible to core.\n*/\nconst streamsApiKeyNeed = () => provisionNeed(STREAMS_API_KEY);\n/**\n* The reserved provider param for the streams bearer key: the var name is\n* `STREAMS_API_KEY`. `brand` is `STREAMS_API_KEY` itself (the same symbol\n* `streamsApiKeyNeed()`'s need carries) — control.ts looks its `value(refs)`\n* up by this field.\n*/\nconst STREAMS_API_KEY_PARAM = {\n\tname: \"STREAMS_API_KEY\",\n\tschema: type(\"string\"),\n\tbrand: STREAMS_API_KEY\n};\n/** The address-free name compute.ts re-stashes to and the streams entrypoint reads. */\nconst STREAMS_API_KEY_ENV = configKey(\"\", {\n\towner: \"service\",\n\tname: STREAMS_API_KEY_PARAM.name\n});\n//#endregion\n//#region src/provider-params.ts\nconst RESERVED_PROVIDER_PARAMS = [RPC_ACCEPTED_KEYS_PARAM, STREAMS_API_KEY_PARAM];\n//#endregion\n//#region src/param.ts\n/**\n* Brands the payload `envParam` builds. Core's `paramSource()` is a public\n* SPI, so a user could bypass `envParam` and bind a raw `paramSource('x')`;\n* the brand lets `paramName` reject such a source (or another target's) with\n* a clear error instead of reading an absent `.name`.\n*/\nconst PRISMA_CLOUD_PARAM_SOURCE = blindCast(Symbol.for(\"prisma:prisma-cloud-param-source\"));\nconst RESERVED_PARAM_PREFIX = \"COMPOSER_\";\nconst POISONED_PARAM_NAMES = /* @__PURE__ */ new Set([\"DATABASE_URL\", \"DATABASE_URL_POOLED\"]);\n/**\n* Binds a param slot to a named Prisma Cloud platform env var — the non-secret\n* sibling of `envSecret` (spec: env-sourced config params). The platform\n* injects the value into the running instance per stage; the param's own\n* schema validates it at boot, unredacted. The name may not use the\n* framework's reserved `COMPOSER_` prefix or the poisoned\n* `DATABASE_URL(_POOLED)` keys — same parity as `envSecret`.\n*/\nfunction envParam(name) {\n\tif (typeof name !== \"string\" || name.length === 0) throw new Error(\"envParam() requires a non-empty platform env-var name, e.g. envParam('APP_ORIGIN').\");\n\tif (name.startsWith(RESERVED_PARAM_PREFIX)) throw new Error(`envParam name \"${name}\" may not start with \"${RESERVED_PARAM_PREFIX}\" — that prefix is reserved for the framework's own generated config keys.`);\n\tif (POISONED_PARAM_NAMES.has(name)) throw new Error(`envParam name \"${name}\" is reserved — ${[...POISONED_PARAM_NAMES].join(\" and \")} are poisoned at project provision and cannot back a param.`);\n\treturn paramSource({\n\t\t[PRISMA_CLOUD_PARAM_SOURCE]: true,\n\t\tname\n\t});\n}\n/** True only for a payload that `envParam` built — i.e. one carrying the brand. */\nfunction isEnvParamPayload(payload) {\n\treturn typeof payload === \"object\" && payload !== null && blindCast(payload)[PRISMA_CLOUD_PARAM_SOURCE] === true;\n}\n/** True iff a resolved param value is an env-sourced pointer this target built (as opposed to a literal, or a foreign/raw `ParamSource`). */\nfunction isEnvParamSource(value) {\n\treturn isParamSource(value) && isEnvParamPayload(value.payload);\n}\n/**\n* Reads the Prisma Cloud env-var name back out of a param binding's opaque\n* source. A source not built by `envParam` (a raw `paramSource(...)` or\n* another target's source) carries no name — reject it here. `paramName` runs\n* in preflight and at serialize before any value ever crosses the wire, so a\n* foreign source fails early and clearly rather than producing a broken\n* deploy with an undefined name.\n*/\nfunction paramName(binding) {\n\tconst { binding: bound } = binding;\n\tif (!isEnvParamSource(bound)) throw new Error(`param slot \"${binding.slot}\" of service \"${binding.serviceAddress}\" is bound to a source not created by envParam() — bind env-sourced params with envParam('NAME') from @prisma/composer-prisma-cloud.`);\n\treturn bound.payload.name;\n}\n/**\n* Finds the manifest entry for one service param slot. `serialize` calls this\n* only after confirming `buildConfig` resolved the slot to a `ParamSource`\n* (`isParamSource(value)`), so a miss here means `graph.params` and the\n* resolved `Config` have drifted — a Load invariant violation, surfaced\n* loudly rather than producing a pointer row with an undefined name.\n*/\nfunction paramBindingFor(bindings, serviceAddress, slot) {\n\tconst binding = bindings.find((b) => b.serviceAddress === serviceAddress && b.slot === slot);\n\tif (binding === void 0) throw new Error(`param slot \"${slot}\" of \"${serviceAddress}\" resolved to a source but has no bound entry in the manifest — Load should have recorded it.`);\n\treturn binding;\n}\n//#endregion\n//#region src/provisioned-edges.ts\n/**\n* Every provisioned edge in the graph. Core resolves and mints these (one\n* value per edge, keyed by `edgeId`); this scan is how the target finds them\n* again when it gathers a provider's inbound values.\n*/\nfunction provisionedEdges(graph) {\n\tconst edges = [];\n\tfor (const edge of graph.edges) {\n\t\tif (edge.kind !== \"dependency\") continue;\n\t\tconst consumer = graph.nodes.find((n) => n.id === edge.to)?.node;\n\t\tif (consumer === void 0 || consumer.kind !== \"service\") continue;\n\t\tconst slot = consumer.inputs[edge.input];\n\t\tif (slot === void 0) continue;\n\t\tfor (const param of Object.values(slot.connection.params)) {\n\t\t\tconst brand = param.provision?.brand;\n\t\t\tif (brand === void 0) continue;\n\t\t\tedges.push({\n\t\t\t\tedgeId: `${edge.to}.${edge.input}`,\n\t\t\t\tconsumerAddress: edge.to,\n\t\t\t\tinput: edge.input,\n\t\t\t\tproviderAddress: edge.from,\n\t\t\t\tbrand\n\t\t\t});\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn edges;\n}\n//#endregion\nexport { paramName as a, STREAMS_API_KEY_ENV as c, paramBindingFor as i, streamsApiKeyNeed as l, envParam as n, RESERVED_PROVIDER_PARAMS as o, isEnvParamSource as r, STREAMS_API_KEY as s, provisionedEdges as t };\n\n//# sourceMappingURL=provisioned-edges-DIQAR4q4.mjs.map","import { a as paramName, c as STREAMS_API_KEY_ENV, l as streamsApiKeyNeed, n as envParam, o as RESERVED_PROVIDER_PARAMS, s as STREAMS_API_KEY, t as provisionedEdges } from \"./provisioned-edges-DIQAR4q4.mjs\";\nimport { c as stash, d as envSecret, f as secretName, l as stashProviderParams, n as deserialize, r as deserializeSecrets, t as configKey, u as stashSecrets } from \"./serializer-CX4VYdf_.mjs\";\nimport { dependency, hydrateSecrets, hydrateSync, number, resource, service, string } from \"@internal/core\";\nimport { blindCast } from \"@internal/foundation/casts\";\n//#region src/bucket.ts\n/**\n* The contract a provisioned Bucket provides — deliberately kind-equal to the\n* storage module's `s3Contract` (`kind: 's3'`). `satisfies` compares KIND,\n* not identity (mirrors `postgresContract`): a real bucket and the emulator\n* are interchangeable at every `s3()` dependency slot. Cross-layer import of\n* the storage module's contract is not allowed (layering: 2-shared-modules\n* depends on 1-extensions, not the reverse), which is exactly the design\n* rationale for kind-equality — the two contracts cooperate through their\n* shared kind string, not through object identity.\n*/\nconst bucketContract = Object.freeze({\n\tkind: \"s3\",\n\t__cmp: {\n\t\turl: \"\",\n\t\tbucket: \"\",\n\t\taccessKeyId: \"\",\n\t\tsecretAccessKey: \"\"\n\t},\n\tsatisfies: (required) => required.kind === \"s3\"\n});\nfunction bucket(opts) {\n\tif (opts?.name !== void 0) return resource({\n\t\tname: opts.name,\n\t\textension: \"@prisma/composer-prisma-cloud\",\n\t\tprovides: bucketContract\n\t});\n\treturn dependency({\n\t\ttype: \"s3\",\n\t\tconnection: {\n\t\t\tparams: {\n\t\t\t\turl: string(),\n\t\t\t\tbucket: string(),\n\t\t\t\taccessKeyId: string(),\n\t\t\t\tsecretAccessKey: string()\n\t\t\t},\n\t\t\thydrate: (v) => v\n\t\t},\n\t\trequired: bucketContract\n\t});\n}\n//#endregion\n//#region src/compute.ts\nconst reservedParams = { port: number({ default: 3e3 }) };\n/**\n* A Prisma Compute service — declarations only (deps + params + build + the\n* ports it exposes), no descriptor. `params` merges with the reserved\n* `ReservedParams` (`port`); a user param whose name collides with a reserved\n* one fails at authoring, the same way a colliding dependency name does.\n* Returns the extension's runnable/loadable node:\n* · run(address, boot) — the process controller: deserialize the platform\n* environment (keyed off `address`, the extension's ONE env read) into a\n* typed Config, re-emit it under address-free process-local stash keys,\n* then call boot() to start the app's entry.\n* · load() / config() — called from inside the app's entry: read the stash;\n* load() hydrates + memoizes the deps, config() returns the typed params.\n* Separate accessors so a dep and a param never share a namespace (ADR-0021).\n*\n* `service()`'s underlying node carries `extension: '@prisma/composer-prisma-cloud'` —\n* the control-plane registry key `prisma-composer deploy` resolves through the\n* app's `prisma-composer.config.ts` (ADR-0017). This module loads nothing at\n* deploy time; nodes are pure data.\n*/\nconst compute = (def) => {\n\tconst userParams = def.params ?? blindCast({});\n\tfor (const reserved of Object.keys(reservedParams)) {\n\t\tif (reserved in def.deps) throw new Error(`compute(): dependency \"${reserved}\" collides with the reserved service param of the same name — rename the dependency.`);\n\t\tif (reserved in userParams) throw new Error(`compute(): param \"${reserved}\" collides with the reserved service param of the same name — rename the param.`);\n\t}\n\tconst params = blindCast({\n\t\t...userParams,\n\t\t...reservedParams\n\t});\n\tconst node = service({\n\t\tname: def.name,\n\t\textension: \"@prisma/composer-prisma-cloud\",\n\t\ttype: \"compute\",\n\t\tinputs: def.deps,\n\t\tparams,\n\t\t...def.secrets !== void 0 ? { secrets: def.secrets } : {},\n\t\tbuild: def.build,\n\t\t...def.expose !== void 0 ? { expose: def.expose } : {}\n\t});\n\tlet resolved;\n\tlet loadedDeps;\n\tlet loadedParams;\n\tlet loadedSecrets;\n\tfunction processConfig() {\n\t\tif (resolved === void 0) resolved = deserialize(node, \"\");\n\t\treturn resolved;\n\t}\n\tconst runnable = {\n\t\t...node,\n\t\tasync run(address, boot) {\n\t\t\tconst config = deserialize(node, address);\n\t\t\tstash(node, config);\n\t\t\tstashProviderParams(RESERVED_PROVIDER_PARAMS, address);\n\t\t\tstashSecrets(node, address);\n\t\t\tconst port = config.service[\"port\"];\n\t\t\tif (typeof port === \"number\") process.env[\"PORT\"] = String(port);\n\t\t\treturn boot();\n\t\t},\n\t\tload() {\n\t\t\tif (loadedDeps === void 0) loadedDeps = blindCast(hydrateSync(node, processConfig()));\n\t\t\treturn loadedDeps;\n\t\t},\n\t\tconfig() {\n\t\t\tif (loadedParams === void 0) loadedParams = blindCast(processConfig().service);\n\t\t\treturn loadedParams;\n\t\t},\n\t\tsecrets() {\n\t\t\tif (loadedSecrets === void 0) loadedSecrets = blindCast(hydrateSecrets(node, deserializeSecrets(node, \"\")));\n\t\t\treturn loadedSecrets;\n\t\t}\n\t};\n\treturn Object.freeze(blindCast(runnable));\n};\n//#endregion\n//#region src/http.ts\nconst defaultHttpClient = (cfg) => ({\n\turl: cfg.url,\n\tfetch: (path, init) => fetch(new URL(path, cfg.url), init)\n});\n/**\n* A service-to-service dependency. Its binding (what `load()` returns) is a\n* derived HttpClient — a thin URL-anchored fetch wrapper (fetch is standard\n* across runtimes — no driver, no runtime coupling). http() is a\n* protocol-owned kind: the framework owns the transport, so the client is\n* kind-canonical and derived from the contract, with no user client in the\n* declaration (ADR-0015). The typed generated client arrives with the\n* interface primitive (a later extension point).\n*/\nconst http = (opts) => dependency({\n\tname: opts.name,\n\ttype: \"http\",\n\tconnection: {\n\t\tparams: { url: string() },\n\t\thydrate: (v) => defaultHttpClient({ url: v.url })\n\t}\n});\n//#endregion\n//#region src/postgres.ts\n/**\n* The contract a Postgres provides — and the contract its consumers require.\n* `satisfies` compares KIND, not identity: an extension module can be duplicated\n* across a workspace (same rationale as the Symbol.for node brand), and every\n* duplicate's contract must still satisfy. `__cmp` is the connection config a\n* postgres offers; core never inspects it.\n*/\nconst postgresContract = Object.freeze({\n\tkind: \"postgres\",\n\t__cmp: { url: \"\" },\n\tsatisfies: (required) => required.kind === \"postgres\"\n});\nfunction postgres(opts) {\n\tif (opts?.name !== void 0) return resource({\n\t\tname: opts.name,\n\t\textension: \"@prisma/composer-prisma-cloud\",\n\t\tprovides: postgresContract\n\t});\n\treturn dependency({\n\t\ttype: \"postgres\",\n\t\tconnection: {\n\t\t\tparams: { url: string() },\n\t\t\thydrate: (v) => v\n\t\t},\n\t\trequired: postgresContract\n\t});\n}\n//#endregion\n//#region src/s3-credentials.ts\n/**\n* The contract the `s3-credentials` resource provides — a minted SigV4 key\n* pair. `satisfies` compares KIND only (mirrors `postgresContract`); `__cmp` is\n* the config the resource offers, which core never inspects.\n*/\nconst credentialsContract = Object.freeze({\n\tkind: \"credentials\",\n\t__cmp: {\n\t\taccessKeyId: \"\",\n\t\tsecretAccessKey: \"\"\n\t},\n\tsatisfies: (required) => required.kind === \"credentials\"\n});\nfunction s3Credentials(opts) {\n\tif (opts?.name !== void 0) return resource({\n\t\tname: opts.name,\n\t\textension: \"@prisma/composer-prisma-cloud\",\n\t\tprovides: credentialsContract\n\t});\n\treturn dependency({\n\t\ttype: \"credentials\",\n\t\tconnection: {\n\t\t\tparams: {\n\t\t\t\taccessKeyId: string(),\n\t\t\t\tsecretAccessKey: string()\n\t\t\t},\n\t\t\thydrate: (v) => v\n\t\t},\n\t\trequired: credentialsContract\n\t});\n}\n//#endregion\n//#region src/s3-store.ts\n/**\n* The storage service authoring factory — a `compute` service routed to the\n* `s3-store` lowering instead of `compute`'s. It is exactly `compute`'s\n* runnable (run/load/config, deps, params, build, expose) with the routing\n* `type` overridden to `'s3-store'`: nothing at runtime keys off `type` (the\n* serializer keys off the deployment address and each param's owner/name, and\n* `load`/`config` off deps/params), so only the deploy-time descriptor lookup\n* sees the override and routes to the extended-output lowering (§ 5). The\n* return type is compute's exactly (including the reserved `port` param). The\n* storage module (D4b) calls this with its `db`/`credentials` deps, a `bucket`\n* param, and `expose: { store: s3Contract }`.\n*/\nfunction s3StoreService(def) {\n\tconst node = compute(def);\n\treturn Object.freeze(blindCast({\n\t\t...node,\n\t\ttype: \"s3-store\"\n\t}));\n}\n//#endregion\nexport { STREAMS_API_KEY, STREAMS_API_KEY_ENV, bucket, bucketContract, compute, configKey, credentialsContract, envParam, envSecret, http, paramName, postgres, postgresContract, provisionedEdges, s3Credentials, s3StoreService, secretName, streamsApiKeyNeed };\n\n//# sourceMappingURL=index.mjs.map","import { dependency, string } from \"@internal/core\";\nimport { postgres, s3Credentials, s3StoreService } from \"@internal/prisma-cloud\";\nimport node from \"@internal/node\";\n//#region src/contract.ts\nconst s3Contract = Object.freeze({\n\tkind: \"s3\",\n\t__cmp: {\n\t\turl: \"\",\n\t\tbucket: \"\",\n\t\taccessKeyId: \"\",\n\t\tsecretAccessKey: \"\"\n\t},\n\tsatisfies: (required) => required.kind === \"s3\"\n});\n/**\n* A consumer's dependency on an S3-compatible store. No `region` in the\n* binding — the server accepts whatever region string the client signed.\n*/\nfunction s3() {\n\treturn dependency({\n\t\ttype: \"s3\",\n\t\tconnection: {\n\t\t\tparams: {\n\t\t\t\turl: string(),\n\t\t\t\tbucket: string(),\n\t\t\t\taccessKeyId: string(),\n\t\t\t\tsecretAccessKey: string()\n\t\t\t},\n\t\t\thydrate: (v) => v\n\t\t},\n\t\trequired: s3Contract\n\t});\n}\n//#endregion\n//#region src/exports/storage-service.ts\n/**\n* The storage service node (like cron's `scheduler.ts` + `scheduler-service.ts`\n* combined): `storageService` builds the `s3-store` service — a Postgres `db`\n* dependency, a minted `credentials` dependency, a `bucket` param, and the\n* `store` port exposing `s3Contract`. The deploy bootstrap runs the\n* default-exported bare node (`main.run(address, boot)`); the real bucket comes\n* from serialized config at runtime, so the default's `bucket` is only a\n* placeholder — exactly like `scheduler-service.ts` default-exports\n* `cronScheduler({ jobs: [] })`.\n*/\nfunction storageService(opts) {\n\treturn s3StoreService({\n\t\tname: \"storage\",\n\t\tdeps: {\n\t\t\tdb: postgres(),\n\t\t\tcredentials: s3Credentials()\n\t\t},\n\t\tparams: { bucket: string({ default: opts.bucket }) },\n\t\tbuild: node({\n\t\t\tmodule: new URL(\"./storage-service.mjs\", import.meta.url).href,\n\t\t\tentry: \"./storage-entrypoint.mjs\"\n\t\t}),\n\t\texpose: { store: s3Contract }\n\t});\n}\nvar storage_service_default = storageService({ bucket: \"storage\" });\n//#endregion\nexport { s3Contract as i, storage_service_default as n, s3 as r, storageService as t };\n\n//# sourceMappingURL=storage-service-BQdOiMsW.mjs.map","import { dependency, string } from \"@internal/core\";\nimport { compute, streamsApiKeyNeed } from \"@internal/prisma-cloud\";\nimport { s3 } from \"@internal/storage\";\nimport node from \"@internal/node\";\n//#region \\0rolldown/runtime.js\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);\nvar __copyProps = (to, from, except, desc) => {\n\tif (from && typeof from === \"object\" || typeof from === \"function\") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {\n\t\tkey = keys[i];\n\t\tif (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {\n\t\t\tget: ((k) => from[k]).bind(null, key),\n\t\t\tenumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable\n\t\t});\n\t}\n\treturn to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", {\n\tvalue: mod,\n\tenumerable: true\n}) : target, mod));\n//#endregion\n//#region ../../../../node_modules/reusify/reusify.js\nvar require_reusify = /* @__PURE__ */ __commonJSMin(((exports, module) => {\n\tfunction reusify(Constructor) {\n\t\tvar head = new Constructor();\n\t\tvar tail = head;\n\t\tfunction get() {\n\t\t\tvar current = head;\n\t\t\tif (current.next) head = current.next;\n\t\t\telse {\n\t\t\t\thead = new Constructor();\n\t\t\t\ttail = head;\n\t\t\t}\n\t\t\tcurrent.next = null;\n\t\t\treturn current;\n\t\t}\n\t\tfunction release(obj) {\n\t\t\ttail.next = obj;\n\t\t\ttail = obj;\n\t\t}\n\t\treturn {\n\t\t\tget,\n\t\t\trelease\n\t\t};\n\t}\n\tmodule.exports = reusify;\n}));\n//#endregion\n//#region ../../../../node_modules/@durable-streams/client/dist/index.js\nvar import_queue = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {\n\tvar reusify = require_reusify();\n\tfunction fastqueue(context, worker, _concurrency) {\n\t\tif (typeof context === \"function\") {\n\t\t\t_concurrency = worker;\n\t\t\tworker = context;\n\t\t\tcontext = null;\n\t\t}\n\t\tif (!(_concurrency >= 1)) throw new Error(\"fastqueue concurrency must be equal to or greater than 1\");\n\t\tvar cache = reusify(Task);\n\t\tvar queueHead = null;\n\t\tvar queueTail = null;\n\t\tvar _running = 0;\n\t\tvar errorHandler = null;\n\t\tvar self = {\n\t\t\tpush,\n\t\t\tdrain: noop,\n\t\t\tsaturated: noop,\n\t\t\tpause,\n\t\t\tpaused: false,\n\t\t\tget concurrency() {\n\t\t\t\treturn _concurrency;\n\t\t\t},\n\t\t\tset concurrency(value) {\n\t\t\t\tif (!(value >= 1)) throw new Error(\"fastqueue concurrency must be equal to or greater than 1\");\n\t\t\t\t_concurrency = value;\n\t\t\t\tif (self.paused) return;\n\t\t\t\tfor (; queueHead && _running < _concurrency;) {\n\t\t\t\t\t_running++;\n\t\t\t\t\trelease();\n\t\t\t\t}\n\t\t\t},\n\t\t\trunning,\n\t\t\tresume,\n\t\t\tidle,\n\t\t\tlength,\n\t\t\tgetQueue,\n\t\t\tunshift,\n\t\t\tempty: noop,\n\t\t\tkill,\n\t\t\tkillAndDrain,\n\t\t\terror,\n\t\t\tabort\n\t\t};\n\t\treturn self;\n\t\tfunction running() {\n\t\t\treturn _running;\n\t\t}\n\t\tfunction pause() {\n\t\t\tself.paused = true;\n\t\t}\n\t\tfunction length() {\n\t\t\tvar current = queueHead;\n\t\t\tvar counter = 0;\n\t\t\twhile (current) {\n\t\t\t\tcurrent = current.next;\n\t\t\t\tcounter++;\n\t\t\t}\n\t\t\treturn counter;\n\t\t}\n\t\tfunction getQueue() {\n\t\t\tvar current = queueHead;\n\t\t\tvar tasks = [];\n\t\t\twhile (current) {\n\t\t\t\ttasks.push(current.value);\n\t\t\t\tcurrent = current.next;\n\t\t\t}\n\t\t\treturn tasks;\n\t\t}\n\t\tfunction resume() {\n\t\t\tif (!self.paused) return;\n\t\t\tself.paused = false;\n\t\t\tif (queueHead === null) {\n\t\t\t\t_running++;\n\t\t\t\trelease();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (; queueHead && _running < _concurrency;) {\n\t\t\t\t_running++;\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t\tfunction idle() {\n\t\t\treturn _running === 0 && self.length() === 0;\n\t\t}\n\t\tfunction push(value, done) {\n\t\t\tvar current = cache.get();\n\t\t\tcurrent.context = context;\n\t\t\tcurrent.release = release;\n\t\t\tcurrent.value = value;\n\t\t\tcurrent.callback = done || noop;\n\t\t\tcurrent.errorHandler = errorHandler;\n\t\t\tif (_running >= _concurrency || self.paused) if (queueTail) {\n\t\t\t\tqueueTail.next = current;\n\t\t\t\tqueueTail = current;\n\t\t\t} else {\n\t\t\t\tqueueHead = current;\n\t\t\t\tqueueTail = current;\n\t\t\t\tself.saturated();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_running++;\n\t\t\t\tworker.call(context, current.value, current.worked);\n\t\t\t}\n\t\t}\n\t\tfunction unshift(value, done) {\n\t\t\tvar current = cache.get();\n\t\t\tcurrent.context = context;\n\t\t\tcurrent.release = release;\n\t\t\tcurrent.value = value;\n\t\t\tcurrent.callback = done || noop;\n\t\t\tcurrent.errorHandler = errorHandler;\n\t\t\tif (_running >= _concurrency || self.paused) if (queueHead) {\n\t\t\t\tcurrent.next = queueHead;\n\t\t\t\tqueueHead = current;\n\t\t\t} else {\n\t\t\t\tqueueHead = current;\n\t\t\t\tqueueTail = current;\n\t\t\t\tself.saturated();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_running++;\n\t\t\t\tworker.call(context, current.value, current.worked);\n\t\t\t}\n\t\t}\n\t\tfunction release(holder) {\n\t\t\tif (holder) cache.release(holder);\n\t\t\tvar next = queueHead;\n\t\t\tif (next && _running <= _concurrency) if (!self.paused) {\n\t\t\t\tif (queueTail === queueHead) queueTail = null;\n\t\t\t\tqueueHead = next.next;\n\t\t\t\tnext.next = null;\n\t\t\t\tworker.call(context, next.value, next.worked);\n\t\t\t\tif (queueTail === null) self.empty();\n\t\t\t} else _running--;\n\t\t\telse if (--_running === 0) self.drain();\n\t\t}\n\t\tfunction kill() {\n\t\t\tqueueHead = null;\n\t\t\tqueueTail = null;\n\t\t\tself.drain = noop;\n\t\t}\n\t\tfunction killAndDrain() {\n\t\t\tqueueHead = null;\n\t\t\tqueueTail = null;\n\t\t\tself.drain();\n\t\t\tself.drain = noop;\n\t\t}\n\t\tfunction abort() {\n\t\t\tvar current = queueHead;\n\t\t\tqueueHead = null;\n\t\t\tqueueTail = null;\n\t\t\twhile (current) {\n\t\t\t\tvar next = current.next;\n\t\t\t\tvar callback = current.callback;\n\t\t\t\tvar errorHandler = current.errorHandler;\n\t\t\t\tvar val = current.value;\n\t\t\t\tvar context = current.context;\n\t\t\t\tcurrent.value = null;\n\t\t\t\tcurrent.callback = noop;\n\t\t\t\tcurrent.errorHandler = null;\n\t\t\t\tif (errorHandler) errorHandler(/* @__PURE__ */ new Error(\"abort\"), val);\n\t\t\t\tcallback.call(context, /* @__PURE__ */ new Error(\"abort\"));\n\t\t\t\tcurrent.release(current);\n\t\t\t\tcurrent = next;\n\t\t\t}\n\t\t\tself.drain = noop;\n\t\t}\n\t\tfunction error(handler) {\n\t\t\terrorHandler = handler;\n\t\t}\n\t}\n\tfunction noop() {}\n\tfunction Task() {\n\t\tthis.value = null;\n\t\tthis.callback = noop;\n\t\tthis.next = null;\n\t\tthis.release = noop;\n\t\tthis.context = null;\n\t\tthis.errorHandler = null;\n\t\tvar self = this;\n\t\tthis.worked = function worked(err, result) {\n\t\t\tvar callback = self.callback;\n\t\t\tvar errorHandler = self.errorHandler;\n\t\t\tvar val = self.value;\n\t\t\tself.value = null;\n\t\t\tself.callback = noop;\n\t\t\tif (self.errorHandler) errorHandler(err, val);\n\t\t\tcallback.call(self.context, err, result);\n\t\t\tself.release(self);\n\t\t};\n\t}\n\tfunction queueAsPromised(context, worker, _concurrency) {\n\t\tif (typeof context === \"function\") {\n\t\t\t_concurrency = worker;\n\t\t\tworker = context;\n\t\t\tcontext = null;\n\t\t}\n\t\tfunction asyncWrapper(arg, cb) {\n\t\t\tworker.call(this, arg).then(function(res) {\n\t\t\t\tcb(null, res);\n\t\t\t}, cb);\n\t\t}\n\t\tvar queue = fastqueue(context, asyncWrapper, _concurrency);\n\t\tvar pushCb = queue.push;\n\t\tvar unshiftCb = queue.unshift;\n\t\tqueue.push = push;\n\t\tqueue.unshift = unshift;\n\t\tqueue.drained = drained;\n\t\treturn queue;\n\t\tfunction push(value) {\n\t\t\tvar p = new Promise(function(resolve, reject) {\n\t\t\t\tpushCb(value, function(err, result) {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tresolve(result);\n\t\t\t\t});\n\t\t\t});\n\t\t\tp.catch(noop);\n\t\t\treturn p;\n\t\t}\n\t\tfunction unshift(value) {\n\t\t\tvar p = new Promise(function(resolve, reject) {\n\t\t\t\tunshiftCb(value, function(err, result) {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tresolve(result);\n\t\t\t\t});\n\t\t\t});\n\t\t\tp.catch(noop);\n\t\t\treturn p;\n\t\t}\n\t\tfunction drained() {\n\t\t\treturn new Promise(function(resolve) {\n\t\t\t\tprocess.nextTick(function() {\n\t\t\t\t\tif (queue.idle()) resolve();\n\t\t\t\t\telse {\n\t\t\t\t\t\tvar previousDrain = queue.drain;\n\t\t\t\t\t\tqueue.drain = function() {\n\t\t\t\t\t\t\tif (typeof previousDrain === \"function\") previousDrain();\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\tqueue.drain = previousDrain;\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\tmodule.exports = fastqueue;\n\tmodule.exports.promise = queueAsPromised;\n})))(), 1);\n/**\n* Durable Streams Protocol Constants\n*\n* Header and query parameter names following the Electric Durable Stream Protocol.\n*/\n/**\n* Response header containing the next offset to read from.\n* Offsets are opaque tokens - clients MUST NOT interpret the format.\n*/\nconst STREAM_OFFSET_HEADER = `Stream-Next-Offset`;\n/**\n* Response header for cursor (used for CDN collapsing).\n* Echo this value in subsequent long-poll requests.\n*/\nconst STREAM_CURSOR_HEADER = `Stream-Cursor`;\n/**\n* Presence header indicating response ends at current end of stream.\n* When present (any value), indicates up-to-date.\n*/\nconst STREAM_UP_TO_DATE_HEADER = `Stream-Up-To-Date`;\n/**\n* Response/request header indicating stream is closed (EOF).\n* When present with value \"true\", the stream is permanently closed.\n*/\nconst STREAM_CLOSED_HEADER = `Stream-Closed`;\n/**\n* Request header for writer coordination sequence.\n* Monotonic, lexicographic. If lower than last appended seq -> 409 Conflict.\n*/\nconst STREAM_SEQ_HEADER = `Stream-Seq`;\n/**\n* Request header for stream TTL in seconds (on create).\n*/\nconst STREAM_TTL_HEADER = `Stream-TTL`;\n/**\n* Request header for absolute stream expiry time (RFC3339, on create).\n*/\nconst STREAM_EXPIRES_AT_HEADER = `Stream-Expires-At`;\n/**\n* Request header for producer ID (client-supplied stable identifier).\n*/\nconst PRODUCER_ID_HEADER = `Producer-Id`;\n/**\n* Request/response header for producer epoch.\n* Client-declared, server-validated monotonically increasing.\n*/\nconst PRODUCER_EPOCH_HEADER = `Producer-Epoch`;\n/**\n* Request header for producer sequence number.\n* Monotonically increasing per epoch, per-batch (not per-message).\n*/\nconst PRODUCER_SEQ_HEADER = `Producer-Seq`;\n/**\n* Response header indicating expected sequence number on 409 Conflict.\n*/\nconst PRODUCER_EXPECTED_SEQ_HEADER = `Producer-Expected-Seq`;\n/**\n* Response header indicating received sequence number on 409 Conflict.\n*/\nconst PRODUCER_RECEIVED_SEQ_HEADER = `Producer-Received-Seq`;\n/**\n* Query parameter for starting offset.\n*/\nconst OFFSET_QUERY_PARAM = `offset`;\n/**\n* Query parameter for live mode.\n* Values: \"long-poll\", \"sse\"\n*/\nconst LIVE_QUERY_PARAM = `live`;\n/**\n* Response header indicating SSE data encoding (e.g., base64 for binary streams).\n*/\nconst STREAM_SSE_DATA_ENCODING_HEADER = `stream-sse-data-encoding`;\n/**\n* Error thrown for transport/network errors.\n* Following the @electric-sql/client FetchError pattern.\n*/\nvar FetchError = class FetchError extends Error {\n\tstatus;\n\ttext;\n\tjson;\n\theaders;\n\tconstructor(status, text, json, headers, url, message) {\n\t\tsuper(message || `HTTP Error ${status} at ${url}: ${text ?? JSON.stringify(json)}`);\n\t\tthis.url = url;\n\t\tthis.name = `FetchError`;\n\t\tthis.status = status;\n\t\tthis.text = text;\n\t\tthis.json = json;\n\t\tthis.headers = headers;\n\t}\n\tstatic async fromResponse(response, url) {\n\t\tconst status = response.status;\n\t\tconst headers = Object.fromEntries([...response.headers.entries()]);\n\t\tlet text = void 0;\n\t\tlet json = void 0;\n\t\tconst contentType = response.headers.get(`content-type`);\n\t\tif (!response.bodyUsed && response.body !== null) if (contentType && contentType.includes(`application/json`)) try {\n\t\t\tjson = await response.json();\n\t\t} catch {\n\t\t\ttext = await response.text();\n\t\t}\n\t\telse text = await response.text();\n\t\treturn new FetchError(status, text, json, headers, url);\n\t}\n};\n/**\n* Error thrown when a fetch operation is aborted during backoff.\n*/\nvar FetchBackoffAbortError = class extends Error {\n\tconstructor() {\n\t\tsuper(`Fetch with backoff aborted`);\n\t\tthis.name = `FetchBackoffAbortError`;\n\t}\n};\n/**\n* Protocol-level error for Durable Streams operations.\n* Provides structured error handling with error codes.\n*/\nvar DurableStreamError = class DurableStreamError extends Error {\n\t/**\n\t* HTTP status code, if applicable.\n\t*/\n\tstatus;\n\t/**\n\t* Structured error code for programmatic handling.\n\t*/\n\tcode;\n\t/**\n\t* Additional error details (e.g., raw response body).\n\t*/\n\tdetails;\n\tconstructor(message, code, status, details) {\n\t\tsuper(message);\n\t\tthis.name = `DurableStreamError`;\n\t\tthis.code = code;\n\t\tthis.status = status;\n\t\tthis.details = details;\n\t}\n\t/**\n\t* Create a DurableStreamError from an HTTP response.\n\t*/\n\tstatic async fromResponse(response, url) {\n\t\tconst status = response.status;\n\t\tlet details;\n\t\tconst contentType = response.headers.get(`content-type`);\n\t\tif (!response.bodyUsed && response.body !== null) if (contentType && contentType.includes(`application/json`)) try {\n\t\t\tdetails = await response.json();\n\t\t} catch {\n\t\t\tdetails = await response.text();\n\t\t}\n\t\telse details = await response.text();\n\t\tconst code = statusToCode(status);\n\t\tconst message = `Durable stream error at ${url}: ${response.statusText || status}`;\n\t\treturn new DurableStreamError(message, code, status, details);\n\t}\n\t/**\n\t* Create a DurableStreamError from a FetchError.\n\t*/\n\tstatic fromFetchError(error) {\n\t\tconst code = statusToCode(error.status);\n\t\treturn new DurableStreamError(error.message, code, error.status, error.json ?? error.text);\n\t}\n};\n/**\n* Map HTTP status codes to DurableStreamErrorCode.\n*/\nfunction statusToCode(status) {\n\tswitch (status) {\n\t\tcase 400: return `BAD_REQUEST`;\n\t\tcase 401: return `UNAUTHORIZED`;\n\t\tcase 403: return `FORBIDDEN`;\n\t\tcase 404: return `NOT_FOUND`;\n\t\tcase 409: return `CONFLICT_SEQ`;\n\t\tcase 429: return `RATE_LIMITED`;\n\t\tcase 503: return `BUSY`;\n\t\tdefault: return `UNKNOWN`;\n\t}\n}\n/**\n* Error thrown when stream URL is missing.\n*/\nvar MissingStreamUrlError = class extends Error {\n\tconstructor() {\n\t\tsuper(`Invalid stream options: missing required url parameter`);\n\t\tthis.name = `MissingStreamUrlError`;\n\t}\n};\n/**\n* Error thrown when attempting to append to a closed stream.\n*/\nvar StreamClosedError = class extends DurableStreamError {\n\tcode = `STREAM_CLOSED`;\n\tstatus = 409;\n\tstreamClosed = true;\n\t/**\n\t* The final offset of the stream, if available from the response.\n\t*/\n\tfinalOffset;\n\tconstructor(url, finalOffset) {\n\t\tsuper(`Cannot append to closed stream`, `STREAM_CLOSED`, 409, url);\n\t\tthis.name = `StreamClosedError`;\n\t\tthis.finalOffset = finalOffset;\n\t}\n};\n/**\n* Error thrown when signal option is invalid.\n*/\nvar InvalidSignalError = class extends Error {\n\tconstructor() {\n\t\tsuper(`Invalid signal option. It must be an instance of AbortSignal.`);\n\t\tthis.name = `InvalidSignalError`;\n\t}\n};\n/**\n* HTTP status codes that should be retried.\n*/\nconst HTTP_RETRY_STATUS_CODES = [429, 503];\n/**\n* Default backoff options.\n*/\nconst BackoffDefaults = {\n\tinitialDelay: 100,\n\tmaxDelay: 6e4,\n\tmultiplier: 1.3,\n\tmaxRetries: Infinity\n};\n/**\n* Parse Retry-After header value and return delay in milliseconds.\n* Supports both delta-seconds format and HTTP-date format.\n* Returns 0 if header is not present or invalid.\n*/\nfunction parseRetryAfterHeader(retryAfter) {\n\tif (!retryAfter) return 0;\n\tconst retryAfterSec = Number(retryAfter);\n\tif (Number.isFinite(retryAfterSec) && retryAfterSec > 0) return retryAfterSec * 1e3;\n\tconst retryDate = Date.parse(retryAfter);\n\tif (!isNaN(retryDate)) {\n\t\tconst deltaMs = retryDate - Date.now();\n\t\treturn Math.max(0, Math.min(deltaMs, 36e5));\n\t}\n\treturn 0;\n}\n/**\n* Creates a fetch client that retries failed requests with exponential backoff.\n*\n* @param fetchClient - The base fetch client to wrap\n* @param backoffOptions - Options for retry behavior\n* @returns A fetch function with automatic retry\n*/\nfunction createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {\n\tconst { initialDelay, maxDelay, multiplier, debug = false, onFailedAttempt, maxRetries = Infinity } = backoffOptions;\n\treturn async (...args) => {\n\t\tconst url = args[0];\n\t\tconst options = args[1];\n\t\tlet delay = initialDelay;\n\t\tlet attempt = 0;\n\t\twhile (true) try {\n\t\t\tconst result = await fetchClient(...args);\n\t\t\tif (result.ok) return result;\n\t\t\tthrow await FetchError.fromResponse(result, url.toString());\n\t\t} catch (e) {\n\t\t\tonFailedAttempt?.();\n\t\t\tif (options?.signal?.aborted) throw new FetchBackoffAbortError();\n\t\t\telse if (e instanceof FetchError && !HTTP_RETRY_STATUS_CODES.includes(e.status) && e.status >= 400 && e.status < 500) throw e;\n\t\t\telse {\n\t\t\t\tattempt++;\n\t\t\t\tif (attempt > maxRetries) {\n\t\t\t\t\tif (debug) console.log(`Max retries reached (${attempt}/${maxRetries}), giving up`);\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t\tconst serverMinimumMs = e instanceof FetchError ? parseRetryAfterHeader(e.headers[`retry-after`]) : 0;\n\t\t\t\tconst jitter = Math.random() * delay;\n\t\t\t\tconst clientBackoffMs = Math.min(jitter, maxDelay);\n\t\t\t\tconst waitMs = Math.max(serverMinimumMs, clientBackoffMs);\n\t\t\t\tif (debug) console.log(`Retry attempt #${attempt} after ${waitMs}ms (${serverMinimumMs > 0 ? `server+client` : `client`}, serverMin=${serverMinimumMs}ms, clientBackoff=${clientBackoffMs}ms)`);\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, waitMs));\n\t\t\t\tdelay = Math.min(delay * multiplier, maxDelay);\n\t\t\t}\n\t\t}\n\t};\n}\n/**\n* Status codes where we shouldn't try to read the body.\n*/\nconst NO_BODY_STATUS_CODES = [\n\t201,\n\t204,\n\t205\n];\n/**\n* Creates a fetch client that ensures the response body is fully consumed.\n* This prevents issues with connection pooling when bodies aren't read.\n*\n* Uses arrayBuffer() instead of text() to preserve binary data integrity.\n*\n* @param fetchClient - The base fetch client to wrap\n* @returns A fetch function that consumes response bodies\n*/\nfunction createFetchWithConsumedBody(fetchClient) {\n\treturn async (...args) => {\n\t\tconst url = args[0];\n\t\tconst res = await fetchClient(...args);\n\t\ttry {\n\t\t\tif (res.status < 200 || NO_BODY_STATUS_CODES.includes(res.status)) return res;\n\t\t\tconst buf = await res.arrayBuffer();\n\t\t\treturn new Response(buf, {\n\t\t\t\tstatus: res.status,\n\t\t\t\tstatusText: res.statusText,\n\t\t\t\theaders: res.headers\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tif (args[1]?.signal?.aborted) throw new FetchBackoffAbortError();\n\t\t\tthrow new FetchError(res.status, void 0, void 0, Object.fromEntries([...res.headers.entries()]), url.toString(), err instanceof Error ? err.message : typeof err === `string` ? err : `failed to read body`);\n\t\t}\n\t};\n}\n/**\n* Check if a value has Symbol.asyncIterator defined.\n*/\nfunction hasAsyncIterator(stream$1) {\n\treturn typeof Symbol !== `undefined` && typeof Symbol.asyncIterator === `symbol` && typeof stream$1[Symbol.asyncIterator] === `function`;\n}\n/**\n* Define [Symbol.asyncIterator] and .values() on a ReadableStream instance.\n*\n* Uses getReader().read() to implement spec-consistent iteration.\n* On completion or early exit (break/return/throw), releases lock and cancels as appropriate.\n*\n* **Iterator behavior notes:**\n* - `return(value?)` accepts an optional cancellation reason passed to `reader.cancel()`\n* - `return()` always resolves with `{ done: true, value: undefined }` regardless of the\n* input value. This matches `for await...of` semantics where the return value is ignored.\n* Manual iteration users should be aware of this behavior.\n*/\nfunction defineAsyncIterator(stream$1) {\n\tif (typeof Symbol === `undefined` || typeof Symbol.asyncIterator !== `symbol`) return;\n\tif (typeof stream$1[Symbol.asyncIterator] === `function`) return;\n\tconst createIterator = function() {\n\t\tconst reader = this.getReader();\n\t\tlet finished = false;\n\t\tlet pendingReads = 0;\n\t\treturn {\n\t\t\tasync next() {\n\t\t\t\tif (finished) return {\n\t\t\t\t\tdone: true,\n\t\t\t\t\tvalue: void 0\n\t\t\t\t};\n\t\t\t\tpendingReads++;\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = await reader.read();\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tfinished = true;\n\t\t\t\t\t\treader.releaseLock();\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tdone: true,\n\t\t\t\t\t\t\tvalue: void 0\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdone: false,\n\t\t\t\t\t\tvalue\n\t\t\t\t\t};\n\t\t\t\t} catch (err) {\n\t\t\t\t\tfinished = true;\n\t\t\t\t\ttry {\n\t\t\t\t\t\treader.releaseLock();\n\t\t\t\t\t} catch {}\n\t\t\t\t\tthrow err;\n\t\t\t\t} finally {\n\t\t\t\t\tpendingReads--;\n\t\t\t\t}\n\t\t\t},\n\t\t\tasync return(value) {\n\t\t\t\tif (pendingReads > 0) throw new TypeError(`Cannot close a readable stream reader when it has pending read requests`);\n\t\t\t\tfinished = true;\n\t\t\t\tconst cancelPromise = reader.cancel(value);\n\t\t\t\treader.releaseLock();\n\t\t\t\tawait cancelPromise;\n\t\t\t\treturn {\n\t\t\t\t\tdone: true,\n\t\t\t\t\tvalue: void 0\n\t\t\t\t};\n\t\t\t},\n\t\t\tasync throw(err) {\n\t\t\t\tif (pendingReads > 0) throw new TypeError(`Cannot close a readable stream reader when it has pending read requests`);\n\t\t\t\tfinished = true;\n\t\t\t\tconst cancelPromise = reader.cancel(err);\n\t\t\t\treader.releaseLock();\n\t\t\t\tawait cancelPromise;\n\t\t\t\tthrow err;\n\t\t\t},\n\t\t\t[Symbol.asyncIterator]() {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t};\n\t};\n\ttry {\n\t\tObject.defineProperty(stream$1, Symbol.asyncIterator, {\n\t\t\tconfigurable: true,\n\t\t\twritable: true,\n\t\t\tvalue: createIterator\n\t\t});\n\t} catch {\n\t\treturn;\n\t}\n\ttry {\n\t\tObject.defineProperty(stream$1, `values`, {\n\t\t\tconfigurable: true,\n\t\t\twritable: true,\n\t\t\tvalue: createIterator\n\t\t});\n\t} catch {}\n}\n/**\n* Ensure a ReadableStream is async-iterable.\n*\n* If the stream already has [Symbol.asyncIterator] defined (native or polyfilled),\n* it is returned as-is. Otherwise, [Symbol.asyncIterator] is defined on the\n* stream instance (not the prototype).\n*\n* The returned value is the same ReadableStream instance, so:\n* - `stream instanceof ReadableStream` remains true\n* - Any code relying on native branding/internal slots continues to work\n*\n* @example\n* ```typescript\n* const stream = someApiReturningReadableStream();\n* const iterableStream = asAsyncIterableReadableStream(stream);\n*\n* // Now works on Safari/iOS:\n* for await (const chunk of iterableStream) {\n* console.log(chunk);\n* }\n* ```\n*/\nfunction asAsyncIterableReadableStream(stream$1) {\n\tif (!hasAsyncIterator(stream$1)) defineAsyncIterator(stream$1);\n\treturn stream$1;\n}\n/**\n* Parse SSE events from a ReadableStream<Uint8Array>.\n* Yields parsed events as they arrive.\n*/\nasync function* parseSSEStream(stream$1, signal) {\n\tconst reader = stream$1.getReader();\n\tconst decoder = new TextDecoder();\n\tlet buffer = ``;\n\tlet currentEvent = { data: [] };\n\ttry {\n\t\twhile (true) {\n\t\t\tif (signal?.aborted) break;\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\tbuffer = buffer.replace(/\\r\\n/g, `\\n`).replace(/\\r/g, `\\n`);\n\t\t\tconst lines = buffer.split(`\\n`);\n\t\t\tbuffer = lines.pop() ?? ``;\n\t\t\tfor (const line of lines) if (line === ``) {\n\t\t\t\tif (currentEvent.type && currentEvent.data.length > 0) {\n\t\t\t\t\tconst dataStr = currentEvent.data.join(`\\n`);\n\t\t\t\t\tif (currentEvent.type === `data`) yield {\n\t\t\t\t\t\ttype: `data`,\n\t\t\t\t\t\tdata: dataStr\n\t\t\t\t\t};\n\t\t\t\t\telse if (currentEvent.type === `control`) try {\n\t\t\t\t\t\tconst control = JSON.parse(dataStr);\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: `control`,\n\t\t\t\t\t\t\tstreamNextOffset: control.streamNextOffset,\n\t\t\t\t\t\t\tstreamCursor: control.streamCursor,\n\t\t\t\t\t\t\tupToDate: control.upToDate,\n\t\t\t\t\t\t\tstreamClosed: control.streamClosed\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst preview = dataStr.length > 100 ? dataStr.slice(0, 100) + `...` : dataStr;\n\t\t\t\t\t\tthrow new DurableStreamError(`Failed to parse SSE control event: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcurrentEvent = { data: [] };\n\t\t\t} else if (line.startsWith(`event:`)) {\n\t\t\t\tconst eventType = line.slice(6);\n\t\t\t\tcurrentEvent.type = eventType.startsWith(` `) ? eventType.slice(1) : eventType;\n\t\t\t} else if (line.startsWith(`data:`)) {\n\t\t\t\tconst content = line.slice(5);\n\t\t\t\tcurrentEvent.data.push(content.startsWith(` `) ? content.slice(1) : content);\n\t\t\t}\n\t\t}\n\t\tconst remaining = decoder.decode();\n\t\tif (remaining) buffer += remaining;\n\t\tif (buffer && currentEvent.type && currentEvent.data.length > 0) {\n\t\t\tconst dataStr = currentEvent.data.join(`\\n`);\n\t\t\tif (currentEvent.type === `data`) yield {\n\t\t\t\ttype: `data`,\n\t\t\t\tdata: dataStr\n\t\t\t};\n\t\t\telse if (currentEvent.type === `control`) try {\n\t\t\t\tconst control = JSON.parse(dataStr);\n\t\t\t\tyield {\n\t\t\t\t\ttype: `control`,\n\t\t\t\t\tstreamNextOffset: control.streamNextOffset,\n\t\t\t\t\tstreamCursor: control.streamCursor,\n\t\t\t\t\tupToDate: control.upToDate,\n\t\t\t\t\tstreamClosed: control.streamClosed\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst preview = dataStr.length > 100 ? dataStr.slice(0, 100) + `...` : dataStr;\n\t\t\t\tthrow new DurableStreamError(`Failed to parse SSE control event: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t}\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n}\n/**\n* Abstract base class for stream response state.\n* All state transitions return new immutable state objects.\n*/\nvar StreamResponseState = class {\n\tshouldContinueLive(stopAfterUpToDate, liveMode) {\n\t\tif (stopAfterUpToDate && this.upToDate) return false;\n\t\tif (liveMode === false) return false;\n\t\tif (this.streamClosed) return false;\n\t\treturn true;\n\t}\n};\n/**\n* State for long-poll mode. shouldUseSse() returns false.\n*/\nvar LongPollState = class LongPollState extends StreamResponseState {\n\toffset;\n\tcursor;\n\tupToDate;\n\tstreamClosed;\n\tconstructor(fields) {\n\t\tsuper();\n\t\tthis.offset = fields.offset;\n\t\tthis.cursor = fields.cursor;\n\t\tthis.upToDate = fields.upToDate;\n\t\tthis.streamClosed = fields.streamClosed;\n\t}\n\tshouldUseSse() {\n\t\treturn false;\n\t}\n\twithResponseMetadata(update) {\n\t\treturn new LongPollState({\n\t\t\toffset: update.offset ?? this.offset,\n\t\t\tcursor: update.cursor ?? this.cursor,\n\t\t\tupToDate: update.upToDate,\n\t\t\tstreamClosed: this.streamClosed || update.streamClosed\n\t\t});\n\t}\n\twithSSEControl(event) {\n\t\tconst streamClosed = this.streamClosed || (event.streamClosed ?? false);\n\t\treturn new LongPollState({\n\t\t\toffset: event.streamNextOffset,\n\t\t\tcursor: event.streamCursor || this.cursor,\n\t\t\tupToDate: event.streamClosed ?? false ? true : event.upToDate ?? this.upToDate,\n\t\t\tstreamClosed\n\t\t});\n\t}\n\tpause() {\n\t\treturn new PausedState(this);\n\t}\n};\n/**\n* State for SSE mode. shouldUseSse() returns true.\n* Tracks SSE connection resilience (short connection detection).\n*/\nvar SSEState = class SSEState extends StreamResponseState {\n\toffset;\n\tcursor;\n\tupToDate;\n\tstreamClosed;\n\tconsecutiveShortConnections;\n\tconnectionStartTime;\n\tconstructor(fields) {\n\t\tsuper();\n\t\tthis.offset = fields.offset;\n\t\tthis.cursor = fields.cursor;\n\t\tthis.upToDate = fields.upToDate;\n\t\tthis.streamClosed = fields.streamClosed;\n\t\tthis.consecutiveShortConnections = fields.consecutiveShortConnections ?? 0;\n\t\tthis.connectionStartTime = fields.connectionStartTime;\n\t}\n\tshouldUseSse() {\n\t\treturn true;\n\t}\n\twithResponseMetadata(update) {\n\t\treturn new SSEState({\n\t\t\toffset: update.offset ?? this.offset,\n\t\t\tcursor: update.cursor ?? this.cursor,\n\t\t\tupToDate: update.upToDate,\n\t\t\tstreamClosed: this.streamClosed || update.streamClosed,\n\t\t\tconsecutiveShortConnections: this.consecutiveShortConnections,\n\t\t\tconnectionStartTime: this.connectionStartTime\n\t\t});\n\t}\n\twithSSEControl(event) {\n\t\tconst streamClosed = this.streamClosed || (event.streamClosed ?? false);\n\t\treturn new SSEState({\n\t\t\toffset: event.streamNextOffset,\n\t\t\tcursor: event.streamCursor || this.cursor,\n\t\t\tupToDate: event.streamClosed ?? false ? true : event.upToDate ?? this.upToDate,\n\t\t\tstreamClosed,\n\t\t\tconsecutiveShortConnections: this.consecutiveShortConnections,\n\t\t\tconnectionStartTime: this.connectionStartTime\n\t\t});\n\t}\n\tstartConnection(now) {\n\t\treturn new SSEState({\n\t\t\toffset: this.offset,\n\t\t\tcursor: this.cursor,\n\t\t\tupToDate: this.upToDate,\n\t\t\tstreamClosed: this.streamClosed,\n\t\t\tconsecutiveShortConnections: this.consecutiveShortConnections,\n\t\t\tconnectionStartTime: now\n\t\t});\n\t}\n\thandleConnectionEnd(now, wasAborted, config) {\n\t\tif (this.connectionStartTime === void 0) return {\n\t\t\taction: `healthy`,\n\t\t\tstate: this\n\t\t};\n\t\tconst duration = now - this.connectionStartTime;\n\t\tif (duration < config.minConnectionDuration && !wasAborted) {\n\t\t\tconst newCount = this.consecutiveShortConnections + 1;\n\t\t\tif (newCount >= config.maxShortConnections) return {\n\t\t\t\taction: `fallback`,\n\t\t\t\tstate: new LongPollState({\n\t\t\t\t\toffset: this.offset,\n\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\tupToDate: this.upToDate,\n\t\t\t\t\tstreamClosed: this.streamClosed\n\t\t\t\t})\n\t\t\t};\n\t\t\treturn {\n\t\t\t\taction: `reconnect`,\n\t\t\t\tstate: new SSEState({\n\t\t\t\t\toffset: this.offset,\n\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\tupToDate: this.upToDate,\n\t\t\t\t\tstreamClosed: this.streamClosed,\n\t\t\t\t\tconsecutiveShortConnections: newCount,\n\t\t\t\t\tconnectionStartTime: this.connectionStartTime\n\t\t\t\t}),\n\t\t\t\tbackoffAttempt: newCount\n\t\t\t};\n\t\t}\n\t\tif (duration >= config.minConnectionDuration) return {\n\t\t\taction: `healthy`,\n\t\t\tstate: new SSEState({\n\t\t\t\toffset: this.offset,\n\t\t\t\tcursor: this.cursor,\n\t\t\t\tupToDate: this.upToDate,\n\t\t\t\tstreamClosed: this.streamClosed,\n\t\t\t\tconsecutiveShortConnections: 0,\n\t\t\t\tconnectionStartTime: this.connectionStartTime\n\t\t\t})\n\t\t};\n\t\treturn {\n\t\t\taction: `healthy`,\n\t\t\tstate: this\n\t\t};\n\t}\n\tpause() {\n\t\treturn new PausedState(this);\n\t}\n};\n/**\n* Paused state wrapper. Delegates all sync field access to the inner state.\n* resume() returns the wrapped state unchanged (identity preserved).\n*/\nvar PausedState = class PausedState extends StreamResponseState {\n\t#inner;\n\tconstructor(inner) {\n\t\tsuper();\n\t\tthis.#inner = inner;\n\t}\n\tget offset() {\n\t\treturn this.#inner.offset;\n\t}\n\tget cursor() {\n\t\treturn this.#inner.cursor;\n\t}\n\tget upToDate() {\n\t\treturn this.#inner.upToDate;\n\t}\n\tget streamClosed() {\n\t\treturn this.#inner.streamClosed;\n\t}\n\tshouldUseSse() {\n\t\treturn this.#inner.shouldUseSse();\n\t}\n\twithResponseMetadata(update) {\n\t\tconst newInner = this.#inner.withResponseMetadata(update);\n\t\treturn new PausedState(newInner);\n\t}\n\twithSSEControl(event) {\n\t\tconst newInner = this.#inner.withSSEControl(event);\n\t\treturn new PausedState(newInner);\n\t}\n\tpause() {\n\t\treturn this;\n\t}\n\tresume() {\n\t\treturn {\n\t\t\tstate: this.#inner,\n\t\t\tjustResumed: true\n\t\t};\n\t}\n};\n/**\n* Constant used as abort reason when pausing the stream due to visibility change.\n*/\nconst PAUSE_STREAM = `PAUSE_STREAM`;\n/**\n* Implementation of the StreamResponse interface.\n*/\nvar StreamResponseImpl = class {\n\turl;\n\tcontentType;\n\tlive;\n\tstartOffset;\n\t#headers;\n\t#status;\n\t#statusText;\n\t#ok;\n\t#isLoading;\n\t#syncState;\n\t#isJsonMode;\n\t#abortController;\n\t#fetchNext;\n\t#startSSE;\n\t#closedResolve;\n\t#closedReject;\n\t#closed;\n\t#stopAfterUpToDate = false;\n\t#consumptionMethod = null;\n\t#state = `active`;\n\t#requestAbortController;\n\t#unsubscribeFromVisibilityChanges;\n\t#pausePromise;\n\t#pauseResolve;\n\t#sseResilience;\n\t#encoding;\n\t#responseStream;\n\tconstructor(config) {\n\t\tthis.url = config.url;\n\t\tthis.contentType = config.contentType;\n\t\tthis.live = config.live;\n\t\tthis.startOffset = config.startOffset;\n\t\tconst syncFields = {\n\t\t\toffset: config.initialOffset,\n\t\t\tcursor: config.initialCursor,\n\t\t\tupToDate: config.initialUpToDate,\n\t\t\tstreamClosed: config.initialStreamClosed\n\t\t};\n\t\tthis.#syncState = config.startSSE ? new SSEState(syncFields) : new LongPollState(syncFields);\n\t\tthis.#headers = config.firstResponse.headers;\n\t\tthis.#status = config.firstResponse.status;\n\t\tthis.#statusText = config.firstResponse.statusText;\n\t\tthis.#ok = config.firstResponse.ok;\n\t\tthis.#isLoading = false;\n\t\tthis.#isJsonMode = config.isJsonMode;\n\t\tthis.#abortController = config.abortController;\n\t\tthis.#fetchNext = config.fetchNext;\n\t\tthis.#startSSE = config.startSSE;\n\t\tthis.#sseResilience = {\n\t\t\tminConnectionDuration: config.sseResilience?.minConnectionDuration ?? 1e3,\n\t\t\tmaxShortConnections: config.sseResilience?.maxShortConnections ?? 3,\n\t\t\tbackoffBaseDelay: config.sseResilience?.backoffBaseDelay ?? 100,\n\t\t\tbackoffMaxDelay: config.sseResilience?.backoffMaxDelay ?? 5e3,\n\t\t\tlogWarnings: config.sseResilience?.logWarnings ?? true\n\t\t};\n\t\tthis.#encoding = config.encoding;\n\t\tthis.#closed = new Promise((resolve, reject) => {\n\t\t\tthis.#closedResolve = resolve;\n\t\t\tthis.#closedReject = reject;\n\t\t});\n\t\tthis.#responseStream = this.#createResponseStream(config.firstResponse);\n\t\tthis.#abortController.signal.addEventListener(`abort`, () => {\n\t\t\tthis.#requestAbortController?.abort(this.#abortController.signal.reason);\n\t\t\tthis.#pauseResolve?.();\n\t\t\tthis.#pausePromise = void 0;\n\t\t\tthis.#pauseResolve = void 0;\n\t\t}, { once: true });\n\t\tthis.#subscribeToVisibilityChanges();\n\t}\n\t/**\n\t* Subscribe to document visibility changes to pause/resume syncing.\n\t* When the page is hidden, we pause to save battery and bandwidth.\n\t* When visible again, we resume syncing.\n\t*/\n\t#subscribeToVisibilityChanges() {\n\t\tif (typeof document === `object` && typeof document.hidden === `boolean` && typeof document.addEventListener === `function`) {\n\t\t\tconst visibilityHandler = () => {\n\t\t\t\tif (document.hidden) this.#pause();\n\t\t\t\telse this.#resume();\n\t\t\t};\n\t\t\tdocument.addEventListener(`visibilitychange`, visibilityHandler);\n\t\t\tthis.#unsubscribeFromVisibilityChanges = () => {\n\t\t\t\tif (typeof document === `object`) document.removeEventListener(`visibilitychange`, visibilityHandler);\n\t\t\t};\n\t\t\tif (document.hidden) this.#pause();\n\t\t}\n\t}\n\t/**\n\t* Pause the stream when page becomes hidden.\n\t* Aborts any in-flight request to free resources.\n\t* Creates a promise that pull() will await while paused.\n\t*/\n\t#pause() {\n\t\tif (this.#state === `active`) {\n\t\t\tthis.#state = `pause-requested`;\n\t\t\tthis.#syncState = this.#syncState.pause();\n\t\t\tthis.#pausePromise = new Promise((resolve) => {\n\t\t\t\tthis.#pauseResolve = resolve;\n\t\t\t});\n\t\t\tthis.#requestAbortController?.abort(PAUSE_STREAM);\n\t\t}\n\t}\n\t/**\n\t* Resume the stream when page becomes visible.\n\t* Resolves the pause promise to unblock pull().\n\t*/\n\t#resume() {\n\t\tif (this.#state === `paused` || this.#state === `pause-requested`) {\n\t\t\tif (this.#abortController.signal.aborted) return;\n\t\t\tif (this.#syncState instanceof PausedState) this.#syncState = this.#syncState.resume().state;\n\t\t\tthis.#state = `active`;\n\t\t\tthis.#pauseResolve?.();\n\t\t\tthis.#pausePromise = void 0;\n\t\t\tthis.#pauseResolve = void 0;\n\t\t}\n\t}\n\tget headers() {\n\t\treturn this.#headers;\n\t}\n\tget status() {\n\t\treturn this.#status;\n\t}\n\tget statusText() {\n\t\treturn this.#statusText;\n\t}\n\tget ok() {\n\t\treturn this.#ok;\n\t}\n\tget isLoading() {\n\t\treturn this.#isLoading;\n\t}\n\tget offset() {\n\t\treturn this.#syncState.offset;\n\t}\n\tget cursor() {\n\t\treturn this.#syncState.cursor;\n\t}\n\tget upToDate() {\n\t\treturn this.#syncState.upToDate;\n\t}\n\tget streamClosed() {\n\t\treturn this.#syncState.streamClosed;\n\t}\n\t#ensureJsonMode() {\n\t\tif (!this.#isJsonMode) throw new DurableStreamError(`JSON methods are only valid for JSON-mode streams. Content-Type is \"${this.contentType}\" and json hint was not set.`, `BAD_REQUEST`);\n\t}\n\t#markClosed() {\n\t\tthis.#unsubscribeFromVisibilityChanges?.();\n\t\tthis.#closedResolve();\n\t}\n\t#markError(err) {\n\t\tthis.#unsubscribeFromVisibilityChanges?.();\n\t\tthis.#closedReject(err);\n\t}\n\t/**\n\t* Ensure only one consumption method is used per StreamResponse.\n\t* Throws if any consumption method was already called.\n\t*/\n\t#ensureNoConsumption(method) {\n\t\tif (this.#consumptionMethod !== null) throw new DurableStreamError(`Cannot call ${method}() - this StreamResponse is already being consumed via ${this.#consumptionMethod}()`, `ALREADY_CONSUMED`);\n\t\tthis.#consumptionMethod = method;\n\t}\n\t/**\n\t* Determine if we should continue with live updates based on live mode\n\t* and whether we've received upToDate or streamClosed.\n\t*/\n\t#shouldContinueLive() {\n\t\treturn this.#syncState.shouldContinueLive(this.#stopAfterUpToDate, this.live);\n\t}\n\t/**\n\t* Update state from response headers.\n\t*/\n\t#updateStateFromResponse(response) {\n\t\tthis.#syncState = this.#syncState.withResponseMetadata({\n\t\t\toffset: response.headers.get(STREAM_OFFSET_HEADER) || void 0,\n\t\t\tcursor: response.headers.get(STREAM_CURSOR_HEADER) || void 0,\n\t\t\tupToDate: response.headers.has(STREAM_UP_TO_DATE_HEADER),\n\t\t\tstreamClosed: response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`\n\t\t});\n\t\tthis.#headers = response.headers;\n\t\tthis.#status = response.status;\n\t\tthis.#statusText = response.statusText;\n\t\tthis.#ok = response.ok;\n\t}\n\t/**\n\t* Update instance state from an SSE control event.\n\t*/\n\t#updateStateFromSSEControl(controlEvent) {\n\t\tthis.#syncState = this.#syncState.withSSEControl(controlEvent);\n\t}\n\t#updateEncodingFromSSEResponse(response) {\n\t\tthis.#encoding = response.headers.get(STREAM_SSE_DATA_ENCODING_HEADER) === `base64` ? `base64` : void 0;\n\t}\n\t/**\n\t* Mark the start of an SSE connection for duration tracking.\n\t* If the state is not SSEState (e.g., auto-detected SSE from content-type),\n\t* transitions to SSEState first.\n\t*/\n\t#markSSEConnectionStart() {\n\t\tif (!(this.#syncState instanceof SSEState)) this.#syncState = new SSEState({\n\t\t\toffset: this.#syncState.offset,\n\t\t\tcursor: this.#syncState.cursor,\n\t\t\tupToDate: this.#syncState.upToDate,\n\t\t\tstreamClosed: this.#syncState.streamClosed\n\t\t});\n\t\tthis.#syncState = this.#syncState.startConnection(Date.now());\n\t}\n\t/**\n\t* Try to reconnect SSE and return the new iterator, or null if reconnection\n\t* is not possible or fails.\n\t*/\n\tasync #trySSEReconnect() {\n\t\tif (!this.#syncState.shouldUseSse()) return null;\n\t\tif (!this.#shouldContinueLive() || !this.#startSSE) return null;\n\t\tconst result = this.#syncState.handleConnectionEnd(Date.now(), this.#abortController.signal.aborted, this.#sseResilience);\n\t\tthis.#syncState = result.state;\n\t\tif (result.action === `fallback`) {\n\t\t\tif (this.#sseResilience.logWarnings) console.warn(\"[Durable Streams] SSE connections are closing immediately (possibly due to proxy buffering or misconfiguration). Falling back to long polling. Your proxy must support streaming SSE responses (not buffer the complete response). Configuration: Nginx add 'X-Accel-Buffering: no', Caddy add 'flush_interval -1' to reverse_proxy.\");\n\t\t\treturn null;\n\t\t}\n\t\tif (result.action === `reconnect`) {\n\t\t\tconst maxDelay = Math.min(this.#sseResilience.backoffMaxDelay, this.#sseResilience.backoffBaseDelay * Math.pow(2, result.backoffAttempt));\n\t\t\tconst delayMs = Math.floor(Math.random() * maxDelay);\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, delayMs));\n\t\t}\n\t\tthis.#markSSEConnectionStart();\n\t\tthis.#requestAbortController = new AbortController();\n\t\tconst newSSEResponse = await this.#startSSE(this.offset, this.cursor, this.#requestAbortController.signal);\n\t\tthis.#updateEncodingFromSSEResponse(newSSEResponse);\n\t\tif (newSSEResponse.body) return parseSSEStream(newSSEResponse.body, this.#requestAbortController.signal);\n\t\treturn null;\n\t}\n\t/**\n\t* Process SSE events from the iterator.\n\t* Returns an object indicating the result:\n\t* - { type: 'response', response, newIterator? } - yield this response\n\t* - { type: 'closed' } - stream should be closed\n\t* - { type: 'error', error } - an error occurred\n\t* - { type: 'continue', newIterator? } - continue processing (control-only event)\n\t*/\n\tasync #processSSEEvents(sseEventIterator) {\n\t\tconst { done, value: event } = await sseEventIterator.next();\n\t\tif (done) {\n\t\t\ttry {\n\t\t\t\tconst newIterator = await this.#trySSEReconnect();\n\t\t\t\tif (newIterator) return {\n\t\t\t\t\ttype: `continue`,\n\t\t\t\t\tnewIterator\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: `error`,\n\t\t\t\t\terror: err instanceof Error ? err : /* @__PURE__ */ new Error(`SSE reconnection failed`)\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { type: `closed` };\n\t\t}\n\t\tif (event.type === `data`) return this.#processSSEDataEvent(event.data, sseEventIterator);\n\t\tthis.#updateStateFromSSEControl(event);\n\t\tif (event.upToDate) return {\n\t\t\ttype: `response`,\n\t\t\tresponse: createSSESyntheticResponse(``, event.streamNextOffset, event.streamCursor, true, event.streamClosed ?? false, this.contentType, this.#encoding)\n\t\t};\n\t\treturn { type: `continue` };\n\t}\n\t/**\n\t* Process an SSE data event by waiting for its corresponding control event.\n\t* In SSE protocol, control events come AFTER data events.\n\t* Multiple data events may arrive before a single control event - we buffer them.\n\t*\n\t* For base64 mode, each data event is independently base64 encoded, so we\n\t* collect them as an array and decode each separately.\n\t*/\n\tasync #processSSEDataEvent(pendingData, sseEventIterator) {\n\t\tconst bufferedDataParts = [pendingData];\n\t\twhile (true) {\n\t\t\tconst { done: controlDone, value: controlEvent } = await sseEventIterator.next();\n\t\t\tif (controlDone) {\n\t\t\t\tconst response = createSSESyntheticResponseFromParts(bufferedDataParts, this.offset, this.cursor, this.upToDate, this.streamClosed, this.contentType, this.#encoding, this.#isJsonMode);\n\t\t\t\ttry {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: `response`,\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\tnewIterator: await this.#trySSEReconnect() ?? void 0\n\t\t\t\t\t};\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: `error`,\n\t\t\t\t\t\terror: err instanceof Error ? err : /* @__PURE__ */ new Error(`SSE reconnection failed`)\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (controlEvent.type === `control`) {\n\t\t\t\tthis.#updateStateFromSSEControl(controlEvent);\n\t\t\t\treturn {\n\t\t\t\t\ttype: `response`,\n\t\t\t\t\tresponse: createSSESyntheticResponseFromParts(bufferedDataParts, controlEvent.streamNextOffset, controlEvent.streamCursor, controlEvent.upToDate ?? false, controlEvent.streamClosed ?? false, this.contentType, this.#encoding, this.#isJsonMode)\n\t\t\t\t};\n\t\t\t}\n\t\t\tbufferedDataParts.push(controlEvent.data);\n\t\t}\n\t}\n\t/**\n\t* Create the core ReadableStream<Response> that yields responses.\n\t* This is consumed once - all consumption methods use this same stream.\n\t*\n\t* For long-poll mode: yields actual Response objects.\n\t* For SSE mode: yields synthetic Response objects created from SSE data events.\n\t*/\n\t#createResponseStream(firstResponse) {\n\t\tlet firstResponseYielded = false;\n\t\tlet sseEventIterator = null;\n\t\treturn new ReadableStream({\n\t\t\tpull: async (controller) => {\n\t\t\t\ttry {\n\t\t\t\t\tif (!firstResponseYielded) {\n\t\t\t\t\t\tfirstResponseYielded = true;\n\t\t\t\t\t\tif ((firstResponse.headers.get(`content-type`)?.includes(`text/event-stream`) ?? false) && firstResponse.body) {\n\t\t\t\t\t\t\tthis.#markSSEConnectionStart();\n\t\t\t\t\t\t\tthis.#updateEncodingFromSSEResponse(firstResponse);\n\t\t\t\t\t\t\tthis.#requestAbortController = new AbortController();\n\t\t\t\t\t\t\tsseEventIterator = parseSSEStream(firstResponse.body, this.#requestAbortController.signal);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontroller.enqueue(firstResponse);\n\t\t\t\t\t\t\tif (this.upToDate && !this.#shouldContinueLive()) {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!sseEventIterator && this.upToDate && this.#startSSE && this.#shouldContinueLive()) {\n\t\t\t\t\t\tif (this.#state === `pause-requested` || this.#state === `paused`) {\n\t\t\t\t\t\t\tthis.#state = `paused`;\n\t\t\t\t\t\t\tif (this.#pausePromise) await this.#pausePromise;\n\t\t\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.#markSSEConnectionStart();\n\t\t\t\t\t\tthis.#requestAbortController = new AbortController();\n\t\t\t\t\t\tconst sseResponse = await this.#startSSE(this.offset, this.cursor, this.#requestAbortController.signal);\n\t\t\t\t\t\tthis.#updateEncodingFromSSEResponse(sseResponse);\n\t\t\t\t\t\tif (sseResponse.body) sseEventIterator = parseSSEStream(sseResponse.body, this.#requestAbortController.signal);\n\t\t\t\t\t}\n\t\t\t\t\tif (sseEventIterator) {\n\t\t\t\t\t\tif (this.#state === `pause-requested` || this.#state === `paused`) {\n\t\t\t\t\t\t\tthis.#state = `paused`;\n\t\t\t\t\t\t\tif (this.#pausePromise) await this.#pausePromise;\n\t\t\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst newIterator = await this.#trySSEReconnect();\n\t\t\t\t\t\t\tif (newIterator) sseEventIterator = newIterator;\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true) {\n\t\t\t\t\t\t\tconst result = await this.#processSSEEvents(sseEventIterator);\n\t\t\t\t\t\t\tswitch (result.type) {\n\t\t\t\t\t\t\t\tcase `response`:\n\t\t\t\t\t\t\t\t\tif (result.newIterator) sseEventIterator = result.newIterator;\n\t\t\t\t\t\t\t\t\tcontroller.enqueue(result.response);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tcase `closed`:\n\t\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tcase `error`:\n\t\t\t\t\t\t\t\t\tthis.#markError(result.error);\n\t\t\t\t\t\t\t\t\tcontroller.error(result.error);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tcase `continue`:\n\t\t\t\t\t\t\t\t\tif (result.newIterator) sseEventIterator = result.newIterator;\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (this.#shouldContinueLive()) {\n\t\t\t\t\t\tlet resumingFromPause = false;\n\t\t\t\t\t\tif (this.#state === `pause-requested` || this.#state === `paused`) {\n\t\t\t\t\t\t\tthis.#state = `paused`;\n\t\t\t\t\t\t\tif (this.#pausePromise) await this.#pausePromise;\n\t\t\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresumingFromPause = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.#requestAbortController = new AbortController();\n\t\t\t\t\t\tconst response = await this.#fetchNext(this.offset, this.cursor, this.#requestAbortController.signal, this.upToDate, resumingFromPause);\n\t\t\t\t\t\tthis.#updateStateFromResponse(response);\n\t\t\t\t\t\tcontroller.enqueue(response);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\tcontroller.close();\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (this.#requestAbortController?.signal.aborted && this.#requestAbortController.signal.reason === PAUSE_STREAM) {\n\t\t\t\t\t\tif (this.#state === `pause-requested`) this.#state = `paused`;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\t\tthis.#markClosed();\n\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#markError(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t\t\tcontroller.error(err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\tthis.#abortController.abort();\n\t\t\t\tthis.#unsubscribeFromVisibilityChanges?.();\n\t\t\t\tthis.#markClosed();\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Get the response stream reader. Can only be called once.\n\t*/\n\t#getResponseReader() {\n\t\treturn this.#responseStream.getReader();\n\t}\n\tasync body() {\n\t\tthis.#ensureNoConsumption(`body`);\n\t\tthis.#stopAfterUpToDate = true;\n\t\tconst reader = this.#getResponseReader();\n\t\tconst blobs = [];\n\t\ttry {\n\t\t\tlet result = await reader.read();\n\t\t\twhile (!result.done) {\n\t\t\t\tconst wasUpToDate = this.upToDate;\n\t\t\t\tconst blob = await result.value.blob();\n\t\t\t\tif (blob.size > 0) blobs.push(blob);\n\t\t\t\tif (wasUpToDate) break;\n\t\t\t\tresult = await reader.read();\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tthis.#markClosed();\n\t\tif (blobs.length === 0) return /* @__PURE__ */ new Uint8Array(0);\n\t\tif (blobs.length === 1) return new Uint8Array(await blobs[0].arrayBuffer());\n\t\tconst combined = new Blob(blobs);\n\t\treturn new Uint8Array(await combined.arrayBuffer());\n\t}\n\tasync json() {\n\t\tthis.#ensureNoConsumption(`json`);\n\t\tthis.#ensureJsonMode();\n\t\tthis.#stopAfterUpToDate = true;\n\t\tconst reader = this.#getResponseReader();\n\t\tconst items = [];\n\t\ttry {\n\t\t\tlet result = await reader.read();\n\t\t\twhile (!result.done) {\n\t\t\t\tconst wasUpToDate = this.upToDate;\n\t\t\t\tconst content = (await result.value.text()).trim() || `[]`;\n\t\t\t\tlet parsed;\n\t\t\t\ttry {\n\t\t\t\t\tparsed = JSON.parse(content);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst preview = content.length > 100 ? content.slice(0, 100) + `...` : content;\n\t\t\t\t\tthrow new DurableStreamError(`Failed to parse JSON response: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(parsed)) items.push(...parsed);\n\t\t\t\telse items.push(parsed);\n\t\t\t\tif (wasUpToDate) break;\n\t\t\t\tresult = await reader.read();\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tthis.#markClosed();\n\t\treturn items;\n\t}\n\tasync text() {\n\t\tthis.#ensureNoConsumption(`text`);\n\t\tthis.#stopAfterUpToDate = true;\n\t\tconst reader = this.#getResponseReader();\n\t\tconst parts = [];\n\t\ttry {\n\t\t\tlet result = await reader.read();\n\t\t\twhile (!result.done) {\n\t\t\t\tconst wasUpToDate = this.upToDate;\n\t\t\t\tconst text = await result.value.text();\n\t\t\t\tif (text) parts.push(text);\n\t\t\t\tif (wasUpToDate) break;\n\t\t\t\tresult = await reader.read();\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tthis.#markClosed();\n\t\treturn parts.join(``);\n\t}\n\t/**\n\t* Internal helper to create the body stream without consumption check.\n\t* Used by both bodyStream() and textStream().\n\t*/\n\t#createBodyStreamInternal() {\n\t\tconst { readable, writable } = new TransformStream();\n\t\tconst reader = this.#getResponseReader();\n\t\tconst pipeBodyStream = async () => {\n\t\t\ttry {\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tconst wasUpToDate = this.upToDate;\n\t\t\t\t\tconst body = result.value.body;\n\t\t\t\t\tif (body) await body.pipeTo(writable, {\n\t\t\t\t\t\tpreventClose: true,\n\t\t\t\t\t\tpreventAbort: true,\n\t\t\t\t\t\tpreventCancel: true\n\t\t\t\t\t});\n\t\t\t\t\tif (wasUpToDate && !this.#shouldContinueLive()) break;\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tawait writable.close();\n\t\t\t\tthis.#markClosed();\n\t\t\t} catch (err) {\n\t\t\t\tif (this.#abortController.signal.aborted) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait writable.close();\n\t\t\t\t\t} catch {}\n\t\t\t\t\tthis.#markClosed();\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait writable.abort(err);\n\t\t\t\t\t} catch {}\n\t\t\t\t\tthis.#markError(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t};\n\t\tpipeBodyStream();\n\t\treturn readable;\n\t}\n\tbodyStream() {\n\t\tthis.#ensureNoConsumption(`bodyStream`);\n\t\treturn asAsyncIterableReadableStream(this.#createBodyStreamInternal());\n\t}\n\tjsonStream() {\n\t\tthis.#ensureNoConsumption(`jsonStream`);\n\t\tthis.#ensureJsonMode();\n\t\tconst reader = this.#getResponseReader();\n\t\tlet pendingItems = [];\n\t\treturn asAsyncIterableReadableStream(new ReadableStream({\n\t\t\tpull: async (controller) => {\n\t\t\t\tif (pendingItems.length > 0) {\n\t\t\t\t\tcontroller.enqueue(pendingItems.shift());\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tconst content = (await result.value.text()).trim() || `[]`;\n\t\t\t\t\tlet parsed;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tparsed = JSON.parse(content);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst preview = content.length > 100 ? content.slice(0, 100) + `...` : content;\n\t\t\t\t\t\tthrow new DurableStreamError(`Failed to parse JSON response: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t\t\t}\n\t\t\t\t\tpendingItems = Array.isArray(parsed) ? parsed : [parsed];\n\t\t\t\t\tif (pendingItems.length > 0) {\n\t\t\t\t\t\tcontroller.enqueue(pendingItems.shift());\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tthis.#markClosed();\n\t\t\t\tcontroller.close();\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\treader.releaseLock();\n\t\t\t\tthis.cancel();\n\t\t\t}\n\t\t}));\n\t}\n\ttextStream() {\n\t\tthis.#ensureNoConsumption(`textStream`);\n\t\tconst decoder = new TextDecoder();\n\t\treturn asAsyncIterableReadableStream(this.#createBodyStreamInternal().pipeThrough(new TransformStream({\n\t\t\ttransform(chunk, controller) {\n\t\t\t\tcontroller.enqueue(decoder.decode(chunk, { stream: true }));\n\t\t\t},\n\t\t\tflush(controller) {\n\t\t\t\tconst remaining = decoder.decode();\n\t\t\t\tif (remaining) controller.enqueue(remaining);\n\t\t\t}\n\t\t})));\n\t}\n\tsubscribeJson(subscriber) {\n\t\tthis.#ensureNoConsumption(`subscribeJson`);\n\t\tthis.#ensureJsonMode();\n\t\tconst abortController = new AbortController();\n\t\tconst reader = this.#getResponseReader();\n\t\tconst consumeJsonSubscription = async () => {\n\t\t\ttry {\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tif (abortController.signal.aborted) break;\n\t\t\t\t\tconst response = result.value;\n\t\t\t\t\tconst { offset, cursor, upToDate, streamClosed } = getMetadataFromResponse(response, this.offset, this.cursor, this.streamClosed);\n\t\t\t\t\tconst content = (await response.text()).trim() || `[]`;\n\t\t\t\t\tlet parsed;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tparsed = JSON.parse(content);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst preview = content.length > 100 ? content.slice(0, 100) + `...` : content;\n\t\t\t\t\t\tthrow new DurableStreamError(`Failed to parse JSON response: ${err instanceof Error ? err.message : String(err)}. Data: ${preview}`, `PARSE_ERROR`);\n\t\t\t\t\t}\n\t\t\t\t\tawait subscriber({\n\t\t\t\t\t\titems: Array.isArray(parsed) ? parsed : [parsed],\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\tupToDate,\n\t\t\t\t\t\tstreamClosed\n\t\t\t\t\t});\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tthis.#markClosed();\n\t\t\t} catch (e) {\n\t\t\t\tconst isAborted = abortController.signal.aborted;\n\t\t\t\tconst isBodyError = e instanceof TypeError && String(e).includes(`Body`);\n\t\t\t\tif (!isAborted && !isBodyError) this.#markError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\telse this.#markClosed();\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t};\n\t\tconsumeJsonSubscription();\n\t\treturn () => {\n\t\t\tabortController.abort();\n\t\t\tthis.cancel();\n\t\t};\n\t}\n\tsubscribeBytes(subscriber) {\n\t\tthis.#ensureNoConsumption(`subscribeBytes`);\n\t\tconst abortController = new AbortController();\n\t\tconst reader = this.#getResponseReader();\n\t\tconst consumeBytesSubscription = async () => {\n\t\t\ttry {\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tif (abortController.signal.aborted) break;\n\t\t\t\t\tconst response = result.value;\n\t\t\t\t\tconst { offset, cursor, upToDate, streamClosed } = getMetadataFromResponse(response, this.offset, this.cursor, this.streamClosed);\n\t\t\t\t\tconst buffer = await response.arrayBuffer();\n\t\t\t\t\tawait subscriber({\n\t\t\t\t\t\tdata: new Uint8Array(buffer),\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\tupToDate,\n\t\t\t\t\t\tstreamClosed\n\t\t\t\t\t});\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tthis.#markClosed();\n\t\t\t} catch (e) {\n\t\t\t\tconst isAborted = abortController.signal.aborted;\n\t\t\t\tconst isBodyError = e instanceof TypeError && String(e).includes(`Body`);\n\t\t\t\tif (!isAborted && !isBodyError) this.#markError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\telse this.#markClosed();\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t};\n\t\tconsumeBytesSubscription();\n\t\treturn () => {\n\t\t\tabortController.abort();\n\t\t\tthis.cancel();\n\t\t};\n\t}\n\tsubscribeText(subscriber) {\n\t\tthis.#ensureNoConsumption(`subscribeText`);\n\t\tconst abortController = new AbortController();\n\t\tconst reader = this.#getResponseReader();\n\t\tconst consumeTextSubscription = async () => {\n\t\t\ttry {\n\t\t\t\tlet result = await reader.read();\n\t\t\t\twhile (!result.done) {\n\t\t\t\t\tif (abortController.signal.aborted) break;\n\t\t\t\t\tconst response = result.value;\n\t\t\t\t\tconst { offset, cursor, upToDate, streamClosed } = getMetadataFromResponse(response, this.offset, this.cursor, this.streamClosed);\n\t\t\t\t\tawait subscriber({\n\t\t\t\t\t\ttext: await response.text(),\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\tupToDate,\n\t\t\t\t\t\tstreamClosed\n\t\t\t\t\t});\n\t\t\t\t\tresult = await reader.read();\n\t\t\t\t}\n\t\t\t\tthis.#markClosed();\n\t\t\t} catch (e) {\n\t\t\t\tconst isAborted = abortController.signal.aborted;\n\t\t\t\tconst isBodyError = e instanceof TypeError && String(e).includes(`Body`);\n\t\t\t\tif (!isAborted && !isBodyError) this.#markError(e instanceof Error ? e : new Error(String(e)));\n\t\t\t\telse this.#markClosed();\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t};\n\t\tconsumeTextSubscription();\n\t\treturn () => {\n\t\t\tabortController.abort();\n\t\t\tthis.cancel();\n\t\t};\n\t}\n\tcancel(reason) {\n\t\tthis.#abortController.abort(reason);\n\t\tthis.#unsubscribeFromVisibilityChanges?.();\n\t\tthis.#markClosed();\n\t}\n\tget closed() {\n\t\treturn this.#closed;\n\t}\n};\n/**\n* Extract stream metadata from Response headers.\n* Falls back to the provided defaults when headers are absent.\n*/\nfunction getMetadataFromResponse(response, fallbackOffset, fallbackCursor, fallbackStreamClosed) {\n\tconst offset = response.headers.get(STREAM_OFFSET_HEADER);\n\tconst cursor = response.headers.get(STREAM_CURSOR_HEADER);\n\tconst upToDate = response.headers.has(STREAM_UP_TO_DATE_HEADER);\n\tconst streamClosed = response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`;\n\treturn {\n\t\toffset: offset ?? fallbackOffset,\n\t\tcursor: cursor ?? fallbackCursor,\n\t\tupToDate,\n\t\tstreamClosed: streamClosed || fallbackStreamClosed\n\t};\n}\n/**\n* Decode base64 string to Uint8Array.\n* Per protocol: concatenate data lines, remove \\n and \\r, then decode.\n*/\nfunction decodeBase64(base64Str) {\n\tconst cleaned = base64Str.replace(/[\\n\\r]/g, ``);\n\tif (cleaned.length === 0) return /* @__PURE__ */ new Uint8Array(0);\n\tif (cleaned.length % 4 !== 0) throw new DurableStreamError(`Invalid base64 data: length ${cleaned.length} is not a multiple of 4`, `PARSE_ERROR`);\n\ttry {\n\t\tif (typeof Buffer !== `undefined`) return new Uint8Array(Buffer.from(cleaned, `base64`));\n\t\telse {\n\t\t\tconst binaryStr = atob(cleaned);\n\t\t\tconst bytes = new Uint8Array(binaryStr.length);\n\t\t\tfor (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);\n\t\t\treturn bytes;\n\t\t}\n\t} catch (err) {\n\t\tthrow new DurableStreamError(`Failed to decode base64 data: ${err instanceof Error ? err.message : String(err)}`, `PARSE_ERROR`);\n\t}\n}\n/**\n* Create a synthetic Response from SSE data with proper headers.\n* Includes offset/cursor/upToDate/streamClosed in headers so subscribers can read them.\n*/\nfunction createSSESyntheticResponse(data, offset, cursor, upToDate, streamClosed, contentType, encoding) {\n\treturn createSSESyntheticResponseFromParts([data], offset, cursor, upToDate, streamClosed, contentType, encoding);\n}\n/**\n* Create a synthetic Response from multiple SSE data parts.\n* For base64 mode, each part is independently encoded, so we decode each\n* separately and concatenate the binary results.\n* For text mode, parts are simply concatenated as strings.\n*/\nfunction createSSESyntheticResponseFromParts(dataParts, offset, cursor, upToDate, streamClosed, contentType, encoding, isJsonMode) {\n\tconst headers = {\n\t\t\"content-type\": contentType ?? `application/json`,\n\t\t[STREAM_OFFSET_HEADER]: String(offset)\n\t};\n\tif (cursor) headers[STREAM_CURSOR_HEADER] = cursor;\n\tif (upToDate) headers[STREAM_UP_TO_DATE_HEADER] = `true`;\n\tif (streamClosed) headers[STREAM_CLOSED_HEADER] = `true`;\n\tlet body;\n\tif (encoding === `base64`) {\n\t\tconst decodedParts = dataParts.filter((part) => part.length > 0).map((part) => decodeBase64(part));\n\t\tif (decodedParts.length === 0) body = /* @__PURE__ */ new ArrayBuffer(0);\n\t\telse if (decodedParts.length === 1) {\n\t\t\tconst decoded = decodedParts[0];\n\t\t\tbody = decoded.buffer.slice(decoded.byteOffset, decoded.byteOffset + decoded.byteLength);\n\t\t} else {\n\t\t\tconst totalLength = decodedParts.reduce((sum, part) => sum + part.length, 0);\n\t\t\tconst combined = new Uint8Array(totalLength);\n\t\t\tlet offset$1 = 0;\n\t\t\tfor (const part of decodedParts) {\n\t\t\t\tcombined.set(part, offset$1);\n\t\t\t\toffset$1 += part.length;\n\t\t\t}\n\t\t\tbody = combined.buffer;\n\t\t}\n\t} else if (isJsonMode) {\n\t\tconst mergedParts = [];\n\t\tfor (const part of dataParts) {\n\t\t\tconst trimmed = part.trim();\n\t\t\tif (trimmed.length === 0) continue;\n\t\t\tif (trimmed.startsWith(`[`) && trimmed.endsWith(`]`)) {\n\t\t\t\tconst inner = trimmed.slice(1, -1).trim();\n\t\t\t\tif (inner.length > 0) mergedParts.push(inner);\n\t\t\t} else mergedParts.push(trimmed);\n\t\t}\n\t\tbody = `[${mergedParts.join(`,`)}]`;\n\t} else body = dataParts.join(``);\n\treturn new Response(body, {\n\t\tstatus: 200,\n\t\theaders\n\t});\n}\n/**\n* Resolve headers from HeadersRecord (supports async functions).\n* Unified implementation used by both stream() and DurableStream.\n*/\nasync function resolveHeaders(headers) {\n\tconst resolved = {};\n\tif (!headers) return resolved;\n\tfor (const [key, value] of Object.entries(headers)) if (typeof value === `function`) resolved[key] = await value();\n\telse resolved[key] = value;\n\treturn resolved;\n}\n/**\n* Handle error responses from the server.\n* Throws appropriate DurableStreamError based on status code.\n*/\nasync function handleErrorResponse(response, url, context) {\n\tconst status = response.status;\n\tif (status === 404) throw new DurableStreamError(`Stream not found: ${url}`, `NOT_FOUND`, 404);\n\tif (status === 409) {\n\t\tif (response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`) throw new StreamClosedError(url, response.headers.get(STREAM_OFFSET_HEADER) ?? void 0);\n\t\tthrow new DurableStreamError(context?.operation === `create` ? `Stream already exists: ${url}` : `Sequence conflict: seq is lower than last appended`, context?.operation === `create` ? `CONFLICT_EXISTS` : `CONFLICT_SEQ`, 409);\n\t}\n\tif (status === 400) throw new DurableStreamError(`Bad request (possibly content-type mismatch)`, `BAD_REQUEST`, 400);\n\tthrow await DurableStreamError.fromResponse(response, url);\n}\n/**\n* Resolve params from ParamsRecord (supports async functions).\n*/\nasync function resolveParams(params) {\n\tconst resolved = {};\n\tif (!params) return resolved;\n\tfor (const [key, value] of Object.entries(params)) if (value !== void 0) if (typeof value === `function`) resolved[key] = await value();\n\telse resolved[key] = value;\n\treturn resolved;\n}\nconst warnedOrigins = /* @__PURE__ */ new Set();\n/**\n* Safely read NODE_ENV without triggering \"process is not defined\" errors.\n* Works in both browser and Node.js environments.\n*/\nfunction getNodeEnvSafely() {\n\tif (typeof process === `undefined`) return void 0;\n\treturn process.env?.NODE_ENV;\n}\n/**\n* Check if we're in a browser environment.\n*/\nfunction isBrowserEnvironment() {\n\treturn typeof globalThis.window !== `undefined`;\n}\n/**\n* Get window.location.href safely, returning undefined if not available.\n*/\nfunction getWindowLocationHref() {\n\tif (typeof globalThis.window !== `undefined` && typeof globalThis.window.location !== `undefined`) return globalThis.window.location.href;\n}\n/**\n* Resolve a URL string, handling relative URLs in browser environments.\n* Returns undefined if the URL cannot be parsed.\n*/\nfunction resolveUrlMaybe(urlString) {\n\ttry {\n\t\treturn new URL(urlString);\n\t} catch {\n\t\tconst base = getWindowLocationHref();\n\t\tif (base) try {\n\t\t\treturn new URL(urlString, base);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\treturn;\n\t}\n}\n/**\n* Warn if using HTTP (not HTTPS) URL in a browser environment.\n* HTTP typically limits browsers to ~6 concurrent connections per origin under HTTP/1.1,\n* which can cause slow streams and app freezes with multiple active streams.\n*\n* Features:\n* - Warns only once per origin to prevent log spam\n* - Handles relative URLs by resolving against window.location.href\n* - Safe to call in Node.js environments (no-op)\n* - Skips warning during tests (NODE_ENV=test)\n*/\nfunction warnIfUsingHttpInBrowser(url, warnOnHttp) {\n\tif (warnOnHttp === false) return;\n\tif (getNodeEnvSafely() === `test`) return;\n\tif (!isBrowserEnvironment() || typeof console === `undefined` || typeof console.warn !== `function`) return;\n\tconst parsedUrl = resolveUrlMaybe(url instanceof URL ? url.toString() : url);\n\tif (!parsedUrl) return;\n\tif (parsedUrl.protocol === `http:`) {\n\t\tif (!warnedOrigins.has(parsedUrl.origin)) {\n\t\t\twarnedOrigins.add(parsedUrl.origin);\n\t\t\tconsole.warn(\"[DurableStream] Using HTTP (not HTTPS) typically limits browsers to ~6 concurrent connections per origin under HTTP/1.1. This can cause slow streams and app freezes with multiple active streams. Use HTTPS for HTTP/2 support. See https://electric-sql.com/r/electric-http2 for more information.\");\n\t\t}\n\t}\n}\n/**\n* Create a streaming session to read from a durable stream.\n*\n* This is a fetch-like API:\n* - The promise resolves after the first network request succeeds\n* - It rejects for auth/404/other protocol errors\n* - Returns a StreamResponse for consuming the data\n*\n* @example\n* ```typescript\n* // Catch-up JSON:\n* const res = await stream<{ message: string }>({\n* url,\n* auth,\n* offset: \"0\",\n* live: false,\n* })\n* const items = await res.json()\n*\n* // Live JSON:\n* const live = await stream<{ message: string }>({\n* url,\n* auth,\n* offset: savedOffset,\n* live: true,\n* })\n* live.subscribeJson(async (batch) => {\n* for (const item of batch.items) {\n* handle(item)\n* }\n* })\n* ```\n*/\nasync function stream(options) {\n\tif (!options.url) throw new DurableStreamError(`Invalid stream options: missing required url parameter`, `BAD_REQUEST`);\n\tlet currentHeaders = options.headers;\n\tlet currentParams = options.params;\n\twhile (true) try {\n\t\treturn await streamInternal({\n\t\t\t...options,\n\t\t\theaders: currentHeaders,\n\t\t\tparams: currentParams\n\t\t});\n\t} catch (err) {\n\t\tif (options.onError) {\n\t\t\tconst retryOpts = await options.onError(err instanceof Error ? err : new Error(String(err)));\n\t\t\tif (retryOpts === void 0) throw err;\n\t\t\tif (retryOpts.params) currentParams = {\n\t\t\t\t...currentParams,\n\t\t\t\t...retryOpts.params\n\t\t\t};\n\t\t\tif (retryOpts.headers) currentHeaders = {\n\t\t\t\t...currentHeaders,\n\t\t\t\t...retryOpts.headers\n\t\t\t};\n\t\t\tcontinue;\n\t\t}\n\t\tthrow err;\n\t}\n}\n/**\n* Internal implementation of stream that doesn't handle onError retries.\n*/\nasync function streamInternal(options) {\n\tconst url = options.url instanceof URL ? options.url.toString() : options.url;\n\twarnIfUsingHttpInBrowser(url, options.warnOnHttp);\n\tconst fetchUrl = new URL(url);\n\tconst startOffset = options.offset ?? `-1`;\n\tfetchUrl.searchParams.set(OFFSET_QUERY_PARAM, startOffset);\n\tconst live = options.live ?? true;\n\tconst params = await resolveParams(options.params);\n\tfor (const [key, value] of Object.entries(params)) fetchUrl.searchParams.set(key, value);\n\tconst headers = await resolveHeaders(options.headers);\n\tconst abortController = new AbortController();\n\tif (options.signal) options.signal.addEventListener(`abort`, () => abortController.abort(options.signal?.reason), { once: true });\n\tconst fetchClient = createFetchWithBackoff(options.fetch ?? ((...args) => fetch(...args)), options.backoffOptions ?? BackoffDefaults);\n\tlet firstResponse;\n\ttry {\n\t\tfirstResponse = await fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `GET`,\n\t\t\theaders,\n\t\t\tsignal: abortController.signal\n\t\t});\n\t} catch (err) {\n\t\tif (err instanceof FetchBackoffAbortError) throw new DurableStreamError(`Stream request was aborted`, `UNKNOWN`);\n\t\tthrow err;\n\t}\n\tconst contentType = firstResponse.headers.get(`content-type`) ?? void 0;\n\tconst initialOffset = firstResponse.headers.get(STREAM_OFFSET_HEADER) ?? startOffset;\n\tconst initialCursor = firstResponse.headers.get(STREAM_CURSOR_HEADER) ?? void 0;\n\tconst initialUpToDate = firstResponse.headers.has(STREAM_UP_TO_DATE_HEADER);\n\tconst initialStreamClosed = firstResponse.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`;\n\tconst isJsonMode = options.json === true || (contentType?.includes(`application/json`) ?? false);\n\tconst encoding = firstResponse.headers.get(STREAM_SSE_DATA_ENCODING_HEADER) === `base64` ? `base64` : void 0;\n\tconst fetchNext = async (offset, cursor, signal, upToDate, resumingFromPause) => {\n\t\tconst nextUrl = new URL(url);\n\t\tnextUrl.searchParams.set(OFFSET_QUERY_PARAM, offset);\n\t\tif (upToDate && !resumingFromPause) {\n\t\t\tif (live === true || live === `long-poll`) nextUrl.searchParams.set(LIVE_QUERY_PARAM, `long-poll`);\n\t\t}\n\t\tif (cursor) nextUrl.searchParams.set(`cursor`, cursor);\n\t\tconst nextParams = await resolveParams(options.params);\n\t\tfor (const [key, value] of Object.entries(nextParams)) nextUrl.searchParams.set(key, value);\n\t\tconst nextHeaders = await resolveHeaders(options.headers);\n\t\tconst response = await fetchClient(nextUrl.toString(), {\n\t\t\tmethod: `GET`,\n\t\t\theaders: nextHeaders,\n\t\t\tsignal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, url);\n\t\treturn response;\n\t};\n\treturn new StreamResponseImpl({\n\t\turl,\n\t\tcontentType,\n\t\tlive,\n\t\tstartOffset,\n\t\tisJsonMode,\n\t\tinitialOffset,\n\t\tinitialCursor,\n\t\tinitialUpToDate,\n\t\tinitialStreamClosed,\n\t\tfirstResponse,\n\t\tabortController,\n\t\tfetchNext,\n\t\tstartSSE: live === `sse` ? async (offset, cursor, signal) => {\n\t\t\tconst sseUrl = new URL(url);\n\t\t\tsseUrl.searchParams.set(OFFSET_QUERY_PARAM, offset);\n\t\t\tsseUrl.searchParams.set(LIVE_QUERY_PARAM, `sse`);\n\t\t\tif (cursor) sseUrl.searchParams.set(`cursor`, cursor);\n\t\t\tconst sseParams = await resolveParams(options.params);\n\t\t\tfor (const [key, value] of Object.entries(sseParams)) sseUrl.searchParams.set(key, value);\n\t\t\tconst sseHeaders = await resolveHeaders(options.headers);\n\t\t\tconst response = await fetchClient(sseUrl.toString(), {\n\t\t\t\tmethod: `GET`,\n\t\t\t\theaders: sseHeaders,\n\t\t\t\tsignal\n\t\t\t});\n\t\t\tif (!response.ok) await handleErrorResponse(response, url);\n\t\t\treturn response;\n\t\t} : void 0,\n\t\tsseResilience: options.sseResilience,\n\t\tencoding\n\t});\n}\n/**\n* Error thrown when a producer's epoch is stale (zombie fencing).\n*/\nvar StaleEpochError = class extends Error {\n\t/**\n\t* The current epoch on the server.\n\t*/\n\tcurrentEpoch;\n\tconstructor(currentEpoch) {\n\t\tsuper(`Producer epoch is stale. Current server epoch: ${currentEpoch}. Call restart() or create a new producer with a higher epoch.`);\n\t\tthis.name = `StaleEpochError`;\n\t\tthis.currentEpoch = currentEpoch;\n\t}\n};\n/**\n* Error thrown when an unrecoverable sequence gap is detected.\n*\n* With maxInFlight > 1, HTTP requests can arrive out of order at the server,\n* causing temporary 409 responses. The client automatically handles these\n* by waiting for earlier sequences to complete, then retrying.\n*\n* This error is only thrown when the gap cannot be resolved (e.g., the\n* expected sequence is >= our sequence, indicating a true protocol violation).\n*/\nvar SequenceGapError = class extends Error {\n\texpectedSeq;\n\treceivedSeq;\n\tconstructor(expectedSeq, receivedSeq) {\n\t\tsuper(`Producer sequence gap: expected ${expectedSeq}, received ${receivedSeq}`);\n\t\tthis.name = `SequenceGapError`;\n\t\tthis.expectedSeq = expectedSeq;\n\t\tthis.receivedSeq = receivedSeq;\n\t}\n};\n/**\n* Normalize content-type by extracting the media type (before any semicolon).\n*/\nfunction normalizeContentType$1(contentType) {\n\tif (!contentType) return ``;\n\treturn contentType.split(`;`)[0].trim().toLowerCase();\n}\n/**\n* An idempotent producer for exactly-once writes to a durable stream.\n*\n* Features:\n* - Fire-and-forget: append() returns immediately, batches in background\n* - Exactly-once: server deduplicates using (producerId, epoch, seq)\n* - Batching: multiple appends batched into single HTTP request\n* - Pipelining: up to maxInFlight concurrent batches\n* - Zombie fencing: stale producers rejected via epoch validation\n*\n* @example\n* ```typescript\n* const stream = new DurableStream({ url: \"https://...\" });\n* const producer = new IdempotentProducer(stream, \"order-service-1\", {\n* epoch: 0,\n* autoClaim: true,\n* });\n*\n* // Fire-and-forget writes (synchronous, returns immediately)\n* producer.append(\"message 1\");\n* producer.append(\"message 2\");\n*\n* // Ensure all messages are delivered before shutdown\n* await producer.flush();\n* await producer.close();\n* ```\n*/\nvar IdempotentProducer = class {\n\t#stream;\n\t#producerId;\n\t#epoch;\n\t#nextSeq = 0;\n\t#autoClaim;\n\t#maxBatchBytes;\n\t#lingerMs;\n\t#fetchClient;\n\t#headers;\n\t#signal;\n\t#onError;\n\t#pendingBatch = [];\n\t#batchBytes = 0;\n\t#lingerTimeout = null;\n\t#queue;\n\t#maxInFlight;\n\t#deferredEnqueues = /* @__PURE__ */ new Set();\n\t#closed = false;\n\t#closeResult = null;\n\t#pendingFinalMessage;\n\t#lastSuccessfulOffset;\n\t#epochClaimed;\n\t#seqState = /* @__PURE__ */ new Map();\n\t/**\n\t* Create an idempotent producer for a stream.\n\t*\n\t* @param stream - The DurableStream to write to\n\t* @param producerId - Stable identifier for this producer (e.g., \"order-service-1\")\n\t* @param opts - Producer options\n\t*/\n\tconstructor(stream$1, producerId, opts) {\n\t\tconst epoch = opts?.epoch ?? 0;\n\t\tconst maxBatchBytes = opts?.maxBatchBytes ?? 1024 * 1024;\n\t\tconst maxInFlight = opts?.maxInFlight ?? 5;\n\t\tconst lingerMs = opts?.lingerMs ?? 5;\n\t\tif (epoch < 0) throw new Error(`epoch must be >= 0`);\n\t\tif (maxBatchBytes <= 0) throw new Error(`maxBatchBytes must be > 0`);\n\t\tif (maxInFlight <= 0) throw new Error(`maxInFlight must be > 0`);\n\t\tif (lingerMs < 0) throw new Error(`lingerMs must be >= 0`);\n\t\tthis.#stream = stream$1;\n\t\tthis.#producerId = producerId;\n\t\tthis.#epoch = epoch;\n\t\tthis.#autoClaim = opts?.autoClaim ?? false;\n\t\tthis.#maxBatchBytes = maxBatchBytes;\n\t\tthis.#lingerMs = lingerMs;\n\t\tthis.#signal = opts?.signal;\n\t\tthis.#headers = opts?.headers;\n\t\tthis.#onError = opts?.onError;\n\t\tthis.#fetchClient = opts?.fetch ?? ((...args) => fetch(...args));\n\t\tthis.#maxInFlight = maxInFlight;\n\t\tthis.#epochClaimed = !this.#autoClaim;\n\t\tthis.#queue = import_queue.default.promise(this.#batchWorker.bind(this), this.#maxInFlight);\n\t\tif (this.#signal) this.#signal.addEventListener(`abort`, () => {\n\t\t\tthis.#rejectPendingBatch(new DurableStreamError(`Producer aborted`, `ALREADY_CLOSED`, void 0, void 0));\n\t\t}, { once: true });\n\t}\n\t/**\n\t* Append data to the stream.\n\t*\n\t* This is fire-and-forget: returns immediately after adding to the batch.\n\t* The message is batched and sent when:\n\t* - maxBatchBytes is reached\n\t* - lingerMs elapses\n\t* - flush() is called\n\t*\n\t* Errors are reported via onError callback if configured. Use flush() to\n\t* wait for all pending messages to be sent.\n\t*\n\t* For JSON streams, pass pre-serialized JSON strings.\n\t* For byte streams, pass string or Uint8Array.\n\t*\n\t* @param body - Data to append (string or Uint8Array)\n\t*\n\t* @example\n\t* ```typescript\n\t* // JSON stream\n\t* producer.append(JSON.stringify({ message: \"hello\" }));\n\t*\n\t* // Byte stream\n\t* producer.append(\"raw text data\");\n\t* producer.append(new Uint8Array([1, 2, 3]));\n\t* ```\n\t*/\n\tappend(body) {\n\t\tif (this.#closed) throw new DurableStreamError(`Producer is closed`, `ALREADY_CLOSED`, void 0, void 0);\n\t\tlet bytes;\n\t\tif (typeof body === `string`) bytes = new TextEncoder().encode(body);\n\t\telse if (body instanceof Uint8Array) bytes = body;\n\t\telse throw new DurableStreamError(`append() requires string or Uint8Array. For objects, use JSON.stringify().`, `BAD_REQUEST`, 400, void 0);\n\t\tthis.#pendingBatch.push({ body: bytes });\n\t\tthis.#batchBytes += bytes.length;\n\t\tif (this.#batchBytes >= this.#maxBatchBytes) this.#enqueuePendingBatch();\n\t\telse if (!this.#lingerTimeout) this.#lingerTimeout = setTimeout(() => {\n\t\t\tthis.#lingerTimeout = null;\n\t\t\tif (this.#pendingBatch.length > 0) this.#enqueuePendingBatch();\n\t\t}, this.#lingerMs);\n\t}\n\t/**\n\t* Send any pending batch immediately and wait for all in-flight batches.\n\t*\n\t* Call this before shutdown to ensure all messages are delivered.\n\t*/\n\tasync flush() {\n\t\tif (this.#lingerTimeout) {\n\t\t\tclearTimeout(this.#lingerTimeout);\n\t\t\tthis.#lingerTimeout = null;\n\t\t}\n\t\tif (this.#pendingBatch.length > 0) this.#enqueuePendingBatch();\n\t\tdo {\n\t\t\tawait this.#queue.drained();\n\t\t\tawait Promise.all(this.#deferredEnqueues);\n\t\t} while (this.#deferredEnqueues.size > 0 || this.inFlightCount > 0);\n\t}\n\t/**\n\t* Stop the producer without closing the underlying stream.\n\t*\n\t* Use this when you want to:\n\t* - Hand off writing to another producer\n\t* - Keep the stream open for future writes\n\t* - Stop this producer but not signal EOF to readers\n\t*\n\t* Flushes any pending messages before detaching.\n\t* After calling detach(), further append() calls will throw.\n\t*/\n\tasync detach() {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\ttry {\n\t\t\tawait this.flush();\n\t\t} catch {}\n\t}\n\t/**\n\t* Flush pending messages and close the underlying stream (EOF).\n\t*\n\t* This is the typical way to end a producer session. It:\n\t* 1. Flushes all pending messages\n\t* 2. Optionally appends a final message\n\t* 3. Closes the stream (no further appends permitted)\n\t*\n\t* **Idempotent**: Unlike `DurableStream.close({ body })`, this method is\n\t* idempotent even with a final message because it uses producer headers\n\t* for deduplication. Safe to retry on network failures.\n\t*\n\t* @param finalMessage - Optional final message to append atomically with close\n\t* @returns CloseResult with the final offset\n\t*/\n\tasync close(finalMessage) {\n\t\tif (this.#closed) {\n\t\t\tif (this.#closeResult) return this.#closeResult;\n\t\t\tawait this.flush();\n\t\t\tconst result$1 = await this.#doClose(this.#pendingFinalMessage);\n\t\t\tthis.#closeResult = result$1;\n\t\t\treturn result$1;\n\t\t}\n\t\tthis.#closed = true;\n\t\tthis.#pendingFinalMessage = finalMessage;\n\t\tawait this.flush();\n\t\tconst result = await this.#doClose(finalMessage);\n\t\tthis.#closeResult = result;\n\t\treturn result;\n\t}\n\t/**\n\t* Actually close the stream with optional final message.\n\t* Uses producer headers for idempotency.\n\t*/\n\tasync #doClose(finalMessage) {\n\t\tconst contentType = this.#stream.contentType ?? `application/octet-stream`;\n\t\tconst isJson = normalizeContentType$1(contentType) === `application/json`;\n\t\tlet body;\n\t\tif (finalMessage !== void 0) {\n\t\t\tconst bodyBytes = typeof finalMessage === `string` ? new TextEncoder().encode(finalMessage) : finalMessage;\n\t\t\tif (isJson) body = `[${new TextDecoder().decode(bodyBytes)}]`;\n\t\t\telse body = bodyBytes;\n\t\t}\n\t\tconst seqForThisRequest = this.#nextSeq;\n\t\tconst headers = await this.#buildHeaders({\n\t\t\t\"content-type\": contentType,\n\t\t\t[PRODUCER_ID_HEADER]: this.#producerId,\n\t\t\t[PRODUCER_EPOCH_HEADER]: this.#epoch.toString(),\n\t\t\t[PRODUCER_SEQ_HEADER]: seqForThisRequest.toString(),\n\t\t\t[STREAM_CLOSED_HEADER]: `true`\n\t\t});\n\t\tconst response = await this.#fetchClient(this.#stream.url, {\n\t\t\tmethod: `POST`,\n\t\t\theaders,\n\t\t\tbody,\n\t\t\tsignal: this.#signal\n\t\t});\n\t\tif (response.status === 204) {\n\t\t\tthis.#nextSeq = seqForThisRequest + 1;\n\t\t\tconst finalOffset = response.headers.get(STREAM_OFFSET_HEADER) ?? ``;\n\t\t\tthis.#recordSuccessfulOffset(finalOffset);\n\t\t\treturn { finalOffset };\n\t\t}\n\t\tif (response.status === 200) {\n\t\t\tthis.#nextSeq = seqForThisRequest + 1;\n\t\t\tconst finalOffset = response.headers.get(STREAM_OFFSET_HEADER) ?? ``;\n\t\t\tthis.#recordSuccessfulOffset(finalOffset);\n\t\t\treturn { finalOffset };\n\t\t}\n\t\tif (response.status === 403) {\n\t\t\tconst currentEpochStr = response.headers.get(PRODUCER_EPOCH_HEADER);\n\t\t\tconst currentEpoch = currentEpochStr ? parseInt(currentEpochStr, 10) : this.#epoch;\n\t\t\tif (this.#autoClaim) {\n\t\t\t\tconst newEpoch = currentEpoch + 1;\n\t\t\t\tthis.#epoch = newEpoch;\n\t\t\t\tthis.#nextSeq = 0;\n\t\t\t\treturn this.#doClose(finalMessage);\n\t\t\t}\n\t\t\tthrow new StaleEpochError(currentEpoch);\n\t\t}\n\t\tthrow await FetchError.fromResponse(response, this.#stream.url);\n\t}\n\t/**\n\t* Increment epoch and reset sequence.\n\t*\n\t* Call this when restarting the producer to establish a new session.\n\t* Flushes any pending messages first.\n\t*/\n\tasync restart() {\n\t\tawait this.flush();\n\t\tthis.#epoch++;\n\t\tthis.#nextSeq = 0;\n\t}\n\t/**\n\t* Current epoch for this producer.\n\t*/\n\tget epoch() {\n\t\treturn this.#epoch;\n\t}\n\t/**\n\t* Next sequence number to be assigned.\n\t*/\n\tget nextSeq() {\n\t\treturn this.#nextSeq;\n\t}\n\t/**\n\t* Number of messages in the current pending batch.\n\t*/\n\tget pendingCount() {\n\t\treturn this.#pendingBatch.length;\n\t}\n\t/**\n\t* Number of batches currently in flight.\n\t*/\n\tget inFlightCount() {\n\t\treturn this.#queue.length() + this.#queue.running();\n\t}\n\t/**\n\t* The greatest non-empty stream offset returned by a successful producer\n\t* append or close request.\n\t*/\n\tget lastSuccessfulOffset() {\n\t\treturn this.#lastSuccessfulOffset;\n\t}\n\t/**\n\t* Enqueue the current pending batch for processing.\n\t*/\n\t#enqueuePendingBatch() {\n\t\tif (this.#pendingBatch.length === 0) return;\n\t\tconst batch = this.#pendingBatch;\n\t\tthis.#pendingBatch = [];\n\t\tthis.#batchBytes = 0;\n\t\tif (this.#autoClaim && !this.#epochClaimed && this.inFlightCount > 0) {\n\t\t\tconst deferred = this.#queue.drained().then(() => {\n\t\t\t\tthis.#pushBatch(batch);\n\t\t\t}).finally(() => {\n\t\t\t\tthis.#deferredEnqueues.delete(deferred);\n\t\t\t});\n\t\t\tthis.#deferredEnqueues.add(deferred);\n\t\t\tdeferred.catch(() => {});\n\t\t} else this.#pushBatch(batch);\n\t}\n\t#pushBatch(batch) {\n\t\tconst seq = this.#nextSeq;\n\t\tthis.#nextSeq++;\n\t\tthis.#queue.push({\n\t\t\tbatch,\n\t\t\tseq\n\t\t}).catch(() => {});\n\t}\n\t/**\n\t* Batch worker - processes batches via fastq.\n\t*/\n\tasync #batchWorker(task) {\n\t\tconst { batch, seq } = task;\n\t\tconst epoch = this.#epoch;\n\t\ttry {\n\t\t\tconst result = await this.#doSendBatch(batch, seq, epoch);\n\t\t\tthis.#recordSuccessfulOffset(result.offset);\n\t\t\tif (!this.#epochClaimed) this.#epochClaimed = true;\n\t\t\tthis.#signalSeqComplete(epoch, seq, void 0);\n\t\t} catch (error) {\n\t\t\tthis.#signalSeqComplete(epoch, seq, error);\n\t\t\tif (this.#onError) this.#onError(error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\t#recordSuccessfulOffset(offset) {\n\t\tif (offset && (!this.#lastSuccessfulOffset || offset > this.#lastSuccessfulOffset)) this.#lastSuccessfulOffset = offset;\n\t}\n\t/**\n\t* Signal that a sequence has completed (success or failure).\n\t*/\n\t#signalSeqComplete(epoch, seq, error) {\n\t\tlet epochMap = this.#seqState.get(epoch);\n\t\tif (!epochMap) {\n\t\t\tepochMap = /* @__PURE__ */ new Map();\n\t\t\tthis.#seqState.set(epoch, epochMap);\n\t\t}\n\t\tconst state = epochMap.get(seq);\n\t\tif (state) {\n\t\t\tstate.resolved = true;\n\t\t\tstate.error = error;\n\t\t\tfor (const waiter of state.waiters) waiter(error);\n\t\t\tstate.waiters = [];\n\t\t} else epochMap.set(seq, {\n\t\t\tresolved: true,\n\t\t\terror,\n\t\t\twaiters: []\n\t\t});\n\t\tconst cleanupThreshold = seq - this.#maxInFlight * 3;\n\t\tif (cleanupThreshold > 0) {\n\t\t\tfor (const oldSeq of epochMap.keys()) if (oldSeq < cleanupThreshold) epochMap.delete(oldSeq);\n\t\t}\n\t}\n\t/**\n\t* Wait for a specific sequence to complete.\n\t* Returns immediately if already completed.\n\t* Throws if the sequence failed.\n\t*/\n\t#waitForSeq(epoch, seq) {\n\t\tlet epochMap = this.#seqState.get(epoch);\n\t\tif (!epochMap) {\n\t\t\tepochMap = /* @__PURE__ */ new Map();\n\t\t\tthis.#seqState.set(epoch, epochMap);\n\t\t}\n\t\tconst state = epochMap.get(seq);\n\t\tif (state?.resolved) {\n\t\t\tif (state.error) return Promise.reject(state.error);\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst waiter = (err) => {\n\t\t\t\tif (err) reject(err);\n\t\t\t\telse resolve();\n\t\t\t};\n\t\t\tif (state) state.waiters.push(waiter);\n\t\t\telse epochMap.set(seq, {\n\t\t\t\tresolved: false,\n\t\t\t\twaiters: [waiter]\n\t\t\t});\n\t\t});\n\t}\n\t/**\n\t* Actually send the batch to the server.\n\t* Handles auto-claim retry on 403 (stale epoch) if autoClaim is enabled.\n\t* Does NOT implement general retry/backoff for network errors or 5xx responses.\n\t*/\n\tasync #doSendBatch(batch, seq, epoch) {\n\t\tconst contentType = this.#stream.contentType ?? `application/octet-stream`;\n\t\tconst isJson = normalizeContentType$1(contentType) === `application/json`;\n\t\tlet batchedBody;\n\t\tif (isJson) batchedBody = `[${batch.map((e) => new TextDecoder().decode(e.body)).join(`,`)}]`;\n\t\telse {\n\t\t\tconst totalSize = batch.reduce((sum, e) => sum + e.body.length, 0);\n\t\t\tconst concatenated = new Uint8Array(totalSize);\n\t\t\tlet offset = 0;\n\t\t\tfor (const entry of batch) {\n\t\t\t\tconcatenated.set(entry.body, offset);\n\t\t\t\toffset += entry.body.length;\n\t\t\t}\n\t\t\tbatchedBody = concatenated;\n\t\t}\n\t\tconst url = this.#stream.url;\n\t\tconst headers = await this.#buildHeaders({\n\t\t\t\"content-type\": contentType,\n\t\t\t[PRODUCER_ID_HEADER]: this.#producerId,\n\t\t\t[PRODUCER_EPOCH_HEADER]: epoch.toString(),\n\t\t\t[PRODUCER_SEQ_HEADER]: seq.toString()\n\t\t});\n\t\tconst response = await this.#fetchClient(url, {\n\t\t\tmethod: `POST`,\n\t\t\theaders,\n\t\t\tbody: batchedBody,\n\t\t\tsignal: this.#signal\n\t\t});\n\t\tif (response.status === 204) return {\n\t\t\toffset: ``,\n\t\t\tduplicate: true\n\t\t};\n\t\tif (response.status === 200) return {\n\t\t\toffset: response.headers.get(STREAM_OFFSET_HEADER) ?? ``,\n\t\t\tduplicate: false\n\t\t};\n\t\tif (response.status === 403) {\n\t\t\tconst currentEpochStr = response.headers.get(PRODUCER_EPOCH_HEADER);\n\t\t\tconst currentEpoch = currentEpochStr ? parseInt(currentEpochStr, 10) : epoch;\n\t\t\tif (this.#autoClaim) {\n\t\t\t\tconst newEpoch = currentEpoch + 1;\n\t\t\t\tthis.#epoch = newEpoch;\n\t\t\t\tthis.#nextSeq = 1;\n\t\t\t\treturn this.#doSendBatch(batch, 0, newEpoch);\n\t\t\t}\n\t\t\tthrow new StaleEpochError(currentEpoch);\n\t\t}\n\t\tif (response.status === 409) {\n\t\t\tconst expectedSeqStr = response.headers.get(PRODUCER_EXPECTED_SEQ_HEADER);\n\t\t\tconst expectedSeq = expectedSeqStr ? parseInt(expectedSeqStr, 10) : 0;\n\t\t\tif (expectedSeq < seq) {\n\t\t\t\tconst waitPromises = [];\n\t\t\t\tfor (let s = expectedSeq; s < seq; s++) waitPromises.push(this.#waitForSeq(epoch, s));\n\t\t\t\tawait Promise.all(waitPromises);\n\t\t\t\treturn this.#doSendBatch(batch, seq, epoch);\n\t\t\t}\n\t\t\tconst receivedSeqStr = response.headers.get(PRODUCER_RECEIVED_SEQ_HEADER);\n\t\t\tthrow new SequenceGapError(expectedSeq, receivedSeqStr ? parseInt(receivedSeqStr, 10) : seq);\n\t\t}\n\t\tif (response.status === 400) throw await DurableStreamError.fromResponse(response, url);\n\t\tthrow await FetchError.fromResponse(response, url);\n\t}\n\tasync #buildHeaders(protocolHeaders) {\n\t\tconst streamHeaders = await this.#stream.resolveHeaders();\n\t\tconst producerHeaders = await resolveHeaders(this.#headers);\n\t\treturn {\n\t\t\t...streamHeaders,\n\t\t\t...producerHeaders,\n\t\t\t...protocolHeaders\n\t\t};\n\t}\n\t/**\n\t* Clear pending batch and report error.\n\t*/\n\t#rejectPendingBatch(error) {\n\t\tif (this.#onError && this.#pendingBatch.length > 0) this.#onError(error);\n\t\tthis.#pendingBatch = [];\n\t\tthis.#batchBytes = 0;\n\t\tif (this.#lingerTimeout) {\n\t\t\tclearTimeout(this.#lingerTimeout);\n\t\t\tthis.#lingerTimeout = null;\n\t\t}\n\t}\n};\n/**\n* Normalize content-type by extracting the media type (before any semicolon).\n* Handles cases like \"application/json; charset=utf-8\".\n*/\nfunction normalizeContentType(contentType) {\n\tif (!contentType) return ``;\n\treturn contentType.split(`;`)[0].trim().toLowerCase();\n}\n/**\n* Check if a value is a Promise or Promise-like (thenable).\n*/\nfunction isPromiseLike(value) {\n\treturn value != null && typeof value.then === `function`;\n}\n/**\n* A handle to a remote durable stream for read/write operations.\n*\n* This is a lightweight, reusable handle - not a persistent connection.\n* It does not automatically start reading or listening.\n* Create sessions as needed via stream().\n*\n* @example\n* ```typescript\n* // Create a new stream\n* const stream = await DurableStream.create({\n* url: \"https://streams.example.com/my-stream\",\n* headers: { Authorization: \"Bearer my-token\" },\n* contentType: \"application/json\"\n* });\n*\n* // Single write\n* await stream.append(JSON.stringify({ message: \"hello\" }));\n*\n* // Read with the new API\n* const res = await stream.stream<{ message: string }>();\n* res.subscribeJson(async (batch) => {\n* for (const item of batch.items) {\n* console.log(item.message);\n* }\n* });\n* ```\n*/\nvar DurableStream = class DurableStream {\n\t/**\n\t* The URL of the durable stream.\n\t*/\n\turl;\n\t/**\n\t* The content type of the stream (populated after connect/head/read).\n\t*/\n\tcontentType;\n\t#options;\n\t#fetchClient;\n\t#baseFetchClient;\n\t#onError;\n\t#batchingEnabled;\n\t#queue;\n\t#buffer = [];\n\t/**\n\t* Create a cold handle to a stream.\n\t* No network IO is performed by the constructor.\n\t*/\n\tconstructor(opts) {\n\t\tvalidateOptions(opts);\n\t\tconst urlStr = opts.url instanceof URL ? opts.url.toString() : opts.url;\n\t\tthis.url = urlStr;\n\t\tthis.#options = {\n\t\t\t...opts,\n\t\t\turl: urlStr\n\t\t};\n\t\tthis.#onError = opts.onError;\n\t\tif (opts.contentType) this.contentType = opts.contentType;\n\t\tthis.#batchingEnabled = opts.batching !== false;\n\t\tif (this.#batchingEnabled) this.#queue = import_queue.default.promise(this.#batchWorker.bind(this), 1);\n\t\tthis.#baseFetchClient = opts.fetch ?? ((...args) => fetch(...args));\n\t\tconst backOffOpts = { ...opts.backoffOptions ?? BackoffDefaults };\n\t\tconst fetchWithBackoffClient = createFetchWithBackoff(this.#baseFetchClient, backOffOpts);\n\t\tthis.#fetchClient = createFetchWithConsumedBody(fetchWithBackoffClient);\n\t}\n\t/**\n\t* Create a new stream (create-only PUT) and return a handle.\n\t* Fails with DurableStreamError(code=\"CONFLICT_EXISTS\") if it already exists.\n\t*/\n\tstatic async create(opts) {\n\t\tconst stream$1 = new DurableStream(opts);\n\t\tawait stream$1.create({\n\t\t\tcontentType: opts.contentType,\n\t\t\tttlSeconds: opts.ttlSeconds,\n\t\t\texpiresAt: opts.expiresAt,\n\t\t\tbody: opts.body,\n\t\t\tclosed: opts.closed\n\t\t});\n\t\treturn stream$1;\n\t}\n\t/**\n\t* Validate that a stream exists and fetch metadata via HEAD.\n\t* Returns a handle with contentType populated (if sent by server).\n\t*\n\t* **Important**: This only performs a HEAD request for validation - it does\n\t* NOT open a session or start reading data. To read from the stream, call\n\t* `stream()` on the returned handle.\n\t*\n\t* @example\n\t* ```typescript\n\t* // Validate stream exists before reading\n\t* const handle = await DurableStream.connect({ url })\n\t* const res = await handle.stream() // Now actually read\n\t* ```\n\t*/\n\tstatic async connect(opts) {\n\t\tconst stream$1 = new DurableStream(opts);\n\t\tawait stream$1.head();\n\t\treturn stream$1;\n\t}\n\t/**\n\t* HEAD metadata for a stream without creating a handle.\n\t*/\n\tstatic async head(opts) {\n\t\treturn new DurableStream(opts).head();\n\t}\n\t/**\n\t* Delete a stream without creating a handle.\n\t*/\n\tstatic async delete(opts) {\n\t\treturn new DurableStream(opts).delete();\n\t}\n\t/**\n\t* HEAD metadata for this stream.\n\t*/\n\tasync head(opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst response = await this.#baseFetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `HEAD`,\n\t\t\theaders: requestHeaders,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tif (response.status === 404) return { exists: false };\n\t\t\tawait handleErrorResponse(response, this.url);\n\t\t}\n\t\tconst contentType = response.headers.get(`content-type`) ?? void 0;\n\t\tconst offset = response.headers.get(STREAM_OFFSET_HEADER) ?? void 0;\n\t\tconst etag = response.headers.get(`etag`) ?? void 0;\n\t\tconst cacheControl = response.headers.get(`cache-control`) ?? void 0;\n\t\tconst streamClosed = response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`;\n\t\tif (contentType) this.contentType = contentType;\n\t\treturn {\n\t\t\texists: true,\n\t\t\tcontentType,\n\t\t\toffset,\n\t\t\tetag,\n\t\t\tcacheControl,\n\t\t\tstreamClosed\n\t\t};\n\t}\n\t/**\n\t* Create this stream (create-only PUT) using the URL/auth from the handle.\n\t*/\n\tasync create(opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = opts?.contentType ?? this.#options.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\tif (opts?.ttlSeconds !== void 0) requestHeaders[STREAM_TTL_HEADER] = String(opts.ttlSeconds);\n\t\tif (opts?.expiresAt) requestHeaders[STREAM_EXPIRES_AT_HEADER] = opts.expiresAt;\n\t\tif (opts?.closed) requestHeaders[STREAM_CLOSED_HEADER] = `true`;\n\t\tconst body = encodeBody(opts?.body);\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `PUT`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody,\n\t\t\tsignal: this.#options.signal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url, { operation: `create` });\n\t\tconst responseContentType = response.headers.get(`content-type`);\n\t\tif (responseContentType) this.contentType = responseContentType;\n\t\telse if (contentType) this.contentType = contentType;\n\t\treturn this;\n\t}\n\t/**\n\t* Delete this stream.\n\t*/\n\tasync delete(opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `DELETE`,\n\t\t\theaders: requestHeaders,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t}\n\t/**\n\t* Close the stream, optionally with a final message.\n\t*\n\t* After closing:\n\t* - No further appends are permitted (server returns 409)\n\t* - Readers can observe the closed state and treat it as EOF\n\t* - The stream's data remains fully readable\n\t*\n\t* Closing is:\n\t* - **Durable**: The closed state is persisted\n\t* - **Monotonic**: Once closed, a stream cannot be reopened\n\t*\n\t* **Idempotency:**\n\t* - `close()` without body: Idempotent — safe to call multiple times\n\t* - `close({ body })` with body: NOT idempotent — throws `StreamClosedError`\n\t* if stream is already closed (use `IdempotentProducer.close()` for\n\t* idempotent close-with-body semantics)\n\t*\n\t* @returns CloseResult with the final offset\n\t* @throws StreamClosedError if called with body on an already-closed stream\n\t*/\n\tasync close(opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = opts?.contentType ?? this.#options.contentType ?? this.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\trequestHeaders[STREAM_CLOSED_HEADER] = `true`;\n\t\tlet body;\n\t\tif (opts?.body !== void 0) if (normalizeContentType(contentType) === `application/json`) body = `[${typeof opts.body === `string` ? opts.body : new TextDecoder().decode(opts.body)}]`;\n\t\telse body = typeof opts.body === `string` ? opts.body : opts.body;\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `POST`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (response.status === 409) {\n\t\t\tif (response.headers.get(STREAM_CLOSED_HEADER)?.toLowerCase() === `true`) {\n\t\t\t\tconst finalOffset$1 = response.headers.get(STREAM_OFFSET_HEADER) ?? void 0;\n\t\t\t\tthrow new StreamClosedError(this.url, finalOffset$1);\n\t\t\t}\n\t\t}\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t\treturn { finalOffset: response.headers.get(STREAM_OFFSET_HEADER) ?? `` };\n\t}\n\t/**\n\t* Append a single payload to the stream.\n\t*\n\t* Batching: when batching is enabled (default), append() calls that overlap\n\t* in time (e.g. fired without awaiting each one) are coalesced into a\n\t* single POST while a prior POST is in flight. If every call is awaited\n\t* before the next is issued, no batching happens — each call becomes its\n\t* own roundtrip. For tight loops driving an async iterable (e.g. LLM\n\t* token streams), prefer `appendStream()` / `writable()` which pipe the\n\t* source over a single POST, or fire `append()` calls without awaiting\n\t* each one and await the last promise (and `close()`) at the end.\n\t*\n\t* - `body` must be string or Uint8Array.\n\t* - For JSON streams, pass pre-serialized JSON strings.\n\t* - `body` may also be a Promise that resolves to string or Uint8Array.\n\t* - Strings are encoded as UTF-8.\n\t* - `seq` (if provided) is sent as stream-seq (writer coordination).\n\t*\n\t* @example\n\t* ```typescript\n\t* // JSON stream - pass pre-serialized JSON (single write)\n\t* await stream.append(JSON.stringify({ message: \"hello\" }));\n\t*\n\t* // Byte stream\n\t* await stream.append(\"raw text data\");\n\t* await stream.append(new Uint8Array([1, 2, 3]));\n\t*\n\t* // Promise value - awaited before buffering\n\t* await stream.append(fetchData());\n\t*\n\t* // High-frequency writes from an async iterable - fire-and-track-last\n\t* let last: Promise<void> = Promise.resolve();\n\t* for await (const chunk of source) {\n\t* last = stream.append(JSON.stringify(chunk));\n\t* }\n\t* await last;\n\t* await stream.close();\n\t* ```\n\t*/\n\tasync append(body, opts) {\n\t\tconst resolvedBody = isPromiseLike(body) ? await body : body;\n\t\tif (this.#batchingEnabled && this.#queue) return this.#appendWithBatching(resolvedBody, opts);\n\t\treturn this.#appendDirect(resolvedBody, opts);\n\t}\n\t/**\n\t* Direct append without batching (used when batching is disabled).\n\t*/\n\tasync #appendDirect(body, opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = opts?.contentType ?? this.#options.contentType ?? this.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\tif (opts?.seq) requestHeaders[STREAM_SEQ_HEADER] = opts.seq;\n\t\tconst isJson = normalizeContentType(contentType) === `application/json`;\n\t\tlet encodedBody;\n\t\tif (isJson) encodedBody = `[${typeof body === `string` ? body : new TextDecoder().decode(body)}]`;\n\t\telse if (typeof body === `string`) encodedBody = body;\n\t\telse encodedBody = body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength);\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `POST`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody: encodedBody,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t}\n\t/**\n\t* Append with batching - buffers messages and sends them in batches.\n\t*/\n\tasync #appendWithBatching(body, opts) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.#buffer.push({\n\t\t\t\tdata: body,\n\t\t\t\tseq: opts?.seq,\n\t\t\t\tcontentType: opts?.contentType,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tresolve,\n\t\t\t\treject\n\t\t\t});\n\t\t\tif (this.#queue.idle()) {\n\t\t\t\tconst batch = this.#buffer.splice(0);\n\t\t\t\tthis.#queue.push(batch).catch((err) => {\n\t\t\t\t\tfor (const msg of batch) msg.reject(err);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Batch worker - processes batches of messages.\n\t*/\n\tasync #batchWorker(batch) {\n\t\ttry {\n\t\t\tawait this.#sendBatch(batch);\n\t\t\tfor (const msg of batch) msg.resolve();\n\t\t\tif (this.#buffer.length > 0) {\n\t\t\t\tconst nextBatch = this.#buffer.splice(0);\n\t\t\t\tthis.#queue.push(nextBatch).catch((err) => {\n\t\t\t\t\tfor (const msg of nextBatch) msg.reject(err);\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfor (const msg of batch) msg.reject(error);\n\t\t\tfor (const msg of this.#buffer) msg.reject(error);\n\t\t\tthis.#buffer = [];\n\t\t\tthrow error;\n\t\t}\n\t}\n\t/**\n\t* Send a batch of messages as a single POST request.\n\t*/\n\tasync #sendBatch(batch) {\n\t\tif (batch.length === 0) return;\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = batch[0]?.contentType ?? this.#options.contentType ?? this.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\tlet highestSeq;\n\t\tfor (let i = batch.length - 1; i >= 0; i--) if (batch[i].seq !== void 0) {\n\t\t\thighestSeq = batch[i].seq;\n\t\t\tbreak;\n\t\t}\n\t\tif (highestSeq) requestHeaders[STREAM_SEQ_HEADER] = highestSeq;\n\t\tconst isJson = normalizeContentType(contentType) === `application/json`;\n\t\tlet batchedBody;\n\t\tif (isJson) batchedBody = `[${batch.map((m) => typeof m.data === `string` ? m.data : new TextDecoder().decode(m.data)).join(`,`)}]`;\n\t\telse {\n\t\t\tconst hasUint8Array = batch.some((m) => m.data instanceof Uint8Array);\n\t\t\tconst hasString = batch.some((m) => typeof m.data === `string`);\n\t\t\tif (hasUint8Array && !hasString) {\n\t\t\t\tconst chunks = batch.map((m) => m.data);\n\t\t\t\tconst totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n\t\t\t\tconst combined = new Uint8Array(totalLength);\n\t\t\t\tlet offset = 0;\n\t\t\t\tfor (const chunk of chunks) {\n\t\t\t\t\tcombined.set(chunk, offset);\n\t\t\t\t\toffset += chunk.length;\n\t\t\t\t}\n\t\t\t\tbatchedBody = combined;\n\t\t\t} else if (hasString && !hasUint8Array) batchedBody = batch.map((m) => m.data).join(``);\n\t\t\telse {\n\t\t\t\tconst encoder = new TextEncoder();\n\t\t\t\tconst chunks = batch.map((m) => typeof m.data === `string` ? encoder.encode(m.data) : m.data);\n\t\t\t\tconst totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n\t\t\t\tconst combined = new Uint8Array(totalLength);\n\t\t\t\tlet offset = 0;\n\t\t\t\tfor (const chunk of chunks) {\n\t\t\t\t\tcombined.set(chunk, offset);\n\t\t\t\t\toffset += chunk.length;\n\t\t\t\t}\n\t\t\t\tbatchedBody = combined;\n\t\t\t}\n\t\t}\n\t\tconst signals = [];\n\t\tif (this.#options.signal) signals.push(this.#options.signal);\n\t\tfor (const msg of batch) if (msg.signal) signals.push(msg.signal);\n\t\tconst combinedSignal = signals.length > 0 ? AbortSignal.any(signals) : void 0;\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `POST`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody: batchedBody,\n\t\t\tsignal: combinedSignal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t}\n\t/**\n\t* Append a streaming body to the stream.\n\t*\n\t* Supports piping from any ReadableStream or async iterable:\n\t* - `source` yields Uint8Array or string chunks.\n\t* - Strings are encoded as UTF-8; no delimiters are added.\n\t* - Internally uses chunked transfer or HTTP/2 streaming.\n\t*\n\t* @example\n\t* ```typescript\n\t* // Pipe from a ReadableStream\n\t* const readable = new ReadableStream({\n\t* start(controller) {\n\t* controller.enqueue(\"chunk 1\");\n\t* controller.enqueue(\"chunk 2\");\n\t* controller.close();\n\t* }\n\t* });\n\t* await stream.appendStream(readable);\n\t*\n\t* // Pipe from an async generator\n\t* async function* generate() {\n\t* yield \"line 1\\n\";\n\t* yield \"line 2\\n\";\n\t* }\n\t* await stream.appendStream(generate());\n\t*\n\t* // Pipe from fetch response body\n\t* const response = await fetch(\"https://example.com/data\");\n\t* await stream.appendStream(response.body!);\n\t* ```\n\t*/\n\tasync appendStream(source, opts) {\n\t\tconst { requestHeaders, fetchUrl } = await this.#buildRequest();\n\t\tconst contentType = opts?.contentType ?? this.#options.contentType ?? this.contentType;\n\t\tif (contentType) requestHeaders[`content-type`] = contentType;\n\t\tif (opts?.seq) requestHeaders[STREAM_SEQ_HEADER] = opts.seq;\n\t\tconst body = toReadableStream(source);\n\t\tconst response = await this.#fetchClient(fetchUrl.toString(), {\n\t\t\tmethod: `POST`,\n\t\t\theaders: requestHeaders,\n\t\t\tbody,\n\t\t\tduplex: `half`,\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\tif (!response.ok) await handleErrorResponse(response, this.url);\n\t}\n\t/**\n\t* Create a writable stream that pipes data to this durable stream.\n\t*\n\t* Returns a WritableStream that can be used with `pipeTo()` or\n\t* `pipeThrough()` from any ReadableStream source.\n\t*\n\t* Uses IdempotentProducer internally for:\n\t* - Automatic batching (controlled by lingerMs, maxBatchBytes)\n\t* - Exactly-once delivery semantics\n\t* - Streaming writes (doesn't buffer entire content in memory)\n\t*\n\t* @example\n\t* ```typescript\n\t* // Pipe from fetch response\n\t* const response = await fetch(\"https://example.com/data\");\n\t* await response.body!.pipeTo(stream.writable());\n\t*\n\t* // Pipe through a transform\n\t* const readable = someStream.pipeThrough(new TextEncoderStream());\n\t* await readable.pipeTo(stream.writable());\n\t*\n\t* // With custom producer options\n\t* await source.pipeTo(stream.writable({\n\t* producerId: \"my-producer\",\n\t* lingerMs: 10,\n\t* maxBatchBytes: 64 * 1024,\n\t* }));\n\t* ```\n\t*/\n\twritable(opts) {\n\t\tconst producerId = opts?.producerId ?? `writable-${crypto.randomUUID().slice(0, 8)}`;\n\t\tlet writeError = null;\n\t\tconst producer = new IdempotentProducer(this, producerId, {\n\t\t\tautoClaim: true,\n\t\t\theaders: opts?.headers,\n\t\t\tlingerMs: opts?.lingerMs,\n\t\t\tmaxBatchBytes: opts?.maxBatchBytes,\n\t\t\tonError: (error) => {\n\t\t\t\tif (!writeError) writeError = error;\n\t\t\t\topts?.onError?.(error);\n\t\t\t},\n\t\t\tsignal: opts?.signal ?? this.#options.signal\n\t\t});\n\t\treturn new WritableStream({\n\t\t\twrite(chunk) {\n\t\t\t\tproducer.append(chunk);\n\t\t\t},\n\t\t\tasync close() {\n\t\t\t\tawait producer.close();\n\t\t\t\tif (writeError) throw writeError;\n\t\t\t},\n\t\t\tabort(_reason) {\n\t\t\t\tproducer.detach().catch((err) => {\n\t\t\t\t\topts?.onError?.(err);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Start a fetch-like streaming session against this handle's URL/headers/params.\n\t* The first request is made inside this method; it resolves when we have\n\t* a valid first response, or rejects on errors.\n\t*\n\t* Call-specific headers and params are merged with handle-level ones,\n\t* with call-specific values taking precedence.\n\t*\n\t* @example\n\t* ```typescript\n\t* const handle = await DurableStream.connect({\n\t* url,\n\t* headers: { Authorization: `Bearer ${token}` }\n\t* });\n\t* const res = await handle.stream<{ message: string }>();\n\t*\n\t* // Accumulate all JSON items\n\t* const items = await res.json();\n\t*\n\t* // Or stream live with ReadableStream\n\t* const reader = res.jsonStream().getReader();\n\t* let result = await reader.read();\n\t* while (!result.done) {\n\t* console.log(result.value);\n\t* result = await reader.read();\n\t* }\n\t*\n\t* // Or use subscriber for backpressure-aware consumption\n\t* res.subscribeJson(async (batch) => {\n\t* for (const item of batch.items) {\n\t* console.log(item);\n\t* }\n\t* });\n\t* ```\n\t*/\n\tasync stream(options) {\n\t\tconst mergedHeaders = {\n\t\t\t...this.#options.headers,\n\t\t\t...options?.headers\n\t\t};\n\t\tconst mergedParams = {\n\t\t\t...this.#options.params,\n\t\t\t...options?.params\n\t\t};\n\t\treturn stream({\n\t\t\turl: this.url,\n\t\t\theaders: mergedHeaders,\n\t\t\tparams: mergedParams,\n\t\t\tsignal: options?.signal ?? this.#options.signal,\n\t\t\tfetch: this.#options.fetch,\n\t\t\tbackoffOptions: this.#options.backoffOptions,\n\t\t\toffset: options?.offset,\n\t\t\tlive: options?.live,\n\t\t\tjson: options?.json,\n\t\t\tonError: options?.onError ?? this.#onError,\n\t\t\twarnOnHttp: options?.warnOnHttp ?? this.#options.warnOnHttp\n\t\t});\n\t}\n\t/**\n\t* Resolve the stream's configured headers.\n\t* Used by IdempotentProducer to merge auth headers into its requests.\n\t* @internal\n\t*/\n\tasync resolveHeaders() {\n\t\treturn resolveHeaders(this.#options.headers);\n\t}\n\t/**\n\t* Build request headers and URL.\n\t*/\n\tasync #buildRequest() {\n\t\tconst requestHeaders = await resolveHeaders(this.#options.headers);\n\t\tconst fetchUrl = new URL(this.url);\n\t\tconst params = await resolveParams(this.#options.params);\n\t\tfor (const [key, value] of Object.entries(params)) fetchUrl.searchParams.set(key, value);\n\t\treturn {\n\t\t\trequestHeaders,\n\t\t\tfetchUrl\n\t\t};\n\t}\n};\n/**\n* Encode a body value to the appropriate format.\n* Strings are encoded as UTF-8.\n* Objects are JSON-serialized.\n*/\nfunction encodeBody(body) {\n\tif (body === void 0) return void 0;\n\tif (typeof body === `string`) return new TextEncoder().encode(body);\n\tif (body instanceof Uint8Array) return body;\n\tif (body instanceof Blob || body instanceof FormData || body instanceof ReadableStream || body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return body;\n\treturn new TextEncoder().encode(JSON.stringify(body));\n}\n/**\n* Convert an async iterable to a ReadableStream.\n*/\nfunction toReadableStream(source) {\n\tif (source instanceof ReadableStream) return source.pipeThrough(new TransformStream({ transform(chunk, controller) {\n\t\tif (typeof chunk === `string`) controller.enqueue(new TextEncoder().encode(chunk));\n\t\telse controller.enqueue(chunk);\n\t} }));\n\tconst encoder = new TextEncoder();\n\tconst iterator = source[Symbol.asyncIterator]();\n\treturn new ReadableStream({\n\t\tasync pull(controller) {\n\t\t\ttry {\n\t\t\t\tconst { done, value } = await iterator.next();\n\t\t\t\tif (done) controller.close();\n\t\t\t\telse if (typeof value === `string`) controller.enqueue(encoder.encode(value));\n\t\t\t\telse controller.enqueue(value);\n\t\t\t} catch (e) {\n\t\t\t\tcontroller.error(e);\n\t\t\t}\n\t\t},\n\t\tcancel() {\n\t\t\titerator.return?.();\n\t\t}\n\t});\n}\n/**\n* Validate stream options.\n*/\nfunction validateOptions(options) {\n\tif (!options.url) throw new MissingStreamUrlError();\n\tif (options.signal && !(options.signal instanceof AbortSignal)) throw new InvalidSignalError();\n\twarnIfUsingHttpInBrowser(options.url, options.warnOnHttp);\n}\n//#endregion\n//#region src/client.ts\n/**\n* The streams client a consumer's `durableStreams()` binding hydrates to —\n* the RPC parity: RPC users don't hand-roll request encoding (`rpc()` hydrates\n* through `makeClient`), and streams users don't hand-roll the Durable Streams\n* protocol. All protocol knowledge lives here: the URL layout, the bearer\n* scheme, JSON-array append framing, opaque offsets, and the long-poll dance\n* — plus the stream lifecycle (ensure-create, the proven-safe 404 heal) that\n* used to live in application code. The wire client is\n* `@durable-streams/client` (ElectricSQL's canonical protocol client,\n* Apache-2.0); this wrapper narrows it to what the module contract promises\n* and adds the platform compensations, each annotated with the ticket it\n* stands in for.\n*\n* Two classes: `StreamsClient` holds the transport (base URL, bearer header,\n* the per-stream write handles a batched append needs) and hands out one\n* `StreamHandle` per stream name, memoized so its ensure-create state\n* survives repeat calls. `StreamHandle` holds one stream's name and\n* ensure-create memo, and is what a consumer actually calls `append`/`read`/\n* `tail` on — no call site names a stream twice.\n*\n* Exported standalone (and via the umbrella) so local dev and tests can wrap\n* the stand-in's URL without a deployed binding:\n*\n* const client = new StreamsClient({ url: standIn.url, apiKey: 'unused' });\n* await client.stream('log').append({ n: 1 });\n*/\nconst JSON_CONTENT_TYPE = \"application/json\";\n/**\n* PRO-219: a scale-to-zero streams service can reset the first connection\n* while its instance boots (~3.5–8s observed), so IDEMPOTENT operations ride\n* it out with a bounded backoff. The wire client retries any failure except\n* a 4xx other than 429 — thrown network errors and 5xx statuses included —\n* so a real protocol error (401, 404, 409) surfaces on the first try. The\n* bound is ATTEMPTS, not wall-clock: each wait is jittered up to the current\n* delay, and a server Retry-After acts as a per-wait floor (capped upstream\n* at 1h). Appends never get any of this (see `StreamsClient.append`). Remove\n* when CI's \"Cold-start canary (PRO-217)\" goes clean — it exists to flag\n* exactly that.\n*/\nconst IDEMPOTENT_BACKOFF = {\n\t...BackoffDefaults,\n\tinitialDelay: 250,\n\tmaxDelay: 5e3,\n\tmultiplier: 2,\n\tmaxRetries: 5\n};\n/** The wire client retries network errors by default — appends must not be (no idempotency key). */\nconst NO_RETRY_BACKOFF = {\n\t...BackoffDefaults,\n\tmaxRetries: 0\n};\nconst DEFAULT_TAIL_TIMEOUT_MS = 2e4;\nfunction isAlreadyExists(error) {\n\treturn error instanceof DurableStreamError && error.status === 409;\n}\n/**\n* Whether a client operation failed because the stream does not exist — the\n* one failure that provably applied NOTHING, so re-creating the stream and\n* re-running the operation is safe even for an append. Deliberately exactly\n* that: ambiguous failures (socket closes, 502/504) never match. Not\n* exported — its only consumer is `StreamHandle`'s own heal, so no app code\n* needs the wire client's error shape.\n*/\nfunction isStreamNotFound(error) {\n\treturn (error instanceof FetchError || error instanceof DurableStreamError) && error.status === 404;\n}\nfunction streamUrl(base, name) {\n\treturn `${base}/v1/stream/${encodeURIComponent(name)}`;\n}\n/**\n* The transport a consumer's `durableStreams()` binding hydrates to (bare\n* form) — holds the base URL, the bearer header, and the per-stream write\n* handles a batched append needs. `stream(name)` is the client's whole\n* public surface: a dynamic streams consumer names a stream by calling it,\n* never by any other method here.\n*/\nvar StreamsClient = class {\n\tbase;\n\theaders;\n\twriters = /* @__PURE__ */ new Map();\n\thandles = /* @__PURE__ */ new Map();\n\tconstructor(config) {\n\t\tthis.base = config.url.replace(/\\/$/, \"\");\n\t\tthis.headers = { authorization: `Bearer ${config.apiKey}` };\n\t}\n\t/** One handle per stream name, memoized so its ensure-create state survives repeat calls. */\n\tstream(name) {\n\t\tlet handle = this.handles.get(name);\n\t\tif (handle === void 0) {\n\t\t\thandle = new StreamHandle(name, this);\n\t\t\tthis.handles.set(name, handle);\n\t\t}\n\t\treturn handle;\n\t}\n\twriter(name) {\n\t\tlet handle = this.writers.get(name);\n\t\tif (handle === void 0) {\n\t\t\thandle = new DurableStream({\n\t\t\t\turl: streamUrl(this.base, name),\n\t\t\t\theaders: this.headers,\n\t\t\t\tcontentType: JSON_CONTENT_TYPE,\n\t\t\t\tbatching: false,\n\t\t\t\tbackoffOptions: NO_RETRY_BACKOFF\n\t\t\t});\n\t\t\tthis.writers.set(name, handle);\n\t\t}\n\t\treturn handle;\n\t}\n\t/** Creates the stream (idempotent: an existing stream of any content type is success). Used by `StreamHandle`'s ensure-create. */\n\tasync create(name) {\n\t\tconst handle = new DurableStream({\n\t\t\turl: streamUrl(this.base, name),\n\t\t\theaders: this.headers,\n\t\t\tcontentType: JSON_CONTENT_TYPE,\n\t\t\tbackoffOptions: IDEMPOTENT_BACKOFF\n\t\t});\n\t\ttry {\n\t\t\tawait handle.create();\n\t\t} catch (error) {\n\t\t\tif (!isAlreadyExists(error)) throw error;\n\t\t}\n\t}\n\t/**\n\t* Appends one JSON event. NEVER retried beyond `StreamHandle`'s one-shot\n\t* 404 heal: the protocol has no idempotency key, so a failed request is\n\t* indistinguishable from one that applied — the caller retries, because\n\t* only it knows whether a duplicate is acceptable.\n\t*/\n\tasync append(name, event) {\n\t\tawait this.writer(name).append(JSON.stringify(event));\n\t}\n\t/** Reads the stream from `offset` (default: the beginning) to the current head. */\n\tasync read(name, opts) {\n\t\tconst res = await stream({\n\t\t\turl: streamUrl(this.base, name),\n\t\t\theaders: this.headers,\n\t\t\toffset: opts?.offset ?? \"-1\",\n\t\t\tlive: false,\n\t\t\tjson: true,\n\t\t\tbackoffOptions: IDEMPOTENT_BACKOFF\n\t\t});\n\t\treturn {\n\t\t\tevents: await res.json(),\n\t\t\tnextOffset: res.offset\n\t\t};\n\t}\n\t/**\n\t* Waits for the next live delivery after `offset` (default: the current\n\t* head), via long-poll — SSE cannot traverse the Compute ingress (PRO-218).\n\t* Resolves with the delivered events, or `timedOut: true` after `timeoutMs`\n\t* (default 20s) with nothing new.\n\t*/\n\tasync tail(name, opts) {\n\t\tconst abort = new AbortController();\n\t\tconst onCallerAbort = () => abort.abort();\n\t\topts?.signal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\t\tconst timer = setTimeout(() => abort.abort(), opts?.timeoutMs ?? DEFAULT_TAIL_TIMEOUT_MS);\n\t\ttry {\n\t\t\tconst res = await stream({\n\t\t\t\turl: streamUrl(this.base, name),\n\t\t\t\theaders: this.headers,\n\t\t\t\toffset: opts?.offset ?? \"now\",\n\t\t\t\tlive: \"long-poll\",\n\t\t\t\tjson: true,\n\t\t\t\tbackoffOptions: IDEMPOTENT_BACKOFF,\n\t\t\t\tsignal: abort.signal\n\t\t\t});\n\t\t\treturn await new Promise((resolve, reject) => {\n\t\t\t\tabort.signal.addEventListener(\"abort\", () => resolve({\n\t\t\t\t\tevents: [],\n\t\t\t\t\tnextOffset: res.offset,\n\t\t\t\t\ttimedOut: true\n\t\t\t\t}), { once: true });\n\t\t\t\ttry {\n\t\t\t\t\tres.subscribeJson((batch) => {\n\t\t\t\t\t\tif (batch.items.length === 0) return;\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tevents: batch.items,\n\t\t\t\t\t\t\tnextOffset: batch.offset,\n\t\t\t\t\t\t\ttimedOut: false\n\t\t\t\t\t\t});\n\t\t\t\t\t\tabort.abort();\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\treject(error);\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (abort.signal.aborted) return {\n\t\t\t\tevents: [],\n\t\t\t\tnextOffset: opts?.offset ?? \"now\",\n\t\t\t\ttimedOut: true\n\t\t\t};\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t\topts?.signal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t}\n\t}\n};\n/**\n* One stream's handle — the name and the ensure-create memo. Everything a\n* `durableStreams(contract)` handle or a `durableStreams()` client's\n* `stream(name)` result exposes; no call site passes a name again.\n*\n* Owns the lifecycle the app used to hand-roll: the first operation creates\n* the stream (memoized here; upstream create is already ensure-style, so a\n* racing second instance is harmless — using a stream is sufficient to\n* create it), and a 404 on any operation heals by dropping the memo,\n* re-creating, and retrying that operation once. A 404 is generated INSTEAD\n* OF a write at every layer, so it proves nothing was applied — retrying\n* once cannot duplicate an event, even an append. Ambiguous failures (socket\n* closes, 502/504) never match `isStreamNotFound` and surface raw.\n*/\nvar StreamHandle = class {\n\tname;\n\ttransport;\n\tensured;\n\tconstructor(name, transport) {\n\t\tthis.name = name;\n\t\tthis.transport = transport;\n\t}\n\tensureCreate() {\n\t\tif (this.ensured === void 0) this.ensured = this.transport.create(this.name).catch((error) => {\n\t\t\tthis.ensured = void 0;\n\t\t\tthrow error;\n\t\t});\n\t\treturn this.ensured;\n\t}\n\tasync withHeal(op) {\n\t\tawait this.ensureCreate();\n\t\ttry {\n\t\t\treturn await op();\n\t\t} catch (error) {\n\t\t\tif (!isStreamNotFound(error)) throw error;\n\t\t\tthis.ensured = void 0;\n\t\t\tawait this.ensureCreate();\n\t\t\treturn op();\n\t\t}\n\t}\n\t/**\n\t* Appends one JSON event. NEVER retried beyond the one-shot 404 heal above:\n\t* the protocol has no idempotency key, so a failed request is\n\t* indistinguishable from one that applied — the caller retries, because\n\t* only it knows whether a duplicate is acceptable.\n\t*/\n\tappend(event) {\n\t\treturn this.withHeal(() => this.transport.append(this.name, event));\n\t}\n\t/** Reads the stream from `offset` (default: the beginning) to the current head. */\n\tread(opts) {\n\t\treturn this.withHeal(() => this.transport.read(this.name, opts));\n\t}\n\t/**\n\t* Waits for the next live delivery after `offset` (default: the current\n\t* head), via long-poll. Resolves with the delivered events, or\n\t* `timedOut: true` after `timeoutMs` (default 20s) with nothing new.\n\t*/\n\ttail(opts) {\n\t\treturn this.withHeal(() => this.transport.tail(this.name, opts));\n\t}\n};\n//#endregion\n//#region src/contract.ts\n/** Declares an untyped stream in a `streamsContract` def map. */\nfunction streamDef() {\n\treturn Object.freeze({ kind: \"stream-def\" });\n}\n/**\n* Names the streams a contract transports, each with an optional def:\n* `streamsContract({ jobs: streamDef(), audit: streamDef() })`. The\n* `durableStreams(contract)` dependency built from it hydrates to one handle\n* per declared name.\n*/\nfunction streamsContract(defs) {\n\treturn Object.freeze({\n\t\tkind: \"streams\",\n\t\t__cmp: defs,\n\t\tsatisfies: (required) => required.kind === \"streams\"\n\t});\n}\n/**\n* The `streams()` module's own exposed port: a general streams provider,\n* satisfied by kind alone — the `postgresContract` pattern. The module\n* cannot know its eventual consumers' stream names (different consumers of\n* one module each name their own), and the server genuinely serves any\n* stream, so what a consumer requires of its provider is only \"is a streams\n* provider\". That is exactly what this wide type says, and the empty def\n* map is a legitimate `StreamDefs` value — a placeholder nobody reads, like\n* postgres's `{ url: '' }`. Consumers keep their literal handle typing from\n* `durableStreams(contract)`'s generic parameter, which is independent of\n* the wiring-compatibility type here.\n*/\nconst streamsProviderContract = Object.freeze({\n\tkind: \"streams\",\n\t__cmp: {},\n\tsatisfies: (required) => required.kind === \"streams\"\n});\nconst connectionParams = {\n\turl: string(),\n\tapiKey: string({ provision: streamsApiKeyNeed() })\n};\nfunction durableStreams(contract) {\n\treturn dependency({\n\t\ttype: \"streams\",\n\t\tconnection: {\n\t\t\tparams: connectionParams,\n\t\t\thydrate: (v) => {\n\t\t\t\tconst client = new StreamsClient(v);\n\t\t\t\tif (contract === void 0) return client;\n\t\t\t\tconst handles = {};\n\t\t\t\tfor (const name of Object.keys(contract.__cmp)) handles[name] = client.stream(name);\n\t\t\t\treturn handles;\n\t\t\t}\n\t\t},\n\t\trequired: contract ?? streamsProviderContract\n\t});\n}\n//#endregion\n//#region src/exports/streams-service.ts\n/**\n* The streams service node: a plain `compute` service — the contract binding's\n* `url` is a producer output compute's deploy already carries, and its\n* `apiKey` is minted by the target's registered provisioner (ADR-0031), so\n* nothing is left for a bespoke lowering to extend. It declares the `store`\n* dependency (`s3()`, the storage module's port) and the `streams` expose; the\n* bearer key reaches this service through the target's reserved provider\n* param, not through a dependency. The deploy bootstrap runs the\n* default-exported bare node; the real wiring arrives through serialized\n* config at runtime — exactly like `storage-service.ts`.\n*/\nfunction streamsService() {\n\treturn compute({\n\t\tname: \"streams\",\n\t\tdeps: { store: s3() },\n\t\tbuild: node({\n\t\t\tmodule: new URL(\"./streams-service.mjs\", import.meta.url).href,\n\t\t\tentry: \"./streams-entrypoint.mjs\"\n\t\t}),\n\t\texpose: { streams: streamsProviderContract }\n\t});\n}\nvar streams_service_default = streamsService();\n//#endregion\nexport { streamsContract as a, StreamsClient as c, streamDef as i, streams_service_default as n, streamsProviderContract as o, durableStreams as r, StreamHandle as s, streamsService as t };\n\n//# sourceMappingURL=streams-service-Br5Tj3AY.mjs.map"],"mappings":"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"}
|