@jarenjs/linq 0.66.1 → 0.67.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/docs/DB-CLIENT.md CHANGED
@@ -83,10 +83,9 @@ invent one. §2 keeps its D3 slot and its meaning — this is where every
83
83
  name a caller writes is named — under the title that describes what it
84
84
  holds.
85
85
 
86
- The vocabulary is small and the surface is not. Two exported names, and
87
- then whatever those two hand back: a client of frozen handles, each of
86
+ The exports include the store door and its helpers. The door hands back a client of frozen handles, each of
88
87
  which is the store's own set plus the chain plus three additions. §2.1
89
- divides the two; §2.2 to §2.5 enumerate them.
88
+ divides the responsibilities; §2.2 to §2.7 enumerate the surface.
90
89
 
91
90
  ### 2.1 What is the store's and what is the client's
92
91
 
@@ -105,14 +104,15 @@ decides which document answers a question about behaviour.
105
104
  | `client.collections.<name>` | the store's collection | the same chain start and `live`, typed from the pen's collection schema (§2.5) |
106
105
  | `saveChanges()`, `transaction(fn)`, `close()`, `capabilities`, `store` | the store's | pass-throughs; `saveChanges` and `live` exist exactly when the model declares entities, as on the store; `store` is the escape hatch, typed `TypedStore` |
107
106
 
108
- ### 2.2 The three exported names
107
+ ### 2.2 The exported names
109
108
 
110
109
  The whole export surface: a door, a type-level reader for what it hands
111
- back, and the durable ledger over what it opened.
110
+ back, the durable ledger over what it opened, and replication document authoring.
112
111
 
113
112
  | Name | Answers | Type reading |
114
113
  |---|---|---|
115
114
  | `open(model, options)` | a promise of the frozen client — `store`, `capabilities`, `entities`, `collections`, `transaction`, `close`, and `saveChanges`/`live` when the model declares entities | `Client<InferMeta<typeof model>>` for a pen model; `Client<E>` for `open<E>(json, …)`; the wide map for a bare JSON model |
115
+ | `defineReplication(header)` | a logical replication document builder — §2.7 | `ReplicationPen` |
116
116
  | `defaultValidator()` | `new JarenValidator({ collectErrors: true })` with `stringFormats` and `dateTimeFormats` registered | `JarenValidator` |
117
117
  | `createDbLedger(client, options?)` | the contract idempotency ledger (`claim`/`commit`/`fail`/`lookup`/`sweep`) over a declared collection of the client's store — §2.6 | `DbLedger`; structurally `@jarenjs/contract`'s `Ledger` |
118
118
 
@@ -298,6 +298,17 @@ await db.transaction(async (tx) => { // a settlement in
298
298
  });
