graphddb 0.7.9 → 0.8.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/README.md +6 -6
- package/dist/cdc/index.d.ts +389 -4
- package/dist/cdc/index.js +4 -3
- package/dist/{chunk-ZPNRLOKA.js → chunk-GS4C5VGO.js} +4 -6
- package/dist/chunk-HNY2EJPV.js +1184 -0
- package/dist/{chunk-NYM7K2ST.js → chunk-I4LEJ4TF.js} +3812 -6724
- package/dist/{chunk-PFFPLD4B.js → chunk-L2NEDS7U.js} +725 -2112
- package/dist/chunk-L4QRCHRQ.js +278 -0
- package/dist/chunk-LGHSZIEE.js +187 -0
- package/dist/chunk-N4NWYNGZ.js +1987 -0
- package/dist/{chunk-PDUVTYC5.js → chunk-XTWXMOHD.js} +0 -1
- package/dist/cli.js +63 -252
- package/dist/index.d.ts +23 -1548
- package/dist/index.js +100 -1778
- package/dist/internal/index.d.ts +84 -0
- package/dist/internal/index.js +701 -0
- package/dist/{maintenance-view-adapter-BATUh_I8.d.ts → key-DR7_lpyk.d.ts} +538 -2975
- package/dist/linter/index.d.ts +39 -6
- package/dist/linter/index.js +22 -4
- package/dist/{registry-CXhP4TaE.d.ts → linter-C-vypgut.d.ts} +22 -22
- package/dist/prepared-artifact-BpPgkXEo.d.ts +281 -0
- package/dist/spec/index.d.ts +506 -4
- package/dist/spec/index.js +36 -17
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +4 -3
- package/dist/transform/index.d.ts +460 -1
- package/dist/transform/index.js +2085 -2
- package/dist/types-2PMXEn5x.d.ts +1205 -0
- package/dist/types-BXLzIcQD.d.ts +450 -0
- package/docs/cdc-projection.md +5 -5
- package/docs/class-hydration.md +1 -1
- package/docs/cqrs-contract.md +28 -20
- package/docs/design-patterns.md +5 -5
- package/docs/docs-generation.md +6 -6
- package/docs/middleware.md +15 -15
- package/docs/mutation-command-derivation.md +52 -42
- package/docs/prepared-statements.md +14 -14
- package/docs/python-bridge.md +113 -66
- package/docs/spec.md +153 -124
- package/docs/testing.md +9 -8
- package/package.json +20 -5
- package/dist/chunk-MMVHOUM4.js +0 -24
- package/dist/from-change-DanwjE5b.d.ts +0 -327
- package/dist/index-CtPJSMrc.d.ts +0 -934
- package/dist/relation-depth-Dg3yhl7S.d.ts +0 -36
package/dist/linter/index.d.ts
CHANGED
|
@@ -1,8 +1,41 @@
|
|
|
1
|
-
import { L as LintRule } from '../
|
|
2
|
-
export {
|
|
3
|
-
|
|
4
|
-
import '../
|
|
5
|
-
import '
|
|
1
|
+
import { L as Linter, a as LintRule } from '../linter-C-vypgut.js';
|
|
2
|
+
export { b as LintResult } from '../linter-C-vypgut.js';
|
|
3
|
+
import '../types-BXLzIcQD.js';
|
|
4
|
+
import '../key-DR7_lpyk.js';
|
|
5
|
+
import '../types-2PMXEn5x.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a Linter pre-loaded with rules safe for Entity registration.
|
|
9
|
+
*
|
|
10
|
+
* Rules included: no-scan, require-limit, gsi-ambiguity, missing-gsi,
|
|
11
|
+
* relation-depth, same-partition-preset, plus the Epic #118 Phase 1 maintenance
|
|
12
|
+
* validators (issue #126): missing-context, 400kb, hot-partition, fan-out,
|
|
13
|
+
* multi-maintainer-same-row. The maintenance validators are no-ops for any
|
|
14
|
+
* relation that does not declare `write.maintainedOn`, so unannotated models are
|
|
15
|
+
* unaffected. query-boundary is excluded because it flags non-unique GSIs which
|
|
16
|
+
* are valid for list() operations; boundary enforcement is handled at runtime by
|
|
17
|
+
* the planner's boundary-check.
|
|
18
|
+
*
|
|
19
|
+
* Also includes cfn-schema-consistency (issue #169): a whole-table validator
|
|
20
|
+
* that rejects entities sharing a physical table with an ambiguous base
|
|
21
|
+
* KeySchema, inconsistently-shared GSI index names, or more than 20 unioned
|
|
22
|
+
* GSIs — the CFn deploy-consistency user-error class, caught statically at
|
|
23
|
+
* finalize. It is additive: a single entity on its own table with ≤ 20 GSIs is
|
|
24
|
+
* never affected.
|
|
25
|
+
*/
|
|
26
|
+
declare function createDefaultLinter(): Linter;
|
|
27
|
+
|
|
28
|
+
declare const noScanRule: LintRule;
|
|
29
|
+
|
|
30
|
+
declare const requireLimitRule: LintRule;
|
|
31
|
+
|
|
32
|
+
declare const queryBoundaryRule: LintRule;
|
|
33
|
+
|
|
34
|
+
declare const gsiAmbiguityRule: LintRule;
|
|
35
|
+
|
|
36
|
+
declare const missingGsiRule: LintRule;
|
|
37
|
+
|
|
38
|
+
declare const relationDepthRule: LintRule;
|
|
6
39
|
|
|
7
40
|
/**
|
|
8
41
|
* `samePartition` preset validator (Epic #118 child issue H).
|
|
@@ -123,4 +156,4 @@ declare const multiMaintainerSameRowRule: LintRule;
|
|
|
123
156
|
|
|
124
157
|
declare const cfnSchemaConsistencyRule: LintRule;
|
|
125
158
|
|
|
126
|
-
export { LintRule, cfnSchemaConsistencyRule, embeddedSnapshotSizeRule, fanOutRule, hotPartitionRule, missingContextRule, multiMaintainerSameRowRule, samePartitionPresetRule };
|
|
159
|
+
export { LintRule, Linter, cfnSchemaConsistencyRule, createDefaultLinter, embeddedSnapshotSizeRule, fanOutRule, gsiAmbiguityRule, hotPartitionRule, missingContextRule, missingGsiRule, multiMaintainerSameRowRule, noScanRule, queryBoundaryRule, relationDepthRule, requireLimitRule, samePartitionPresetRule };
|
package/dist/linter/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
queryBoundaryRule
|
|
3
|
-
} from "../chunk-MMVHOUM4.js";
|
|
4
1
|
import {
|
|
5
2
|
Linter,
|
|
6
3
|
cfnSchemaConsistencyRule,
|
|
@@ -16,7 +13,28 @@ import {
|
|
|
16
13
|
relationDepthRule,
|
|
17
14
|
requireLimitRule,
|
|
18
15
|
samePartitionPresetRule
|
|
19
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-XTWXMOHD.js";
|
|
17
|
+
|
|
18
|
+
// src/linter/rules/query-boundary.ts
|
|
19
|
+
var queryBoundaryRule = {
|
|
20
|
+
id: "query-boundary",
|
|
21
|
+
severity: "error",
|
|
22
|
+
check(metadata) {
|
|
23
|
+
const results = [];
|
|
24
|
+
for (const gsi of metadata.gsiDefinitions) {
|
|
25
|
+
if (!gsi.unique) {
|
|
26
|
+
results.push({
|
|
27
|
+
ruleId: "query-boundary",
|
|
28
|
+
severity: "error",
|
|
29
|
+
message: `GSI '${gsi.indexName}' on entity '${metadata.prefix}' is not marked as unique. Using query() on a non-unique GSI may return multiple items. Use list() instead, or mark the GSI as unique if it guarantees single results.`,
|
|
30
|
+
entity: metadata.prefix,
|
|
31
|
+
field: gsi.indexName
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return results;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
20
38
|
export {
|
|
21
39
|
Linter,
|
|
22
40
|
cfnSchemaConsistencyRule,
|
|
@@ -1,24 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
interface LintRule {
|
|
4
|
-
id: string;
|
|
5
|
-
severity: 'error' | 'warning';
|
|
6
|
-
check(metadata: EntityMetadata, registry: typeof MetadataRegistry): LintResult[];
|
|
7
|
-
}
|
|
8
|
-
interface LintResult {
|
|
9
|
-
ruleId: string;
|
|
10
|
-
severity: 'error' | 'warning';
|
|
11
|
-
message: string;
|
|
12
|
-
entity: string;
|
|
13
|
-
field?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
declare class Linter {
|
|
17
|
-
private rules;
|
|
18
|
-
addRule(rule: LintRule): void;
|
|
19
|
-
run(metadata: EntityMetadata, registry: typeof MetadataRegistry): LintResult[];
|
|
20
|
-
runAll(registry: typeof MetadataRegistry): LintResult[];
|
|
21
|
-
}
|
|
1
|
+
import { E as EntityMetadata } from './types-BXLzIcQD.js';
|
|
22
2
|
|
|
23
3
|
declare class MetadataRegistry {
|
|
24
4
|
private static store;
|
|
@@ -73,4 +53,24 @@ declare class MetadataRegistry {
|
|
|
73
53
|
private static handleLintResults;
|
|
74
54
|
}
|
|
75
55
|
|
|
76
|
-
|
|
56
|
+
interface LintRule {
|
|
57
|
+
id: string;
|
|
58
|
+
severity: 'error' | 'warning';
|
|
59
|
+
check(metadata: EntityMetadata, registry: typeof MetadataRegistry): LintResult[];
|
|
60
|
+
}
|
|
61
|
+
interface LintResult {
|
|
62
|
+
ruleId: string;
|
|
63
|
+
severity: 'error' | 'warning';
|
|
64
|
+
message: string;
|
|
65
|
+
entity: string;
|
|
66
|
+
field?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare class Linter {
|
|
70
|
+
private rules;
|
|
71
|
+
addRule(rule: LintRule): void;
|
|
72
|
+
run(metadata: EntityMetadata, registry: typeof MetadataRegistry): LintResult[];
|
|
73
|
+
runAll(registry: typeof MetadataRegistry): LintResult[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { Linter as L, MetadataRegistry as M, type LintRule as a, type LintResult as b };
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { E as EntityMetadata } from './types-BXLzIcQD.js';
|
|
2
|
+
import { C as ContractSpec, Q as QuerySpec, a as CommandSpec, T as TransactionSpec, b as ContextSpec, S as SPEC_VERSION, P as ParamSpec } from './types-2PMXEn5x.js';
|
|
3
|
+
import { Q as QueryModelContract, k as QueryMethodSpec, l as CommandModelContract, m as CommandMethodSpec } from './key-DR7_lpyk.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Contract-layer serialization (issue #59, CQRS Contract layer, Epic #57;
|
|
7
|
+
* spec `docs/cqrs-contract.md`, "SSoT Schema").
|
|
8
|
+
*
|
|
9
|
+
* The Contract IR (#58, `src/define/contract.ts`) holds, per contract method, a
|
|
10
|
+
* resolved declarative {@link ContractMethodOp} plus the **decided facts** the
|
|
11
|
+
* planner derived (`resolution` / `inputArity` / `result`). This module
|
|
12
|
+
* **serializes** those facts into the JSON SSoT — it does **not** re-derive them:
|
|
13
|
+
*
|
|
14
|
+
* - The `contracts` map (contract name → {@link ContractSpec}) is layered **on
|
|
15
|
+
* top of** the existing `queries` / `commands` / `transactions`. Each method
|
|
16
|
+
* references one of them by name (`ContractName__methodName`), so the existing
|
|
17
|
+
* operation-spec shapes are unchanged and the current runtime keeps working.
|
|
18
|
+
* - The referenced operation spec is produced by **reusing** the proven
|
|
19
|
+
* {@link buildQuerySpec} / {@link buildCommandSpec} planners: a
|
|
20
|
+
* {@link ContractMethodOp} is translated back into the {@link AnyOperationDefinition}
|
|
21
|
+
* shape those planners consume (the contract's sentinel references become the
|
|
22
|
+
* `Param` placeholders the planner already understands), so the symbolic key
|
|
23
|
+
* evaluation, projection, relation chaining, and condition handling are shared
|
|
24
|
+
* — never re-implemented, never drifting.
|
|
25
|
+
*
|
|
26
|
+
* Everything emitted is **JSON-serializable** by construction (only strings /
|
|
27
|
+
* numbers / booleans / arrays / plain objects). A contract-free input emits no
|
|
28
|
+
* `contracts` / `contexts` keys, so the pre-#59 operations document is reproduced
|
|
29
|
+
* byte-for-byte (backward compatibility).
|
|
30
|
+
*
|
|
31
|
+
* ## What this issue serializes vs. defers
|
|
32
|
+
*
|
|
33
|
+
* The #58 IR captures a single declarative op per method with a boolean `select`
|
|
34
|
+
* projection; it does **not** model External Query / Query Composition (no
|
|
35
|
+
* `query(Contract.method, { from(...) })` primitive exists yet). So no #58
|
|
36
|
+
* contract produces a `compose`. The serializer nonetheless **supports** it: when
|
|
37
|
+
* a method op carries composition (a forward-compatible {@link ContractMethodOp}
|
|
38
|
+
* extension), it is emitted per the proposal's `compose` shape. The N+1 checker
|
|
39
|
+
* (#60), boundary lint (#61), and runtime execution (#62) are out of scope here —
|
|
40
|
+
* this is serialization + generator only.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A contract as accepted by the serializer: either a resolved
|
|
45
|
+
* {@link QueryModelContract} or a {@link CommandModelContract} (the #58 factory
|
|
46
|
+
* output). The Key type is erased — the serializer reads the key **fields** off
|
|
47
|
+
* the resolved op / model metadata, not the phantom type.
|
|
48
|
+
*/
|
|
49
|
+
type AnyModelContract = QueryModelContract<unknown, Record<string, QueryMethodSpec<unknown, unknown, unknown>>> | CommandModelContract<unknown, Record<string, CommandMethodSpec<unknown, unknown, unknown>>>;
|
|
50
|
+
/** A map of contract name → resolved contract IR (as passed to the generator). */
|
|
51
|
+
type ContractMap = Record<string, AnyModelContract>;
|
|
52
|
+
/**
|
|
53
|
+
* A context-ownership declaration as authored by the producer: context name →
|
|
54
|
+
* the Model (entity) and Contract names that belong to it. The serializer sorts
|
|
55
|
+
* the member lists deterministically; see {@link ContextSpec}.
|
|
56
|
+
*/
|
|
57
|
+
interface ContextOwnership {
|
|
58
|
+
readonly models?: readonly string[];
|
|
59
|
+
readonly contracts?: readonly string[];
|
|
60
|
+
}
|
|
61
|
+
/** A map of context name → its membership (as passed to the generator). */
|
|
62
|
+
type ContextOwnershipMap = Record<string, ContextOwnership>;
|
|
63
|
+
/**
|
|
64
|
+
* The output of {@link buildContracts}: the `contracts` map and the
|
|
65
|
+
* **synthesized** operation specs each method references. The caller merges the
|
|
66
|
+
* synthesized `queries` / `commands` / `transactions` into the document's
|
|
67
|
+
* existing maps (a contract method's referenced op lives alongside hand-written
|
|
68
|
+
* definitions, addressed by name).
|
|
69
|
+
*/
|
|
70
|
+
interface BuiltContracts {
|
|
71
|
+
readonly contracts: Record<string, ContractSpec>;
|
|
72
|
+
/** Synthesized read ops referenced by query contract methods. */
|
|
73
|
+
readonly queries: Record<string, QuerySpec>;
|
|
74
|
+
/** Synthesized write ops referenced by command contract methods (single form). */
|
|
75
|
+
readonly commands: Record<string, CommandSpec>;
|
|
76
|
+
/**
|
|
77
|
+
* Synthesized transactions referenced by command contract methods whose array
|
|
78
|
+
* form resolves to a `'transact'` batched write (issue #64). One transaction per
|
|
79
|
+
* such method, named `<Contract>__<method>__batch`: a single `forEach`-over-keys
|
|
80
|
+
* write item that the runtime expands once per key (≤25, atomic), reusing the
|
|
81
|
+
* proven declarative-transaction machinery (#46). Empty when no command method
|
|
82
|
+
* declares a `'transact'` batch.
|
|
83
|
+
*/
|
|
84
|
+
readonly transactions: Record<string, TransactionSpec>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The derived-effect family of one serialized prepared-write transaction item
|
|
88
|
+
* (issue #208). Index-aligned to `TransactionSpec.items`; the AOT loader groups
|
|
89
|
+
* rendered items by category ACROSS the plan's ops so the composed
|
|
90
|
+
* `TransactWriteItems` matches the in-process execution core's order
|
|
91
|
+
* (writes, then all edges, then all derived updates, …) byte-for-byte.
|
|
92
|
+
*/
|
|
93
|
+
type PreparedWriteItemCategory = 'base' | 'edge' | 'derive' | 'unique' | 'outbox' | 'idempotency' | 'maintain' | 'maintainOutbox' | 'check';
|
|
94
|
+
/**
|
|
95
|
+
* Serialize a map of resolved contracts into the `contracts` SSoT map plus the
|
|
96
|
+
* synthesized operation specs each method references. Deterministic: contracts
|
|
97
|
+
* and methods are emitted in sorted-key order.
|
|
98
|
+
*
|
|
99
|
+
* @param contracts Contract name → resolved {@link QueryModelContract} /
|
|
100
|
+
* {@link CommandModelContract} (the #58 factory output). Empty → empty output.
|
|
101
|
+
* @throws if a contract method op cannot be serialized (a non-boolean projection
|
|
102
|
+
* slot, an unsupported write condition); or if a contract violates an N+1
|
|
103
|
+
* safety rule (#60, {@link assertContractN1Safe}) — an array into a `range`
|
|
104
|
+
* method, a "list under a list", or a `range` composed child.
|
|
105
|
+
*/
|
|
106
|
+
declare function buildContracts(contracts?: ContractMap): BuiltContracts;
|
|
107
|
+
/**
|
|
108
|
+
* Serialize the context-ownership declarations into the SSoT `contexts` map.
|
|
109
|
+
* Member lists are sorted for determinism. An empty input yields an empty map
|
|
110
|
+
* (the caller then omits the key for backward compatibility).
|
|
111
|
+
*/
|
|
112
|
+
declare function buildContexts(contexts?: ContextOwnershipMap): Record<string, ContextSpec>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Static prepared-plan artifact — the SHARED, dependency-minimal half of the
|
|
116
|
+
* AOT pipeline (issue #208; layering fixed by #223).
|
|
117
|
+
*
|
|
118
|
+
* This module carries everything BOTH sides of the pipeline need:
|
|
119
|
+
*
|
|
120
|
+
* - the artifact shapes ({@link PreparedPlanDocument} and friends),
|
|
121
|
+
* - the format version ({@link PREPARED_FORMAT_VERSION}),
|
|
122
|
+
* - canonical JSON ({@link canonicalJson}) and the drift-detection
|
|
123
|
+
* fingerprints ({@link entityFingerprint} / {@link planFingerprint}).
|
|
124
|
+
*
|
|
125
|
+
* ## Layering (#223)
|
|
126
|
+
*
|
|
127
|
+
* The dependency direction is strictly one-way:
|
|
128
|
+
*
|
|
129
|
+
* ```
|
|
130
|
+
* emitter (src/spec/prepared.ts, build-time) ──▶ THIS MODULE
|
|
131
|
+
* loader (src/runtime/prepared-loader.ts) ──▶ THIS MODULE
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* The loader must NEVER import the emitter: the emitter drags the whole
|
|
135
|
+
* build-time spec machinery into the runtime bundle (`dist/index.js`), which
|
|
136
|
+
* is exactly the leak the size-limit CI gate caught in #223. This module's
|
|
137
|
+
* only value-level dependencies are ones the loader already carries
|
|
138
|
+
* (`buildManifestEntity` / spec types).
|
|
139
|
+
*
|
|
140
|
+
* ## Fingerprints are checksums, not cryptography
|
|
141
|
+
*
|
|
142
|
+
* The fingerprint exists to detect DRIFT (model declarations changed since
|
|
143
|
+
* the artifact was generated). It is not a security boundary, so it uses a
|
|
144
|
+
* pure-TypeScript FNV-1a 64-bit hash — no `node:crypto`, no platform builtin,
|
|
145
|
+
* bundles everywhere. Switching the algorithm (sha-256 → FNV-1a) is what
|
|
146
|
+
* bumped {@link PREPARED_FORMAT_VERSION} '1' → '2': a format-'1' artifact's
|
|
147
|
+
* fingerprints can never match, so the loader rejects the version loudly
|
|
148
|
+
* instead of failing the comparison confusingly.
|
|
149
|
+
*/
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The prepared-plan artifact format version (independent of {@link SPEC_VERSION}).
|
|
153
|
+
*
|
|
154
|
+
* '2' (#223): fingerprints are FNV-1a 64-bit over canonical JSON (16 hex
|
|
155
|
+
* chars). '1' (#208, graphddb ≤ 0.7.2) used sha-256 via `node:crypto`; the
|
|
156
|
+
* loader rejects '1' artifacts with a regeneration instruction.
|
|
157
|
+
*/
|
|
158
|
+
declare const PREPARED_FORMAT_VERSION: "2";
|
|
159
|
+
/**
|
|
160
|
+
* One serialized value bind: a `$`-param slot (bound from the caller's
|
|
161
|
+
* `execute(params)` by name) or a static literal recorded at build time. `Date`
|
|
162
|
+
* and `bigint` literals — which JSON cannot carry natively — are encoded
|
|
163
|
+
* explicitly and revived by the loader, so the bound value is the SAME typed
|
|
164
|
+
* value the runtime `prepare` would have captured.
|
|
165
|
+
*/
|
|
166
|
+
type PreparedBindSpec = {
|
|
167
|
+
readonly param: string;
|
|
168
|
+
} | {
|
|
169
|
+
readonly literal: string | number | boolean | null;
|
|
170
|
+
} | {
|
|
171
|
+
readonly literalDate: string;
|
|
172
|
+
} | {
|
|
173
|
+
readonly literalBigInt: string;
|
|
174
|
+
};
|
|
175
|
+
/** A `{ field: bind }` map (a serialized slot map). */
|
|
176
|
+
type PreparedBindMap = Readonly<Record<string, PreparedBindSpec>>;
|
|
177
|
+
/** One serialized read route of a prepared READ plan. */
|
|
178
|
+
interface PreparedReadRouteSpec {
|
|
179
|
+
readonly alias: string;
|
|
180
|
+
readonly op: 'query' | 'list';
|
|
181
|
+
/** The target entity name (re-bound via the registry at load). */
|
|
182
|
+
readonly entity: string;
|
|
183
|
+
/** The static, params-independent select template (JSON-safe by the #206 lint). */
|
|
184
|
+
readonly select: Record<string, unknown>;
|
|
185
|
+
/** Key-field binds (`{ field: { param | literal } }`). */
|
|
186
|
+
readonly key: PreparedBindMap;
|
|
187
|
+
/** Static option literals decided at build time. */
|
|
188
|
+
readonly maxDepth?: number;
|
|
189
|
+
readonly order?: 'ASC' | 'DESC';
|
|
190
|
+
readonly filter?: Record<string, unknown>;
|
|
191
|
+
/** Dynamic option binds (a `$` param or a literal, decided per call). */
|
|
192
|
+
readonly consistentRead?: PreparedBindSpec;
|
|
193
|
+
readonly limit?: PreparedBindSpec;
|
|
194
|
+
readonly after?: PreparedBindSpec;
|
|
195
|
+
/**
|
|
196
|
+
* The spec-IR read plan (`operations.json` vocabulary: physical ops, templated
|
|
197
|
+
* `{<field>}` key conditions, relation fan-outs, execution plan) derived from
|
|
198
|
+
* this route at build time. Key-condition tokens are the entity's key FIELD
|
|
199
|
+
* names; the per-call param→field mapping is {@link key}. Deriving it at build
|
|
200
|
+
* time surfaces a broken route as a BUILD failure and freezes the physical
|
|
201
|
+
* plan for drift comparison.
|
|
202
|
+
*/
|
|
203
|
+
readonly query: QuerySpec;
|
|
204
|
+
}
|
|
205
|
+
/** One serialized write op of a prepared WRITE plan. */
|
|
206
|
+
interface PreparedWriteOpSpec {
|
|
207
|
+
readonly alias: string;
|
|
208
|
+
readonly entity: string;
|
|
209
|
+
readonly intent: 'create' | 'update' | 'remove' | 'upsert';
|
|
210
|
+
/** The target model's primary-key input fields (W1 key/changes split + read-back key). */
|
|
211
|
+
readonly keyFields: readonly string[];
|
|
212
|
+
/** Key-field binds. */
|
|
213
|
+
readonly key: PreparedBindMap;
|
|
214
|
+
/** Input-field binds. */
|
|
215
|
+
readonly input: PreparedBindMap;
|
|
216
|
+
/** In-process write-gate binds (flat equality / existence template), if declared. */
|
|
217
|
+
readonly condition?: PreparedBindMap;
|
|
218
|
+
/** The read-back projection + options, verbatim (JSON-safe by the #206 lint). */
|
|
219
|
+
readonly result?: {
|
|
220
|
+
readonly select?: Record<string, unknown>;
|
|
221
|
+
readonly options?: {
|
|
222
|
+
readonly consistentRead?: boolean;
|
|
223
|
+
readonly maxDepth?: number;
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* The consistent read-back's spec-IR plan (derived from `result.select` at
|
|
228
|
+
* build time — a broken read-back projection fails the BUILD). Present iff
|
|
229
|
+
* {@link result} declares a non-empty select.
|
|
230
|
+
*/
|
|
231
|
+
readonly readback?: QuerySpec;
|
|
232
|
+
/**
|
|
233
|
+
* The op's full declarative {@link TransactionSpec}: `items[0]` is the base
|
|
234
|
+
* write, followed by every derived effect the mutation compiler resolved at
|
|
235
|
+
* build time. Templates bind `{<field>}` tokens — the op's key/input FIELD
|
|
236
|
+
* names — which the loader renders from the per-call bound field values.
|
|
237
|
+
*/
|
|
238
|
+
readonly transaction: TransactionSpec;
|
|
239
|
+
/** Per-item derived-effect categories, index-aligned to `transaction.items`. */
|
|
240
|
+
readonly categories: readonly PreparedWriteItemCategory[];
|
|
241
|
+
}
|
|
242
|
+
/** One compiled prepared plan (all routes of one `DDBModel.prepare` body). */
|
|
243
|
+
interface PreparedPlanSpec {
|
|
244
|
+
readonly kind: 'read' | 'write';
|
|
245
|
+
/**
|
|
246
|
+
* The `$` params the plan binds (union across routes), with kinds recovered
|
|
247
|
+
* from the bound entity fields where determinable.
|
|
248
|
+
*/
|
|
249
|
+
readonly params: Readonly<Record<string, ParamSpec>>;
|
|
250
|
+
/**
|
|
251
|
+
* Entity name → fingerprint of its canonical manifest entry at build time.
|
|
252
|
+
* The loader recomputes these from the live registry and LOUDLY rejects a
|
|
253
|
+
* mismatch (stale plan / model drift).
|
|
254
|
+
*/
|
|
255
|
+
readonly entities: Readonly<Record<string, string>>;
|
|
256
|
+
/** Read routes, in body declaration order (read plans only). */
|
|
257
|
+
readonly reads?: readonly PreparedReadRouteSpec[];
|
|
258
|
+
/** Write ops, in body declaration order (write plans only). */
|
|
259
|
+
readonly writes?: readonly PreparedWriteOpSpec[];
|
|
260
|
+
}
|
|
261
|
+
/** The full static prepared-plan artifact. */
|
|
262
|
+
interface PreparedPlanDocument {
|
|
263
|
+
readonly formatVersion: typeof PREPARED_FORMAT_VERSION;
|
|
264
|
+
/** The shared operation-IR version the plans were compiled against. */
|
|
265
|
+
readonly specVersion: typeof SPEC_VERSION;
|
|
266
|
+
/** Plan id (the transform's stable call-site id) → compiled plan. */
|
|
267
|
+
readonly plans: Readonly<Record<string, PreparedPlanSpec>>;
|
|
268
|
+
}
|
|
269
|
+
/** Deterministic JSON: object keys sorted at every level (arrays keep order). */
|
|
270
|
+
declare function canonicalJson(value: unknown): string;
|
|
271
|
+
/**
|
|
272
|
+
* The fingerprint of one entity's canonical manifest entry — every plan-relevant
|
|
273
|
+
* declaration fact (table, physical name, prefix, fields + formats, key / GSI
|
|
274
|
+
* templates, relations incl. `refs` bindings, TTL). Computed identically at
|
|
275
|
+
* build (emit) and at load (live registry), so any drift is caught.
|
|
276
|
+
*/
|
|
277
|
+
declare function entityFingerprint(metadata: EntityMetadata): string;
|
|
278
|
+
/** Stable content hash of a compiled plan (drift-check convenience). */
|
|
279
|
+
declare function planFingerprint(plan: PreparedPlanSpec): string;
|
|
280
|
+
|
|
281
|
+
export { type AnyModelContract as A, type BuiltContracts as B, type ContractMap as C, type PreparedWriteOpSpec as P, type PreparedPlanDocument as a, type PreparedBindSpec as b, type PreparedPlanSpec as c, type PreparedReadRouteSpec as d, type ContextOwnershipMap as e, type ContextOwnership as f, PREPARED_FORMAT_VERSION as g, type PreparedBindMap as h, buildContexts as i, buildContracts as j, canonicalJson as k, entityFingerprint as l, planFingerprint as p };
|