@thomasfosterau/legation 0.0.0 → 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 +2054 -0
- package/LICENSE +21 -0
- package/README.md +349 -1
- package/dist/MemoryBackend-BziXwfcs.d.ts +4884 -0
- package/dist/MemoryBackend-BziXwfcs.d.ts.map +1 -0
- package/dist/MemoryBackend-DxP8t4ge.js +9477 -0
- package/dist/MemoryBackend-DxP8t4ge.js.map +1 -0
- package/dist/index-CPPfp0F4.d.ts +399 -0
- package/dist/index-CPPfp0F4.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/internal-CxXRlFK9.d.ts +2362 -0
- package/dist/internal-CxXRlFK9.d.ts.map +1 -0
- package/dist/internal-JyoQMlfK.js +3758 -0
- package/dist/internal-JyoQMlfK.js.map +1 -0
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +3 -0
- package/dist/rolldown-runtime-D8jQpDG7.js +12 -0
- package/dist/sql/index.d.ts +294 -0
- package/dist/sql/index.d.ts.map +1 -0
- package/dist/sql/index.js +969 -0
- package/dist/sql/index.js.map +1 -0
- package/dist/src-FWXpu_vP.js +1082 -0
- package/dist/src-FWXpu_vP.js.map +1 -0
- package/package.json +61 -3
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { $ as MutatorRegistry, Bt as StoreError, I as LocalRow, Lt as MutatorError, Q as Mutator, U as ServerHandler, Ut as VersionNotSupportedError, V as ClientTransport, Vt as TransportError, X as AnyMutator, Z as LocalHandler, c as CvrStore, f as IdentityResolver, o as InvalidationBus, p as SyncMiddleware, pt as NodeRegistry, r as SyncServerOptions, st as Backend, tt as ClientStore, u as AuthPolicy, x as Read, y as QueryResolver } from "./MemoryBackend-BziXwfcs.js";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Scope from "effect/Scope";
|
|
5
|
+
declare namespace CrudMutation_d_exports {
|
|
6
|
+
export { DeleteArgs, Entry, Operation, Options, WriteArgs, Writes, entries, name, registry };
|
|
7
|
+
}
|
|
8
|
+
/** The three operations a graph-derived mutation performs. */
|
|
9
|
+
type Operation = "create" | "update" | "delete";
|
|
10
|
+
/**
|
|
11
|
+
* Which operations to derive, per node type. A type absent from the map gets
|
|
12
|
+
* none; an absent map derives all three for every node.
|
|
13
|
+
*/
|
|
14
|
+
type Writes = Readonly<Record<string, ReadonlyArray<Operation>>>;
|
|
15
|
+
/** The mutation name for a type and an operation: `"{type}/{operation}"`. */
|
|
16
|
+
declare const name: (type: string, operation: Operation) => string;
|
|
17
|
+
/** The args of a `{type}/create` or `{type}/update`: the row's fields as a record, keyed by its id. */
|
|
18
|
+
declare const WriteArgs: Schema.Struct<{
|
|
19
|
+
readonly type: Schema.String;
|
|
20
|
+
readonly id: Schema.String;
|
|
21
|
+
readonly attributes: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
22
|
+
}>;
|
|
23
|
+
/** The decoded (and encoded) args of a create or an update. */
|
|
24
|
+
type WriteArgs = typeof WriteArgs.Type;
|
|
25
|
+
/** The args of a `{type}/delete`. */
|
|
26
|
+
declare const DeleteArgs: Schema.Struct<{
|
|
27
|
+
readonly type: Schema.String;
|
|
28
|
+
readonly id: Schema.String;
|
|
29
|
+
}>;
|
|
30
|
+
/** The decoded (and encoded) args of a delete. */
|
|
31
|
+
type DeleteArgs = typeof DeleteArgs.Type;
|
|
32
|
+
/** One derived mutation: its definition, its client handler, and what it does to which type. */
|
|
33
|
+
interface Entry {
|
|
34
|
+
readonly mutator: AnyMutator;
|
|
35
|
+
readonly local: LocalHandler<any>;
|
|
36
|
+
readonly type: string;
|
|
37
|
+
readonly operation: Operation;
|
|
38
|
+
}
|
|
39
|
+
/** Options for {@link entries} and {@link registry}. */
|
|
40
|
+
interface Options {
|
|
41
|
+
/** Which operations to derive per type; default all three for every node. */
|
|
42
|
+
readonly writes?: Writes | undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The graph-derived CRUD mutations of every node in the graph (those `writes`
|
|
46
|
+
* selects), as registry entries an app spreads beside its own named
|
|
47
|
+
* mutations: `Mutation.registry([...mine, ...CrudMutation.entries(nodes)])`.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import * as Schema from "effect/Schema";
|
|
52
|
+
* import { CrudMutation, Edge, Mutation, Node } from "@thomasfosterau/legation";
|
|
53
|
+
*
|
|
54
|
+
* const products = Node.make("products", { attributes: { name: Schema.String } });
|
|
55
|
+
* const reviews = Node.make("reviews", {
|
|
56
|
+
* attributes: { rating: Schema.Number },
|
|
57
|
+
* edges: { product: Edge.one("products", { via: "productId" }) },
|
|
58
|
+
* });
|
|
59
|
+
* const nodes = Node.registry([products, reviews]);
|
|
60
|
+
*
|
|
61
|
+
* const registry = Mutation.registry(
|
|
62
|
+
* CrudMutation.entries(nodes, { writes: { reviews: ["create", "delete"] } })
|
|
63
|
+
* );
|
|
64
|
+
* console.log([...registry.mutators.keys()]); // ["reviews/create", "reviews/delete"]
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare const entries: (nodes: NodeRegistry, options?: Options) => ReadonlyArray<Entry>;
|
|
68
|
+
/** The graph-derived CRUD mutations as a registry of their own. Duplicate names cannot occur. */
|
|
69
|
+
declare const registry: (nodes: NodeRegistry, options?: Options) => MutatorRegistry;
|
|
70
|
+
declare namespace Hydration_d_exports {
|
|
71
|
+
export { RemoteSnapshotOptions, Snapshot, SnapshotError, SnapshotFromJson, SnapshotOptions, SnapshotRow, dehydrate, hydrate, hydrateIfEmpty, isEmpty, rowsFor, snapshot };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* One dehydrated row: a {@link StoredRow} tagged with the collection it belongs
|
|
75
|
+
* to, so the flat `rows` array reconstructs the per-collection layout on
|
|
76
|
+
* hydrate. `value` stays `Unknown` (envelope-validated only, ADR-0014).
|
|
77
|
+
*/
|
|
78
|
+
declare const SnapshotRow: Schema.Struct<{
|
|
79
|
+
readonly id: Schema.String;
|
|
80
|
+
readonly version: Schema.Union<readonly [Schema.String, Schema.Number]>;
|
|
81
|
+
readonly value: Schema.Unknown;
|
|
82
|
+
readonly collection: Schema.String;
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* A serialisable capture of a {@link ClientStore}: confirmed rows (flattened
|
|
86
|
+
* with their collection), the pull cookie, the pending-mutation journal, the
|
|
87
|
+
* acknowledged-but-unpulled tail (#336), and each client's mutation id counter
|
|
88
|
+
* (#271). The tail and the counters are optional so a snapshot taken before
|
|
89
|
+
* they existed still loads, as an empty tail and no counters. The schema is
|
|
90
|
+
* the source of truth; {@link Snapshot} is derived from it.
|
|
91
|
+
*
|
|
92
|
+
* The counters are what let a client id be reused across the hydration
|
|
93
|
+
* boundary: once acknowledgements have drained the journal, they are the only
|
|
94
|
+
* record of the ids the backend has already applied, and a hydrated store
|
|
95
|
+
* without them would issue those ids again, which the backend skips as
|
|
96
|
+
* duplicates (a silent lost write).
|
|
97
|
+
*/
|
|
98
|
+
declare const Snapshot: Schema.Struct<{
|
|
99
|
+
readonly rows: Schema.$Array<Schema.Struct<{
|
|
100
|
+
readonly id: Schema.String;
|
|
101
|
+
readonly version: Schema.Union<readonly [Schema.String, Schema.Number]>;
|
|
102
|
+
readonly value: Schema.Unknown;
|
|
103
|
+
readonly collection: Schema.String;
|
|
104
|
+
}>>;
|
|
105
|
+
readonly cookie: Schema.optional<Schema.String>;
|
|
106
|
+
readonly journal: Schema.$Array<Schema.Struct<{
|
|
107
|
+
readonly clientId: Schema.String;
|
|
108
|
+
readonly mutationId: Schema.Number;
|
|
109
|
+
readonly mutator: Schema.String;
|
|
110
|
+
readonly args: Schema.Unknown;
|
|
111
|
+
readonly createdAt: Schema.Number;
|
|
112
|
+
}>>;
|
|
113
|
+
readonly unpulled: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
114
|
+
readonly clientId: Schema.String;
|
|
115
|
+
readonly mutationId: Schema.Number;
|
|
116
|
+
readonly mutator: Schema.String;
|
|
117
|
+
readonly args: Schema.Unknown;
|
|
118
|
+
readonly createdAt: Schema.Number;
|
|
119
|
+
}>>>;
|
|
120
|
+
readonly counters: Schema.optional<Schema.$Record<Schema.String, Schema.Number>>;
|
|
121
|
+
}>;
|
|
122
|
+
/** The type {@link Snapshot} decodes to. */
|
|
123
|
+
type Snapshot = typeof Snapshot.Type;
|
|
124
|
+
/** The type {@link SnapshotRow} decodes to. */
|
|
125
|
+
type SnapshotRow = typeof SnapshotRow.Type;
|
|
126
|
+
/**
|
|
127
|
+
* JSON codec for a {@link Snapshot}: `decode` parses a JSON string and validates
|
|
128
|
+
* it in one step (SSR/devtools ingest), `encode` produces the JSON string.
|
|
129
|
+
*/
|
|
130
|
+
declare const SnapshotFromJson: Schema.fromJsonString<Schema.Struct<{
|
|
131
|
+
readonly rows: Schema.$Array<Schema.Struct<{
|
|
132
|
+
readonly id: Schema.String;
|
|
133
|
+
readonly version: Schema.Union<readonly [Schema.String, Schema.Number]>;
|
|
134
|
+
readonly value: Schema.Unknown;
|
|
135
|
+
readonly collection: Schema.String;
|
|
136
|
+
}>>;
|
|
137
|
+
readonly cookie: Schema.optional<Schema.String>;
|
|
138
|
+
readonly journal: Schema.$Array<Schema.Struct<{
|
|
139
|
+
readonly clientId: Schema.String;
|
|
140
|
+
readonly mutationId: Schema.Number;
|
|
141
|
+
readonly mutator: Schema.String;
|
|
142
|
+
readonly args: Schema.Unknown;
|
|
143
|
+
readonly createdAt: Schema.Number;
|
|
144
|
+
}>>;
|
|
145
|
+
readonly unpulled: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
146
|
+
readonly clientId: Schema.String;
|
|
147
|
+
readonly mutationId: Schema.Number;
|
|
148
|
+
readonly mutator: Schema.String;
|
|
149
|
+
readonly args: Schema.Unknown;
|
|
150
|
+
readonly createdAt: Schema.Number;
|
|
151
|
+
}>>>;
|
|
152
|
+
readonly counters: Schema.optional<Schema.$Record<Schema.String, Schema.Number>>;
|
|
153
|
+
}>>;
|
|
154
|
+
/** The type {@link SnapshotFromJson} decodes to. */
|
|
155
|
+
type SnapshotFromJson = typeof SnapshotFromJson.Type;
|
|
156
|
+
/**
|
|
157
|
+
* Read a {@link ClientStore} into a {@link Snapshot}: enumerate the collections,
|
|
158
|
+
* gather their confirmed rows (flattened with the collection), the cookie, the
|
|
159
|
+
* journal, the unpulled tail and the mutation counters. The tail and the
|
|
160
|
+
* counters are each left out when empty, so a snapshot without them keeps its
|
|
161
|
+
* previous shape.
|
|
162
|
+
*
|
|
163
|
+
* The five parts are one state when the store offers {@link ClientStore.snapshot}
|
|
164
|
+
* (the memory and key-value stores do): a pull or a push acknowledgement lands wholly
|
|
165
|
+
* before or wholly after the read (#392). A store without it is read member by member.
|
|
166
|
+
*/
|
|
167
|
+
declare const dehydrate: (store: ClientStore) => Effect.Effect<Snapshot, StoreError>;
|
|
168
|
+
/**
|
|
169
|
+
* Write a {@link Snapshot} into a {@link ClientStore}: validate it through
|
|
170
|
+
* {@link Snapshot} (so a malformed snapshot fails as a `StoreError`), then
|
|
171
|
+
* put the rows, set the cookie if present, park the unpulled tail, raise the
|
|
172
|
+
* store's mutation counters to the snapshot's, and append the journal, skipping
|
|
173
|
+
* any entry the tail already holds. A snapshot without a tail parks nothing. An
|
|
174
|
+
* outstanding pull release is finished first.
|
|
175
|
+
*
|
|
176
|
+
* The counters are raised, never lowered (#271): a client id reused after
|
|
177
|
+
* hydration continues above every id the snapshot's store had issued, so it
|
|
178
|
+
* never reissues an id the backend has already applied. A snapshot without
|
|
179
|
+
* counters leaves the store's as they are.
|
|
180
|
+
*
|
|
181
|
+
* A running {@link ClientEngine} built over the store re-reads its view and built
|
|
182
|
+
* indexes afterwards: a direct write does not go through the engine, so without this
|
|
183
|
+
* an indexed query could return a row whose indexed field changed (#350). The re-read
|
|
184
|
+
* runs when a write fails too, since the rows written before the failure are in the
|
|
185
|
+
* store. It reaches only the engines built over this exact store object: a store
|
|
186
|
+
* wrapped in a new object (`ClientStore.of({ ...store })`) is not seen, so its engine
|
|
187
|
+
* can stay stale. The same re-read tracks the appended journal entries in its
|
|
188
|
+
* `mutationStates` as `"pending"` (#358), so they settle like a local mutation. Journal ids
|
|
189
|
+
* should be ids this client has not already settled: an id the map has evicted is tracked again,
|
|
190
|
+
* and its outcome event can then follow a second time.
|
|
191
|
+
*
|
|
192
|
+
* The writes are not atomic. Between the first `putRow` and the re-read, an indexed
|
|
193
|
+
* read on an async store can see the old index against the new rows. Once `hydrate`
|
|
194
|
+
* returns or fails, the engine's view and indexes match the store again.
|
|
195
|
+
*
|
|
196
|
+
* `hydrate` does not take the overlay lock of an engine built over the store, so it must
|
|
197
|
+
* not run while that engine is pulling. Its first step finishes an outstanding pull release
|
|
198
|
+
* (#387). If that release is a live pull's, the pull's remaining row writes then land over
|
|
199
|
+
* the snapshot's rows. Hydrate before the engine starts, or while it is stopped.
|
|
200
|
+
*/
|
|
201
|
+
declare const hydrate: (store: ClientStore, snapshot: Snapshot) => Effect.Effect<void, StoreError>;
|
|
202
|
+
/**
|
|
203
|
+
* Whether a store holds nothing: no rows, no cookie, no journalled or unpulled mutations.
|
|
204
|
+
* The "fresh browser" test {@link hydrateIfEmpty} gates on.
|
|
205
|
+
*/
|
|
206
|
+
declare const isEmpty: (store: ClientStore) => Effect.Effect<boolean, StoreError>;
|
|
207
|
+
/**
|
|
208
|
+
* {@link hydrate}, but only into an empty store; returns whether it hydrated.
|
|
209
|
+
*
|
|
210
|
+
* This is the right client-boot default over a *durable* store: on a repeat
|
|
211
|
+
* visit the store already holds rows, a cookie, and possibly journalled
|
|
212
|
+
* offline mutations that are all fresher than the SSR snapshot — hydrating
|
|
213
|
+
* over them would regress the cookie (and with it the CVR conversation) and
|
|
214
|
+
* clobber newer confirmed rows. An empty store (first visit, cleared storage)
|
|
215
|
+
* takes the snapshot wholesale.
|
|
216
|
+
*/
|
|
217
|
+
declare const hydrateIfEmpty: (store: ClientStore, snapshot: Snapshot) => Effect.Effect<boolean, StoreError>;
|
|
218
|
+
/**
|
|
219
|
+
* Project a snapshot onto a read, locally and synchronously: the snapshot's
|
|
220
|
+
* rows for the read's collection, filtered/sorted/windowed by the read's
|
|
221
|
+
* compiled root window. This is how a component derives its initial value
|
|
222
|
+
* (e.g. the rune hooks' `initial` option) from the page's snapshot — during
|
|
223
|
+
* SSR and on first client render — without touching an engine.
|
|
224
|
+
*
|
|
225
|
+
* `include`d edges are not resolved here: a snapshot is flat rows, and
|
|
226
|
+
* resolving edges is the Client's job once the engine is up. Seed the base
|
|
227
|
+
* rows and let the first live emission fill the edges in.
|
|
228
|
+
*/
|
|
229
|
+
declare const rowsFor: (snapshot: Snapshot, nodes: NodeRegistry, read: Read) => ReadonlyArray<LocalRow>;
|
|
230
|
+
/** Options for {@link snapshot}. */
|
|
231
|
+
interface SnapshotOptions {
|
|
232
|
+
/**
|
|
233
|
+
* The client group the render belongs to — the browser's group id (e.g.
|
|
234
|
+
* carried in an HTTP cookie), so the cookie in the produced snapshot
|
|
235
|
+
* continues that group's CVR conversation on the client's first pull.
|
|
236
|
+
*/
|
|
237
|
+
readonly clientGroupId: string;
|
|
238
|
+
/** Client id for the request-scoped engine (never pushes). Default `"ssr"`. */
|
|
239
|
+
readonly clientId?: string;
|
|
240
|
+
/** The node graph the reads compile against. */
|
|
241
|
+
readonly nodes: NodeRegistry;
|
|
242
|
+
/** The reads the page needs — subscribed and pulled once. */
|
|
243
|
+
readonly reads: ReadonlyArray<Read>;
|
|
244
|
+
/** Mutation registry for the request-scoped engine. Default: none. */
|
|
245
|
+
readonly mutations?: MutatorRegistry;
|
|
246
|
+
/**
|
|
247
|
+
* The carrier the request-scoped engine pulls over. Omit it for the
|
|
248
|
+
* in-process default — a loop-back transport to the in-context
|
|
249
|
+
* {@link ServerHandler} — which is what a single-process app wants.
|
|
250
|
+
*
|
|
251
|
+
* Pass one when the renderer is *not* the process holding the backend: a
|
|
252
|
+
* SvelteKit Worker rendering against a separate API Worker, an SSR tier in
|
|
253
|
+
* front of a remote sync server. Whatever the carrier, it must preserve the
|
|
254
|
+
* CVR conversation end to end — the request's `clientGroupId` reaches the
|
|
255
|
+
* Server unchanged, and the Server's fresh cookie comes back in the pull
|
|
256
|
+
* response — or the snapshot's cookie belongs to a conversation the client
|
|
257
|
+
* is not in, and its first pull silently degrades to the reset path.
|
|
258
|
+
*/
|
|
259
|
+
readonly transport?: ClientTransport;
|
|
260
|
+
}
|
|
261
|
+
/** {@link SnapshotOptions} with the carrier supplied — no `ServerHandler` needed. */
|
|
262
|
+
interface RemoteSnapshotOptions extends SnapshotOptions {
|
|
263
|
+
readonly transport: ClientTransport;
|
|
264
|
+
}
|
|
265
|
+
/** What a snapshot render can fail with. */
|
|
266
|
+
type SnapshotError = StoreError | TransportError | MutatorError | VersionNotSupportedError;
|
|
267
|
+
/**
|
|
268
|
+
* Produce an SSR snapshot over a request-scoped engine: build an in-memory
|
|
269
|
+
* {@link ClientStore}, subscribe the page's subsets over the given
|
|
270
|
+
* {@link ClientTransport}, pull once, and {@link dehydrate}. Everything is
|
|
271
|
+
* scoped to the call — nothing outlives it.
|
|
272
|
+
*
|
|
273
|
+
* With `options.transport` the render needs nothing from context; without it
|
|
274
|
+
* the in-process path applies and the app's sync server is taken from context
|
|
275
|
+
* as `ServerHandler`, carried by a loop-back transport.
|
|
276
|
+
*
|
|
277
|
+
* This is the server half of the SSR flow described above; run it inside a
|
|
278
|
+
* request handler (a SvelteKit `load`, a Next.js loader). Framework packages
|
|
279
|
+
* wrap this — they add the framework's own plumbing (a cookie, a `load`
|
|
280
|
+
* signature), never their own hydration logic.
|
|
281
|
+
*/
|
|
282
|
+
declare function snapshot(options: RemoteSnapshotOptions): Effect.Effect<Snapshot, SnapshotError>;
|
|
283
|
+
/** The in-process form: renders against the app's sync server, the `ServerHandler` in context. */
|
|
284
|
+
declare function snapshot(options: SnapshotOptions): Effect.Effect<Snapshot, SnapshotError, ServerHandler>;
|
|
285
|
+
declare namespace Server_d_exports {
|
|
286
|
+
export { Broadcast, MakeOptions, MutateRequest, Receipt, Server, make };
|
|
287
|
+
}
|
|
288
|
+
/** A change announcement for {@link Server.broadcast}. */
|
|
289
|
+
interface Broadcast {
|
|
290
|
+
readonly collection: string;
|
|
291
|
+
/** The changed row ids, when the writer knows them (finer fan-out). */
|
|
292
|
+
readonly ids?: ReadonlyArray<string>;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* One Mutation for {@link Server.mutate} to run: the client group, the client
|
|
296
|
+
* and mutation id that name it, and the Mutation with its args.
|
|
297
|
+
*
|
|
298
|
+
* A form action passes a **form client** id minted for the rendered form, with
|
|
299
|
+
* mutation id `1` (ADR-0030 #215 §2). A mutation id is per client and
|
|
300
|
+
* contiguous, so the action must not borrow the next id of a tab's engine.
|
|
301
|
+
*/
|
|
302
|
+
interface MutateRequest<Args, ArgsEncoded> {
|
|
303
|
+
/** The client group the mutation belongs to (ADR-0020's client-group cookie). */
|
|
304
|
+
readonly clientGroupId: string;
|
|
305
|
+
/** The client that names the mutation: a form client id for a form action. */
|
|
306
|
+
readonly clientId: string;
|
|
307
|
+
/** The mutation's id for that client: `1` for a freshly rendered form. */
|
|
308
|
+
readonly mutationId: number;
|
|
309
|
+
/** The Mutation definition to run; its name selects the backend's handler. */
|
|
310
|
+
readonly mutation: Mutator<string, Args, ArgsEncoded>;
|
|
311
|
+
/**
|
|
312
|
+
* The args, as the form layer hands them over: decoded and validated. They
|
|
313
|
+
* are encoded against `mutation.args` for the backend, which decodes them
|
|
314
|
+
* again as for a pushed mutation.
|
|
315
|
+
*/
|
|
316
|
+
readonly args: Args;
|
|
317
|
+
/** The schema version to check, as a push carries it (#48); unset when omitted. */
|
|
318
|
+
readonly schemaVersion?: string | undefined;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* What {@link Server.mutate} answers: the mutation it ran, named by its client
|
|
322
|
+
* and mutation id, and the backend's ruling (ADR-0030 #215 §3). The phase uses
|
|
323
|
+
* `MutationState`'s vocabulary: `acknowledged`, or `rejected` with the reason
|
|
324
|
+
* the backend gave. A client holding an optimistic effect for this mutation
|
|
325
|
+
* releases it when a pull's `lastMutationIds` covers it, not on the receipt.
|
|
326
|
+
*/
|
|
327
|
+
type Receipt = {
|
|
328
|
+
readonly clientId: string;
|
|
329
|
+
readonly mutationId: number;
|
|
330
|
+
readonly phase: "acknowledged";
|
|
331
|
+
} | {
|
|
332
|
+
readonly clientId: string;
|
|
333
|
+
readonly mutationId: number;
|
|
334
|
+
readonly phase: "rejected";
|
|
335
|
+
/** The backend's permanent-rejection reason. */
|
|
336
|
+
readonly reason: string;
|
|
337
|
+
};
|
|
338
|
+
/** One per backend: the protocol `handler` plus `broadcast` for out-of-band changes. */
|
|
339
|
+
interface Server {
|
|
340
|
+
/** The sync protocol handler — mount it on any router or carrier. */
|
|
341
|
+
readonly handler: ServerHandler;
|
|
342
|
+
/**
|
|
343
|
+
* Announce out-of-band changes: subscribers whose windows may be
|
|
344
|
+
* affected are poked and pull. Writes pushed through {@link handler}
|
|
345
|
+
* broadcast implicitly.
|
|
346
|
+
*/
|
|
347
|
+
readonly broadcast: (change: Broadcast) => Effect.Effect<void>;
|
|
348
|
+
/**
|
|
349
|
+
* Run one named Mutation as one of a client group's mutations, and answer
|
|
350
|
+
* its {@link Receipt} (ADR-0030 #215 §1–§3).
|
|
351
|
+
*
|
|
352
|
+
* The path is the push path minus the transport: the group's identity is
|
|
353
|
+
* resolved through the `IdentityResolver`, the middleware's `onPush` runs,
|
|
354
|
+
* the backend applies the mutation with its id bumped in the same
|
|
355
|
+
* transaction as its effects (a permanent rejection bumps it with no
|
|
356
|
+
* effects, ADR-0008), and the write's hints are broadcast as a pushed
|
|
357
|
+
* write's are. A pull from any client of the group then lists `clientId` in
|
|
358
|
+
* `lastMutationIds`.
|
|
359
|
+
*
|
|
360
|
+
* A resubmission of the same `(clientId, mutationId)` is a replay: the
|
|
361
|
+
* backend's ledger skips it, the handler does not run again, and the call
|
|
362
|
+
* answers the original ruling (a rejection from the backend's rejection
|
|
363
|
+
* memory, Backend guarantee 4).
|
|
364
|
+
*
|
|
365
|
+
* Args that do not encode against the Mutation's schema are a defect of the
|
|
366
|
+
* hand-over from the form layer, not a field error (§5): the effect dies.
|
|
367
|
+
* Every other failure (identity, middleware, a transient backend error, an
|
|
368
|
+
* unsupported schema version) fails as the push path does.
|
|
369
|
+
*/
|
|
370
|
+
readonly mutate: <Args, ArgsEncoded>(request: MutateRequest<Args, ArgsEncoded>) => Effect.Effect<Receipt, TransportError | VersionNotSupportedError>;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Options for {@link make}: the backend and auth are required; CVR storage and the bus default
|
|
374
|
+
* to in-memory / in-process.
|
|
375
|
+
*/
|
|
376
|
+
interface MakeOptions {
|
|
377
|
+
/** The storage contract (ADR-0009). */
|
|
378
|
+
readonly backend: Backend;
|
|
379
|
+
readonly auth: {
|
|
380
|
+
/** Deny-by-default per-collection filters. */
|
|
381
|
+
readonly policy: AuthPolicy;
|
|
382
|
+
/** Resolve a client group to its identity (session binding). */
|
|
383
|
+
readonly identity?: IdentityResolver;
|
|
384
|
+
};
|
|
385
|
+
/** Named-query resolution (server-authoritative subsets). */
|
|
386
|
+
readonly queries?: QueryResolver;
|
|
387
|
+
/** Cross-cutting interception (tenancy, cost control, telemetry). */
|
|
388
|
+
readonly middleware?: SyncMiddleware;
|
|
389
|
+
/** CVR storage; defaults to in-memory. */
|
|
390
|
+
readonly cvr?: CvrStore;
|
|
391
|
+
/** The hint fan-out bus; defaults to in-process. */
|
|
392
|
+
readonly bus?: InvalidationBus;
|
|
393
|
+
/** Handler tuning passthrough. */
|
|
394
|
+
readonly options?: SyncServerOptions;
|
|
395
|
+
}
|
|
396
|
+
/** Build the Server: handler + broadcast over backend and auth. */
|
|
397
|
+
declare const make: (options: MakeOptions) => Effect.Effect<Server, never, Scope.Scope>;
|
|
398
|
+
export { Hydration_d_exports as n, CrudMutation_d_exports as r, Server_d_exports as t };
|
|
399
|
+
//# sourceMappingURL=index-CPPfp0F4.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CPPfp0F4.d.ts","names":["Mutator.AnyMutator","Mutator.LocalHandler","Node.NodeRegistry","Mutator.MutatorRegistry","Node.NodeRegistry","Query.Read","ClientEngineModule.LocalRow","Mutator.MutatorRegistry","Mutator.Mutator","Transport.ServerHandler","BackendService","Authorization.AuthPolicy","Authorization.IdentityResolver","Query.QueryResolver","Authorization.SyncMiddleware","Cvr.CvrStore","InvalidationBus.InvalidationBus","SyncServer.SyncServerOptions"],"sources":["../src/CrudMutation.ts","../src/Hydration.ts","../src/Server.ts"],"mappings":";;;;;;;;KA+CY;;;;;KAMA,SAAS,SAAS,eAAe,cAAc;;cAG9C,OAAQ,cAAc,WAAW;;cAGjC,WAAS,OAAA;;;;;;KAOV,mBAAmB,UAAU;;cAG5B,YAAU,OAAA;;;;;KAGX,oBAAoB,WAAW;;UAG1B;WACN,SAASA;WACT,OAAOC;WACP;WACA,WAAW;;;UAIL;;WAEN,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;cAwEP,UAAW,OAAOC,cAAmB,UAAU,YAAU,cAAc;;cAIvE,WAAY,OAAOA,cAAmB,UAAU,YAAUC;;;;;;;;;cClF1D,aAAW,OAAA;;;;;;;;;;;;;;;;;;;;cAmBX,UAAQ,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;KAcT,kBAAkB,SAAS;;KAG3B,qBAAqB,YAAY;;;;;cAMhC,kBAAgB,OAAA,eAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;KAGjB,0BAA0B,iBAAiB;;;;;;;;;;;;cAyC1C,YAAa,OAAO,gBAAc,OAAO,OAAO,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkD1D,UAAW,OAAO,aAAa,UAAU,aAAW,OAAO,aAAa;;;;;cAoDxE,UAAW,OAAO,gBAAc,OAAO,gBAAgB;;;;;;;;;;;cAqBvD,iBACX,OAAO,aACP,UAAU,aACT,OAAO,gBAAgB;;;;;;;;;;;;cAkBb,UACX,UAAU,UACV,OAAOC,cACP,MAAMC,SACL,cAAcC;;UASA;;;;;;WAMN;;WAEA;;WAEA,OAAOF;;WAEP,OAAO,cAAcC;;WAErB,YAAYE;;;;;;;;;;;;;;WAcZ,YAAY;;;UAIN,8BAA8B;WACpC,WAAW;;;KAIV,gBAAgB,aAAa,iBAAiB,eAAe;;;;;;;;;;;;;;;;iBA8CzD,SAAS,SAAS,wBAAwB,OAAO,OAAO,UAAU;;iBAElE,SACd,SAAS,kBACR,OAAO,OAAO,UAAU,eAAe;;;;;UC5WzB;WACN;;WAEA,MAAM;;;;;;;;;;UAWA,cAAc,MAAM;;WAE1B;;WAEA;;WAEA;;WAEA,UAAUC,gBAAwB,MAAM;;;;;;WAMxC,MAAM;;WAEN;;;;;;;;;KAUC;WAEG;WACA;WACA;;WAGA;WACA;WACA;;WAEA;;;UAIE;;WAEN,SAASC;;;;;;WAMT,YAAY,QAAQ,cAAc,OAAO;;;;;;;;;;;;;;;;;;;;;;;WAuBzC,SAAS,MAAM,aACtB,SAAS,cAAc,MAAM,iBAC1B,OAAO,OAAO,SAAS,iBAAiB;;;;;;UAiC9B;;WAEN,SAASC;WACT;;aAEE,QAAQC;;aAER,WAAWC;;;WAGb,UAAUC;;WAEV,aAAaC;;WAEb,MAAMC;;WAEN,MAAMC;;WAEN,UAAUC;;;cAIR,OAAQ,SAAS,gBAAc,OAAO,OAAO,eAAe,MAAM"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { At as Predicate_d_exports, Bt as StoreError, Ft as JournalError, Ht as UnknownCollectionError, It as MutationRejected, Lt as MutatorError, Mt as BackendError, Nt as DuplicateNameError, Pt as FilterDeclarationError, Rt as ProtocolError, Ut as VersionNotSupportedError, Vt as TransportError, W as Transport_d_exports, b as Query_d_exports, ct as Backend_d_exports, d as Authorization_d_exports, et as Mutator_d_exports, ht as Edge_d_exports, jt as AuthorizationError, m as Client_d_exports, mt as Node_d_exports, n as MemoryBackend_d_exports, nt as ClientStore_d_exports, ot as Aggregate_d_exports, rt as Identity_d_exports, vt as Collection_d_exports, yt as FilterPolicy_d_exports, zt as QueryError } from "./MemoryBackend-BziXwfcs.js";
|
|
2
|
+
import { n as Hydration_d_exports, r as CrudMutation_d_exports, t as Server_d_exports } from "./index-CPPfp0F4.js";
|
|
3
|
+
export { Aggregate_d_exports as Aggregate, Authorization_d_exports as Authorization, AuthorizationError, Backend_d_exports as Backend, BackendError, Client_d_exports as Client, ClientStore_d_exports as ClientStore, Collection_d_exports as Collection, CrudMutation_d_exports as CrudMutation, DuplicateNameError, Edge_d_exports as Edge, FilterDeclarationError, FilterPolicy_d_exports as FilterPolicy, Hydration_d_exports as Hydration, Identity_d_exports as Identity, JournalError, MemoryBackend_d_exports as MemoryBackend, Mutator_d_exports as Mutation, Mutator_d_exports as Mutator, MutationRejected, MutatorError, Node_d_exports as Node, Predicate_d_exports as Predicate, ProtocolError, Query_d_exports as Query, QueryError, Server_d_exports as Server, StoreError, Transport_d_exports as Transport, TransportError, UnknownCollectionError, VersionNotSupportedError };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Bn as StoreError, Bt as Query_exports, C as Authorization_exports, Cn as Collection_exports, Fn as JournalError, Ft as Mutator_exports, Hn as UnknownCollectionError, In as MutationRejected, Ln as MutatorError, Mn as BackendError, Nn as DuplicateNameError, On as FilterPolicy_exports, Pn as FilterDeclarationError, Rn as ProtocolError, Rt as Aggregate_exports, Un as VersionNotSupportedError, Vn as TransportError, bt as ClientStore_exports, g as Backend_exports, in as Predicate_exports, jn as AuthorizationError, jt as Identity_exports, rt as Transport_exports, t as MemoryBackend_exports, zn as QueryError } from "./MemoryBackend-DxP8t4ge.js";
|
|
2
|
+
import { a as Edge_exports, i as CrudMutation_exports, n as Hydration_exports, o as Node_exports, r as Client_exports, t as Server_exports } from "./src-FWXpu_vP.js";
|
|
3
|
+
export { Aggregate_exports as Aggregate, Authorization_exports as Authorization, AuthorizationError, Backend_exports as Backend, BackendError, Client_exports as Client, ClientStore_exports as ClientStore, Collection_exports as Collection, CrudMutation_exports as CrudMutation, DuplicateNameError, Edge_exports as Edge, FilterDeclarationError, FilterPolicy_exports as FilterPolicy, Hydration_exports as Hydration, Identity_exports as Identity, JournalError, MemoryBackend_exports as MemoryBackend, Mutator_exports as Mutation, Mutator_exports as Mutator, MutationRejected, MutatorError, Node_exports as Node, Predicate_exports as Predicate, ProtocolError, Query_exports as Query, QueryError, Server_exports as Server, StoreError, Transport_exports as Transport, TransportError, UnknownCollectionError, VersionNotSupportedError };
|