@jarenjs/linq 0.75.0 → 0.83.2
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/README.md +8 -1
- package/docs/AI-PEN.md +1 -1
- package/docs/APP-PEN.md +3 -3
- package/docs/CHARTS-PEN.md +1 -1
- package/docs/CONTRACT-PEN.md +4 -4
- package/docs/DB-CLIENT.md +200 -8
- package/docs/FLOW-PEN.md +3 -3
- package/docs/FORMS-PEN.md +2 -2
- package/docs/FORMULA-PEN.md +41 -0
- package/docs/JSLT-PEN.md +4 -4
- package/docs/JTLT-PEN.md +1 -1
- package/docs/LINQ-FORMAT.md +60 -43
- package/docs/MESSAGES-PEN.md +1 -1
- package/docs/MIGRATION-PEN.md +3 -3
- package/docs/MODEL-PEN.md +27 -3
- package/docs/PROJECT-PEN.md +10 -4
- package/docs/QUERY-PEN.md +25 -8
- package/docs/SCHEMA-PEN.md +2 -2
- package/package.json +10 -6
- package/src/db/effects.js +148 -0
- package/src/db/handle.js +2 -0
- package/src/db/index.js +6 -0
- package/src/db/ingest.js +153 -0
- package/src/db/open.js +3 -0
- package/src/db/range.js +261 -0
- package/src/db/receipts.js +151 -0
- package/src/db/records.js +61 -0
- package/src/db/runs.js +164 -0
- package/src/db/search.js +86 -0
- package/src/errors.js +3 -1
- package/src/expression.js +5 -2
- package/src/formula/index.js +15 -0
- package/src/model/define.js +2 -0
- package/src/model/entity.js +15 -0
- package/src/project/index.js +6 -5
- package/types/db.d.ts +101 -0
- package/types/formula.d.ts +9 -0
- package/types/index.d.ts +4 -0
- package/types/model.d.ts +18 -0
- package/types/project.d.ts +9 -3
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @jarenjs/linq
|
|
2
2
|
|
|
3
|
+
The pens emit documents; `linq/db` supplies the declared optional database adapter edge. The [combined adoption recipe](../../docs/ADOPTION-EVIDENCE.md) composes mappings, receipts, ingestion and run adapters over one transaction owner, with host and retirement limits visible.
|
|
4
|
+
|
|
3
5
|
**Write it once, in typed JavaScript. Keep it as data.**
|
|
4
6
|
|
|
5
7
|
Every engine in this repository runs a JSON document. The validator runs
|
|
@@ -47,7 +49,7 @@ SQL — and nothing is hidden: the chain's `explain()` shows the document
|
|
|
47
49
|
it sent, and the store's `explain(document)` shows what that became,
|
|
48
50
|
`SELECT … FROM "User" WHERE "age" > ? ORDER BY "name"`.
|
|
49
51
|
|
|
50
|
-
Coverage: <!--fact:coverage.pens-->
|
|
52
|
+
Coverage: <!--fact:coverage.pens-->15 public pen/client subpaths beside the chain; 69/69 owned schema keywords have dedicated emission routes.<!--/fact-->
|
|
51
53
|
|
|
52
54
|
## What you gain
|
|
53
55
|
|
|
@@ -729,6 +731,7 @@ Every subpath a consumer can import, derived from the manifest by
|
|
|
729
731
|
| `@jarenjs/linq/jtlt` | JavaScript | declared |
|
|
730
732
|
| `@jarenjs/linq/messages` | JavaScript | declared |
|
|
731
733
|
| `@jarenjs/linq/ai` | JavaScript | declared |
|
|
734
|
+
| `@jarenjs/linq/formula` | JavaScript | declared |
|
|
732
735
|
<!--/fact-->
|
|
733
736
|
|
|
734
737
|
Explicit cross-provider joins use `federate({ sources, maxRows, maxBytes,
|
|
@@ -737,3 +740,7 @@ including successive fluent `.join()` calls, preserve the engine's result
|
|
|
737
740
|
order while sharing cumulative admission credits. See
|
|
738
741
|
[QUERY-PEN §12.1](docs/QUERY-PEN.md#121-the-federation-boundary-federate) for
|
|
739
742
|
planning, buffering limits and cleanup guarantees.
|
|
743
|
+
|
|
744
|
+
## Saved formula documents
|
|
745
|
+
|
|
746
|
+
`@jarenjs/linq/formula` exports `defineFormula` for immutable JSON Query profiles with revision, bindings and schema/helper references. See [FORMULA-PEN](docs/FORMULA-PEN.md); execution remains in json/formula.
|
package/docs/AI-PEN.md
CHANGED
|
@@ -94,5 +94,5 @@ sub-call budgets, storage and result interpretation remain runner concerns.
|
|
|
94
94
|
|
|
95
95
|
## 7. Cost
|
|
96
96
|
|
|
97
|
-
The isolated AI program pen costs **<!--fact:bundle.ai-->
|
|
97
|
+
The isolated AI program pen costs **<!--fact:bundle.ai-->15,472<!--/fact--> bytes**.
|
|
98
98
|
Its tree probe excludes AI, other target engines and the query chain.
|
package/docs/APP-PEN.md
CHANGED
|
@@ -1123,7 +1123,7 @@ not look for them:
|
|
|
1123
1123
|
|
|
1124
1124
|
## 7. Cost
|
|
1125
1125
|
|
|
1126
|
-
`@jarenjs/linq/app` builds to **<!--fact:bundle.app-->
|
|
1126
|
+
`@jarenjs/linq/app` builds to **<!--fact:bundle.app-->49,574<!--/fact--> bytes** as a minified,
|
|
1127
1127
|
tree-shaken ESM bundle — the figure `scripts/check-tree-shaking.js`
|
|
1128
1128
|
measures and `npm run test:tree-shaking` reports, published rounded
|
|
1129
1129
|
beside the other nine subpath prices in
|
|
@@ -1133,8 +1133,8 @@ pen and the JSLT pen (state, and views), and no chain module, no
|
|
|
1133
1133
|
|
|
1134
1134
|
It is the second-largest pen bundle after the client, and the two pens
|
|
1135
1135
|
it carries are most of it. The three figures the same probe measures,
|
|
1136
|
-
side by side: `@jarenjs/linq/schema` <!--fact:bundle.schema-->
|
|
1137
|
-
`@jarenjs/linq/jslt` <!--fact:bundle.jslt-->
|
|
1136
|
+
side by side: `@jarenjs/linq/schema` <!--fact:bundle.schema-->35,285<!--/fact--> bytes,
|
|
1137
|
+
`@jarenjs/linq/jslt` <!--fact:bundle.jslt-->18,424<!--/fact-->, `@jarenjs/linq/app` <!--fact:bundle.app-->49,574<!--/fact-->. The subpath sums do not add — all
|
|
1138
1138
|
three carry the capture, the expression lowering and the JSON boundary,
|
|
1139
1139
|
which each bundle counts once — so what the app pen costs a consumer who
|
|
1140
1140
|
already imports the schema pen is the difference the numbers do state:
|
package/docs/CHARTS-PEN.md
CHANGED
|
@@ -89,6 +89,6 @@ render tooltips; those responsibilities remain in the chart engine.
|
|
|
89
89
|
|
|
90
90
|
## 7. Cost
|
|
91
91
|
|
|
92
|
-
The isolated chart pen costs **<!--fact:bundle.charts-->
|
|
92
|
+
The isolated chart pen costs **<!--fact:bundle.charts-->15,582<!--/fact--> bytes**.
|
|
93
93
|
The tree-shaking gate refuses chart engine, other target engine and chain
|
|
94
94
|
modules in this bundle, and checks that the chain and schema pen do not import it.
|
package/docs/CONTRACT-PEN.md
CHANGED
|
@@ -1188,10 +1188,10 @@ to write, and reaching them means one import of `@jarenjs/contract` over
|
|
|
1188
1188
|
|
|
1189
1189
|
## 7. Cost
|
|
1190
1190
|
|
|
1191
|
-
`@jarenjs/linq/contract` builds to **<!--fact:bundle.contract-->
|
|
1191
|
+
`@jarenjs/linq/contract` builds to **<!--fact:bundle.contract-->47,427<!--/fact--> bytes** as a minified,
|
|
1192
1192
|
tree-shaken ESM bundle — the figure `scripts/check-tree-shaking.js`
|
|
1193
1193
|
measures and `npm run test:tree-shaking` reports, published rounded
|
|
1194
|
-
(<!--fact:bundle.contract.kb-->
|
|
1194
|
+
(<!--fact:bundle.contract.kb-->47<!--/fact--> kB) beside the other nine subpath prices in
|
|
1195
1195
|
[docs/CONSUMING.md](../../../docs/CONSUMING.md).
|
|
1196
1196
|
|
|
1197
1197
|
The probe is a gate, not a report: building a one-operation contract as a
|
|
@@ -1200,7 +1200,7 @@ them:
|
|
|
1200
1200
|
|
|
1201
1201
|
- **the schema pen is included, and that is the ceiling.** A contract's
|
|
1202
1202
|
inputs and outputs are schemas, so the two are measured together and
|
|
1203
|
-
the bundle carries <!--fact:bundle.schema-->
|
|
1203
|
+
the bundle carries <!--fact:bundle.schema-->35,285<!--/fact--> of its <!--fact:bundle.contract-->47,427<!--/fact--> bytes as the schema pen's own.
|
|
1204
1204
|
The contract pen's own share is the remaining ~12 kB, most of it the
|
|
1205
1205
|
refusal messages §4 lists;
|
|
1206
1206
|
- **no chain module** — none of `sequence.js`, `document.js`, `async.js`,
|
|
@@ -1216,6 +1216,6 @@ them:
|
|
|
1216
1216
|
A consumer who writes a contract and also compiles it pays both prices
|
|
1217
1217
|
and they add rather than overlap. That is the shape the separation is
|
|
1218
1218
|
for: a browser bundle that only needs the TYPES a contract implies —
|
|
1219
|
-
`typedClient` over an HTTP binding, say — ships the pen's <!--fact:bundle.contract.kb-->
|
|
1219
|
+
`typedClient` over an HTTP binding, say — ships the pen's <!--fact:bundle.contract.kb-->47<!--/fact--> kB and none
|
|
1220
1220
|
of the compiler, while the server that serves the contract imports
|
|
1221
1221
|
`@jarenjs/contract` and does not need the pen at all.
|
package/docs/DB-CLIENT.md
CHANGED
|
@@ -115,6 +115,11 @@ back, the durable ledger over what it opened, and replication document authoring
|
|
|
115
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
|
+
| `createDbReceipts(client, options)` | permanent receipts and independent fenced leases; see durable mapped records | structural receipt repository |
|
|
119
|
+
| `createDbEffectStore(client, options)` | reviewed external intent and reconciliation under job fences | structural effect store |
|
|
120
|
+
| `createDbRunStore(client, options)` | mapped workflow checkpoints and bounded revision event pages | structural run store |
|
|
121
|
+
| `createDbIngestionStore(client, options)` | atomic page/checkpoint staging and complete snapshot publication; see [complete ingestion store](DB-CLIENT.md#complete-ingestion-store) | structural ingestion store |
|
|
122
|
+
| `createDbRangeProvider(store, entity, spec, options)` | a bounded structural range source over keyset pages and committed capture; also `handle.range(spec, options)` — [COLLECTION-PROVIDER.md](../../app/docs/COLLECTION-PROVIDER.md) | `Promise<DbRangeProvider>` |
|
|
118
123
|
|
|
119
124
|
`open` is the only door, and it is deliberately not a coded refusal: a
|
|
120
125
|
missing `options`, or a `validator` that is not a `JarenValidator`, is a
|
|
@@ -128,18 +133,18 @@ reconstruct the configuration by reading this paragraph.
|
|
|
128
133
|
|
|
129
134
|
### 2.3 The entity handle
|
|
130
135
|
|
|
131
|
-
A handle
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
A handle has no Proxy. It combines the store's entity set, the asynchronous
|
|
137
|
+
chain, and the client's graph, live and range adapters. `explain` is shared
|
|
138
|
+
and resolved below.
|
|
134
139
|
|
|
135
140
|
| Group | Members |
|
|
136
141
|
|---|---|
|
|
137
|
-
| the unit of work | `create` `get` `update` `delete` `add` `put` `remove` `discard` `asNoTracking` |
|
|
142
|
+
| the unit of work | `create` `get` `update` `delete` `add` `put` `remove` `discard` `asNoTracking`; `mutate` executes an untracked [native column mutation](../../db/docs/NATIVE-PLANS.md) |
|
|
138
143
|
| the store's reads | `load` `explainLoad` `execute` |
|
|
139
144
|
| the provider seam | `root` `scope` `relations` |
|
|
140
145
|
| membership | `link` `unlink` — the store's, behind §4.2's check |
|
|
141
146
|
| the chain | every `AsyncSequence` operator and terminal: `where` `select` `selectMany` `orderBy` `orderByDescending` `thenBy` `thenByDescending` `groupBy` `aggregate` `join` `groupJoin` `skip` `take` `distinct` `reverse` `concat` `defaultIfEmpty` `ofType` `cast` `zip` `mapAsync` `params` `toDocument` `toArray` `first` `firstOrDefault` `single` `singleOrDefault` `last` `lastOrDefault` `elementAt` `elementAtOrDefault` `count` `sum` `average` `min` `max` `any` `all`, and `Symbol.asyncIterator` |
|
|
142
|
-
| the client's own | `include` (§2.4) and `
|
|
147
|
+
| the client's own | `include` (§2.4), `live`, and `range(spec, options)` |
|
|
143
148
|
| in both | `explain` |
|
|
144
149
|
|
|
145
150
|
**`explain` is the one name the store's set and the chain both carry, and
|
|
@@ -309,6 +314,18 @@ See the [replication format](../../db/docs/REPLICATION-FORMAT.md) for causality,
|
|
|
309
314
|
conflict policy and bounded reset contracts. Authoring does not allocate a
|
|
310
315
|
committed sequence; normal replication exports the Store's committed pages.
|
|
311
316
|
|
|
317
|
+
### Lexical ranges
|
|
318
|
+
|
|
319
|
+
`createLexicalRangeProvider(source, text, request, options)` composes a
|
|
320
|
+
`createDbSearch` source from `@jarenjs/db/search` with the shared structural range
|
|
321
|
+
implementation. `maxMatches` and `maxSourceBytes` cap complete source membership;
|
|
322
|
+
`maxRows`, `maxBytes`, `maxPages` and `maxInFlight` cap range work and retained pages.
|
|
323
|
+
A truncated search refuses rather than presenting incomplete membership as a
|
|
324
|
+
complete collection. Filters/facets/order use the query provider's one meaning.
|
|
325
|
+
Source resets invalidate requests; `refresh()` rebuilds the bounded range under
|
|
326
|
+
the new source revision. Disposal drains the range and unsubscribes; set
|
|
327
|
+
`disposeSource` when the range also owns its source.
|
|
328
|
+
|
|
312
329
|
## 3. Worked examples
|
|
313
330
|
|
|
314
331
|
The client's examples are not builder-to-document pairs, and this is
|
|
@@ -826,10 +843,10 @@ never builds one; the migration between two of them is
|
|
|
826
843
|
|
|
827
844
|
## 7. Cost
|
|
828
845
|
|
|
829
|
-
`@jarenjs/linq/db` builds to **<!--fact:bundle.db-->
|
|
846
|
+
`@jarenjs/linq/db` builds to **<!--fact:bundle.db-->675,752<!--/fact--> bytes** as a minified,
|
|
830
847
|
tree-shaken ESM bundle — the figure `scripts/check-tree-shaking.js`
|
|
831
848
|
measures and `npm run test:tree-shaking` reports, published rounded
|
|
832
|
-
(<!--fact:bundle.db.kb-->
|
|
849
|
+
(<!--fact:bundle.db.kb-->676<!--/fact--> kB) beside the other nine subpath prices in
|
|
833
850
|
[docs/CONSUMING.md](../../../docs/CONSUMING.md).
|
|
834
851
|
|
|
835
852
|
It is by far the largest of the ten, and the reason is §1.1's edge rather
|
|
@@ -840,6 +857,10 @@ planner, a unit of work, a live-maintenance engine and a JSON Schema
|
|
|
840
857
|
validator, and the honest way to read the figure is as the price of the
|
|
841
858
|
database, not of the front door.
|
|
842
859
|
|
|
860
|
+
Explicit physical codecs, catalog verification, invariant lowering and guarded
|
|
861
|
+
SQL also ride with the store. Their measured cost is included in this figure;
|
|
862
|
+
the structural bundle ceiling is 665 kB. The frozen consumer budgets are unchanged.
|
|
863
|
+
|
|
843
864
|
What the probe asserts, and fails the build on:
|
|
844
865
|
|
|
845
866
|
- **all three peers ride** — `@jarenjs/db`, `@jarenjs/validate` and
|
|
@@ -856,7 +877,7 @@ What the probe asserts, and fails the build on:
|
|
|
856
877
|
asserts the same exclusion.
|
|
857
878
|
|
|
858
879
|
A consumer who wants the model pen's types without the store pays
|
|
859
|
-
`./model`'s <!--fact:bundle.model-->
|
|
880
|
+
`./model`'s <!--fact:bundle.model-->44,143<!--/fact--> bytes and installs no peer; one who wants to run
|
|
860
881
|
queries against an array rather than a database pays the chain's price
|
|
861
882
|
(§17 of [QUERY-PEN.md](QUERY-PEN.md)) and installs no peer. `./db` is
|
|
862
883
|
the one subpath whose `package.json` entry carries an optional peer at
|
|
@@ -891,3 +912,174 @@ survives is structural, not temporal** — the graph load's statement
|
|
|
891
912
|
counts are printed beside its timings, and the client answers a
|
|
892
913
|
two-level graph in ONE statement where the schema-first ORM takes three,
|
|
893
914
|
whatever the corpus and whatever the clock says.
|
|
915
|
+
|
|
916
|
+
## Trusted SQL during adoption
|
|
917
|
+
|
|
918
|
+
`open()` forwards `adopt: true` and physical model declarations to the store.
|
|
919
|
+
A transaction client exposes `tx.sql`, `tx.jobs`, and the store's optional
|
|
920
|
+
`tx.sync` surface. `tx.sql.prepare(text, { access: 'read' | 'write', affects? })`
|
|
921
|
+
returns `run(params)`, `get(params)`, `all(params)` and `close()`. Parameters are
|
|
922
|
+
positional arrays. These methods answer values on synchronous hosts and promises
|
|
923
|
+
on asynchronous hosts. Always await asynchronous operations inside the callback;
|
|
924
|
+
statement preparation rechecks scope ownership before execution, so a late
|
|
925
|
+
preparation cannot write after settlement.
|
|
926
|
+
|
|
927
|
+
```js
|
|
928
|
+
await client.transaction(async tx => {
|
|
929
|
+
const insert = tx.sql.prepare('INSERT INTO legacy_note(body) VALUES (?)',
|
|
930
|
+
{ access: 'write' });
|
|
931
|
+
await insert.run(['reviewed']);
|
|
932
|
+
await tx.entities.Setting.update('locale', { value: 'nl-NL' });
|
|
933
|
+
await tx.jobs.enqueue('publish', { key: 'locale' });
|
|
934
|
+
insert.close();
|
|
935
|
+
}, { mode: 'immediate' });
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
The SQL capability accepts trusted application statements with explicit access.
|
|
939
|
+
It refuses multiple statements, transaction control, schema changes and connection
|
|
940
|
+
configuration. A retained statement or continuation refuses after scope settlement
|
|
941
|
+
or while a nested scope owns the connection. Closing a statement invalidates its
|
|
942
|
+
public handle; underlying cached/native storage belongs to the connection.
|
|
943
|
+
|
|
944
|
+
SQL writes conservatively invalidate clean tracked entities, including effects of
|
|
945
|
+
unknown triggers/cascades. Pending tracked changes must first be saved or discarded.
|
|
946
|
+
The optional `affects` declaration does not narrow this conservative policy.
|
|
947
|
+
SQL writes refuse capture/replication and store-only invariant configurations whose
|
|
948
|
+
coverage they cannot honor. This capability is not an untrusted-SQL sandbox;
|
|
949
|
+
application-supplied SQL and host functions remain trusted.
|
|
950
|
+
|
|
951
|
+
`store.sync.transaction(fn, { mode: 'immediate' })` uses the same writer and
|
|
952
|
+
savepoint owner. It rejects thenables and invalidates post-return work. Async-only
|
|
953
|
+
hosts have no synchronous transaction surface. The outbox infrastructure must
|
|
954
|
+
already have been provisioned through an explicit setup/migration before a
|
|
955
|
+
no-DDL adoption; opening with jobs enabled is a separate infrastructure operation.
|
|
956
|
+
|
|
957
|
+
## Complete ingestion store
|
|
958
|
+
|
|
959
|
+
`createDbIngestionStore(client,{staging,checkpoints,publications,facts?,reconcile?})`
|
|
960
|
+
uses application-declared document collections through the root or transaction
|
|
961
|
+
client. Collection names must be distinct. The root adapter opens an immediate
|
|
962
|
+
transaction; a transaction adapter nests under that owner. It introduces no
|
|
963
|
+
second ledger, transaction engine or fixed provider schema.
|
|
964
|
+
|
|
965
|
+
```js
|
|
966
|
+
import { open, createDbIngestionStore } from '@jarenjs/linq/db';
|
|
967
|
+
import { nodeDriver } from '@jarenjs/db/node';
|
|
968
|
+
|
|
969
|
+
const model = { $model: '0.1', collections: Object.fromEntries(
|
|
970
|
+
['observations', 'pulls', 'snapshots', 'facts'].map((name) => [name, {
|
|
971
|
+
key: '/id', schema: { type: 'object' }, indexes: [],
|
|
972
|
+
}]),
|
|
973
|
+
) };
|
|
974
|
+
const client = await open(model, { driver: nodeDriver(), path: 'ingestion.db' });
|
|
975
|
+
const store = createDbIngestionStore(client, {
|
|
976
|
+
staging: 'observations', checkpoints: 'pulls', publications: 'snapshots', facts: 'facts',
|
|
977
|
+
reconcile: (existing, incoming) => existing?.provenance === 'manual' ? existing : incoming,
|
|
978
|
+
});
|
|
979
|
+
// Pass store to createIngestion; close client after ingestion and workers drain.
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
`begin(plan)` creates or resumes a generation, or returns `unchanged` when the
|
|
983
|
+
current published fingerprint matches. A fingerprint includes source version,
|
|
984
|
+
partitions, input, policy revision and consistency. Generations cannot be reused
|
|
985
|
+
with a changed plan. `stage(plan,partition,page)` commits exact raw page text,
|
|
986
|
+
parsed/transformed observations and continuation/completion evidence together.
|
|
987
|
+
An identical repeated page does no work; a conflicting page or stale cursor is
|
|
988
|
+
refused. `inspect(plan)` returns the checkpoint and retained observations.
|
|
989
|
+
`invalidate` preserves them while fencing the generation from publication.
|
|
990
|
+
|
|
991
|
+
`publish(plan,evidence)` requires completed coverage of every requested
|
|
992
|
+
partition, matching source evidence and the publication generation observed at
|
|
993
|
+
begin. Concurrent stale publication is refused. The pointer, completion record
|
|
994
|
+
and any reconciled facts commit together. If reconciliation or persistence
|
|
995
|
+
fails, all those changes roll back while staging remains available for recovery.
|
|
996
|
+
`current(source)` reads the published pointer and its completion evidence.
|
|
997
|
+
|
|
998
|
+
Facts use the collision-free JSON tuple `[source,partition,providerId]`; strings
|
|
999
|
+
retain leading zeros. `reconcile(existingValue,incomingRow,evidence)` is a pure
|
|
1000
|
+
synchronous policy and defaults to the incoming row. It must explicitly preserve
|
|
1001
|
+
manual provenance when required. Equal values do not write or increment the
|
|
1002
|
+
fact's revision. Reported `changes`, `writes` and `revisions` count effective
|
|
1003
|
+
fact changes; staging/checkpoint/manifest metadata is separate. An identical
|
|
1004
|
+
published pull performs no metadata writes either. A new policy or source
|
|
1005
|
+
version can publish a new manifest with zero fact changes.
|
|
1006
|
+
|
|
1007
|
+
The complete pointer defines source membership. The facts collection is a
|
|
1008
|
+
reconciled history of observed identities; missing identities are not implicitly
|
|
1009
|
+
deleted. Applications own retirement of absent facts, staging retention and
|
|
1010
|
+
business-history policy. Without `facts`, only raw staging and publication are
|
|
1011
|
+
maintained. No provider schema, receipt TTL or manual-edit rule is inferred.
|
|
1012
|
+
|
|
1013
|
+
## Durable mapped records
|
|
1014
|
+
|
|
1015
|
+
`createDbReceipts`, `createDbEffectStore` and `createDbRunStore` from
|
|
1016
|
+
`@jarenjs/linq/db` adapt application-declared collections or entities. Each record option
|
|
1017
|
+
accepts its name, `{ collection, read, write }` or `{ entity, read, write, key? }`:
|
|
1018
|
+
synchronous, lossless mappings
|
|
1019
|
+
between application fields and canonical records with an `id`. The optional
|
|
1020
|
+
`key(id)` maps canonical identity to the declared physical key, including a
|
|
1021
|
+
composite key object. Entity writes use the existing direct create/update/delete
|
|
1022
|
+
API, read back the persisted result, and refuse lost identity before commit. A failed
|
|
1023
|
+
round-trip or changed identity refuses `JL2009`. Physical tables and column names
|
|
1024
|
+
remain the model's declarations; no adapter creates a second authoritative
|
|
1025
|
+
business ledger. Root operations use immediate transactions; transaction-client
|
|
1026
|
+
adapters use the caller's savepoint and commit with that caller.
|
|
1027
|
+
|
|
1028
|
+
`createDbReceipts(client, { receipts, leases?, runtime? })` stores permanent
|
|
1029
|
+
command identity, validated outcome, stable references and creation/revision
|
|
1030
|
+
metadata. Its trusted-host methods are `lookup`, `execute`, `claim`, `release`,
|
|
1031
|
+
`sweep`, `migrate` and `compact`. Authorization belongs to the command layer.
|
|
1032
|
+
Claim leases are independent execution capabilities: expiry/recovery replaces
|
|
1033
|
+
the token, while receipt lookup always wins before admitting any work. A hash
|
|
1034
|
+
or hash-version collision refuses; receipts never expire. Sweep accepts at most
|
|
1035
|
+
1000 selected identities and deletes only expired leases. It never interprets
|
|
1036
|
+
replication acknowledgement as retention permission.
|
|
1037
|
+
|
|
1038
|
+
Migration takes at most 1000 explicit receipt outcomes with references. It
|
|
1039
|
+
preserves originals and later receipts; a conflicting identity/outcome/reference
|
|
1040
|
+
refuses the whole batch. Repeating it reports zero changes, writes and revisions,
|
|
1041
|
+
including after compaction/restart. Expired HTTP claims cannot be imported as
|
|
1042
|
+
business outcomes implicitly. Compaction requires `retainReplay: true`,
|
|
1043
|
+
`retainReferences: true`, `actor` and `reason`; it removes only auxiliary data,
|
|
1044
|
+
keeps collision identity/outcome/references, and becomes a zero-write no-op on
|
|
1045
|
+
repeat. Erasure is unsupported and refused.
|
|
1046
|
+
|
|
1047
|
+
`createDbEffectStore(client, { operations, maxLegs?, maxBytes? })` provides
|
|
1048
|
+
`prepare`, `get`, `begin`, `settle`, `recover` and `reconcile`. A reviewed plan
|
|
1049
|
+
contains `id`, `jobId`, `kind`, `actor`, `reason`, `hashVersion` and bounded `legs`.
|
|
1050
|
+
Each leg names `id`, a provider `request` and `maxAttempts`; arbitrary reviewed
|
|
1051
|
+
selection/payload declarations stay in the frozen plan. Preparation plus its
|
|
1052
|
+
optional local callback and enqueue co-commit. Repeated preparation is a no-op;
|
|
1053
|
+
changed reviewed bytes refuse. Each sending/settlement operation compares the
|
|
1054
|
+
operation revision and uses `tx.jobs.assertLease` against the plan's job ID.
|
|
1055
|
+
Remote I/O occurs outside these transactions. Confirmed/rejected/unresolved
|
|
1056
|
+
states and individual leg attempts survive lease takeover.
|
|
1057
|
+
|
|
1058
|
+
Reconciliation requires a unique decision `id`, `actor`, `reason`, `action`
|
|
1059
|
+
(`confirm`, `reject`, `retry`) and public `evidence`. Repeating identical evidence
|
|
1060
|
+
is a zero-write/revision no-op; a reused decision ID with different evidence
|
|
1061
|
+
refuses. Idempotent retries preserve the provider key and original attempt
|
|
1062
|
+
budget. Absence without an authoritative non-application guarantee is not retry
|
|
1063
|
+
permission. A single-send leg remains limited to one attempt; a proven negative
|
|
1064
|
+
may be rejected and followed by a separately reviewed operation. Compensation
|
|
1065
|
+
requires a separate plan with `compensationOf`, `compensationAuthorized: true`
|
|
1066
|
+
and its own authorized actor/reason. The trusted host must establish that
|
|
1067
|
+
permission; the boolean is recorded evidence, not authentication.
|
|
1068
|
+
|
|
1069
|
+
`createDbRunStore(client, { runs, events, statuses?, summary?, canReset?,
|
|
1070
|
+
maxPage?, maxBytes? })` attaches existing IDs and status vocabularies to workflow
|
|
1071
|
+
checkpoints. `attach` verifies workflow/schema/job identity, `load` checks it
|
|
1072
|
+
before reading a checkpoint, and `save` combines workflow generation CAS, the
|
|
1073
|
+
job fence, mapped status, summary and event in one transaction. The application
|
|
1074
|
+
`summary(snapshot)` projects only public JSON. Default summaries contain status
|
|
1075
|
+
and generation, not inputs or results. `get` is trusted/private;
|
|
1076
|
+
`page(id, { after, limit })` exposes bounded public events and current summary.
|
|
1077
|
+
Missing event history returns `reset-required` with the current durable cursor.
|
|
1078
|
+
|
|
1079
|
+
`requestCancel` compares the observed revision and records actor/reason;
|
|
1080
|
+
`finish` persists a final cancelled/failed observation after draining.
|
|
1081
|
+
`reset` changes only this run's checkpoint and requires current revision,
|
|
1082
|
+
inactive status, actor/reason and a transactional `canReset(tx, record)` policy.
|
|
1083
|
+
The default refuses; the policy must consult receipts and unresolved effects.
|
|
1084
|
+
Reset never deletes those tables. Incompatible workflow/schema identities refuse;
|
|
1085
|
+
a host must perform an explicitly reviewed migration before attachment.
|
package/docs/FLOW-PEN.md
CHANGED
|
@@ -985,10 +985,10 @@ meaning is a `$return` that constructs an array explicitly.
|
|
|
985
985
|
|
|
986
986
|
## 7. Cost
|
|
987
987
|
|
|
988
|
-
`@jarenjs/linq/flow` builds to **<!--fact:bundle.flow-->
|
|
988
|
+
`@jarenjs/linq/flow` builds to **<!--fact:bundle.flow-->18,478<!--/fact--> bytes** as a minified,
|
|
989
989
|
tree-shaken ESM bundle — the figure `scripts/check-tree-shaking.js`
|
|
990
990
|
measures and `npm run test:tree-shaking` reports, published rounded
|
|
991
|
-
(<!--fact:bundle.flow.kb-->
|
|
991
|
+
(<!--fact:bundle.flow.kb-->18<!--/fact--> kB) beside the other nine subpath prices in
|
|
992
992
|
[docs/CONSUMING.md](../../../docs/CONSUMING.md).
|
|
993
993
|
|
|
994
994
|
The probe is a gate, not a report. Building a machine with a guard and
|
|
@@ -1015,7 +1015,7 @@ two effects as a consumer would — `defineFsm`, `state`, `on` and
|
|
|
1015
1015
|
`packages/linq/src/flow/`.
|
|
1016
1016
|
|
|
1017
1017
|
Two documents, two grammars, thirteen exported names — and 57 bytes more
|
|
1018
|
-
than `./jslt`'s <!--fact:bundle.jslt-->
|
|
1018
|
+
than `./jslt`'s <!--fact:bundle.jslt-->18,424<!--/fact-->, which writes one. The reason is that most of
|
|
1019
1019
|
both prices is the same shared machinery: the recording proxy
|
|
1020
1020
|
(`expression.js`), the root capture (`capture-root.js`) and the JSON
|
|
1021
1021
|
boundary (`json-boundary.js`). What this pen adds on top of them is 685
|
package/docs/FORMS-PEN.md
CHANGED
|
@@ -925,7 +925,7 @@ for this pen at all.
|
|
|
925
925
|
|
|
926
926
|
## 7. Cost
|
|
927
927
|
|
|
928
|
-
`@jarenjs/linq/forms` builds to **<!--fact:bundle.forms-->
|
|
928
|
+
`@jarenjs/linq/forms` builds to **<!--fact:bundle.forms-->39,441<!--/fact--> bytes** as a minified,
|
|
929
929
|
tree-shaken ESM bundle — the figure `scripts/check-tree-shaking.js`
|
|
930
930
|
measures and `npm run test:tree-shaking` reports, published rounded
|
|
931
931
|
beside the other nine subpath prices in
|
|
@@ -934,7 +934,7 @@ pen it subclasses, and no chain module, no `@jarenjs/forms` byte and no
|
|
|
934
934
|
model pen.
|
|
935
935
|
|
|
936
936
|
Most of that figure is the schema pen: `@jarenjs/linq/schema` alone
|
|
937
|
-
is <!--fact:bundle.schema-->
|
|
937
|
+
is <!--fact:bundle.schema-->35,285<!--/fact--> bytes, so the whole `x-form` vocabulary — the mixin, the rule
|
|
938
938
|
capture, the submit transform and their refusal messages — is about 4 kB
|
|
939
939
|
on top of a pen a form-shaped consumer usually already carries. A
|
|
940
940
|
consumer importing both subpaths pays the schema pen once.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Formula document authoring
|
|
2
|
+
|
|
3
|
+
> `./formula` — author versioned saved JSON Query profiles without executing them.
|
|
4
|
+
|
|
5
|
+
## 1. What it writes
|
|
6
|
+
|
|
7
|
+
`defineFormula(id, expression, options?)` from `@jarenjs/linq/formula` emits a frozen
|
|
8
|
+
`$formula: "1"` JSON document. The default revision is `"1"`. Options declare
|
|
9
|
+
revision, immutable bindings, input/result schema references, helper versions and
|
|
10
|
+
result mode. The expression is an existing JSON Query document. The pen validates
|
|
11
|
+
the envelope and JSON boundary without executing a formula or importing a component.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { defineFormula } from '@jarenjs/linq/formula';
|
|
15
|
+
const amount = defineFormula('amount', { $mul: ['$.price', '$.quantity'] }, {
|
|
16
|
+
revision: '2',
|
|
17
|
+
inputSchema: { id: 'row', version: '1' },
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Compile the document using `@jarenjs/json/formula` and a host schema registry/type
|
|
22
|
+
compiler. [The formula format](../../json/docs/FORMULA-FORMAT.md) owns execution,
|
|
23
|
+
missing/null arithmetic, explicit migration and reviewed-plan semantics.
|
|
24
|
+
|
|
25
|
+
## 2. The mapping table
|
|
26
|
+
|
|
27
|
+
| Call / option | Emitted member |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `defineFormula(id, expression)` | `$formula`, `id`, `expression`, default `revision` |
|
|
30
|
+
| `revision`, `bindings`, schema/helper references, result mode | Same named profile members |
|
|
31
|
+
|
|
32
|
+
## 3. Refusals
|
|
33
|
+
|
|
34
|
+
Non-JSON authoring input is `JL0101`; invalid envelopes and unresolved runtime
|
|
35
|
+
capabilities use the owning JSON formula registry. The pen never executes a query.
|
|
36
|
+
|
|
37
|
+
## 4. Cost
|
|
38
|
+
|
|
39
|
+
The isolated formula pen costs **<!--fact:bundle.formula-->14,850<!--/fact--> bytes**.
|
|
40
|
+
Its bundle contains envelope validation and JSON helpers, with no Query evaluator
|
|
41
|
+
or component. The tree-shaking gate enforces the separate authoring boundary.
|
package/docs/JSLT-PEN.md
CHANGED
|
@@ -919,10 +919,10 @@ non-judgement is itself gated.
|
|
|
919
919
|
|
|
920
920
|
## 7. Cost
|
|
921
921
|
|
|
922
|
-
`@jarenjs/linq/jslt` builds to **<!--fact:bundle.jslt-->
|
|
922
|
+
`@jarenjs/linq/jslt` builds to **<!--fact:bundle.jslt-->18,424<!--/fact--> bytes** as a minified,
|
|
923
923
|
tree-shaken ESM bundle — the figure `scripts/check-tree-shaking.js`
|
|
924
924
|
measures and `npm run test:tree-shaking` reports, published rounded
|
|
925
|
-
(<!--fact:bundle.jslt.kb-->
|
|
925
|
+
(<!--fact:bundle.jslt.kb-->18<!--/fact--> kB) beside the other nine subpath prices in
|
|
926
926
|
[docs/CONSUMING.md](../../../docs/CONSUMING.md).
|
|
927
927
|
|
|
928
928
|
The probe is a gate, not a report. Building a stylesheet as a consumer
|
|
@@ -948,8 +948,8 @@ source. That makes it the SMALLEST of the nine pen bundles, and the
|
|
|
948
948
|
reason is that a stylesheet is mostly bodies, and a body is the shared
|
|
949
949
|
machine every pen already pays for.
|
|
950
950
|
|
|
951
|
-
Two figures worth reading beside it: `./migration` (<!--fact:bundle.migration-->
|
|
951
|
+
Two figures worth reading beside it: `./migration` (<!--fact:bundle.migration-->22,827<!--/fact--> bytes)
|
|
952
952
|
carries this pen's `body()` and pays for it, which is why the two prices
|
|
953
|
-
sit so close; and `./flow` (<!--fact:bundle.flow-->
|
|
953
|
+
sit so close; and `./flow` (<!--fact:bundle.flow-->18,478<!--/fact--> bytes) is within 60 bytes of this one
|
|
954
954
|
despite writing two formats, because it shares the same capture and adds
|
|
955
955
|
almost nothing but member checks and their messages.
|
package/docs/JTLT-PEN.md
CHANGED
|
@@ -79,5 +79,5 @@ validate XML well-formedness, render text, or add a second dispatch language.
|
|
|
79
79
|
|
|
80
80
|
## 7. Cost
|
|
81
81
|
|
|
82
|
-
The isolated JTLT pen costs **<!--fact:bundle.jtlt-->
|
|
82
|
+
The isolated JTLT pen costs **<!--fact:bundle.jtlt-->15,293<!--/fact--> bytes**.
|
|
83
83
|
Its tree probe excludes target engines and the query chain.
|