@thomasfosterau/legation-jsonapi 0.0.0-stage → 0.1.0
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/CHANGELOG.md +973 -0
- package/LICENSE +21 -0
- package/README.md +755 -2
- package/dist/index.d.ts +1708 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4304 -0
- package/dist/index.js.map +1 -0
- package/dist/rolldown-runtime-D8jQpDG7.js +12 -0
- package/package.json +53 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["Relationship","attributesOf","UrlQuery","recordOf","invalid","nodeOf","carriedTypes","Query","jsonApiHeaders","refOf","idOf","attributesOf","JsonApiQuery.canonical","linkageOf","writeOf","make","Ledger.memory","descriptorsOf","DocumentWriter.relatedValuesOf","DocumentWriter.idOf","resolve","Query","Linkage.planOf","JsonApiQuery.invalidParameter","make","JsonApiQuery.resourcesOf","Linkage.resolve","collection","DocumentWriter.collection","data","DocumentWriter.data","JsonApiQuery.parseRead","Linkage.collectionsOf","ApiError","Linkage.resolve","Linkage.planOf","JsonApiQuery.parseParams","DocumentWriter.collection","JsonApiQuery.singleRowParams","DocumentWriter.data","Convention.segmentsOf","Convention.reflectResources","Convention.isParam","RestHandlers.queryErrorDocument","FacadeWrites.graphIntentOf","ReplicaDocuments.make","JsonApiQuery.parseRead","Query","FacadeWrites.decodeWrite","FacadeWrites.preferencesOf","MutationStatus.parseId","MutationStatus.unknownDocument","MutationStatus.current","MutationStatus.settled","document","MutationStatus.document","Ledger.keyValue","JsonApiBackend.make"],"sources":["../src/errors.ts","../src/schema.ts","../src/JsonApiQuery.ts","../src/CollectionLoader.ts","../src/Convention.ts","../src/Derive.ts","../src/DocumentWriter.ts","../src/Ledger.ts","../src/JsonApiBackend.ts","../src/FacadeWrites.ts","../src/MutationStatus.ts","../src/Linkage.ts","../src/ReplicaDocuments.ts","../src/RestHandlers.ts","../src/JsonApiFacade.ts","../src/JsonApiSync.ts","../src/NodeBridge.ts","../src/Relationships.ts"],"sourcesContent":["/**\n * Synchronizer Errors\n *\n * Tagged error types for the JSON:API adapter. All errors extend\n * `Schema.TaggedError`, so they are yieldable inside `Effect.gen`, usable with\n * `Effect.fail`, and handled with `Effect.catchTag` / `Effect.catchTags`.\n * Because `Schema.TaggedError` extends `Error`, the `message` field is also\n * available as `.message` on instances.\n */\n\nimport { Document } from \"@thomasfosterau/effect-jsonapi\";\nimport * as Schema from \"effect/Schema\";\n\n/**\n * Base error for synchronizer operations.\n */\nexport class SyncError extends Schema.TaggedError<SyncError, { readonly brand: unique symbol }>()(\n \"SyncError\",\n {\n message: Schema.String,\n cause: Schema.optional(Schema.Defect()),\n }\n) {}\n\n/**\n * Network-related error (connection failure, timeout, etc.).\n */\nexport class NetworkError extends Schema.TaggedError<\n NetworkError,\n { readonly brand: unique symbol }\n>()(\"NetworkError\", {\n message: Schema.String,\n cause: Schema.optional(Schema.Defect()),\n}) {}\n\n/**\n * Parsing error for JSON:API documents.\n */\nexport class ParseError extends Schema.TaggedError<ParseError, { readonly brand: unique symbol }>()(\n \"ParseError\",\n {\n message: Schema.String,\n cause: Schema.optional(Schema.Defect()),\n }\n) {}\n\n/**\n * API error carrying the JSON:API error objects returned by the server.\n */\nexport class ApiError extends Schema.TaggedError<ApiError, { readonly brand: unique symbol }>()(\n \"ApiError\",\n {\n message: Schema.String,\n errors: Schema.Array(Document.ErrorObject),\n }\n) {}\n\n/**\n * Conflict error raised when local and remote resource versions mismatch.\n */\nexport class ConflictError extends Schema.TaggedError<\n ConflictError,\n { readonly brand: unique symbol }\n>()(\"ConflictError\", {\n message: Schema.String,\n localVersion: Schema.optional(Schema.String),\n remoteVersion: Schema.optional(Schema.String),\n}) {}\n","/**\n * JSON:API Schemas\n *\n * Generic codecs for the JSON:API v1.1 document types this loader decodes from\n * arbitrary upstream servers, plus a `decodeDocument` helper that validates\n * untrusted input (e.g. a parsed HTTP response body) into a `JsonApiDocument`.\n *\n * The spec primitives — link objects, the `jsonapi` member, error objects, and\n * free-form `meta` — are adopted from `@thomasfosterau/effect-jsonapi`'s\n * `Document` module (the canonical, spec-compliant definitions) rather than\n * hand-rolled here. What stays local are the *generic, untyped* composites\n * (`ResourceObject`, `Relationship`, `JsonApiDocument`): the library models\n * documents per known `Resource` definition, but a collection loader reads\n * resources whose `type` and attribute shapes it does not know ahead of time,\n * so it needs a resource-agnostic document schema layered over those\n * primitives.\n *\n * JSON:API is an *open* format: documents and most member objects may carry\n * implementation-specific members beyond those the spec names. Effect v4\n * `Schema.Struct` already drops excess properties during decoding rather than\n * rejecting them, so these schemas validate the *shape* of the members we care\n * about while tolerating extra members. Free-form members (`meta`,\n * `attributes`) are modelled as `Document.AnyMeta`\n * (`Schema.Record(Schema.String, Schema.Unknown)`).\n *\n * Schema failures are mapped to the package's `ParseError`, with the\n * underlying `Schema` issue attached as `cause`.\n */\n\nimport { Document } from \"@thomasfosterau/effect-jsonapi\";\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\nimport { ParseError } from \"./errors.js\";\n\n/** Free-form `meta` / `attributes` object: arbitrary JSON values by key. */\nconst MetaSchema = Document.AnyMeta;\n\n/**\n * Schema for a JSON:API link object (`{ href, ... }`), adopted from the\n * library's spec-compliant definition.\n */\nexport const LinkObject = Document.LinkObject;\n\n/** A JSON:API link object. */\nexport type LinkObject = typeof LinkObject.Type;\n\n/**\n * Schema for a single link value: either a URL string or a link object.\n */\nconst LinkValue = Document.Link;\n\n/**\n * Schema for a JSON:API `links` object. The spec allows arbitrary link names,\n * so this is a record of link values; `self` / `related` are simply well-known\n * keys within it.\n */\nexport const Links = Schema.Record(Schema.String, LinkValue);\n\n/** A JSON:API `links` object: arbitrary link names → string | link object. */\nexport type Links = typeof Links.Type;\n\n/**\n * Schema for a JSON:API resource identifier (`{ type, id, meta? }`).\n */\nexport const ResourceIdentifier = Schema.Struct({\n type: Schema.String,\n id: Schema.String,\n meta: Schema.optional(MetaSchema),\n});\n\n/** A JSON:API resource identifier (`{ type, id, meta? }`). */\nexport type ResourceIdentifier = typeof ResourceIdentifier.Type;\n\n/**\n * Schema for a JSON:API relationship (`{ data?, links?, meta? }`). The\n * `data` member may be a single identifier, an array of identifiers, or\n * `null`.\n */\nexport const Relationship = Schema.Struct({\n data: Schema.optional(\n Schema.NullOr(Schema.Union([ResourceIdentifier, Schema.Array(ResourceIdentifier)]))\n ),\n links: Schema.optional(Links),\n meta: Schema.optional(MetaSchema),\n});\n\n/** A JSON:API relationship (`{ data?, links?, meta? }`). */\nexport type Relationship = typeof Relationship.Type;\n\n/**\n * Schema for a JSON:API resource object (a resource identifier plus\n * optional `attributes`, `relationships`, and `links`).\n */\nexport const ResourceObject = Schema.Struct({\n type: Schema.String,\n id: Schema.String,\n meta: Schema.optional(MetaSchema),\n attributes: Schema.optional(MetaSchema),\n relationships: Schema.optional(Schema.Record(Schema.String, Relationship)),\n links: Schema.optional(Links),\n});\n\n/** A JSON:API resource object (identifier + optional attributes/relationships/links). */\nexport type ResourceObject = typeof ResourceObject.Type;\n\n/**\n * Schema for a JSON:API error object, adopted from the library's\n * spec-compliant definition.\n */\nexport const JsonApiError = Document.ErrorObject;\n\n/** A JSON:API error object. */\nexport type JsonApiError = typeof JsonApiError.Type;\n\n/**\n * Schema for a top-level JSON:API document.\n *\n * The `data` member may be a single resource, a collection of resources, a\n * resource identifier (or collection thereof), or `null`. The other\n * top-level members (`errors`, `meta`, `included`, `links`, `jsonapi`) are\n * all optional. The `jsonapi` member reuses the library's `JsonApiObject`.\n */\nexport const JsonApiDocument = Schema.Struct({\n data: Schema.optional(\n Schema.NullOr(\n Schema.Union([\n ResourceObject,\n Schema.Array(ResourceObject),\n ResourceIdentifier,\n Schema.Array(ResourceIdentifier),\n ])\n )\n ),\n errors: Schema.optional(Schema.Array(JsonApiError)),\n meta: Schema.optional(MetaSchema),\n included: Schema.optional(Schema.Array(ResourceObject)),\n links: Schema.optional(Links),\n jsonapi: Schema.optional(Document.JsonApiObject),\n});\n\n/**\n * A top-level JSON:API document. Derived from {@link JsonApiDocument}\n * so the type and the validator cannot drift.\n */\nexport type JsonApiDocument = typeof JsonApiDocument.Type;\n\nconst decodeJsonApiDocument = Schema.decodeUnknownEffect(JsonApiDocument);\n\n/**\n * Decode an unknown value (e.g. a parsed HTTP response body) into a\n * `JsonApiDocument`. Schema failures become `ParseError`, with the schema\n * issue attached as `cause`.\n */\nexport const decodeDocument = (input: unknown): Effect.Effect<JsonApiDocument, ParseError> =>\n decodeJsonApiDocument(input).pipe(\n Effect.mapError((cause) => new ParseError({ message: \"Invalid JSON:API document\", cause }))\n );\n","/**\n * JsonApiQuery\n *\n * The bridge between the filter grammar's URL form and the engine's plan\n * (ADR-0028 §5, issue #161) — a façade-boundary projection for one job\n * (ADR-0029 §6: a URL must mean the same thing answered from the replica as\n * answered by the network), not a general translation between two dialects\n * of one language. effect-jsonapi owns the grammar — its AST (`Filter.Ast`),\n * the `filter[...]` ⇄ AST codec (`Query.Filter`), the whole query codec\n * (`Query.schema`) and the canonical query string (`Query.canonical`); this\n * module owns the three translations legation needs on top of them:\n *\n * - **Filter AST ⇄ `Predicate`** ({@link fromFilterAst}, {@link toFilterAst}):\n * both directions are partial, and neither is the other's inverse.\n * {@link fromFilterAst} rejects a literal that is not a wire scalar\n * (`string | number | boolean`) or a `Date` (encoded to its instant text —\n * see below) with a typed `QueryError`, since a grammar AST is typed by\n * the attribute's **decoded** schema and that type is open-ended (issue\n * #218's design note). {@link toFilterAst} returns `None` for `Exists`\n * (server-only, no URL form), an empty `In` / `NotIn` list, and a `null`\n * literal (the grammar's lists are non-empty and `NULL` is never a\n * literal — `isnull` names it); those callers fail closed.\n * {@link foldConstants} removes the two definite cases before encoding:\n * an empty `In` is false and an empty `NotIn` is true under ADR-0028's\n * per-operator table, so they fold away exactly. Both functions carry a\n * **field-namespace precondition**: a field name is copied verbatim\n * between the two ASTs, which is correct only because every caller in\n * this module pre-synthesises a resource whose field names are already\n * the engine's ({@link resourcesOf} — a to-one edge is named by its FK key\n * field, never the relationship name). Neither function checks that a\n * field it is given actually names something on the other side; a caller\n * bridging an AST built over a resource with its own naming must\n * translate field names first. A `Date` literal's conversion to\n * `value.toISOString()` is an **encode, not a copy**: ADR-0028 rule (e)\n * fixes instant comparison to that exact text, so an instant literal that\n * arrives any other way (a differently-formatted string, say) will not\n * compare correctly downstream — this is the one step in either direction\n * that changes a value's representation rather than re-tagging it, which\n * is also why {@link toFilterAst} is a separate partial function rather\n * than {@link fromFilterAst}'s inverse: the type erasure `Date → string`\n * cannot be undone from the `Predicate` side alone.\n * - **URL → `Query.Read`** ({@link parseRead}, {@link parseParams}): a\n * request URL is decoded with effect-jsonapi's `Query.schema` for the\n * collection's node — `include`, `fields`, `sort`, `page` and `filter` —\n * and mapped onto the declarative read: `filter` → `where`, `sort` →\n * `order`, `page[limit]` / `page[after]` → `first` / `after`, `include`\n * → the edge selects. `fields[]` is a serialisation-time projection\n * (ADR-0029 §5) and is carried beside the read, never into the plan.\n * Every rejection is a `QueryError` naming the parameter, so a façade or\n * a derived REST handler answers 400 with `source.parameter` set.\n * - **`Query.Read` → canonical string** ({@link canonical}): the read is\n * compiled with `Query.plan` and its plan is encoded through the\n * canonical encoder, so two reads with one plan have one string —\n * subscription identity for `Client.subscribe(url)` (ADR-0029 §2).\n * {@link urlReads} packages the parse and the canonical string as the\n * `Client.UrlReads` seam a Client or an engine host is built with (#159).\n *\n * The query codec is derived from the **node graph**, not from an\n * effect-jsonapi resource: {@link resourcesOf} synthesises one resource per\n * node whose filterable attributes carry the node's filterable set (the\n * operators and literal kinds of ADR-0028 rule d, #154) and whose\n * relationships are the node's edges. A filter names the row field the\n * engine evaluates — a `one`-edge is filtered by its key field\n * (`filter[categoryId]=c-audio`, as in ADR-0029's worked examples), not by\n * the edge name. Include paths are single level (decision D1 of ADR-0028):\n * a read includes a node's own edges only, so `include=variants.product` is\n * rejected as a parse failure.\n *\n * The **exact encoder** ({@link defaultEncoder}) is what `JsonApiBackend`\n * pushes to the server: the whole predicate as the grammar's canonical\n * `filter[...]` record (operators, `or`, `not`, `isnull` and `nin`\n * included — nothing is dropped any more), plus `sort`. Order, cursor and\n * limit stay local: `Subset.apply` still finalises the window, which is now\n * redundancy over an exact filter rather than correction of a superset\n * (ADR-0028 §6). A predicate that can never match (an empty allow-set)\n * encodes to `None` and the backend skips the request.\n */\n\nimport { Filter, Query as UrlQuery, Relationship, Resource } from \"@thomasfosterau/effect-jsonapi\";\nimport * as Arr from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport * as R from \"effect/Record\";\nimport * as Result from \"effect/Result\";\nimport * as Schema from \"effect/Schema\";\nimport * as SchemaIssue from \"effect/SchemaIssue\";\nimport * as Str from \"effect/String\";\nimport {\n type Client,\n FilterPolicy,\n type Node,\n Predicate,\n Query,\n QueryError,\n} from \"@thomasfosterau/legation\";\nimport type { Subset } from \"@thomasfosterau/legation/internal\";\nimport type { JsonApiRequestOptions, SortTerm } from \"./types.js\";\n\n// ─── Filter AST ⇄ Predicate ──────────────────────────────────────────────────\n\n/**\n * A grammar literal as a `Predicate` literal: scalars as they are, a `Date`\n * as its instant text (the load-bearing encode of ADR-0028 rule e), or a\n * typed `QueryError` for anything else — a grammar AST is typed by the\n * attribute's decoded schema (issue #218's design note), which is\n * open-ended, so this is the one place that type meets `Predicate.Literal`'s\n * closed wire-scalar union and can fail.\n */\nconst literalOf = (field: string, value: unknown): Result.Result<Predicate.Literal, QueryError> => {\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n return Result.succeed(value);\n default:\n return value instanceof Date\n ? Result.succeed(value.toISOString())\n : Result.fail(\n new QueryError({\n message: `Filter literal ${JSON.stringify(value)} for field \"${field}\" is not a scalar`,\n parameter: `filter[${field}]`,\n })\n );\n }\n};\n\n/**\n * The engine form of a filter AST, or a typed `QueryError` naming the field\n * whose literal {@link literalOf} rejects: `Compare` / `In` / `NotIn` /\n * `IsNull` map node for node, `And` / `Or` / `Not` recurse, and the empty\n * conjunction (the grammar's \"true\") is `Predicate.always`. The map is\n * structural — a singleton group, which the grammar's normal form keeps\n * after deduplicating `Or(x, x)`, stays a singleton group rather than\n * collapsing through `Predicate.or` — so {@link canonical} is idempotent.\n * Literals are the codec's decoded scalars; a `Date` (a `DateFromString`\n * attribute) becomes its ISO-8601 UTC text (see the module doc's encode\n * note). Field names are copied verbatim — the module doc's\n * field-namespace precondition.\n *\n * This module's own callers ({@link readOf}, {@link filterOf}) never see\n * this fail: their ASTs are decoded through {@link resourcesOf}'s synthetic\n * resource, whose filterable attributes admit only wire scalars, or are\n * built by {@link toFilterAst} from a `Predicate.Literal`, which is one\n * already. The typed failure exists for this function's public contract —\n * any caller bridging an AST built over a resource with a richer decoded\n * attribute type (a `Date`-valued one aside, which is handled) — not for\n * either call site here.\n */\nexport const fromFilterAst = (ast: Filter.Node): Result.Result<Predicate.Predicate, QueryError> => {\n switch (ast._tag) {\n case \"Compare\":\n return Result.map(literalOf(ast.field, ast.value), (value) =>\n Predicate.compare(ast.op, ast.field, value)\n );\n case \"In\":\n return Result.map(\n Result.all(ast.values.map((value) => literalOf(ast.field, value))),\n (values) => Predicate.isIn(ast.field, values)\n );\n case \"NotIn\":\n return Result.map(\n Result.all(ast.values.map((value) => literalOf(ast.field, value))),\n (values) => Predicate.notIn(ast.field, values)\n );\n case \"IsNull\":\n return Result.succeed(\n ast.negated ? Predicate.isNotNull(ast.field) : Predicate.isNull(ast.field)\n );\n case \"And\":\n return Arr.isReadonlyArrayEmpty(ast.members)\n ? Result.succeed(Predicate.always)\n : Result.map(\n Result.all(ast.members.map(fromFilterAst)),\n (predicates): Predicate.Predicate => ({ _tag: \"And\", predicates })\n );\n case \"Or\":\n return Result.map(\n Result.all(ast.members.map(fromFilterAst)),\n (predicates): Predicate.Predicate => ({ _tag: \"Or\", predicates })\n );\n case \"Not\":\n return Result.map(fromFilterAst(ast.member), Predicate.not);\n }\n};\n\n/** A non-empty list of non-null literals, or `None` (the grammar has neither an empty list nor a `NULL` literal). */\nconst literalList = (\n values: ReadonlyArray<Predicate.Literal>\n): Option.Option<readonly [Predicate.Literal, ...Array<Predicate.Literal>]> => {\n const [head, ...tail] = values;\n return head === undefined || head === null || tail.includes(null)\n ? Option.none()\n : Option.some([head, ...(tail as Array<Predicate.Literal>)]);\n};\n\n/**\n * The grammar form of a predicate, or `None` where it has no URL form:\n * `Exists` (server-only, ADR-0028 §5), an empty `In` / `NotIn` list, or a\n * `null` literal (the deprecated wire form of `isnull`; it evaluates to\n * unknown and cannot be folded). `True` is the empty conjunction.\n * `fromFilterAst ∘ toFilterAst` is the identity on every constructor-built\n * predicate it accepts.\n */\nexport const toFilterAst = (predicate: Predicate.Predicate): Option.Option<Filter.Node> => {\n switch (predicate._tag) {\n case \"True\":\n return Option.some(Filter.and());\n case \"Compare\":\n return predicate.value === null\n ? Option.none()\n : Option.some({\n _tag: \"Compare\",\n op: predicate.op,\n field: predicate.field,\n value: predicate.value,\n } satisfies Filter.Compare);\n case \"In\":\n return Option.map(literalList(predicate.values), (values) =>\n Filter.isIn(predicate.field, values)\n );\n case \"NotIn\":\n return Option.map(literalList(predicate.values), (values) =>\n Filter.notIn(predicate.field, values)\n );\n case \"IsNull\":\n return Option.some(Filter.isNull(predicate.field, predicate.negated === true));\n case \"And\":\n return Option.map(Option.all(predicate.predicates.map(toFilterAst)), (members) =>\n Filter.and(...members)\n );\n case \"Or\":\n return Option.map(Option.all(predicate.predicates.map(toFilterAst)), (members) =>\n Filter.or(...members)\n );\n case \"Not\":\n return Option.map(toFilterAst(predicate.predicate), Filter.not);\n case \"Exists\":\n case \"InSet\":\n return Option.none();\n }\n};\n\n// ─── Constant folding ────────────────────────────────────────────────────────\n\n/** The definite-false predicate: the empty disjunction (`Some(false)` for every row). */\nconst FALSE: Predicate.Predicate = { _tag: \"Or\", predicates: [] };\n\nconst isTrue = (predicate: Predicate.Predicate): boolean => predicate._tag === \"True\";\nconst isFalse = (predicate: Predicate.Predicate): boolean =>\n predicate._tag === \"Or\" && Arr.isReadonlyArrayEmpty(predicate.predicates);\n\n/** Kleene `And` over folded members: any false is false; true members vanish. */\nconst foldAnd = (members: ReadonlyArray<Predicate.Predicate>): Predicate.Predicate => {\n const folded = members.map(foldConstants);\n if (folded.some(isFalse)) return FALSE;\n const kept = folded.filter((member) => !isTrue(member));\n return Arr.isReadonlyArrayEmpty(kept) ? Predicate.always : Predicate.and(...kept);\n};\n\n/** Kleene `Or` over folded members: any true is true; false members vanish. */\nconst foldOr = (members: ReadonlyArray<Predicate.Predicate>): Predicate.Predicate => {\n const folded = members.map(foldConstants);\n if (folded.some(isTrue)) return Predicate.always;\n const kept = folded.filter((member) => !isFalse(member));\n return Arr.isReadonlyArrayEmpty(kept) ? FALSE : Predicate.or(...kept);\n};\n\nconst foldNot = (inner: Predicate.Predicate): Predicate.Predicate => {\n const folded = foldConstants(inner);\n return isTrue(folded) ? FALSE : isFalse(folded) ? Predicate.always : Predicate.not(folded);\n};\n\n/**\n * Fold the definite constants out of a predicate, exactly under ADR-0028's\n * three-valued semantics: an empty `In` is false and an empty `NotIn` is\n * true for every row (the compilers render them `1 = 0` / `1 = 1`), a\n * false conjunct or a true disjunct decides its connective, and true\n * conjuncts / false disjuncts vanish. Unknown is never folded — a `null`\n * literal stays where it is. The result is `Predicate.always`, the empty\n * `Or` (false), or a predicate free of empty lists.\n */\nexport const foldConstants = (predicate: Predicate.Predicate): Predicate.Predicate => {\n switch (predicate._tag) {\n case \"In\":\n return Arr.isReadonlyArrayEmpty(predicate.values) ? FALSE : predicate;\n case \"NotIn\":\n return Arr.isReadonlyArrayEmpty(predicate.values) ? Predicate.always : predicate;\n case \"And\":\n return foldAnd(predicate.predicates);\n case \"Or\":\n return foldOr(predicate.predicates);\n case \"Not\":\n return foldNot(predicate.predicate);\n default:\n return predicate;\n }\n};\n\n// ─── The node graph as a query declaration ───────────────────────────────────\n\n/** A check that a decoded literal is a value of the kind (`FilterPolicy.matchesKind`). */\nconst kindCheck = (kind: FilterPolicy.LiteralKind) =>\n Schema.makeFilter<Predicate.Literal>((value) => FilterPolicy.matchesKind(kind, value), {\n identifier: `LiteralKind.${kind}`,\n title: kind,\n description: `a literal of kind \"${kind}\"`,\n });\n\n/**\n * The attribute schema a filter literal of the kind decodes through: the\n * wire string is parsed as the scalar the schema's encoded form names, then\n * checked against the kind (int4 range, the fixed instant format).\n */\nconst literalSchema = (kind: FilterPolicy.LiteralKind): Schema.Top => {\n switch (kind) {\n case \"text\":\n return Schema.String;\n case \"instant\":\n return Schema.String.pipe(Schema.check(kindCheck(\"instant\")));\n case \"integer\":\n return Schema.Number.pipe(Schema.check(kindCheck(\"integer\")));\n case \"double\":\n return Schema.Number;\n case \"boolean\":\n return Schema.Boolean;\n }\n};\n\n/**\n * The synthetic resource's attributes: every filterable field (`id` and the\n * `one`-edge keys included) with its kind's schema and its operators\n * declared through `Filter.able`; every other attribute as `Unknown`, so\n * `fields[type]` still names it but no filter reaches it.\n */\nconst attributesOf = (node: Node.AnyNode): Record<string, Schema.Top> => {\n const filterable: Record<string, Schema.Top> = R.map(node.filterable, (declared) =>\n literalSchema(declared.kind).pipe(Filter.able(declared.operators))\n );\n // Declared filterable fields first, then the other attributes, untyped.\n return {\n ...filterable,\n ...R.map(\n R.filter(node.attributes, (_, field) => !R.has(filterable, field)),\n (): Schema.Top => Schema.Unknown\n ),\n };\n};\n\n/**\n * The synthetic resource's relationships: the node's edges, targets\n * resolved lazily through the graph. A paginated edge is a `many`\n * relationship here: effect-jsonapi keeps `Relationship.paginated` out of\n * `include` paths, whereas a read includes a paginated edge like any other\n * (its per-parent window is the plan's, not the URL's — {@link canonical}\n * refuses `include: { first }`).\n */\n/**\n * The resource of node `type`. {@link resourcesOf} builds one per node and\n * every edge targets a node, so a miss is a defect, never a request error.\n */\nconst resourceIn = (resources: ReadonlyMap<string, Resource.Any>, type: string): Resource.Any => {\n const resource = resources.get(type);\n if (resource === undefined) throw new QueryError({ message: `No resource for node \"${type}\"` });\n return resource;\n};\n\nconst relationshipsOf = (\n node: Node.AnyNode,\n resources: ReadonlyMap<string, Resource.Any>\n): Record<string, Relationship.Descriptor> => {\n return R.map(node.edges, (edge): Relationship.Descriptor => {\n const target = () => resourceIn(resources, edge.target);\n return edge.kind === \"one\" ? Relationship.one(target) : Relationship.many(target);\n });\n};\n\nconst resourceGraphs = new WeakMap<Node.NodeRegistry, ReadonlyMap<string, Resource.Any>>();\n\n/**\n * The node graph as effect-jsonapi resource definitions, one per node —\n * the declaration the URL codecs are derived from. Attributes are typed by\n * the node's filterable set (kind and operators), relationships are its\n * edges; nothing else about the resource is faithful (a document is never\n * serialised through it). Memoised per registry.\n */\nexport const resourcesOf = (nodes: Node.NodeRegistry): ReadonlyMap<string, Resource.Any> => {\n const cached = resourceGraphs.get(nodes);\n if (cached !== undefined) return cached;\n const resources = new Map<string, Resource.Any>();\n nodes.nodes.forEach((node) =>\n resources.set(\n node.type,\n Resource.make(node.type, {\n attributes: attributesOf(node),\n relationships: relationshipsOf(node, resources),\n })\n )\n );\n resourceGraphs.set(nodes, resources);\n return resources;\n};\n\n/**\n * The root window's page parameters: `page[limit]` is the read's `first`\n * (a positive integer), `page[after]` its `after` cursor (a row id,\n * opaque on the wire), `page[offset]` its `offset` (a non-negative\n * integer, #209 — every audited app's pagination idiom). `page[offset]`\n * and `page[after]` are different pagination idioms; {@link parseParams}\n * rejects a request naming both, and {@link decodedOf} emits `limit` then\n * whichever of `after` / `offset` the read carries — the order the\n * canonical string keeps.\n */\nexport const PageWindow = {\n limit: Schema.optionalKey(\n Schema.FiniteFromString.pipe(Schema.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(1)))\n ),\n after: Schema.optionalKey(Schema.String),\n offset: Schema.optionalKey(\n Schema.FiniteFromString.pipe(Schema.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0)))\n ),\n};\n\n/** The decoded shape of a collection's query, as the node-derived codec produces it. */\nexport interface DecodedQuery {\n readonly include?: ReadonlyArray<string>;\n readonly fields?: Readonly<Record<string, ReadonlyArray<string>>>;\n readonly sort?: ReadonlyArray<SortTerm>;\n readonly page?: { readonly limit?: number; readonly after?: string; readonly offset?: number };\n readonly filter?: Filter.Node;\n}\n\n/** One collection's query codec and its canonical encoder. */\ninterface QueryCodec {\n readonly schema: Schema.Codec<DecodedQuery, Readonly<Record<string, unknown>>>;\n readonly canonical: (decoded: DecodedQuery) => string;\n}\n\n/** A value derived per node, memoised per registry then per node type. */\nconst memoised = <A>(\n store: WeakMap<Node.NodeRegistry, Map<string, A>>,\n nodes: Node.NodeRegistry,\n node: Node.AnyNode,\n build: () => A\n): A => {\n let byType = store.get(nodes);\n if (byType === undefined) {\n byType = new Map();\n store.set(nodes, byType);\n }\n const cached = byType.get(node.type);\n if (cached !== undefined) return cached;\n const value = build();\n byType.set(node.type, value);\n return value;\n};\n\n/** The `include` option of a node's query codecs: single-level paths only (ADR-0028 D1); no edges, no `include` at all. */\nconst includeOption = (node: Node.AnyNode) =>\n !R.isEmptyReadonlyRecord(node.edges) ? ({ depth: 1 } as const) : false;\n\nconst queryCodecs = new WeakMap<Node.NodeRegistry, Map<string, QueryCodec>>();\n\n/** Build (or fetch) the query codec of one node: `Query.schema` over its synthetic resource. */\nconst codecOf = (nodes: Node.NodeRegistry, node: Node.AnyNode): QueryCodec =>\n memoised(queryCodecs, nodes, node, () => {\n const resource = resourceIn(resourcesOf(nodes), node.type);\n const schema = UrlQuery.schema(resource, {\n include: includeOption(node),\n fields: true,\n sort: node.sortable as ReadonlyArray<Resource.AttributeKeys<Resource.Any>>,\n page: PageWindow,\n filter: true,\n }) as QueryCodec[\"schema\"];\n return {\n schema,\n canonical: UrlQuery.canonical(schema as UrlQuery.FlatQuerySchema) as (\n decoded: DecodedQuery\n ) => string,\n };\n });\n\n/** The node a collection names, or a `QueryError` thrown — a definition-time defect. */\nconst nodeOrThrow = (nodes: Node.NodeRegistry, collection: string): Node.AnyNode => {\n const node = nodes.nodes.get(collection);\n if (node === undefined) {\n throw new QueryError({ message: `Unknown collection: ${collection}`, query: collection });\n }\n return node;\n};\n\n/**\n * The query codec of a collection's `list` endpoint — `include`, `fields[…]`,\n * `sort`, `page[…]` and `filter[…]` exactly as the node graph declares them:\n * the codec {@link parseParams} decodes with, so an effect-jsonapi endpoint\n * served by a derived handler (`RestHandlers.list`) declares the grammar the\n * handler parses when it is passed as `Endpoint.list(R, { query })`.\n * effect-jsonapi's own `filter: true` derives a grammar from the *resource*\n * instead, and the two spell a to-one relationship's filter differently: the\n * resource grammar names the relationship (`filter[category]=c-audio`), the\n * node graph — and every URL the engine emits ({@link canonical}) — names the\n * key field (`filter[categoryId]=c-audio`, as ADR-0029's URLs do). One codec\n * on both sides keeps the endpoint's contract and the handler's parse the\n * same language. Every edge is includable under it, so a resource served\n * with it declares its collection-valued edges `Relationship.many`, never\n * `paginated` (whose `include=` only the resource grammar refuses). Throws a\n * `QueryError` for an unknown collection — a definition-time defect.\n */\nexport const querySchema = (\n nodes: Node.NodeRegistry,\n collection: string\n): Schema.Codec<DecodedQuery, Readonly<Record<string, unknown>>> =>\n codecOf(nodes, nodeOrThrow(nodes, collection)).schema;\n\n/** The decoded shape of a single-resource request's query: `include` and `fields[…]` only. */\nexport interface SingleRowQuery {\n readonly include?: ReadonlyArray<string>;\n readonly fields?: Readonly<Record<string, ReadonlyArray<string>>>;\n}\n\nconst singleRowCodecs = new WeakMap<\n Node.NodeRegistry,\n Map<string, Schema.Codec<SingleRowQuery, Readonly<Record<string, unknown>>>>\n>();\n\n/**\n * The query codec of a collection's `get` endpoint — `include` and\n * `fields[…]` exactly as the node graph declares them, the two parameters a\n * single-resource request takes ({@link singleRowParams}) — for\n * `Endpoint.get(R, { query })`, the counterpart of {@link querySchema}: the\n * endpoint's contract and the derived handler's parse are one grammar on\n * the single-row route too. Throws a `QueryError` for an unknown collection.\n */\nexport const singleRowSchema = (\n nodes: Node.NodeRegistry,\n collection: string\n): Schema.Codec<SingleRowQuery, Readonly<Record<string, unknown>>> => {\n const node = nodeOrThrow(nodes, collection);\n return memoised(\n singleRowCodecs,\n nodes,\n node,\n () =>\n UrlQuery.schema(resourceIn(resourcesOf(nodes), node.type), {\n include: includeOption(node),\n fields: true,\n }) as Schema.Codec<SingleRowQuery, Readonly<Record<string, unknown>>>\n );\n};\n\n// ─── URL → Query.Read ────────────────────────────────────────────────────────\n\n/** A sparse-fieldset projection: attribute names by resource type (ADR-0029 §5). */\nexport type Projection = Readonly<Record<string, ReadonlyArray<string>>>;\n\n/**\n * A parsed URL: the declarative read, the `fields[]` projection beside it,\n * and — from {@link parseRead} of a `/{type}/{id}` path — the row id the\n * path addressed, so the caller knows to write a single-resource document\n * (the read already carries it as `filter[id]`, first 1).\n */\nexport interface ParsedRead {\n readonly read: Query.Read;\n readonly fields?: Projection;\n readonly id?: string;\n}\n\n/** The flat query record: `URLSearchParams` with repeated keys as arrays (as `UrlParams.toRecord` does). */\nconst recordOf = (\n params: URLSearchParams | Readonly<Record<string, string | ReadonlyArray<string>>>\n): Record<string, string | ReadonlyArray<string>> => {\n if (!(params instanceof URLSearchParams)) return { ...params };\n const record: Record<string, string | ReadonlyArray<string>> = {};\n params.forEach((value, key) => {\n const existing = record[key];\n record[key] =\n existing === undefined\n ? value\n : P.isString(existing)\n ? [existing, value]\n : [...existing, value];\n });\n return record;\n};\n\n/**\n * The rejection of one query parameter, in the shape every check here\n * raises (`parameter` names the offending key, so a caller answers 400 with\n * `source.parameter`). Exported for a caller that checks a parsed URL\n * against a declaration of its own — the replica-side writer against the\n * resource it is bound to — and must reject the way the codec does.\n */\nexport const invalidParameter = (\n collection: string,\n parameter: string,\n detail: string\n): QueryError =>\n new QueryError({\n message: `Invalid query for \"${collection}\" (${parameter}): ${detail}`,\n query: collection,\n parameter,\n });\n\nconst invalid = invalidParameter;\n\nconst nodeOf = (\n nodes: Node.NodeRegistry,\n collection: string\n): Effect.Effect<Node.AnyNode, QueryError> => {\n const node = nodes.nodes.get(collection);\n return node === undefined\n ? Effect.fail(\n new QueryError({ message: `Unknown collection: ${collection}`, query: collection })\n )\n : Effect.succeed(node);\n};\n\n/** The `include` tokens of the wire value: the comma form, the repeated key, or both. */\nconst includeTokens = (value: string | ReadonlyArray<string> | undefined): ReadonlyArray<string> =>\n value === undefined\n ? []\n : (P.isString(value) ? [value] : value).flatMap((item) => item.split(\",\"));\n\n/**\n * Check `include` before decoding: every path is one of the node's own\n * edges. A nested path is rejected by decision D1; an undeclared edge is\n * rejected so the caller can rule on it (a façade falls through, ADR-0029\n * §1). The codec would reject both too; the check gives the reason.\n */\nconst checkInclude = (\n node: Node.AnyNode,\n value: string | ReadonlyArray<string> | undefined\n): Effect.Effect<void, QueryError> =>\n failFirst(includeTokens(value), (token) =>\n token.includes(\".\")\n ? Option.some(\n invalid(\n node.type,\n \"include\",\n `nested include path \"${token}\" is not supported; a read includes a node's own edges only (ADR-0028 D1)`\n )\n )\n : node.edges[token] === undefined\n ? Option.some(\n invalid(\n node.type,\n \"include\",\n `\"${token}\" is not an edge of \"${node.type}\" (edges: ${Object.keys(node.edges).join(\", \")})`\n )\n )\n : Option.none()\n );\n\n/** Fail with the first item's error, in order; succeed when no item has one. */\nconst failFirst = <A>(\n items: Iterable<A>,\n errorOf: (item: A) => Option.Option<QueryError>\n): Effect.Effect<void, QueryError> =>\n Option.match(Arr.findFirst(items, errorOf), { onNone: () => Effect.void, onSome: Effect.fail });\n\n/** One segment of a Standard Schema issue path: a key, or an object carrying one. */\ntype PathSegment = PropertyKey | { readonly key: PropertyKey };\n\nconst keyOf = (segment: PathSegment): PropertyKey =>\n P.isObjectOrArray(segment) ? segment.key : segment;\n\n/** The types a read on the node can carry: its own and its edge targets'. */\nconst carriedTypes = (node: Node.AnyNode): ReadonlySet<string> =>\n new Set([node.type, ...Object.values(node.edges).map((edge) => edge.target)]);\n\n/**\n * The rejection of a `fields[type]` projection the read cannot carry, or\n * `undefined` when it can. The codec silently drops such a type; a\n * projection nobody can apply is a client mistake worth a 400, and the same\n * rule keeps {@link canonical} and {@link parseParams} in agreement.\n */\nconst projectionError = (node: Node.AnyNode, type: string): QueryError | undefined => {\n const types = carriedTypes(node);\n return types.has(type)\n ? undefined\n : invalid(\n node.type,\n `fields[${type}]`,\n `\"${type}\" is not a type this read can carry (types: ${[...types].join(\", \")})`\n );\n};\n\n/** Check every `fields[…]` key before decoding (see {@link projectionError}). */\nconst checkFields = (\n node: Node.AnyNode,\n record: Readonly<Record<string, unknown>>\n): Effect.Effect<void, QueryError> =>\n failFirst(Object.keys(record), (key) => {\n const match = /^fields\\[(.*)\\]$/.exec(key);\n return Option.fromUndefinedOr(\n match === null ? undefined : projectionError(node, match[1] ?? \"\")\n );\n });\n\n/**\n * `page[offset]` and `page[after]` are different pagination idioms — one\n * request names one (#209). The schema alone cannot reject the\n * combination (each key decodes fine on its own), so this runs before\n * decoding, the way {@link checkInclude} rejects a nested path.\n */\nconst checkPage = (\n node: Node.AnyNode,\n record: Readonly<Record<string, unknown>>\n): Effect.Effect<void, QueryError> =>\n record[\"page[after]\"] !== undefined && record[\"page[offset]\"] !== undefined\n ? Effect.fail(\n invalid(\n node.type,\n \"page[offset]\",\n `\"page[offset]\" and \"page[after]\" are different pagination idioms; a request names one`\n )\n )\n : Effect.void;\n\n/** The query-string parameter an issue path names: the flat key itself, or `family[member]` for the nested families. */\nconst parameterOf = (path: ReadonlyArray<PathSegment> | undefined): string | undefined => {\n const [head, second] = (path ?? []).map(keyOf);\n if (!P.isString(head)) return undefined;\n return (head === \"fields\" || head === \"page\") && P.isString(second) ? `${head}[${second}]` : head;\n};\n\n/** A codec rejection as a `QueryError` naming the parameter (the issue's path is the flat key). */\nconst decodeError =\n (collection: string) =>\n (error: Schema.SchemaError): QueryError => {\n const issue = SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues[0];\n const parameter = parameterOf(issue?.path);\n return new QueryError({\n message: `Invalid query for \"${collection}\"${parameter === undefined ? \"\" : ` (${parameter})`}: ${issue?.message ?? error.message}`,\n query: collection,\n parameter,\n cause: error,\n });\n };\n\n/** Sort terms as `order` tokens (`name`, `-createdAt`). */\nconst orderOf = (sort: ReadonlyArray<SortTerm>): ReadonlyArray<string> =>\n sort.map((term) => (term.direction === \"desc\" ? `-${term.field}` : term.field));\n\n/**\n * The declarative read a decoded query describes, or the typed `QueryError`\n * {@link fromFilterAst} fails with for `decoded.filter` — unreachable in\n * practice (the module doc's note on this call site), carried as a `Result`\n * rather than thrown so {@link parseParams}'s `Effect.Effect<_, QueryError>`\n * contract holds even if that precondition is ever violated.\n */\nconst readOf = (\n collection: string,\n decoded: DecodedQuery\n): Result.Result<Query.Read, QueryError> => {\n const whereResult =\n decoded.filter === undefined\n ? Result.succeed<Predicate.Predicate | undefined>(undefined)\n : fromFilterAst(decoded.filter);\n return Result.map(whereResult, (where) => ({\n collection,\n ...(where === undefined ? {} : { where }),\n ...(decoded.include === undefined || Arr.isReadonlyArrayEmpty(decoded.include)\n ? {}\n : { include: Object.fromEntries(decoded.include.map((edge) => [edge, true as const])) }),\n ...(decoded.sort === undefined || Arr.isReadonlyArrayEmpty(decoded.sort)\n ? {}\n : { order: orderOf(decoded.sort) }),\n ...(decoded.page?.limit === undefined ? {} : { first: decoded.page.limit }),\n ...(decoded.page?.after === undefined ? {} : { after: decoded.page.after }),\n ...(decoded.page?.offset === undefined ? {} : { offset: decoded.page.offset }),\n }));\n};\n\n/**\n * Parse a collection's query parameters into a read. `include`, `fields`,\n * `sort`, `page` and `filter` are decoded with the node-derived query codec\n * (unknown filter fields, undeclared operators, literals of the wrong kind,\n * unsortable fields, unknown sparse fields and nested include paths all\n * fail with a `QueryError` naming the parameter) and mapped onto the read;\n * `fields[]` rides beside it as the projection.\n */\nexport const parseParams = (\n nodes: Node.NodeRegistry,\n collection: string,\n params: URLSearchParams | Readonly<Record<string, string | ReadonlyArray<string>>>\n): Effect.Effect<ParsedRead, QueryError> =>\n Effect.gen(function* () {\n const node = yield* nodeOf(nodes, collection);\n const record = recordOf(params);\n yield* checkInclude(node, record[\"include\"]);\n yield* checkFields(node, record);\n yield* checkPage(node, record);\n const decoded = yield* Schema.decodeUnknownEffect(codecOf(nodes, node).schema)(record).pipe(\n Effect.mapError(decodeError(collection))\n );\n const read = yield* Effect.fromResult(readOf(collection, decoded));\n return {\n read,\n ...(decoded.fields === undefined ? {} : { fields: decoded.fields }),\n };\n });\n\n/** A path segment percent-decoded, or a `QueryError` naming `id` when it is malformed. */\nconst decodeId = (collection: string, segment: string): Effect.Effect<string, QueryError> =>\n Effect.try({\n try: () => decodeURIComponent(segment),\n catch: () => invalid(collection, \"id\", `path segment \"${segment}\" is not percent-encoded`),\n });\n\n/**\n * The resource a request path addresses: `…/{type}/{id}` (one row) when the\n * segment before the last names a node, else `…/{type}` (a listing) when\n * the last does. A node named earlier on the path — the spec's related\n * resource (`/products/p-1/variants`) and relationship (`…/relationships/…`)\n * URLs — is not a read this parser serves (read the related collection\n * with its key filter instead), so it is rejected rather than misread as a\n * whole-collection listing.\n */\nconst locate = (\n nodes: Node.NodeRegistry,\n url: URL\n): Effect.Effect<{ readonly collection: string; readonly id?: string }, QueryError> => {\n const segments = url.pathname.split(\"/\").filter((segment) => Str.isNonEmpty(segment));\n const last = segments.at(-1);\n const previous = segments.at(-2);\n if (previous !== undefined && last !== undefined && nodes.nodes.has(previous)) {\n return Effect.map(decodeId(previous, last), (id) => ({ collection: previous, id }));\n }\n const message = segments.slice(0, -2).some((segment) => nodes.nodes.has(segment))\n ? `Nested resource path \"${url.pathname}\" is not a read; filter the related collection by its key instead`\n : last !== undefined && nodes.nodes.has(last)\n ? undefined\n : `No collection on path \"${url.pathname}\"`;\n return message === undefined && last !== undefined\n ? Effect.succeed({ collection: last })\n : Effect.fail(\n new QueryError({\n message: message ?? `No collection on path \"${url.pathname}\"`,\n query: url.pathname,\n })\n );\n};\n\n/**\n * The query of a single-row read — `filter[id]=…`, first 1 (ADR-0029 §3) —\n * from a `/{type}/{id}` request's own query, which takes `include` and\n * `fields[…]` only. Shared by {@link parseRead} and the derived `get`\n * handler, which has the id from the route instead of the path.\n */\nexport const singleRowParams = (\n collection: string,\n id: string,\n params: URLSearchParams\n): Effect.Effect<URLSearchParams, QueryError> => {\n const extra = Arr.findFirst(\n params.keys(),\n (key) => key !== \"include\" && !key.startsWith(\"fields[\")\n );\n if (Option.isSome(extra)) {\n return Effect.fail(\n invalid(\n collection,\n extra.value,\n `a single-resource request takes \"include\" and \"fields[…]\" only`\n )\n );\n }\n const widened = new URLSearchParams(params);\n // Through the grammar's own encoder, so an id carrying `,` or `\\` is\n // escaped as a literal rather than read as a list.\n widened.set(\"filter[id]\", flatFilter(Filter.eq(\"id\", id))[\"filter[id]\"] ?? \"\");\n widened.set(\"page[limit]\", \"1\");\n return Effect.succeed(widened);\n};\n\n/**\n * Parse a request URL into a read. The collection is the path's last\n * segment that names a node (`/api/products?…`, any prefix), or the\n * segment before a row id (`/api/products/p-1?…`, which reads as\n * `filter[id]=p-1` with `first` 1). The query is then {@link parseParams}.\n */\nexport const parseRead = (\n nodes: Node.NodeRegistry,\n url: string | URL\n): Effect.Effect<ParsedRead, QueryError> =>\n Effect.gen(function* () {\n const parsed = P.isString(url) ? new URL(url, \"http://localhost\") : url;\n const located = yield* locate(nodes, parsed);\n const params =\n located.id === undefined\n ? parsed.searchParams\n : yield* singleRowParams(located.collection, located.id, parsed.searchParams);\n const result = yield* parseParams(nodes, located.collection, params);\n return located.id === undefined ? result : { ...result, id: located.id };\n });\n\n// ─── Query.Read → canonical string ───────────────────────────────────────────\n\nconst noUrlForm = (collection: string, detail: string): QueryError =>\n new QueryError({\n message: `Read on \"${collection}\" has no URL form: ${detail}`,\n query: collection,\n });\n\n/** The plan's edge selects as include paths, in code-point order (the include set is unordered). */\nconst includeOf = (collection: string, edges: Query.Plan[\"edges\"]): ReadonlyArray<string> =>\n edges\n .map((edge) => {\n if (edge.first !== undefined) {\n throw noUrlForm(\n collection,\n `the per-edge window on \"${edge.edge}\" (include: { first }) has no query parameter`\n );\n }\n return edge.edge;\n })\n .toSorted((a, b) => Predicate.compareText(a, b));\n\nconst astOf = (collection: string, predicate: Predicate.Predicate): Filter.Node =>\n Option.getOrThrowWith(toFilterAst(predicate), () =>\n noUrlForm(collection, `\"${predicate._tag}\" carries an Exists node or a null literal`)\n );\n\n/** Passes {@link filterOf} allows the normal form to settle in; two suffice in practice. */\nconst NORMAL_FORM_PASSES = 8;\n\n/**\n * The plan's root predicate as a filter AST in normal form; `undefined` for\n * the whole collection. Two normalisations meet here: {@link foldConstants}\n * on the engine side (constants, singleton groups) and `Filter.normalise`\n * on the grammar side (member order, deduplication, literal-list order).\n * Each can hand the other new work — deduplicating `Or(x, x)` leaves a\n * singleton group the fold then collapses — so the result is their\n * fixpoint, which makes {@link canonical} idempotent: parsing a canonical\n * string and canonicalising again gives the same string.\n */\nconst filterOf = (\n collection: string,\n declaration: Filter.LiteralCodecs,\n where: Predicate.Predicate\n): Filter.Node | undefined => {\n const settle = (predicate: Predicate.Predicate, pass: number): Option.Option<Filter.Node> => {\n if (pass >= NORMAL_FORM_PASSES) return Option.some(astOf(collection, predicate));\n if (isTrue(predicate)) return Option.none();\n const ast = Filter.normalise(astOf(collection, predicate), declaration);\n // Safe by construction, not merely by convention: `ast` was normalised\n // from `astOf`'s output, whose every literal is copied verbatim from a\n // `Predicate.Literal` (`toFilterAst`'s `Compare` case) — already a wire\n // scalar, so `literalOf` cannot reject it. Defect-by-contract for this\n // one call site; the module doc explains why the exported function\n // still returns a typed failure for its general contract.\n const back = fromFilterAst(ast);\n if (Result.isFailure(back)) throw back.failure;\n const next = foldConstants(back.success);\n if (JSON.stringify(next) === JSON.stringify(predicate)) return Option.some(ast);\n return settle(next, pass + 1);\n };\n return Option.getOrUndefined(settle(foldConstants(where), 0));\n};\n\n/**\n * The decoded query a compiled read denotes. The page comes from the\n * **read**, not the compiled window: an offset read's `root.limit`\n * absorbs `offset` (`Query.plan`'s `rootLimit`, #209), so reconstructing\n * `page[limit]`/`page[after]` from `root` would leak the inflated fetch\n * size into the URL instead of the request the caller actually made.\n */\nconst decodedOf = (\n compiled: Query.Plan,\n declaration: Filter.LiteralCodecs,\n fields: Projection | undefined,\n read: Query.Read\n): DecodedQuery => {\n const { root } = compiled;\n const include = includeOf(root.collection, compiled.edges);\n const filter = filterOf(root.collection, declaration, root.where);\n const page =\n read.offset === undefined\n ? {\n ...(root.limit === undefined ? {} : { limit: root.limit }),\n ...(root.cursor === undefined ? {} : { after: root.cursor }),\n }\n : { ...(read.first === undefined ? {} : { limit: read.first }), offset: read.offset };\n return {\n ...(Arr.isReadonlyArrayEmpty(include) ? {} : { include }),\n ...(fields === undefined ? {} : { fields: projectionOf(fields) }),\n ...(filter === undefined ? {} : { filter }),\n ...(Arr.isReadonlyArrayEmpty(root.orderBy) ? {} : { sort: root.orderBy }),\n ...(R.isEmptyReadonlyRecord<string, unknown>(page) ? {} : { page }),\n };\n};\n\n/** A projection with each type's field list in code-point order (a set). */\nconst projectionOf = (fields: Projection): Projection =>\n Object.fromEntries(\n Object.entries(fields).map(([type, names]) => [type, names.toSorted(Predicate.compareText)])\n );\n\n/**\n * The canonical URL of a read — `/{collection}?{query}` (no API prefix;\n * `parseRead` accepts it back) — through effect-jsonapi's canonical encoder\n * over the compiled plan: one string per plan, whatever spelling the read\n * used (`where` as a map or a predicate, conjuncts in any order, `True`\n * conjuncts). It is the subscription identity of ADR-0029 §2. Throws a\n * `QueryError` for a read the plan or the grammar refuses: an unknown\n * collection or edge, a field outside the filterable set, an `Exists`, a\n * `null` literal, or a per-edge window. A `fields[]` projection rides\n * along when given.\n */\nexport const canonical = (\n nodes: Node.NodeRegistry,\n read: Query.Read,\n fields?: Projection\n): string => {\n const compiled = Query.plan(nodes, read);\n const node = nodes.nodes.get(read.collection);\n if (node === undefined) {\n throw new QueryError({\n message: `Unknown collection: ${read.collection}`,\n query: read.collection,\n });\n }\n Object.keys(fields ?? {}).forEach((type) => {\n const error = projectionError(node, type);\n if (error !== undefined) throw error;\n });\n const encoded = Result.try({\n try: () => {\n const declaration = Resource.filterable(resourceIn(resourcesOf(nodes), node.type));\n return codecOf(nodes, node).canonical(decodedOf(compiled, declaration, fields, read));\n },\n catch: (error) =>\n error instanceof QueryError\n ? error\n : new QueryError({\n message: `Read on \"${read.collection}\" has no URL form: ${error instanceof Error ? error.message : String(error)}`,\n query: read.collection,\n cause: error,\n }),\n });\n if (Result.isFailure(encoded)) throw encoded.failure;\n const query = encoded.success;\n return query === \"\" ? `/${read.collection}` : `/${read.collection}?${query}`;\n};\n\n/** {@link canonical} as an effect: the `QueryError` it throws becomes a typed failure. */\nconst tryCanonical = (\n nodes: Node.NodeRegistry,\n read: Query.Read\n): Effect.Effect<string, QueryError> =>\n Effect.suspend(() => {\n const result = Result.try(() => canonical(nodes, read));\n if (Result.isSuccess(result)) return Effect.succeed(result.success);\n return result.failure instanceof QueryError\n ? Effect.fail(result.failure)\n : Effect.die(result.failure);\n });\n\n/**\n * The `Client.UrlReads` seam over this bridge (#159, ADR-0029 §2): pass as\n * `urls` to `Client.make` / `Client.connect` / `Client.fromView` so\n * `client.subscribe(url)` parses through {@link parseRead} and keys the pin\n * by {@link canonical}, and to an engine host (`ServiceWorkerHost.run`) so\n * a page with no Client can register by URL. The `fields[]` projection a\n * URL carries is dropped: it never changes what a subscription syncs\n * (ADR-0029 §5), so two URLs differing only in `fields[]` are one\n * subscription.\n */\nexport const urlReads = (nodes: Node.NodeRegistry): Client.UrlReads => ({\n parse: (url) => Effect.map(parseRead(nodes, url), (parsed) => parsed.read),\n canonical: (read) => tryCanonical(nodes, read),\n});\n\n// ─── The exact encoder ───────────────────────────────────────────────────────\n\n/** The attribute schema of a field whose literals have the JS type. */\nconst scalarSchema = (type: \"string\" | \"number\" | \"boolean\"): Schema.Top =>\n type === \"string\" ? Schema.String : type === \"number\" ? Schema.Number : Schema.Boolean;\n\n/** Collect the literal JS types each field of a tree is compared with (mutates `types`). */\nconst collectLiteralTypes = (ast: Filter.Node, types: Map<string, Set<string>>): void => {\n const add = (field: string, value: unknown) => {\n const set = types.get(field) ?? new Set<string>();\n set.add(typeof value);\n types.set(field, set);\n };\n switch (ast._tag) {\n case \"Compare\":\n return add(ast.field, ast.value);\n case \"In\":\n case \"NotIn\":\n return ast.values.forEach((value) => add(ast.field, value));\n case \"IsNull\":\n return void (types.get(ast.field) ?? types.set(ast.field, new Set()));\n case \"And\":\n case \"Or\":\n return ast.members.forEach((member) => collectLiteralTypes(member, types));\n case \"Not\":\n return collectLiteralTypes(ast.member, types);\n }\n};\n\n/** The one JS type each field of a tree is compared with (`string` for a field only null-tested). */\nconst literalTypesOf = (ast: Filter.Node): ReadonlyMap<string, string> => {\n const types = new Map<string, Set<string>>();\n collectLiteralTypes(ast, types);\n const resolved = new Map<string, string>();\n types.forEach((kinds, field) => {\n const [kind, ...rest] = kinds;\n if (Arr.isReadonlyArrayNonEmpty(rest)) {\n throw new QueryError({\n message: `Field \"${field}\" is compared with literals of several types (${[...kinds].join(\", \")}); ADR-0028 rule (d) admits one`,\n parameter: `filter[${field}]`,\n });\n }\n resolved.set(field, kind ?? \"string\");\n });\n return resolved;\n};\n\n/** The flat `filter[...]` codec of an untyped declaration. */\ntype FlatFilterCodec = Schema.Codec<Filter.Node, Readonly<Record<string, string>>>;\n\nconst flatFilterCodecs = new Map<string, FlatFilterCodec>();\n\n/**\n * The codec for encoding a tree without a node graph: each field it names\n * admits every operator, typed by the JS type of its literals. The wire\n * form of a scalar does not depend on its declared kind, so this encodes\n * exactly what the typed codec would. Memoised by the field → type\n * signature, since a backend encodes the same shapes on every pull.\n */\nconst flatFilterCodecOf = (ast: Filter.Node): FlatFilterCodec => {\n const types = literalTypesOf(ast);\n const signature = [...types]\n .map(([field, type]) => `${field}:${type}`)\n .toSorted(Predicate.compareText)\n .join(\"\\n\");\n const cached = flatFilterCodecs.get(signature);\n if (cached !== undefined) return cached;\n const attributes = R.fromIterableWith(types, ([field, type]): [string, Schema.Top] => [\n field,\n scalarSchema(type as \"string\" | \"number\" | \"boolean\").pipe(Filter.able()),\n ]);\n const codec = UrlQuery.Filter(Resource.make(\"query\", { attributes })) as FlatFilterCodec;\n flatFilterCodecs.set(signature, codec);\n return codec;\n};\n\n/**\n * The canonical flat `filter[...]` record of a filter AST — the grammar's\n * own encoder (`Query.Filter`), so the shorthand, the group form, escaping\n * and member order are effect-jsonapi's byte for byte.\n */\nexport const flatFilter = (ast: Filter.Node): Readonly<Record<string, string>> =>\n Schema.encodeSync(flatFilterCodecOf(ast))(ast);\n\n/**\n * Serialize sort terms into the JSON:API `sort` value (`-field,field`) through\n * the library's `Query.Sort` codec, so the wire encoding matches the spec's\n * descending-prefix convention by construction.\n *\n * Since effect-jsonapi 0.15 the codec's encoded side is `Repeatable`\n * (`string | ReadonlyArray<string>`) because it also decodes the repeated-key\n * spelling; its encoder emits the comma form, and an array is joined into\n * that same form rather than trusted to never appear.\n */\nconst encodeSort = (terms: ReadonlyArray<SortTerm>): string => {\n const encoded = Schema.encodeSync(UrlQuery.Sort(terms.map((term) => term.field)))(\n terms.map((term) => ({ field: term.field, direction: term.direction }))\n );\n return P.isString(encoded) ? encoded : encoded.join(\",\");\n};\n\n/**\n * Build the JSON:API query string (with its leading `?`, or `` when empty)\n * for `include` / `fields` / `filter` / `sort` / `page`, in the canonical\n * family order and percent-encoding (`Query.serialise`). `filter` is a\n * filter AST, encoded exactly through {@link flatFilter}.\n */\nexport const buildQueryString = (options?: JsonApiRequestOptions): string => {\n if (options === undefined) return \"\";\n const pairs: Array<UrlQuery.Pair> = [];\n if (options.include && Arr.isReadonlyArrayNonEmpty(options.include))\n pairs.push([\"include\", options.include.join(\",\")]);\n pairs.push(\n ...Object.entries(options.fields ?? {}).map(([type, names]): UrlQuery.Pair => [\n `fields[${type}]`,\n names.join(\",\"),\n ])\n );\n if (options.filter !== undefined) pairs.push(...Object.entries(flatFilter(options.filter)));\n if (options.sort && Arr.isReadonlyArrayNonEmpty(options.sort))\n pairs.push([\"sort\", encodeSort(options.sort)]);\n pairs.push(\n ...Object.entries(options.page ?? {}).flatMap(([key, value]): Array<UrlQuery.Pair> =>\n value === undefined ? [] : [[`page[${key}]`, String(value)]]\n )\n );\n const query = UrlQuery.serialise(pairs);\n return query === \"\" ? \"\" : `?${query}`;\n};\n\n/**\n * Encode a subset into a JSON:API query string (incl. leading `?`, or ``),\n * or `None` when no row can match it (the request is skipped). A predicate\n * without a URL form is a `QueryError`: the backend fails closed.\n */\nexport interface QueryEncoder {\n readonly encode: (subset: Subset.Subset) => Effect.Effect<Option.Option<string>, QueryError>;\n}\n\n/**\n * The request options a subset encodes to, or `None` when its predicate\n * folds to false. The filter is the whole predicate, constants folded;\n * `orderBy` becomes `sort`. Limit and cursor are not pushed: the window is\n * applied locally over the exact filter. Throws a `QueryError` for a\n * predicate with no URL form (`Exists`, a `null` literal).\n */\nexport const toRequestOptions = (subset: Subset.Subset): Option.Option<JsonApiRequestOptions> => {\n const where = foldConstants(subset.where);\n if (isFalse(where)) return Option.none();\n const filter = isTrue(where)\n ? undefined\n : Option.getOrThrowWith(toFilterAst(where), () =>\n noUrlForm(subset.collection, \"the predicate carries an Exists node or a null literal\")\n );\n const sort = subset.orderBy.map((term) => ({ field: term.field, direction: term.direction }));\n return Option.some({\n ...(filter === undefined ? {} : { filter }),\n ...(Arr.isReadonlyArrayEmpty(sort) ? {} : { sort }),\n });\n};\n\n/** The shipped encoder: exact under ADR-0028 (see the module doc). */\nexport const defaultEncoder: QueryEncoder = {\n encode: (subset) =>\n Effect.try({\n try: () => Option.map(toRequestOptions(subset), buildQueryString),\n catch: (error) =>\n error instanceof QueryError\n ? error\n : new QueryError({\n message: `Subset on \"${subset.collection}\" could not be encoded: ${error instanceof Error ? error.message : String(error)}`,\n query: subset.collection,\n cause: error,\n }),\n }),\n};\n","/**\n * CollectionLoader\n *\n * The JSON:API package's place in the v2 model (ADR-0008): a *collection\n * loader*. A JSON:API `type` is a collection, each resource's `id` is a row\n * id, and a resource maps to a row value (attributes + resolved\n * relationship references). Loaders read documents into collection rows;\n * they do not own a sync model of their own.\n *\n * This is a read-side adapter. Writes in the v2 engine are named mutators\n * (ADR-0008), not ad-hoc REST calls, so the former conflict-strategy\n * push/pull helpers are gone. To sync a JSON:API upstream, back a `Backend`\n * (or a read-only collection) with `load`/`loadOne` and emit row versions\n * from the upstream's own change token (ETag, `meta.version`, …).\n */\n\nimport * as Arr from \"effect/Array\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as P from \"effect/Predicate\";\nimport * as R from \"effect/Record\";\nimport * as Result from \"effect/Result\";\nimport * as HttpClient from \"effect/http/HttpClient\";\nimport type * as HttpClientError from \"effect/http/HttpClientError\";\nimport * as HttpClientRequest from \"effect/http/HttpClientRequest\";\nimport type * as HttpClientResponse from \"effect/http/HttpClientResponse\";\nimport { ApiError, ParseError } from \"./errors.js\";\nimport { buildQueryString } from \"./JsonApiQuery.js\";\nimport { decodeDocument } from \"./schema.js\";\nimport type {\n JsonApiDocument,\n JsonApiRequestOptions,\n ResourceIdentifier,\n ResourceObject,\n} from \"./types.js\";\n\n// ─── Row mapping ─────────────────────────────────────────────────────────────\n\n/** A relationship as it lands in a row value: linkage only, no documents. */\nexport type RelationshipRef =\n | { readonly type: string; readonly id: string }\n | ReadonlyArray<{ readonly type: string; readonly id: string }>\n | null;\n\n/** The value a JSON:API resource takes as a collection row. */\nexport interface ResourceValue {\n readonly type: string;\n readonly id: string;\n readonly attributes: Record<string, unknown>;\n readonly relationships: Record<string, RelationshipRef>;\n}\n\n/** A collection row materialized from a resource: (collection, id, value). */\nexport interface CollectionRow {\n readonly collection: string;\n readonly id: string;\n readonly value: ResourceValue;\n}\n\n/** The rows a document yields: its primary data and its compound `included`. */\nexport interface LoadedRows {\n readonly rows: ReadonlyArray<CollectionRow>;\n readonly included: ReadonlyArray<CollectionRow>;\n}\n\nconst identifier = (ref: ResourceIdentifier) => ({ type: ref.type, id: ref.id });\n\n/**\n * `Array.isArray` types its guard as `any[]`, so it does not narrow the\n * `ReadonlyArray` members the schema-derived document types use. This guard\n * narrows them correctly.\n */\nconst isReadonlyArray = (value: unknown): value is ReadonlyArray<unknown> => Array.isArray(value);\n\n/** Map a resource (or bare identifier) to a collection row. */\nexport const resourceToRow = (resource: ResourceObject | ResourceIdentifier): CollectionRow => {\n const full = resource as ResourceObject;\n const relationships = R.filterMap(full.relationships ?? {}, ({ data }) =>\n data === undefined\n ? Result.failVoid\n : Result.succeed<RelationshipRef>(\n data === null ? null : isReadonlyArray(data) ? data.map(identifier) : identifier(data)\n )\n );\n return {\n collection: resource.type,\n id: resource.id,\n value: {\n type: resource.type,\n id: resource.id,\n attributes: full.attributes ?? {},\n relationships,\n },\n };\n};\n\nconst dataResources = (\n data: JsonApiDocument[\"data\"]\n): ReadonlyArray<ResourceObject | ResourceIdentifier> =>\n data === undefined || data === null ? [] : isReadonlyArray(data) ? data : [data];\n\n/** Map a whole document to its primary rows and its `included` rows. */\nexport const documentToRows = (document: JsonApiDocument): LoadedRows => ({\n rows: dataResources(document.data).map(resourceToRow),\n included: (document.included ?? []).map(resourceToRow),\n});\n\n// ─── Loading ─────────────────────────────────────────────────────────────────\n\n/** The JSON:API endpoint a loader reads from. */\nexport interface JsonApiSource {\n readonly baseUrl: string;\n}\n\n/** The {@link JsonApiSource} service loaders read from. */\nexport const JsonApiSource = Context.Service<JsonApiSource>(\n \"@thomasfosterau/legation-jsonapi/JsonApiSource\"\n);\n\nconst jsonApiHeaders = {\n \"Content-Type\": \"application/vnd.api+json\",\n Accept: \"application/vnd.api+json\",\n} as const;\n\n/** The query string of a request's options; see `JsonApiQuery.buildQueryString`. */\nexport { buildQueryString };\n\n/** Validate a JSON:API response into a document (non-2xx / `errors` → ApiError). */\nexport const parseResponse = (\n response: HttpClientResponse.HttpClientResponse\n): Effect.Effect<JsonApiDocument, ParseError | ApiError | HttpClientError.HttpClientError> =>\n Effect.gen(function* () {\n if (response.status < 200 || response.status >= 300) {\n const body = yield* response.json.pipe(Effect.orElseSucceed(() => undefined));\n const candidate = P.isObjectOrArray(body) ? (body as JsonApiDocument).errors : undefined;\n const errors = Array.isArray(candidate) ? candidate : [];\n return yield* new ApiError({ message: `HTTP ${response.status}`, errors });\n }\n const json = yield* response.json.pipe(\n Effect.mapError((cause) => new ParseError({ message: \"Failed to parse JSON body\", cause }))\n );\n const document = yield* decodeDocument(json);\n if (document.errors && Arr.isReadonlyArrayNonEmpty(document.errors)) {\n return yield* new ApiError({ message: \"Document carried errors\", errors: document.errors });\n }\n return document;\n });\n\nconst get = (url: string) =>\n HttpClientRequest.get(url).pipe(HttpClientRequest.setHeaders(jsonApiHeaders));\n\n/** Load a collection (`GET /{type}`) into rows. */\nexport const load = (\n type: string,\n options?: JsonApiRequestOptions\n): Effect.Effect<\n LoadedRows,\n ParseError | ApiError | HttpClientError.HttpClientError,\n HttpClient.HttpClient | JsonApiSource\n> =>\n Effect.gen(function* () {\n const source = yield* JsonApiSource;\n const client = yield* HttpClient.HttpClient;\n const url = `${source.baseUrl}/${type}${buildQueryString(options)}`;\n const response = yield* Effect.scoped(client.execute(get(url)));\n return documentToRows(yield* parseResponse(response));\n });\n\n/** Load a single resource (`GET /{type}/{id}`); `undefined` if absent. */\nexport const loadOne = (\n type: string,\n id: string,\n options?: JsonApiRequestOptions\n): Effect.Effect<\n CollectionRow | undefined,\n ParseError | ApiError | HttpClientError.HttpClientError,\n HttpClient.HttpClient | JsonApiSource\n> =>\n Effect.gen(function* () {\n const source = yield* JsonApiSource;\n const client = yield* HttpClient.HttpClient;\n const url = `${source.baseUrl}/${type}/${id}${buildQueryString(options)}`;\n const response = yield* Effect.scoped(client.execute(get(url)));\n return documentToRows(yield* parseResponse(response)).rows[0];\n });\n","/**\n * Convention\n *\n * Convention-first discovery of a JSON:API resource surface from an app's\n * Effect `HttpApi` (the happy path: \"bring a JSON:API api, get sync\"). We\n * reflect the api's endpoints and classify each one by HTTP method + path\n * into a JSON:API role, so no per-endpoint annotation is required:\n *\n * | method | path shape | role |\n * | ------- | --------------- | -------- |\n * | GET | `/{type}` | list |\n * | GET | `/{type}/:id` | getOne |\n * | POST | `/{type}` | create |\n * | PATCH | `/{type}/:id` | update |\n * | PUT | `/{type}/:id` | update |\n * | DELETE | `/{type}/:id` | delete |\n *\n * The resource `type` (the collection name) is the last static path segment\n * (the segment before a trailing `:id` param, or the final segment). Any\n * prefix (`/api`, version segments) is ignored. Endpoints that don't fit the\n * table — nested routes, RPCs, custom actions — are simply not part of the\n * derived CRUD surface; the app can still call them directly.\n *\n * One endpoint is recognised structurally rather than by path: an atomic\n * operations endpoint (the JSON:API Atomic Operations extension, e.g.\n * effect-jsonapi's `Endpoint.operations`, conventionally `POST /operations`)\n * is any endpoint whose request payload is an `atomic:operations` document.\n * By path shape alone it would read as `create` on a phantom `operations`\n * resource, so `reflectResources` skips it and `reflectAtomic` reports it\n * instead — the backend then pushes a whole batch as one request.\n */\n\nimport * as Iterable from \"effect/Iterable\";\nimport type * as SchemaAST from \"effect/SchemaAST\";\nimport * as Str from \"effect/String\";\nimport * as HttpApi from \"effect/http-api/HttpApi\";\nimport type * as HttpApiEndpoint from \"effect/http-api/HttpApiEndpoint\";\nimport type * as HttpApiGroup from \"effect/http-api/HttpApiGroup\";\n\n/** A JSON:API role a CRUD endpoint plays for one resource type. */\nexport type Operation = \"list\" | \"getOne\" | \"create\" | \"update\" | \"delete\";\n\n/** A reflected endpoint we can address on the app's HttpApi. */\nexport interface EndpointRef {\n readonly groupId: string;\n readonly name: string;\n readonly method: string;\n /** Route template as declared, e.g. `/todos/:id`. */\n readonly path: string;\n}\n\n/** The CRUD endpoints discovered for one resource type (collection). */\nexport interface ResourceEndpoints {\n readonly type: string;\n readonly list?: EndpointRef;\n readonly getOne?: EndpointRef;\n readonly create?: EndpointRef;\n readonly update?: EndpointRef;\n readonly delete?: EndpointRef;\n}\n\n/** Resource endpoints keyed by type (collection name). */\nexport type ResourceMap = ReadonlyMap<string, ResourceEndpoints>;\n\n/** A route template's segments, empty ones dropped (`/todos/:id` is `[\"todos\", \":id\"]`). */\nexport const segmentsOf = (path: string): ReadonlyArray<string> =>\n path.split(\"/\").filter((segment) => Str.isNonEmpty(segment));\n\n/** Whether a template segment is a path parameter (`:id`). */\nexport const isParam = (segment: string): boolean => segment.startsWith(\":\");\n\n/** Map an HTTP method + whether the route has a trailing id to a CRUD role. */\nconst roleOf = (method: string, hasId: boolean): Operation | undefined => {\n switch (method.toUpperCase()) {\n case \"GET\":\n return hasId ? \"getOne\" : \"list\";\n case \"POST\":\n return hasId ? undefined : \"create\";\n case \"PATCH\":\n case \"PUT\":\n return hasId ? \"update\" : undefined;\n case \"DELETE\":\n return hasId ? \"delete\" : undefined;\n default:\n return undefined;\n }\n};\n\n/**\n * Classify a (method, path) into a resource type + role, or `undefined` if\n * it isn't a conventional JSON:API CRUD route — `/{type}` or `/{type}/:id`,\n * where the type is a static segment and the only param is a trailing id\n * (nested routes like `/todos/:id/comments` are not CRUD on a single type).\n */\nexport const classify = (\n method: string,\n path: string\n): { readonly type: string; readonly operation: Operation } | undefined => {\n const segments = segmentsOf(path);\n const last = segments.at(-1);\n if (last === undefined) return undefined;\n\n const hasId = isParam(last);\n const type = hasId ? segments[segments.length - 2] : last;\n if (type === undefined || isParam(type)) return undefined;\n const params = segments.filter(isParam);\n if (params.length > 1 || (params.length === 1 && !hasId)) return undefined;\n\n const operation = roleOf(method, hasId);\n return operation === undefined ? undefined : { type, operation };\n};\n\n/** The top-level member that makes a request an atomic operations document. */\nconst ATOMIC_OPERATIONS_MEMBER = \"atomic:operations\";\n\n/** Depth bound for walking a payload schema's unions and suspensions. */\nconst MEMBER_WALK_DEPTH = 8;\n\n/**\n * Whether a schema is (or, through unions and suspensions, may be) an object\n * with a top-level `atomic:operations` member.\n */\nconst hasAtomicMember = (ast: SchemaAST.AST, depth = 0): boolean => {\n if (depth > MEMBER_WALK_DEPTH) return false;\n switch (ast._tag) {\n case \"Objects\":\n return ast.propertySignatures.some((property) => property.name === ATOMIC_OPERATIONS_MEMBER);\n case \"Union\":\n return ast.types.some((member) => hasAtomicMember(member, depth + 1));\n case \"Suspend\":\n return hasAtomicMember(ast.thunk(), depth + 1);\n default:\n return false;\n }\n};\n\n/**\n * Whether an endpoint takes an `atomic:operations` request document: some\n * payload schema (any content type) is an object with a top-level\n * `atomic:operations` member, possibly one arm of a union. This is what\n * makes an endpoint the atomic operations endpoint — not its path, which is\n * configurable.\n */\nexport const isAtomicEndpoint = (endpoint: HttpApiEndpoint.Top): boolean =>\n Iterable.some(endpoint.payload.values(), ({ schemas }) =>\n Iterable.some(schemas, (schema) => hasAtomicMember(schema.ast))\n );\n\nconst refOf = (group: HttpApiGroup.Top, endpoint: HttpApiEndpoint.Top): EndpointRef => ({\n groupId: group.identifier,\n name: endpoint.identifier,\n method: endpoint.method,\n path: endpoint.path,\n});\n\n/**\n * Reflect an `HttpApi` into its JSON:API resource surface. The first endpoint\n * matching each (type, role) wins; later duplicates are ignored. An atomic\n * operations endpoint is never a resource (see `reflectAtomic`).\n */\nexport const reflectResources = <Id extends string, Groups extends HttpApiGroup.Constraint>(\n api: HttpApi.HttpApi<Id, Groups>\n): ResourceMap => {\n const resources = new Map<\n string,\n { type: string } & { -readonly [K in Operation]?: EndpointRef }\n >();\n\n HttpApi.reflect(api, {\n onGroup: () => {},\n onEndpoint: ({ group, endpoint }) => {\n if (isAtomicEndpoint(endpoint)) return;\n const role = classify(endpoint.method, endpoint.path);\n if (role === undefined) return;\n const existing = resources.get(role.type) ?? { type: role.type };\n if (existing[role.operation] !== undefined) return;\n existing[role.operation] = refOf(group, endpoint);\n resources.set(role.type, existing);\n },\n });\n\n return resources;\n};\n\n/**\n * Reflect an `HttpApi`'s atomic operations endpoint, if it declares one: the\n * first endpoint whose request payload is an `atomic:operations` document.\n * `JsonApiSync` uses it to push a batch as one all-or-nothing request.\n */\nexport const reflectAtomic = <Id extends string, Groups extends HttpApiGroup.Constraint>(\n api: HttpApi.HttpApi<Id, Groups>\n): EndpointRef | undefined => {\n let atomic: EndpointRef | undefined;\n HttpApi.reflect(api, {\n onGroup: () => {},\n onEndpoint: ({ group, endpoint }) => {\n if (atomic === undefined && isAtomicEndpoint(endpoint)) atomic = refOf(group, endpoint);\n },\n });\n return atomic;\n};\n","/**\n * Derive\n *\n * Turn a discovered JSON:API resource surface (Convention.ts) into the\n * engine's shared model: one `Collection` per resource type, and the three\n * CRUD mutators (create / update / delete) per type that has the matching\n * endpoint. Only the *client* (optimistic) handlers live here — they write\n * the overlay; the authoritative side is JsonApiBackend.ts, which replays\n * the same intents as HTTP calls.\n *\n * Rows are stored as the loader's `ResourceValue` (type, id, attributes,\n * relationship linkage), so the derived collections line up exactly with\n * what `CollectionLoader.documentToRows` produces on the read path.\n */\n\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\nimport { Collection, Mutator } from \"@thomasfosterau/legation\";\nimport type { RelationshipRef, ResourceValue } from \"./CollectionLoader.js\";\nimport type { Operation, ResourceMap } from \"./Convention.js\";\n\n/**\n * The engine row for a JSON:API resource: attributes flattened to the top\n * level so predicates and orderBy address them directly (e.g.\n * `Predicate.eq(\"status\", \"open\")`), exactly as JSON:API `filter[status]`\n * does. The keys `id` and `relationships` are reserved.\n */\nexport interface JsonApiRow {\n readonly id: string;\n readonly relationships: Record<string, RelationshipRef>;\n readonly [field: string]: unknown;\n}\n\n/** Flatten a loaded resource into an engine row (attributes at top level). */\nexport const toRow = (value: ResourceValue): JsonApiRow => ({\n ...value.attributes,\n id: value.id,\n relationships: value.relationships,\n});\n\n/** Permissive codec for a row (the engine never decodes rows through it). */\n// oxlint-disable-next-line effect/avoid-any, effect/no-chained-type-assertions -- deliberately permissive: the runtime codec is `Record<string, unknown>` (no `id`/`relationships` check), typed as the row it carries; the two types do not overlap, so no single assertion or schema change keeps both the runtime behaviour and the exported type\nexport const RowSchema = Schema.Record(\n Schema.String,\n Schema.Unknown\n) as unknown as Schema.Codec<JsonApiRow>;\n\n/** The collection for a resource type: rows keyed by resource id. */\nexport const collectionFor = (type: string): Collection.Collection<JsonApiRow> =>\n Collection.make({\n name: type,\n schema: RowSchema,\n id: (value) => value.id,\n });\n\n/** The mutator name for a (type, operation): `\"{type}/{operation}\"`. */\nexport const mutatorName = (type: string, operation: Operation): string => `${type}/${operation}`;\n\n// ─── Mutator argument schemas ────────────────────────────────────────────────\n\n/** Create: the full resource to insert (client supplies the id). */\nexport const CreateArgs = Schema.Struct({\n type: Schema.String,\n id: Schema.String,\n attributes: Schema.Record(Schema.String, Schema.Unknown),\n relationships: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n});\n\n/** The type {@link CreateArgs} decodes to. */\nexport type CreateArgs = typeof CreateArgs.Type;\n\n/** Update: a partial attribute patch, merged over the current row. */\nexport const UpdateArgs = Schema.Struct({\n type: Schema.String,\n id: Schema.String,\n attributes: Schema.Record(Schema.String, Schema.Unknown),\n});\n\n/** The type {@link UpdateArgs} decodes to. */\nexport type UpdateArgs = typeof UpdateArgs.Type;\n\n/** Delete: address one row. */\nexport const DeleteArgs = Schema.Struct({\n type: Schema.String,\n id: Schema.String,\n});\n\n/** The type {@link DeleteArgs} decodes to. */\nexport type DeleteArgs = typeof DeleteArgs.Type;\n\n// ─── Derivation ──────────────────────────────────────────────────────────────\n\n/** Which CRUD operation a derived mutator performs, and on what type. */\nexport interface OperationInfo {\n readonly operation: Operation;\n readonly type: string;\n}\n\n/**\n * What {@link derive} produces from a resource map: collections, mutators and their CRUD mapping.\n */\nexport interface Derived {\n readonly collections: ReadonlyArray<Collection.AnyCollection>;\n /** Mutator definitions + client (optimistic) handlers. */\n readonly registry: Mutator.MutatorRegistry;\n /** Mutator name → CRUD operation + type, for the authoritative backend. */\n readonly operations: ReadonlyMap<string, OperationInfo>;\n}\n\n/**\n * Derive collections, CRUD mutators, and operation metadata from a resource\n * map. A mutator is only derived when the resource exposes the corresponding\n * write endpoint (no create endpoint ⇒ no `create` mutator).\n */\nexport const derive = (resources: ResourceMap): Derived => {\n const collections: Array<Collection.AnyCollection> = [];\n const entries: Array<{\n readonly mutator: Mutator.AnyMutator;\n readonly local: Mutator.LocalHandler<any>;\n }> = [];\n const operations = new Map<string, OperationInfo>();\n\n const add = (\n type: string,\n operation: Operation,\n args: Schema.Codec<any, any>,\n local: Mutator.LocalHandler<any>\n ) => {\n const name = mutatorName(type, operation);\n entries.push({ mutator: Mutator.make(name, args), local });\n operations.set(name, { operation, type });\n };\n\n resources.forEach((resource) => {\n const type = resource.type;\n collections.push(collectionFor(type));\n\n if (resource.create !== undefined) {\n add(type, \"create\", CreateArgs, (args, writer) =>\n writer.put(\n type,\n args.id,\n toRow({\n type,\n id: args.id,\n attributes: args.attributes,\n relationships: args.relationships ?? {},\n })\n )\n );\n }\n\n if (resource.update !== undefined) {\n add(type, \"update\", UpdateArgs, (args, writer) =>\n Effect.gen(function* () {\n const current = (yield* writer.get(type, args.id)) as JsonApiRow | undefined;\n // Flat rows: overlay the new attributes, keep id + relationships.\n yield* writer.put(type, args.id, {\n ...(current ?? { id: args.id, relationships: {} }),\n ...args.attributes,\n id: args.id,\n });\n })\n );\n }\n\n if (resource.delete !== undefined) {\n add(type, \"delete\", DeleteArgs, (args, writer) => writer.del(type, args.id));\n }\n });\n\n return {\n collections,\n registry: Mutator.registry(entries),\n operations,\n };\n};\n","/**\n * DocumentWriter\n *\n * Rows to a JSON:API compound document — the **one serialiser** ADR-0029 §6\n * binds both the derived REST handlers ({@link RestHandlers}, #163) and the\n * replica-side writer behind the service-worker façade\n * ({@link ReplicaDocuments}, #164) to: \"same URL, same result\". The\n * document is a pure function of the node graph, the read, the resolved\n * rows and the `fields[]` projection — no HTTP, no backend, no clock — so\n * the two sides agree byte for byte on document content whichever source\n * produced the rows.\n *\n * The mapping, node for node (CONTEXT.md: a `type` is a collection, a\n * resource `id` is a row id, a resource is a row value):\n *\n * - **Attributes** are the node's declared attributes, in declaration order,\n * read off the row value. A `one`-edge's key field (`categoryId`) is not\n * an attribute: it is linkage.\n * - **Relationships** come from two places. A `one` edge's linkage is its\n * key on the row (`{ data: { type, id } }`, or `data: null` when the key\n * is null). A collection-valued edge's linkage is the edge rows the read\n * resolved onto the row (`related[edge]`): present when the read path\n * fetched them, absent otherwise — a relationship never claims an empty\n * list it did not see. A paginated edge always carries the spec's `links`\n * (`self` / `related`, effect-jsonapi's model of an unbounded\n * relationship) and, when the read resolved its rows (`include=reviews`\n * includes a paginated edge like any other; only a per-edge window has no\n * URL form), their linkage beside the links.\n * - **`included`** holds the rows of every edge the read `include`s, in\n * code-point order of edge name then root-row order, deduplicated by\n * `(type, id)` with full linkage checked (`Handlers.buildIncluded`: an\n * included row no resource identifier in the document references is\n * thrown at, never emitted). An included resource carries its own\n * `one`-edge linkage and paginated links, and the collection-valued\n * linkage the caller resolved for it ({@link Input.linkage} — the third\n * batch, keyed by the included rows); an edge with no resolved rows is\n * omitted. The member itself is present exactly when the read has an\n * `include`, as an empty array when nothing resolved (JSON:API 1.1\n * §Fetching Includes: a response to a request carrying `include` is a\n * compound document).\n * - **`fields[type]`** is applied last, to attributes only, on primary and\n * included resources alike (ADR-0029 §5: a serialisation-time projection\n * over full rows). Linkage is never projected away.\n * - **`links.self`** is the read's canonical string (`JsonApiQuery.canonical`)\n * — one string per plan, whatever the request's spelling — and a\n * collection whose window is full (`first` rows came back) carries\n * `links.next`: the same canonical query with `page[after]` at the last\n * row's id, the cursor `Subset.apply` continues from. A short page has no\n * `next`. An optional `prefix` (the api's mount path) is prepended to\n * every link; ADR-0029 §6 lets the host differ, nothing else.\n *\n * Only **node rows** are written (a row value carrying the node's attributes\n * and its `one`-edge key fields, as `Node.row` decodes and `Query.run`\n * resolves). The `JsonApiRow` shape of `Derive.ts` (linkage under\n * `relationships`, no node graph) is not a second strategy here: its\n * collections declare no graph to plan against, so nothing can write them\n * until a bridge (`NodeBridge` over the app's resources) gives them one —\n * the seam is {@link relationshipOf}, the one place a row's linkage is read.\n */\n\nimport { Handlers } from \"@thomasfosterau/effect-jsonapi\";\nimport * as P from \"effect/Predicate\";\nimport * as R from \"effect/Record\";\nimport * as Result from \"effect/Result\";\nimport { type Node, Predicate, type Query } from \"@thomasfosterau/legation\";\nimport type { Related } from \"@thomasfosterau/legation/internal\";\nimport * as JsonApiQuery from \"./JsonApiQuery.js\";\n\n/** A resource identifier: `{ type, id }`. */\nexport interface Identifier {\n readonly type: string;\n readonly id: string;\n}\n\n/**\n * A relationship object as written: inline linkage for `one` / `many`\n * edges; links for a paginated edge, with its rows' linkage when resolved.\n */\nexport type RelationshipValue =\n | { readonly data: Identifier | ReadonlyArray<Identifier> | null }\n | {\n readonly links: { readonly self: string; readonly related: string };\n readonly data?: ReadonlyArray<Identifier>;\n };\n\n/** A resource object as written: the node's attributes and its edges' relationships. */\nexport interface ResourceValue {\n readonly type: string;\n readonly id: string;\n readonly attributes: Readonly<Record<string, unknown>>;\n readonly relationships?: Readonly<Record<string, RelationshipValue>>;\n}\n\n/** A collection document: `{ data: [...], included?, links }`, with `included` exactly when the read has an `include`. */\nexport type CollectionDocument = Handlers.DocumentValue<\n ReadonlyArray<ResourceValue>,\n ResourceValue\n>;\n\n/** A single-resource document: `{ data: resource | null, included?, links }`, with `included` exactly when the read has an `include`. */\nexport type DataDocument = Handlers.DocumentValue<ResourceValue | null, ResourceValue>;\n\n/** Edge rows by collection, then row id, then edge name (see {@link Input.linkage}). */\nexport type Linkage = ReadonlyMap<\n string,\n ReadonlyMap<string, Readonly<Record<string, ReadonlyArray<unknown>>>>\n>;\n\n/** What a document is a function of (ADR-0029 §6). */\nexport interface Input {\n readonly nodes: Node.NodeRegistry;\n /** The read as parsed from the URL — its `include` selects `included`, its plan is `links.self`. */\n readonly read: Query.Read;\n /**\n * The read's resolved rows (`Query.runVia` / `Query.run`): root rows in\n * window order, each with the edge rows resolved onto `related`. Edges\n * beyond `read.include` may be present (the linkage plan resolves every\n * declared `many` edge); they contribute linkage, not `included`.\n */\n readonly rows: ReadonlyArray<Related.RelatedRow>;\n /**\n * Collection-valued edge rows resolved for resources beyond the root rows\n * — the included resources' own `many` edges — by collection, then row\n * id, then edge name. Consulted where a row has no `related` entry for\n * the edge; a parent listed with an empty array gets `data: []`.\n */\n readonly linkage?: Linkage;\n /** The `fields[]` projection, applied to attributes at the end. */\n readonly fields?: JsonApiQuery.Projection;\n /** Prepended to every link (the api's mount path, e.g. `/jsonapi`); default `\"\"`. */\n readonly prefix?: string;\n}\n\n// ─── Row helpers (shared with the linkage derivation) ────────────────────────\n\n/** A row value as a record (a node row always is one). */\nconst recordOf = (value: unknown): Readonly<Record<string, unknown>> =>\n P.isObjectOrArray(value) ? (value as Record<string, unknown>) : {};\n\n/** The row id a row value carries (node rows carry `id` in the value). */\nexport const idOf = (value: unknown): string => String(recordOf(value)[\"id\"]);\n\n/** A resolved edge's value as its rows: a list as it is, a single row alone, `null` / `undefined` as none. */\nexport const relatedValuesOf = (value: Related.RelatedValue): ReadonlyArray<unknown> =>\n Array.isArray(value) ? value : value === null || value === undefined ? [] : [value];\n\n// ─── Rows → resource objects ─────────────────────────────────────────────────\n\n/** The per-document constants every row is written under. */\ninterface Env {\n readonly nodes: Node.NodeRegistry;\n readonly linkage: Linkage | undefined;\n readonly prefix: string;\n}\n\nconst envOf = (input: Input): Env => ({\n nodes: input.nodes,\n linkage: input.linkage,\n prefix: input.prefix ?? \"\",\n});\n\n/** The node's declared attributes off the row value, in declaration order; absent ones are left out. */\nconst attributesOf = (node: Node.AnyNode, value: Readonly<Record<string, unknown>>) => {\n return R.filterMap(node.attributes, (_, field) => {\n const attribute = value[field];\n return attribute === undefined ? Result.failVoid : Result.succeed(attribute);\n });\n};\n\n/** A row as the writer sees it: its id and value, the root rows' `related`, and everything else's linkage. */\ninterface Row {\n readonly id: string;\n readonly value: unknown;\n readonly related?: Related.RelatedRow[\"related\"];\n}\n\n/** The resolved rows of one collection-valued edge of a row: `related` first, then the caller's linkage. */\nconst edgeRowsOf = (\n env: Env,\n node: Node.AnyNode,\n row: Row,\n name: string\n): ReadonlyArray<unknown> | undefined => {\n const related = row.related?.[name];\n return Array.isArray(related) ? related : env.linkage?.get(node.type)?.get(row.id)?.[name];\n};\n\n/**\n * The relationship object of one edge, or `undefined` when nothing is known\n * about it. This is where a row's linkage is read: a `one` edge's key off\n * its `via` field, a collection-valued edge's identifiers off its resolved\n * rows.\n */\nconst relationshipOf = (\n env: Env,\n node: Node.AnyNode,\n row: Row,\n name: string\n): RelationshipValue | undefined => {\n const edge = node.edges[name];\n if (edge === undefined) return undefined;\n if (edge.kind === \"one\") {\n const key = recordOf(row.value)[edge.via];\n return {\n data: key === undefined || key === null ? null : { type: edge.target, id: String(key) },\n };\n }\n const rows = edgeRowsOf(env, node, row, name);\n const data =\n rows === undefined\n ? undefined\n : { data: rows.map((value) => ({ type: edge.target, id: idOf(value) })) };\n if (edge.kind === \"many\") return data;\n return {\n links: {\n self: `${env.prefix}${Handlers.relationshipLink(node.type, row.id, name)}`,\n related: `${env.prefix}${Handlers.relatedLink(node.type, row.id, name)}`,\n },\n ...data,\n };\n};\n\n/** The resource object of one row of a node. */\nconst resourceOf = (env: Env, node: Node.AnyNode, row: Row): ResourceValue => {\n const relationships = R.filterMap(node.edges, (_, name) => {\n const relationship = relationshipOf(env, node, row, name);\n return relationship === undefined ? Result.failVoid : Result.succeed(relationship);\n });\n return {\n type: node.type,\n id: row.id,\n attributes: attributesOf(node, recordOf(row.value)),\n ...(R.isEmptyReadonlyRecord(relationships) ? {} : { relationships }),\n };\n};\n\n/** The edge rows of one included edge across the root rows, as resources of the target node. */\nconst includedOf = (\n env: Env,\n node: Node.AnyNode,\n rows: ReadonlyArray<Related.RelatedRow>,\n name: string\n): ReadonlyArray<ResourceValue> => {\n const edge = node.edges[name];\n const target = edge === undefined ? undefined : env.nodes.nodes.get(edge.target);\n if (target === undefined) return [];\n return rows.flatMap((row) =>\n relatedValuesOf(row.related[name]).map((related) =>\n resourceOf(env, target, { id: idOf(related), value: related })\n )\n );\n};\n\n/** The resource's attributes narrowed to its type's `fields[]` entry, when one is given. */\nconst project = (\n resource: ResourceValue,\n fields: JsonApiQuery.Projection | undefined\n): ResourceValue => {\n const names = fields?.[resource.type];\n if (names === undefined) return resource;\n const attributes = R.filter(resource.attributes, (_, field) => names.includes(field));\n return { ...resource, attributes };\n};\n\n// ─── Documents ───────────────────────────────────────────────────────────────\n\n/** The node a read addresses; a read on an unknown collection is a definition defect. */\nconst nodeOf = (nodes: Node.NodeRegistry, read: Query.Read): Node.AnyNode => {\n const node = nodes.nodes.get(read.collection);\n if (node === undefined)\n throw new Error(`DocumentWriter: unknown collection \"${read.collection}\"`);\n return node;\n};\n\n/**\n * The primary resources and the compound `included`, both projected.\n * `included` is `undefined` for a read with no `include`, so the member is\n * omitted; a read with one gets the array even when it is empty, because a\n * response to a request carrying `include` is a compound document (JSON:API\n * 1.1 §Fetching Includes).\n */\nconst assemble = (input: Input, node: Node.AnyNode) => {\n const env = envOf(input);\n const data = input.rows.map((row) => project(resourceOf(env, node, row), input.fields));\n const include = input.read.include;\n const included =\n include === undefined\n ? undefined\n : Object.keys(include)\n .toSorted(Predicate.compareText)\n .flatMap((name) => includedOf(env, node, input.rows, name))\n .map((resource) => project(resource, input.fields));\n return { data, included };\n};\n\n/** `links.self`: the read's canonical string behind the prefix. */\nconst selfLink = (input: Input): string =>\n `${input.prefix ?? \"\"}${JsonApiQuery.canonical(input.nodes, input.read, input.fields)}`;\n\n/**\n * The read's resolved rows sliced to the page it actually asked for\n * (#209). An offset read's root window was compiled with\n * `limit = offset + first` (`Query.plan`'s `rootLimit`) so a covering\n * subscription could be judged by the ordinary limit-prefix rule and the\n * window fetched in one shot; `input.rows` therefore holds up to\n * `offset + first` rows in window order, and this is where they are\n * sliced back down to the `first` rows starting at `offset` — the one\n * place both the derived REST handler and the replica-side writer apply\n * the slice, since both call this module. A cursor-paginated read has no\n * `offset`, so its rows are its page already.\n */\nconst pageOf = (input: Input): ReadonlyArray<Related.RelatedRow> => {\n const { offset, first } = input.read;\n if (offset === undefined) return input.rows;\n return input.rows.slice(offset, first === undefined ? undefined : offset + first);\n};\n\n/**\n * `links.next` for a full page: an offset read continues at `offset +\n * first` in the same idiom it was asked in; a cursor read continues after\n * the page's last row (`page[after]`), the cursor `Subset.apply` resumes\n * from. A short page — fewer rows than `first`, or no window at all — has\n * no next; switching a cursor request to `page[after]`-of-offset (or vice\n * versa) is never done — pagination links stay in the idiom the request\n * used (#209).\n */\nconst nextLink = (input: Input, page: ReadonlyArray<Related.RelatedRow>): string | undefined => {\n const { first, offset } = input.read;\n if (first === undefined || page.length < first) return undefined;\n const link = (read: Query.Read): string =>\n `${input.prefix ?? \"\"}${JsonApiQuery.canonical(input.nodes, read, input.fields)}`;\n if (offset !== undefined) return link({ ...input.read, offset: offset + first });\n const last = page.at(-1);\n return last === undefined ? undefined : link({ ...input.read, after: last.id });\n};\n\n/**\n * `links.prev` for an offset page past the first: the same query at\n * `max(0, offset - first)`. Cursor pagination has no `prev` — a forward\n * cursor names no way back, and ADR-0029's model is unbounded-forward only\n * (#209 adds `prev` for the offset idiom alone).\n */\nconst prevLink = (input: Input): string | undefined => {\n const { first, offset } = input.read;\n if (offset === undefined || offset <= 0 || first === undefined) return undefined;\n const read: Query.Read = { ...input.read, offset: Math.max(0, offset - first) };\n return `${input.prefix ?? \"\"}${JsonApiQuery.canonical(input.nodes, read, input.fields)}`;\n};\n\n/**\n * The collection document of a read: every row of its page as primary\n * data, the included edges compounded, `links.self` canonical and\n * `links.next` (and, for an offset read past the first page, `links.prev`)\n * when the page is full. Throws for a read the canonical encoder refuses\n * (a per-edge window, an `Exists`) — such a read has no URL, so it is\n * never one a URL produced.\n */\nexport const collection = (input: Input): CollectionDocument => {\n const page = pageOf(input);\n const { data, included } = assemble({ ...input, rows: page }, nodeOf(input.nodes, input.read));\n const next = nextLink(input, page);\n const prev = prevLink(input);\n return Handlers.collection(data, {\n ...(included === undefined ? {} : { included }),\n links: {\n self: selfLink(input),\n ...(next === undefined ? {} : { next }),\n ...(prev === undefined ? {} : { prev }),\n },\n });\n};\n\n/**\n * The single-resource document of a read: the first row as primary data\n * (`null` when the read matched nothing — the caller decides the 404), the\n * included edges compounded, `links.self` canonical.\n */\nexport const data = (input: Input): DataDocument => {\n const first = input.rows[0];\n const { data: primary, included } = assemble(\n { ...input, rows: first === undefined ? [] : [first] },\n nodeOf(input.nodes, input.read)\n );\n return Handlers.data(primary[0] ?? null, {\n ...(included === undefined ? {} : { included }),\n links: { self: selfLink(input) },\n });\n};\n","/**\n * Ledger\n *\n * The ledger a `JsonApiBackend` keeps for each client group (#468): the highest\n * acknowledged mutation id per client (`lastMutationIds`) and the permanent\n * rejections it still remembers, each with its reason (#366, #365). A\n * `LedgerStore` is where that state is read from and written to. The default,\n * {@link memory}, keeps nothing, so the backend's own in-memory copy is the\n * ledger and a restart forgets it. {@link keyValue} stores each group's ledger\n * in an Effect `KeyValueStore`, which survives a restart when that store does.\n */\n\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\nimport { KeyValueStore } from \"effect/persistence\";\nimport { BackendError } from \"@thomasfosterau/legation\";\n\n/** A permanent rejection the ledger remembers: the mutation and the reason it was refused. */\nexport interface Rejection {\n readonly clientId: string;\n readonly mutationId: number;\n readonly reason: string;\n}\n\n/** One client group's ledger, as a store holds it. */\nexport interface GroupLedger {\n /** Highest acknowledged mutation id per client. */\n readonly lastMutationIds: Readonly<Record<string, number>>;\n /** The rejections still remembered, for replayed copies and pulls. */\n readonly rejections: ReadonlyArray<Rejection>;\n}\n\n/** An empty group ledger: nothing acknowledged, nothing remembered. */\nexport const emptyGroup: GroupLedger = { lastMutationIds: {}, rejections: [] };\n\n/**\n * Where a `JsonApiBackend` reads and writes each client group's ledger (#468).\n * `read` is called once per group when the backend first needs it; `write`\n * replaces the group's stored ledger after each change, and only after the\n * server has applied the writes the change acknowledges.\n */\nexport interface LedgerStore {\n /** The stored ledger of a client group, or {@link emptyGroup} when it has none. */\n readonly read: (clientGroupId: string) => Effect.Effect<GroupLedger, BackendError>;\n /** Replace a client group's stored ledger with `ledger`. */\n readonly write: (clientGroupId: string, ledger: GroupLedger) => Effect.Effect<void, BackendError>;\n}\n\n/**\n * The in-memory ledger store: it persists nothing, so the backend keeps each\n * group's ledger in its own memory for the life of the instance. A restart of\n * the backend forgets every acknowledged id and remembered rejection.\n */\nexport const memory: LedgerStore = {\n read: () => Effect.succeed(emptyGroup),\n write: () => Effect.void,\n};\n\nconst Rejection = Schema.Struct({\n clientId: Schema.String,\n mutationId: Schema.Number,\n reason: Schema.String,\n});\n\nconst GroupLedger = Schema.Struct({\n lastMutationIds: Schema.Record(Schema.String, Schema.Number),\n rejections: Schema.Array(Rejection),\n});\n\nconst decodeGroup = Schema.decodeUnknownEffect(GroupLedger);\n\n/**\n * A ledger store over an Effect `KeyValueStore`: each client group's ledger is\n * one JSON value under `${prefix}${clientGroupId}`. Use a durable key/value\n * store (a file system, SQL or browser storage layer) for it to survive a\n * restart. A stored value that does not decode is a `BackendError`, not an\n * empty ledger, so a corrupt store is never mistaken for a fresh one.\n */\nexport const keyValue = (\n store: KeyValueStore.KeyValueStore,\n options: { readonly prefix?: string | undefined } = {}\n): LedgerStore => {\n const keyOf = (clientGroupId: string) =>\n `${options.prefix ?? \"legation-jsonapi:ledger:\"}${clientGroupId}`;\n return {\n read: (clientGroupId) =>\n store.get(keyOf(clientGroupId)).pipe(\n Effect.mapError((cause) => new BackendError({ message: \"Ledger read failed\", cause })),\n Effect.flatMap((raw) =>\n raw === undefined\n ? Effect.succeed(emptyGroup)\n : Effect.try({\n try: () => JSON.parse(raw) as unknown,\n catch: (cause) => new BackendError({ message: \"Ledger is not JSON\", cause }),\n }).pipe(\n Effect.flatMap((value) =>\n decodeGroup(value).pipe(\n Effect.mapError(\n (cause) => new BackendError({ message: \"Ledger does not decode\", cause })\n )\n )\n )\n )\n )\n ),\n write: (clientGroupId, ledger) =>\n store\n .set(keyOf(clientGroupId), JSON.stringify(ledger))\n .pipe(\n Effect.mapError((cause) => new BackendError({ message: \"Ledger write failed\", cause }))\n ),\n };\n};\n","/**\n * JsonApiBackend\n *\n * An implementation of the core `Backend` contract (ADR-0009) backed by a\n * JSON:API HTTP surface instead of app-owned storage. This is what lets the\n * library \"figure out the sync story\" from a plain REST API: the sync server\n * (in-process for the client-direct happy path) drives this backend's three\n * operations, and the existing engine supplies journal, overlay, rebase, and\n * CVR diffing on top.\n *\n * Mapping:\n * - `evaluate` lists the collection (`GET /{type}`), pushing the whole\n * predicate to the server as the filter grammar's canonical `filter[...]`\n * form via the `QueryEncoder` (exact under ADR-0028; a predicate that can\n * never match skips the request) and applying predicate, order and limit\n * locally with `Subset.apply` — the window is local, and re-running the\n * filter is redundancy over an exact server answer, not correction.\n * With `includes`, it adds `?include=...` and harvests the compound document's\n * related rows, serving auto-subscribed `id IN (...)` subsets from that cache.\n * - `getRows` serves row values from the cache `evaluate` populates and this\n * backend's own writes keep current (the sync server always evaluates before\n * fetching put rows in the same pull), falling back to `GET /{type}/{id}`.\n * The cache reflects this instance's own writes only, so a deployment runs\n * one JsonApiBackend per server and writes the server only through it\n * (#447): another writer's changes go unseen, and `getRows` can serve a\n * superseded row.\n * - `applyMutations` replays the batch as HTTP writes. Each mutation is one\n * JSON:API write (`Write`: a create, update or delete of one resource —\n * derived CRUD mutators map directly, and `writes` expresses custom\n * mutators). With `atomic` configured the whole batch goes as one\n * `atomic:operations` request (`create` → `add`, `update` → `update`,\n * `delete` → `remove`, sent with the extension's media type); otherwise\n * each write is its own `POST`/`PATCH`/`DELETE`.\n *\n * **Versioning.** A plain REST API exposes no row-version token, so versions\n * are a content hash of the resource value: the hash changes iff the row\n * changed, which is exactly what CVR diffing needs.\n *\n * **Change hints.** A push's hints carry each touched row's pre-push value as\n * `oldValues`, as MemoryBackend's do, so topic-derived fan-out (ADR-0023) pokes\n * the windows a row moved away from. A REST API keeps no change token, and\n * nothing here says whether a cached row is still current (a write made\n * elsewhere goes unseen, #447; this backend's own writes do keep its cache\n * current, #395), so the old value is always read: each update or delete does one\n * `GET /{type}/{id}` before its write, once per row per push. A row the push\n * creates was absent before the push, so it is not read (`enterBatchCreate`),\n * unless the server refuses the create and a later write of the row needs its\n * value (`readRefusedCreates`, #402). Every failed read fails the push with\n * BackendError, a 4xx and a 404 included, and so does a 2xx with no resource, so\n * an update or delete is either sent with its old value or not sent. On the\n * atomic path nothing has been written by then, so the retry reads again. On the\n * per-resource path the writes before the failed read have already applied and\n * been acknowledged, so the retry does not resend them\n * and their hints are lost: the at-least-once delivery described below, as for\n * any transient write failure there. A read the server refuses (a 4xx) stalls\n * that client's queue until the refusal is resolved. A resource that receives\n * updates or deletes needs a `getOne` route: without one each of its updates\n * and deletes fails its push, before anything is written. The new value of a\n * create or update is the server's returned document when it sends one, else\n * the row read before the push merged with the write (so a partial PATCH hints\n * the full row), else the written value.\n *\n * **Delivery semantics.** Without a cooperating server there is no\n * server-side mutation-id ledger, so this backend keeps one per client group:\n * the highest acknowledged id per client, and the rejections it remembers.\n * The ledger lives in this instance's memory by default (`Ledger.memory`), so\n * a restart of the backend forgets it: a resent mutation that was already\n * applied looks new, guarded only by the server's own idempotency, if any, and\n * a replayed copy or a pull can no longer report an earlier rejection. A\n * deployment that restarts its backend passes a durable `Ledger.LedgerStore`\n * (`ledger`, e.g. `Ledger.keyValue` over an Effect `KeyValueStore`) to keep\n * both across restarts (#468). Each ledger change is written after the server\n * has applied its writes and before the ids are acknowledged, in the order the\n * push already uses. If that ledger write fails after the server write\n * succeeded, the push fails with a `BackendError`. Mutations acknowledged earlier\n * in the same push keep their acknowledgement; the failed one and the rest of the\n * push are not acknowledged, so the client's resend re-applies them. On the atomic\n * path a rejection recorded before the failing write stays remembered, and the\n * resend records it again. That is the same window as a crash between the two\n * writes, and with or without a store the server's own idempotency is what guards\n * it.\n *\n * Over an atomic operations endpoint (`atomic` set) a push is all-or-nothing\n * per batch: one request, and the ledger advances only once the server has\n * applied every operation in it. A transient failure — transport, 5xx, or a\n * 4xx naming no operation — leaves the server holding nothing and the ledger\n * unmoved, so the client's retry resends the same batch. A 4xx error document\n * whose `source.pointer` names an operation (`Atomic.operationPointer(i)`) is\n * a permanent rejection of that mutation (ADR-0008's poison-mutation\n * semantics): it is recorded as rejected and the batch is resent without it,\n * until the remainder applies or nothing is left; every mutation in the batch\n * is then acknowledged in order (one round trip per rejection, bounded by the\n * batch size). `lid` is supported by the wire format but unused: derived\n * creates carry the client-generated `id`, and no mutator yet needs a\n * server-assigned one.\n *\n * The ledger also remembers the rejections it has made (#366), so a\n * replayed copy of a rejected mutation lists it in `rejected` with the same reason,\n * as MemoryBackend does. A push forgets the rejections below its lowest id per\n * client. The memory is bounded per client: a client that never pushes again keeps\n * its last push's rejections. It assumes one journal per `clientId`, which backend\n * contiguity already requires.\n *\n * Over per-resource endpoints (no `atomic`) delivery is *at-least-once*:\n * make writes idempotent (client-generated ids on create; PATCH/DELETE are\n * naturally idempotent) and retries are safe.\n */\n\nimport * as Arr from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport * as R from \"effect/Record\";\nimport * as Ref from \"effect/Ref\";\nimport * as Schema from \"effect/Schema\";\nimport * as Semaphore from \"effect/Semaphore\";\nimport * as HttpClient from \"effect/http/HttpClient\";\nimport * as HttpClientRequest from \"effect/http/HttpClientRequest\";\nimport { Atomic } from \"@thomasfosterau/effect-jsonapi\";\nimport { Backend, BackendError, MutationRejected, Predicate } from \"@thomasfosterau/legation\";\nimport { Hash, Protocol, RejectionMemory, UnknownMutator } from \"@thomasfosterau/legation/internal\";\nimport { Subset } from \"@thomasfosterau/legation/internal\";\nimport type { Mutator } from \"@thomasfosterau/legation\";\nimport {\n documentToRows,\n parseResponse,\n resourceToRow,\n type RelationshipRef,\n} from \"./CollectionLoader.js\";\nimport type { ResourceMap } from \"./Convention.js\";\nimport { toRow, type JsonApiRow, type OperationInfo } from \"./Derive.js\";\nimport { defaultEncoder, type QueryEncoder } from \"./JsonApiQuery.js\";\nimport * as Ledger from \"./Ledger.js\";\nimport { ResourceObject } from \"./schema.js\";\n\n/**\n * One JSON:API write — the unit both delivery paths speak: a create (`POST`,\n * or atomic `add`), update (`PATCH` / `update`) or delete (`DELETE` /\n * `remove`) of one resource. Creates carry the client-generated id.\n */\nexport interface Write {\n readonly operation: \"create\" | \"update\" | \"delete\";\n readonly type: string;\n readonly id: string;\n readonly attributes?: Record<string, unknown>;\n readonly relationships?: Record<string, unknown>;\n}\n\n/** Configuration for {@link make}. */\nexport interface JsonApiBackendConfig {\n /** Base URL the resource paths are resolved against (no trailing slash). */\n readonly baseUrl: string;\n readonly resources: ResourceMap;\n /** Mutator definitions, for decoding/validating pushed args. */\n readonly mutators: ReadonlyMap<string, Mutator.AnyMutator>;\n /** Mutator name → CRUD operation + type. */\n readonly operations: ReadonlyMap<string, OperationInfo>;\n /**\n * Mutators beyond the derived CRUD ones, and how to express each one's\n * decoded args as a single JSON:API `Write`. Consulted before `operations`,\n * so an app can push its own named intents through this backend as long\n * as each is one create/update/delete of one resource.\n */\n readonly writes?: ReadonlyMap<string, (args: unknown) => Write> | undefined;\n /**\n * The server's JSON:API Atomic Operations endpoint (`POST {path}`), when it\n * has one. With it set, `applyMutations` pushes a whole batch as one\n * all-or-nothing `atomic:operations` request; without it, each mutation is\n * its own request. `JsonApiSync` fills this in from the reflected api\n * (`Convention.reflectAtomic`).\n */\n readonly atomic?: { readonly path: string } | undefined;\n /** Subset → JSON:API query string. Defaults to the exact filter-grammar encoder. */\n readonly query?: QueryEncoder | undefined;\n /**\n * Relationship names to compound-load per collection (`?include=...`). When a\n * listing pulls in related resources, they are harvested so an auto-subscribed\n * `id IN (...)` subset over those collections is served from the same response\n * — no extra round trip. See `Relationships.related`.\n */\n readonly includes?: Readonly<Record<string, ReadonlyArray<string>>> | undefined;\n /**\n * Where each client group's ledger (its acknowledged mutation ids and\n * remembered rejections) is kept across restarts (#468). Unset, the ledger\n * lives in this instance's memory (`Ledger.memory`), so a restart forgets it.\n * `Ledger.keyValue` over a durable Effect `KeyValueStore` keeps it.\n */\n readonly ledger?: Ledger.LedgerStore | undefined;\n}\n\n/** A mutation as the sync server pushes it to a backend. */\ntype PushedMutation = Protocol.Mutation;\n\nconst jsonApiHeaders = {\n \"Content-Type\": \"application/vnd.api+json\",\n Accept: \"application/vnd.api+json\",\n} as const;\n\n/** The extension media type an atomic operations request carries both ways. */\nconst atomicHeaders = {\n \"Content-Type\": Atomic.MEDIA_TYPE,\n Accept: Atomic.MEDIA_TYPE,\n} as const;\n\nconst trimSlashes = (s: string): string => s.replace(/\\/+$/, \"\");\n\n/** Resolve a route template against the base url, substituting the id param. */\nconst urlFor = (baseUrl: string, path: string, id?: string): string =>\n trimSlashes(baseUrl) + path.replace(/:[^/]+/g, () => encodeURIComponent(id ?? \"\"));\n\n/** A content-hash row version: a plain REST API exposes no version token. */\nexport const versionOf = Hash.contentHash;\n\nconst backendError = (message: string) => (cause: unknown) => new BackendError({ message, cause });\n\n/** The refusal for a mutation past its client's next expected id (Backend.ts guarantee 1). */\nconst mutationGap = (clientId: string, expected: number, got: number) =>\n new BackendError({\n message: `Mutation-id gap for client \"${clientId}\": expected ${expected}, got ${got}`,\n });\n\n/** Append `?`/`&`-joined params to an existing query string. */\nconst appendQuery = (query: string, extra: string): string =>\n extra === \"\" ? query : query === \"\" ? `?${extra}` : `${query}&${extra}`;\n\n/**\n * The set of ids a subset pins via an `id IN (...)` / `id = ...` filter, or\n * `undefined` if it isn't id-pinned. Used to recognize auto-subscribed\n * relationship subsets that the include fast-path can serve from cache.\n */\nconst pinnedIds = (predicate: Predicate.Predicate): ReadonlySet<string> | undefined => {\n switch (predicate._tag) {\n case \"In\":\n return predicate.field === \"id\"\n ? new Set(predicate.values.map((value) => String(value)))\n : undefined;\n case \"Compare\":\n return predicate.op === \"eq\" && predicate.field === \"id\"\n ? new Set([String(predicate.value)])\n : undefined;\n case \"And\":\n return Option.getOrUndefined(\n Arr.findFirst(predicate.predicates, (inner) => Option.fromUndefinedOr(pinnedIds(inner)))\n );\n default:\n return undefined;\n }\n};\n\n/** What an applied write leaves in its row: the value it wrote, or a delete. */\ntype WriteEffect = { readonly _tag: \"put\"; readonly value: unknown } | { readonly _tag: \"delete\" };\n\n/**\n * Fold one applied write's effect into a push's PUT values (mutates `puts`). A\n * put records the row's value. A delete drops an earlier write's value for the\n * row, so a later delete in the same push leaves the hint naming it as a\n * delete (#369).\n */\nconst recordEffect = (\n puts: Map<string, Map<string, unknown>>,\n collection: string,\n id: string,\n effect: WriteEffect\n): void => {\n if (effect._tag === \"delete\") {\n puts.get(collection)?.delete(id);\n } else {\n puts.set(\n collection,\n (puts.get(collection) ?? new Map<string, unknown>()).set(id, effect.value)\n );\n }\n};\n\n/** Record a touched id under its collection (mutates `touched`). */\nconst recordTouched = (touched: Map<string, Set<string>>, collection: string, id: string): void => {\n touched.set(collection, (touched.get(collection) ?? new Set<string>()).add(id));\n};\n\n/** What one push knows about a row it writes (ADR-0023's `oldValues`). */\ninterface RowEntry {\n /** The row's value before the push's first write to it: none when absent, or when the push created it. */\n readonly before: Option.Option<JsonApiRow>;\n /** The row's value after the writes applied so far: none once deleted, or when unknown. */\n current: Option.Option<JsonApiRow>;\n}\n\n/** The mutable accumulators one push folds its per-mutation outcomes into. */\ninterface WriteAccumulator {\n readonly touched: Map<string, Set<string>>;\n readonly puts: Map<string, Map<string, unknown>>;\n readonly rejected: Array<Backend.RejectedMutation>;\n /** The rows this push has read or applied a write to, by collection, then id. */\n readonly rows: Map<string, Map<string, RowEntry>>;\n}\n\n/** The row entry for (collection, id), if this push has entered the row. */\nconst entryOf = (acc: WriteAccumulator, collection: string, id: string): RowEntry | undefined =>\n acc.rows.get(collection)?.get(id);\n\n/** Enter a row under (collection, id) (mutates `acc`). */\nconst setEntry = (acc: WriteAccumulator, collection: string, id: string, entry: RowEntry): void => {\n acc.rows.set(\n collection,\n (acc.rows.get(collection) ?? new Map<string, RowEntry>()).set(id, entry)\n );\n};\n\n/**\n * The pre-push values this push read, as the hints' `olds`: the same snapshot\n * MemoryBackend takes before it applies a batch.\n */\nconst oldsOf = (acc: WriteAccumulator): Map<string, Map<string, unknown>> => {\n const olds = new Map<string, Map<string, unknown>>();\n acc.rows.forEach((entries, collection) =>\n entries.forEach((entry, id) => {\n if (Option.isSome(entry.before)) {\n olds.set(\n collection,\n (olds.get(collection) ?? new Map<string, unknown>()).set(id, entry.before.value)\n );\n }\n })\n );\n return olds;\n};\n\n/**\n * Fold one applied write into the push: the row's value after it, and the\n * write's effect on the hint. A row the push has not entered was absent before\n * the push wrote it (a create), so it starts with no value.\n */\nconst recordApplied = (\n acc: WriteAccumulator,\n write: Write,\n document: JsonApiRow | undefined\n): void => {\n const entry = entryOf(acc, write.type, write.id) ?? {\n before: Option.none<JsonApiRow>(),\n current: Option.none<JsonApiRow>(),\n };\n setEntry(acc, write.type, write.id, entry);\n entry.current =\n write.operation === \"delete\"\n ? Option.none<JsonApiRow>()\n : Option.some(rowAfter(write, entry.current, document));\n recordTouched(acc.touched, write.type, write.id);\n recordEffect(\n acc.puts,\n write.type,\n write.id,\n Option.isSome(entry.current) ? { _tag: \"put\", value: entry.current.value } : { _tag: \"delete\" }\n );\n};\n\n/** Build a JSON:API write body (`{ data: { type, id, attributes, ... } }`). */\nconst writeBody = (\n type: string,\n id: string,\n attributes: Record<string, unknown>,\n relationships?: Record<string, unknown>\n): { readonly data: Record<string, unknown> } => ({\n data: {\n type,\n id,\n attributes,\n ...(relationships !== undefined ? { relationships } : {}),\n },\n});\n\n/** A write's relationships in the row's linkage shape, as `toRow` gives a server document. */\nconst linkageOf = (write: Write): Record<string, RelationshipRef> =>\n resourceToRow({\n type: write.type,\n id: write.id,\n relationships: write.relationships ?? {},\n } as ResourceObject).value.relationships;\n\n/**\n * The value a create/update writes, as the hint carries it — the same shape\n * `toRow` gives a resource the server returned, so a hint looks alike\n * whichever path produced it and whatever the server answered.\n */\nconst writtenValue = (write: Write): JsonApiRow => ({\n ...write.attributes,\n id: write.id,\n relationships: linkageOf(write),\n});\n\n/** The row after a partial update: the row read before the push, with the write laid over it. */\nconst mergeWrite = (read: JsonApiRow, write: Write): JsonApiRow => ({\n ...read,\n ...write.attributes,\n id: write.id,\n relationships: { ...read.relationships, ...linkageOf(write) },\n});\n\n/**\n * The value a create or update leaves its row with: the server's document when\n * it returned one; otherwise the row's value so far merged with the write; or\n * the written value alone when the push does not know the row.\n */\nconst rowAfter = (\n write: Write,\n current: Option.Option<JsonApiRow>,\n document: JsonApiRow | undefined\n): JsonApiRow =>\n document ?? (Option.isSome(current) ? mergeWrite(current.value, write) : writtenValue(write));\n\n/** Express a derived CRUD mutator's decoded args as one JSON:API write. */\nconst writeOf = (operation: OperationInfo, args: unknown): Effect.Effect<Write, BackendError> => {\n switch (operation.operation) {\n case \"create\": {\n const a = args as {\n id: string;\n attributes: Record<string, unknown>;\n relationships?: Record<string, unknown>;\n };\n return Effect.succeed({\n operation: \"create\",\n type: operation.type,\n id: a.id,\n attributes: a.attributes,\n ...(a.relationships !== undefined ? { relationships: a.relationships } : {}),\n });\n }\n case \"update\": {\n const a = args as { id: string; attributes: Record<string, unknown> };\n return Effect.succeed({\n operation: \"update\",\n type: operation.type,\n id: a.id,\n attributes: a.attributes,\n });\n }\n case \"delete\": {\n const a = args as { id: string };\n return Effect.succeed({ operation: \"delete\", type: operation.type, id: a.id });\n }\n default:\n return Effect.fail(\n new BackendError({ message: `Operation \"${operation.operation}\" is not a write` })\n );\n }\n};\n\n/** One write as an atomic operation object (`add` / `update` / `remove`). */\nconst operationOf = (write: Write): Record<string, unknown> => {\n switch (write.operation) {\n case \"create\":\n return {\n op: \"add\",\n data: {\n type: write.type,\n id: write.id,\n attributes: write.attributes ?? {},\n ...(write.relationships !== undefined ? { relationships: write.relationships } : {}),\n },\n };\n case \"update\":\n return {\n op: \"update\",\n data: {\n type: write.type,\n id: write.id,\n attributes: write.attributes ?? {},\n ...(write.relationships !== undefined ? { relationships: write.relationships } : {}),\n },\n };\n case \"delete\":\n return { op: \"remove\", ref: { type: write.type, id: write.id } };\n }\n};\n\n/**\n * The index of the operation an error's `source.pointer` names — the\n * operation itself (`Atomic.operationPointer(i)`) or a member below it — or\n * `undefined` when the pointer names none of the `count` operations sent.\n */\nconst operationIndex = (pointer: string, count: number): number | undefined => {\n const match = /^\\/atomic:operations\\/(\\d+)(?:\\/|$)/.exec(pointer);\n if (match === null) return undefined;\n const index = Number(match[1]);\n return index < count && Atomic.operationPointer(index) === `/atomic:operations/${index}`\n ? index\n : undefined;\n};\n\n/** The per-operation rejections an error document carries, by operation index. */\nconst rejectionsOf = (\n body: unknown,\n count: number,\n fallbackReason: string\n): ReadonlyArray<{ readonly index: number; readonly reason: string }> => {\n const errors =\n P.isObjectOrArray(body) && Array.isArray((body as { errors?: unknown }).errors)\n ? ((body as { errors: ReadonlyArray<unknown> }).errors as ReadonlyArray<{\n readonly title?: string;\n readonly detail?: string;\n readonly source?: { readonly pointer?: string };\n }>)\n : [];\n const byIndex = new Map<number, string>();\n errors.forEach((error) => {\n const pointer = error?.source?.pointer;\n if (!P.isString(pointer)) return;\n const index = operationIndex(pointer, count);\n if (index === undefined || byIndex.has(index)) return;\n byIndex.set(index, error.detail ?? error.title ?? fallbackReason);\n });\n return [...byIndex].map(([index, reason]) => ({ index, reason }));\n};\n\n/** A write of one push's batch, with its position in the batch. */\ninterface BatchEntry {\n readonly index: number;\n readonly write: Write;\n}\n\n/** The row an `atomic:results` entry carries, if it returned a resource. */\nconst resultRow = (result: unknown): JsonApiRow | undefined => {\n const data = P.isObjectOrArray(result) ? (result as { data?: unknown }).data : undefined;\n const resource = Schema.decodeUnknownOption(ResourceObject)(data);\n return Option.isSome(resource) ? toRow(resourceToRow(resource.value).value) : undefined;\n};\n\n/** One atomic request's outcome: everything applied, or some operations named as rejected. */\ntype AtomicOutcome =\n | { readonly _tag: \"applied\"; readonly results: ReadonlyArray<unknown> }\n | {\n readonly _tag: \"rejected\";\n readonly rejections: ReadonlyArray<{ readonly index: number; readonly reason: string }>;\n };\n\n/**\n * Enter a row an atomic batch creates, before the batch's one request. The row\n * was absent before the push, so it needs no read: a later update or delete of\n * it in the same batch must not GET it, since that 404 would fail the push. An\n * entry already present (an earlier delete in the batch read the row) is kept.\n * A create the server refuses is the one case where the row may exist; the\n * resend reads it then (`readRefusedCreates`).\n */\nconst enterBatchCreate = (acc: WriteAccumulator, write: Write): void => {\n if (entryOf(acc, write.type, write.id) === undefined)\n setEntry(acc, write.type, write.id, { before: Option.none(), current: Option.none() });\n};\n\n/**\n * A client group's ledger as the backend holds it (#468): the highest acknowledged\n * mutation id per client, and the rejections remembered per client, by mutation id.\n */\ninterface Group {\n readonly acknowledged: ReadonlyMap<string, number>;\n readonly rejections: ReadonlyMap<string, ReadonlyMap<number, string>>;\n}\n\n/** A stored group ledger, as the backend holds it. */\nconst groupOf = (ledger: Ledger.GroupLedger): Group => {\n const rejections = new Map<string, Map<number, string>>();\n ledger.rejections.forEach((entry) => {\n const ids = rejections.get(entry.clientId) ?? new Map<number, string>();\n ids.set(entry.mutationId, entry.reason);\n rejections.set(entry.clientId, ids);\n });\n return { acknowledged: new Map(Object.entries(ledger.lastMutationIds)), rejections };\n};\n\n/** A group as the store holds it. */\nconst ledgerOf = (group: Group): Ledger.GroupLedger => ({\n lastMutationIds: Object.fromEntries(group.acknowledged),\n rejections: [...group.rejections].flatMap(([clientId, ids]) =>\n [...ids].map(([mutationId, reason]) => ({ clientId, mutationId, reason }))\n ),\n});\n\n/** Build the JsonApiBackend from its config; requires an `HttpClient`. */\nexport const make = (\n config: JsonApiBackendConfig\n): Effect.Effect<Backend.Backend, never, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient;\n const encoder = config.query ?? defaultEncoder;\n const includes = config.includes ?? {};\n // collection → id → the latest value this backend listed or wrote (warms getRows).\n const cache = yield* Ref.make(new Map<string, Map<string, JsonApiRow>>());\n // collection → ids known complete in cache via a compound `included` harvest.\n const includedIds = yield* Ref.make(new Map<string, Set<string>>());\n // clientGroupId → the group's ledger (#468): read from the store on first use,\n // then kept current with each change written to it.\n const groups = yield* Ref.make(new Map<string, Group>());\n const ledgerStore = config.ledger ?? Ledger.memory;\n // Every ledger read-modify-write runs under this lock, so the store is never\n // written with a group that a concurrent change has already moved past.\n const ledgerLock = yield* Semaphore.make(1);\n\n const getJson = (url: string) =>\n Effect.scoped(\n client.execute(\n HttpClientRequest.get(url).pipe(HttpClientRequest.setHeaders(jsonApiHeaders))\n )\n );\n\n // A transport-level failure (connection lost) or a 5xx is transient — a\n // BackendError that aborts the push. A 4xx is a permanent rejection (bad\n // request, forbidden, conflict): the server did not apply the write, so it\n // is a MutationRejected that skips the mutation without poisoning the queue.\n // 408/429 are the transient exceptions in the 4xx band (timeout, rate limit).\n const transientStatuses = new Set([408, 429]);\n const isPermanentStatus = (status: number): boolean =>\n status >= 400 && status < 500 && !transientStatuses.has(status);\n /** Send one write; the resource document it answers with, if it answers with one. */\n const sendWrite = (request: HttpClientRequest.HttpClientRequest) =>\n Effect.scoped(client.execute(request)).pipe(\n Effect.mapError(backendError(\"JSON:API write failed\")),\n Effect.flatMap(\n (response): Effect.Effect<JsonApiRow | undefined, BackendError | MutationRejected> => {\n if (response.status >= 200 && response.status < 300)\n return response.json.pipe(\n Effect.orElseSucceed(() => undefined),\n Effect.map(resultRow)\n );\n const message = `JSON:API write returned HTTP ${response.status}`;\n return isPermanentStatus(response.status)\n ? Effect.fail(new MutationRejected({ reason: message }))\n : Effect.fail(new BackendError({ message }));\n }\n )\n );\n\n /**\n * The `getOne` route an update or delete reads its row through. A resource\n * with no such route cannot be written by update or delete, so the write\n * fails with BackendError before anything is sent.\n */\n const getOneFor = (type: string): Effect.Effect<{ readonly path: string }, BackendError> => {\n const getOne = config.resources.get(type)?.getOne;\n return getOne === undefined\n ? Effect.fail(\n new BackendError({\n message: `\"${type}\" has no getOne route, so its updates and deletes cannot read the row before writing it`,\n })\n )\n : Effect.succeed(getOne);\n };\n\n /**\n * Read a row before the push writes it: the value the server holds now. Every\n * failed read fails the push with BackendError, a 404 and any other 4xx\n * included, and so does a 2xx whose document carries no resource: an update\n * or delete that went out without its old value would hint no `oldValues`, so\n * it is not sent instead. On the atomic path every read precedes the one\n * request, so nothing is written on a read the push cannot complete. On the\n * per-resource path the writes before the failed read have already applied,\n * and their hints are lost (see the module header's delivery note).\n *\n * The cache is never consulted here: it has no freshness signal for a write\n * made elsewhere (a version token would be needed), and this backend's own\n * writes keep it current for `getRows` only (#395). So each push reads the row.\n */\n const readBefore = (type: string, id: string): Effect.Effect<JsonApiRow, BackendError> =>\n Effect.gen(function* () {\n const getOne = yield* getOneFor(type);\n const response = yield* getJson(urlFor(config.baseUrl, getOne.path, id)).pipe(\n Effect.mapError(backendError(`Failed to read ${type}/${id} before writing it`))\n );\n if (response.status < 200 || response.status >= 300)\n return yield* new BackendError({\n message: `JSON:API read of ${type}/${id} returned HTTP ${response.status}`,\n });\n const document = yield* parseResponse(response).pipe(\n Effect.mapError(backendError(`Invalid JSON:API resource ${type}/${id}`))\n );\n const resource = documentToRows(document).rows[0]?.value;\n if (resource === undefined)\n return yield* new BackendError({\n message: `JSON:API read of ${type}/${id} returned no resource`,\n });\n return toRow(resource);\n });\n\n /**\n * Enter a row the write touches. An update or delete reads the row on the\n * push's first write to it, so the pre-push value is kept for the hint (the\n * read is `readBefore`, where a cache hit would replace it, #395). A row\n * already entered is not read again. A create reads nothing and enters no\n * row: its row is entered when the create applies, or up front for the\n * atomic path's batch (`enterBatchCreate`).\n */\n const enterRow = (acc: WriteAccumulator, write: Write): Effect.Effect<void, BackendError> => {\n if (write.operation === \"create\" || entryOf(acc, write.type, write.id) !== undefined)\n return Effect.void;\n return readBefore(write.type, write.id).pipe(\n Effect.map((before) =>\n setEntry(acc, write.type, write.id, {\n before: Option.some(before),\n current: Option.some(before),\n })\n )\n );\n };\n\n /**\n * Refuse a write that cannot be read before it is sent: an update or delete\n * of a resource with no `getOne` route. Checked for a whole push before its\n * first write, so a push that cannot be read sends nothing on either path.\n */\n const checkReadable = (write: Write): Effect.Effect<void, BackendError> =>\n write.operation === \"create\" ? Effect.void : getOneFor(write.type).pipe(Effect.asVoid);\n\n /** Enter one write of an atomic batch before its request: a create as absent, others by reading the row. */\n const enterBatchWrite = (\n acc: WriteAccumulator,\n write: Write\n ): Effect.Effect<void, BackendError> =>\n write.operation === \"create\"\n ? Effect.sync(() => enterBatchCreate(acc, write))\n : enterRow(acc, write);\n\n /**\n * Read the rows the batch's refused creates would have made absent (#402).\n * The batch entered each row a create touches as absent, which is right only\n * while the create applies. The server refused these creates, so the row may\n * exist: when a later update or delete of it is still to be sent, read it\n * now, before the resend, so that write carries its pre-push value. Each row\n * is read at most once, and a row no remaining update or delete touches is\n * not read, so a create that applies never makes a read that can fail the push.\n */\n const readRefusedCreates = (\n acc: WriteAccumulator,\n refused: ReadonlyArray<BatchEntry>,\n remaining: ReadonlyArray<BatchEntry>\n ): Effect.Effect<void, BackendError> =>\n Effect.forEach(\n refused.filter((entry) => entry.write.operation === \"create\"),\n (create) => {\n const { type, id } = create.write;\n const laterWrite = remaining.some(\n (entry) =>\n entry.index > create.index &&\n entry.write.operation !== \"create\" &&\n entry.write.type === type &&\n entry.write.id === id\n );\n const entry = entryOf(acc, type, id);\n if (!laterWrite || (entry !== undefined && Option.isSome(entry.before)))\n return Effect.void;\n return readBefore(type, id).pipe(\n Effect.map((row) =>\n setEntry(acc, type, id, { before: Option.some(row), current: Option.some(row) })\n )\n );\n },\n { discard: true }\n );\n\n const cacheRows = (collection: string, rows: ReadonlyArray<JsonApiRow>) =>\n Ref.update(cache, (current) => {\n const next = new Map(current);\n const map = new Map(next.get(collection) ?? []);\n rows.forEach((value) => map.set(value.id, value));\n next.set(collection, map);\n return next;\n });\n\n /**\n * Bring the cache into line with a write the server has applied (#395): the\n * row's value after the push's writes so far, or no row once a delete has\n * applied, so `getRows` never serves a value the push has superseded.\n */\n const cacheApplied = (acc: WriteAccumulator, write: Write) => {\n const current = entryOf(acc, write.type, write.id)?.current ?? Option.none<JsonApiRow>();\n return Ref.update(cache, (rows) => {\n const next = new Map(rows);\n const map = new Map(next.get(write.type) ?? []);\n if (Option.isSome(current)) map.set(write.id, current.value);\n else map.delete(write.id);\n next.set(write.type, map);\n return next;\n });\n };\n\n /** Harvest a compound document's `included` rows; record their ids complete. */\n const harvestIncluded = (\n included: ReadonlyArray<JsonApiRow & { readonly $collection: string }>\n ) =>\n Effect.gen(function* () {\n const byCollection = Arr.groupBy(included, (row) => row.$collection);\n yield* Effect.forEach(\n R.toEntries(byCollection),\n ([collection, rows]) =>\n cacheRows(collection, rows).pipe(\n Effect.andThen(\n Ref.update(includedIds, (current) => {\n const next = new Map(current);\n const ids = new Set(next.get(collection) ?? []);\n rows.forEach((row) => ids.add(row.id));\n next.set(collection, ids);\n return next;\n })\n )\n ),\n { concurrency: 1, discard: true }\n );\n });\n\n const entriesFrom = (values: ReadonlyArray<JsonApiRow>, subset: Subset.Subset) =>\n Subset.apply(\n values.map((value) => ({ id: value.id, value })),\n subset\n ).map((row) => ({ id: row.id, version: versionOf(row.value) }));\n\n const evaluate: Backend.Backend[\"evaluate\"] = (_context, subset) =>\n Effect.gen(function* () {\n const list = config.resources.get(subset.collection)?.list;\n if (list === undefined) return [];\n // Correlated Exists is a relational join this REST backend can't resolve;\n // fail closed rather than silently skip the filter (denormalize, or use a\n // backend that resolves Exists).\n if (Predicate.hasExists(subset.where)) {\n return yield* new BackendError({\n message: `JSON:API backend does not support Exists predicates on \"${subset.collection}\"`,\n });\n }\n\n // Include fast-path: an auto-subscribed `id IN (...)` subset whose ids\n // were all delivered by a prior compound `included` harvest is served\n // from cache — the related rows arrived with their parent, no round trip.\n const ids = pinnedIds(subset.where);\n if (ids !== undefined) {\n const complete = (yield* Ref.get(includedIds)).get(subset.collection);\n if (complete !== undefined && [...ids].every((id) => complete.has(id))) {\n const cached = (yield* Ref.get(cache)).get(subset.collection);\n if (cached !== undefined && [...ids].every((id) => cached.has(id))) {\n return entriesFrom([...cached.values()], subset);\n }\n }\n }\n\n // The exact filter goes to the server; a predicate no row can match\n // (an empty allow-set) is answered here without a request. A\n // predicate with no URL form fails closed.\n const encoded = yield* encoder\n .encode(subset)\n .pipe(Effect.mapError(backendError(`Subset on \"${subset.collection}\" has no URL form`)));\n if (Option.isNone(encoded)) return [];\n const includeParam = (includes[subset.collection] ?? []).join(\",\");\n const query = appendQuery(\n encoded.value,\n includeParam === \"\" ? \"\" : `include=${encodeURIComponent(includeParam)}`\n );\n const url = urlFor(config.baseUrl, list.path) + query;\n const response = yield* getJson(url).pipe(\n Effect.mapError(backendError(`Failed to list \"${subset.collection}\"`))\n );\n const document = yield* parseResponse(response).pipe(\n Effect.mapError(backendError(`Invalid JSON:API listing \"${subset.collection}\"`))\n );\n const loaded = documentToRows(document);\n const values = loaded.rows.map((row) => toRow(row.value));\n yield* cacheRows(subset.collection, values);\n yield* harvestIncluded(\n loaded.included.map((row) => ({ ...toRow(row.value), $collection: row.collection }))\n );\n return entriesFrom(values, subset);\n });\n\n const getRows: Backend.Backend[\"getRows\"] = (_context, collection, ids) =>\n Effect.gen(function* () {\n const cached = (yield* Ref.get(cache)).get(collection);\n const getOne = config.resources.get(collection)?.getOne;\n const found = yield* Effect.forEach(\n ids,\n (id) =>\n Effect.gen(function* () {\n const hit = cached?.get(id);\n if (hit !== undefined) return [{ id, version: versionOf(hit), value: hit }];\n if (getOne === undefined) return [];\n const response = yield* getJson(urlFor(config.baseUrl, getOne.path, id)).pipe(\n Effect.mapError(backendError(`Failed to fetch ${collection}/${id}`))\n );\n // A 404 is an absent row: omitted, as the contract requires.\n if (response.status === 404) return [];\n const document = yield* parseResponse(response).pipe(\n Effect.mapError(backendError(`Invalid JSON:API resource ${collection}/${id}`))\n );\n const resource = documentToRows(document).rows[0]?.value;\n if (resource === undefined) return [];\n const value = toRow(resource);\n return [{ id, version: versionOf(value), value }];\n }),\n { concurrency: 1 }\n );\n return found.flat();\n });\n\n /** Decode a pushed mutation's args and express it as one JSON:API write. */\n const writeFor = (mutation: PushedMutation): Effect.Effect<Write, BackendError> =>\n Effect.gen(function* () {\n const definition = config.mutators.get(mutation.mutator);\n const custom = config.writes?.get(mutation.mutator);\n const operation = config.operations.get(mutation.mutator);\n if (definition === undefined || (custom === undefined && operation === undefined))\n return yield* UnknownMutator.make(mutation.mutator);\n const args = yield* Schema.decodeUnknownEffect(definition.args)(mutation.args).pipe(\n Effect.mapError(backendError(`Invalid args for mutator \"${mutation.mutator}\"`))\n );\n // A `writes` function that refuses its args (it throws, as\n // `FacadeWrites.writesOf` does for args naming another type) fails as\n // args that do not decode do, never as a defect.\n if (custom !== undefined) {\n return yield* Effect.try({\n try: () => custom(args),\n catch: backendError(`Invalid args for mutator \"${mutation.mutator}\"`),\n });\n }\n if (operation === undefined) return yield* UnknownMutator.make(mutation.mutator);\n return yield* writeOf(operation, args);\n });\n\n // Apply one write as its own request. Resolves to the resource document the\n // server answered a create or update with, if it sent one.\n const applyOne = (\n write: Write\n ): Effect.Effect<JsonApiRow | undefined, BackendError | MutationRejected> =>\n Effect.gen(function* () {\n const resource = config.resources.get(write.type);\n switch (write.operation) {\n case \"create\": {\n const ref = resource?.create;\n if (ref === undefined)\n return yield* new BackendError({ message: `No create endpoint for \"${write.type}\"` });\n return yield* sendWrite(\n HttpClientRequest.post(urlFor(config.baseUrl, ref.path)).pipe(\n HttpClientRequest.setHeaders(jsonApiHeaders),\n HttpClientRequest.bodyJsonUnsafe(\n writeBody(write.type, write.id, write.attributes ?? {}, write.relationships)\n )\n )\n );\n }\n case \"update\": {\n const ref = resource?.update;\n if (ref === undefined)\n return yield* new BackendError({ message: `No update endpoint for \"${write.type}\"` });\n return yield* sendWrite(\n HttpClientRequest.patch(urlFor(config.baseUrl, ref.path, write.id)).pipe(\n HttpClientRequest.setHeaders(jsonApiHeaders),\n HttpClientRequest.bodyJsonUnsafe(\n writeBody(write.type, write.id, write.attributes ?? {}, write.relationships)\n )\n )\n );\n }\n case \"delete\": {\n const ref = resource?.delete;\n if (ref === undefined)\n return yield* new BackendError({ message: `No delete endpoint for \"${write.type}\"` });\n yield* sendWrite(\n HttpClientRequest.make(\"DELETE\")(urlFor(config.baseUrl, ref.path, write.id)).pipe(\n HttpClientRequest.setHeaders(jsonApiHeaders)\n )\n );\n return undefined;\n }\n }\n });\n\n /** The group's ledger, filled from the store on first use. Callers hold `ledgerLock`. */\n const fillGroup = (clientGroupId: string): Effect.Effect<Group, BackendError> =>\n Effect.gen(function* () {\n const cached = (yield* Ref.get(groups)).get(clientGroupId);\n if (cached !== undefined) return cached;\n const group = groupOf(yield* ledgerStore.read(clientGroupId));\n yield* Ref.update(groups, (current) => new Map(current).set(clientGroupId, group));\n return group;\n });\n\n /** A client group's ledger, read under `ledgerLock` so a first read cannot race an update. */\n const readGroup = (clientGroupId: string): Effect.Effect<Group, BackendError> =>\n Semaphore.withPermit(ledgerLock, fillGroup(clientGroupId));\n\n /**\n * Change a client group's ledger. `change` returns the group it becomes, or\n * the group it was when nothing changes, and then nothing is written. The\n * store is written before the new group is kept, so a failed write leaves the\n * store and this instance agreeing on the old group.\n */\n const updateGroup = (clientGroupId: string, change: (group: Group) => Group) =>\n Semaphore.withPermit(\n ledgerLock,\n Effect.gen(function* () {\n const current = yield* fillGroup(clientGroupId);\n const next = change(current);\n if (next === current) return;\n yield* ledgerStore.write(clientGroupId, ledgerOf(next));\n yield* Ref.update(groups, (all) => new Map(all).set(clientGroupId, next));\n })\n );\n\n /** Acknowledge mutations in the ledger, in the order given, in one update. */\n const bumpLedger = (\n context: Backend.SyncContext,\n mutations: ReadonlyArray<{ readonly clientId: string; readonly mutationId: number }>\n ) =>\n Arr.isReadonlyArrayEmpty(mutations)\n ? Effect.void\n : updateGroup(context.clientGroupId, (group) => {\n const acknowledged = new Map(group.acknowledged);\n mutations.forEach((mutation) =>\n acknowledged.set(mutation.clientId, mutation.mutationId)\n );\n return { ...group, acknowledged };\n });\n\n /** Remember permanent rejections, so a replayed copy of them reports the same outcome (#366). */\n const rememberRejections = (\n context: Backend.SyncContext,\n rejected: ReadonlyArray<Backend.RejectedMutation>\n ) =>\n Arr.isReadonlyArrayEmpty(rejected)\n ? Effect.void\n : updateGroup(context.clientGroupId, (group) => {\n const rejections = new Map(group.rejections);\n rejected.forEach((entry) => {\n const ids = new Map(rejections.get(entry.clientId) ?? []);\n ids.set(entry.mutationId, entry.reason);\n rejections.set(entry.clientId, ids);\n });\n return { ...group, rejections };\n });\n\n /**\n * Forget the rejections this push's floors have moved past (#355), so the\n * memory is bounded per client, as MemoryBackend's is.\n */\n const forgetRejections = (\n context: Backend.SyncContext,\n mutations: ReadonlyArray<PushedMutation>\n ) =>\n updateGroup(context.clientGroupId, (group) => {\n const rejections = RejectionMemory.forgetBelow(\n group.rejections,\n RejectionMemory.floorsOf(mutations)\n );\n return rejections === group.rejections ? group : { ...group, rejections };\n });\n\n /**\n * The rejections a push's replayed copies were committed with (an id the ledger\n * already covers, with a remembered rejection). They are reported again (#366).\n */\n const replayedRejections = (\n context: Backend.SyncContext,\n mutations: ReadonlyArray<PushedMutation>\n ): Effect.Effect<Array<Backend.RejectedMutation>, BackendError> =>\n Effect.gen(function* () {\n const group = yield* readGroup(context.clientGroupId);\n return mutations.flatMap((mutation): Array<Backend.RejectedMutation> => {\n if (mutation.mutationId > (group.acknowledged.get(mutation.clientId) ?? 0)) return [];\n const reason = group.rejections.get(mutation.clientId)?.get(mutation.mutationId);\n return reason === undefined\n ? []\n : [{ clientId: mutation.clientId, mutationId: mutation.mutationId, reason }];\n });\n });\n\n const lastMutationIdsOf = (context: Backend.SyncContext) =>\n readGroup(context.clientGroupId).pipe(\n Effect.map((group) => Object.fromEntries(group.acknowledged))\n );\n\n /** The group's remembered rejections, each with its reason (#365). A pull reports those its watermark covers. */\n const rememberedRejections = (context: Backend.SyncContext) =>\n readGroup(context.clientGroupId).pipe(\n Effect.map((group) =>\n [...group.rejections].flatMap(([clientId, ids]) =>\n [...ids].map(([mutationId, reason]): Backend.RejectedMutation => ({\n clientId,\n mutationId,\n reason,\n }))\n )\n )\n );\n\n /**\n * The mutations a push still has to send, in order, each with its write. A\n * mutation at or below its client's acknowledged id was already applied, so it\n * is skipped (idempotent, acknowledged). With `strict`, a mutation past the next\n * expected id is a gap the push cannot apply, so the push is refused.\n */\n const unacknowledged = (\n context: Backend.SyncContext,\n mutations: ReadonlyArray<PushedMutation>,\n strict: boolean\n ): Effect.Effect<\n Array<{ readonly mutation: PushedMutation; readonly write: Write }>,\n BackendError\n > =>\n Effect.gen(function* () {\n const group = yield* readGroup(context.clientGroupId);\n const expected = new Map<string, number>(group.acknowledged);\n const batch: Array<{ readonly mutation: PushedMutation; readonly write: Write }> = [];\n yield* Effect.forEach(\n mutations,\n (mutation) => {\n const last = expected.get(mutation.clientId) ?? 0;\n if (mutation.mutationId <= last) return Effect.void; // idempotent (acknowledged)\n if (strict && mutation.mutationId > last + 1)\n return Effect.fail(mutationGap(mutation.clientId, last + 1, mutation.mutationId));\n expected.set(mutation.clientId, mutation.mutationId);\n return Effect.map(writeFor(mutation), (write) => {\n batch.push({ mutation, write });\n });\n },\n { concurrency: 1, discard: true }\n );\n return batch;\n });\n\n /**\n * The mutations a per-resource push still has to send, in order. A mutation\n * at or below its client's acknowledged id was already applied, so it is\n * skipped (idempotent, acknowledged). A mutation past the next expected id is a\n * gap, refused with a `BackendError` before any write of the push is sent, as\n * the atomic path refuses it (`unacknowledged`, strict). Unlike\n * `unacknowledged`, nothing is decoded here: the send loop decodes each write\n * in turn, so an undecodable mutation still fails at its own place in the push.\n */\n const pendingEach = (\n context: Backend.SyncContext,\n mutations: ReadonlyArray<PushedMutation>\n ): Effect.Effect<ReadonlyArray<PushedMutation>, BackendError> =>\n Effect.gen(function* () {\n const expected = new Map<string, number>(\n (yield* readGroup(context.clientGroupId)).acknowledged\n );\n const pending: Array<PushedMutation> = [];\n yield* Effect.forEach(\n mutations,\n (mutation) => {\n const last = expected.get(mutation.clientId) ?? 0;\n if (mutation.mutationId <= last) return Effect.void; // idempotent (acknowledged)\n if (mutation.mutationId > last + 1)\n return Effect.fail(mutationGap(mutation.clientId, last + 1, mutation.mutationId));\n expected.set(mutation.clientId, mutation.mutationId);\n pending.push(mutation);\n return Effect.void;\n },\n { concurrency: 1, discard: true }\n );\n return pending;\n });\n\n /**\n * Replay each write as its own request (at-least-once, in order). Before the\n * first request, each pending mutation that decodes is checked for a `getOne`\n * route, so a write that cannot be read sends nothing. A mutation whose args\n * do not decode is not checked: the loop fails the push at it, after the\n * writes before it, as it always has.\n */\n const applyEach = (\n context: Backend.SyncContext,\n mutations: ReadonlyArray<PushedMutation>\n ): Effect.Effect<Backend.ApplyResult, BackendError> =>\n Effect.gen(function* () {\n const acc: WriteAccumulator = {\n touched: new Map(),\n puts: new Map(),\n rejected: [],\n rows: new Map(),\n };\n const replays = yield* replayedRejections(context, mutations);\n const pending = yield* pendingEach(context, mutations);\n const decoded = yield* Effect.forEach(pending, (mutation) =>\n Effect.gen(function* () {\n const write = yield* writeFor(mutation).pipe(Effect.option);\n if (Option.isSome(write)) yield* checkReadable(write.value);\n return { mutation, write };\n })\n );\n\n yield* Effect.forEach(\n decoded,\n ({ mutation, write: decodedWrite }) =>\n Effect.gen(function* () {\n // An undecodable mutation decodes again here and fails the push with the\n // same BackendError it always raised, leaving its ledger entry unmoved.\n const write = Option.isSome(decodedWrite)\n ? decodedWrite.value\n : yield* writeFor(mutation);\n yield* enterRow(acc, write);\n // A permanent HTTP rejection (4xx) skips this mutation but still bumps\n // its id, so it is acknowledged and never poisons the queue. A\n // transient failure propagates and aborts the push.\n const outcome = yield* applyOne(write).pipe(\n Effect.map((document) => ({ _tag: \"applied\", document }) as const),\n Effect.catchTag(\"MutationRejected\", (error) =>\n Effect.succeed({ _tag: \"rejected\", reason: error.reason } as const)\n )\n );\n if (outcome._tag === \"applied\") {\n recordApplied(acc, write, outcome.document);\n yield* cacheApplied(acc, write);\n } else {\n const rejection = {\n clientId: mutation.clientId,\n mutationId: mutation.mutationId,\n reason: outcome.reason,\n };\n acc.rejected.push(rejection);\n // Remembered before the id is acknowledged, so a copy that sees the id\n // as covered also sees its rejection (#366).\n yield* rememberRejections(context, [rejection]);\n }\n yield* bumpLedger(context, [mutation]);\n }),\n { concurrency: 1, discard: true }\n );\n\n const rejected = [...replays, ...acc.rejected];\n return {\n lastMutationIds: yield* lastMutationIdsOf(context),\n hints: Backend.buildChangeHints(acc.touched, acc.puts, oldsOf(acc)),\n ...(Arr.isReadonlyArrayNonEmpty(rejected) ? { rejected } : {}),\n };\n });\n\n /** Send one `atomic:operations` request and classify the server's answer. */\n const sendAtomic = (\n path: string,\n operations: ReadonlyArray<Record<string, unknown>>\n ): Effect.Effect<AtomicOutcome, BackendError> =>\n Effect.gen(function* () {\n const response = yield* Effect.scoped(\n client.execute(\n HttpClientRequest.post(urlFor(config.baseUrl, path)).pipe(\n HttpClientRequest.bodyText(\n JSON.stringify({ \"atomic:operations\": operations }),\n Atomic.MEDIA_TYPE\n ),\n HttpClientRequest.setHeaders(atomicHeaders)\n )\n )\n ).pipe(Effect.mapError(backendError(\"JSON:API atomic:operations request failed\")));\n const status = response.status;\n const message = `JSON:API atomic:operations returned HTTP ${status}`;\n // A 204 (or an unparseable success body) still means every operation applied.\n const body = yield* response.json.pipe(Effect.orElseSucceed(() => undefined));\n if (status >= 200 && status < 300) {\n const results = P.isObjectOrArray(body)\n ? (body as { readonly \"atomic:results\"?: unknown })[\"atomic:results\"]\n : undefined;\n return { _tag: \"applied\", results: Array.isArray(results) ? results : [] } as const;\n }\n if (isPermanentStatus(status)) {\n const rejections = rejectionsOf(body, operations.length, message);\n if (Arr.isReadonlyArrayNonEmpty(rejections))\n return { _tag: \"rejected\", rejections } as const;\n }\n // 5xx, 408/429, transport, or a 4xx naming no operation: transient.\n return yield* new BackendError({ message });\n });\n\n /**\n * Push the batch as one `atomic:operations` request. Nothing is\n * acknowledged until the server has applied the whole (remaining) batch;\n * permanently rejected operations are dropped and the rest resent.\n */\n const applyAtomic = (\n context: Backend.SyncContext,\n mutations: ReadonlyArray<PushedMutation>,\n atomic: { readonly path: string }\n ): Effect.Effect<Backend.ApplyResult, BackendError> =>\n Effect.gen(function* () {\n const replays = yield* replayedRejections(context, mutations);\n const batch = yield* unacknowledged(context, mutations, true);\n\n // Read the rows the batch updates or deletes before the one request that\n // writes them, so a failed read sends nothing. A row the batch creates is\n // not read (see enterBatchCreate).\n const acc: WriteAccumulator = {\n touched: new Map(),\n puts: new Map(),\n rejected: [],\n rows: new Map(),\n };\n yield* Effect.forEach(batch, ({ write }) => enterBatchWrite(acc, write), {\n concurrency: 1,\n discard: true,\n });\n\n // Batch index → rejection reason; each round trip drops at least one.\n const rejectedAt = new Map<number, string>();\n type Pending = ReadonlyArray<(typeof batch)[number] & { readonly index: number }>;\n // One round trip; refused operations are dropped and the rest resent.\n const round = (\n pending: Pending\n ): Effect.Effect<\n { readonly pending: Pending; readonly results: ReadonlyArray<unknown> },\n BackendError\n > =>\n Effect.gen(function* () {\n if (Arr.isReadonlyArrayEmpty(pending)) return { pending, results: [] };\n const outcome = yield* sendAtomic(\n atomic.path,\n pending.map((entry) => operationOf(entry.write))\n );\n if (outcome._tag === \"applied\") return { pending, results: outcome.results };\n const refused = outcome.rejections.flatMap(({ index }) => {\n const entry = pending[index];\n return entry === undefined ? [] : [entry];\n });\n outcome.rejections.forEach(({ index, reason }) => {\n const entry = pending[index];\n if (entry !== undefined) rejectedAt.set(entry.index, reason);\n });\n const next = pending.filter((entry) => !rejectedAt.has(entry.index));\n // A create the server refused may have left its row in place: read it\n // before the resend when a later write of it still needs the old value.\n yield* readRefusedCreates(acc, refused, next);\n return yield* round(next);\n });\n const { pending, results } = yield* round(\n batch.map((entry, index) => ({ ...entry, index }))\n );\n\n // Hints from what applied, in push order: each row's value from the\n // result document where the server returned one, else as merged or\n // written. A delete drops an earlier write's value for the row (#369).\n yield* Effect.forEach(\n pending,\n ({ write }, position) => {\n recordApplied(acc, write, resultRow(results[position]));\n return cacheApplied(acc, write);\n },\n { concurrency: 1, discard: true }\n );\n\n const rejected = [...rejectedAt]\n .toSorted(([a], [b]) => a - b)\n .flatMap(([index, reason]) => {\n const entry = batch[index];\n return entry === undefined\n ? []\n : [\n {\n clientId: entry.mutation.clientId,\n mutationId: entry.mutation.mutationId,\n reason,\n },\n ];\n });\n // The rejections are remembered before the ids are acknowledged (#366).\n yield* rememberRejections(context, rejected);\n // Applied and rejected alike are acknowledged, in original order.\n yield* bumpLedger(\n context,\n batch.map(({ mutation }) => mutation)\n );\n\n const reported = [...replays, ...rejected];\n return {\n lastMutationIds: yield* lastMutationIdsOf(context),\n hints: Backend.buildChangeHints(acc.touched, acc.puts, oldsOf(acc)),\n ...(Arr.isReadonlyArrayNonEmpty(reported) ? { rejected: reported } : {}),\n };\n });\n\n const applyMutations: Backend.Backend[\"applyMutations\"] = (context, mutations) =>\n Effect.gen(function* () {\n // The rejections this push has moved past are forgotten first (#355, #366).\n yield* forgetRejections(context, mutations);\n return config.atomic === undefined\n ? yield* applyEach(context, mutations)\n : yield* applyAtomic(context, mutations, config.atomic);\n });\n\n return Backend.Backend.of({\n applyMutations,\n lastMutationIds: lastMutationIdsOf,\n rejections: rememberedRejections,\n evaluate,\n getRows,\n });\n });\n","/**\n * FacadeWrites\n *\n * The pieces of a façade write (ADR-0030) that do not depend on the fetch\n * handler: reading the `Prefer` header (RFC 7240), decoding a write's body\n * **structurally** into a `JsonApiBackend.Write`, and the default **intent\n * mapping** from a `Write` to the graph-derived CRUD mutation the engine\n * journals (`CrudMutation`, graph row form). `JsonApiFacade` composes them.\n *\n * Structural means exactly ADR-0030 §5's list: `data` is an object whose\n * `type` is the route's, whose `id` (when present) is the path's for a\n * `PATCH`, whose `attributes` / `relationships` are objects when present, and\n * whose relationships are `one` edges of the node with `{ type, id }` or\n * `null` linkage. Attribute values are never checked: the server rules on\n * them, and a value it refuses surfaces as a permanent rejection.\n */\n\nimport * as Arr from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport { flow } from \"effect/Function\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport * as R from \"effect/Record\";\nimport * as Result from \"effect/Result\";\nimport * as Schema from \"effect/Schema\";\nimport { CrudMutation } from \"@thomasfosterau/legation\";\nimport type { Node } from \"@thomasfosterau/legation\";\nimport type { JsonApiBackendConfig, Write } from \"./JsonApiBackend.js\";\n\n// ─── Prefer ──────────────────────────────────────────────────────────────────\n\n/** The preferences a façade write reads from `Prefer` (RFC 7240 §4); others are forwarded untouched. */\nexport interface Preferences {\n /** `Prefer: respond-async`: journal and answer a receipt even when online. */\n readonly respondAsync: boolean;\n /** `Prefer: handling=strict`: never journal. */\n readonly strict: boolean;\n /** `Prefer: wait=N`, in seconds, when present and a non-negative integer. */\n readonly wait?: number;\n}\n\n/** Read the `Prefer` headers of a request (several headers and comma-separated lists alike). */\nexport const preferencesOf = (headers: Headers): Preferences => {\n const pairs = Arr.map((headers.get(\"prefer\") ?? \"\").split(\",\"), (part) => {\n const [token = \"\"] = part.split(\";\");\n const [rawName = \"\", ...rest] = token.split(\"=\");\n const value = rest\n .join(\"=\")\n .trim()\n .replace(/^\"(.*)\"$/, \"$1\")\n .toLowerCase();\n return [rawName.trim().toLowerCase(), value] as const;\n });\n const has = (name: string, value?: string) =>\n Arr.some(pairs, ([n, v]) => n === name && (value === undefined || v === value));\n const wait = Arr.findLast(pairs, ([n, v]) => n === \"wait\" && /^\\d+$/.test(v));\n const preferences = { respondAsync: has(\"respond-async\"), strict: has(\"handling\", \"strict\") };\n return Option.match(wait, {\n onNone: () => preferences,\n onSome: ([, v]) => ({ ...preferences, wait: Number(v) }),\n });\n};\n\n// ─── Decoding ────────────────────────────────────────────────────────────────\n\n/**\n * Why a write's body cannot be journaled, as the error object an offline\n * façade answers with (ADR-0030 §3): `400 invalid_document`, `409\n * type_mismatch` / `id_mismatch`, `422 unsupported_relationship`, or the\n * `client_id_required` a `POST` without an id meets.\n */\nexport interface Refusal {\n readonly status: 400 | 409 | 422 | 503;\n readonly code:\n | \"invalid_document\"\n | \"type_mismatch\"\n | \"id_mismatch\"\n | \"unsupported_relationship\"\n | \"client_id_required\";\n readonly title: string;\n readonly detail: string;\n readonly pointer?: string;\n}\n\nconst refuse = (refusal: Refusal): Effect.Effect<never, Refusal> => Effect.fail(refusal);\n\nconst invalid = (detail: string, pointer: string): Effect.Effect<never, Refusal> =>\n refuse({ status: 400, code: \"invalid_document\", title: \"Invalid document\", detail, pointer });\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n P.isObject(value) && !Array.isArray(value);\n\nconst decodeJson = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown));\n\n/** What a write route matched: its operation, the route's type, and the path's id for `PATCH` / `DELETE`. */\nexport type Target =\n | { readonly operation: \"create\"; readonly type: string }\n | { readonly operation: \"update\" | \"delete\"; readonly type: string; readonly id: string };\n\n/** The linkage of one relationship: a related id, `null`, or a refusal. */\nconst linkageOf = (\n name: string,\n member: unknown,\n node: Node.AnyNode\n): Effect.Effect<string | null, Refusal> => {\n const pointer = `/data/relationships/${name}`;\n const edge = node.edges[name];\n if (edge === undefined || edge.kind !== \"one\") {\n return refuse({\n status: 422,\n code: \"unsupported_relationship\",\n title: \"Unsupported relationship\",\n detail:\n edge === undefined\n ? `\"${name}\" is not a relationship of ${node.type}`\n : `\"${name}\" is a to-many relationship; its linkage lives on the related resources, not on ${node.type}`,\n pointer,\n });\n }\n if (!isRecord(member) || !(\"data\" in member)) {\n return invalid(`relationship \"${name}\" must be an object with a \"data\" member`, pointer);\n }\n const data = member[\"data\"];\n if (data === null) return Effect.succeed(null);\n if (!isRecord(data) || !P.isString(data[\"id\"]) || data[\"type\"] !== edge.target) {\n return invalid(\n `relationship \"${name}\" must link one \"${edge.target}\" by type and id, or be null`,\n `${pointer}/data`\n );\n }\n return Effect.succeed(data[\"id\"]);\n};\n\n/** The body's `data` member as an object, or the refusal for a body that has none. */\nconst dataOf = (\n body: Effect.Effect<string, unknown>\n): Effect.Effect<Record<string, unknown>, Refusal> =>\n Effect.gen(function* () {\n const text = yield* body.pipe(\n Effect.catch(() => invalid(\"the request body could not be read\", \"\"))\n );\n const document = yield* decodeJson(text).pipe(\n Effect.catch(() => invalid(\"the request body is not JSON\", \"\"))\n );\n if (!isRecord(document) || !(\"data\" in document)) {\n return yield* invalid('a write document needs a \"data\" member', \"\");\n }\n const data = document[\"data\"];\n return isRecord(data) ? data : yield* invalid('\"data\" must be a resource object', \"/data\");\n });\n\nconst clientIdRequired: Refusal = {\n status: 503,\n code: \"client_id_required\",\n title: \"Client id required\",\n detail: \"A create the façade journals offline needs a client-generated id in data.id.\",\n pointer: \"/data/id\",\n};\n\n/** The resource id a create or an update addresses, checked against the route's type and path. */\nconst idOf = (\n target: Exclude<Target, { readonly operation: \"delete\" }>,\n data: Record<string, unknown>\n): Effect.Effect<string, Refusal> => {\n if (data[\"type\"] !== target.type) {\n return refuse({\n status: 409,\n code: \"type_mismatch\",\n title: \"Type mismatch\",\n detail: `this endpoint writes \"${target.type}\" resources`,\n pointer: \"/data/type\",\n });\n }\n const id = data[\"id\"];\n if (id !== undefined && !P.isString(id)) {\n return invalid('\"data.id\" must be a string', \"/data/id\");\n }\n if (target.operation === \"create\") {\n return id === undefined || id === \"\" ? refuse(clientIdRequired) : Effect.succeed(id);\n }\n if (id === undefined) return invalid(\"an update's data needs the id the path names\", \"/data/id\");\n return id === target.id\n ? Effect.succeed(id)\n : refuse({\n status: 409,\n code: \"id_mismatch\",\n title: \"Id mismatch\",\n detail: `\"data.id\" must be the id the path names (\"${target.id}\")`,\n pointer: \"/data/id\",\n });\n};\n\n/** An optional object member of `data` (`attributes`, `relationships`): `{}` when absent. */\nconst memberOf = (\n data: Record<string, unknown>,\n name: \"attributes\" | \"relationships\"\n): Effect.Effect<Record<string, unknown>, Refusal> => {\n const member = data[name] ?? {};\n return isRecord(member)\n ? Effect.succeed(member)\n : invalid(`\"data.${name}\" must be an object`, `/data/${name}`);\n};\n\n/**\n * Decode a write's body structurally into a `Write` whose `relationships`\n * are flattened into `one`-edge ids by relationship name (`null` clears).\n * A `DELETE` reads no body. Fails with the {@link Refusal} the offline façade\n * answers with; a create without a client id is refused only once the rest\n * of its body has passed.\n */\nexport const decodeWrite = (\n node: Node.AnyNode,\n target: Target,\n body: Effect.Effect<string, unknown>\n): Effect.Effect<Write, Refusal> => {\n if (target.operation === \"delete\") {\n return Effect.succeed({ operation: \"delete\", type: target.type, id: target.id });\n }\n return Effect.gen(function* () {\n const data = yield* dataOf(body);\n // A missing client id is refused last, after the body's other faults (ADR-0030 §3).\n const checked = yield* Effect.result(idOf(target, data));\n if (Result.isFailure(checked) && checked.failure.code !== \"client_id_required\") {\n return yield* refuse(checked.failure);\n }\n const attributes = yield* memberOf(data, \"attributes\");\n const relationships = yield* memberOf(data, \"relationships\");\n const linkage = yield* Effect.forEach(\n R.toEntries(relationships),\n ([name, member]) =>\n Effect.map(linkageOf(name, member, node), (related) => [name, related] as const),\n { concurrency: 1 }\n );\n return {\n operation: target.operation,\n type: target.type,\n id: yield* Result.match(checked, { onFailure: refuse, onSuccess: Effect.succeed }),\n attributes,\n relationships: R.fromEntries(linkage),\n };\n });\n};\n\n// ─── The intent mapping ──────────────────────────────────────────────────────\n\n/** The mutation a write is journaled as: a registered mutator name and its encoded args. */\nexport interface Intent {\n readonly mutator: string;\n readonly args: unknown;\n}\n\n/**\n * The intent mapping (ADR-0030 §5): a decoded `Write` to the mutation the\n * engine journals, or `undefined` when the write is not interceptable.\n * `relationships` arrive flattened by {@link decodeWrite}: relationship name\n * to related id (or `null`).\n */\nexport type IntentOf = (write: Write) => Intent | undefined;\n\n/**\n * The default intent mapping: the graph-derived CRUD mutations\n * (`CrudMutation`), args in the graph row form — the attributes plus, per\n * `one` edge the payload links, its `via` key.\n */\nexport const graphIntentOf =\n (nodes: Node.NodeRegistry): IntentOf =>\n (write) => {\n const node = nodes.nodes.get(write.type);\n if (node === undefined) return undefined;\n const mutator = CrudMutation.name(write.type, write.operation);\n if (write.operation === \"delete\") return { mutator, args: { type: write.type, id: write.id } };\n const linked = Arr.map(R.toEntries(write.relationships ?? {}), ([name, related]) => {\n const edge = node.edges[name];\n return edge?.kind === \"one\" ? Option.some([edge.via, related] as const) : Option.none();\n });\n const vias = Option.all(linked);\n if (Option.isNone(vias)) return undefined;\n const attributes = { ...write.attributes, ...R.fromEntries(vias.value) };\n return { mutator, args: { type: write.type, id: write.id, attributes } };\n };\n\n// ─── The inverse mapping ─────────────────────────────────────────────────────\n\nconst decodeWriteArgs = Schema.decodeUnknownSync(CrudMutation.WriteArgs);\nconst decodeDeleteArgs = Schema.decodeUnknownSync(CrudMutation.DeleteArgs);\n\n/**\n * One graph-row write as a `JsonApiBackend` write: each `one` edge's `via` key\n * moves out of the attributes into `relationships[edge].data` (`null` linkage\n * when the key is `null`). A key the args do not carry leaves the relationship\n * out, as a payload that did not link it.\n */\nconst writeOf = (\n node: Node.AnyNode,\n operation: \"create\" | \"update\",\n args: CrudMutation.WriteArgs\n): Write => {\n const oneEdges = R.toEntries(node.edges).flatMap(([name, edge]) =>\n edge.kind === \"one\" ? [[name, edge] as const] : []\n );\n const vias = HashSet.fromIterable(oneEdges.map(([, edge]) => edge.via));\n const relationships = R.fromEntries(\n oneEdges.flatMap(([name, edge]) =>\n Object.hasOwn(args.attributes, edge.via)\n ? [\n [\n name,\n {\n data: P.isString(args.attributes[edge.via])\n ? { type: edge.target, id: args.attributes[edge.via] }\n : null,\n },\n ] as const,\n ]\n : []\n )\n );\n return {\n operation,\n // The node's own type, never the args': the mutation's name is what the\n // server authorised, so the write goes to that type's endpoint only.\n type: node.type,\n id: args.id,\n attributes: R.filter(args.attributes, (_, field) => !HashSet.has(vias, field)),\n relationships,\n };\n};\n\n/**\n * Refuse args whose `type` is not the mutation's own (#529): a `notes/create`\n * naming `secrets` would otherwise write a type the mutation's name, which the\n * server authorised, never covered. `JsonApiBackend` reports the refusal as\n * invalid args, as it does args that do not decode.\n */\nconst sameType =\n (type: string, mutator: string) =>\n <A extends { readonly type: string }>(args: A): A => {\n if (args.type !== type) {\n throw new InvalidWriteArgs({\n message: `\"${mutator}\" writes \"${type}\", but its args name \"${args.type}\"`,\n });\n }\n return args;\n };\n\n/** Graph-derived CRUD args that do not fit the mutation they were journaled under. */\nexport class InvalidWriteArgs extends Schema.TaggedError<\n InvalidWriteArgs,\n { readonly brand: unique symbol }\n>()(\"InvalidWriteArgs\", {\n message: Schema.String,\n}) {}\n\n/**\n * The inverse of {@link graphIntentOf} (ADR-0030 §5): for every graph-derived\n * CRUD mutation (`CrudMutation`, filtered by `options.writes` as the registry\n * is), how its args replay as one JSON:API write. Pass it as a\n * `JsonApiBackend`'s `writes`, so a node-graph app's journaled `{type}/create`,\n * `{type}/update` and `{type}/delete` reach the server as `POST`, `PATCH` and\n * `DELETE` (or atomic operations), with each `one` edge's `via` key rebuilt as\n * the relationship's linkage. The write's `type` is always the mutation's own:\n * args naming another type are refused ({@link InvalidWriteArgs}).\n */\nexport const writesOf = (\n nodes: Node.NodeRegistry,\n options?: CrudMutation.Options\n): NonNullable<JsonApiBackendConfig[\"writes\"]> =>\n new Map(\n CrudMutation.entries(nodes, options).flatMap((entry) => {\n const node = nodes.nodes.get(entry.type);\n if (node === undefined) return [];\n const name = entry.mutator.name;\n const operation = entry.operation;\n return [\n [\n name,\n operation === \"delete\"\n ? flow(decodeDeleteArgs, sameType(entry.type, name), (args): Write => ({\n operation,\n type: entry.type,\n id: args.id,\n }))\n : flow(decodeWriteArgs, sameType(entry.type, name), (args) =>\n writeOf(node, operation, args)\n ),\n ] as const,\n ];\n })\n );\n","/**\n * MutationStatus\n *\n * The **mutation status URL** of a façade write (ADR-0030 §2):\n * `{prefix}/_legation/mutations/{mutationId}`, a `GET` the façade answers\n * from the engine's mutation-state map (`ClientEngine.mutationStates`,\n * #116) and never forwards — the server has no such resource. Where a\n * plain-fetch caller learns whether the intent its `202` receipt named was\n * applied, or permanently rejected and why.\n *\n * - `200 OK`: one `legation-mutations` resource whose attributes are the\n * mutation's `phase` (`MutationState.MutationPhase` verbatim: `pending`,\n * `acknowledged`, `rejected`, `dropped`), `mutator`, `journaledAt`,\n * `settledAt` once settled and `reason` only when rejected; `links.self`\n * and, for a graph-derived CRUD mutation, `links.resource`. The args are\n * never exposed: the status is about the intent's fate, not its content.\n * - `404 Not Found`, `code: \"unknown_mutation\"`, for an id the map does not\n * hold: never journaled by this engine, settled and evicted beyond the\n * retention window, or settled before this worker started — the three are\n * indistinguishable (ADR-0030 open point 1). A pending mutation survives a\n * worker restart, because the journal seeds the map.\n * - `Prefer: wait=N` (RFC 7240 §4.3) holds a `pending` answer until the\n * mutation leaves `pending` or `N` seconds pass, capped by the façade\n * (default 30 s), answering the current phase either way, with\n * `Preference-Applied: wait=N` (the wait applied, after the cap).\n */\n\nimport * as Duration from \"effect/Duration\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashMap from \"effect/HashMap\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport * as Stream from \"effect/Stream\";\nimport type { Node } from \"@thomasfosterau/legation\";\nimport type { MutationState } from \"@thomasfosterau/legation/internal\";\nimport type * as RestHandlers from \"./RestHandlers.js\";\n\n/** The JSON:API type of a status resource; `_legation` and this type are never an app's. */\nexport const resourceType = \"legation-mutations\";\n\n/** The path segments of the status route after the api prefix: `/_legation/mutations/{id}`. */\nexport const segment = \"_legation\";\n\n/** The default cap on `Prefer: wait`: a `respondWith` promise must not outlive the worker's patience. */\nexport const defaultMaxWait: Duration.Input = \"30 seconds\";\n\n/** The status resource of one tracked mutation. */\nexport interface StatusResource {\n readonly type: typeof resourceType;\n readonly id: string;\n readonly attributes: {\n readonly phase: MutationState.MutationPhase;\n readonly mutator: string;\n readonly journaledAt: number;\n readonly settledAt?: number;\n readonly reason?: string;\n };\n readonly links: { readonly self: string; readonly resource?: string };\n}\n\n/**\n * The link to the resource a graph-derived CRUD mutation (`{type}/create|update|delete`,\n * args `{ type, id, … }`) addresses: `{prefix}/{type}/{id}`. `undefined` for any other mutation.\n */\nconst resourceLink = (\n nodes: Node.NodeRegistry,\n prefix: string,\n state: MutationState.MutationState\n): string | undefined => {\n const parts = state.mutator.split(\"/\");\n const [type = \"\", operation = \"\"] = parts;\n if (parts.length !== 2 || !nodes.nodes.has(type)) return undefined;\n if (operation !== \"create\" && operation !== \"update\" && operation !== \"delete\") return undefined;\n const args = state.args;\n if (!P.isObject(args) || !(\"id\" in args) || !P.isString(args.id)) return undefined;\n return `${prefix}/${type}/${encodeURIComponent(args.id)}`;\n};\n\n/** The `200` document of the status URL: one status resource. */\nexport interface StatusDocument {\n readonly data: StatusResource;\n}\n\n/** The status document of a tracked mutation; `prefix` is where the api is mounted, as links see it. */\nexport const document = (\n nodes: Node.NodeRegistry,\n prefix: string,\n state: MutationState.MutationState\n): StatusDocument => {\n const self = `${prefix}/${segment}/mutations/${state.mutationId}`;\n const resource = resourceLink(nodes, prefix, state);\n const base = { phase: state.phase, mutator: state.mutator, journaledAt: state.journaledAt };\n const settledAt = state.settledAt;\n const timed = settledAt === undefined ? base : { ...base, settledAt };\n const reason = state.phase === \"rejected\" ? state.reason : undefined;\n return {\n data: {\n type: resourceType,\n id: String(state.mutationId),\n attributes: reason === undefined ? timed : { ...timed, reason },\n links: resource === undefined ? { self } : { self, resource },\n },\n };\n};\n\n/** The `404 unknown_mutation` error document. */\nexport const unknownDocument = (id: string): RestHandlers.ErrorDocument => ({\n errors: [\n {\n status: \"404\",\n code: \"unknown_mutation\",\n title: \"Unknown mutation\",\n detail:\n `No mutation ${id} is tracked here. It was never journaled by this worker, or it ` +\n \"settled and was evicted beyond the retention window, or it settled before this worker \" +\n \"started; the three cannot be told apart.\",\n },\n ],\n});\n\n/** A mutation id as the route carries it: a positive integer, or none. */\nexport const parseId = (raw: string): Option.Option<number> =>\n /^[1-9]\\d*$/.test(raw) ? Option.some(Number(raw)) : Option.none();\n\n/** One mutation's state now, from the engine's map stream (it emits the current map first). */\nexport const current = (\n states: Stream.Stream<MutationState.MutationStateMap>,\n mutationId: number\n): Effect.Effect<Option.Option<MutationState.MutationState>> =>\n Stream.runHead(states).pipe(Effect.map(Option.flatMap((map) => HashMap.get(map, mutationId))));\n\n/**\n * The mutation's state once it leaves `pending` (or is no longer tracked),\n * or as it is when `wait` elapses first.\n */\nexport const settled = (\n states: Stream.Stream<MutationState.MutationStateMap>,\n mutationId: number,\n wait: Duration.Duration\n): Effect.Effect<Option.Option<MutationState.MutationState>> =>\n states.pipe(\n Stream.map((map) => HashMap.get(map, mutationId)),\n Stream.filter((state) => Option.isNone(state) || state.value.phase !== \"pending\"),\n Stream.runHead,\n Effect.map(Option.flatten),\n Effect.timeoutOption(wait),\n Effect.flatMap(\n Option.match({\n onNone: () => current(states, mutationId),\n onSome: Effect.succeed,\n })\n )\n );\n","/**\n * Linkage\n *\n * What a document's relationships are resolved from beside the URL's\n * includes — shared by the derived REST handlers ({@link RestHandlers}) and\n * the replica-side writer ({@link ReplicaDocuments}), so both sides resolve\n * the same edges for the same declarations and the one serialiser\n * ({@link DocumentWriter}) writes the same bytes (ADR-0029 §6).\n *\n * **Linkage follows the resource's declaration.** effect-jsonapi's resource\n * schemas require every declared relationship on every resource object, so\n * a read resolves, beside its includes, the rows of every `Relationship.many`\n * the resource declares — on the primary resource, and on each included\n * resource's own declaration — and writes them as linkage, not `included`.\n * A `one` relationship's linkage is the edge's key field and costs nothing.\n * The primary resource's `many` relationships ride in the read's second\n * phase (they are selected beside its includes, {@link withLinkage}); the\n * included resources' ride in one more batch keyed by the included rows\n * ({@link resolve}). Nothing the resource does not declare is resolved, so a\n * collection the URL never named is never touched — neither for its cost\n * nor for its policy verdict. A paginated node edge is served under either\n * declaration: as `Relationship.many` it carries the spec's `links` and its\n * rows' linkage (the edge's declared order) and can be `include`d; as\n * `Relationship.paginated` it carries `links` only.\n *\n * A declaration the node graph cannot serve (a relationship that is no\n * edge, or of the other kind, or targeting another type) is a\n * definition-time defect ({@link planOf} throws).\n *\n * The rows come from a {@link Fetch}: the server's authorized batch\n * evaluation on the REST side (`SyncServer.readSubsets`), the replica's\n * local view on the worker side. One plan, one join, whichever source\n * answers (ADR-0025).\n *\n * Package-internal: the two callers import it directly; nothing outside\n * `@thomasfosterau/legation-jsonapi` derives linkage.\n */\n\nimport * as Arr from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as R from \"effect/Record\";\nimport type { Relationship, Resource } from \"@thomasfosterau/effect-jsonapi\";\nimport { Collection, type Node, Predicate, Query } from \"@thomasfosterau/legation\";\nimport { type Related, Subset } from \"@thomasfosterau/legation/internal\";\nimport * as DocumentWriter from \"./DocumentWriter.js\";\n\n/** A batch of subsets evaluated to rows — the row source a read runs over. */\nexport type Fetch<E> = (\n subsets: ReadonlyArray<Subset.Subset>\n) => Effect.Effect<ReadonlyArray<Related.SourcedRow>, E>;\n\n/**\n * The edges resolved beside the URL's includes, read off the resource's\n * declared relationships: the root resource's `Relationship.many` edges,\n * and per includable relationship, the target resource's own — the edge\n * names each included row's linkage is resolved for.\n */\nexport interface Plan {\n readonly root: ReadonlyArray<string>;\n readonly included: ReadonlyMap<string, ReadonlyArray<string>>;\n}\n\n/** The read's rows with the included resources' linkage resolved beside them. */\nexport interface Resolved {\n readonly rows: ReadonlyArray<Related.RelatedRow>;\n readonly linkage: DocumentWriter.Linkage;\n}\n\n// ─── The plan: what the resource declares ────────────────────────────────────\n\nconst declared = (resource: Resource.Any, name: string): string =>\n `Linkage: relationship \"${name}\" of resource \"${resource.type}\"`;\n\nconst descriptorsOf = (\n resource: Resource.Any\n): ReadonlyArray<readonly [string, Relationship.Descriptor]> =>\n Object.entries(resource.relationships) as ReadonlyArray<[string, Relationship.Descriptor]>;\n\n/** One declared relationship checked against the node's edge of that name: same name, same arity, same target. */\nconst checkDeclaration = (\n resource: Resource.Any,\n node: Node.AnyNode,\n name: string,\n descriptor: Relationship.Descriptor\n): void => {\n const edge = node.edges[name];\n if (edge === undefined) {\n throw new Error(`${declared(resource, name)} is not an edge of the \"${node.type}\" node`);\n }\n const toMany = descriptor.kind === \"many\" || descriptor.kind === \"paginated\";\n if (toMany === (edge.kind === \"one\")) {\n throw new Error(\n `${declared(resource, name)} is \"${descriptor.kind}\" but the node edge is \"${edge.kind}\"`\n );\n }\n if (descriptor.ref().type !== edge.target) {\n throw new Error(\n `${declared(resource, name)} targets \"${descriptor.ref().type}\" but the node edge targets \"${edge.target}\"`\n );\n }\n};\n\n/**\n * The resource's relationships as node edges, each checked against the\n * node's edge of that name. Returns the `Relationship.many` names — the\n * edges resolved for linkage.\n */\nconst manyEdgesOf = (resource: Resource.Any, node: Node.AnyNode): ReadonlyArray<string> => {\n const descriptors = descriptorsOf(resource);\n descriptors.forEach(([name, descriptor]) => checkDeclaration(resource, node, name, descriptor));\n return descriptors.flatMap(([name, descriptor]) => (descriptor.kind === \"many\" ? [name] : []));\n};\n\n/** The linkage plan of a resource over its node (a definition-time check of the whole declaration). */\nexport const planOf = (\n nodes: Node.NodeRegistry,\n resource: Resource.Any,\n node: Node.AnyNode\n): Plan => {\n const root = manyEdgesOf(resource, node);\n const included = new Map<string, ReadonlyArray<string>>(\n descriptorsOf(resource).flatMap(([name, descriptor]) => {\n if (descriptor.kind === \"paginated\") return [];\n const target = descriptor.ref();\n const targetNode = nodes.nodes.get(target.type);\n return targetNode === undefined ? [] : [[name, manyEdgesOf(target, targetNode)] as const];\n })\n );\n return { root, included };\n};\n\n/** The read to run: the URL's read with the root linkage edges selected beside its includes. */\nexport const withLinkage = (plan: Plan, read: Query.Read): Query.Read => {\n const include: Record<string, true | Query.IncludeOptions> = {\n ...R.fromIterableWith(plan.root, (name): [string, true] => [name, true]),\n ...read.include,\n };\n return R.isEmptyReadonlyRecord(include) ? read : { ...read, include };\n};\n\n/**\n * The collections the declared linkage is resolved from beyond the read's\n * own includes: the targets of the root's declared `many` edges the read\n * does not include, and of every declared `many` edge of each included\n * type. A replica that holds each of these whole answers the linkage\n * exactly as the server does — the coverage requirement\n * `ReplicaDocuments.toCover` states.\n */\nexport const collectionsOf = (\n nodes: Node.NodeRegistry,\n node: Node.AnyNode,\n plan: Plan,\n read: Query.Read\n): ReadonlyArray<string> => {\n const included = read.include ?? {};\n const roots = plan.root.flatMap((name) => {\n const edge = node.edges[name];\n return included[name] === undefined && edge !== undefined ? [edge.target] : [];\n });\n const nested = Object.keys(included).flatMap((name) => includedTargets(nodes, node, plan, name));\n return [...new Set([...roots, ...nested])];\n};\n\n/** The targets of the declared `many` edges of included edge `name`'s type. */\nconst includedTargets = (\n nodes: Node.NodeRegistry,\n node: Node.AnyNode,\n plan: Plan,\n name: string\n): ReadonlyArray<string> => {\n const via = node.edges[name];\n const target = via === undefined ? undefined : nodes.nodes.get(via.target);\n if (target === undefined) return [];\n return (plan.included.get(name) ?? []).flatMap((edge) => {\n const next = target.edges[edge];\n return next === undefined ? [] : [next.target];\n });\n};\n\n// ─── The included resources' batch ───────────────────────────────────────────\n\n/** The ids of the rows one included edge resolved across the root rows. */\nconst includedIds = (\n rows: ReadonlyArray<Related.RelatedRow>,\n name: string\n): ReadonlySet<string> => {\n return new Set(\n rows.flatMap((row) =>\n DocumentWriter.relatedValuesOf(row.related[name]).map(DocumentWriter.idOf)\n )\n );\n};\n\n/** One subset of the included-linkage batch: an edge's rows for a set of included parents. */\ninterface LinkageQuery {\n readonly type: string;\n readonly edge: string;\n readonly collection: string;\n readonly field: string;\n readonly order: ReadonlyArray<Subset.OrderBy>;\n readonly parents: Set<string>;\n}\n\n/** Add an included type's `many` edge to the batch for a set of parents, merging into the entry the batch already has. */\nconst addLinkageQuery = (\n nodes: Node.NodeRegistry,\n queries: Map<string, LinkageQuery>,\n type: string,\n edge: string,\n parents: ReadonlySet<string>\n): void => {\n const key = `${type}\\0${edge}`;\n const existing = queries.get(key);\n if (existing !== undefined) {\n parents.forEach((id) => existing.parents.add(id));\n return;\n }\n const relationship = Collection.relationshipsOf(nodes.collections, type).get(edge);\n if (relationship === undefined) return;\n queries.set(key, {\n type,\n edge,\n collection: relationship.collection,\n field: relationship.foreignField,\n order: relationship.order ?? [],\n parents: new Set(parents),\n });\n};\n\n/** The included-linkage batch a read needs: one subset per (included type, `many` edge), parents merged. */\nconst linkageQueries = (\n nodes: Node.NodeRegistry,\n plan: Plan,\n node: Node.AnyNode,\n read: Query.Read,\n rows: ReadonlyArray<Related.RelatedRow>\n): ReadonlyArray<LinkageQuery> => {\n const queries = new Map<string, LinkageQuery>();\n Object.keys(read.include ?? {}).forEach((name) => {\n const edges = plan.included.get(name) ?? [];\n const parents = includedIds(rows, name);\n if (Arr.isReadonlyArrayEmpty(edges) || parents.size === 0) return;\n const type = node.edges[name]?.target;\n if (type === undefined) return;\n edges.forEach((edge) => addLinkageQuery(nodes, queries, type, edge, parents));\n });\n return [...queries.values()];\n};\n\n/** The fetched rows of the batch, assigned to their parents: every parent gets every edge, empty or not. */\nconst assignLinkage = (\n queries: ReadonlyArray<LinkageQuery>,\n fetched: ReadonlyArray<Related.SourcedRow>\n): DocumentWriter.Linkage => {\n const linkage = new Map<string, Map<string, Record<string, Array<unknown>>>>();\n const bucket = (type: string, parent: string, edge: string): Array<unknown> => {\n const byId = linkage.get(type) ?? new Map<string, Record<string, Array<unknown>>>();\n linkage.set(type, byId);\n const edges = byId.get(parent) ?? {};\n byId.set(parent, edges);\n return (edges[edge] ??= []);\n };\n queries.forEach((query) => {\n query.parents.forEach((parent) => bucket(query.type, parent, query.edge));\n fetched.forEach((row) => {\n if (row.collection !== query.collection) return;\n const parent = String((row.value as Record<string, unknown>)[query.field]);\n if (query.parents.has(parent)) bucket(query.type, parent, query.edge).push(row.value);\n });\n });\n return linkage;\n};\n\n/**\n * Run a read over a row source with the linkage its resource declares:\n * the read's two phases (`Query.runVia`, the root linkage edges selected\n * beside the includes), then the included resources' `many` edges in one\n * more batch, keyed by the included rows. The rows and the linkage are\n * exactly what {@link DocumentWriter} takes.\n */\nexport const resolve = <E>(\n fetchRows: Fetch<E>,\n nodes: Node.NodeRegistry,\n node: Node.AnyNode,\n plan: Plan,\n read: Query.Read\n): Effect.Effect<Resolved, E> =>\n Effect.gen(function* () {\n const rows = yield* Query.runVia(fetchRows, nodes, withLinkage(plan, read));\n const queries = linkageQueries(nodes, plan, node, read, rows);\n const fetched = Arr.isReadonlyArrayEmpty(queries)\n ? []\n : yield* fetchRows(\n queries.map((query) =>\n Subset.make({\n collection: query.collection,\n where: Predicate.isIn(query.field, [...query.parents]),\n orderBy: query.order,\n })\n )\n );\n return { rows, linkage: assignLinkage(queries, fetched) };\n });\n","/**\n * ReplicaDocuments\n *\n * JSON:API documents written from the **replica** (issue #164): the\n * worker-side caller of {@link DocumentWriter}, the counterpart of the\n * derived REST handlers ({@link RestHandlers}) that write the same\n * documents from the backend. Given the node graph and a local view, a URL\n * (or a parsed read with its `fields[]` projection) runs as a read over the\n * rows the replica holds — `Query.runVia` over the view, the two-phase\n * include of ADR-0025 with the plan's edge windows applied — and its rows\n * are serialised by the one serialiser, so the same URL yields the same\n * document content on either side (ADR-0029 §6). The document sees the\n * optimistic overlay exactly as `Client.query` does (ADR-0029 §4); it\n * depends on nothing but `effect` and the two legation packages, so it runs\n * where the engine runs — a service worker included.\n *\n * **How the replica learns which relationships to emit.** The REST tier\n * derives its linkage from the endpoint's effect-jsonapi resource: every\n * `Relationship.many` the resource declares is resolved beside the URL's\n * includes and written as linkage ({@link Linkage}). The replica takes the\n * same input — a resource declaration per type ({@link Options.resources})\n * — and derives its plan through the same function, so for the same\n * declarations both sides resolve the same edges and write the same bytes\n * by construction; the façade (#166) is built from the app's `HttpApi` and\n * has these declarations at hand. An app that has only the node graph\n * passes nothing and gets `JsonApiQuery.resourcesOf(nodes)`: the synthetic\n * resources whose relationships are the node's edges — every collection\n * edge (paginated ones as `many`) resolved for linkage — which a REST\n * handler built over the same synthetic resources reproduces. A resource\n * the node graph cannot serve is a definition-time defect here as there.\n *\n * **One grammar on both sides.** A URL is parsed with the node-derived\n * codec (`JsonApiQuery.parseRead`), so parity holds when the endpoint is\n * declared with the same codec — `JsonApiQuery.querySchema(nodes,\n * collection)`, or declarations equivalent to it: a filter names the edge's\n * key field (`filter[categoryId]`), `sort` admits the node's sortable set\n * and `id`, and collection edges are `many` (a `paginated` declaration\n * refuses `include=` the node grammar accepts). Where the bound resource\n * declares less than the node — an edge it leaves out, a type it never\n * reaches — the endpoint cannot emit what the URL asks for, so the replica\n * refuses it the same way the codec would: an `include` edge or a\n * `fields[type]` type the resource does not declare is a `QueryError`\n * naming the parameter, raised before the read runs.\n *\n * **What the replica must hold.** The writer resolves everything from the\n * local view and cannot tell a missing row from an absent one, so a\n * document is faithful only when the replica holds every row the read and\n * its linkage need. That is the caller's coverage check (ADR-0029 §3,\n * `Client.coverageOf`): {@link ReplicaDocuments.toCover} names the reads a\n * request needs covered — the URL's read as stated, plus one\n * whole-collection read per collection the declared linkage resolves from\n * beyond the read's includes (the root's declared `many` edges the URL did\n * not include, and every declared `many` edge of each included type). A\n * replica holding each of those whole (under the same auth filter the\n * server applies) answers the linkage exactly as the server does. The\n * requirement is sound and conservative: a pin that holds an edge window\n * without the whole collection is not credited, and a read that is\n * uncovered goes to the network unchanged (ADR-0029 §4). The façade serves\n * a URL only when every read `toCover` lists is covered; this module never\n * decides that itself.\n *\n * A URL is network input, so nothing about it is a defect: a collection no\n * bound resource declares fails every entry point with a `QueryError`, and\n * the façade routes the request to the network.\n */\n\nimport * as Effect from \"effect/Effect\";\nimport type { Relationship, Resource } from \"@thomasfosterau/effect-jsonapi\";\nimport { type Node, type Query, QueryError } from \"@thomasfosterau/legation\";\nimport type { ClientView, Subset } from \"@thomasfosterau/legation/internal\";\nimport * as DocumentWriter from \"./DocumentWriter.js\";\nimport * as JsonApiQuery from \"./JsonApiQuery.js\";\nimport * as Linkage from \"./Linkage.js\";\n\n/** What the replica-side writer is bound to: the graph, the declarations linkage follows, the link prefix. */\nexport interface Options {\n /** The node graph URLs are parsed against, reads compile through and rows are written by. */\n readonly nodes: Node.NodeRegistry;\n /**\n * The resource declarations linkage follows, by type — the resources the\n * app's REST endpoints are declared with, so the replica emits exactly\n * the relationships the derived REST handler emits. Default: the node\n * graph's synthetic resources (`JsonApiQuery.resourcesOf(nodes)`), every\n * collection edge resolved. Every resource is checked against its node\n * when the writer is built; a read on a type no resource declares fails\n * with a `QueryError`.\n */\n readonly resources?: ReadonlyMap<string, Resource.Any>;\n /** The api's mount path, prepended to every link (`/jsonapi`); default `\"\"`. */\n readonly prefix?: string;\n}\n\n/** A document a URL yields: a collection document for `/{type}`, a single-resource document for `/{type}/{id}`. */\nexport type Document = DocumentWriter.CollectionDocument | DocumentWriter.DataDocument;\n\n/** The replica-side writer, bound to one graph and one set of declarations. */\nexport interface ReplicaDocuments {\n /**\n * Run a parsed read over the view and write its collection document.\n * Fails with a `QueryError` for a collection no bound resource declares,\n * or an `include` / `fields[type]` the bound resource does not declare.\n */\n readonly collection: (\n view: ClientView.Reader,\n parsed: JsonApiQuery.ParsedRead\n ) => Effect.Effect<DocumentWriter.CollectionDocument, QueryError>;\n /**\n * Run a parsed read over the view and write its single-resource document:\n * the first row, or `data: null` when the replica holds no matching row\n * (the caller decides the 404). Fails as {@link ReplicaDocuments.collection}.\n */\n readonly data: (\n view: ClientView.Reader,\n parsed: JsonApiQuery.ParsedRead\n ) => Effect.Effect<DocumentWriter.DataDocument, QueryError>;\n /**\n * Parse a URL (`JsonApiQuery.parseRead`: the read and its `fields[]`\n * projection together) and write the document it addresses — a\n * single-resource document for `/{type}/{id}`, a collection document\n * otherwise. Fails with the `QueryError` the grammar gives, naming the\n * parameter, for a URL the server would reject the same way; and as\n * {@link ReplicaDocuments.collection} for what the bound resource does\n * not declare.\n */\n readonly fromUrl: (\n view: ClientView.Reader,\n url: string | URL\n ) => Effect.Effect<Document, QueryError>;\n /**\n * The reads a request needs covered for its document to be faithful: the\n * read as stated, then one whole-collection read per collection the\n * declared linkage resolves from beyond the read's includes (see the\n * module doc). The caller checks each with `Client.coverageOf`. Fails\n * with a `QueryError` for a collection no bound resource declares — a\n * request the façade sends to the network.\n */\n readonly toCover: (read: Query.Read) => Effect.Effect<ReadonlyArray<Query.Read>, QueryError>;\n}\n\n/**\n * The local view as a row source: each subset evaluated over the replica\n * (confirmed rows with the optimistic overlay), rows tagged with their\n * collection, batches concatenated in subset order — the shape\n * `SyncServer.readSubsets` gives the REST tier. The subsets of a batch are\n * independent, so they run concurrently. A store failure is a defect, as\n * `Query.run` treats it.\n */\nexport const fetchOf =\n (view: ClientView.Reader): Linkage.Fetch<never> =>\n (subsets: ReadonlyArray<Subset.Subset>) =>\n Effect.forEach(\n subsets,\n (subset) =>\n view.query(subset).pipe(\n Effect.orDie,\n Effect.map((rows) =>\n rows.map((row) => ({ collection: subset.collection, id: row.id, value: row.value }))\n )\n ),\n { concurrency: \"unbounded\" }\n ).pipe(Effect.map((batches) => batches.flat()));\n\n// ─── The bound declarations ──────────────────────────────────────────────────\n\n/** One type as the writer serves it: its node, its resource, and the linkage plan derived from both. */\ninterface Binding {\n readonly node: Node.AnyNode;\n readonly resource: Resource.Any;\n readonly plan: Linkage.Plan;\n}\n\n/** Every resource bound to its node (a definition-time check of each declaration). */\nconst bindAll = (\n nodes: Node.NodeRegistry,\n resources: ReadonlyMap<string, Resource.Any>\n): ReadonlyMap<string, Binding> => {\n const bindings = new Map<string, Binding>();\n resources.forEach((resource) => {\n const node = nodes.nodes.get(resource.type);\n if (node === undefined) {\n throw new Error(`ReplicaDocuments: no node \"${resource.type}\" in the graph for the resource`);\n }\n bindings.set(resource.type, { node, resource, plan: Linkage.planOf(nodes, resource, node) });\n });\n return bindings;\n};\n\nconst descriptorsOf = (resource: Resource.Any): Readonly<Record<string, Relationship.Descriptor>> =>\n resource.relationships as Readonly<Record<string, Relationship.Descriptor>>;\n\n/** The types a resource's document can carry: its own and its relationships' targets. */\nconst carriedTypes = (resource: Resource.Any): ReadonlyArray<string> => [\n resource.type,\n ...Object.values(descriptorsOf(resource)).map((descriptor) => descriptor.ref().type),\n];\n\n/**\n * The rejection of what the bound resource does not declare, in the codec's\n * shape: an `include` edge that is no relationship of the resource, or a\n * `fields[type]` type its document cannot carry. Checked before the read\n * runs, so a refused request costs no query.\n */\nconst undeclared = (binding: Binding, parsed: JsonApiQuery.ParsedRead): QueryError | undefined => {\n const { resource } = binding;\n const relationships = descriptorsOf(resource);\n const name = Object.keys(parsed.read.include ?? {}).find(\n (included) => relationships[included] === undefined\n );\n if (name !== undefined) {\n return JsonApiQuery.invalidParameter(\n resource.type,\n \"include\",\n `\"${name}\" is not a relationship the \"${resource.type}\" resource declares (relationships: ${Object.keys(relationships).join(\", \")})`\n );\n }\n const types = carriedTypes(resource);\n const type = Object.keys(parsed.fields ?? {}).find((projected) => !types.includes(projected));\n if (type !== undefined) {\n return JsonApiQuery.invalidParameter(\n resource.type,\n `fields[${type}]`,\n `\"${type}\" is not a type the \"${resource.type}\" resource can carry (types: ${types.join(\", \")})`\n );\n }\n return undefined;\n};\n\n/** Bind the replica-side writer to a graph and its declarations (a definition-time check of every declaration). */\nexport const make = (options: Options): ReplicaDocuments => {\n const { nodes, prefix } = options;\n const bindings = bindAll(nodes, options.resources ?? JsonApiQuery.resourcesOf(nodes));\n\n /** The binding of a read's collection; a type nothing declares is the URL's failure, not a defect. */\n const bound = (read: Query.Read): Effect.Effect<Binding, QueryError> => {\n const binding = bindings.get(read.collection);\n return binding === undefined\n ? Effect.fail(\n new QueryError({\n message: `No resource declares \"${read.collection}\"; the replica cannot serve it`,\n query: read.collection,\n })\n )\n : Effect.succeed(binding);\n };\n\n /** The binding of a parsed read, with what the resource does not declare refused. */\n const checked = (parsed: JsonApiQuery.ParsedRead): Effect.Effect<Binding, QueryError> =>\n Effect.flatMap(bound(parsed.read), (binding) => {\n const error = undeclared(binding, parsed);\n return error === undefined ? Effect.succeed(binding) : Effect.fail(error);\n });\n\n /** The writer's input for a parsed read's rows off the view. */\n const input = (\n view: ClientView.Reader,\n parsed: JsonApiQuery.ParsedRead\n ): Effect.Effect<DocumentWriter.Input, QueryError> =>\n Effect.flatMap(checked(parsed), ({ node, plan }) =>\n Linkage.resolve(fetchOf(view), nodes, node, plan, parsed.read).pipe(\n Effect.map((resolved) => ({\n nodes,\n read: parsed.read,\n rows: resolved.rows,\n linkage: resolved.linkage,\n ...(parsed.fields === undefined ? {} : { fields: parsed.fields }),\n ...(prefix === undefined ? {} : { prefix }),\n }))\n )\n );\n\n const collection: ReplicaDocuments[\"collection\"] = (view, parsed) =>\n Effect.map(input(view, parsed), DocumentWriter.collection);\n\n const data: ReplicaDocuments[\"data\"] = (view, parsed) =>\n Effect.map(input(view, parsed), DocumentWriter.data);\n\n const fromUrl: ReplicaDocuments[\"fromUrl\"] = (view, url) =>\n JsonApiQuery.parseRead(nodes, url).pipe(\n Effect.flatMap((parsed): Effect.Effect<Document, QueryError> =>\n parsed.id === undefined ? collection(view, parsed) : data(view, parsed)\n )\n );\n\n const toCover: ReplicaDocuments[\"toCover\"] = (read) =>\n Effect.map(bound(read), ({ node, plan }) => [\n read,\n ...Linkage.collectionsOf(nodes, node, plan, read).map((name) => ({ collection: name })),\n ]);\n\n return { collection, data, fromUrl, toCover };\n};\n","/**\n * RestHandlers\n *\n * Derived JSON:API `list` / `get` handlers over the sync engine's read path\n * (issue #163). A JSON:API `GET` is ADR-0025's `read` operation with a\n * document body: the URL is parsed into a `Query.Read` by the one grammar\n * (`JsonApiQuery.parseParams`), the request's identity becomes a\n * `SyncContext`, the read runs through `Query.plan` → the filterable check\n * and the deny-by-default auth filters (`Authorization.authorize`) →\n * `Backend.evaluate` + `getRows` with ADR-0025's two-phase include\n * resolution (`Query.runVia` over `SyncServer.readSubsets` — the very\n * function the protocol's `handleRead` runs), and the rows are serialised\n * by {@link DocumentWriter}. Two carriers, one evaluator, one auth path:\n * what the sync tier syncs for a window is what the REST tier answers for\n * the same URL, so a façade serving that URL from the replica (ADR-0029 §6)\n * can match it.\n *\n * Scoping is the auth policy's, never the handler's: a request without\n * identity to a private collection sees the policy's empty allow-set —\n * an empty collection for `list`, a 404 for `get` — exactly as the sync\n * tier's `isIn(field, [])` behaves. No `WHERE userId` lives here.\n *\n * Sorting and paging are `Subset.apply`'s (ADR-0026 / ADR-0028): code-point\n * text order, NULLs last, the id tie-break, `page[after]` as the cursor —\n * the REST tier inherits them by construction.\n *\n * **Linkage follows the resource's declaration** ({@link Linkage}, shared\n * with the replica-side writer): beside the URL's includes, the rows of\n * every `Relationship.many` the endpoint's resource declares are resolved —\n * on the primary resource, and on each included resource's own declaration\n * — and written as linkage, not `included`; nothing the resource does not\n * declare is touched. A paginated node edge under `Relationship.paginated`\n * carries `links` only, and the endpoint's own codec refuses `include=`\n * for it. A declaration the node graph cannot serve is a definition-time\n * defect, thrown when the handler is built.\n *\n * **Outcomes the derivation owns.** A URL the grammar rejects is answered\n * with the codec's 400 error document, `source.parameter` naming the\n * offending key, before any backend call; a collection the policy denies\n * (no auth filter declared) is a 403, and within a batch every subset is\n * authorized before any is evaluated. Both are written as JSON:API error\n * responses by the handler — effect-jsonapi's `ApiError` classes carry no\n * `source` member, and every endpoint already declares the 400. A `get`\n * that matches no row fails with the error the caller declares on the\n * endpoint (`notFound`), so the api's own 404 class is what the client\n * decodes. A backend failure is a defect (500), as the hand-written\n * handlers' `orDie` made it.\n *\n * Derivation is opt-in per endpoint: `handlers.handle(\"list\", rest.list(Product))`\n * beside hand-written handlers on the same api.\n */\n\nimport * as Arr from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\nimport type { HttpServerRequest } from \"effect/http/HttpServerRequest\";\nimport * as HttpServerResponse from \"effect/http/HttpServerResponse\";\nimport {\n ApiError,\n type Document,\n MEDIA_TYPE,\n Middleware,\n type Resource,\n} from \"@thomasfosterau/effect-jsonapi\";\nimport {\n type Authorization,\n AuthorizationError,\n type Backend,\n BackendError,\n type Node,\n type Query,\n QueryError,\n} from \"@thomasfosterau/legation\";\nimport { type Subset, SyncServer } from \"@thomasfosterau/legation/internal\";\nimport * as DocumentWriter from \"./DocumentWriter.js\";\nimport * as JsonApiQuery from \"./JsonApiQuery.js\";\nimport * as Linkage from \"./Linkage.js\";\n\n// ─── Options ─────────────────────────────────────────────────────────────────\n\n/** What the derived handlers run over: the graph, the read path's seams, and the request's identity. */\nexport interface Options {\n /** The node graph the URLs are parsed against and the rows are written by. */\n readonly nodes: Node.NodeRegistry;\n /** The storage contract the read evaluates through. */\n readonly backend: Backend.Backend;\n /** The deny-by-default auth policy, with the filterable declarations (#154). */\n readonly policy: Authorization.AuthPolicy;\n /**\n * The identity seam: an HTTP request to the `SyncContext` the auth filters\n * see — the HTTP analogue of `IdentityResolver`, which resolves a client\n * group. Derive `identity` from the verified session (a forwarded header\n * the app trusts, a session token); never from anything a browser can\n * forge. `clientGroupId` names the carrier (`\"http\"`) or the session.\n */\n readonly context: (\n request: HttpServerRequest\n ) => Effect.Effect<Backend.SyncContext, AuthorizationError>;\n /** The interception seam around reads (`onRead`); absent means passthrough. */\n readonly middleware?: Authorization.SyncMiddleware;\n /** The api's mount path, prepended to every link (`/jsonapi`); default `\"\"`. */\n readonly prefix?: string;\n}\n\n/** The handler input a `list` endpoint gives (the rest of the request is not needed). */\nexport interface ListInput {\n readonly request: HttpServerRequest;\n}\n\n/** The handler input a `get` endpoint gives: the `:id` path parameter and the request. */\nexport interface GetInput {\n readonly params: { readonly id: string };\n readonly request: HttpServerRequest;\n}\n\n/** The collection document type of a resource's default `Endpoint.list` success. */\nexport type CollectionDocumentOf<R extends Resource.Any> = Document.CollectionDocument<\n R,\n Resource.DefaultIncluded<R[\"relationships\"]>,\n typeof Document.AnyMeta\n>[\"Type\"];\n\n/** The single-resource document type of a resource's default `Endpoint.get` success. */\nexport type DataDocumentOf<R extends Resource.Any> = Document.DataDocument<\n R,\n Resource.DefaultIncluded<R[\"relationships\"]>,\n typeof Document.AnyMeta\n>[\"Type\"];\n\n/** Options of a derived `get`: the endpoint's own 404. */\nexport interface GetOptions<E> {\n /** The error to fail with when no row matches — the `ApiError` class the endpoint declares. */\n readonly notFound: () => E;\n}\n\n/** The derived handler factories, bound to one graph and one read path. */\nexport interface RestHandlers {\n /**\n * The `list` handler of a resource: `GET /{type}?…` as a read over the\n * node of the same type. Typed as the resource's default collection\n * document; the endpoint's success encoder checks the document at\n * runtime, so a resource whose declaration disagrees with the node graph\n * (an attribute the node calls an edge) fails there, not silently.\n */\n readonly list: <R extends Resource.Any>(\n resource: R\n ) => (\n input: ListInput\n ) => Effect.Effect<CollectionDocumentOf<R> | HttpServerResponse.HttpServerResponse>;\n /**\n * The `get` handler of a resource: `GET /{type}/{id}?…` as the read\n * `filter[id]={id}`, first 1, taking `include` and `fields[…]` only.\n */\n readonly get: <R extends Resource.Any, E>(\n resource: R,\n options: GetOptions<E>\n ) => (\n input: GetInput\n ) => Effect.Effect<DataDocumentOf<R> | HttpServerResponse.HttpServerResponse, E>;\n}\n\n// ─── Error documents ─────────────────────────────────────────────────────────\n\n/** A JSON:API error document value (the shape `ApiError.toDocument` produces). */\nexport type ErrorDocument = typeof ApiError.WireDocument.Type;\n\n/**\n * The 400 error document of a URL the grammar rejects: the codec's own\n * document (`Middleware.schemaErrorDocument`, one error object per issue,\n * each with `source.parameter`) when the rejection came from decoding; the\n * same shape around the `QueryError`'s message and `parameter` when it came\n * from the graph checks that run before decoding (an undeclared include, a\n * `fields[]` type the read cannot carry). The façade answers a parse failure\n * with this document too (ADR-0029 §1).\n */\nexport const queryErrorDocument = (error: QueryError): ErrorDocument => {\n if (Schema.isSchemaError(error.cause)) {\n return Middleware.schemaErrorDocument(\"Query\", error.cause);\n }\n return {\n errors: [\n {\n status: String(ApiError.BadRequest.status),\n code: ApiError.BadRequest.code,\n ...(ApiError.BadRequest.title === undefined ? {} : { title: ApiError.BadRequest.title }),\n detail: error.message,\n ...(error.parameter === undefined ? {} : { source: { parameter: error.parameter } }),\n },\n ],\n };\n};\n\n/** The 403 error document of a collection the policy denies. */\nconst forbiddenDocument = (error: AuthorizationError): ErrorDocument => ({\n errors: [\n {\n status: String(ApiError.Forbidden.status),\n code: ApiError.Forbidden.code,\n ...(ApiError.Forbidden.title === undefined ? {} : { title: ApiError.Forbidden.title }),\n detail: error.message,\n },\n ],\n});\n\n/** An error document as a JSON:API response. */\nconst errorResponse = (\n status: number,\n document: ErrorDocument\n): HttpServerResponse.HttpServerResponse =>\n HttpServerResponse.jsonUnsafe(document, { status, contentType: MEDIA_TYPE });\n\n// ─── URL → read ──────────────────────────────────────────────────────────────\n\n/** `HttpServerRequest.url` is path + query; any origin makes it parseable. */\nconst searchParamsOf = (request: HttpServerRequest): URLSearchParams =>\n new URL(request.url, \"http://localhost\").searchParams;\n\n// ─── Failures ────────────────────────────────────────────────────────────────\n\n/** An outcome the derivation owns, as a response; a backend failure is a defect. */\nconst respondToFailures = <A, E>(\n effect: Effect.Effect<A, E | QueryError | AuthorizationError | BackendError>\n): Effect.Effect<A | HttpServerResponse.HttpServerResponse, E> =>\n Effect.catch(effect, (error) => {\n if (error instanceof QueryError) {\n return Effect.succeed(errorResponse(ApiError.BadRequest.status, queryErrorDocument(error)));\n }\n if (error instanceof AuthorizationError) {\n return Effect.succeed(errorResponse(ApiError.Forbidden.status, forbiddenDocument(error)));\n }\n if (error instanceof BackendError) return Effect.die(error);\n return Effect.fail(error as E);\n });\n\n// ─── The handlers ────────────────────────────────────────────────────────────\n\n/**\n * Bind the derived handlers to a graph and a read path. The node of a\n * resource is looked up by its `type` when the handler is built and the\n * resource's relationships are checked against the node's edges then, so a\n * declaration the graph cannot serve is a definition-time defect, never a\n * 500.\n */\nexport const make = (options: Options): RestHandlers => {\n const { nodes, backend, policy, middleware, prefix } = options;\n const deps: SyncServer.ReadDeps = {\n backend,\n authPolicy: policy,\n ...(middleware && { middleware }),\n };\n\n const nodeOf = (resource: Resource.Any): Node.AnyNode => {\n const node = nodes.nodes.get(resource.type);\n if (node === undefined) {\n throw new Error(`RestHandlers: no node \"${resource.type}\" in the graph for the resource`);\n }\n return node;\n };\n\n // ADR-0025's read behind the request's identity: `readSubsets` per batch\n // (filterable check, middleware, auth filters, evaluate + getRows) is the\n // row source; the two phases, the edge windows and the included\n // resources' linkage batch are `Linkage.resolve`'s — the same steps the\n // replica-side writer (`ReplicaDocuments`) runs over the local view.\n const run = (\n context: Backend.SyncContext,\n node: Node.AnyNode,\n plan: Linkage.Plan,\n read: Query.Read\n ): Effect.Effect<Linkage.Resolved, AuthorizationError | BackendError> =>\n Linkage.resolve(\n (subsets: ReadonlyArray<Subset.Subset>) =>\n SyncServer.readSubsets(deps, context, { clientGroupId: context.clientGroupId, subsets }),\n nodes,\n node,\n plan,\n read\n );\n\n /** The writer's input for a read's rows (the projection and prefix only when given). */\n const input = (\n read: Query.Read,\n resolved: Linkage.Resolved,\n fields: JsonApiQuery.Projection | undefined\n ): DocumentWriter.Input => ({\n nodes,\n read,\n rows: resolved.rows,\n linkage: resolved.linkage,\n ...(fields === undefined ? {} : { fields }),\n ...(prefix === undefined ? {} : { prefix }),\n });\n\n const list = <R extends Resource.Any>(resource: R) => {\n const node = nodeOf(resource);\n const plan = Linkage.planOf(nodes, resource, node);\n return ({ request }: ListInput) =>\n respondToFailures<CollectionDocumentOf<R>, never>(\n Effect.gen(function* () {\n const context = yield* options.context(request);\n const { read, fields } = yield* JsonApiQuery.parseParams(\n nodes,\n node.type,\n searchParamsOf(request)\n );\n const resolved = yield* run(context, node, plan, read);\n // The endpoint's success encoder checks the document against the\n // resource at runtime; the type here is the default collection\n // document the resource declares.\n return DocumentWriter.collection(\n input(read, resolved, fields)\n ) as CollectionDocumentOf<R>;\n })\n );\n };\n\n const get = <R extends Resource.Any, E>(resource: R, { notFound }: GetOptions<E>) => {\n const node = nodeOf(resource);\n const plan = Linkage.planOf(nodes, resource, node);\n return ({ params, request }: GetInput) =>\n respondToFailures<DataDocumentOf<R>, E>(\n Effect.gen(function* () {\n const context = yield* options.context(request);\n const single = yield* JsonApiQuery.singleRowParams(\n node.type,\n params.id,\n searchParamsOf(request)\n );\n const { read, fields } = yield* JsonApiQuery.parseParams(nodes, node.type, single);\n const resolved = yield* run(context, node, plan, read);\n if (Arr.isReadonlyArrayEmpty(resolved.rows)) return yield* Effect.fail(notFound());\n return DocumentWriter.data(input(read, resolved, fields)) as DataDocumentOf<R>;\n })\n );\n };\n\n return { list, get };\n};\n","/**\n * JsonApiFacade\n *\n * The façade of ADR-0029 (issue #166): a fetch handler that answers a\n * JSON:API `GET` from the replica when an explicit subscription covers it,\n * and stays out of the way otherwise. A service worker composes it into its\n * `fetch` listener **first**, before the HTTP cache and the network, so a\n * cached copy never becomes a second source of truth for a locally\n * answerable document (ADR-0029 §1).\n *\n * The handler is built from the app's `HttpApi` and the replica it reads:\n *\n * 1. **Route reflection.** `Convention.reflectResources(api)` gives the\n * `list` and `getOne` routes per type; those whose type is a node of the\n * graph are kept, so a route the replica cannot read (a server-only\n * resource) is never the façade's. A request is its business iff its\n * method is `GET`, its `Accept` names `application/vnd.api+json`, and its\n * path — under {@link Options.baseUrl} — matches one of those route\n * templates segment for segment. Anything else yields `undefined` and\n * the caller composes what comes next.\n * 2. **Parse.** The URL becomes a `Query.Read` through the one grammar\n * (`JsonApiQuery.parseRead`). A URL the grammar rejects is answered with\n * the codec's 400 error document (`RestHandlers.queryErrorDocument`),\n * whether or not the request is covered, because the server rejects it\n * identically — except an `include` the graph does not declare, which\n * goes to the network where the server rules on it (ADR-0029 §1), and a\n * path the graph cannot place, likewise.\n * 3. **Coverage.** Every read `ReplicaDocuments.toCover` names for the\n * request — the read itself and the whole collections its declared\n * linkage resolves from — is checked with {@link Options.coverageOf}, the\n * ledger's verdict (`Client.coverageOf`, or `Coverage.coverageOf` over\n * the registrations an `EngineHost` holds on mirrors' behalf). One\n * uncovered read sends the request to the network unchanged.\n * 4. **Answer.** A covered read runs over the view — confirmed rows with the\n * optimistic overlay, exactly what `Client.query` sees for a covered read\n * — and is serialised by the one writer, so the document's content is\n * byte-equal to the derived REST handler's for the same declarations\n * (ADR-0029 §6). The response is `200` `application/vnd.api+json` with\n * `Cache-Control: no-store` (the replica is the cache) and\n * `x-legation-served-at: <cookie>`, the replica's CVR cookie at the time\n * of the answer, so devtools and tests can\n * tell a local answer from a network one.\n * 5. **Offline.** An uncovered request while the network is unreachable —\n * `navigator.onLine === false` here, or a forwarded fetch that rejected\n * at the transport in the caller ({@link FetchHandler.offline}) — is\n * answered with the 503 `offline` error document, the one error the\n * façade synthesises that the server never would (ADR-0029 §4). A status\n * code from the server is never offline, and a covered request is never\n * affected by connectivity.\n *\n * **The parity assumption.** Answering a parse failure locally, and a\n * covered request at all, presumes the server rules on the same URL the\n * same way: its read endpoints are declared with the graph's own codec\n * (`JsonApiQuery.querySchema` for a `list`, `singleRowSchema` for a `get`)\n * and served by the derived handlers (`RestHandlers`), as the commerce\n * example does. A hand-written server with another grammar — a filter key\n * the node does not declare, a `sort` the codec refuses, a different `page`\n * vocabulary — must not compose the façade: its 400s and its documents\n * would diverge from the server's.\n *\n * 6. **Writes** (ADR-0030, with {@link Options.mutate} set). A `POST` /\n * `PATCH` / `DELETE` on a reflected write route of a type the graph\n * declares (and {@link Options.writes} allows) is forwarded unchanged\n * while online and unasked; offline, after a forward that rejected at the\n * transport, or on `Prefer: respond-async`, it is decoded structurally\n * (`FacadeWrites`), mapped to a mutation by the intent mapping (default:\n * the graph-derived CRUD mutations, `CrudMutation`), journaled, and\n * answered with a `202 Accepted` **write receipt**: the resource as\n * journaled, read back through the one writer, `meta.legation.status:\n * \"pending\"` and a `Location` naming the mutation status URL. Never `201`,\n * `200` or `204`: those are the server's words for \"applied\". A write it\n * cannot journal is forwarded online; offline it gets ADR-0030 §3's error\n * documents: `400 invalid_document`, `409 type_mismatch` / `id_mismatch`\n * or `422 unsupported_relationship` for a malformed body, and the `503`\n * `offline` document otherwise, with `client_id_required` appended for a\n * create without an id and `not_journalable` for a mutation the engine\n * refuses. Attribute values are never the façade's to refuse.\n *\n * 7. **The mutation status URL** (ADR-0030 §2, with\n * {@link Options.mutationStates} set): `GET {prefix}/_legation/mutations/{id}`\n * beside every reflected prefix is answered from the engine's\n * mutation-state map and never forwarded (`MutationStatus`): `200` with\n * the mutation's phase, `404 unknown_mutation` for an id the map does not\n * hold, `Prefer: wait=N` holding a pending answer up to\n * {@link Options.maxWait}.\n *\n * What it never does: register a subscription because a request arrived,\n * journal a write online unless asked, or rewrite a request it forwards. A single-resource\n * request whose row the covered replica does not hold is forwarded too: the\n * 404 is the endpoint's own error class, which only the server can write.\n *\n * It lives in `@thomasfosterau/legation-jsonapi` rather than `@thomasfosterau/legation-browser` by\n * ADR-0006's rule: its dependencies are this package's (the codec, the\n * writer, route reflection) plus the standard `Request` / `Response`\n * globals, and the one browser-only reading — `navigator.onLine` — is an\n * option with a guarded default. `@thomasfosterau/legation-browser` therefore stays free of\n * effect-jsonapi; its `ServiceWorkerHost.start` hands a worker what this\n * handler needs from the host.\n */\n\nimport * as Arr from \"effect/Array\";\nimport * as Duration from \"effect/Duration\";\nimport * as Effect from \"effect/Effect\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport * as Result from \"effect/Result\";\nimport * as Schema from \"effect/Schema\";\nimport type * as Stream from \"effect/Stream\";\nimport type * as HttpApi from \"effect/http-api/HttpApi\";\nimport type * as HttpApiGroup from \"effect/http-api/HttpApiGroup\";\nimport { MEDIA_TYPE, type Resource } from \"@thomasfosterau/effect-jsonapi\";\nimport { Query } from \"@thomasfosterau/legation\";\nimport type {\n CrudMutation,\n MutatorError,\n Node,\n QueryError,\n StoreError,\n} from \"@thomasfosterau/legation\";\nimport type {\n ClientEngine,\n ClientView,\n Coverage,\n MutationState,\n} from \"@thomasfosterau/legation/internal\";\nimport { Subset } from \"@thomasfosterau/legation/internal\";\nimport * as Convention from \"./Convention.js\";\nimport * as FacadeWrites from \"./FacadeWrites.js\";\nimport * as JsonApiQuery from \"./JsonApiQuery.js\";\nimport * as MutationStatus from \"./MutationStatus.js\";\nimport * as ReplicaDocuments from \"./ReplicaDocuments.js\";\nimport type { Write } from \"./JsonApiBackend.js\";\nimport * as RestHandlers from \"./RestHandlers.js\";\n\n// ─── Options ─────────────────────────────────────────────────────────────────\n\n/** What the façade is built from: the api's routes, the graph, the replica and its ledger. */\nexport interface Options<Id extends string, Groups extends HttpApiGroup.Constraint> {\n /** The node graph URLs are parsed against and documents are written by. */\n readonly nodes: Node.NodeRegistry;\n /**\n * The app's api; its `list` / `getOne` routes (the api's own prefix\n * included) whose type is a node of the graph are what the façade\n * recognises. Its read endpoints must be declared with the graph's codec\n * (the module doc's parity assumption).\n */\n readonly api: HttpApi.HttpApi<Id, Groups>;\n /**\n * Where the api is served as the browser sees it, in front of the routes\n * the api declares: an origin (`https://api.example.com`), an\n * origin-relative path (`/proxy`), or `\"\"` (default) for the page's own\n * origin with no extra path.\n */\n readonly baseUrl?: string;\n /** The replica a covered read runs over: `ClientView.fromEngine(engine)` in a worker, `client.view` over a Client. */\n readonly view: ClientView.Reader;\n /**\n * The ledger's verdict for a read — `client.coverageOf`, or\n * `Coverage.coverageOf(nodes, view.query, host.registrations)` over the registrations\n * an `EngineHost` holds on mirrors' behalf. A request is answered locally\n * only when every read it needs is covered. `options.snapshot` is the root\n * rows the façade read for the request, with their subset: the verdict is\n * judged over them for that subset (#426), and any other read is judged as usual.\n */\n readonly coverageOf: (\n read: Query.Read,\n options?: Coverage.JudgeOptions\n ) => Effect.Effect<Coverage.Verdict>;\n /**\n * The replica's CVR cookie, for `x-legation-served-at` — the store's\n * `getCookie`, read only when a response is synthesised. Absent, or\n * failing, the header is empty.\n */\n readonly cookie?: Effect.Effect<string | undefined, unknown>;\n /**\n * The resource declarations linkage follows — those the api's endpoints\n * are declared with, so the replica writes the relationships the server\n * writes. Default: the graph's synthetic resources (see `ReplicaDocuments`).\n */\n readonly resources?: ReadonlyMap<string, Resource.Any>;\n /**\n * The prefix of every link in a document. Default: the matched route's\n * own prefix (`/jsonapi` for a route `/jsonapi/products`), which is what\n * a server mounting the api at its declared prefix writes.\n */\n readonly prefix?: string;\n /** Whether the network is reachable; default `navigator.onLine !== false` (reachable where there is no `navigator`). */\n readonly online?: () => boolean;\n /**\n * The engine's journal seam for façade writes (ADR-0030 §5): in a worker,\n * `host.engine.mutateWithAck`. Absent, the façade intercepts no write: a\n * `POST` / `PATCH` / `DELETE` is never its business, as before ADR-0030.\n */\n readonly mutate?: (\n mutator: string,\n args: unknown\n ) => Effect.Effect<ClientEngine.MutationHandle, MutatorError | StoreError>;\n /**\n * The intent mapping: a decoded write to the mutation the engine journals,\n * or `undefined` when it is not interceptable. Default: the graph-derived\n * CRUD mutations (`CrudMutation`, `FacadeWrites.graphIntentOf`), which the\n * engine's registry must then carry (`CrudMutation.entries(nodes)`), with a\n * server handler under each name.\n */\n readonly intentOf?: FacadeWrites.IntentOf;\n /**\n * Which reflected write routes may be intercepted, per type: owning this\n * declaration means owning the server's side of it (handlers under the\n * mutation names, creates that honour the client id, ADR-0030 §4).\n * Default: every reflected `create` / `update` / `delete` route of a type\n * the graph declares.\n */\n readonly writes?: CrudMutation.Writes;\n /**\n * The pull to signal after a write forwarded online succeeded\n * ({@link FetchHandler.forwarded}): in a worker, `host.engine.pull`. Its\n * failure is ignored; the sync loop pulls again on its own.\n */\n readonly pull?: Effect.Effect<unknown, unknown>;\n /**\n * The engine's mutation-state map (`engine.mutationStates`, #116), which\n * the mutation status URL `{prefix}/_legation/mutations/{mutationId}` is\n * answered from (ADR-0030 §2, `MutationStatus`). Absent, that route is not\n * the façade's. A worker composing the façade should raise the engine's\n * `mutationStateRetention.maxTerminal`, so a settled phase outlives a busy\n * session.\n */\n readonly mutationStates?: Stream.Stream<MutationState.MutationStateMap>;\n /** The cap on a status request's `Prefer: wait`; default 30 seconds. */\n readonly maxWait?: Duration.Input;\n}\n\n/** The built façade. */\nexport interface FetchHandler {\n /**\n * Whether a request is the façade's business: a `GET` accepting\n * `application/vnd.api+json` on a reflected read route under `baseUrl`,\n * or — with {@link Options.mutate} set — a `POST` / `PATCH` / `DELETE` on a\n * reflected write route the façade may intercept, accepting the media\n * type and (for `POST` / `PATCH`) sending it without the atomic extension\n * (ADR-0030 §3). A worker asks it for every method, clones a matched\n * write before forwarding it, and turns a forward that rejected at the\n * transport into {@link FetchHandler.offline}.\n */\n readonly matches: (request: Request) => boolean;\n /**\n * The façade's answer: a document (200), the codec's 400 for a URL the\n * grammar rejects, the 503 `offline` document for an uncovered request\n * while offline, a `202` write receipt for a write it journals (offline,\n * or on `Prefer: respond-async`) — or `undefined` when the request is not\n * the façade's business, is uncovered and online, or is a write to\n * forward, for the caller to forward unchanged. A write's body is read\n * from a clone, so the request itself can still be forwarded. A store\n * failure while reading the replica is a defect, as `Query.run` treats it.\n */\n readonly handle: (request: Request) => Effect.Effect<Response | undefined>;\n /**\n * What a worker answers when the forward of a request {@link matches} held\n * for rejected at the transport, the other half of ADR-0029 §4's\n * definition: for a write, the request is journaled and answered with a\n * `202` receipt (pass the clone taken before forwarding, whose body is\n * unread); otherwise, or when the write cannot be journaled, the 503\n * `offline` response with the replica's current cookie.\n */\n readonly offline: (request: Request) => Effect.Effect<Response>;\n /**\n * Tell the façade what a forwarded request came back with: after a `2xx`\n * to a write it {@link matches}, it signals {@link Options.pull} so a\n * covered read soon shows the server's row (ADR-0030 §3). A worker runs it\n * in the background (`event.waitUntil`); it never fails.\n */\n readonly forwarded: (request: Request, response: Response) => Effect.Effect<void>;\n}\n\n// ─── Headers and documents ───────────────────────────────────────────────────\n\n/** The header a locally served response carries: the replica's CVR cookie at the time of the answer. */\nexport const servedAtHeader = \"x-legation-served-at\";\n\n/** The 503 error document of an uncovered request while offline (ADR-0029 §4). */\nexport const offlineDocument: RestHandlers.ErrorDocument = {\n errors: [\n {\n status: \"503\",\n code: \"offline\",\n title: \"Service unavailable\",\n detail: \"The request is not covered by a local subscription and the network is unreachable.\",\n },\n ],\n};\n\n/** Every response the façade synthesises: JSON:API, never cached, marked as served locally. */\nconst respondWith = (\n status: number,\n body: unknown,\n cookie: string | undefined,\n headers: Readonly<Record<string, string>> = {}\n): Response =>\n new Response(JSON.stringify(body), {\n status,\n headers: {\n ...headers,\n \"content-type\": MEDIA_TYPE,\n \"cache-control\": \"no-store\",\n [servedAtHeader]: cookie ?? \"\",\n },\n });\n\n/**\n * Why a write candidate was not journaled: its body was refused\n * structurally (`FacadeWrites.Refusal`), the engine refused the mutation (a\n * `MutatorError`: the intent mapping named a mutator it does not register),\n * or there is no mutation to journal (the intent mapping declined it, or the\n * store failed).\n */\ntype Unjournaled =\n | { readonly _tag: \"Refused\"; readonly refusal: FacadeWrites.Refusal }\n | { readonly _tag: \"NotJournalable\"; readonly detail: string }\n | { readonly _tag: \"Unmapped\" };\n\n/** One error object of a façade-synthesised write error, `source.pointer` when it names one. */\nconst errorObject = (refusal: {\n readonly status: number;\n readonly code: string;\n readonly title: string;\n readonly detail: string;\n readonly pointer?: string;\n}): RestHandlers.ErrorDocument[\"errors\"][number] => {\n const error = {\n status: String(refusal.status),\n code: refusal.code,\n title: refusal.title,\n detail: refusal.detail,\n };\n return refusal.pointer === undefined ? error : { ...error, source: { pointer: refusal.pointer } };\n};\n\n/** The 503 `offline` document with a second error object saying why the write was not journaled. */\nconst offlineWith = (reason: Parameters<typeof errorObject>[0]): RestHandlers.ErrorDocument => ({\n errors: [...offlineDocument.errors, errorObject(reason)],\n});\n\n/**\n * The offline answer to a write it could not journal (ADR-0030 §3): a\n * structural refusal is its own `400` / `409` / `422` document — the statuses\n * JSON:API prescribes for the same faults, so no divergence from the server —\n * except a create without a client id, which is the `503` `offline` document\n * with `client_id_required` appended; an engine refusal is `503` `offline`\n * with `not_journalable`; anything else the plain `503` `offline`.\n */\nconst unjournaledDocument = (\n failure: Unjournaled\n): readonly [status: number, document: RestHandlers.ErrorDocument] =>\n Match.valueTags(failure, {\n Refused: ({ refusal }): readonly [number, RestHandlers.ErrorDocument] =>\n refusal.status === 503\n ? [503, offlineWith(refusal)]\n : [refusal.status, { errors: [errorObject(refusal)] }],\n NotJournalable: ({ detail }): readonly [number, RestHandlers.ErrorDocument] => [\n 503,\n offlineWith({ status: 503, code: \"not_journalable\", title: \"Not journalable\", detail }),\n ],\n Unmapped: (): readonly [number, RestHandlers.ErrorDocument] => [503, offlineDocument],\n });\n\n/** The 503 response of an uncovered request while offline, marked with the cookie when known. */\nexport const offlineResponse = (cookie?: string): Response =>\n respondWith(503, offlineDocument, cookie);\n\n// ─── Routes ──────────────────────────────────────────────────────────────────\n\n/** One reflected read route, ready to match a request path against. */\ninterface Route {\n readonly type: string;\n /** The template's segments (`Convention.segmentsOf`); a `:param` segment matches any one. */\n readonly segments: ReadonlyArray<string>;\n /** The link prefix the route implies: the template before `/{type}`. */\n readonly prefix: string;\n}\n\nconst routeOf = (type: string, template: string, single: boolean): Route => {\n const segments = Convention.segmentsOf(template);\n const prefix = segments.slice(0, segments.length - (single ? 2 : 1));\n return { type, segments, prefix: Arr.isReadonlyArrayEmpty(prefix) ? \"\" : `/${prefix.join(\"/\")}` };\n};\n\n/** The read routes of the api whose type the graph declares: a `list` and a `getOne` per such resource. */\nconst routesOf = <Id extends string, Groups extends HttpApiGroup.Constraint>(\n api: HttpApi.HttpApi<Id, Groups>,\n nodes: Node.NodeRegistry\n): ReadonlyArray<Route> => {\n return [...Convention.reflectResources(api).values()].flatMap((resource) => {\n if (!nodes.nodes.has(resource.type)) return [];\n const list =\n resource.list === undefined ? [] : [routeOf(resource.type, resource.list.path, false)];\n const one =\n resource.getOne === undefined ? [] : [routeOf(resource.type, resource.getOne.path, true)];\n return list.concat(one);\n });\n};\n\n/** One reflected write route the façade may intercept (ADR-0030 §3). */\ninterface WriteRoute extends Route {\n readonly operation: \"create\" | \"update\" | \"delete\";\n /** The node the route writes. */\n readonly node: Node.AnyNode;\n /** The method it answers: `POST`, `PATCH` or `DELETE` (a `PUT` update is never intercepted). */\n readonly method: string;\n}\n\nconst writeMethods = { create: \"POST\", update: \"PATCH\", delete: \"DELETE\" } as const;\n\n/** The write routes of the api whose type the graph declares and `writes` allows. */\nconst writeRoutesOf = <Id extends string, Groups extends HttpApiGroup.Constraint>(\n api: HttpApi.HttpApi<Id, Groups>,\n nodes: Node.NodeRegistry,\n writes: CrudMutation.Writes | undefined\n): ReadonlyArray<WriteRoute> =>\n Arr.flatMap([...Convention.reflectResources(api).values()], (resource) => {\n const node = nodes.nodes.get(resource.type);\n if (node === undefined) return [];\n return Arr.filterMap([\"create\", \"update\", \"delete\"] as const, (operation) => {\n const endpoint = resource[operation];\n const method = writeMethods[operation];\n const allowed = writes === undefined || (writes[resource.type] ?? []).includes(operation);\n return endpoint === undefined || endpoint.method.toUpperCase() !== method || !allowed\n ? Result.failVoid\n : Result.succeed({\n ...routeOf(resource.type, endpoint.path, operation !== \"create\"),\n operation,\n node,\n method,\n });\n });\n });\n\nconst matchesTemplate = (route: Route, segments: ReadonlyArray<string>): boolean =>\n route.segments.length === segments.length &&\n route.segments.every((template, index) =>\n Convention.isParam(template) ? true : template === segments[index]\n );\n\n/** Where the api is served: an origin to require, and the path in front of the routes. */\ninterface Base {\n readonly origin?: string;\n readonly path: string;\n}\n\nconst baseOf = (baseUrl: string): Base => {\n if (baseUrl === \"\" || baseUrl.startsWith(\"/\")) return { path: baseUrl.replace(/\\/+$/, \"\") };\n const url = new URL(baseUrl);\n return { origin: url.origin, path: url.pathname.replace(/\\/+$/, \"\") };\n};\n\n/**\n * The request path relative to the base, or `undefined` when it lies\n * elsewhere. A trailing slash is left to the server: the route templates\n * carry none, and whether `/products/` is `/products` is its ruling.\n */\nconst pathUnder = (base: Base, url: URL): string | undefined => {\n if (base.origin !== undefined && url.origin !== base.origin) return undefined;\n if (!url.pathname.startsWith(base.path) || url.pathname.endsWith(\"/\")) return undefined;\n const rest = url.pathname.slice(base.path.length);\n return rest.startsWith(\"/\") ? rest : undefined;\n};\n\n// ─── Requests ────────────────────────────────────────────────────────────────\n\n/** Whether an `Accept` header names the JSON:API media type (parameters aside). */\nconst acceptsJsonApi = (header: string | null): boolean =>\n header !== null &&\n header\n .split(\",\")\n .some((part) => (part.trim().split(\";\")[0] ?? \"\").trim().toLowerCase() === MEDIA_TYPE);\n\n/**\n * Whether a `Content-Type` is the JSON:API media type without the atomic\n * extension: an `ext` parameter naming atomic marks the operations endpoint,\n * never a façade write (ADR-0030 §5).\n */\nconst sendsJsonApi = (header: string | null): boolean => {\n if (header === null) return false;\n const [type = \"\", ...parameters] = header.split(\";\");\n if (type.trim().toLowerCase() !== MEDIA_TYPE) return false;\n return !parameters.some((parameter) => {\n const [name = \"\", value = \"\"] = parameter.split(\"=\");\n return name.trim().toLowerCase() === \"ext\" && value.toLowerCase().includes(\"atomic\");\n });\n};\n\nconst navigatorOnline = (): boolean => {\n const navigator = (globalThis as { navigator?: { onLine?: boolean } }).navigator;\n return navigator?.onLine !== false;\n};\n\n/** A candidate request: the route it matched and its URL, parsed once. */\ninterface Candidate {\n readonly route: Route;\n readonly url: URL;\n}\n\n// ─── Outcomes ────────────────────────────────────────────────────────────────\n\n/** How a candidate request leaves the façade short of a document: forwarded, or answered with an error. */\ntype Outcome =\n | { readonly _tag: \"Forward\" }\n | { readonly _tag: \"Respond\"; readonly response: Response };\n\nconst forward: Outcome = { _tag: \"Forward\" };\nconst respond = (response: Response): Outcome => ({ _tag: \"Respond\", response });\n\n/**\n * A grammar rejection as the server would rule on it. An `include` the\n * graph does not declare is the server's call (ADR-0029 §1), and so is a\n * path the graph cannot place (no parameter, no decoding issue: the URL\n * names something the graph does not); anything else is the codec's 400,\n * which the server returns identically.\n */\nconst queryFailure = (error: QueryError, cookie: string | undefined): Outcome =>\n error.parameter === \"include\" ||\n (error.parameter === undefined && !Schema.isSchemaError(error.cause))\n ? forward\n : respond(respondWith(400, RestHandlers.queryErrorDocument(error), cookie));\n\n// ─── The handler ─────────────────────────────────────────────────────────────\n\n/**\n * Build the façade over an api and a replica. Route reflection and the\n * writer's declaration checks run here, so a declaration the graph cannot\n * serve is a definition-time defect, never a response.\n */\nexport const fetchHandler = <Id extends string, Groups extends HttpApiGroup.Constraint>(\n options: Options<Id, Groups>\n): FetchHandler => {\n const { nodes, view, coverageOf } = options;\n const routes = routesOf(options.api, nodes);\n const mutate = options.mutate;\n const writeRoutes = mutate === undefined ? [] : writeRoutesOf(options.api, nodes, options.writes);\n const intentOf = options.intentOf ?? FacadeWrites.graphIntentOf(nodes);\n const base = baseOf(options.baseUrl ?? \"\");\n const online = options.online ?? navigatorOnline;\n /** The cookie at the time of an answer; read only when a response is synthesised. */\n const cookie: Effect.Effect<string | undefined> =\n options.cookie === undefined\n ? Effect.succeed(undefined)\n : Effect.catch(options.cookie, () => Effect.succeed(undefined));\n // One writer per link prefix the routes imply (one, for an api mounted once).\n const writers = new Map<string, ReplicaDocuments.ReplicaDocuments>();\n /** The writer for a link prefix: one per prefix, built when a route first needs it. */\n const writerFor = (prefix: string): ReplicaDocuments.ReplicaDocuments => {\n const existing = writers.get(prefix);\n if (existing !== undefined) return existing;\n const made = ReplicaDocuments.make({\n nodes,\n prefix,\n ...(options.resources === undefined ? {} : { resources: options.resources }),\n });\n writers.set(prefix, made);\n return made;\n };\n\n routes.forEach((route) => {\n writerFor(options.prefix ?? route.prefix);\n });\n\n const candidateOf = (request: Request): Candidate | undefined => {\n if (request.method !== \"GET\" || !acceptsJsonApi(request.headers.get(\"accept\"))) {\n return undefined;\n }\n const url = new URL(request.url);\n const path = pathUnder(base, url);\n if (path === undefined) return undefined;\n const segments = Convention.segmentsOf(path);\n const route = routes.find((candidate) => matchesTemplate(candidate, segments));\n return route === undefined ? undefined : { route, url };\n };\n\n /** Rules 1 to 4 for every read the request needs, judged over the request's root rows: covered by the ledger, or not the façade's to answer. */\n const covered = (\n reads: ReadonlyArray<Query.Read>,\n snapshot: Coverage.Snapshot\n ): Effect.Effect<boolean> =>\n Effect.forEach(reads, (read) => coverageOf(read, { snapshot })).pipe(\n Effect.map((verdicts) => verdicts.every((verdict) => verdict._tag === \"Covered\"))\n );\n\n /** The replica with the request's root window answered from `rows`: the rows coverage judged, not a second read. */\n const pinned = (\n base: ClientView.Reader,\n root: Subset.Subset,\n rows: ReadonlyArray<ClientEngine.LocalRow>\n ): ClientView.Reader => ({\n query: (subset) =>\n Subset.hash(subset) === Subset.hash(root) ? Effect.succeed(rows) : base.query(subset),\n observe: base.observe,\n });\n\n /** A rejection as an outcome, with the cookie read for the response it may carry. */\n const rejected = (error: QueryError): Effect.Effect<never, Outcome> =>\n Effect.flatMap(cookie, (served) => Effect.fail(queryFailure(error, served)));\n\n const answer = ({ route, url }: Candidate) =>\n Effect.gen(function* () {\n const docs = writers.get(options.prefix ?? route.prefix);\n // Every route's prefix has a writer (built above); an unknown one is the server's to answer.\n if (docs === undefined) return yield* Effect.fail(forward);\n const parsed = yield* JsonApiQuery.parseRead(nodes, url).pipe(Effect.catch(rejected));\n // A collection no bound resource declares: the server rules on it.\n const needed = yield* docs.toCover(parsed.read).pipe(Effect.mapError(() => forward));\n // The request's root rows, read once: coverage is judged over them and the document is\n // written from them, so a pull between the two cannot add a root row whose edge windows\n // are not pulled yet (#426). A root that cannot be read is uncovered, as before.\n const root = yield* Query.tryPlan(nodes, parsed.read).pipe(Effect.mapError(() => forward));\n const rows = yield* view\n .query(root.root)\n .pipe(\n Effect.orElseSucceed((): ReadonlyArray<ClientEngine.LocalRow> | undefined => undefined)\n );\n if (rows === undefined || !(yield* covered(needed, { subset: root.root, rows }))) {\n if (online()) return yield* Effect.fail(forward);\n return yield* Effect.flatMap(cookie, (served) =>\n Effect.fail(respond(offlineResponse(served)))\n );\n }\n const replica = pinned(view, root.root, rows);\n const write: Effect.Effect<ReplicaDocuments.Document, QueryError> =\n parsed.id === undefined ? docs.collection(replica, parsed) : docs.data(replica, parsed);\n const document = yield* write.pipe(Effect.catch(rejected));\n // No such row in a faithful replica: the 404 is the endpoint's own.\n if (parsed.id !== undefined && document.data === null) return yield* Effect.fail(forward);\n return respondWith(200, document, yield* cookie);\n });\n\n const readHandle = (request: Request): Effect.Effect<Response | undefined> => {\n const candidate = candidateOf(request);\n if (candidate === undefined) return Effect.succeed(undefined);\n return answer(candidate).pipe(\n Effect.catchTags({\n Forward: () => Effect.succeed(undefined),\n Respond: (outcome) => Effect.succeed(outcome.response),\n })\n );\n };\n\n // ─── Writes (ADR-0030) ─────────────────────────────────────────────────────\n\n /** A write the façade may intercept: the route, its target, and where its api is mounted. */\n interface WriteCandidate {\n readonly route: WriteRoute;\n readonly target: FacadeWrites.Target;\n }\n\n const writeCandidateOf = (request: Request): WriteCandidate | undefined => {\n const method = request.method.toUpperCase();\n if (!acceptsJsonApi(request.headers.get(\"accept\"))) return undefined;\n if (method !== \"DELETE\" && !sendsJsonApi(request.headers.get(\"content-type\"))) {\n return undefined;\n }\n const path = pathUnder(base, new URL(request.url));\n if (path === undefined) return undefined;\n const segments = Convention.segmentsOf(path);\n const route = writeRoutes.find(\n (candidate) => candidate.method === method && matchesTemplate(candidate, segments)\n );\n if (route === undefined) return undefined;\n const target: FacadeWrites.Target =\n route.operation === \"create\"\n ? { operation: \"create\", type: route.type }\n : {\n operation: route.operation,\n type: route.type,\n id: decodeURIComponent(segments.at(-1) ?? \"\"),\n };\n return { route, target };\n };\n\n /** The mutation status URL of a journaled mutation: beside the api it belongs to (ADR-0030 §2). */\n const statusUrl = (route: Route, mutationId: number): string =>\n `${base.origin ?? \"\"}${base.path}${route.prefix}/_legation/mutations/${mutationId}`;\n\n /**\n * The receipt's `data`: the resource read back through the one writer\n * after journaling (ADR-0030 §1), or — when the replica does not hold the\n * row (a patch of a row it never pulled) — the request's own members.\n */\n const receiptData = ({ route }: WriteCandidate, write: Write): Effect.Effect<unknown> => {\n const prefix = options.prefix ?? route.prefix;\n const docs = writerFor(prefix);\n const sent = {\n type: write.type,\n id: write.id,\n attributes: write.attributes ?? {},\n };\n return docs.fromUrl(view, `${prefix}/${write.type}/${encodeURIComponent(write.id)}`).pipe(\n Effect.map((document) =>\n \"data\" in document && document.data !== null && !Array.isArray(document.data)\n ? document.data\n : sent\n ),\n Effect.orElseSucceed(() => sent)\n );\n };\n\n /**\n * Journal a write and answer its `202` receipt, or fail with `undefined`\n * when it cannot be journaled (the caller forwards it online, or answers\n * offline). The body is read from a clone.\n */\n const journal = (\n request: Request,\n candidate: WriteCandidate,\n preferences: FacadeWrites.Preferences\n ): Effect.Effect<Response, Unjournaled> =>\n Effect.gen(function* () {\n const body = Effect.tryPromise(() => request.clone().text());\n const write = yield* FacadeWrites.decodeWrite(\n candidate.route.node,\n candidate.target,\n body\n ).pipe(Effect.mapError((refusal): Unjournaled => ({ _tag: \"Refused\", refusal })));\n const intent = intentOf(write);\n if (intent === undefined || mutate === undefined) {\n return yield* Effect.fail<Unjournaled>({ _tag: \"Unmapped\" });\n }\n const handle = yield* mutate(intent.mutator, intent.args).pipe(\n Effect.mapError((error): Unjournaled =>\n P.isTagged(error, \"MutatorError\")\n ? { _tag: \"NotJournalable\", detail: error.message }\n : { _tag: \"Unmapped\" }\n )\n );\n const location = statusUrl(candidate.route, handle.mutationId);\n const meta = {\n legation: { status: \"pending\", mutationId: handle.mutationId, mutation: location },\n };\n const document =\n write.operation === \"delete\"\n ? { meta }\n : { data: yield* receiptData(candidate, write), meta };\n const headers = preferences.respondAsync\n ? { location, \"preference-applied\": \"respond-async\" }\n : { location };\n return respondWith(202, document, yield* cookie, headers);\n });\n\n const offlineNow: Effect.Effect<Response> = Effect.map(cookie, offlineResponse);\n\n /** The offline answer to a write it could not journal: ADR-0030 §3's error documents. */\n const unjournaled = (failure: Unjournaled): Effect.Effect<Response> =>\n Effect.map(cookie, (served) => {\n const [status, document] = unjournaledDocument(failure);\n return respondWith(status, document, served);\n });\n\n /** ADR-0030 §3's decision table for a write candidate, offline meaning `navigator.onLine` false. */\n const writeHandle = (\n request: Request,\n candidate: WriteCandidate\n ): Effect.Effect<Response | undefined> => {\n const preferences = FacadeWrites.preferencesOf(request.headers);\n const reachable = online();\n if (preferences.strict) return reachable ? Effect.succeed(undefined) : offlineNow;\n if (reachable && !preferences.respondAsync) return Effect.succeed(undefined);\n return journal(request, candidate, preferences).pipe(\n Effect.catch((failure) => (reachable ? Effect.succeed(undefined) : unjournaled(failure)))\n );\n };\n\n // ─── The mutation status URL (ADR-0030 §2) ─────────────────────────────────\n\n const mutationStates = options.mutationStates;\n const maxWait = Duration.fromInputUnsafe(options.maxWait ?? MutationStatus.defaultMaxWait);\n /** Every prefix the api's reflected routes sit under: the status route sits beside each. */\n const prefixes = Arr.dedupe(Arr.map([...routes, ...writeRoutes], (route) => route.prefix));\n\n /** A status request: the route prefix it names and the id segment, or `undefined`. */\n const statusCandidateOf = (\n request: Request\n ): { readonly prefix: string; readonly id: string } | undefined => {\n if (mutationStates === undefined || request.method !== \"GET\") return undefined;\n if (!acceptsJsonApi(request.headers.get(\"accept\"))) return undefined;\n const path = pathUnder(base, new URL(request.url));\n if (path === undefined) return undefined;\n const segments = Convention.segmentsOf(path);\n const [id = \"\", mutations = \"\", legation = \"\"] = segments.toReversed();\n if (legation !== MutationStatus.segment || mutations !== \"mutations\") return undefined;\n const prefix = segments.slice(0, -3);\n const joined = Arr.isReadonlyArrayEmpty(prefix) ? \"\" : `/${prefix.join(\"/\")}`;\n return prefixes.includes(joined) ? { prefix: joined, id: decodeURIComponent(id) } : undefined;\n };\n\n const statusHandle = (\n request: Request,\n states: Stream.Stream<MutationState.MutationStateMap>,\n candidate: { readonly prefix: string; readonly id: string }\n ): Effect.Effect<Response> =>\n Effect.gen(function* () {\n const links = `${base.origin ?? \"\"}${base.path}${candidate.prefix}`;\n const mutationId = MutationStatus.parseId(candidate.id);\n if (Option.isNone(mutationId)) {\n return respondWith(404, MutationStatus.unknownDocument(candidate.id), yield* cookie);\n }\n const now = yield* MutationStatus.current(states, mutationId.value);\n const asked = FacadeWrites.preferencesOf(request.headers).wait;\n const wait =\n asked === undefined || Option.isNone(now) || now.value.phase !== \"pending\"\n ? undefined\n : Duration.min(Duration.seconds(asked), maxWait);\n const state =\n wait === undefined ? now : yield* MutationStatus.settled(states, mutationId.value, wait);\n const served = yield* cookie;\n if (Option.isNone(state)) {\n return respondWith(404, MutationStatus.unknownDocument(candidate.id), served);\n }\n const document = MutationStatus.document(nodes, links, state.value);\n return wait === undefined\n ? respondWith(200, document, served)\n : respondWith(200, document, served, {\n \"preference-applied\": `wait=${Math.floor(Duration.toSeconds(wait))}`,\n });\n });\n\n const handle: FetchHandler[\"handle\"] = (request) => {\n const status = statusCandidateOf(request);\n if (status !== undefined && mutationStates !== undefined) {\n return statusHandle(request, mutationStates, status);\n }\n const write = writeCandidateOf(request);\n return write === undefined ? readHandle(request) : writeHandle(request, write);\n };\n\n const offline: FetchHandler[\"offline\"] = (request) => {\n const write = writeCandidateOf(request);\n if (write === undefined) return offlineNow;\n const preferences = FacadeWrites.preferencesOf(request.headers);\n if (preferences.strict) return offlineNow;\n return journal(request, write, preferences).pipe(Effect.catch(unjournaled));\n };\n\n const forwarded: FetchHandler[\"forwarded\"] = (request, response) =>\n options.pull !== undefined &&\n response.status >= 200 &&\n response.status < 300 &&\n writeCandidateOf(request) !== undefined\n ? Effect.ignore(options.pull)\n : Effect.void;\n\n return {\n matches: (request) =>\n candidateOf(request) !== undefined ||\n writeCandidateOf(request) !== undefined ||\n statusCandidateOf(request) !== undefined,\n handle,\n offline,\n forwarded,\n };\n};\n","/**\n * JsonApiSync\n *\n * The happy path: hand it an app's JSON:API `HttpApi` and get a fully wired,\n * offline-capable sync engine. It reflects the api into resources\n * (Convention.ts), derives collections + CRUD mutators (Derive.ts), and\n * composes the JsonApiBackend with an in-process sync room and the client\n * engine — so the app's existing REST API gains optimistic writes, a durable\n * journal, rebase, and live queries with no extra server to deploy\n * (client-direct deployment; \"realtime\" is periodic pull).\n *\n * The same JsonApiBackend satisfies the BYO `Backend` contract, so a later\n * server-side deployment for CVR fan-out reuses it unchanged.\n *\n * When the api advertises the JSON:API Atomic Operations extension (an\n * endpoint taking an `atomic:operations` document), pushes go to it as one\n * all-or-nothing request per batch; otherwise each mutation is replayed as\n * its own request (`JsonApiSyncOptions.atomic`).\n */\n\nimport * as Duration from \"effect/Duration\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Scope from \"effect/Scope\";\nimport * as HttpClient from \"effect/http/HttpClient\";\nimport type * as HttpApi from \"effect/http-api/HttpApi\";\nimport type * as HttpApiGroup from \"effect/http-api/HttpApiGroup\";\nimport { KeyValueStore } from \"effect/persistence\";\nimport { Authorization, Backend, ClientStore, Transport } from \"@thomasfosterau/legation\";\nimport { ClientEngine, SyncRoom } from \"@thomasfosterau/legation/internal\";\nimport {\n reflectAtomic,\n reflectResources,\n type EndpointRef,\n type ResourceMap,\n} from \"./Convention.js\";\nimport { derive, type Derived } from \"./Derive.js\";\nimport * as JsonApiBackend from \"./JsonApiBackend.js\";\nimport type { QueryEncoder } from \"./JsonApiQuery.js\";\nimport * as Ledger from \"./Ledger.js\";\n\n/**\n * An app's JSON:API surface defined with Effect `HttpApi`, with its identifier\n * and group types erased. `HttpApi`'s group parameter is invariant, so the\n * entry points below are generic over the concrete api rather than accepting\n * this alias directly.\n */\nexport type JsonApi = HttpApi.Constraint;\n\n/** Options for {@link layer}. */\nexport interface JsonApiSyncOptions {\n /** Base URL the resource paths resolve against (no trailing slash). */\n readonly baseUrl: string;\n /** This client's id (stable per device/tab). */\n readonly clientId: string;\n /** The client group this client belongs to (shared journal scope). */\n readonly clientGroupId: string;\n /** Override the Subset → JSON:API query encoding (e.g. your own package). */\n readonly queryEncoder?: QueryEncoder | undefined;\n /**\n * Relationship names to compound-load per collection (`?include=...`), so\n * `Relationships.related` resolves them without extra round trips.\n */\n readonly includes?: Readonly<Record<string, ReadonlyArray<string>>> | undefined;\n /**\n * Where the backend keeps its ledger (acknowledged mutation ids and remembered\n * rejections) across restarts (#468). Unset, it is `Ledger.keyValue` over\n * `keyValueStore` when that is given, and otherwise in memory, where a restart\n * of the backend forgets it. A durable ledger needs a durable client store too\n * (`keyValueStore` or `store`): with the in-memory store, a reload restarts the\n * client's mutation ids at 1, the ledger already acknowledges them, and the\n * backend skips the new writes as already applied, with no error.\n */\n readonly ledger?: Ledger.LedgerStore | undefined;\n /**\n * The durable Effect `KeyValueStore` the client store is built over (#468). When\n * it is set, the client store defaults to `ClientStore.layerKeyValue()` over it\n * (unless `store` is given), and the ledger defaults to `Ledger.keyValue` over it\n * (unless `ledger` is given), so one key/value store keeps the journal and the\n * ledger across a reload. A `store` given with it must be built over this same\n * key/value store: `store` is an opaque layer, so the layer cannot check that.\n */\n readonly keyValueStore?: KeyValueStore.KeyValueStore | undefined;\n /**\n * Atomic operations. When the api advertises the JSON:API Atomic Operations\n * extension (an endpoint taking an `atomic:operations` document, e.g.\n * effect-jsonapi's `Endpoint.operations`), the backend pushes each batch as\n * one all-or-nothing request to it — detected from the api by default.\n * Pass `false` to keep one request per mutation, or `{ path }` to name the\n * endpoint explicitly (an api that serves it outside the reflected\n * `HttpApi`).\n */\n readonly atomic?: false | { readonly path: string } | undefined;\n /**\n * Periodic pull interval — the correctness backstop that picks up changes\n * made elsewhere (\"realtime\" is periodic pull for client-direct deployment).\n * Defaults to 5 seconds; set to `null` to disable interval pulling.\n */\n readonly pullInterval?: Duration.Input | null | undefined;\n /**\n * Auto-push debounce window. When set, mutations are pushed automatically\n * (coalesced) without an app-level `push` call.\n */\n readonly pushDebounce?: Duration.Input | undefined;\n /**\n * The client store backing the engine. Defaults to `ClientStore.layerKeyValue()`\n * over `keyValueStore` when that is given, and otherwise to the in-memory store.\n * A durable store (e.g. `IndexedDbClientStore.layerWindow()` from\n * `@thomasfosterau/legation-browser`, or `ClientStore.layerKeyValue` over localStorage)\n * keeps the journal and confirmed rows across reloads (offline-first). It needs\n * a durable ledger too: pass `keyValueStore` (the key/value store it is built\n * over) or `ledger`. With the in-memory ledger, a reload forgets the\n * acknowledged ids, and the backend refuses every later push with a\n * mutation-id gap.\n */\n readonly store?: Layer.Layer<ClientStore.ClientStore> | undefined;\n}\n\n/**\n * Reflect + derive an api's resources, collections, mutators, operations —\n * and its atomic operations endpoint, when it declares one.\n */\nexport const inspect = <Id extends string, Groups extends HttpApiGroup.Constraint>(\n api: HttpApi.HttpApi<Id, Groups>\n): { readonly resources: ResourceMap; readonly atomic?: EndpointRef } & Derived => {\n const resources = reflectResources(api);\n const atomic = reflectAtomic(api);\n return { resources, ...(atomic !== undefined ? { atomic } : {}), ...derive(resources) };\n};\n\n/** Every resource collection is readable; the REST API enforces real auth. */\nconst authPolicy = (resources: ResourceMap): Authorization.AuthPolicy =>\n Authorization.policy(\n Object.fromEntries([...resources.keys()].map((type) => [type, Authorization.allowAll]))\n );\n\n/**\n * The full client-direct stack as a layer: provide an `HttpClient`, get a\n * ready `ClientEngine`. CVR store and invalidation bus are in-process; the\n * client store defaults to in-memory, or to the durable store over\n * `keyValueStore` (pass it for offline persistence and a durable ledger across\n * reloads, or pass `store` and `ledger` for another durable store).\n */\nexport const layer = <Id extends string, Groups extends HttpApiGroup.Constraint>(\n api: HttpApi.HttpApi<Id, Groups>,\n options: JsonApiSyncOptions\n): Layer.Layer<ClientEngine.ClientEngine, never, HttpClient.HttpClient> => {\n const { resources, registry, operations, atomic } = inspect(api);\n // Atomic pushes when the api advertises the extension, unless opted out;\n // an explicit path overrides what reflection found.\n const atomicPath = options.atomic === false ? undefined : (options.atomic?.path ?? atomic?.path);\n\n // A durable key/value store makes the ledger durable too, unless the app names one.\n const ledger =\n options.ledger ??\n (options.keyValueStore !== undefined ? Ledger.keyValue(options.keyValueStore) : undefined);\n // The durable client store over the same key/value store, unless the app names one.\n const clientStore =\n options.store ??\n (options.keyValueStore !== undefined\n ? ClientStore.layerKeyValue().pipe(\n Layer.provide(Layer.succeed(KeyValueStore.KeyValueStore)(options.keyValueStore))\n )\n : ClientStore.layerMemory);\n\n const backendLayer = Layer.effect(Backend.Backend)(\n JsonApiBackend.make({\n baseUrl: options.baseUrl,\n resources,\n mutators: registry.mutators,\n operations,\n ...(atomicPath !== undefined ? { atomic: { path: atomicPath } } : {}),\n ...(options.queryEncoder !== undefined ? { query: options.queryEncoder } : {}),\n ...(options.includes !== undefined ? { includes: options.includes } : {}),\n ...(ledger !== undefined ? { ledger } : {}),\n })\n );\n const authLayer = Layer.succeed(Authorization.AuthPolicy)(authPolicy(resources));\n\n const serverLayer = SyncRoom.layer.pipe(Layer.provide(backendLayer), Layer.provide(authLayer));\n const transportLayer = Transport.layerInMemory(options.clientGroupId).pipe(\n Layer.provide(serverLayer)\n );\n\n // Interval pull is now a core sync-loop concern (default 5s, opt-out with\n // `null`); no bespoke poll loop in `start`.\n const pullInterval =\n options.pullInterval === null ? undefined : (options.pullInterval ?? Duration.seconds(5));\n const syncLoop: ClientEngine.SyncLoopOptions = {\n ...(pullInterval !== undefined ? { pullInterval } : {}),\n ...(options.pushDebounce !== undefined ? { pushDebounce: options.pushDebounce } : {}),\n };\n\n return ClientEngine.layer({\n clientId: options.clientId,\n clientGroupId: options.clientGroupId,\n mutators: registry,\n syncLoop,\n }).pipe(Layer.provide(transportLayer), Layer.provide(clientStore));\n};\n\n/**\n * Start syncing: run the engine's sync loop. Interval pull, push-on-mutate,\n * pull-on-poke and push+pull-on-reconnect are all scheduled by the core loop\n * (configure the interval/debounce on `layer`'s options). Requires a `Scope` —\n * fork it into the app's runtime and the fibers live until the scope closes.\n */\nexport const start: Effect.Effect<void, never, ClientEngine.ClientEngine | Scope.Scope> =\n Effect.gen(function* () {\n const engine = yield* ClientEngine.ClientEngine;\n // Forking never surfaces the loop's errors; die on the impossible.\n yield* engine.runSync.pipe(Effect.orDie);\n });\n","/**\n * NodeBridge\n *\n * The first-class integration ADR-0022 promised: a JSON:API resource\n * definition (`Resource.make` from `@thomasfosterau/effect-jsonapi`) **is**\n * a node definition — same type name, same attributes, and relationships\n * that map one-for-one onto edges. This module derives {@link Node} graphs\n * from resource definitions so an app declares its resources once and gets\n * the sync engine's replica, queries, joins, and fan-out topics from the\n * same source of truth as its HTTP API.\n *\n * The mapping:\n *\n * - `Relationship.one` / `Relationship.optional` → `Edge.one`, stored in\n * the foreign-key field `` `${name}Id` `` (override per relationship with\n * `via`). JSON:API keeps relationship linkage out of `attributes`, so the\n * engine-side row gains the key field the edge declares.\n * - `Relationship.many` / `Relationship.paginated` → `Edge.many` /\n * `Edge.paginated`. The **inverse** — the one-edge on the target holding\n * the key — is discovered when it is unambiguous, and named explicitly\n * when it is not: on the resource, with the `@legation/inverses`\n * annotation ({@link syncAnnotations}), or in the `inverses` option.\n * - `paginated` edges need an `order` (cursor pagination requires a stable\n * order, and it is part of the edge's identity — ADR-0022). It is read off\n * the relationship's own declaration, `Relationship.paginated(ref, { order })`\n * (#220), or given in the `order` option.\n *\n * **Sync metadata on the resource (#220).** What only the sync engine needs —\n * an inverse name, the literal kind of a field no schema can tell (an\n * `instant` stored as text) — is declared on the resource as\n * `@legation/`-namespaced annotations: `Resource.make(…, { annotations:\n * syncAnnotations({ inverses, kinds }) })`, or `Resource.annotate`, which\n * `Resource.extend` keeps. The {@link FromResourceOptions} remain, as\n * explicit overrides: an option entry wins over the resource's annotation or\n * declaration for the same relationship or field. A to-one relationship's\n * key field is still `` `${name}Id` `` or the `via` option until\n * effect-jsonapi's storage-key slot (effect-jsonapi#509) reaches this\n * package.\n *\n * **Acyclic resource graphs.** The library's resource types expand eagerly,\n * so mutually-referencing definitions (`Product ⇄ Review`) cannot be\n * authored; the idiomatic JSON:API graph points parent → child and the\n * child carries its foreign key as a plain attribute (`productId`). The\n * `edges` option closes that gap: it promotes such an attribute to a\n * declared one-edge on the bridged node, and {@link registry} discovers\n * collection-valued inverses across **bridged** one-edges — declared and\n * relationship-derived alike — so the acyclic graph bridges without ever\n * naming an inverse by hand.\n *\n * **The filterable set** (ADR-0028 rule d, #154) is read off the resource's\n * own declaration (effect-jsonapi, since 0.13: `Filter.able` / `Sort.able` piped\n * onto an attribute schema, `Resource.attribute(schema, { filter, sort })`,\n * `Relationship.one(ref, { filter })`) through `Resource.filterable` /\n * `Resource.sortable`. An attribute keeps its name and derives its literal\n * kind from its schema exactly as `Node.make` does; a to-one relationship's\n * declaration lands on the edge's **key field** (`author` → `authorId`,\n * kind `text`), which is the field the engine filters by. The\n * `filterable` / `sortable` options remain as overrides: an option entry\n * replaces the resource's declaration for that field (the way to give an\n * `instant` its kind, which no schema can tell), and adds fields the\n * resource does not declare.\n *\n * All mismatches are definition-time defects (a thrown\n * {@link ResourceBridgeError}), never runtime failures: a resource graph\n * either bridges completely or not at all.\n *\n * **Identity** is always `id` here: a JSON:API resource is identified by the\n * spec's `id` member, so a bridged node declares no identity attribute of its\n * own (`Node.make`'s `id` option, #144). The JSON:API surface — `/{type}/{id}`\n * widening to `filter[id]`, linkage and `included` reading `id` off a row\n * value — assumes that, so a hand-built node naming a natural key is not yet\n * servable through these handlers.\n */\n\nimport { Resource } from \"@thomasfosterau/effect-jsonapi\";\nimport { Edge, type FilterPolicy, Node } from \"@thomasfosterau/legation\";\nimport * as Arr from \"effect/Array\";\nimport * as R from \"effect/Record\";\nimport * as Result from \"effect/Result\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\n\n/** A definition-time mismatch between a resource graph and the node model. */\nexport class ResourceBridgeError extends Schema.TaggedError<\n ResourceBridgeError,\n { readonly brand: unique symbol }\n>()(\"ResourceBridgeError\", {\n resource: Schema.String,\n relationship: Schema.String,\n message: Schema.String,\n}) {}\n\n// ─── Sync annotations (#220) ──────────────────────────────────────────────────\n//\n// What only the sync engine needs to know about a resource is declared on the\n// resource itself, as `@legation/`-namespaced annotations (effect-jsonapi's\n// `Resource.make({ annotations })` / `Resource.annotate`), so an app declares\n// it next to the resource rather than in a per-resource options table.\n\n/** The annotation key naming the inverse edge of collection relationships, by relationship name. */\nexport const InversesAnnotation = \"@legation/inverses\";\n\n/** The annotation key naming the literal kind of filterable fields, by row field. */\nexport const KindsAnnotation = \"@legation/kinds\";\n\n/** The sync metadata a resource can declare about itself (#220). */\nexport interface SyncAnnotations {\n /**\n * The inverse edge name on the target, by `many` / `paginated` relationship\n * name — needed only where discovery is ambiguous or impossible.\n */\n readonly inverses?: Readonly<Record<string, string>>;\n /**\n * The literal kind of a filterable field, by row field, where its schema\n * cannot tell it: an `instant` stored as text. The field must be declared\n * filterable on the resource.\n */\n readonly kinds?: Readonly<Record<string, FilterPolicy.LiteralKind>>;\n}\n\n/** {@link SyncAnnotations} as resource annotations, under the bridge's keys. */\nexport type SyncAnnotationRecord = {\n readonly [InversesAnnotation]?: SyncAnnotations[\"inverses\"];\n readonly [KindsAnnotation]?: SyncAnnotations[\"kinds\"];\n};\n\n/**\n * The resource annotations that declare `sync`, to pass as (or merge into)\n * `Resource.make`'s `annotations` or `Resource.annotate`'s.\n */\nexport const syncAnnotations = (sync: SyncAnnotations): SyncAnnotationRecord => {\n let record: SyncAnnotationRecord = {};\n if (sync.inverses !== undefined) record = { ...record, [InversesAnnotation]: sync.inverses };\n if (sync.kinds !== undefined) record = { ...record, [KindsAnnotation]: sync.kinds };\n return record;\n};\n\nconst Inverses = Schema.Record(Schema.String, Schema.String);\nconst Kinds = Schema.Record(\n Schema.String,\n Schema.Literals([\"text\", \"integer\", \"double\", \"boolean\", \"instant\"])\n);\n\n/**\n * Read one of the bridge's annotations off a resource: absent reads as empty,\n * and a value of the wrong shape is a definition-time defect.\n */\nconst annotationOf = <A>(\n resource: Resource.Any,\n key: string,\n schema: Schema.Codec<A, unknown>\n): Option.Option<A> =>\n Option.map(Option.fromUndefinedOr(Resource.annotations(resource)[key]), (value) =>\n Option.getOrElse(Schema.decodeUnknownOption(schema)(value), () =>\n fail(resource.type, key, `the \"${key}\" annotation does not have the shape the bridge reads`)\n )\n );\n\n/** Per-resource overrides for {@link fromResource} / {@link registry}. */\nexport interface FromResourceOptions {\n /**\n * The foreign-key field a `one`/`optional` relationship's edge stores its\n * id in, by relationship name. Defaults to `` `${name}Id` ``.\n */\n readonly via?: Record<string, string>;\n /**\n * One-edges beyond the resource's relationships, by edge name — promote\n * a foreign-key **attribute** to an edge when the resource graph is\n * acyclic and could not declare the relationship itself (see the module\n * doc). The attribute named by `via` moves out of the node's attributes;\n * the edge's key field replaces it.\n */\n readonly edges?: Record<string, { readonly target: string; readonly via: string }>;\n /**\n * The inverse edge name on the target, by relationship name — required\n * only when discovery is ambiguous (the target has several one-edges\n * back) or impossible (it has none).\n */\n readonly inverses?: Record<string, string>;\n /**\n * The edge order for `paginated` relationships, by relationship name\n * (field names, `-` prefixed for descending). Required for every\n * `paginated` relationship — order is part of the edge's identity.\n */\n readonly order?: Record<string, ReadonlyArray<string>>;\n /** Passed through to the node (fine fan-out topics — ADR-0023). */\n readonly hintKeys?: ReadonlyArray<string>;\n /**\n * Overrides and additions to the resource's own filterable declaration\n * (ADR-0028, #154; see the module doc), by row field: the operators\n * alone (the literal kind is derived from the attribute schema), or\n * `{ operators, kind }` where the schema cannot tell the kind (an\n * `instant` stored as text). An entry replaces the resource's declaration\n * for that field. `id` and every bridged one-edge's key field are\n * filterable by `eq` / `in` regardless.\n */\n readonly filterable?: Record<string, FilterPolicy.FilterableInput>;\n /** Sortable fields beyond the resource's `Sort.able` declaration; `id` is always sortable. */\n readonly sortable?: ReadonlyArray<string>;\n}\n\nconst fail = (resource: string, relationship: string, message: string): never => {\n throw new ResourceBridgeError({ resource, relationship, message });\n};\n\n/**\n * The one-edges a resource bridges to: its `one`/`optional` relationships\n * plus the option-declared extras. This is the map inverse discovery\n * scans, so declared and relationship-derived edges resolve identically.\n */\nconst oneEdgesOf = (\n resource: Resource.Any,\n options: FromResourceOptions\n): Record<string, Edge.One> => {\n const related = R.filterMap(resource.relationships, (descriptor, name) =>\n descriptor.kind === \"one\" || descriptor.kind === \"optional\"\n ? Result.succeed(Edge.one(descriptor.ref().type, { via: options.via?.[name] ?? `${name}Id` }))\n : Result.failVoid\n );\n const declared = R.map(options.edges ?? {}, (edge) => Edge.one(edge.target, { via: edge.via }));\n return { ...related, ...declared };\n};\n\n/**\n * Discover the inverse of a collection-valued relationship: the unique\n * one-edge on the (bridged) target that points back at `source`.\n */\nconst discoverInverse = (\n source: string,\n name: string,\n target: string,\n targetOneEdges: Record<string, Edge.One>\n): string => {\n const candidates = Object.entries(targetOneEdges).filter(([, edge]) => edge.target === source);\n const only = candidates[0];\n if (candidates.length === 1 && only !== undefined) return only[0];\n return fail(\n source,\n name,\n Arr.isReadonlyArrayEmpty(candidates)\n ? `no inverse found: \"${target}\" bridges no one-edge back to \"${source}\" — declare one (a relationship, or options.edges over its key attribute), or name it in options.inverses`\n : `ambiguous inverse: \"${target}\" bridges ${candidates.length} one-edges back to \"${source}\" (${candidates\n .map(([candidate]) => `\"${candidate}\"`)\n .join(\", \")}) — name the right one in options.inverses`\n );\n};\n\n/** A `many` / `paginated` relationship's descriptor, as the bridge reads it. */\ntype CollectionRelationship = Extract<\n Resource.Any[\"relationships\"][string],\n { readonly kind: \"many\" | \"paginated\" }\n>;\n\n/**\n * A paginated relationship's own canonical order (effect-jsonapi's\n * `Relationship.paginated(ref, { order })`), as the engine spells an order:\n * field names, `-` prefixed for descending.\n */\nconst declaredOrder = (descriptor: CollectionRelationship): Option.Option<ReadonlyArray<string>> =>\n descriptor.kind === \"paginated\"\n ? Option.map(Option.fromUndefinedOr(descriptor.order), (order) =>\n order.map((term) => (term.direction === \"desc\" ? `-${term.field}` : term.field))\n )\n : Option.none();\n\n/**\n * Bridge one collection-valued relationship to its edge: the inverse is\n * named in the options or discovered on the target; a paginated one also\n * needs its declared order.\n */\nconst collectionEdge = (\n resource: Resource.Any,\n name: string,\n descriptor: CollectionRelationship,\n options: FromResourceOptions,\n oneEdgesOfTarget: (target: Resource.Any) => Record<string, Edge.One>\n): Edge.Edge => {\n const target = descriptor.ref();\n const inverse =\n options.inverses?.[name] ??\n Option.getOrUndefined(\n Option.flatMapNullishOr(\n annotationOf(resource, InversesAnnotation, Inverses),\n (inverses) => inverses[name]\n )\n ) ??\n discoverInverse(resource.type, name, target.type, oneEdgesOfTarget(target));\n if (descriptor.kind === \"many\") return Edge.many(target.type, { inverse });\n const order = options.order?.[name] ?? Option.getOrUndefined(declaredOrder(descriptor));\n if (order === undefined) {\n return fail(\n resource.type,\n name,\n `a paginated relationship needs an edge order (cursor pagination requires a stable order) — declare it on the relationship, Relationship.paginated(ref, { order }), or in options.order`\n );\n }\n return Edge.paginated(target.type, { inverse, order });\n};\n\n/** The resource's edges: its one-edges plus every collection-valued relationship's. */\nconst edgesOf = (\n resource: Resource.Any,\n options: FromResourceOptions,\n oneEdgesOfTarget: (target: Resource.Any) => Record<string, Edge.One>\n): Record<string, Edge.Edge> => {\n const collections = R.filterMap(resource.relationships, (descriptor, name) =>\n descriptor.kind === \"many\" || descriptor.kind === \"paginated\"\n ? Result.succeed(collectionEdge(resource, name, descriptor, options, oneEdgesOfTarget))\n : Result.failVoid\n );\n return { ...oneEdgesOf(resource, options), ...collections };\n};\n\n/**\n * The resource's attributes minus every one-edge's key field: a one-edge's\n * key replaces any attribute of the same name (the promoted-attribute\n * case); the edge's branded id carries the field.\n */\nconst attributesOf = (\n resource: Resource.Any,\n edges: Record<string, Edge.Edge>\n): Schema.Struct.Fields => {\n const keys = new Set(\n Object.values(edges).flatMap((edge) => (edge.kind === \"one\" ? [edge.via] : []))\n );\n return R.filter(resource.fields.attributes.fields, (_, field) => !keys.has(field));\n};\n\n/** One entry of `Resource.filterable`, as the bridge reads it. */\ninterface DeclaredField {\n readonly operators: ReadonlyArray<FilterPolicy.FilterOperator>;\n}\n\n/**\n * The filterable set the resource declares, keyed by **row field**: an\n * attribute under its own name, with the kind left to `Node.make` to derive\n * from its schema; a to-one relationship under its edge's key field, kind\n * `text` (an id). A key field declared twice — the relationship and the\n * attribute it is stored in both filterable — is a definition-time defect:\n * neither declaration may silently win.\n */\nconst declaredFilterable = (\n resource: Resource.Any,\n edges: Record<string, Edge.Edge>\n): Record<string, FilterPolicy.FilterableInput> => {\n const declared: Record<string, FilterPolicy.FilterableInput> = {};\n const attributes = resource.fields.attributes.fields;\n const entries = Object.entries(Resource.filterable(resource)) as Array<[string, DeclaredField]>;\n entries.forEach(([key, entry]) => {\n const edge = edges[key];\n const viaRelationship = attributes[key] === undefined && edge?.kind === \"one\";\n const field = viaRelationship ? edge.via : key;\n if (declared[field] !== undefined) {\n fail(\n resource.type,\n key,\n `key field \"${field}\" is declared filterable twice (by relationship \"${key}\" and by the attribute it is stored in) — declare it once`\n );\n }\n declared[field] = viaRelationship\n ? { operators: entry.operators, kind: \"text\" }\n : entry.operators;\n });\n return declared;\n};\n\n/**\n * The declared filterable set with the resource's `@legation/kinds`\n * annotation applied: each named field keeps its operators and takes the\n * annotated kind. Naming a field the resource does not declare filterable is a\n * definition-time defect.\n */\nconst withKinds = (\n resource: Resource.Any,\n declared: Record<string, FilterPolicy.FilterableInput>\n): Record<string, FilterPolicy.FilterableInput> =>\n R.reduce(\n Option.getOrElse(annotationOf(resource, KindsAnnotation, Kinds), () => ({})),\n declared,\n (current, kind, field) => {\n const entry = current[field];\n if (entry === undefined) {\n return fail(\n resource.type,\n KindsAnnotation,\n `\"${field}\" has a kind in \"${KindsAnnotation}\" but is not declared filterable on the resource`\n );\n }\n const operators = \"operators\" in entry ? entry.operators : entry;\n return { ...current, [field]: { operators, kind } };\n }\n );\n\n/**\n * The per-node options: hint keys from the bridge options; the filterable\n * set and sortable fields from the resource's declaration, each option\n * entry replacing the resource's for its field.\n */\nconst nodeOptionsOf = (\n resource: Resource.Any,\n edges: Record<string, Edge.Edge>,\n options: FromResourceOptions\n): {\n readonly hintKeys?: ReadonlyArray<string>;\n readonly filterable: Record<string, FilterPolicy.FilterableInput>;\n readonly sortable: ReadonlyArray<string>;\n} => ({\n ...(options.hintKeys === undefined ? {} : { hintKeys: options.hintKeys }),\n filterable: {\n ...withKinds(resource, declaredFilterable(resource, edges)),\n ...options.filterable,\n },\n sortable: [...Resource.sortable(resource), ...(options.sortable ?? [])],\n});\n\n/** Bridge one resource, resolving inverses through `oneEdgesOfTarget`. */\nconst bridge = (\n resource: Resource.Any,\n options: FromResourceOptions,\n oneEdgesOfTarget: (target: Resource.Any) => Record<string, Edge.One>\n): Node.AnyNode => {\n const edges = edgesOf(resource, options, oneEdgesOfTarget);\n return Node.make(resource.type, {\n attributes: attributesOf(resource, edges),\n edges,\n ...nodeOptionsOf(resource, edges, options),\n });\n};\n\n/**\n * Derive a {@link Node} definition from a single JSON:API resource\n * definition. Inverse discovery here sees only the target resource's own\n * relationships — bridge a whole graph with {@link registry} to discover\n * across option-declared edges too.\n */\nexport const fromResource = (\n resource: Resource.Any,\n options: FromResourceOptions = {}\n): Node.AnyNode => bridge(resource, options, (target) => oneEdgesOf(target, {}));\n\n/**\n * Bridge a whole resource graph and close it as a validated\n * {@link Node.NodeRegistry} — nodes plus the derived engine\n * `CollectionRegistry`, ready for `Client.make` / `Server.make`.\n * Options are keyed by resource type.\n */\nexport const registry = (\n resources: ReadonlyArray<Resource.Any>,\n options: Record<string, FromResourceOptions> = {}\n): Node.NodeRegistry =>\n Node.registry(\n resources.map((resource) =>\n bridge(resource, options[resource.type] ?? {}, (target) =>\n oneEdgesOf(target, options[target.type] ?? {})\n )\n )\n );\n","/**\n * Relationships\n *\n * Read-side relationship resolution: a JSON:API resource row carries\n * relationship *linkage* (`{ type, id }` references), and once the referenced\n * collections are synced into the local mirror, a relationship name resolves\n * to the actual related row value(s) — a client-side join over already-synced\n * data, no extra request.\n *\n * The incremental-join plumbing (base `observe` → target collections →\n * per-collection index → `switchMap` on linkage shift → dedup; auto-subscribe\n * the narrowed foreign subsets + scope teardown) is the protocol-agnostic core\n * `Related` module. This module supplies JSON:API's linkage-based\n * {@link Related.Strategy} — `targets` derived from `{ type, id }` refs,\n * `resolveRow` via {@link hydrate} over those refs — and reuses the shared\n * machinery, so `query`/`observe`/`related` are thin adapters over it with no\n * behaviour change (audit #10). The linkage extraction stays here; only the\n * generic pipeline is shared.\n */\n\nimport * as Effect from \"effect/Effect\";\nimport * as P from \"effect/Predicate\";\nimport * as R from \"effect/Record\";\nimport * as Scope from \"effect/Scope\";\nimport * as Stream from \"effect/Stream\";\nimport { ClientEngine, Related, Subset } from \"@thomasfosterau/legation/internal\";\nimport type { RelationshipRef } from \"./CollectionLoader.js\";\nimport type { JsonApiRow } from \"./Derive.js\";\n\n/** A resolved relationship: a row, a list of rows, `null`, or `undefined`. */\nexport type RelatedValue = JsonApiRow | ReadonlyArray<JsonApiRow> | null | undefined;\n\n/** A base row with its named relationships resolved against the mirror. */\nexport interface RelatedRow {\n readonly id: string;\n readonly value: JsonApiRow;\n readonly related: Record<string, RelatedValue>;\n}\n\n/** Look up a row by (collection, id) from the local mirror. */\nexport type Lookup = (collection: string, id: string) => JsonApiRow | undefined;\n\nconst refOf = (value: JsonApiRow, name: string): RelationshipRef =>\n (value.relationships?.[name] ?? null) as RelationshipRef;\n\nconst isLink = (value: unknown): value is { readonly type: string; readonly id: string } =>\n P.isObjectOrArray(value) && \"type\" in value && \"id\" in value;\n\n/** The `{ type, id }` links a row's named relationship points at. */\nconst linksOf = (\n value: JsonApiRow,\n name: string\n): ReadonlyArray<{ readonly type: string; readonly id: string }> => {\n const ref = refOf(value, name);\n if (ref === null || ref === undefined) return [];\n return (Array.isArray(ref) ? ref : [ref]).filter(isLink);\n};\n\n/** Resolve one relationship of a row against a lookup (linkage → value[s]). */\nexport const resolve = (lookup: Lookup, value: JsonApiRow, name: string): RelatedValue => {\n const ref = refOf(value, name);\n if (ref === null || ref === undefined) return ref;\n if (Array.isArray(ref)) {\n return ref.flatMap((link) => {\n const row = lookup(link.type, link.id);\n return row === undefined ? [] : [row];\n });\n }\n return isLink(ref) ? lookup(ref.type, ref.id) : undefined;\n};\n\n/** Resolve several named relationships of a row. */\nexport const hydrate = (\n lookup: Lookup,\n value: JsonApiRow,\n names: ReadonlyArray<string>\n): Record<string, RelatedValue> => {\n return R.fromIterableWith(names, (name): [string, RelatedValue] => [\n name,\n resolve(lookup, value, name),\n ]);\n};\n\n// ─── Delegation to the core `Related` plumbing ───────────────────────────────\n//\n// JSON:API's relationship model differs from core's declared field mappings: it\n// extracts `{ type, id }` linkage from the row value rather than matching a\n// `localField`/`foreignField`. That difference is confined to the strategy; the\n// incremental-join pipeline is the shared core module.\n\n/**\n * The linkage strategy: `targets` pins each referenced collection by `id` and\n * the linked ids; `resolveRow` reads the referenced rows out of the index by id\n * and hydrates via {@link hydrate}, so resolution is byte-for-byte the previous\n * behaviour.\n */\nconst linkageStrategy = (names: ReadonlyArray<string>): Related.Strategy => ({\n targets: (baseRows) => {\n const map = new Map<string, { field: string; ids: Set<string> }>();\n const links = baseRows.flatMap((row) =>\n names.flatMap((name) => linksOf(row.value as JsonApiRow, name))\n );\n links.forEach((link) => {\n const entry = map.get(link.type) ?? { field: \"id\", ids: new Set<string>() };\n entry.ids.add(link.id);\n map.set(link.type, entry);\n });\n return map;\n },\n resolveRow: (index, baseRow) => {\n const lookup: Lookup = (collection, id) =>\n index.get(collection)?.get(id)?.[0]?.value as JsonApiRow | undefined;\n return hydrate(lookup, baseRow.value as JsonApiRow, names);\n },\n});\n\n/**\n * Resolve a subset's rows together with their named relationships, reading the\n * referenced collections from the engine's local view. Delegates to\n * {@link Related.queryWith} with the linkage strategy.\n */\nexport const query = (\n engine: ClientEngine.ClientEngine,\n subset: Subset.Subset,\n names: ReadonlyArray<string>\n): Effect.Effect<ReadonlyArray<RelatedRow>, never, never> =>\n Related.queryWith(engine, linkageStrategy(names), subset) as Effect.Effect<\n ReadonlyArray<RelatedRow>,\n never,\n never\n >;\n\n/**\n * Live version of {@link query} as an incrementally-maintained join. Delegates\n * to {@link Related.observeWith}: a write to a referenced row re-hydrates the\n * join without re-querying the base; a base change that shifts referenced\n * collections re-establishes the observers.\n */\nexport const observe = (\n engine: ClientEngine.ClientEngine,\n subset: Subset.Subset,\n names: ReadonlyArray<string>\n): Stream.Stream<ReadonlyArray<RelatedRow>, never, never> =>\n Related.observeWith(engine, linkageStrategy(names), subset) as Stream.Stream<\n ReadonlyArray<RelatedRow>,\n never,\n never\n >;\n\n/**\n * Auto-subscribing relational read: subscribes the base subset and the narrowed\n * `id IN (...)` subsets of each referenced collection, tracks the live linkage,\n * and tears the subscriptions down when the scope closes. Delegates to\n * {@link Related.relatedWith}. Pair with the backend's `includes` config to\n * deliver the related rows in the parent's response (no extra round trip).\n */\nexport const related = (\n engine: ClientEngine.ClientEngine,\n subset: Subset.Subset,\n names: ReadonlyArray<string>\n): Effect.Effect<Stream.Stream<ReadonlyArray<RelatedRow>, never, never>, never, Scope.Scope> =>\n Related.relatedWith(engine, linkageStrategy(names), subset) as Effect.Effect<\n Stream.Stream<ReadonlyArray<RelatedRow>, never, never>,\n never,\n Scope.Scope\n >;\n"],"mappings":"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"}
|