graphddb 0.2.5 → 0.3.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.
@@ -1003,7 +1003,7 @@ interface Executor {
1003
1003
 
1004
1004
  /**
1005
1005
  * Write middleware / hook public surface (issue #50 write path, #139). The merged
1006
- * design is `docs/proposals/read-middleware.md`; this module implements the
1006
+ * design is `docs/middleware.md`; this module implements the
1007
1007
  * **write** hook points W1–W5 and their context objects, layered on the SAME
1008
1008
  * registry / runtime machinery the read hooks (#138) introduced.
1009
1009
  *
@@ -1014,18 +1014,18 @@ interface Executor {
1014
1014
  * the TS↔Python bridge (#48) is unaffected. It is **unrestricted by intent**: a
1015
1015
  * hook may observe, mutate `ctx`, `throw` to cancel, or (on `onError`) recover by
1016
1016
  * returning a value. The library does NOT validate hook logic or impose semantics
1017
- * (proposal appendix A). The internal CDC / capture mechanism (`src/capture/`,
1017
+ * (see docs/middleware.md). The internal CDC / capture mechanism (`src/capture/`,
1018
1018
  * `src/cdc/`) is a SEPARATE surface — write hooks are not a substitute for it nor
1019
- * it for them (proposal appendix C).
1019
+ * it for them (see docs/middleware.md).
1020
1020
  *
1021
- * @see docs/proposals/read-middleware.md (hook points W1–W5)
1021
+ * @see docs/middleware.md (hook points W1–W5)
1022
1022
  */
1023
1023
 
1024
1024
  /**
1025
1025
  * The logical write kinds a {@link WriteCtx} may carry (W1 / W2 / W5). A W1 hook
1026
1026
  * may REWRITE this in place — the canonical case is a `delete` → `update`
1027
1027
  * (soft-delete-by-rewrite); derivation then runs on the rewritten op, so the
1028
- * stored effect is the update, not the delete (proposal W1 + examples).
1028
+ * stored effect is the update, not the delete (see docs/middleware.md).
1029
1029
  */
1030
1030
  type WriteKind = 'put' | 'update' | 'delete';
1031
1031
  /**
@@ -1122,9 +1122,9 @@ interface PersistCtx {
1122
1122
  * The write half of a registered {@link import('./types.js').Middleware}. Any
1123
1123
  * subset of the write hook points may be set; an unset hook is skipped. All hooks
1124
1124
  * are async-first — the runtime always `await`s, so sync and async hooks compose
1125
- * uniformly (proposal "sync / async").
1125
+ * uniformly (see docs/middleware.md).
1126
1126
  *
1127
- * @see docs/proposals/read-middleware.md (hook points W1–W5)
1127
+ * @see docs/middleware.md (hook points W1–W5)
1128
1128
  */
1129
1129
  interface WriteMiddleware {
1130
1130
  /** W1 — logical write, before effect derivation. May mutate `ctx.input` / `ctx.kind`; `throw` cancels (in a tx, aborts all). */
@@ -1157,7 +1157,7 @@ interface WriteMiddleware {
1157
1157
 
1158
1158
  /**
1159
1159
  * Read middleware / hook public surface (issue #50, implemented for the read
1160
- * path in #138). The merged design is `docs/proposals/read-middleware.md`; this
1160
+ * path in #138). The merged design is `docs/middleware.md`; this
1161
1161
  * module implements the **read** hook points R1–R5 and their context objects.
1162
1162
  *
1163
1163
  * A {@link Middleware} is a host-only, runtime-registered object (registered via
@@ -1167,9 +1167,9 @@ interface WriteMiddleware {
1167
1167
  * `operations.json`, so the TS↔Python bridge (#48) is unaffected. Hooks are
1168
1168
  * **unrestricted by intent**: a hook may observe, mutate `ctx`, `throw` to
1169
1169
  * cancel, or return a replacement value. The library does NOT validate hook
1170
- * logic or impose semantics — see the proposal appendix A.
1170
+ * logic or impose semantics — see docs/middleware.md.
1171
1171
  *
1172
- * @see docs/proposals/read-middleware.md
1172
+ * @see docs/middleware.md
1173
1173
  */
1174
1174
 
1175
1175
  /** A raw DynamoDB item (the shape R3 sees, per-op). */
@@ -1196,7 +1196,7 @@ interface CtxBase {
1196
1196
  /**
1197
1197
  * Scratch space shared across this op's phases (R2 → R3 → R5 for one op, or
1198
1198
  * R1 → R4 → R5 for the request). A fresh object per request context object;
1199
- * each fan-out op gets its own `state` (see proposal appendix D — siblings run
1199
+ * each fan-out op gets its own `state` ((docs/middleware.md) — siblings run
1200
1200
  * concurrently, so a shared accumulator should live on a host object via
1201
1201
  * `context`, updated commutatively).
1202
1202
  */
@@ -1278,10 +1278,10 @@ interface ReadOpCtx extends CtxBase {
1278
1278
  /**
1279
1279
  * A registered read middleware object. Any subset of the read hook points may
1280
1280
  * be set; an unset hook is simply skipped. All hooks may be synchronous or
1281
- * return a `Promise` — the runtime always `await`s (async-first, see proposal
1281
+ * return a `Promise` — the runtime always `await`s (async-first, see docs/middleware.md
1282
1282
  * "sync / async").
1283
1283
  *
1284
- * @see docs/proposals/read-middleware.md (the write hooks W1–W5 are a later phase)
1284
+ * @see docs/middleware.md (the write hooks W1–W5 are a later phase)
1285
1285
  */
1286
1286
  interface Middleware {
1287
1287
  /** Optional name (for host-side debugging / ordering introspection). */
@@ -1301,7 +1301,7 @@ interface Middleware {
1301
1301
  * an `Item[]`: those become this op's items and the read pipeline continues
1302
1302
  * (the first hook that returns a value wins and short-circuits the chain).
1303
1303
  * Return `void` / `undefined` to decline — if no hook recovers, the original
1304
- * error rethrows. (See proposal R5 + appendix A — hooks are unrestricted.)
1304
+ * error rethrows. (see docs/middleware.md — hooks are unrestricted.)
1305
1305
  */
1306
1306
  onError?(ctx: ReadOpCtx, err: unknown): void | Item[] | Promise<void | Item[]>;
1307
1307
  };
@@ -1969,6 +1969,259 @@ interface DeriveEffect {
1969
1969
  /** The amount to add (for an increment). */
1970
1970
  readonly amount: number;
1971
1971
  }
1972
+ /**
1973
+ * A model lifecycle event that triggers a maintenance effect, expressed as an
1974
+ * `Entity.event` string — the source entity's class name, a dot, then one of the
1975
+ * lifecycle events. The three events mirror {@link WriteLifecyclePhase}
1976
+ * (`create` / `update` / `remove`) in past-tense event form, so a maintenance
1977
+ * effect is keyed by *what happened* to the source row.
1978
+ *
1979
+ * The string is **branded** ({@link MaintainTrigger}) so a raw `string` is not
1980
+ * accepted where a validated trigger is required; construct one with
1981
+ * {@link maintainTrigger}, which rejects a malformed value.
1982
+ *
1983
+ * @example `'Post.created'`, `'User.updated'`, `'Comment.removed'`
1984
+ */
1985
+ type MaintainEvent = 'created' | 'updated' | 'removed';
1986
+ /** The brand carried by a validated {@link MaintainTrigger}. */
1987
+ declare const MAINTAIN_TRIGGER_BRAND: unique symbol;
1988
+ /**
1989
+ * A validated `Entity.event` maintenance trigger string (e.g. `'Post.created'`).
1990
+ * Branded so it is told apart from a raw `string`; build one with
1991
+ * {@link maintainTrigger}. The shape is `${EntityName}.${MaintainEvent}` where
1992
+ * `EntityName` is a non-empty identifier-ish token.
1993
+ */
1994
+ type MaintainTrigger = `${string}.${MaintainEvent}` & {
1995
+ readonly [MAINTAIN_TRIGGER_BRAND]: true;
1996
+ };
1997
+ /**
1998
+ * Construct a validated {@link MaintainTrigger} from an `Entity.event` string.
1999
+ * Rejects a value that is not a non-empty entity name followed by `.created` /
2000
+ * `.updated` / `.removed`, so an invalid trigger is refused at construction time
2001
+ * (the AC's "invalid trigger string is rejected"). The brand is a compile-time
2002
+ * marker only; the returned value is the input string verbatim.
2003
+ *
2004
+ * @throws if `value` is not a well-formed `Entity.event` trigger string.
2005
+ */
2006
+ declare function maintainTrigger(value: string): MaintainTrigger;
2007
+ /** Runtime guard: is `value` a well-formed {@link MaintainTrigger} string? */
2008
+ declare function isMaintainTrigger(value: unknown): value is MaintainTrigger;
2009
+ /**
2010
+ * A projection transform op (issue #120, 論点3 = 関数形): the function-form
2011
+ * `w.transform(path, op, ...args)` is the **primary** authoring surface (there is
2012
+ * no string DSL). The initial op set is:
2013
+ *
2014
+ * - `identity` — copy the source path through unchanged (no args).
2015
+ * - `preview` — keep a length-bounded preview of the source value; `n` is the
2016
+ * bound (`w.transform('$.body', 'preview', 200)`).
2017
+ *
2018
+ * New ops extend this union (and {@link ProjectionTransform}'s `args` shape) as
2019
+ * the maintenance graph (#124) needs them.
2020
+ */
2021
+ type ProjectionTransformOp = 'identity' | 'preview';
2022
+ /**
2023
+ * One entry in a maintenance projection map: a `w.transform(path, op, ...args)`
2024
+ * IR node binding a source {@link EffectPath} to a target attribute through a
2025
+ * {@link ProjectionTransformOp}. `args` carries the op's positional arguments
2026
+ * (e.g. `preview`'s length bound); `identity` carries none.
2027
+ *
2028
+ * The function form is the only authoring surface (no string DSL); the node is a
2029
+ * plain branded record so the maintenance graph (#124) and compile injection
2030
+ * (#125) can read it without retaining a closure.
2031
+ */
2032
+ interface ProjectionTransform {
2033
+ readonly kind: 'transform';
2034
+ /** The path-rooted source value (`$.input.*` / `$.entity.*`). */
2035
+ readonly path: EffectPath;
2036
+ /** The transform op applied to the source value. */
2037
+ readonly op: ProjectionTransformOp;
2038
+ /** The op's positional arguments (e.g. `[200]` for `preview`); empty for `identity`. */
2039
+ readonly args: readonly unknown[];
2040
+ }
2041
+ /**
2042
+ * A maintenance **projection map**: target attribute name → its
2043
+ * {@link ProjectionTransform}. Generalizes the way {@link DeriveEffect} names a
2044
+ * single derived `attribute`, to a whole projected row / collection item.
2045
+ */
2046
+ type ProjectionMap = Readonly<Record<string, ProjectionTransform>>;
2047
+ /**
2048
+ * Standalone authoring helper for a `preview` {@link ProjectionTransform}: keep a
2049
+ * length-bounded preview of the source `path` (the first `n` characters). This is
2050
+ * the recorder-free counterpart to `w.transform(path, 'preview', n)` — used where
2051
+ * there is no {@link WriteRecorder} `w`, the relation-options decorator arguments
2052
+ * (epic #118 §5.2 / issue #121, e.g. `projection: { textPreview: preview('body',
2053
+ * 120) }`). It produces the **same** IR node as `w.transform` (both route through
2054
+ * {@link makeProjectionTransform}), so the two surfaces never diverge.
2055
+ *
2056
+ * @param path The source value the preview is taken of (a projection source path).
2057
+ * @param n The preview length bound (a positive integer).
2058
+ * @throws if `n` is not a positive integer.
2059
+ */
2060
+ declare function preview(path: EffectPath, n: number): ProjectionTransform;
2061
+ /**
2062
+ * Standalone authoring helper for an `identity` {@link ProjectionTransform}: copy
2063
+ * the source `path` through unchanged. The recorder-free counterpart to
2064
+ * `w.transform(path, 'identity')`. In relation-options `projection` maps a bare
2065
+ * `string` path is the idiomatic identity shorthand; this helper is provided for
2066
+ * symmetry / when an explicit IR node is wanted. Routes through
2067
+ * {@link makeProjectionTransform} so it is structurally identical to the recorder
2068
+ * form.
2069
+ *
2070
+ * @param path The source value copied through unchanged.
2071
+ */
2072
+ declare function identity(path: EffectPath): ProjectionTransform;
2073
+ /**
2074
+ * The **path** a maintenance write travels (shared vocabulary, epic #118 A/B
2075
+ * reconciliation — RFC §5.1 / issue #121 are the authority). `mutation` lands the
2076
+ * maintenance write **synchronously**, in the same `TransactWriteItems` as the
2077
+ * source mutation; `stream` defers it to the **asynchronous** Streams path. This
2078
+ * is the path axis, NOT a write-reconciliation axis.
2079
+ *
2080
+ * NOTE: A(#120) previously defined `updateMode` as an *invented* write-reconcile
2081
+ * axis (`'overwrite' | 'ifNewer'`); that axis is **removed for Phase 1** (論点2=b
2082
+ * fixes "1 mutation × 1 target row = 1 effect", so no reconcile is needed) and the
2083
+ * name is reclaimed for the path vocabulary above. A reconcile axis may be
2084
+ * reintroduced later under a *different* name if a future phase needs it.
2085
+ */
2086
+ type MaintainUpdateMode = 'mutation' | 'stream';
2087
+ /**
2088
+ * The read/write consistency a maintenance effect is realized under (shared
2089
+ * vocabulary, epic #118 A/B reconciliation — RFC §5.1 / issue #121 are the
2090
+ * authority). `transactional` requires the maintenance write to land in the same
2091
+ * transaction as the source write; `eventual` (the default the consumers assume
2092
+ * when omitted) lets it lag. A's earlier `'strong'` value is **retired** in favor
2093
+ * of `'transactional'`.
2094
+ */
2095
+ type MaintainConsistency = 'transactional' | 'eventual';
2096
+ /**
2097
+ * A **snapshot** maintenance effect (issue #120): on a {@link MaintainTrigger}
2098
+ * the source's {@link project} is mirrored into a single target row resolved by
2099
+ * {@link targetFactory} + {@link keys}. Generalizes {@link DeriveEffect} from a
2100
+ * single scalar `ADD`/`SET` to a projected row. Consumed by the maintenance graph
2101
+ * (#124) and compile injection (#125); #120 defines the type only.
2102
+ */
2103
+ interface SnapshotEffect {
2104
+ readonly kind: 'snapshot';
2105
+ /** The lifecycle event of the source entity that drives the snapshot. */
2106
+ readonly trigger: MaintainTrigger;
2107
+ /** Resolves the target entity whose row holds the snapshot. */
2108
+ readonly targetFactory: () => new (...args: unknown[]) => unknown;
2109
+ /** The key binding of the target row (path-rooted values). */
2110
+ readonly keys: Readonly<Record<string, EffectPath>>;
2111
+ /** The projection map: target attribute → `w.transform(...)` IR. */
2112
+ readonly project: ProjectionMap;
2113
+ /** The path the write travels — synchronous `mutation` tx or async `stream`. */
2114
+ readonly updateMode?: MaintainUpdateMode;
2115
+ /** The consistency the write lands under (default `eventual`). */
2116
+ readonly consistency?: MaintainConsistency;
2117
+ }
2118
+ /**
2119
+ * Options for the bounded collection a {@link CollectionEffect} maintains: the
2120
+ * target {@link field} that holds the collection, an optional {@link maxItems}
2121
+ * cap (oldest items are evicted past it), and an optional {@link orderBy} source
2122
+ * path the items are ordered by.
2123
+ */
2124
+ interface CollectionOptions {
2125
+ /** The target attribute that holds the maintained collection. */
2126
+ readonly field: string;
2127
+ /** Cap on the collection size; items past it are evicted (unbounded if omitted). */
2128
+ readonly maxItems?: number;
2129
+ /** A path-rooted source value the collection is ordered by (e.g. `$.entity.createdAt`). */
2130
+ readonly orderBy?: EffectPath;
2131
+ }
2132
+ /**
2133
+ * A **collection** maintenance effect (issue #120): on a {@link MaintainTrigger}
2134
+ * the source's {@link project} is appended as an item into the bounded collection
2135
+ * named by {@link collection} on the target row resolved by {@link targetFactory}
2136
+ * + {@link keys}. Generalizes {@link DeriveEffect} to a bounded list projection.
2137
+ * Consumed by the maintenance graph (#124) and compile injection (#125); #120
2138
+ * defines the type only.
2139
+ */
2140
+ interface CollectionEffect {
2141
+ readonly kind: 'collection';
2142
+ /** The lifecycle event of the source entity that drives the collection write. */
2143
+ readonly trigger: MaintainTrigger;
2144
+ /** Resolves the target entity whose row holds the collection. */
2145
+ readonly targetFactory: () => new (...args: unknown[]) => unknown;
2146
+ /** The key binding of the target row (path-rooted values). */
2147
+ readonly keys: Readonly<Record<string, EffectPath>>;
2148
+ /** The projection map for each collection item: attribute → `w.transform(...)` IR. */
2149
+ readonly project: ProjectionMap;
2150
+ /** The bounded-collection options (`field` / `maxItems` / `orderBy`). */
2151
+ readonly collection: CollectionOptions;
2152
+ /** The path the write travels — synchronous `mutation` tx or async `stream`. */
2153
+ readonly updateMode?: MaintainUpdateMode;
2154
+ /** The consistency the write lands under (default `eventual`). */
2155
+ readonly consistency?: MaintainConsistency;
2156
+ }
2157
+ /**
2158
+ * The aggregation a {@link CounterEffect} maintains (Epic #118 §5.2 counter /
2159
+ * latest preset; issue #141). The function-form IR `count()` / `max(field)` the
2160
+ * `@aggregate` value helpers build, lifted into the maintenance IR:
2161
+ *
2162
+ * - `count` — the cardinality of the matched source rows: a `created` trigger
2163
+ * adds `+1`, a `removed` trigger adds `-1` (the {@link CounterEffect.delta}).
2164
+ * - `max` — the running maximum of a named source `field`. A synchronous
2165
+ * transactional max cannot be expressed as a concurrency-safe single-item
2166
+ * `UpdateExpression` (a conditional `SET` whose guard fails would roll back the
2167
+ * *source* write that legitimately happened), so Phase 1 records the IR but the
2168
+ * compile injection (#141) rejects it for the synchronous `mutation` path —
2169
+ * `max` is the asynchronous stream path (#130, Phase 2). The op is kept here so
2170
+ * the IR is complete and the reject is precise.
2171
+ */
2172
+ type CounterAggregate = {
2173
+ readonly op: 'count';
2174
+ } | {
2175
+ readonly op: 'max';
2176
+ readonly field: string;
2177
+ };
2178
+ /**
2179
+ * A **counter** maintenance effect (Epic #118 §5.2 counter preset; issue #141): on
2180
+ * a {@link MaintainTrigger} a scalar aggregate on a single target row resolved by
2181
+ * {@link targetFactory} + {@link keys} is kept in sync with the source entity's
2182
+ * lifecycle. Where {@link SnapshotEffect} mirrors a projection and
2183
+ * {@link CollectionEffect} appends an item, a counter applies an atomic scalar
2184
+ * `ADD` — the maintenance-pipeline generalization of the self-lifecycle
2185
+ * {@link DeriveEffect} (`w.increment`, #85), but driven by a CROSS-entity
2186
+ * `maintainedOn` trigger rather than the written entity's own lifecycle.
2187
+ *
2188
+ * For `value.op === 'count'` the {@link delta} is the signed amount the trigger
2189
+ * applies (`+1` on `created`, `-1` on `removed`); the maintenance graph (#124)
2190
+ * derives it from the trigger event. Two counter effects targeting the SAME row in
2191
+ * one mutation MERGE (the symmetric-ADD collapse #92), unlike snapshot/collection
2192
+ * which reject a same-row collision — an `ADD` is commutative.
2193
+ *
2194
+ * Consumed by the maintenance graph (#124, `em.aggregates` walk) and the compile
2195
+ * injection (#141, `DerivedMaintainWrite` of `kind: 'counter'`).
2196
+ */
2197
+ interface CounterEffect {
2198
+ readonly kind: 'counter';
2199
+ /** The lifecycle event of the source entity that drives the counter. */
2200
+ readonly trigger: MaintainTrigger;
2201
+ /** Resolves the target entity whose row holds the counter scalar. */
2202
+ readonly targetFactory: () => new (...args: unknown[]) => unknown;
2203
+ /** The key binding of the target row (path-rooted values). */
2204
+ readonly keys: Readonly<Record<string, EffectPath>>;
2205
+ /** The target attribute the aggregate scalar is written to (e.g. `postCount`). */
2206
+ readonly attribute: string;
2207
+ /** The aggregation maintained (`count()` / `max(field)`). */
2208
+ readonly value: CounterAggregate;
2209
+ /**
2210
+ * For `value.op === 'count'`, the signed `ADD` delta this trigger applies
2211
+ * (`+1` created / `-1` removed). Absent for `max` (not realized synchronously).
2212
+ */
2213
+ readonly delta?: number;
2214
+ /** The path the write travels — synchronous `mutation` tx or async `stream`. */
2215
+ readonly updateMode?: MaintainUpdateMode;
2216
+ /** The consistency the write lands under (default `eventual`). */
2217
+ readonly consistency?: MaintainConsistency;
2218
+ }
2219
+ /**
2220
+ * The union of maintenance effects a {@link SnapshotEffect}, {@link CollectionEffect},
2221
+ * or {@link CounterEffect} can be. The shared IR the maintenance graph (#124) and
2222
+ * compile injection (#125 snapshot/collection, #141 counter) consume.
2223
+ */
2224
+ type MaintainEffect = SnapshotEffect | CollectionEffect | CounterEffect;
1972
2225
  /**
1973
2226
  * A domain event (proposal §2 `emits`): an outbox `Put` drained to Streams /
1974
2227
  * `src/cdc/`. Derived by #87 — stored opaquely here.
@@ -2077,6 +2330,21 @@ interface WriteRecorder {
2077
2330
  deleteEdge(target: () => new (...args: unknown[]) => unknown, relationProperty: string): EdgeEffect;
2078
2331
  /** Declare a derived / cascading update (§2 `derive`; derived #85). */
2079
2332
  increment(target: () => new (...args: unknown[]) => unknown, keys: Readonly<Record<string, EffectPath>>, attribute: string, amount: number): DeriveEffect;
2333
+ /**
2334
+ * Build a projection transform IR node (issue #120, 関数形): the primary
2335
+ * function-form authoring surface for a maintenance projection map entry. The
2336
+ * initial ops are `identity` (no args — copy the source path through) and
2337
+ * `preview` (one numeric arg — keep a length-bounded preview). There is no
2338
+ * string DSL. The returned {@link ProjectionTransform} is consumed by the
2339
+ * maintenance graph (#124) / compile injection (#125).
2340
+ *
2341
+ * NOTE (issue #120 scope): the escape-hatch recorders that *attach* a
2342
+ * {@link SnapshotEffect} / {@link CollectionEffect} to a lifecycle
2343
+ * (`w.snapshotInto` / `w.captureInto`) and the `LifecycleEffects.maintain`
2344
+ * wiring are **Phase 2** and are intentionally NOT part of this recorder.
2345
+ */
2346
+ transform(path: EffectPath, op: 'identity'): ProjectionTransform;
2347
+ transform(path: EffectPath, op: 'preview', n: number): ProjectionTransform;
2080
2348
  /** Declare a domain event (§2 `emits`; derived #87). */
2081
2349
  event(name: string, payload: Readonly<Record<string, EffectPath>>): EmitEffect;
2082
2350
  /** Declare an idempotency guard (§2 `idempotency`; derived #87). */
@@ -2400,6 +2668,163 @@ declare function mutation(name: string, body: MutationBody): CommandPlan;
2400
2668
  */
2401
2669
  declare const definePlan: typeof mutation;
2402
2670
 
2671
+ /**
2672
+ * Maintenance graph builder (Epic #118 issue #124 — the RFC B-案 core).
2673
+ *
2674
+ * ## What this module is
2675
+ *
2676
+ * A relation may declare a **maintenance** side via its relation options
2677
+ * (issue #121, the B work): `write.maintainedOn` lists the cross-entity
2678
+ * lifecycle triggers (`"<Entity>.<event>"`, e.g. `"Post.created"`) that should
2679
+ * keep the relation's materialized shape in sync, and `projection` declares how
2680
+ * the source entity is projected into that shape. This module walks every
2681
+ * registered model (`MetadataRegistry.getAll()`), reads those relation-side
2682
+ * declarations, and builds an **index**:
2683
+ *
2684
+ * trigger source entity × lifecycle event (created/updated/removed)
2685
+ * → list of maintenance effects to apply
2686
+ *
2687
+ * That index is exactly the question the compile-injection step (#125) asks of
2688
+ * a mutation: "this mutation `created` a `Post` — what must be maintained?". This
2689
+ * module answers *which* effect fires for *which* trigger, and validates that
2690
+ * every declared effect is realizable (round-trips with the read side); it does
2691
+ * **not** inject anything into the compiler — see "Scope" below.
2692
+ *
2693
+ * ## Input is relation-side declarations only (論点1 = c)
2694
+ *
2695
+ * The only input is each relation's `options.write.maintainedOn` +
2696
+ * `options.projection` (the #121 relation options). The `entityWrites` escape
2697
+ * hatch (`w.snapshotInto` / `w.captureInto` attached to a lifecycle) is **Phase
2698
+ * 2** and is deliberately not read here.
2699
+ *
2700
+ * ## Reuses the A (#120) maintenance IR — no second definition
2701
+ *
2702
+ * The maintenance effect each index entry carries is the **A-defined IR** —
2703
+ * {@link SnapshotEffect} / {@link CollectionEffect} / {@link ProjectionTransform}
2704
+ * from `src/define/entity-writes.ts` (also re-exported from the root barrel). This
2705
+ * module *synthesizes* those nodes from the relation-side declaration (it is the
2706
+ * relation-options → IR lowering); it never re-defines the IR shapes.
2707
+ *
2708
+ * ## Round-trip validation (流用 of `assertRelationRoundTrips`)
2709
+ *
2710
+ * Mirroring `src/relation/edge-write.ts`'s build-time round-trip guard, the graph
2711
+ * is verified the moment it is built, and a mis-declaration is a **loud reject**:
2712
+ *
2713
+ * - **Snapshot/collection target key points at a real row.** The relation's
2714
+ * `keyBinding` target fields must resolve to a real access pattern on the
2715
+ * target entity (the row that holds the snapshot/collection), via the *same*
2716
+ * {@link resolveKey} the read planner uses. A binding that covers no partition
2717
+ * would write/read an unreachable row → reject.
2718
+ * - **Projection source attributes exist on the source payload (論点4 = payload
2719
+ * 同梱のみ).** Every projection source path (`$.entity.<field>` /
2720
+ * `$.input.<field>`) must name an attribute that the *source* entity (the
2721
+ * trigger origin) actually carries. There is no fetch / re-projection: an
2722
+ * attribute that is not in the source payload is rejected, not fetched.
2723
+ * - **Unresolved trigger.** A trigger whose entity segment names no registered
2724
+ * model, or whose event is not `created`/`updated`/`removed`, is rejected.
2725
+ * - **Cycle.** A maintenance dependency cycle (entity A's event maintains a
2726
+ * shape on B while B's event maintains a shape on A, transitively) is detected
2727
+ * and rejected — an unbounded maintenance cascade.
2728
+ *
2729
+ * ## Scope (#124 only — NOT #125)
2730
+ *
2731
+ * This module builds and validates the index, and exposes enough structure for
2732
+ * the compile-injection step (#125/#126) to consume it — including the material
2733
+ * to detect that *two* maintainers target the **same** target row (論点2 = b,
2734
+ * "1 mutation × 1 target row = 1 effect"). It does **not** resolve maintainers
2735
+ * into the mutation compiler, derive `DerivedMaintainWrite`s, or emit any
2736
+ * transaction items; `resolveMaintainers` / `deriveMaintainItems` are #125's.
2737
+ */
2738
+
2739
+ type ModelClass = new (...args: unknown[]) => unknown;
2740
+ /**
2741
+ * One maintenance effect, keyed in the graph by its {@link trigger}. Synthesized
2742
+ * from a single relation's maintenance declaration (its `write.maintainedOn` +
2743
+ * `projection`).
2744
+ *
2745
+ * The role mapping follows RFC §5.1 (`relation({ from, to, maintainedOn })`):
2746
+ *
2747
+ * - **source** = the relation's `to` (its `targetFactory()`): the entity whose
2748
+ * lifecycle event fires the maintenance and whose payload is projected. The
2749
+ * trigger's `Entity` segment names this source.
2750
+ * - **owner** = the relation's `from` (the model declaring the relation): the row
2751
+ * that *holds* the maintained snapshot / collection — the **destination** of the
2752
+ * maintenance write.
2753
+ *
2754
+ * So a `Post.created` trigger on `ThreadSummary.latestPosts → Post` maintains the
2755
+ * `ThreadSummary` (owner) row from the `Post` (source) payload. It carries the
2756
+ * A-defined {@link MaintainEffect} IR ({@link SnapshotEffect} /
2757
+ * {@link CollectionEffect}) the maintenance lowers to.
2758
+ */
2759
+ interface MaintainItem {
2760
+ /** The validated `Entity.event` trigger that fires this effect. */
2761
+ readonly trigger: MaintainTrigger;
2762
+ /**
2763
+ * The source entity name (trigger origin — the row whose lifecycle fires this
2764
+ * and whose payload is projected). Equals the relation's target (`to`).
2765
+ */
2766
+ readonly sourceEntity: string;
2767
+ /** The source model class (the relation's `targetFactory()`). */
2768
+ readonly sourceClass: ModelClass;
2769
+ /**
2770
+ * The entity that *declares* the maintaining relation (the relation owner /
2771
+ * `from`) — the row that holds the maintained snapshot / collection (the
2772
+ * maintenance write **destination**).
2773
+ */
2774
+ readonly ownerEntity: string;
2775
+ /** The owner model class (the maintenance destination). */
2776
+ readonly ownerClass: ModelClass;
2777
+ /** The relation property on the owner that declares this maintenance. */
2778
+ readonly relationProperty: string;
2779
+ /**
2780
+ * A stable key for the **destination row** a single trigger writes (the owner
2781
+ * row), derived from the relation's bound owner-key fields. Two
2782
+ * {@link MaintainItem}s firing on the same trigger with the same
2783
+ * {@link destinationRowKey} write the same row — the material #125/#126 uses to
2784
+ * enforce 論点2 = b ("1 mutation × 1 target row = 1 effect"; multiple is a
2785
+ * reject). Built deterministically (sorted), so it is a directly comparable
2786
+ * string.
2787
+ */
2788
+ readonly destinationRowKey: string;
2789
+ /** The A-defined maintenance IR this relation lowers to. */
2790
+ readonly effect: MaintainEffect;
2791
+ }
2792
+ /**
2793
+ * The maintenance graph: the trigger → effects index plus the validation surface.
2794
+ *
2795
+ * `byTrigger` is the core index: a `MaintainTrigger` (`"Post.created"`) maps to
2796
+ * every {@link MaintainItem} that fires on it, in a stable order (owner entity,
2797
+ * then relation property). Empty (no entry) for a trigger nothing maintains on.
2798
+ */
2799
+ interface MaintenanceGraph {
2800
+ /** Every maintenance item, flattened, in deterministic order. */
2801
+ readonly items: readonly MaintainItem[];
2802
+ /** The core index: trigger → the effects it fires. */
2803
+ readonly byTrigger: ReadonlyMap<MaintainTrigger, readonly MaintainItem[]>;
2804
+ /** Look up the effects fired by a trigger (empty array if none). */
2805
+ effectsFor(trigger: MaintainTrigger): readonly MaintainItem[];
2806
+ /**
2807
+ * Items that, under the SAME trigger, write the SAME target row — grouped by
2808
+ * `"<trigger><targetRowKey>"`. Only groups with **more than one** item are
2809
+ * present, so an empty map means no trigger has a multi-maintainer collision.
2810
+ * This is the detection material for 論点2 = b; #124 surfaces it, #125/#126
2811
+ * decide the reject. (Build-time we do NOT reject here — a model may legitimately
2812
+ * declare overlapping shapes that a later phase reconciles; #124's contract is
2813
+ * to make the collision *detectable*.)
2814
+ */
2815
+ readonly multiMaintainerTargets: ReadonlyMap<string, readonly MaintainItem[]>;
2816
+ }
2817
+ /**
2818
+ * Build the {@link MaintenanceGraph} from every registered model's relation-side
2819
+ * maintenance declarations (`MetadataRegistry.getAll()`), validating each as it is
2820
+ * collected (round-trip, unresolved trigger) and the whole graph (cycle) before
2821
+ * returning. Throws a loud, actionable error on any invalid declaration.
2822
+ *
2823
+ * @param registry The models to scan. Defaults to `MetadataRegistry.getAll()`;
2824
+ * an explicit map is accepted for tests / scoped builds.
2825
+ */
2826
+ declare function buildMaintenanceGraph(registry?: ReadonlyMap<Function, EntityMetadata>): MaintenanceGraph;
2827
+
2403
2828
  /**
2404
2829
  * Serializable static operation specs and manifest (issue #42, Python-bridge
2405
2830
  * Phase 0b).
@@ -2764,6 +3189,99 @@ interface TransactionItemSpec {
2764
3189
  * entity / edge / counter / ConditionCheck item), so those paths are unchanged.
2765
3190
  */
2766
3191
  readonly literalKey?: boolean;
3192
+ /**
3193
+ * A **relation-side maintenance write** (Epic #118, issue #129 — the JSON-SSoT /
3194
+ * Python mirror of the TS in-process `renderMaintainWriteItem`). Present ONLY on an
3195
+ * `Update` item that materializes a maintained access path: a projected
3196
+ * {@link DerivedMaintainWrite} of a just-written source row into a SEPARATE owner
3197
+ * (destination) row, in the SAME atomic transaction as the source write.
3198
+ *
3199
+ * The item's {@link keyCondition} carries the owner row's key templates (bound from
3200
+ * the source payload — `{sourceInputField}`), so the same key derivation / collapse
3201
+ * signature the other `Update` items use applies unchanged. This `maintain` payload
3202
+ * carries the projection transform IR (`identity` / `preview`) the runtimes apply
3203
+ * IDENTICALLY when rendering the `SET … = :v` (snapshot) / `list_append(…)`
3204
+ * (collection) `UpdateExpression`, so the maintained row is byte-consistent across
3205
+ * TS and Python. The `changes` / `add` fields are NOT used when this is present.
3206
+ */
3207
+ readonly maintain?: MaintainItemSpec;
3208
+ }
3209
+ /**
3210
+ * The transform op applied to one projected maintenance attribute (Epic #118).
3211
+ * Mirrors `ProjectionTransformOp` from `src/define/entity-writes.ts`: `identity`
3212
+ * copies the source value through unchanged; `preview` keeps the first `n`
3213
+ * characters of (the string form of) the source value. The runtimes apply this
3214
+ * IDENTICALLY so the maintained row is byte-consistent.
3215
+ */
3216
+ type MaintainProjectionOp = 'identity' | 'preview';
3217
+ /**
3218
+ * One projected maintenance attribute: the source value is read from the mutation
3219
+ * input field {@link inputField} (payload 同梱 — the just-written source row image),
3220
+ * then run through {@link op} with {@link args} (e.g. `preview`'s length bound).
3221
+ */
3222
+ interface MaintainProjectionEntry {
3223
+ /** The transform op applied to the source value (`identity` / `preview`). */
3224
+ readonly op: MaintainProjectionOp;
3225
+ /** The op's positional arguments (`[n]` for `preview`; empty for `identity`). */
3226
+ readonly args: readonly unknown[];
3227
+ /** The mutation-input field the source value is read from (`{inputField}`). */
3228
+ readonly inputField: string;
3229
+ }
3230
+ /**
3231
+ * The bounded-collection options a `collection` maintenance write carries. Phase 1
3232
+ * is **append-only**: `maxItems` / `orderBy` are recorded for the future async trim
3233
+ * (#130) but NOT applied synchronously — a single `UpdateExpression` cannot
3234
+ * read-modify-write a bounded/ordered list.
3235
+ */
3236
+ interface MaintainCollectionSpec {
3237
+ /** The target attribute that holds the maintained collection. */
3238
+ readonly field: string;
3239
+ /** Cap on the collection size (recorded for #130; not trimmed in Phase 1). */
3240
+ readonly maxItems?: number;
3241
+ /** The mutation-input field the items are ordered by (recorded for #130). */
3242
+ readonly orderBy?: string;
3243
+ }
3244
+ /**
3245
+ * The maintenance payload an `Update` {@link TransactionItemSpec} carries when it
3246
+ * materializes a maintained access path (Epic #118 / #129). A `snapshot` mirrors
3247
+ * the projection onto the owner row via `SET`; a `collection` appends the projection
3248
+ * as an item into the bounded list named by {@link collection} via `list_append`.
3249
+ */
3250
+ interface MaintainItemSpec {
3251
+ /**
3252
+ * Whether the write mirrors a single row (`snapshot`), appends a collection item
3253
+ * (`collection`), or applies a scalar `ADD` counter (`counter`, Epic #118 / #141).
3254
+ */
3255
+ readonly kind: 'snapshot' | 'collection' | 'counter';
3256
+ /** The relation property / `@aggregate` field that declared this maintenance (documentary). */
3257
+ readonly relationProperty: string;
3258
+ /** The trigger (`<sourceLogicalName>.<event>`) that fired this maintenance. */
3259
+ readonly trigger: string;
3260
+ /** target attribute → its projection transform (source field + op + args). Empty for `counter`. */
3261
+ readonly projection: Readonly<Record<string, MaintainProjectionEntry>>;
3262
+ /** The bounded-collection options; present only for `kind: 'collection'`. */
3263
+ readonly collection?: MaintainCollectionSpec;
3264
+ /**
3265
+ * The scalar counter `ADD`; present only for `kind: 'counter'` (#141). The runtimes
3266
+ * render `ADD #attr :delta` — an atomic, concurrency-safe increment that MERGES with
3267
+ * a same-row counter ADD (#92), the maintenance-pipeline analogue of the
3268
+ * self-lifecycle derived counter's `add` slot. `delta` is a numeric template string
3269
+ * (the compile-time constant `+1` created / `-1` removed).
3270
+ */
3271
+ readonly counter?: MaintainCounterSpec;
3272
+ }
3273
+ /**
3274
+ * The scalar counter a `counter` maintenance write applies (Epic #118 / #141): an
3275
+ * atomic `ADD #attribute :delta`. `delta` is a literal numeric template string (the
3276
+ * compile-time constant the trigger fixed — `"1"` created / `"-1"` removed); the
3277
+ * runtimes serialize it as a number. Only `count()` is realized synchronously
3278
+ * (`max(field)` is rejected for the synchronous path — #130 / Phase 2).
3279
+ */
3280
+ interface MaintainCounterSpec {
3281
+ /** The target attribute the counter increments (e.g. `postCount`). */
3282
+ readonly attribute: string;
3283
+ /** The signed `ADD` delta as a numeric template string (`"1"` / `"-1"`). */
3284
+ readonly delta: string;
2767
3285
  }
2768
3286
  /** A declarative transaction definition's full execution spec. */
2769
3287
  interface TransactionSpec {
@@ -3193,6 +3711,75 @@ interface DerivedUpdate {
3193
3711
  /** The signed delta to add (e.g. `+1` create, `-1` remove). */
3194
3712
  readonly amount: number;
3195
3713
  }
3714
+ /**
3715
+ * One **derived maintenance write** — the projection of a just-written source row
3716
+ * into a *separate* target (owner) row, derived from one maintenance-graph
3717
+ * {@link MaintainItem} (issue #125; the D/#124 → compile lowering). It generalizes
3718
+ * {@link DerivedUpdate}: where a `derive` is one scalar `ADD`, a maintenance write
3719
+ * mirrors a whole projection — a single-row {@link SnapshotEffect} (`kind:
3720
+ * 'snapshot'`) or an item appended into a bounded collection ({@link
3721
+ * CollectionEffect}, `kind: 'collection'`).
3722
+ *
3723
+ * The target row's key is bound from the source payload (the relation's owner-key
3724
+ * fields, filled from `$.entity.<sourceField>` → the fragment's `<sourceField>`
3725
+ * input param), and each projected attribute is a {@link ProjectionTransform} IR
3726
+ * node (A/#120 関数形 — `identity` / `preview`) resolved to the input param it reads.
3727
+ * #125 produces this structure; the runtime realization (the actual `Put` / `Update`
3728
+ * item and its placement in the atomic `TransactWriteItems`) is #127.
3729
+ */
3730
+ interface DerivedMaintainWrite {
3731
+ /** The maintained (destination / owner) entity whose row holds the snapshot / collection. */
3732
+ readonly entity: EntityRef;
3733
+ /** The relation property on the owner that declared this maintenance (documentary). */
3734
+ readonly relationProperty: string;
3735
+ /** The trigger (`<sourceLogicalName>.<event>`) that fired this maintenance. */
3736
+ readonly trigger: MaintainTrigger;
3737
+ /**
3738
+ * Whether the write mirrors a single row (`snapshot`), appends a collection item
3739
+ * (`collection`), or applies a scalar `ADD` counter (`counter`, #141).
3740
+ */
3741
+ readonly kind: 'snapshot' | 'collection' | 'counter';
3742
+ /**
3743
+ * The destination row's key binding: target key field → the mutation-input param
3744
+ * that supplies it (resolved from the effect's `$.entity.<sourceField>` paths —
3745
+ * the source row image, payload 同梱). Every owner-key field is bound.
3746
+ */
3747
+ readonly keyBinding: Readonly<Record<string, string>>;
3748
+ /**
3749
+ * The projection: target attribute → `{ op, args, inputField }`, where `inputField`
3750
+ * is the mutation-input param the source value is read from and `op` / `args` are
3751
+ * the A/#120 {@link ProjectionTransform} realization (`identity` copies through,
3752
+ * `preview` keeps the first `n` chars). Empty for a `counter` (a scalar `ADD`
3753
+ * projects no row attributes).
3754
+ */
3755
+ readonly projection: Readonly<Record<string, {
3756
+ readonly op: ProjectionTransform['op'];
3757
+ readonly args: readonly unknown[];
3758
+ readonly inputField: string;
3759
+ }>>;
3760
+ /**
3761
+ * For a `collection` write, the bounded-collection options (the target `field`,
3762
+ * the optional `maxItems` cap, and the optional `orderBy` input param); absent for
3763
+ * a `snapshot` / `counter`.
3764
+ */
3765
+ readonly collection?: {
3766
+ readonly field: string;
3767
+ readonly maxItems?: number;
3768
+ readonly orderBy?: string;
3769
+ };
3770
+ /**
3771
+ * For a `counter` write (#141 — `@aggregate(..., { pattern: 'counter', value:
3772
+ * count() })`), the scalar `ADD`: the target {@link counter.attribute} and the
3773
+ * signed {@link counter.delta} the trigger applies (`+1` created / `-1` removed).
3774
+ * A counter `ADD` is commutative, so two counter writes on the SAME row MERGE (the
3775
+ * #92 symmetric-counter collapse) rather than reject — unlike snapshot/collection.
3776
+ * Absent for a `snapshot` / `collection`.
3777
+ */
3778
+ readonly counter?: {
3779
+ readonly attribute: string;
3780
+ readonly delta: number;
3781
+ };
3782
+ }
3196
3783
  /**
3197
3784
  * A **derived uniqueness guard** — the marker-row `Put` (and, on a unique-field
3198
3785
  * change, the old-guard `Delete` + new-guard `Put` swap) that enforces an
@@ -3385,6 +3972,20 @@ interface CompiledFragment {
3385
3972
  * guard and rolls the WHOLE transaction back — so no effect is double-applied.
3386
3973
  */
3387
3974
  readonly idempotencyGuard?: DerivedIdempotencyGuard;
3975
+ /**
3976
+ * The maintenance writes derived from the maintenance graph (issue #125; the
3977
+ * D/#124 → compile lowering): one {@link DerivedMaintainWrite} per relation that
3978
+ * declared `write.maintainedOn` for this fragment's lifecycle event (a projected
3979
+ * snapshot / collection on a SEPARATE target row). Present (non-empty) only when
3980
+ * the fragment's trigger fires at least one maintainer; absent otherwise (no
3981
+ * regression — a fragment that maintains nothing compiles exactly as before).
3982
+ *
3983
+ * SCOPE (#125): each entry is the runtime-neutral structure the runtime (#127)
3984
+ * realizes into the atomic `TransactWriteItems`; #125 derives it and rejects a
3985
+ * same-target collision (論点2 = b). The cross-fragment AGGREGATION and the
3986
+ * one-atomic-tx execution wiring are #127 — not done here.
3987
+ */
3988
+ readonly maintainWrites?: readonly DerivedMaintainWrite[];
3388
3989
  }
3389
3990
  /**
3390
3991
  * Resolve the {@link LifecycleContract} a fragment adopts for its intent:
@@ -3425,8 +4026,12 @@ type EntityRefResolver = (ref: MutationEntityRef, consumerIndex: number, consume
3425
4026
  * @param resolveEntityRef Resolver for a `$.entity[i].field` cross-fragment
3426
4027
  * reference (multi-fragment compile), or `null` for a single-fragment compile
3427
4028
  * (where such a reference is a hard error).
4029
+ * @param maintenanceGraph The {@link MaintenanceGraph} the #125 maintain injection
4030
+ * queries for this fragment's trigger ({@link resolveMaintainers}). Defaults to a
4031
+ * lazily-built, cached graph over the global registry; an explicit graph is
4032
+ * accepted for scoped tests.
3428
4033
  */
3429
- declare function compileFragment(fragment: MutationFragment, index?: number, resolveEntityRef?: EntityRefResolver | null): CompiledFragment;
4034
+ declare function compileFragment(fragment: MutationFragment, index?: number, resolveEntityRef?: EntityRefResolver | null, maintenanceGraph?: MaintenanceGraph): CompiledFragment;
3430
4035
  /**
3431
4036
  * Compile a single-fragment {@link CommandPlan} into its {@link CompiledFragment}.
3432
4037
  * The N-fragment atomic merge is **#90** ({@link compileMutationPlan}); this entry
@@ -4098,6 +4703,23 @@ interface CommandMethodSpec<TKey, TParams, TResult> {
4098
4703
  * the guard and rolls the WHOLE write back — no effect is double-applied.
4099
4704
  */
4100
4705
  readonly idempotencyGuard?: DerivedIdempotencyGuard;
4706
+ /**
4707
+ * The maintenance writes derived from the relation-side `write.maintainedOn`
4708
+ * declarations (issue #125; D/#124 → compile lowering), flattened across every
4709
+ * fragment in declaration order. Present (non-empty) only when a fragment's
4710
+ * lifecycle event (`Post.created` etc.) fires at least one maintainer; absent
4711
+ * otherwise (no regression — a maintainer-free mutation is byte-identical to its
4712
+ * pre-#127 form). Each {@link DerivedMaintainWrite} projects the just-written
4713
+ * source row into a SEPARATE owner (destination) row — a single-row snapshot
4714
+ * (`kind: 'snapshot'`) or an item appended into a bounded collection (`kind:
4715
+ * 'collection'`). Their presence (like {@link conditionChecks}) **promotes** an
4716
+ * otherwise single-op method to a transaction: the runtime (#127) realizes each
4717
+ * into the method's atomic `TransactWriteItems`, so the maintained row moves
4718
+ * atomically with the source write (a failure rolls the WHOLE set back). #127 is
4719
+ * the synchronous (`updateMode: 'mutation'`) path only; the async stream path is
4720
+ * #130 (loud-rejected at compile time, never silently dropped).
4721
+ */
4722
+ readonly maintainWrites?: readonly DerivedMaintainWrite[];
4101
4723
  /** @internal Phantom carrier retaining the formal `CommandMethod` type. */
4102
4724
  readonly __signature?: CommandMethod<TKey, TParams, TResult>;
4103
4725
  }
@@ -4698,6 +5320,22 @@ interface ExecutableCommandContract {
4698
5320
  * Absent on a mutation with no `idempotency` / a #64 hand-written method.
4699
5321
  */
4700
5322
  readonly idempotencyGuard?: DerivedIdempotencyGuard;
5323
+ /**
5324
+ * The maintenance writes derived from the relation-side `write.maintainedOn`
5325
+ * declarations (issue #125 → #127; the D/#124 → compile lowering). When
5326
+ * present (non-empty), a **single-key** call composes each maintenance write
5327
+ * — a projected snapshot (`SET`) or a bounded-collection append
5328
+ * (`SET … = list_append(…)`) on a SEPARATE owner row — into the same atomic
5329
+ * `TransactWriteItems` as the source entity write (and every other effect),
5330
+ * so the maintained row moves ATOMICALLY with the source: a failure on any
5331
+ * item rolls the WHOLE transaction back (the snapshot / collection never
5332
+ * partially persists). The owner row is upserted (a bare `UpdateItem`
5333
+ * creates it if absent — the additive maintenance semantics). This is the
5334
+ * synchronous (`updateMode: 'mutation'`) path only; the async stream path is
5335
+ * #130 (loud-rejected at compile time). Absent on a mutation that fires no
5336
+ * maintainer / a #64 hand-written method.
5337
+ */
5338
+ readonly maintainWrites?: readonly DerivedMaintainWrite[];
4701
5339
  /**
4702
5340
  * The return projection of a `mutation`-derived method (issue #83). When
4703
5341
  * present, a **single-key** call performs the write then issues a
@@ -5169,6 +5807,236 @@ declare function key<T extends Record<string, unknown>>(builder: (c: {
5169
5807
  readonly [K in keyof T]-?: Column<T[K], T>;
5170
5808
  }) => KeyStructure): KeyDefinitionMarker<T>;
5171
5809
 
5810
+ type DynamoType = 'S' | 'N' | 'BOOL' | 'B' | 'SS' | 'NS' | 'L' | 'M';
5811
+ interface FieldOptions {
5812
+ format?: 'datetime' | 'date';
5813
+ readonly?: boolean;
5814
+ serialize?: (value: unknown) => unknown;
5815
+ deserialize?: (value: unknown) => unknown;
5816
+ }
5817
+ interface FieldMetadata {
5818
+ propertyName: string;
5819
+ dynamoType: DynamoType;
5820
+ options?: FieldOptions;
5821
+ /**
5822
+ * For a `@literal(...)` field — a `string`-stored field whose value is one of a
5823
+ * known, finite set — the allowed literal values, in declaration order (issue
5824
+ * #75). Recorded purely as model metadata so a Contract param bound into the
5825
+ * field can recover the precise `literal` param-kind from its bind position
5826
+ * (`src/spec/contracts.ts`), serializing as `{ type: 'literal', literals: [...] }`
5827
+ * instead of the imprecise `'string'`. JSON-safe by construction (a non-empty
5828
+ * array of strings). `undefined` for every other field decorator (`@string`,
5829
+ * `@number`, …), so plain fields are byte-for-byte unchanged (backward compat).
5830
+ */
5831
+ literals?: readonly string[];
5832
+ }
5833
+
5834
+ interface KeyDefinition {
5835
+ /** The canonical structured key (PK/SK segment lists). */
5836
+ segmented: SegmentedKey;
5837
+ inputFieldNames: string[];
5838
+ }
5839
+ interface GsiDefinition {
5840
+ indexName: string;
5841
+ /** The canonical structured key (PK/SK segment lists). */
5842
+ segmented: SegmentedKey;
5843
+ inputFieldNames: string[];
5844
+ unique: boolean;
5845
+ }
5846
+ interface RelationLimitOptions {
5847
+ default: number;
5848
+ max: number;
5849
+ }
5850
+ /**
5851
+ * The named maintenance pattern a relation participates in (Epic #118 §5.1).
5852
+ *
5853
+ * `pattern` is the *preset* selector: omitting it leaves the relation a plain
5854
+ * read-only navigation (the historical `hasMany`/`belongsTo`/`hasOne`
5855
+ * behaviour), exactly backward compatible. When present it names the AWS
5856
+ * design pattern the relation lowers to — the lowering itself (maintenance
5857
+ * graph / compile injection) is out of scope for issue #121 and lands in
5858
+ * #124/#125; here the value is recorded purely as declaration metadata.
5859
+ *
5860
+ * Typed as a `string` union of the known presets but kept open-ended via the
5861
+ * `(string & {})` tail so a future preset can be authored before this union is
5862
+ * widened, without a breaking change to callers.
5863
+ */
5864
+ type RelationPattern = 'samePartition' | 'edge' | 'counter' | 'embeddedSnapshot' | 'materializedView' | 'sparseView' | 'externalProjection' | (string & {});
5865
+ /**
5866
+ * Consistency boundary a maintained write is declared against (Epic #118 §4.A.7):
5867
+ * `transactional` = same `TransactWriteItems`; `eventual` = asynchronous catch-up.
5868
+ */
5869
+ type RelationConsistency = 'transactional' | 'eventual';
5870
+ /**
5871
+ * How a maintained write is applied (Epic #118 §4.A.7):
5872
+ * `mutation` = composed into the same mutation; `stream` = driven asynchronously
5873
+ * off a stream / outbox.
5874
+ */
5875
+ type RelationUpdateMode = 'mutation' | 'stream';
5876
+ /**
5877
+ * Read-strategy hints for a maintained relation (Epic #118 §5.1 `read`).
5878
+ *
5879
+ * All fields optional — present only when a `pattern` declares a read shape
5880
+ * (e.g. an `embeddedSnapshot` keeping the latest N items). A bare relation
5881
+ * carries no `read` block.
5882
+ */
5883
+ interface RelationReadOptions {
5884
+ /** Cap on materialised items kept inline (e.g. "latest 3 posts"). */
5885
+ maxItems?: number;
5886
+ /** Ordering of the maintained collection. */
5887
+ order?: 'ASC' | 'DESC';
5888
+ }
5889
+ /**
5890
+ * Write-maintenance declaration for a relation (Epic #118 §5.1 `write`).
5891
+ *
5892
+ * `maintainedOn` is the cross-entity trigger list (`"<Entity>.<event>"`, e.g.
5893
+ * `"Post.created"`) that the maintenance graph (#124/#125) will key off. Recorded
5894
+ * here as declaration metadata only.
5895
+ */
5896
+ interface RelationWriteOptions {
5897
+ /**
5898
+ * Cross-entity triggers, e.g. `['Post.created', 'Post.removed']`. The event
5899
+ * segment is the confirmed shared lifecycle vocabulary (epic #118 A/B
5900
+ * reconciliation): `created` / `updated` / `removed`.
5901
+ */
5902
+ maintainedOn?: string[];
5903
+ consistency?: RelationConsistency;
5904
+ updateMode?: RelationUpdateMode;
5905
+ }
5906
+ /**
5907
+ * Snapshot / projection capture map for a maintained relation
5908
+ * (Epic #118 §5.1 / §5.2 `projection`).
5909
+ *
5910
+ * Maps each captured field name on the maintaining side to **how** the source
5911
+ * value is projected. The confirmed shared vocabulary (epic #118 A/B
5912
+ * reconciliation) is the **function-form IR** — the same {@link
5913
+ * ProjectionTransform} node A (#120) defines on `src/define/entity-writes.ts`,
5914
+ * re-used here (NOT re-defined) so the two surfaces never re-diverge. Each value
5915
+ * is either:
5916
+ *
5917
+ * - a {@link ProjectionTransform} (built with the standalone authoring helpers,
5918
+ * e.g. `preview('body', 120)` — RFC §5.2 `textPreview: preview('body', 120)`),
5919
+ * or
5920
+ * - a bare `string` — the **identity shorthand**: project that source path
5921
+ * through unchanged (e.g. `{ postId: 'postId' }`).
5922
+ *
5923
+ * `Readonly` so the recorded declaration metadata is not mutated downstream.
5924
+ * Issue #121 scopes this to the declaration shape; the maintenance graph /
5925
+ * compile injection that consumes the IR is #124/#125.
5926
+ *
5927
+ * @example `{ postId: 'postId', textPreview: preview('body', 120) }`
5928
+ */
5929
+ type RelationProjection = Readonly<Record<string, ProjectionTransform | string>>;
5930
+ interface RelationOptions {
5931
+ limit?: RelationLimitOptions;
5932
+ order?: 'ASC' | 'DESC';
5933
+ /**
5934
+ * Named maintenance preset (Epic #118). Omitted = plain read-only navigation,
5935
+ * fully backward compatible with the historical relation decorators.
5936
+ */
5937
+ pattern?: RelationPattern;
5938
+ read?: RelationReadOptions;
5939
+ write?: RelationWriteOptions;
5940
+ projection?: RelationProjection;
5941
+ }
5942
+ interface RelationMetadata {
5943
+ type: 'hasMany' | 'hasOne' | 'belongsTo';
5944
+ propertyName: string;
5945
+ targetFactory: () => new (...args: unknown[]) => unknown;
5946
+ keyBinding: Record<string, string>;
5947
+ options?: RelationOptions;
5948
+ }
5949
+ /**
5950
+ * The scalar-aggregate value an `@aggregate` field derives from its source entity
5951
+ * (Epic #118 §5.2 counter / latest preset; issue #122). It is the function-form
5952
+ * IR built by the {@link count} / {@link max} value helpers — the aggregation an
5953
+ * `@aggregate(() => Source, keyBinding, { pattern, value })` field maintains:
5954
+ *
5955
+ * - `count` — the cardinality of source rows matched by the key binding (no
5956
+ * source field; e.g. `postCount!: number` ← `count()`).
5957
+ * - `max` — the maximum value of a named source `field` (e.g. `lastPostAt!:
5958
+ * string` ← `max('createdAt')`).
5959
+ *
5960
+ * Recorded purely as declaration metadata (issue #122 scope = declaration
5961
+ * surface): the maintenance graph (#124) / compile injection (#125) consume it;
5962
+ * the effect itself is out of scope here. Kept open-ended via the discriminated
5963
+ * `op` so a future aggregation (`min`, `sum`, …) extends the union without a
5964
+ * breaking change.
5965
+ *
5966
+ * @example `count()` → `{ op: 'count' }`
5967
+ * @example `max('createdAt')` → `{ op: 'max', field: 'createdAt' }`
5968
+ */
5969
+ type AggregateValue = {
5970
+ readonly op: 'count';
5971
+ } | {
5972
+ readonly op: 'max';
5973
+ readonly field: string;
5974
+ };
5975
+ /**
5976
+ * Options for an `@aggregate` field (Epic #118 §5.2 counter / latest preset;
5977
+ * issue #122). Mirrors the maintenance vocabulary a relation declares so the two
5978
+ * authoring surfaces stay in lockstep:
5979
+ *
5980
+ * - `pattern` reuses {@link RelationPattern} (e.g. `'counter'`) — the named
5981
+ * maintenance preset, NOT re-defined here.
5982
+ * - `value` is the {@link AggregateValue} the field maintains (`count()` /
5983
+ * `max('createdAt')`).
5984
+ * - `write` reuses {@link RelationWriteOptions} verbatim — `maintainedOn`
5985
+ * triggers (`Post.created` / `Post.removed`, the confirmed shared
5986
+ * `created|updated|removed` event vocabulary) plus `consistency`
5987
+ * (`transactional|eventual`) / `updateMode` (`mutation|stream`). These are NOT
5988
+ * re-defined; they are the same shared types B (#121) added.
5989
+ */
5990
+ interface AggregateOptions {
5991
+ /** Named maintenance preset (typically `'counter'`); reuses {@link RelationPattern}. */
5992
+ pattern?: RelationPattern;
5993
+ /** The scalar aggregation this field maintains (`count()` / `max('createdAt')`). */
5994
+ value: AggregateValue;
5995
+ /** Cross-entity maintenance triggers / consistency / update-mode (reused from B). */
5996
+ write?: RelationWriteOptions;
5997
+ }
5998
+ /**
5999
+ * Declaration metadata recorded by an `@aggregate` field decorator (issue #122).
6000
+ *
6001
+ * An `@aggregate` is a **scalar** field (`postCount!: number`,
6002
+ * `lastPostAt!: string`) whose value is derived — by aggregating rows of a source
6003
+ * entity resolved by {@link targetFactory} + {@link keyBinding} — rather than
6004
+ * stored directly. It is therefore recorded in its **own** metadata array
6005
+ * (`EntityMetadata.aggregates`), distinct from both {@link FieldMetadata} (a
6006
+ * plain stored attribute) and {@link RelationMetadata} (a navigation yielding
6007
+ * model instances): an aggregate carries a source binding like a relation, but
6008
+ * surfaces a scalar value like a field. The collector path mirrors relations
6009
+ * (decorator pushes, `@model` drains).
6010
+ *
6011
+ * Issue #122 scope is the declaration surface + metadata pass-through only; the
6012
+ * aggregation effect's compile / runtime (#124/#125/#127) is out of scope.
6013
+ */
6014
+ interface AggregateMetadata {
6015
+ /** The scalar field the aggregate value is written to. */
6016
+ propertyName: string;
6017
+ /** Resolves the source entity whose rows are aggregated. */
6018
+ targetFactory: () => new (...args: unknown[]) => unknown;
6019
+ /** The key binding selecting the source rows (target key field → source field). */
6020
+ keyBinding: Record<string, string>;
6021
+ /** The aggregate preset / value / maintenance-write declaration. */
6022
+ options: AggregateOptions;
6023
+ }
6024
+ interface EmbeddedMetadata {
6025
+ propertyName: string;
6026
+ modelFactory: () => new (...args: unknown[]) => unknown;
6027
+ }
6028
+ interface EntityMetadata {
6029
+ tableName: string;
6030
+ prefix: string;
6031
+ fields: FieldMetadata[];
6032
+ primaryKey: KeyDefinition | null;
6033
+ gsiDefinitions: GsiDefinition[];
6034
+ relations: RelationMetadata[];
6035
+ /** Scalar `@aggregate` fields (Epic #118 §5.2 counter / latest; issue #122). */
6036
+ aggregates: AggregateMetadata[];
6037
+ embeddedFields: EmbeddedMetadata[];
6038
+ }
6039
+
5172
6040
  /**
5173
6041
  * CDC emulator types (issue #72). These types are **cdc-module-owned**; core
5174
6042
  * never references them. The {@link ChangeEvent} shape mirrors DynamoDB Streams
@@ -5282,4 +6150,4 @@ interface CdcEmulatorOptions {
5282
6150
  }
5283
6151
  type ShardId = string;
5284
6152
 
5285
- export { type EntityRef as $, type ConcurrentRecomputeRef as A, type BatchGetExecInput as B, type ChangeEvent as C, type DynamoDBOperation as D, type Executor as E, type FaultSpec as F, type EventLog as G, type ReplayOptions as H, type Item as I, type ShardId as J, type TransactionItemSpec as K, type Param as L, type ModelStatic as M, type ParamDescriptor as N, type DefinitionMap as O, type PutInput as P, type OperationDefinition as Q, type ReadExecOptions as R, type SelectableOf as S, type TransactWriteExecItem as T, type UpdateInput as U, type WriteDefinitionOptions as V, type WriteExecOptions as W, type PartialQueryKeyOf as X, type StrictSelectSpec as Y, type EntityInput as Z, type UniqueQueryKeyOf as _, type ExecutorResult as a, type DerivedUpdate as a$, type ConditionInput as a0, type QueryModelContract as a1, type QueryMethodSpec as a2, type CommandModelContract as a3, type CommandMethodSpec as a4, type ContractSpec as a5, type QuerySpec as a6, type CommandSpec as a7, type ContextSpec as a8, type OperationsDocument as a9, type ComposeSpec as aA, type CondSlot as aB, type ConditionCheckInput as aC, type Connection as aD, type ContractCallSignature as aE, type ContractCardinality as aF, type ContractCommandParams as aG, type ContractCommandResult as aH, type ContractComposeNode as aI, type ContractFromRef as aJ, type ContractInputArity as aK, type ContractItem as aL, type ContractKeyFieldRef as aM, type ContractKeyInput as aN, type ContractKeyRef as aO, type ContractKeySpec as aP, type ContractKind as aQ, type ContractMethodOp as aR, type ContractParamRef as aS, type ContractQueryParams as aT, type ContractResolution as aU, type CtxBase as aV, DEFAULT_MAX_ATTEMPTS as aW, DEFAULT_RETRY_POLICY as aX, type DeleteOptions as aY, type DeriveEffect as aZ, type DerivedEdgeWrite as a_, type AnyOperationDefinition as aa, type BridgeBundle as ab, type ConditionSpec as ac, type BatchDeleteRequest as ad, type BatchGetOptions as ae, type BatchGetRequest as af, BatchGetResult as ag, type BatchPutRequest as ah, type BatchResult as ai, type BatchWriteRequest as aj, CONTRACT_RANGE_FANOUT_CONCURRENCY as ak, type CdcMode as al, type Change as am, type ChangeBatch as an, type ChangeEventName as ao, type ClockMode as ap, type Column as aq, type ColumnMap as ar, type CommandContractMethodSpec as as, type CommandInputShape as at, type CommandMethod as au, type CommandPlan as av, type CommandResolutionTarget as aw, type CommandResultKind as ax, type CommandSelectShape as ay, type CompiledFragment as az, type WriteResult as b, type ReadOpKind as b$, type DescriptorBinding as b0, ENTITY_WRITES_MARKER as b1, type EdgeEffect as b2, type EffectPath as b3, type EmitEffect as b4, type EntityWritesDefinition as b5, type EntityWritesShape as b6, type ExecutableCommandContract as b7, type ExecutableQueryContract as b8, type FilterInput as b9, type MutateParallelResult as bA, type MutateTransactionResult as bB, type MutationBody as bC, type MutationDescriptorMap as bD, type MutationFragment as bE, type MutationInputProxy as bF, type MutationInputRef as bG, type MutationIntent as bH, type NumberParam as bI, type OperationKind as bJ, type OperationSpec as bK, type ParallelOpResult as bL, type ParamKind as bM, type ParamSpec as bN, type ParamStructure as bO, type PersistCtx as bP, type PersistOrigin as bQ, type PlannedCommandMethod as bR, type PutOptions as bS, type QueryContractMethodSpec as bT, type QueryEnvelopeResult as bU, type QueryKeyOf as bV, type QueryMethod as bW, type QueryResult as bX, type RangeConditionSpec as bY, type ReadEnvelope as bZ, type ReadOpCtx as b_, type FilterSpec as ba, type FragmentInput as bb, type GsiDefinitionMarker as bc, type GsiOptions as bd, type IdempotencyEffect as be, type InProcessWriteDescriptor as bf, type InputArity as bg, type KeyDefinitionMarker as bh, type KeySegment as bi, type KeySlot as bj, type KeyStructure as bk, type KeyedResult as bl, LIFECYCLE_CONTRACT_MARKER as bm, type LifecycleContract as bn, type LifecycleEffects as bo, type LiteralParam as bp, type ManifestEntity as bq, type ManifestField as br, type ManifestFieldType as bs, type ManifestGsi as bt, type ManifestKey as bu, type ManifestRelation as bv, type ManifestTable as bw, type ModelRef as bx, type MutateMode as by, type MutateOptions as bz, type DeleteInput as c, isContractFromRef as c$, type ReadOperationType as c0, type ReadRouteDescriptor as c1, type ReadRouteOptions as c2, type ReadRouteResult as c3, type RecordedCompose as c4, type RelationBuilder as c5, type RelationSelect as c6, type RelationSpec as c7, type RequiresEffect as c8, type Resolution as c9, buildDeleteInput as cA, buildPutInput as cB, buildUpdateInput as cC, compileFragment as cD, compileMutationPlan as cE, compileSingleFragmentPlan as cF, cond as cG, contractOfMethodSpec as cH, definePlan as cI, entityWrites as cJ, executeBatchGet as cK, executeBatchWrite as cL, executeCommandMethod as cM, executeDelete as cN, executeKeyedBatchGet as cO, executePut as cP, executeQueryMethod as cQ, executeRangeFanout as cR, executeTransaction as cS, executeUpdate as cT, from as cU, getEntityWrites as cV, gsi as cW, isColumn as cX, isCommandModelContract as cY, isCommandPlan as cZ, isContractComposeNode as c_, type RetryInfo as ca, type RetryOperationKind as cb, SPEC_VERSION as cc, type SegmentSpec as cd, type SelectBuilder as ce, type SelectOf as cf, type StartingPosition as cg, type StreamViewType as ch, type StringParam as ci, TransactionContext as cj, type TransactionItemType as ck, type UniqueEffect as cl, type Updatable as cm, type UpdateOptions as cn, type WhenSpec as co, type WriteCtx as cp, type WriteDescriptor as cq, type WriteEnvelope as cr, type WriteInput as cs, type WriteKind as ct, type WriteLifecyclePhase as cu, type WriteMiddleware as cv, type WriteOperationType as cw, type WriteRecorder as cx, type WriteResultProjection as cy, attachModelClass as cz, type BatchWriteExecItem as d, isContractKeyFieldRef as d0, isContractKeyRef as d1, isContractParamRef as d2, isEntityWritesDefinition as d3, isKeySegment as d4, isLifecycleContract as d5, isMutationFragment as d6, isMutationInputRef as d7, isParam as d8, isPlannedCommandMethod as d9, isQueryModelContract as da, isRetryableError as db, isRetryableTransactionCancellation as dc, k as dd, key as de, lifecyclePhaseForIntent as df, mintContractKeyFieldRef as dg, mintContractParamRef as dh, mutation as di, param as dj, publicCommandModel as dk, publicQueryModel as dl, query as dm, resolveLifecycle as dn, wholeKeysSentinel as dp, type BatchExecOptions as e, DDBModel as f, type PrimaryKeyOf as g, type RequestContext as h, type Middleware as i, type ReadRequestKind as j, type CtxModel as k, type ReadParams as l, type ReadRequestCtx as m, type RetryPolicy as n, type ExecutionPlanSpec as o, type SegmentedKey as p, type SelectBuilderSpec as q, type RawCondition as r, type TransactionSpec as s, type Manifest as t, type RetryOverride as u, type ExecutionPlan as v, type ResolvedKey as w, type CdcEmulatorOptions as x, type ChangeHandler as y, type Unsubscribe as z };
6153
+ export { type Param as $, type AggregateOptions as A, type BatchGetExecInput as B, type ChangeEvent as C, type DynamoDBOperation as D, type Executor as E, type FieldOptions as F, type GsiDefinition as G, type ResolvedKey as H, type Item as I, type CdcEmulatorOptions as J, type KeyDefinition as K, type ChangeHandler as L, type ModelStatic as M, type Unsubscribe as N, type FaultSpec as O, type PutInput as P, type ConcurrentRecomputeRef as Q, type ReadExecOptions as R, type SelectableOf as S, type TransactWriteExecItem as T, type UpdateInput as U, type EventLog as V, type WriteExecOptions as W, type ReplayOptions as X, type ShardId as Y, type RelationMetadata as Z, type TransactionItemSpec as _, type ExecutorResult as a, type ContractKeySpec as a$, type ParamDescriptor as a0, type DefinitionMap as a1, type OperationDefinition as a2, type WriteDefinitionOptions as a3, type PartialQueryKeyOf as a4, type StrictSelectSpec as a5, type EntityInput as a6, type UniqueQueryKeyOf as a7, type EntityRef as a8, type ConditionInput as a9, type CollectionEffect as aA, type CollectionOptions as aB, type Column as aC, type ColumnMap as aD, type CommandContractMethodSpec as aE, type CommandInputShape as aF, type CommandMethod as aG, type CommandPlan as aH, type CommandResolutionTarget as aI, type CommandResultKind as aJ, type CommandSelectShape as aK, type CompiledFragment as aL, type ComposeSpec as aM, type CondSlot as aN, type ConditionCheckInput as aO, type Connection as aP, type ContractCallSignature as aQ, type ContractCardinality as aR, type ContractCommandParams as aS, type ContractCommandResult as aT, type ContractComposeNode as aU, type ContractFromRef as aV, type ContractInputArity as aW, type ContractItem as aX, type ContractKeyFieldRef as aY, type ContractKeyInput as aZ, type ContractKeyRef as a_, type QueryModelContract as aa, type QueryMethodSpec as ab, type CommandModelContract as ac, type CommandMethodSpec as ad, type ContractSpec as ae, type QuerySpec as af, type CommandSpec as ag, type ContextSpec as ah, type OperationsDocument as ai, type AnyOperationDefinition as aj, type BridgeBundle as ak, type ConditionSpec as al, type AggregateMetadata as am, type BatchDeleteRequest as an, type BatchGetOptions as ao, type BatchGetRequest as ap, BatchGetResult as aq, type BatchPutRequest as ar, type BatchResult as as, type BatchWriteRequest as at, CONTRACT_RANGE_FANOUT_CONCURRENCY as au, type CdcMode as av, type Change as aw, type ChangeBatch as ax, type ChangeEventName as ay, type ClockMode as az, type WriteResult as b, type MutationInputProxy as b$, type ContractKind as b0, type ContractMethodOp as b1, type ContractParamRef as b2, type ContractQueryParams as b3, type ContractResolution as b4, type CounterAggregate as b5, type CounterEffect as b6, type CtxBase as b7, DEFAULT_MAX_ATTEMPTS as b8, DEFAULT_RETRY_POLICY as b9, type KeyedResult as bA, LIFECYCLE_CONTRACT_MARKER as bB, type LifecycleContract as bC, type LifecycleEffects as bD, type LiteralParam as bE, type MaintainConsistency as bF, type MaintainEffect as bG, type MaintainEvent as bH, type MaintainItem as bI, type MaintainTrigger as bJ, type MaintainUpdateMode as bK, type MaintenanceGraph as bL, type ManifestEntity as bM, type ManifestField as bN, type ManifestFieldType as bO, type ManifestGsi as bP, type ManifestKey as bQ, type ManifestRelation as bR, type ManifestTable as bS, type ModelRef as bT, type MutateMode as bU, type MutateOptions as bV, type MutateParallelResult as bW, type MutateTransactionResult as bX, type MutationBody as bY, type MutationDescriptorMap as bZ, type MutationFragment as b_, type DeleteOptions as ba, type DeriveEffect as bb, type DerivedEdgeWrite as bc, type DerivedUpdate as bd, type DescriptorBinding as be, ENTITY_WRITES_MARKER as bf, type EdgeEffect as bg, type EffectPath as bh, type EmbeddedMetadata as bi, type EmitEffect as bj, type EntityWritesDefinition as bk, type EntityWritesShape as bl, type ExecutableCommandContract as bm, type ExecutableQueryContract as bn, type FilterInput as bo, type FilterSpec as bp, type FragmentInput as bq, type GsiDefinitionMarker as br, type GsiOptions as bs, type IdempotencyEffect as bt, type InProcessWriteDescriptor as bu, type InputArity as bv, type KeyDefinitionMarker as bw, type KeySegment as bx, type KeySlot as by, type KeyStructure as bz, type DeleteInput as c, type WriteKind as c$, type MutationInputRef as c0, type MutationIntent as c1, type NumberParam as c2, type OperationKind as c3, type OperationSpec as c4, type ParallelOpResult as c5, type ParamKind as c6, type ParamSpec as c7, type ParamStructure as c8, type PersistCtx as c9, type RelationSelect as cA, type RelationSpec as cB, type RelationUpdateMode as cC, type RelationWriteOptions as cD, type RequiresEffect as cE, type Resolution as cF, type RetryInfo as cG, type RetryOperationKind as cH, SPEC_VERSION as cI, type SegmentSpec as cJ, type SegmentedKey as cK, type SelectBuilder as cL, type SelectOf as cM, type SnapshotEffect as cN, type StartingPosition as cO, type StreamViewType as cP, type StringParam as cQ, TransactionContext as cR, type TransactionItemType as cS, type UniqueEffect as cT, type Updatable as cU, type UpdateOptions as cV, type WhenSpec as cW, type WriteCtx as cX, type WriteDescriptor as cY, type WriteEnvelope as cZ, type WriteInput as c_, type PersistOrigin as ca, type PlannedCommandMethod as cb, type ProjectionMap as cc, type ProjectionTransform as cd, type ProjectionTransformOp as ce, type PutOptions as cf, type QueryContractMethodSpec as cg, type QueryEnvelopeResult as ch, type QueryKeyOf as ci, type QueryMethod as cj, type QueryResult as ck, type RangeConditionSpec as cl, type ReadEnvelope as cm, type ReadOpCtx as cn, type ReadOpKind as co, type ReadOperationType as cp, type ReadRouteDescriptor as cq, type ReadRouteOptions as cr, type ReadRouteResult as cs, type RecordedCompose as ct, type RelationBuilder as cu, type RelationConsistency as cv, type RelationLimitOptions as cw, type RelationPattern as cx, type RelationProjection as cy, type RelationReadOptions as cz, type BatchWriteExecItem as d, resolveLifecycle as d$, type WriteLifecyclePhase as d0, type WriteMiddleware as d1, type WriteOperationType as d2, type WriteRecorder as d3, type WriteResultProjection as d4, attachModelClass as d5, buildDeleteInput as d6, buildMaintenanceGraph as d7, buildPutInput as d8, buildUpdateInput as d9, isContractFromRef as dA, isContractKeyFieldRef as dB, isContractKeyRef as dC, isContractParamRef as dD, isEntityWritesDefinition as dE, isKeySegment as dF, isLifecycleContract as dG, isMaintainTrigger as dH, isMutationFragment as dI, isMutationInputRef as dJ, isParam as dK, isPlannedCommandMethod as dL, isQueryModelContract as dM, isRetryableError as dN, isRetryableTransactionCancellation as dO, k as dP, key as dQ, lifecyclePhaseForIntent as dR, maintainTrigger as dS, mintContractKeyFieldRef as dT, mintContractParamRef as dU, mutation as dV, param as dW, preview as dX, publicCommandModel as dY, publicQueryModel as dZ, query as d_, compileFragment as da, compileMutationPlan as db, compileSingleFragmentPlan as dc, cond as dd, contractOfMethodSpec as de, definePlan as df, entityWrites as dg, executeBatchGet as dh, executeBatchWrite as di, executeCommandMethod as dj, executeDelete as dk, executeKeyedBatchGet as dl, executePut as dm, executeQueryMethod as dn, executeRangeFanout as dp, executeTransaction as dq, executeUpdate as dr, from as ds, getEntityWrites as dt, gsi as du, identity as dv, isColumn as dw, isCommandModelContract as dx, isCommandPlan as dy, isContractComposeNode as dz, type BatchExecOptions as e, wholeKeysSentinel as e0, DDBModel as f, type PrimaryKeyOf as g, type RequestContext as h, type Middleware as i, type ReadRequestKind as j, type CtxModel as k, type ReadParams as l, type ReadRequestCtx as m, type RetryPolicy as n, type ExecutionPlanSpec as o, type EntityMetadata as p, type DynamoType as q, type RelationOptions as r, type AggregateValue as s, type SelectBuilderSpec as t, type RawCondition as u, type TransactionSpec as v, type Manifest as w, type RetryOverride as x, type ExecutionPlan as y, type FieldMetadata as z };