litedbmodel 2.2.2 → 2.2.4
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 +2 -1
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +3 -0
- package/dist/DBModel.js.map +1 -1
- package/dist/Middleware.d.ts +19 -2
- package/dist/Middleware.d.ts.map +1 -1
- package/dist/Middleware.js +1 -0
- package/dist/Middleware.js.map +1 -1
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +8 -0
- package/dist/decorators.js.map +1 -1
- package/dist/drivers/MysqlHelper.d.ts +1 -1
- package/dist/drivers/MysqlHelper.d.ts.map +1 -1
- package/dist/drivers/MysqlHelper.js.map +1 -1
- package/dist/drivers/PostgresHelper.d.ts +1 -1
- package/dist/drivers/PostgresHelper.d.ts.map +1 -1
- package/dist/drivers/PostgresHelper.js.map +1 -1
- package/dist/drivers/SqliteHelper.d.ts +1 -1
- package/dist/drivers/SqliteHelper.d.ts.map +1 -1
- package/dist/drivers/SqliteHelper.js.map +1 -1
- package/dist/index.cjs +105 -74
- package/dist/scp/connection-routing.d.ts +38 -1
- package/dist/scp/connection-routing.d.ts.map +1 -1
- package/dist/scp/connection-routing.js +64 -5
- package/dist/scp/connection-routing.js.map +1 -1
- package/dist/scp/dbmodel-runtime.d.ts +2 -1
- package/dist/scp/dbmodel-runtime.d.ts.map +1 -1
- package/dist/scp/dbmodel-runtime.js +2 -1
- package/dist/scp/dbmodel-runtime.js.map +1 -1
- package/dist/scp/decorator-adapter.d.ts +22 -0
- package/dist/scp/decorator-adapter.d.ts.map +1 -1
- package/dist/scp/decorator-adapter.js +26 -0
- package/dist/scp/decorator-adapter.js.map +1 -1
- package/dist/scp/emit/emitter.d.ts +21 -10
- package/dist/scp/emit/emitter.d.ts.map +1 -1
- package/dist/scp/emit/emitter.js +119 -51
- package/dist/scp/emit/emitter.js.map +1 -1
- package/dist/scp/emit/endpoint.d.ts +3 -8
- package/dist/scp/emit/endpoint.d.ts.map +1 -1
- package/dist/scp/exec-context.d.ts +39 -17
- package/dist/scp/exec-context.d.ts.map +1 -1
- package/dist/scp/exec-context.js +69 -35
- package/dist/scp/exec-context.js.map +1 -1
- package/dist/scp/grouping.d.ts.map +1 -1
- package/dist/scp/grouping.js +0 -0
- package/dist/scp/grouping.js.map +1 -1
- package/dist/scp/index.cjs +257 -670
- package/dist/scp/index.d.ts +6 -11
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +10 -28
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +257 -658
- package/dist/scp/leaf-transport.d.ts +127 -39
- package/dist/scp/leaf-transport.d.ts.map +1 -1
- package/dist/scp/leaf-transport.js +30 -24
- package/dist/scp/leaf-transport.js.map +1 -1
- package/dist/scp/leaves.d.ts +57 -20
- package/dist/scp/leaves.d.ts.map +1 -1
- package/dist/scp/leaves.js +224 -65
- package/dist/scp/leaves.js.map +1 -1
- package/dist/scp/makesql/compile-select.d.ts +28 -1
- package/dist/scp/makesql/compile-select.d.ts.map +1 -1
- package/dist/scp/makesql/compile-select.js +19 -17
- package/dist/scp/makesql/compile-select.js.map +1 -1
- package/dist/scp/makesql/index.d.ts +2 -2
- package/dist/scp/makesql/index.d.ts.map +1 -1
- package/dist/scp/makesql/index.js +4 -6
- package/dist/scp/makesql/index.js.map +1 -1
- package/dist/scp/makesql/tx.d.ts +43 -89
- package/dist/scp/makesql/tx.d.ts.map +1 -1
- package/dist/scp/makesql/tx.js +45 -496
- package/dist/scp/makesql/tx.js.map +1 -1
- package/dist/scp/makesql/writeouttype.d.ts +5 -7
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
- package/dist/scp/makesql/writeouttype.js +13 -19
- package/dist/scp/makesql/writeouttype.js.map +1 -1
- package/dist/scp/middleware.d.ts +4 -4
- package/dist/scp/middleware.d.ts.map +1 -1
- package/dist/scp/middleware.js +2 -2
- package/dist/scp/middleware.js.map +1 -1
- package/dist/scp/relation.d.ts +31 -12
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +16 -6
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/typed-object.d.ts +23 -19
- package/dist/scp/typed-object.d.ts.map +1 -1
- package/dist/scp/typed-object.js +24 -30
- package/dist/scp/typed-object.js.map +1 -1
- package/dist/scp/write-bundle.d.ts +21 -70
- package/dist/scp/write-bundle.d.ts.map +1 -1
- package/dist/scp/write-bundle.js +16 -80
- package/dist/scp/write-bundle.js.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/docs/BENCHMARK.md +26 -22
- package/docs/COMPARISON.md +8 -4
- package/docs/api/README.md +1 -1
- package/docs/api/classes/Conditions.md +10 -10
- package/docs/api/classes/DBHandler.md +17 -17
- package/docs/api/classes/DBModel.md +111 -104
- package/docs/api/classes/LimitExceededError.md +8 -8
- package/docs/api/classes/Middleware.md +18 -18
- package/docs/api/classes/SqlRaw.md +6 -6
- package/docs/api/classes/SqlRef.md +7 -7
- package/docs/api/classes/Values.md +6 -6
- package/docs/api/classes/WriteInReadOnlyContextError.md +5 -5
- package/docs/api/classes/WriteOutsideTransactionError.md +5 -5
- package/docs/api/functions/belongsTo.md +2 -2
- package/docs/api/functions/closeAllPools.md +2 -2
- package/docs/api/functions/condsToRecord.md +2 -2
- package/docs/api/functions/createMiddleware.md +2 -2
- package/docs/api/functions/createPostgresDriver.md +2 -2
- package/docs/api/functions/createSqliteDriver.md +2 -2
- package/docs/api/functions/dbCast.md +3 -3
- package/docs/api/functions/dbCastIn.md +2 -2
- package/docs/api/functions/dbDynamic.md +3 -3
- package/docs/api/functions/dbFalse.md +2 -2
- package/docs/api/functions/dbImmediate.md +2 -2
- package/docs/api/functions/dbIn.md +2 -2
- package/docs/api/functions/dbNotNull.md +2 -2
- package/docs/api/functions/dbNow.md +2 -2
- package/docs/api/functions/dbNull.md +2 -2
- package/docs/api/functions/dbRaw.md +2 -2
- package/docs/api/functions/dbTrue.md +2 -2
- package/docs/api/functions/dbUuid.md +3 -3
- package/docs/api/functions/dbUuidIn.md +2 -2
- package/docs/api/functions/formatLocalDate.md +25 -0
- package/docs/api/functions/formatUTCDate.md +25 -0
- package/docs/api/functions/getDBConfig.md +2 -2
- package/docs/api/functions/getDBHandler.md +2 -2
- package/docs/api/functions/getTransactionConnection.md +2 -2
- package/docs/api/functions/getTransactionContext.md +2 -2
- package/docs/api/functions/hasMany.md +2 -2
- package/docs/api/functions/hasOne.md +2 -2
- package/docs/api/functions/initDBHandler.md +2 -2
- package/docs/api/functions/isAnySqlFragment.md +2 -2
- package/docs/api/functions/isConnectionError.md +26 -0
- package/docs/api/functions/isSqlCondition.md +2 -2
- package/docs/api/functions/isSqlFragment.md +2 -2
- package/docs/api/functions/isSqlRaw.md +2 -2
- package/docs/api/functions/isSqlRef.md +2 -2
- package/docs/api/functions/isSqlTypedFragment.md +2 -2
- package/docs/api/functions/model.md +6 -42
- package/docs/api/functions/parentRef.md +2 -2
- package/docs/api/functions/sql.md +7 -7
- package/docs/api/globals.md +57 -22
- package/docs/api/interfaces/Column.md +31 -31
- package/docs/api/interfaces/ColumnOptions.md +5 -4
- package/docs/api/interfaces/CreatedMiddlewareClass.md +7 -7
- package/docs/api/interfaces/DBConfig.md +13 -11
- package/docs/api/interfaces/DBConfigOptions.md +8 -8
- package/docs/api/interfaces/DeleteOptions.md +4 -4
- package/docs/api/interfaces/InsertOptions.md +8 -8
- package/docs/api/interfaces/LimitConfig.md +4 -4
- package/docs/api/interfaces/MiddlewareConfig.md +15 -15
- package/docs/api/interfaces/ModelOptions.md +8 -7
- package/docs/api/interfaces/PkeyResult.md +4 -4
- package/docs/api/interfaces/SelectOptions.md +17 -16
- package/docs/api/interfaces/SqlCondition.md +6 -6
- package/docs/api/interfaces/SqlFragment.md +5 -5
- package/docs/api/interfaces/SqlTypedFragment.md +7 -7
- package/docs/api/interfaces/TransactionOptions.md +7 -7
- package/docs/api/interfaces/UpdateManyOptions.md +4 -4
- package/docs/api/interfaces/UpdateOptions.md +4 -4
- package/docs/architecture.md +452 -0
- package/docs/benchmark-chart.svg +225 -249
- package/docs/design/phase-a-execution-context.md +2 -0
- package/package.json +20 -5
- package/dist/scp/writes.d.ts +0 -251
- package/dist/scp/writes.d.ts.map +0 -1
- package/dist/scp/writes.js +0 -176
- package/dist/scp/writes.js.map +0 -1
- package/docs/proposal/contracts-architecture-feasibility.md +0 -328
- package/docs/proposal/contracts-architecture.md +0 -579
- package/docs/proposal/litedbmodel-v2-scp-architecture.md +0 -433
- package/docs/proposal/sql-dynamic-expansion-spec.md +0 -175
- package/docs/proposal/v0-coverage-matrix.md +0 -157
- package/docs/proposal/v2-completeness-plan.md +0 -90
- package/docs/proposal/v2-sql-parity-checklist.md +0 -162
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
**対象**: litedbmodel v2 → beta(v1 parity)Epic #74 の基盤フェーズ。tx(#69)・middleware(#70)・reader/writer/複数DB(#72)・config(#72) の全てがこの上に載る。**5 native 言語(TS/rust/go/py/php)共通契約**。設計参照: v1 TS(`AsyncLocalStorage`)・v1 rust(`litedbmodel.rs` `PoolTransaction`)・graphddb。
|
|
4
4
|
|
|
5
|
+
> **現況注記(#227 後)**: 本節 §1/§2 が「ctx を通す入口」として挙げる `executeBundle` / `executeTransactionBundle` / `executeReadGraph`(自前の SqlBundle/ReadGraph 実行系)は **#227 で全削除された**。ctx が通る唯一の実行経路は BC 生成 native がバインドする **leaf transport(`executeSQL`/`pluck`/`group`)+中央 execute/run/runGuarded seam** に一本化されている。以下の記述は Phase A 設計当時の出発点(seam 導入前)として読むこと。seam 自体(ExecutionContext / execute / run / withTransaction)は現行のまま。
|
|
6
|
+
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
## 1. 現状(seam の素地と欠落)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litedbmodel",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
4
4
|
"description": "A lightweight TypeScript ORM for PostgreSQL, MySQL, and SQLite with Active Record pattern",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test": "vitest run",
|
|
36
36
|
"test:unit": "vitest run test/unit",
|
|
37
37
|
"test:integration": "TEST_DB_HOST=localhost vitest run test/integration",
|
|
38
|
-
"parity:capture": "TEST_DB_HOST=localhost TEST_DB_PORT=5433 vitest run test/parity/v1-sql-golden.test.ts",
|
|
38
|
+
"parity:capture": "PARITY_CAPTURE_WRITE=1 TEST_DB_HOST=localhost TEST_DB_PORT=5433 vitest run test/parity/v1-sql-golden.test.ts",
|
|
39
39
|
"parity:scp": "vitest run test/parity/v2-scp-parity.test.ts",
|
|
40
40
|
"test:watch": "vitest",
|
|
41
41
|
"test:coverage": "vitest run --coverage",
|
|
@@ -46,15 +46,28 @@
|
|
|
46
46
|
"docker:up": "docker compose -f docker-compose.test.yml up -d",
|
|
47
47
|
"docker:down": "docker compose -f docker-compose.test.yml down",
|
|
48
48
|
"docker:reset": "docker compose -f docker-compose.test.yml down -v && docker compose -f docker-compose.test.yml up -d",
|
|
49
|
-
"test:integration:docker": "
|
|
50
|
-
"test:ci": "vitest run test/unit",
|
|
49
|
+
"test:integration:docker": "docker compose -f docker-compose.test.yml run --rm --build test-integration; e=$?; npm run docker:down; exit $e",
|
|
51
50
|
"sync:versions": "node scripts/sync-versions.mjs",
|
|
52
51
|
"sync:versions:check": "node scripts/sync-versions.mjs --check",
|
|
53
52
|
"deps:check": "node scripts/check-no-local-deps.mjs",
|
|
53
|
+
"deps:installed": "node scripts/check-installed-deps.mjs",
|
|
54
54
|
"gates:check": "node scripts/check-reachable-test-gates.mjs",
|
|
55
|
+
"go:fmt:check": "node scripts/check-go-fmt.mjs",
|
|
56
|
+
"ts:test": "node scripts/check-ts-test-skips.mjs",
|
|
57
|
+
"py:test": "node scripts/check-python-test-skips.mjs",
|
|
58
|
+
"php:test": "node scripts/check-php-test-skips.mjs",
|
|
59
|
+
"go:test": "node scripts/check-go-test-skips.mjs",
|
|
60
|
+
"rust:test": "node scripts/check-rust-test-skips.mjs",
|
|
55
61
|
"pkg:check": "node scripts/check-package-entrypoints.mjs",
|
|
62
|
+
"types:check": "node scripts/check-typechecked-trees.mjs",
|
|
63
|
+
"tracked:check": "node scripts/check-tracked-files.mjs",
|
|
64
|
+
"spec:check": "node scripts/check-spec-refs.mjs",
|
|
65
|
+
"docs:bench:check": "node scripts/check-bench-docs.mjs",
|
|
56
66
|
"vendor:bc-php": "node scripts/vendor-behavior-contracts-php.mjs",
|
|
57
67
|
"vendor:bc-php:check": "node scripts/vendor-behavior-contracts-php.mjs --check",
|
|
68
|
+
"go:dispatch:check": "LITEDBMODEL_LIVEDB_VECTORS=\"$PWD/conformance/vectors-livedb/livedb.json\" sh -c 'cd go && exec go run ./conformance/livedb --check-coverage'",
|
|
69
|
+
"rust:dispatch:check": "LITEDBMODEL_LIVEDB_VECTORS=\"$PWD/conformance/vectors-livedb/livedb.json\" sh -c 'cd rust && exec cargo run --quiet -p livedb_runner --features livedb -- --check-coverage'",
|
|
70
|
+
"conformance:dispatch:check": "npm run go:dispatch:check && npm run rust:dispatch:check",
|
|
58
71
|
"conformance:gen": "vitest run --config conformance/vitest.config.ts",
|
|
59
72
|
"conformance:gen:livedb": "vitest run --config conformance/vitest.livedb.config.ts",
|
|
60
73
|
"conformance:check:livedb": "LIVEDB_GEN_MODE=check vitest run --config conformance/vitest.livedb.config.ts",
|
|
@@ -63,7 +76,8 @@
|
|
|
63
76
|
"docker:livedb:down": "docker compose -f docker-compose.test.yml -f docker-compose.livedb.yml down -v",
|
|
64
77
|
"conformance:livedb:docker": "npm run docker:livedb:up && sleep 5 && npm run conformance:gen:livedb && npm run conformance:livedb; e=$?; npm run docker:livedb:down; exit $e",
|
|
65
78
|
"native:gen": "bash benchmark/crosslang/gen-native.sh generate",
|
|
66
|
-
"bench:codegen:drift": "bash benchmark/crosslang/gen-native.sh check"
|
|
79
|
+
"bench:codegen:drift": "bash benchmark/crosslang/gen-native.sh check",
|
|
80
|
+
"verify": "node scripts/verify-local.mjs"
|
|
67
81
|
},
|
|
68
82
|
"keywords": [
|
|
69
83
|
"orm",
|
|
@@ -97,6 +111,7 @@
|
|
|
97
111
|
"esbuild": "^0.28.1",
|
|
98
112
|
"eslint": "^9.39.4",
|
|
99
113
|
"globals": "^17.6.0",
|
|
114
|
+
"js-yaml": "4.3.0",
|
|
100
115
|
"mysql2": "^3.16.0",
|
|
101
116
|
"pg": "^8.11.3",
|
|
102
117
|
"terser": "^5.44.1",
|
package/dist/scp/writes.d.ts
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* litedbmodel v2 SCP — write-time relations declaration vocabulary (WS5, #25; spec §6 / §2.2).
|
|
3
|
-
*
|
|
4
|
-
* `entityWrites` / `edgeWrites` declare the **write-side invariants / effects required for
|
|
5
|
-
* an entity to stay consistent** when it is created / updated / removed — the SQL-backend
|
|
6
|
-
* counterpart of graphddb's `entityWrites` save contract (`graphddb/src/define/entity-writes.ts`,
|
|
7
|
-
* same shape: a per-lifecycle map of `w.lifecycle({requires,unique,derive,edges,emits,idempotency})`).
|
|
8
|
-
* This module produces a PORTABLE declaration (pure data, no closures): every value that
|
|
9
|
-
* references the write is a **path-rooted string** (`$.input.<field>` = the mutation input,
|
|
10
|
-
* `$.entity.<field>` = the written row's RETURNING result). {@link ../write-plan} lowers the
|
|
11
|
-
* declaration + a base write op into an ordered, gate-first SQL transaction plan (§6 table).
|
|
12
|
-
*
|
|
13
|
-
* ## Path roots (spec §6 example) — the SSoT for every derived value
|
|
14
|
-
*
|
|
15
|
-
* A leaf value binds to an explicit root so its source is unambiguous and no engine-code
|
|
16
|
-
* fallback is ever needed (hard rule: defaults live in the declaration):
|
|
17
|
-
* - `$.input.<field>` — the Command's input port value (bc flat scope: `{ref:['<field>']}`).
|
|
18
|
-
* - `$.entity.<field>` — the just-written row (the body write's RETURNING row), exposed to
|
|
19
|
-
* the derive/edges/emits stages under the reserved `{@link ENTITY_ROOT}` binding.
|
|
20
|
-
*
|
|
21
|
-
* The declaration is INITIAL-scope (spec §6 / §13): single-statement Command + fixed-order
|
|
22
|
-
* write-time relations. It does NOT model the complex DAG derivation (WS8).
|
|
23
|
-
*/
|
|
24
|
-
/** The reserved scope binding under which the body write's RETURNING row is exposed (`$.entity.*`). */
|
|
25
|
-
export declare const ENTITY_ROOT = "__entity";
|
|
26
|
-
/**
|
|
27
|
-
* The path root a write-relation value binds from:
|
|
28
|
-
* - `input` — the Command input port (bc flat scope).
|
|
29
|
-
* - `entity` — the SOLE body write's RETURNING row (the WS5 single-base-write shorthand),
|
|
30
|
-
* bound under {@link ENTITY_ROOT}.
|
|
31
|
-
* - `ref` — a NAMED upstream write's RETURNING row (`$.ref.<writeName>.<field>`, WS8a
|
|
32
|
-
* composite/DAG scope). `entity` is exactly `ref` targeting the sole base write; keeping
|
|
33
|
-
* it distinct preserves the WS5 vocabulary while composite writes address writes by name.
|
|
34
|
-
*/
|
|
35
|
-
export type PathRoot = 'input' | 'entity' | 'ref';
|
|
36
|
-
/** A parsed, path-rooted write-relation value (`$.input.x` / `$.entity.x` / `$.ref.w.x`). */
|
|
37
|
-
export interface EffectPath {
|
|
38
|
-
readonly root: PathRoot;
|
|
39
|
-
/**
|
|
40
|
-
* For `ref`: the upstream write's NAME (the statement whose RETURNING row is referenced).
|
|
41
|
-
* Absent for `input` / `entity` (those have a single implicit source).
|
|
42
|
-
*/
|
|
43
|
-
readonly writeName?: string;
|
|
44
|
-
/** The field name after the root (a single physical column; no nested paths in α). */
|
|
45
|
-
readonly field: string;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Parse a path-rooted write-relation value string into an {@link EffectPath}. Fail-closed on
|
|
49
|
-
* a malformed path — a write-relation value MUST be `$.input.<field>`, `$.entity.<field>`, or
|
|
50
|
-
* `$.ref.<writeName>.<field>` (no free-form paths, no implicit root), so a typo is a loud build
|
|
51
|
-
* error, never a silent default (hard rule).
|
|
52
|
-
*/
|
|
53
|
-
export declare function parseEffectPath(value: string): EffectPath;
|
|
54
|
-
/**
|
|
55
|
-
* A referential-integrity requirement (§6 `requires`): the named `table` must contain a row
|
|
56
|
-
* whose columns equal the bound keys. Lowered to a gate-first `SELECT 1 FROM <table> WHERE …`
|
|
57
|
-
* existence guard that ROLLBACKs when absent (spec §6 example line 1).
|
|
58
|
-
*/
|
|
59
|
-
export interface RequiresEffect {
|
|
60
|
-
readonly kind: 'requires';
|
|
61
|
-
/** The table whose row must exist. */
|
|
62
|
-
readonly table: string;
|
|
63
|
-
/** target column → path-rooted source value (the existence key). */
|
|
64
|
-
readonly keys: Readonly<Record<string, string>>;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* A uniqueness guard (§6 `unique`): the combined `fields` must be unique within `scope`.
|
|
68
|
-
* Lowered to a guard-row `INSERT INTO <guardTable> … ON CONFLICT DO NOTHING` whose affected-
|
|
69
|
-
* row count is checked (0 rows ⇒ collision ⇒ ROLLBACK) — the SQL idiom of §6 (`ON CONFLICT
|
|
70
|
-
* DO NOTHING` + affected 検査).
|
|
71
|
-
*/
|
|
72
|
-
export interface UniqueEffect {
|
|
73
|
-
readonly kind: 'unique';
|
|
74
|
-
/** The guard-row name (its discriminator column value in the guard table). */
|
|
75
|
-
readonly name: string;
|
|
76
|
-
/** The guard table that materializes the uniqueness rows. */
|
|
77
|
-
readonly guardTable: string;
|
|
78
|
-
/** The scope the uniqueness is partitioned by (path-rooted values). */
|
|
79
|
-
readonly scope: readonly string[];
|
|
80
|
-
/** The fields whose combined value must be unique within the scope (path-rooted values). */
|
|
81
|
-
readonly fields: readonly string[];
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* A derived / cascading counter update (§6 `derive`): `SET <attribute> = <attribute> ± amount`
|
|
85
|
-
* on the `table` row keyed by `keys`. Lowered to `UPDATE <table> SET c = c + :amount WHERE …`
|
|
86
|
-
* (spec §6 example line "derive"). `amount` is the SSoT for the increment — never a code default.
|
|
87
|
-
*/
|
|
88
|
-
export interface DeriveEffect {
|
|
89
|
-
readonly kind: 'derive';
|
|
90
|
-
/** The table whose counter attribute is derived-updated. */
|
|
91
|
-
readonly table: string;
|
|
92
|
-
/** target column → path-rooted source value (the updated row's key). */
|
|
93
|
-
readonly keys: Readonly<Record<string, string>>;
|
|
94
|
-
/** The counter column to increment. */
|
|
95
|
-
readonly attribute: string;
|
|
96
|
-
/** The signed amount added to the counter (the declaration IS the source of truth). */
|
|
97
|
-
readonly amount: number;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* An edge write (§6 `edges`). A many-to-many edge materializes as an intermediate-table
|
|
101
|
-
* `INSERT` (create) / `DELETE` (remove); a one-to-many edge as a foreign-key column `UPDATE`
|
|
102
|
-
* on the related table. Lowered per {@link EdgeEffect.relation} (spec §6 table row `edges`).
|
|
103
|
-
*/
|
|
104
|
-
export interface EdgeEffect {
|
|
105
|
-
readonly kind: 'edge';
|
|
106
|
-
/** `m2m` → intermediate-table INSERT/DELETE; `fk` → related-table FK column UPDATE. */
|
|
107
|
-
readonly relation: 'm2m' | 'fk';
|
|
108
|
-
/** The write action for this lifecycle: `set` (create/link) or `unset` (remove/unlink). */
|
|
109
|
-
readonly action: 'set' | 'unset';
|
|
110
|
-
/**
|
|
111
|
-
* For `m2m`: the intermediate (join) table. For `fk`: the related table whose FK column is set.
|
|
112
|
-
*/
|
|
113
|
-
readonly table: string;
|
|
114
|
-
/**
|
|
115
|
-
* For `m2m`: the join-row columns → path-rooted source values (both endpoint keys).
|
|
116
|
-
* For `fk`: the FK column → path-rooted source value AND the matched-row key columns.
|
|
117
|
-
*/
|
|
118
|
-
readonly columns: Readonly<Record<string, string>>;
|
|
119
|
-
/**
|
|
120
|
-
* For `fk` only: the WHERE key columns (matched-row identity) → path-rooted source values.
|
|
121
|
-
* `columns` then holds ONLY the FK column(s) to SET. For `m2m` this is absent.
|
|
122
|
-
*/
|
|
123
|
-
readonly where?: Readonly<Record<string, string>>;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* A domain event (§6 `emits`): an outbox `INSERT INTO <outboxTable>(type, payload)` in the
|
|
127
|
-
* SAME transaction (spec §6 example line "emits"). The payload is a path-rooted map serialized
|
|
128
|
-
* to a JSON text column at render time.
|
|
129
|
-
*/
|
|
130
|
-
export interface EmitEffect {
|
|
131
|
-
readonly kind: 'emit';
|
|
132
|
-
/** The event type discriminator (e.g. `PostCreated`). */
|
|
133
|
-
readonly name: string;
|
|
134
|
-
/** The outbox table the event row is inserted into. */
|
|
135
|
-
readonly outboxTable: string;
|
|
136
|
-
/** The event payload: field → path-rooted source value. */
|
|
137
|
-
readonly payload: Readonly<Record<string, string>>;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* An idempotency guard (§6 `idempotency`): a client-token guard `INSERT INTO <table>(token)`
|
|
141
|
-
* whose UNIQUE violation detects a duplicate request (spec §6 example line "idempotency").
|
|
142
|
-
* Runs gate-first: a duplicate token short-circuits the whole transaction (no double write).
|
|
143
|
-
*/
|
|
144
|
-
export interface IdempotencyEffect {
|
|
145
|
-
readonly kind: 'idempotency';
|
|
146
|
-
/** The idempotency-key table (a single UNIQUE token column). */
|
|
147
|
-
readonly table: string;
|
|
148
|
-
/** The token column name. */
|
|
149
|
-
readonly column: string;
|
|
150
|
-
/** The path-rooted client-token value (e.g. `$.input.request_id`). */
|
|
151
|
-
readonly token: string;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* The §6 effect set a {@link LifecycleContract} carries. Every field is optional; an omitted
|
|
155
|
-
* field is the empty effect set. Fixed derivation order (spec §6 example): gate-first
|
|
156
|
-
* (requires → idempotency → unique), body, then derive → edges → emits.
|
|
157
|
-
*/
|
|
158
|
-
export interface LifecycleEffects {
|
|
159
|
-
/** Referential-integrity requirements (→ gate-first existence guard). */
|
|
160
|
-
readonly requires?: readonly RequiresEffect[];
|
|
161
|
-
/** Idempotency guard (→ gate-first token INSERT; duplicate short-circuits). */
|
|
162
|
-
readonly idempotency?: IdempotencyEffect;
|
|
163
|
-
/** Uniqueness guards (→ gate-first guard-row INSERT ON CONFLICT DO NOTHING + affected check). */
|
|
164
|
-
readonly unique?: readonly UniqueEffect[];
|
|
165
|
-
/** Derived / cascading counter updates (→ UPDATE … SET c = c ± n). */
|
|
166
|
-
readonly derive?: readonly DeriveEffect[];
|
|
167
|
-
/** Edge writes (→ M:N intermediate INSERT/DELETE or 1:N FK UPDATE). */
|
|
168
|
-
readonly edges?: readonly EdgeEffect[];
|
|
169
|
-
/** Domain events (→ outbox INSERT, same tx). */
|
|
170
|
-
readonly emits?: readonly EmitEffect[];
|
|
171
|
-
}
|
|
172
|
-
/** One lifecycle's save contract — the §6 effect set for a single phase. */
|
|
173
|
-
export interface LifecycleContract {
|
|
174
|
-
readonly effects: LifecycleEffects;
|
|
175
|
-
}
|
|
176
|
-
/** The lifecycle phase a save-contract entry declares (the Command intent selects it). */
|
|
177
|
-
export type WriteLifecyclePhase = 'create' | 'update' | 'remove';
|
|
178
|
-
/** A model's per-lifecycle save contract (`entityWrites(...)` result). */
|
|
179
|
-
export interface EntityWritesDefinition {
|
|
180
|
-
readonly create?: LifecycleContract;
|
|
181
|
-
readonly update?: LifecycleContract;
|
|
182
|
-
readonly remove?: LifecycleContract;
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* The recorder handed to the {@link entityWrites} / {@link edgeWrites} builder. Each method
|
|
186
|
-
* builds ONE §6 effect (pure data). `w.lifecycle({...})` gathers the effect arrays into a
|
|
187
|
-
* {@link LifecycleContract}. Every path-rooted value is validated eagerly ({@link parseEffectPath}).
|
|
188
|
-
*/
|
|
189
|
-
export interface WriteRecorder {
|
|
190
|
-
/** Build one lifecycle's save contract from its §6 effect arrays (each field optional). */
|
|
191
|
-
lifecycle(effects?: LifecycleEffects): LifecycleContract;
|
|
192
|
-
/** `requires` — a referential-integrity existence guard (§6). */
|
|
193
|
-
exists(table: string, keys: Readonly<Record<string, string>>): RequiresEffect;
|
|
194
|
-
/** `unique` — a composite-scope uniqueness guard (§6). */
|
|
195
|
-
unique(spec: {
|
|
196
|
-
readonly name: string;
|
|
197
|
-
readonly guardTable: string;
|
|
198
|
-
readonly scope: readonly string[];
|
|
199
|
-
readonly fields: readonly string[];
|
|
200
|
-
}): UniqueEffect;
|
|
201
|
-
/** `derive` — a cascade counter increment (§6). `amount` is the SSoT (no code default). */
|
|
202
|
-
increment(table: string, keys: Readonly<Record<string, string>>, attribute: string, amount: number): DeriveEffect;
|
|
203
|
-
/** `edges` — a many-to-many intermediate-table link/unlink (§6). */
|
|
204
|
-
edge(spec: {
|
|
205
|
-
readonly relation: 'm2m';
|
|
206
|
-
readonly action: 'set' | 'unset';
|
|
207
|
-
readonly table: string;
|
|
208
|
-
readonly columns: Readonly<Record<string, string>>;
|
|
209
|
-
}): EdgeEffect;
|
|
210
|
-
/** `edges` — a one-to-many foreign-key column set/unset on a related row (§6). */
|
|
211
|
-
edge(spec: {
|
|
212
|
-
readonly relation: 'fk';
|
|
213
|
-
readonly action: 'set' | 'unset';
|
|
214
|
-
readonly table: string;
|
|
215
|
-
readonly columns: Readonly<Record<string, string>>;
|
|
216
|
-
readonly where: Readonly<Record<string, string>>;
|
|
217
|
-
}): EdgeEffect;
|
|
218
|
-
/** `emits` — a domain event into an outbox table, same tx (§6). */
|
|
219
|
-
event(name: string, outboxTable: string, payload: Readonly<Record<string, string>>): EmitEffect;
|
|
220
|
-
/** `idempotency` — a client-token duplicate guard (§6). */
|
|
221
|
-
idempotentBy(table: string, column: string, token: string): IdempotencyEffect;
|
|
222
|
-
}
|
|
223
|
-
/** The per-lifecycle map an {@link entityWrites} builder returns. */
|
|
224
|
-
export interface EntityWritesShape {
|
|
225
|
-
readonly create?: LifecycleContract;
|
|
226
|
-
readonly update?: LifecycleContract;
|
|
227
|
-
readonly remove?: LifecycleContract;
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Declare a model's reusable write-time-relations save contract (spec §2.2 / §6): a
|
|
231
|
-
* per-lifecycle map `{ create?, update?, remove? }`, each value a `w.lifecycle({...})`
|
|
232
|
-
* carrying the §6 effect arrays. Stored on the model as
|
|
233
|
-
* `static readonly writes = entityWrites<Model>((w) => ({ … }))`.
|
|
234
|
-
*
|
|
235
|
-
* @typeParam M documentary model type (the recorder is structural).
|
|
236
|
-
* @throws if no lifecycle is declared, or a lifecycle is not built with `w.lifecycle(...)`.
|
|
237
|
-
*/
|
|
238
|
-
export declare function entityWrites<M = unknown>(builder: (w: WriteRecorder) => EntityWritesShape): EntityWritesDefinition;
|
|
239
|
-
/**
|
|
240
|
-
* Declare an adjacency entity's edge-only write contract (spec §2.2 / §6 — the `edgeWrites`
|
|
241
|
-
* counterpart of graphddb's #82). It is a thin specialization of {@link entityWrites} whose
|
|
242
|
-
* lifecycles carry ONLY `edges` effects — the write side of a many-to-many / one-to-many
|
|
243
|
-
* relation entity. Kept distinct so an author signals intent (an edge entity vs a full
|
|
244
|
-
* save contract), matching graphddb's two coexisting `writes` forms.
|
|
245
|
-
*
|
|
246
|
-
* @throws if a lifecycle declares a non-edge effect (an edge entity has only edge writes).
|
|
247
|
-
*/
|
|
248
|
-
export declare function edgeWrites<M = unknown>(builder: (w: WriteRecorder) => EntityWritesShape): EntityWritesDefinition;
|
|
249
|
-
/** Resolve the {@link LifecycleContract} for a Command intent, or undefined if not declared. */
|
|
250
|
-
export declare function lifecycleFor(def: EntityWritesDefinition, phase: WriteLifecyclePhase): LifecycleContract | undefined;
|
|
251
|
-
//# sourceMappingURL=writes.d.ts.map
|
package/dist/scp/writes.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"writes.d.ts","sourceRoot":"","sources":["../../src/scp/writes.ts"],"names":[],"mappings":"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"}
|
package/dist/scp/writes.js
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* litedbmodel v2 SCP — write-time relations declaration vocabulary (WS5, #25; spec §6 / §2.2).
|
|
4
|
-
*
|
|
5
|
-
* `entityWrites` / `edgeWrites` declare the **write-side invariants / effects required for
|
|
6
|
-
* an entity to stay consistent** when it is created / updated / removed — the SQL-backend
|
|
7
|
-
* counterpart of graphddb's `entityWrites` save contract (`graphddb/src/define/entity-writes.ts`,
|
|
8
|
-
* same shape: a per-lifecycle map of `w.lifecycle({requires,unique,derive,edges,emits,idempotency})`).
|
|
9
|
-
* This module produces a PORTABLE declaration (pure data, no closures): every value that
|
|
10
|
-
* references the write is a **path-rooted string** (`$.input.<field>` = the mutation input,
|
|
11
|
-
* `$.entity.<field>` = the written row's RETURNING result). {@link ../write-plan} lowers the
|
|
12
|
-
* declaration + a base write op into an ordered, gate-first SQL transaction plan (§6 table).
|
|
13
|
-
*
|
|
14
|
-
* ## Path roots (spec §6 example) — the SSoT for every derived value
|
|
15
|
-
*
|
|
16
|
-
* A leaf value binds to an explicit root so its source is unambiguous and no engine-code
|
|
17
|
-
* fallback is ever needed (hard rule: defaults live in the declaration):
|
|
18
|
-
* - `$.input.<field>` — the Command's input port value (bc flat scope: `{ref:['<field>']}`).
|
|
19
|
-
* - `$.entity.<field>` — the just-written row (the body write's RETURNING row), exposed to
|
|
20
|
-
* the derive/edges/emits stages under the reserved `{@link ENTITY_ROOT}` binding.
|
|
21
|
-
*
|
|
22
|
-
* The declaration is INITIAL-scope (spec §6 / §13): single-statement Command + fixed-order
|
|
23
|
-
* write-time relations. It does NOT model the complex DAG derivation (WS8).
|
|
24
|
-
*/
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.ENTITY_ROOT = void 0;
|
|
27
|
-
exports.parseEffectPath = parseEffectPath;
|
|
28
|
-
exports.entityWrites = entityWrites;
|
|
29
|
-
exports.edgeWrites = edgeWrites;
|
|
30
|
-
exports.lifecycleFor = lifecycleFor;
|
|
31
|
-
/** The reserved scope binding under which the body write's RETURNING row is exposed (`$.entity.*`). */
|
|
32
|
-
exports.ENTITY_ROOT = '__entity';
|
|
33
|
-
const PATH_RE = /^\$\.(input|entity)\.([A-Za-z_][A-Za-z0-9_]*)$/;
|
|
34
|
-
const REF_PATH_RE = /^\$\.ref\.([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)$/;
|
|
35
|
-
/**
|
|
36
|
-
* Parse a path-rooted write-relation value string into an {@link EffectPath}. Fail-closed on
|
|
37
|
-
* a malformed path — a write-relation value MUST be `$.input.<field>`, `$.entity.<field>`, or
|
|
38
|
-
* `$.ref.<writeName>.<field>` (no free-form paths, no implicit root), so a typo is a loud build
|
|
39
|
-
* error, never a silent default (hard rule).
|
|
40
|
-
*/
|
|
41
|
-
function parseEffectPath(value) {
|
|
42
|
-
const m = PATH_RE.exec(value);
|
|
43
|
-
if (m !== null)
|
|
44
|
-
return { root: m[1], field: m[2] };
|
|
45
|
-
const r = REF_PATH_RE.exec(value);
|
|
46
|
-
if (r !== null)
|
|
47
|
-
return { root: 'ref', writeName: r[1], field: r[2] };
|
|
48
|
-
throw new Error(`write-time relations: '${value}' is not a valid path-rooted value; use ` +
|
|
49
|
-
`'$.input.<field>' (the Command input), '$.entity.<field>' (the sole written row), or ` +
|
|
50
|
-
`'$.ref.<writeName>.<field>' (a named upstream write's RETURNING row).`);
|
|
51
|
-
}
|
|
52
|
-
/** Assert every value in a path-rooted map parses (fail-closed on a malformed path). */
|
|
53
|
-
function assertPaths(map) {
|
|
54
|
-
for (const v of Object.values(map))
|
|
55
|
-
parseEffectPath(v); // throws on malformed
|
|
56
|
-
}
|
|
57
|
-
const recorder = {
|
|
58
|
-
lifecycle(effects = {}) {
|
|
59
|
-
// Validate every declared effect's paths eagerly (build-time fail-closed).
|
|
60
|
-
for (const r of effects.requires ?? [])
|
|
61
|
-
assertPaths(r.keys);
|
|
62
|
-
if (effects.idempotency !== undefined)
|
|
63
|
-
parseEffectPath(effects.idempotency.token);
|
|
64
|
-
for (const u of effects.unique ?? []) {
|
|
65
|
-
u.scope.forEach((p) => parseEffectPath(p));
|
|
66
|
-
u.fields.forEach((p) => parseEffectPath(p));
|
|
67
|
-
}
|
|
68
|
-
for (const d of effects.derive ?? [])
|
|
69
|
-
assertPaths(d.keys);
|
|
70
|
-
for (const e of effects.edges ?? []) {
|
|
71
|
-
assertPaths(e.columns);
|
|
72
|
-
if (e.where !== undefined)
|
|
73
|
-
assertPaths(e.where);
|
|
74
|
-
}
|
|
75
|
-
for (const em of effects.emits ?? [])
|
|
76
|
-
assertPaths(em.payload);
|
|
77
|
-
return { effects: freezeEffects(effects) };
|
|
78
|
-
},
|
|
79
|
-
exists(table, keys) {
|
|
80
|
-
return { kind: 'requires', table, keys };
|
|
81
|
-
},
|
|
82
|
-
unique(spec) {
|
|
83
|
-
return { kind: 'unique', name: spec.name, guardTable: spec.guardTable, scope: spec.scope, fields: spec.fields };
|
|
84
|
-
},
|
|
85
|
-
increment(table, keys, attribute, amount) {
|
|
86
|
-
if (!Number.isFinite(amount)) {
|
|
87
|
-
throw new Error(`entityWrites: increment amount for '${table}.${attribute}' must be a finite number (got ${String(amount)})`);
|
|
88
|
-
}
|
|
89
|
-
return { kind: 'derive', table, keys, attribute, amount };
|
|
90
|
-
},
|
|
91
|
-
edge(spec) {
|
|
92
|
-
if (spec.relation === 'fk' && spec.where === undefined) {
|
|
93
|
-
throw new Error(`entityWrites: a 'fk' edge on '${spec.table}' requires a 'where' key map (the matched row's identity)`);
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
kind: 'edge',
|
|
97
|
-
relation: spec.relation,
|
|
98
|
-
action: spec.action,
|
|
99
|
-
table: spec.table,
|
|
100
|
-
columns: spec.columns,
|
|
101
|
-
...(spec.where !== undefined ? { where: spec.where } : {}),
|
|
102
|
-
};
|
|
103
|
-
},
|
|
104
|
-
event(name, outboxTable, payload) {
|
|
105
|
-
return { kind: 'emit', name, outboxTable, payload };
|
|
106
|
-
},
|
|
107
|
-
idempotentBy(table, column, token) {
|
|
108
|
-
return { kind: 'idempotency', table, column, token };
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
/** Keep only the present effect fields (an empty `w.lifecycle()` carries an empty set). */
|
|
112
|
-
function freezeEffects(effects) {
|
|
113
|
-
const out = {};
|
|
114
|
-
if (effects.requires !== undefined)
|
|
115
|
-
out.requires = effects.requires;
|
|
116
|
-
if (effects.idempotency !== undefined)
|
|
117
|
-
out.idempotency = effects.idempotency;
|
|
118
|
-
if (effects.unique !== undefined)
|
|
119
|
-
out.unique = effects.unique;
|
|
120
|
-
if (effects.derive !== undefined)
|
|
121
|
-
out.derive = effects.derive;
|
|
122
|
-
if (effects.edges !== undefined)
|
|
123
|
-
out.edges = effects.edges;
|
|
124
|
-
if (effects.emits !== undefined)
|
|
125
|
-
out.emits = effects.emits;
|
|
126
|
-
return out;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Declare a model's reusable write-time-relations save contract (spec §2.2 / §6): a
|
|
130
|
-
* per-lifecycle map `{ create?, update?, remove? }`, each value a `w.lifecycle({...})`
|
|
131
|
-
* carrying the §6 effect arrays. Stored on the model as
|
|
132
|
-
* `static readonly writes = entityWrites<Model>((w) => ({ … }))`.
|
|
133
|
-
*
|
|
134
|
-
* @typeParam M documentary model type (the recorder is structural).
|
|
135
|
-
* @throws if no lifecycle is declared, or a lifecycle is not built with `w.lifecycle(...)`.
|
|
136
|
-
*/
|
|
137
|
-
function entityWrites(builder) {
|
|
138
|
-
void undefined;
|
|
139
|
-
const shape = builder(recorder);
|
|
140
|
-
if (shape.create === undefined && shape.update === undefined && shape.remove === undefined) {
|
|
141
|
-
throw new Error('entityWrites(...) must declare at least one lifecycle (`create` / `update` / `remove`).');
|
|
142
|
-
}
|
|
143
|
-
return {
|
|
144
|
-
...(shape.create !== undefined ? { create: shape.create } : {}),
|
|
145
|
-
...(shape.update !== undefined ? { update: shape.update } : {}),
|
|
146
|
-
...(shape.remove !== undefined ? { remove: shape.remove } : {}),
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Declare an adjacency entity's edge-only write contract (spec §2.2 / §6 — the `edgeWrites`
|
|
151
|
-
* counterpart of graphddb's #82). It is a thin specialization of {@link entityWrites} whose
|
|
152
|
-
* lifecycles carry ONLY `edges` effects — the write side of a many-to-many / one-to-many
|
|
153
|
-
* relation entity. Kept distinct so an author signals intent (an edge entity vs a full
|
|
154
|
-
* save contract), matching graphddb's two coexisting `writes` forms.
|
|
155
|
-
*
|
|
156
|
-
* @throws if a lifecycle declares a non-edge effect (an edge entity has only edge writes).
|
|
157
|
-
*/
|
|
158
|
-
function edgeWrites(builder) {
|
|
159
|
-
const def = entityWrites(builder);
|
|
160
|
-
for (const phase of ['create', 'update', 'remove']) {
|
|
161
|
-
const c = def[phase];
|
|
162
|
-
if (c === undefined)
|
|
163
|
-
continue;
|
|
164
|
-
const e = c.effects;
|
|
165
|
-
if (e.requires !== undefined || e.unique !== undefined || e.derive !== undefined || e.emits !== undefined || e.idempotency !== undefined) {
|
|
166
|
-
throw new Error(`edgeWrites: the '${phase}' lifecycle may declare ONLY 'edges' effects ` +
|
|
167
|
-
`(an edge entity carries only edge writes; use entityWrites for a full save contract).`);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return def;
|
|
171
|
-
}
|
|
172
|
-
/** Resolve the {@link LifecycleContract} for a Command intent, or undefined if not declared. */
|
|
173
|
-
function lifecycleFor(def, phase) {
|
|
174
|
-
return def[phase];
|
|
175
|
-
}
|
|
176
|
-
//# sourceMappingURL=writes.js.map
|
package/dist/scp/writes.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"writes.js","sourceRoot":"","sources":["../../src/scp/writes.ts"],"names":[],"mappings":"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"}
|