299
299
  ```
300
300
 
301
+ ### 2.7 Replication documents
302
+
303
+ The DB client forwards `replication` open options to its Store. Access committed
304
+ pages, frontiers, conflicts and resets through `client.store.replication`.
305
+ `defineReplication({ replica, seq, frontier, model })` authors a logical envelope:
306
+ chain `.change(table, key, before, after)`, then `.toDocument()` or `.toJSON()`.
307
+ It shares the Store's normalization authority and preserves operation order.
308
+ See the [replication format](../../db/docs/REPLICATION-FORMAT.md) for causality,
309
+ conflict policy and bounded reset contracts. Authoring does not allocate a
310
+ committed sequence; normal replication exports the Store's committed pages.
311
+
301
312
  ## 3. Worked examples
302
313
 
303
314
  The client's examples are not builder-to-document pairs, and this is
@@ -815,10 +826,10 @@ never builds one; the migration between two of them is
815
826
 
816
827
  ## 7. Cost
817
828
 
818
- `@jarenjs/linq/db` builds to **<!--fact:bundle.db-->591,917<!--/fact--> bytes** as a minified,
829
+ `@jarenjs/linq/db` builds to **<!--fact:bundle.db-->623,994<!--/fact--> bytes** as a minified,
819
830
  tree-shaken ESM bundle — the figure `scripts/check-tree-shaking.js`
820
831
  measures and `npm run test:tree-shaking` reports, published rounded
821
- (<!--fact:bundle.db.kb-->592<!--/fact--> kB) beside the other nine subpath prices in
832
+ (<!--fact:bundle.db.kb-->624<!--/fact--> kB) beside the other nine subpath prices in
822
833
  [docs/CONSUMING.md](../../../docs/CONSUMING.md).
823
834
 
824
835
  It is by far the largest of the ten, and the reason is §1.1's edge rather
@@ -35,7 +35,7 @@ is the index of the ten, and it is how a reader reaches any of them.
35
35
  <!--fact:pens.index-->
36
36
  | Document | Lines | What it writes, and when to open it |
37
37
  |---|---:|---|
38
- | [LINQ-FORMAT.md](LINQ-FORMAT.md) | 819 | this file, the binder and the family's **normative reference**: what a pen is, the rules all of them keep, the shared `JL01xx` table, and the cross-pen views derived from the ten guides it indexes. **Read it when** you want a rule that is true of every pen, an index of the eleven documents, or one place to look up a method without knowing which pen owns it |
38
+ | [LINQ-FORMAT.md](LINQ-FORMAT.md) | 820 | this file, the binder and the family's **normative reference**: what a pen is, the rules all of them keep, the shared `JL01xx` table, and the cross-pen views derived from the ten guides it indexes. **Read it when** you want a rule that is true of every pen, an index of the eleven documents, or one place to look up a method without knowing which pen owns it |
39
39
  | [QUERY-PEN.md](QUERY-PEN.md) | 1,724 | the chain, `.` — query documents (`jaren-query`) and the provider seam. **Read it when** you are querying data, or implementing a provider that answers a query document |
40
40
  | [SCHEMA-PEN.md](SCHEMA-PEN.md) | 1,218 | `./schema` — JSON Schema 2020-12: the structural keywords, the constraints and the annotations, each with a method of its own, plus `$query`, `$defs`/`$ref` recursion and the normalizer's per-field predicates. **Read it when** you are describing the shape of data — for validation, for a form, or as the base of an entity |
41
41
  | [MODEL-PEN.md](MODEL-PEN.md) | 1,092 | `./model` — the `x-entity` vocabulary on JSON Schema, and the `$model` 0.1 document `openStore` accepts unchanged. **Read it when** you are declaring a store's entities, their keys and their relations |
@@ -45,7 +45,7 @@ is the index of the ten, and it is how a reader reaches any of them.
45
45
  | [FLOW-PEN.md](FLOW-PEN.md) | 1,033 | `./flow` — `jaren-fsm` 0.1 machines and `jaren-dag` 0.1 dataflows, every query-valued member captured. **Read it when** you are declaring a state machine or a dependency graph of tasks |
46
46
  | [APP-PEN.md](APP-PEN.md) | 1,143 | `./app` — the `jaren-app` 0.1 document `createApp` runs, and the JSON Schema of its state beside it. **Read it when** you are declaring a whole application: state, view, actions, effects |
47
47
  | [FORMS-PEN.md](FORMS-PEN.md) | 940 | `./forms` — the `x-form` vocabulary on JSON Schema, and `assertOnSubmit()`, the same rules' layer-3 `$query` twin. **Read it when** you are turning a schema into a form |
48
- | [DB-CLIENT.md](DB-CLIENT.md) | 882 | `./db` — the client: the store's typed front door, not a pen, and the package's one runtime edge. **Read it when** you are reading or writing rows: `load`, `include`, `link`/`unlink`, `live` |
48
+ | [DB-CLIENT.md](DB-CLIENT.md) | 893 | `./db` — the client: the store's typed front door, not a pen, and the package's one runtime edge. **Read it when** you are reading or writing rows: `load`, `include`, `link`/`unlink`, `live` |
49
49
  <!--/fact-->
50
50
 
51
51
  Every row of that table is derived, and none of it is written here: the
@@ -201,7 +201,7 @@ and the bundle is the byte count the tree-shaking probe builds.
201
201
  <!--fact:pens.census-->
202
202
  | Document | Subpath | Lines | Mapping rows | Worked examples | Refusals | Bundle |
203
203
  |---|---|---:|---:|---:|---:|---:|
204
- | [LINQ-FORMAT.md](LINQ-FORMAT.md) | — | 819 | — | — | — | — |
204
+ | [LINQ-FORMAT.md](LINQ-FORMAT.md) | — | 820 | — | — | — | — |
205
205
  | [QUERY-PEN.md](QUERY-PEN.md) | `.` | 1,724 | 34 | 8 | 15 | 174,264 B |
206
206
  | [SCHEMA-PEN.md](SCHEMA-PEN.md) | `./schema` | 1,218 | 66 | 10 | 4 | 33,156 B |
207
207
  | [MODEL-PEN.md](MODEL-PEN.md) | `./model` | 1,092 | 28 | 6 | 3 | 41,582 B |
@@ -211,8 +211,8 @@ and the bundle is the byte count the tree-shaking probe builds.
211
211
  | [FLOW-PEN.md](FLOW-PEN.md) | `./flow` | 1,033 | 16 | 7 | 3 | 19,910 B |
212
212
  | [APP-PEN.md](APP-PEN.md) | `./app` | 1,143 | 22 | 7 | 3 | 47,444 B |
213
213
  | [FORMS-PEN.md](FORMS-PEN.md) | `./forms` | 940 | 18 | 6 | 3 | 37,312 B |
214
- | [DB-CLIENT.md](DB-CLIENT.md) | `./db` | 882 | 40 | 4 | 2 | 591,917 B |
215
- | **eleven documents** | | **11,808** | **290** | **67** | | |
214
+ | [DB-CLIENT.md](DB-CLIENT.md) | `./db` | 893 | 41 | 4 | 2 | 623,994 B |
215
+ | **eleven documents** | | **11,820** | **291** | **67** | | |
216
216
  <!--/fact-->
217
217
 
218
218
  A pen whose mapping rows are far below its worked examples is a pen
@@ -263,7 +263,7 @@ it and each document publishes it. The rounded column is what
263
263
  | `@jarenjs/linq/flow` | [FLOW-PEN.md](FLOW-PEN.md) | 19,910 B | 20 kB |
264
264
  | `@jarenjs/linq/app` | [APP-PEN.md](APP-PEN.md) | 47,444 B | 47 kB |
265
265
  | `@jarenjs/linq/forms` | [FORMS-PEN.md](FORMS-PEN.md) | 37,312 B | 37 kB |
266
- | `@jarenjs/linq/db` | [DB-CLIENT.md](DB-CLIENT.md) | 591,917 B | 592 kB |
266
+ | `@jarenjs/linq/db` | [DB-CLIENT.md](DB-CLIENT.md) | 623,994 B | 624 kB |
267
267
  <!--/fact-->
268
268
 
269
269
  Read these as prices, not as scores. `./db` is the largest by an order of
@@ -767,11 +767,12 @@ it says.
767
767
  | `client.collections.<name>` | the store's collection | the same chain start and `live`, typed from the pen's collection schema (§2.5) |
768
768
  | `saveChanges()`, `transaction(fn)`, `close()`, `capabilities`, `store` | the store's | pass-throughs; `saveChanges` and `live` exist exactly when the model declares entities, as on the store; `store` is the escape hatch, typed `TypedStore` |
769
769
 
770
- **The three exported names**
770
+ **The exported names**
771
771
 
772
772
  | Name | Answers | Type reading |
773
773
  |---|---|---|
774
774
  | `open(model, options)` | a promise of the frozen client — `store`, `capabilities`, `entities`, `collections`, `transaction`, `close`, and `saveChanges`/`live` when the model declares entities | `Client<InferMeta<typeof model>>` for a pen model; `Client<E>` for `open<E>(json, …)`; the wide map for a bare JSON model |
775
+ | `defineReplication(header)` | a logical replication document builder — §2.7 | `ReplicationPen` |
775
776
  | `defaultValidator()` | `new JarenValidator({ collectErrors: true })` with `stringFormats` and `dateTimeFormats` registered | `JarenValidator` |
776
777
  | `createDbLedger(client, options?)` | the contract idempotency ledger (`claim`/`commit`/`fail`/`lookup`/`sweep`) over a declared collection of the client's store — §2.6 | `DbLedger`; structurally `@jarenjs/contract`'s `Ledger` |
777
778
 
package/docs/QUERY-PEN.md CHANGED
@@ -1705,7 +1705,7 @@ making:
1705
1705
  `docs/CONSUMING.md` states the rounded price of all ten subpaths in one
1706
1706
  table, each figure held equal to the same measurements. Two of its rows
1707
1707
  are the ones to read together: the chain at <!--fact:bundle.chain.kb-->174<!--/fact--> kB and
1708
- `./db` at <!--fact:bundle.db.kb-->592<!--/fact--> kB.
1708
+ `./db` at <!--fact:bundle.db.kb-->624<!--/fact--> kB.
1709
1709
  The client costs what the store costs, by construction, and the chain
1710
1710
  costs what running a query costs.
1711
1711
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jarenjs/linq",
3
3
  "private": false,
4
- "version": "0.66.1",
4
+ "version": "0.67.0",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "types": "./types/index.d.ts",
@@ -84,13 +84,13 @@
84
84
  "prepack": "npm run build:types"
85
85
  },
86
86
  "dependencies": {
87
- "@jarenjs/core": "^0.66.1",
88
- "@jarenjs/json": "^0.66.1"
87
+ "@jarenjs/core": "^0.67.0",
88
+ "@jarenjs/json": "^0.67.0"
89
89
  },
90
90
  "peerDependencies": {
91
- "@jarenjs/db": "^0.66.1",
92
- "@jarenjs/formats": "^0.66.1",
93
- "@jarenjs/validate": "^0.66.1"
91
+ "@jarenjs/db": "^0.67.0",
92
+ "@jarenjs/formats": "^0.67.0",
93
+ "@jarenjs/validate": "^0.67.0"
94
94
  },
95
95
  "peerDependenciesMeta": {
96
96
  "@jarenjs/db": {
package/src/db/index.js CHANGED
@@ -22,3 +22,4 @@
22
22
 
23
23
  export { open, defaultValidator } from './open.js';
24
24
  export { createDbLedger } from './ledger.js';
25
+ export { defineReplication } from './replication.js';
@@ -0,0 +1,20 @@
1
+ //@ts-check
2
+ /** Deterministic logical-envelope authoring through the DB format authority. */
3
+ import { normalizeReplication } from '@jarenjs/db';
4
+
5
+ /** Start a transport-neutral replication document; changes remain in declared order.
6
+ * @param {{ replica: string, seq: number, frontier: Record<string, number>, model: string }} header */
7
+ export function defineReplication(header) {
8
+ const operations = [];
9
+ const builder = Object.freeze({
10
+ /** @param {string} table @param {string} key @param {any} before @param {any} after */
11
+ change(table, key, before, after) {
12
+ operations.push(structuredClone({ table, key, before, after }));
13
+ return builder;
14
+ },
15
+ toDocument() { return normalizeReplication({ $replication: '0.1', ...header, operations }); },
16
+ toJSON() { return builder.toDocument(); },
17
+ });
18
+ header = structuredClone(header);
19
+ return builder;
20
+ }
package/types/db.d.ts CHANGED
@@ -357,3 +357,10 @@ export type Client<E extends MetaMap<E>, C = Record<string, unknown>> = {
357
357
  options?: TransactionOptions): Promise<Awaited<R>>;
358
358
  close(options?: { graceMs?: number }): Promise<void>;
359
359
  } & ([keyof E] extends [never] ? {} : EntityClientMembers);
360
+
361
+ /** Author a logical envelope using the DB's canonical format validator. */
362
+ export function defineReplication(header: Omit<import('@jarenjs/db').ReplicationEnvelope, '$replication' | 'operations'>): {
363
+ change(table: string, key: string, before: Record<string, unknown> | null, after: Record<string, unknown> | null): ReturnType<typeof defineReplication>;
364
+ toDocument(): import('@jarenjs/db').ReplicationEnvelope;
365
+ toJSON(): import('@jarenjs/db').ReplicationEnvelope;
366
+ };