graphddb 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,6 +21,7 @@ TypeScript types.
21
21
  - ✅ **CDC emulator** —— drive and test change events equivalent to DynamoDB Streams locally.
22
22
  - ✅ **CDC projection** —— `@cdcProjected()` + `fromChange` / `subscribe` parse CDC change events into typed records (sink delivery / idempotency stay with the consumer).
23
23
  - ✅ **Maintained access paths** —— keep embedded snapshots / aggregate counters synchronized atomically.
24
+ - ✅ **CloudFormation generation** —— emit a CloudFormation template for the DynamoDB table(s) a model set maps onto (GSI union / Streams / TTL / PITR / TableClass / SSE / PROVISIONED / Auto Scaling).
24
25
 
25
26
  ## 🤔 Philosophy
26
27
 
@@ -262,6 +263,7 @@ flowchart LR
262
263
  M["TS Model (SSoT)"] --> RT["Runtime (TS)"]
263
264
  M --> PY["Python client + runtime"]
264
265
  M --> CQ["CQRS Contract"]
266
+ M --> CFN["CloudFormation template"]
265
267
  ```
266
268
 
267
269
  ## 📄 License
@@ -50,7 +50,7 @@ import {
50
50
  serializeFieldValue,
51
51
  serializeRawCondition,
52
52
  skTemplate
53
- } from "./chunk-B3GWIWT6.js";
53
+ } from "./chunk-W3GEJPPV.js";
54
54
 
55
55
  // src/spec/types.ts
56
56
  var SPEC_VERSION = "1.0";
@@ -99,7 +99,10 @@ function buildGsis(metadata) {
99
99
  unique: gsi.unique,
100
100
  inputFields: [...gsi.inputFieldNames],
101
101
  pkTemplate: pk,
102
- skTemplate: sk ?? null
102
+ skTemplate: sk ?? null,
103
+ // Purely-documentary GSI description (issue #166); emitted only when declared
104
+ // so an undescribed index is byte-identical to the pre-#166 manifest.
105
+ ...gsi.description !== void 0 ? { description: gsi.description } : {}
103
106
  };
104
107
  });
105
108
  }
@@ -110,7 +113,10 @@ function buildRelations(metadata) {
110
113
  relations[rel.propertyName] = {
111
114
  type: rel.type,
112
115
  target: targetClass.name,
113
- keyBinding: { ...rel.keyBinding }
116
+ keyBinding: { ...rel.keyBinding },
117
+ // Purely-documentary relation description (issue #166); emitted only when
118
+ // declared so an undescribed relation is byte-identical to the pre-#166 manifest.
119
+ ...rel.options?.description !== void 0 ? { description: rel.options.description } : {}
114
120
  };
115
121
  }
116
122
  return sortedRecord(relations);
@@ -0,0 +1,15 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+ var __commonJS = (cb, mod) => function __require2() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+
12
+ export {
13
+ __require,
14
+ __commonJS
15
+ };
@@ -7,7 +7,7 @@ import {
7
7
  buildMaintenanceGraph,
8
8
  buildPutInput,
9
9
  resolveModelClass
10
- } from "./chunk-B3GWIWT6.js";
10
+ } from "./chunk-W3GEJPPV.js";
11
11
 
12
12
  // src/cdc/prng.ts
13
13
  var SeededRandom = class {
@@ -113,7 +113,10 @@ function gsi(indexName, builder, options) {
113
113
  indexName,
114
114
  segmented,
115
115
  inputFieldNames,
116
- unique: options?.unique ?? false
116
+ unique: options?.unique ?? false,
117
+ // Purely-documentary description (issue #166); emitted only when declared so an
118
+ // undescribed index carries no `description` key (byte-identical to pre-#166).
119
+ ...options?.description !== void 0 ? { description: options.description } : {}
117
120
  };
118
121
  }
119
122
 
@@ -1084,7 +1087,10 @@ var MetadataRegistry = class {
1084
1087
  indexName: value.indexName,
1085
1088
  segmented: value.segmented,
1086
1089
  inputFieldNames: value.inputFieldNames,
1087
- unique: value.unique
1090
+ unique: value.unique,
1091
+ // Purely-documentary GSI description (issue #166); copied only when declared
1092
+ // so an undescribed index is byte-identical to the pre-#166 metadata.
1093
+ ...value.description !== void 0 ? { description: value.description } : {}
1088
1094
  });
1089
1095
  }
1090
1096
  }
package/dist/cli.js CHANGED
@@ -2,11 +2,12 @@
2
2
  import {
3
3
  buildBridgeBundle,
4
4
  buildManifest
5
- } from "./chunk-FI63YKK5.js";
5
+ } from "./chunk-H5TUW2WR.js";
6
6
  import {
7
7
  MetadataRegistry,
8
8
  normalizeSelectSpec
9
- } from "./chunk-B3GWIWT6.js";
9
+ } from "./chunk-W3GEJPPV.js";
10
+ import "./chunk-MCKGQKYU.js";
10
11
 
11
12
  // src/cli.ts
12
13
  import { createRequire } from "module";
@@ -659,6 +660,9 @@ function collectResultTypes(manifest, entity, select, typeName, out, seen) {
659
660
  } else {
660
661
  fields.push([field, `${itemTypeName} | None`]);
661
662
  }
663
+ if (relation.description !== void 0) {
664
+ fieldDescriptions[field] = relation.description;
665
+ }
662
666
  continue;
663
667
  }
664
668
  if (value === true) {
@@ -790,7 +794,15 @@ function methodParams(def) {
790
794
  }
791
795
  return out;
792
796
  }
793
- function collectRepositories(queries, commands) {
797
+ function gsiDescriptionForQuery(name, entity, manifest, querySpecs) {
798
+ if (!manifest || !querySpecs) return void 0;
799
+ const spec = querySpecs[name];
800
+ const indexName = spec?.operations[0]?.indexName;
801
+ if (indexName === void 0) return void 0;
802
+ const gsi = manifest.entities[entity]?.gsis.find((g) => g.indexName === indexName);
803
+ return gsi?.description;
804
+ }
805
+ function collectRepositories(queries, commands, manifest, querySpecs) {
794
806
  const byEntity = /* @__PURE__ */ new Map();
795
807
  const ensure = (entity) => {
796
808
  const cls = `${entityBaseName(entity)}Repository`;
@@ -803,13 +815,14 @@ function collectRepositories(queries, commands) {
803
815
  };
804
816
  for (const name of Object.keys(queries).sort()) {
805
817
  const def = queries[name];
818
+ const description = def.description ?? gsiDescriptionForQuery(name, def.entity.name, manifest, querySpecs);
806
819
  ensure(def.entity.name).push({
807
820
  methodName: toSnakeCase(name),
808
821
  params: methodParams(def),
809
822
  returnType: `${queryResultTypeName(name)} | None`,
810
823
  kind: "query",
811
824
  operationId: name,
812
- ...def.description !== void 0 ? { description: def.description } : {}
825
+ ...description !== void 0 ? { description } : {}
813
826
  });
814
827
  }
815
828
  for (const name of Object.keys(commands).sort()) {
@@ -914,8 +927,8 @@ function renderTransactionsClass(methods) {
914
927
  body.join("\n\n")
915
928
  ].join("\n");
916
929
  }
917
- function generateRepositories(queries, commands, transactions = {}) {
918
- const classes = collectRepositories(queries, commands);
930
+ function generateRepositories(queries, commands, transactions = {}, manifest, querySpecs) {
931
+ const classes = collectRepositories(queries, commands, manifest, querySpecs);
919
932
  const txMethods = collectTransactionMethods(transactions);
920
933
  const resultTypes = /* @__PURE__ */ new Set();
921
934
  for (const name of Object.keys(queries)) {
@@ -1471,11 +1484,243 @@ function renderBundle(queries = {}, commands = {}, registry = MetadataRegistry,
1471
1484
  "manifest.json": JSON.stringify(bundle.manifest, null, 2) + "\n",
1472
1485
  "operations.json": JSON.stringify(bundle.operations, null, 2) + "\n",
1473
1486
  "types.py": generateTypes(bundle.manifest, queries, txSpecs, options),
1474
- "repositories.py": generateRepositories(queries, commands, txSpecs),
1487
+ "repositories.py": generateRepositories(
1488
+ queries,
1489
+ commands,
1490
+ txSpecs,
1491
+ bundle.manifest,
1492
+ bundle.operations.queries
1493
+ ),
1475
1494
  "__init__.py": generateInit(queries, commands, txSpecs)
1476
1495
  };
1477
1496
  }
1478
1497
 
1498
+ // src/codegen/jsdoc.ts
1499
+ async function loadTypescript() {
1500
+ try {
1501
+ const mod = await import("./typescript-ZUQEBJRV.js");
1502
+ return mod.default ?? mod;
1503
+ } catch {
1504
+ return void 0;
1505
+ }
1506
+ }
1507
+ var warnedTypescriptMissing = false;
1508
+ var TYPESCRIPT_MISSING_WARNING = "warning: JSDoc description extraction skipped \u2014 'typescript' is not installed. Install typescript to enable it, or use explicit `description` fields.\n";
1509
+ function docCommentFor(ts, node) {
1510
+ const jsDoc = node.jsDoc;
1511
+ if (!jsDoc || jsDoc.length === 0) return void 0;
1512
+ const last = jsDoc[jsDoc.length - 1];
1513
+ const comment = last.comment;
1514
+ if (typeof comment === "string") {
1515
+ const t = comment.trim();
1516
+ return t === "" ? void 0 : t;
1517
+ }
1518
+ if (Array.isArray(comment)) {
1519
+ const joined = ts.getTextOfJSDocComment(comment);
1520
+ if (joined) {
1521
+ const t = joined.trim();
1522
+ return t === "" ? void 0 : t;
1523
+ }
1524
+ }
1525
+ return void 0;
1526
+ }
1527
+ function hasModelDecorator(ts, node) {
1528
+ const decorators = ts.getDecorators?.(node) ?? [];
1529
+ for (const dec of decorators) {
1530
+ const expr = dec.expression;
1531
+ const callee = ts.isCallExpression(expr) ? expr.expression : expr;
1532
+ if (ts.isIdentifier(callee) && callee.text === "model") return true;
1533
+ }
1534
+ return false;
1535
+ }
1536
+ function gsiIndexNameOf(ts, init) {
1537
+ if (!init || !ts.isCallExpression(init)) return void 0;
1538
+ const callee = init.expression;
1539
+ if (!ts.isIdentifier(callee) || callee.text !== "gsi") return void 0;
1540
+ const first = init.arguments[0];
1541
+ if (first && ts.isStringLiteralLike(first)) return first.text;
1542
+ return void 0;
1543
+ }
1544
+ function collectClassDoc(ts, node) {
1545
+ const members = /* @__PURE__ */ new Map();
1546
+ const gsis = /* @__PURE__ */ new Map();
1547
+ for (const member of node.members) {
1548
+ if (ts.isPropertyDeclaration(member) && member.name) {
1549
+ const doc = docCommentFor(ts, member);
1550
+ if (doc === void 0) continue;
1551
+ const gsiName = gsiIndexNameOf(ts, member.initializer);
1552
+ if (gsiName !== void 0) {
1553
+ gsis.set(gsiName, doc);
1554
+ } else if (ts.isIdentifier(member.name) || ts.isStringLiteralLike(member.name)) {
1555
+ members.set(member.name.text, doc);
1556
+ }
1557
+ }
1558
+ }
1559
+ return { own: docCommentFor(ts, node), members, gsis };
1560
+ }
1561
+ function collectDefinitionDocs(ts, obj, into, ambiguous) {
1562
+ for (const prop of obj.properties) {
1563
+ if (!ts.isPropertyAssignment(prop)) continue;
1564
+ if (!ts.isIdentifier(prop.name) && !ts.isStringLiteralLike(prop.name)) continue;
1565
+ const key = prop.name.text;
1566
+ if (into.has(key) || ambiguous.has(key)) {
1567
+ into.delete(key);
1568
+ ambiguous.add(key);
1569
+ continue;
1570
+ }
1571
+ const params = /* @__PURE__ */ new Map();
1572
+ collectParamDocs(ts, prop.initializer, params);
1573
+ into.set(key, { own: docCommentFor(ts, prop), params });
1574
+ }
1575
+ }
1576
+ function collectParamDocs(ts, node, into) {
1577
+ const visit = (n) => {
1578
+ if (ts.isPropertyAssignment(n)) {
1579
+ const isParamCall = ts.isCallExpression(n.initializer) && ts.isPropertyAccessExpression(n.initializer.expression) && ts.isIdentifier(n.initializer.expression.expression) && n.initializer.expression.expression.text === "param";
1580
+ if (isParamCall && (ts.isIdentifier(n.name) || ts.isStringLiteralLike(n.name))) {
1581
+ const doc = docCommentFor(ts, n);
1582
+ if (doc !== void 0) into.set(n.name.text, doc);
1583
+ }
1584
+ }
1585
+ ts.forEachChild(n, visit);
1586
+ };
1587
+ ts.forEachChild(node, visit);
1588
+ }
1589
+ function extract(ts, files) {
1590
+ const program = ts.createProgram(files, {
1591
+ // Parse-only, permissive options: we never emit and never type-check the
1592
+ // world — we only walk the AST of the requested files. `allowJs` lets a `.js`
1593
+ // definition module (pre-compiled input) be parsed too.
1594
+ allowJs: true,
1595
+ noResolve: true,
1596
+ noLib: true,
1597
+ skipLibCheck: true,
1598
+ types: [],
1599
+ // The definition modules use TC39 standard decorators (repo tsconfig has
1600
+ // `experimentalDecorators: false`); parsing is decorator-flavour agnostic for
1601
+ // AST purposes, but keep it aligned.
1602
+ experimentalDecorators: false
1603
+ });
1604
+ const classes = /* @__PURE__ */ new Map();
1605
+ const ambiguousClassNames = /* @__PURE__ */ new Set();
1606
+ const definitions = /* @__PURE__ */ new Map();
1607
+ const ambiguousDefinitionKeys = /* @__PURE__ */ new Set();
1608
+ const fileSet = new Set(files.map((f) => normalize(f)));
1609
+ for (const sf of program.getSourceFiles()) {
1610
+ if (!fileSet.has(normalize(sf.fileName))) continue;
1611
+ const visit = (node) => {
1612
+ if (ts.isClassDeclaration(node) && node.name && hasModelDecorator(ts, node)) {
1613
+ const name = node.name.text;
1614
+ if (classes.has(name) || ambiguousClassNames.has(name)) {
1615
+ classes.delete(name);
1616
+ ambiguousClassNames.add(name);
1617
+ } else {
1618
+ classes.set(name, collectClassDoc(ts, node));
1619
+ }
1620
+ }
1621
+ if (ts.isCallExpression(node)) {
1622
+ const callee = node.expression;
1623
+ if (ts.isIdentifier(callee) && (callee.text === "defineQueries" || callee.text === "defineCommands")) {
1624
+ const arg = node.arguments[0];
1625
+ if (arg && ts.isObjectLiteralExpression(arg)) {
1626
+ collectDefinitionDocs(ts, arg, definitions, ambiguousDefinitionKeys);
1627
+ }
1628
+ }
1629
+ }
1630
+ ts.forEachChild(node, visit);
1631
+ };
1632
+ visit(sf);
1633
+ }
1634
+ return {
1635
+ classes,
1636
+ ambiguousClassNames,
1637
+ definitions,
1638
+ ambiguousDefinitionKeys
1639
+ };
1640
+ }
1641
+ function normalize(p) {
1642
+ return p.replace(/\\/g, "/");
1643
+ }
1644
+ function mergeIntoRegistry(extracted, registry) {
1645
+ const countByName = /* @__PURE__ */ new Map();
1646
+ for (const [cls] of registry.getAll()) {
1647
+ countByName.set(cls.name, (countByName.get(cls.name) ?? 0) + 1);
1648
+ }
1649
+ for (const [cls, meta] of registry.getAll()) {
1650
+ const name = cls.name;
1651
+ if (extracted.ambiguousClassNames.has(name)) continue;
1652
+ if ((countByName.get(name) ?? 0) !== 1) continue;
1653
+ const classDoc = extracted.classes.get(name);
1654
+ if (!classDoc) continue;
1655
+ applyClassDoc(classDoc, meta);
1656
+ }
1657
+ }
1658
+ function applyClassDoc(classDoc, meta) {
1659
+ if (meta.description === void 0 && classDoc.own !== void 0) {
1660
+ meta.description = classDoc.own;
1661
+ }
1662
+ for (const field of meta.fields) {
1663
+ const doc = classDoc.members.get(field.propertyName);
1664
+ if (doc === void 0) continue;
1665
+ if (field.options?.description !== void 0) continue;
1666
+ field.options = { ...field.options ?? {}, description: doc };
1667
+ }
1668
+ for (const rel of meta.relations) {
1669
+ const doc = classDoc.members.get(rel.propertyName);
1670
+ if (doc === void 0) continue;
1671
+ if (rel.options?.description !== void 0) continue;
1672
+ rel.options = { ...rel.options ?? {}, description: doc };
1673
+ }
1674
+ for (const gsi of meta.gsiDefinitions) {
1675
+ const doc = classDoc.gsis.get(gsi.indexName);
1676
+ if (doc === void 0) continue;
1677
+ if (gsi.description !== void 0) continue;
1678
+ gsi.description = doc;
1679
+ }
1680
+ }
1681
+ function mergeIntoDefinitions(extracted, map) {
1682
+ for (const [key, def] of Object.entries(map)) {
1683
+ if (extracted.ambiguousDefinitionKeys.has(key)) continue;
1684
+ const defDoc = extracted.definitions.get(key);
1685
+ if (!defDoc) continue;
1686
+ if (def.description === void 0 && defDoc.own !== void 0) {
1687
+ def.description = defDoc.own;
1688
+ }
1689
+ for (const [paramName, descriptor] of Object.entries(def.params)) {
1690
+ const doc = defDoc.params.get(paramName);
1691
+ if (doc === void 0) continue;
1692
+ if (descriptor.description !== void 0) continue;
1693
+ descriptor.description = doc;
1694
+ }
1695
+ }
1696
+ }
1697
+ async function applyJsDocDescriptions(sources, queries, commands, registry = MetadataRegistry, opts = {}) {
1698
+ const ts = await (opts.loadTs ?? loadTypescript)();
1699
+ if (!ts) {
1700
+ if (!warnedTypescriptMissing) {
1701
+ warnedTypescriptMissing = true;
1702
+ (opts.warn ?? ((m) => void process.stderr.write(m)))(
1703
+ TYPESCRIPT_MISSING_WARNING
1704
+ );
1705
+ }
1706
+ return false;
1707
+ }
1708
+ try {
1709
+ const files = [
1710
+ sources.entry,
1711
+ ...sources.queries ? [sources.queries] : [],
1712
+ ...sources.commands ? [sources.commands] : []
1713
+ ].filter((f, i, a) => a.indexOf(f) === i);
1714
+ const extracted = extract(ts, files);
1715
+ mergeIntoRegistry(extracted, registry);
1716
+ mergeIntoDefinitions(extracted, queries);
1717
+ mergeIntoDefinitions(extracted, commands);
1718
+ return true;
1719
+ } catch {
1720
+ return false;
1721
+ }
1722
+ }
1723
+
1479
1724
  // src/cli/handlers.ts
1480
1725
  function fail(code, message, exitCode) {
1481
1726
  process.stderr.write(JSON.stringify({ code, message }) + "\n");
@@ -1552,6 +1797,16 @@ var handlers = {
1552
1797
  contextsPath ?? contractsPath ?? entry,
1553
1798
  "contexts"
1554
1799
  );
1800
+ const abs = (p) => isAbsolute(p) ? p : resolve(process.cwd(), p);
1801
+ await applyJsDocDescriptions(
1802
+ {
1803
+ entry: abs(entry),
1804
+ queries: abs(queriesPath ?? entry),
1805
+ commands: abs(commandsPath ?? entry)
1806
+ },
1807
+ queries,
1808
+ commands
1809
+ );
1555
1810
  const files = renderBundle(queries, commands, void 0, transactions, {
1556
1811
  dataclass: Boolean(dataclass),
1557
1812
  contracts: { contracts, contexts }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SelectableOf, g as PrimaryKeyOf, h as RequestContext, i as Middleware, j as ReadRequestKind, k as CtxModel, l as ReadParams, m as ReadRequestCtx, D as DynamoDBOperation, I as Item, E as Executor, n as RetryPolicy, o as ExecutionPlanSpec, p as EntityMetadata, K as KeyDefinition, G as GsiDefinition, q as ModelKind, F as FieldOptions, r as DynamoType, s as ProjectionTransform, t as MaintainEvent, u as MembershipPredicate, v as MaintainConsistency, w as MaintainUpdateMode, x as MembershipPredicateOp, y as RelationOptions, A as AggregateOptions, z as AggregateValue, H as SelectBuilderSpec, J as RawCondition, L as TransactionSpec, N as Manifest, O as RetryOverride, Q as ExecutionPlan, V as FieldMetadata, X as ResolvedKey, R as ReadExecOptions, a as ExecutorResult, B as BatchGetExecInput, P as PutInput, W as WriteExecOptions, b as WriteResult, U as UpdateInput, c as DeleteInput, d as BatchWriteExecItem, e as BatchExecOptions, T as TransactWriteExecItem, Y as CdcEmulatorOptions, Z as ChangeHandler, _ as Unsubscribe, $ as FaultSpec, a0 as ConcurrentRecomputeRef, C as ChangeEvent, a1 as EventLog, a2 as ReplayOptions, a3 as ShardId, a4 as ViewDefinition, a5 as RelationMetadata, a6 as TransactionItemSpec, a7 as MaintainEffect, M as ModelStatic, f as DDBModel, a8 as Param, a9 as ParamDescriptor, aa as DefinitionMap, ab as OperationDefinition, ac as WriteDefinitionOptions, ad as PartialQueryKeyOf, ae as StrictSelectSpec, af as ReadDefinitionOptions, ag as EntityInput, ah as UniqueQueryKeyOf, ai as EntityRef, aj as ConditionInput, ak as QueryModelContract, al as QueryMethodSpec, am as CommandModelContract, an as CommandMethodSpec, ao as ContractSpec, ap as QuerySpec, aq as CommandSpec, ar as ContextSpec, as as OperationsDocument, at as AnyOperationDefinition, au as BridgeBundle, av as ConditionSpec } from './types-B9rJ1z3H.js';
2
- export { aw as AggregateMetadata, ax as BatchDeleteRequest, ay as BatchGetOptions, az as BatchGetRequest, aA as BatchGetResult, aB as BatchPutRequest, aC as BatchResult, aD as BatchWriteRequest, aE as CONTRACT_RANGE_FANOUT_CONCURRENCY, aF as CdcMode, aG as CdcModelRegistry, aH as CdcSubscribeHandlers, aI as Change, aJ as ChangeBatch, aK as ChangeEventName, aL as ClockMode, aM as CollectionEffect, aN as CollectionOptions, aO as Column, aP as ColumnMap, aQ as CommandContractMethodSpec, aR as CommandInputShape, aS as CommandMethod, aT as CommandPlan, aU as CommandResolutionTarget, aV as CommandResultKind, aW as CommandSelectShape, aX as CompiledFragment, aY as ComposeSpec, aZ as CondSlot, a_ as ConditionCheckInput, a$ as Connection, b0 as ContractCallSignature, b1 as ContractCardinality, b2 as ContractCommandParams, b3 as ContractCommandResult, b4 as ContractComposeNode, b5 as ContractFromRef, b6 as ContractInputArity, b7 as ContractItem, b8 as ContractKeyFieldRef, b9 as ContractKeyInput, ba as ContractKeyRef, bb as ContractKeySpec, bc as ContractKind, bd as ContractMethodOp, be as ContractParamRef, bf as ContractQueryParams, bg as ContractResolution, bh as CounterAggregate, bi as CounterEffect, bj as CtxBase, bk as DEFAULT_MAX_ATTEMPTS, bl as DEFAULT_RETRY_POLICY, bm as DeleteOptions, bn as DeriveEffect, bo as DerivedEdgeWrite, bp as DerivedUpdate, bq as DescriptorBinding, br as ENTITY_WRITES_MARKER, bs as EdgeEffect, bt as EffectPath, bu as EmbeddedMetadata, bv as EmitEffect, bw as EntityWritesDefinition, bx as EntityWritesShape, by as ExecutableCommandContract, bz as ExecutableQueryContract, bA as FilterInput, bB as FilterSpec, bC as FragmentInput, bD as GsiDefinitionMarker, bE as GsiOptions, bF as IdempotencyEffect, bG as InProcessWriteDescriptor, bH as InputArity, bI as KeyDefinitionMarker, bJ as KeySegment, bK as KeySlot, bL as KeyStructure, bM as KeyedResult, bN as LIFECYCLE_CONTRACT_MARKER, bO as LifecycleContract, bP as LifecycleEffects, bQ as LiteralParam, bR as MaintainItem, bS as MaintainTrigger, bT as MaintenanceGraph, bU as ManifestEntity, bV as ManifestField, bW as ManifestFieldType, bX as ManifestGsi, bY as ManifestKey, bZ as ManifestRelation, b_ as ManifestTable, b$ as MembershipEffect, c0 as ModelRef, c1 as MutateMode, c2 as MutateOptions, c3 as MutateParallelResult, c4 as MutateTransactionResult, c5 as MutationBody, c6 as MutationDescriptorMap, c7 as MutationFragment, c8 as MutationInputProxy, c9 as MutationInputRef, ca as MutationIntent, cb as NumberParam, cc as OperationKind, cd as OperationSpec, ce as ParallelOpResult, cf as ParamKind, cg as ParamSpec, ch as ParamStructure, ci as PersistCtx, cj as PersistOrigin, ck as PlannedCommandMethod, cl as ProjectionMap, cm as ProjectionTransformOp, cn as PutOptions, co as QueryContractMethodSpec, cp as QueryEnvelopeResult, cq as QueryKeyOf, cr as QueryMethod, cs as QueryResult, ct as RangeConditionSpec, cu as ReadEnvelope, cv as ReadOpCtx, cw as ReadOpKind, cx as ReadOperationType, cy as ReadRouteDescriptor, cz as ReadRouteOptions, cA as ReadRouteResult, cB as RecordedCompose, cC as RelationBuilder, cD as RelationConsistency, cE as RelationLimitOptions, cF as RelationPattern, cG as RelationProjection, cH as RelationReadOptions, cI as RelationSelect, cJ as RelationSpec, cK as RelationUpdateMode, cL as RelationWriteOptions, cM as RequiresEffect, cN as Resolution, cO as RetryInfo, cP as RetryOperationKind, cQ as SPEC_VERSION, cR as SegmentSpec, cS as SegmentedKey, cT as SelectBuilder, cU as SelectOf, cV as SnapshotEffect, cW as StartingPosition, cX as StreamViewType, cY as StringParam, cZ as SubscribeHandler, c_ as SubscribeHandlers, c$ as TransactionContext, d0 as TransactionItemType, d1 as UniqueEffect, d2 as Updatable, d3 as UpdateOptions, d4 as ViewSourceSlice, d5 as WhenSpec, d6 as WriteCtx, d7 as WriteDescriptor, d8 as WriteEnvelope, d9 as WriteInput, da as WriteKind, db as WriteLifecyclePhase, dc as WriteMiddleware, dd as WriteOperationType, de as WriteRecorder, df as WriteResultProjection, dg as attachModelClass, dh as buildDeleteInput, di as buildMaintenanceGraph, dj as buildPutInput, dk as buildSubscribeHandler, dl as buildUpdateInput, dm as collectViewDefinitions, dn as compileFragment, dp as compileMutationPlan, dq as compileSingleFragmentPlan, dr as cond, ds as contractOfMethodSpec, dt as definePlan, du as entityWrites, dv as executeBatchGet, dw as executeBatchWrite, dx as executeCommandMethod, dy as executeDelete, dz as executeKeyedBatchGet, dA as executePut, dB as executeQueryMethod, dC as executeRangeFanout, dD as executeTransaction, dE as executeUpdate, dF as from, dG as getEntityWrites, dH as gsi, dI as identity, dJ as isColumn, dK as isCommandModelContract, dL as isCommandPlan, dM as isContractComposeNode, dN as isContractFromRef, dO as isContractKeyFieldRef, dP as isContractKeyRef, dQ as isContractParamRef, dR as isEntityWritesDefinition, dS as isKeySegment, dT as isLifecycleContract, dU as isMaintainTrigger, dV as isMutationFragment, dW as isMutationInputRef, dX as isParam, dY as isPlannedCommandMethod, dZ as isQueryModelContract, d_ as isRetryableError, d$ as isRetryableTransactionCancellation, e0 as k, e1 as key, e2 as lifecyclePhaseForIntent, e3 as maintainTrigger, e4 as mintContractKeyFieldRef, e5 as mintContractParamRef, e6 as mutation, e7 as param, e8 as preview, e9 as publicCommandModel, ea as publicQueryModel, eb as query, ec as resolveLifecycle, ed as wholeKeysSentinel } from './types-B9rJ1z3H.js';
1
+ import { S as SelectableOf, g as PrimaryKeyOf, h as RequestContext, i as Middleware, j as ReadRequestKind, k as CtxModel, l as ReadParams, m as ReadRequestCtx, D as DynamoDBOperation, I as Item, E as Executor, n as RetryPolicy, o as ExecutionPlanSpec, p as EntityMetadata, K as KeyDefinition, G as GsiDefinition, q as ModelKind, F as FieldOptions, r as DynamoType, s as ProjectionTransform, t as MaintainEvent, u as MembershipPredicate, v as MaintainConsistency, w as MaintainUpdateMode, x as MembershipPredicateOp, y as RelationOptions, A as AggregateOptions, z as AggregateValue, H as SelectBuilderSpec, J as RawCondition, L as TransactionSpec, N as Manifest, O as RetryOverride, Q as ExecutionPlan, V as FieldMetadata, X as ResolvedKey, R as ReadExecOptions, a as ExecutorResult, B as BatchGetExecInput, P as PutInput, W as WriteExecOptions, b as WriteResult, U as UpdateInput, c as DeleteInput, d as BatchWriteExecItem, e as BatchExecOptions, T as TransactWriteExecItem, Y as CdcEmulatorOptions, Z as ChangeHandler, _ as Unsubscribe, $ as FaultSpec, a0 as ConcurrentRecomputeRef, C as ChangeEvent, a1 as EventLog, a2 as ReplayOptions, a3 as ShardId, a4 as ViewDefinition, a5 as RelationMetadata, a6 as TransactionItemSpec, a7 as MaintainEffect, M as ModelStatic, f as DDBModel, a8 as Param, a9 as ParamDescriptor, aa as DefinitionMap, ab as OperationDefinition, ac as WriteDefinitionOptions, ad as PartialQueryKeyOf, ae as StrictSelectSpec, af as ReadDefinitionOptions, ag as EntityInput, ah as UniqueQueryKeyOf, ai as EntityRef, aj as ConditionInput, ak as QueryModelContract, al as QueryMethodSpec, am as CommandModelContract, an as CommandMethodSpec, ao as ContractSpec, ap as QuerySpec, aq as CommandSpec, ar as ContextSpec, as as OperationsDocument, at as AnyOperationDefinition, au as BridgeBundle, av as ConditionSpec } from './types-m1Ect6hG.js';
2
+ export { aw as AggregateMetadata, ax as BatchDeleteRequest, ay as BatchGetOptions, az as BatchGetRequest, aA as BatchGetResult, aB as BatchPutRequest, aC as BatchResult, aD as BatchWriteRequest, aE as CONTRACT_RANGE_FANOUT_CONCURRENCY, aF as CdcMode, aG as CdcModelRegistry, aH as CdcSubscribeHandlers, aI as Change, aJ as ChangeBatch, aK as ChangeEventName, aL as ClockMode, aM as CollectionEffect, aN as CollectionOptions, aO as Column, aP as ColumnMap, aQ as CommandContractMethodSpec, aR as CommandInputShape, aS as CommandMethod, aT as CommandPlan, aU as CommandResolutionTarget, aV as CommandResultKind, aW as CommandSelectShape, aX as CompiledFragment, aY as ComposeSpec, aZ as CondSlot, a_ as ConditionCheckInput, a$ as Connection, b0 as ContractCallSignature, b1 as ContractCardinality, b2 as ContractCommandParams, b3 as ContractCommandResult, b4 as ContractComposeNode, b5 as ContractFromRef, b6 as ContractInputArity, b7 as ContractItem, b8 as ContractKeyFieldRef, b9 as ContractKeyInput, ba as ContractKeyRef, bb as ContractKeySpec, bc as ContractKind, bd as ContractMethodOp, be as ContractParamRef, bf as ContractQueryParams, bg as ContractResolution, bh as CounterAggregate, bi as CounterEffect, bj as CtxBase, bk as DEFAULT_MAX_ATTEMPTS, bl as DEFAULT_RETRY_POLICY, bm as DeleteOptions, bn as DeriveEffect, bo as DerivedEdgeWrite, bp as DerivedUpdate, bq as DescriptorBinding, br as ENTITY_WRITES_MARKER, bs as EdgeEffect, bt as EffectPath, bu as EmbeddedMetadata, bv as EmitEffect, bw as EntityWritesDefinition, bx as EntityWritesShape, by as ExecutableCommandContract, bz as ExecutableQueryContract, bA as FilterInput, bB as FilterSpec, bC as FragmentInput, bD as GsiDefinitionMarker, bE as GsiOptions, bF as IdempotencyEffect, bG as InProcessWriteDescriptor, bH as InputArity, bI as KeyDefinitionMarker, bJ as KeySegment, bK as KeySlot, bL as KeyStructure, bM as KeyedResult, bN as LIFECYCLE_CONTRACT_MARKER, bO as LifecycleContract, bP as LifecycleEffects, bQ as LiteralParam, bR as MaintainItem, bS as MaintainTrigger, bT as MaintenanceGraph, bU as ManifestEntity, bV as ManifestField, bW as ManifestFieldType, bX as ManifestGsi, bY as ManifestKey, bZ as ManifestRelation, b_ as ManifestTable, b$ as MembershipEffect, c0 as ModelRef, c1 as MutateMode, c2 as MutateOptions, c3 as MutateParallelResult, c4 as MutateTransactionResult, c5 as MutationBody, c6 as MutationDescriptorMap, c7 as MutationFragment, c8 as MutationInputProxy, c9 as MutationInputRef, ca as MutationIntent, cb as NumberParam, cc as OperationKind, cd as OperationSpec, ce as ParallelOpResult, cf as ParamKind, cg as ParamSpec, ch as ParamStructure, ci as PersistCtx, cj as PersistOrigin, ck as PlannedCommandMethod, cl as ProjectionMap, cm as ProjectionTransformOp, cn as PutOptions, co as QueryContractMethodSpec, cp as QueryEnvelopeResult, cq as QueryKeyOf, cr as QueryMethod, cs as QueryResult, ct as RangeConditionSpec, cu as ReadEnvelope, cv as ReadOpCtx, cw as ReadOpKind, cx as ReadOperationType, cy as ReadRouteDescriptor, cz as ReadRouteOptions, cA as ReadRouteResult, cB as RecordedCompose, cC as RelationBuilder, cD as RelationConsistency, cE as RelationLimitOptions, cF as RelationPattern, cG as RelationProjection, cH as RelationReadOptions, cI as RelationSelect, cJ as RelationSpec, cK as RelationUpdateMode, cL as RelationWriteOptions, cM as RequiresEffect, cN as Resolution, cO as RetryInfo, cP as RetryOperationKind, cQ as SPEC_VERSION, cR as SegmentSpec, cS as SegmentedKey, cT as SelectBuilder, cU as SelectOf, cV as SnapshotEffect, cW as StartingPosition, cX as StreamViewType, cY as StringParam, cZ as SubscribeHandler, c_ as SubscribeHandlers, c$ as TransactionContext, d0 as TransactionItemType, d1 as UniqueEffect, d2 as Updatable, d3 as UpdateOptions, d4 as ViewSourceSlice, d5 as WhenSpec, d6 as WriteCtx, d7 as WriteDescriptor, d8 as WriteEnvelope, d9 as WriteInput, da as WriteKind, db as WriteLifecyclePhase, dc as WriteMiddleware, dd as WriteOperationType, de as WriteRecorder, df as WriteResultProjection, dg as attachModelClass, dh as buildDeleteInput, di as buildMaintenanceGraph, dj as buildPutInput, dk as buildSubscribeHandler, dl as buildUpdateInput, dm as collectViewDefinitions, dn as compileFragment, dp as compileMutationPlan, dq as compileSingleFragmentPlan, dr as cond, ds as contractOfMethodSpec, dt as definePlan, du as entityWrites, dv as executeBatchGet, dw as executeBatchWrite, dx as executeCommandMethod, dy as executeDelete, dz as executeKeyedBatchGet, dA as executePut, dB as executeQueryMethod, dC as executeRangeFanout, dD as executeTransaction, dE as executeUpdate, dF as from, dG as getEntityWrites, dH as gsi, dI as identity, dJ as isColumn, dK as isCommandModelContract, dL as isCommandPlan, dM as isContractComposeNode, dN as isContractFromRef, dO as isContractKeyFieldRef, dP as isContractKeyRef, dQ as isContractParamRef, dR as isEntityWritesDefinition, dS as isKeySegment, dT as isLifecycleContract, dU as isMaintainTrigger, dV as isMutationFragment, dW as isMutationInputRef, dX as isParam, dY as isPlannedCommandMethod, dZ as isQueryModelContract, d_ as isRetryableError, d$ as isRetryableTransactionCancellation, e0 as k, e1 as key, e2 as lifecyclePhaseForIntent, e3 as maintainTrigger, e4 as mintContractKeyFieldRef, e5 as mintContractParamRef, e6 as mutation, e7 as param, e8 as preview, e9 as publicCommandModel, ea as publicQueryModel, eb as query, ec as resolveLifecycle, ed as wholeKeysSentinel } from './types-m1Ect6hG.js';
3
3
  import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
4
4
  import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
5
5
 
@@ -735,6 +735,16 @@ interface MaintainedFromOptions<Self = unknown> {
735
735
  readonly when?: MembershipPredicate;
736
736
  readonly consistency?: MaintainConsistency;
737
737
  readonly updateMode?: MaintainUpdateMode;
738
+ /**
739
+ * Optional human-readable description of this maintained-from source slice (issue
740
+ * #166, follow-up of #154). Pure documentation metadata — it does NOT affect the
741
+ * maintenance IR or any runtime behaviour. Captured onto
742
+ * {@link MaintainedFromMetadata.description}. The maintenance IR is deliberately
743
+ * kept off `manifest.json` / `operations.json` and the generated Python (see the
744
+ * note on {@link MaintainedFromMetadata.description}), so this is a metadata-layer
745
+ * capture only. Omit for byte-identical metadata.
746
+ */
747
+ readonly description?: string;
738
748
  }
739
749
  /** The `(self, source) =>` symbolic callback evaluated at decoration time. */
740
750
  type MaintainedFromCallback<Self, Source> = (self: SelfProxy<Self>, source: SourceProxy<Source>) => MaintainedFromOptions<Self>;
@@ -837,7 +847,7 @@ type HasManyVersionedCallback<Self, Source> = (self: SelfProxy<Self>, source: So
837
847
  declare function hasMany(targetFactory: () => new (...args: unknown[]) => unknown, keyBinding: Record<string, string>, options?: RelationOptions): (value: undefined, context: ClassFieldDecoratorContext) => void;
838
848
  declare function hasMany<Self = unknown, Source = unknown>(targetFactory: () => new (...args: unknown[]) => unknown, callback: HasManyVersionedCallback<Self, Source>): (value: undefined, context: ClassFieldDecoratorContext) => void;
839
849
  declare function belongsTo(targetFactory: () => new (...args: unknown[]) => unknown, keyBinding: Record<string, string>, options?: RelationOptions): (_value: undefined, context: ClassFieldDecoratorContext) => void;
840
- declare function hasOne(targetFactory: () => new (...args: unknown[]) => unknown, keyBinding: Record<string, string>): (value: undefined, context: ClassFieldDecoratorContext) => void;
850
+ declare function hasOne(targetFactory: () => new (...args: unknown[]) => unknown, keyBinding: Record<string, string>, options?: RelationOptions): (value: undefined, context: ClassFieldDecoratorContext) => void;
841
851
  declare function hasOne<Self = unknown, Source = unknown>(targetFactory: () => new (...args: unknown[]) => unknown, callback: HasOneVersionedCallback<Self, Source>): (value: undefined, context: ClassFieldDecoratorContext) => void;
842
852
 
843
853
  /**
package/dist/index.js CHANGED
@@ -77,7 +77,7 @@ import {
77
77
  validateDepth,
78
78
  when,
79
79
  wholeKeysSentinel
80
- } from "./chunk-FI63YKK5.js";
80
+ } from "./chunk-H5TUW2WR.js";
81
81
  import {
82
82
  CdcEmulator,
83
83
  MAINT_OUTBOX_PK_PREFIX,
@@ -89,7 +89,7 @@ import {
89
89
  orderAndTrimCollection,
90
90
  pathField,
91
91
  projectFrom
92
- } from "./chunk-EMJHTUA4.js";
92
+ } from "./chunk-QBXLQNXY.js";
93
93
  import {
94
94
  BATCH_GET_MAX_KEYS,
95
95
  BATCH_WRITE_MAX_ITEMS,
@@ -156,7 +156,8 @@ import {
156
156
  resolveModelClass,
157
157
  segmentFieldNames,
158
158
  serializeFieldValue
159
- } from "./chunk-B3GWIWT6.js";
159
+ } from "./chunk-W3GEJPPV.js";
160
+ import "./chunk-MCKGQKYU.js";
160
161
 
161
162
  // src/metadata/prefix.ts
162
163
  function derivePrefix(customPrefix, className) {
@@ -520,7 +521,7 @@ function belongsTo(targetFactory, keyBinding, options) {
520
521
  });
521
522
  };
522
523
  }
523
- function hasOne(targetFactory, keyBindingOrCallback) {
524
+ function hasOne(targetFactory, keyBindingOrCallback, options) {
524
525
  return function(_value, context) {
525
526
  const propertyName = String(context.name);
526
527
  assertRelationPropertyNameAllowed(propertyName);
@@ -547,7 +548,12 @@ function hasOne(targetFactory, keyBindingOrCallback) {
547
548
  type: "hasOne",
548
549
  propertyName,
549
550
  targetFactory,
550
- keyBinding: keyBindingOrCallback
551
+ keyBinding: keyBindingOrCallback,
552
+ // Legacy navigation `@hasOne` now accepts a (purely-documentary, issue #166)
553
+ // `RelationOptions` third argument, symmetric with `@hasMany`/`@belongsTo`.
554
+ // Included ONLY when supplied so an option-less `@hasOne` records metadata with
555
+ // no `options` key — byte-identical to the pre-#166 collected metadata.
556
+ ...options !== void 0 ? { options } : {}
551
557
  });
552
558
  };
553
559
  }
@@ -681,7 +687,10 @@ function maintainedFrom(source, callback) {
681
687
  ...collection ? { collection } : {},
682
688
  ...opts.when ? { when: opts.when } : {},
683
689
  ...opts.consistency !== void 0 ? { consistency: opts.consistency } : {},
684
- ...opts.updateMode !== void 0 ? { updateMode: opts.updateMode } : {}
690
+ ...opts.updateMode !== void 0 ? { updateMode: opts.updateMode } : {},
691
+ // Purely-documentary description (issue #166); recorded only when declared so an
692
+ // undescribed `@maintainedFrom` is byte-identical to the pre-#166 metadata.
693
+ ...opts.description !== void 0 ? { description: opts.description } : {}
685
694
  };
686
695
  collectMaintainedFrom(metadata);
687
696
  };
@@ -1,4 +1,4 @@
1
- import { E as Executor, D as DynamoDBOperation, R as ReadExecOptions, a as ExecutorResult, B as BatchGetExecInput, P as PutInput, W as WriteExecOptions, b as WriteResult, U as UpdateInput, c as DeleteInput, d as BatchWriteExecItem, e as BatchExecOptions, T as TransactWriteExecItem, M as ModelStatic, f as DDBModel, C as ChangeEvent } from '../types-B9rJ1z3H.js';
1
+ import { E as Executor, D as DynamoDBOperation, R as ReadExecOptions, a as ExecutorResult, B as BatchGetExecInput, P as PutInput, W as WriteExecOptions, b as WriteResult, U as UpdateInput, c as DeleteInput, d as BatchWriteExecItem, e as BatchExecOptions, T as TransactWriteExecItem, M as ModelStatic, f as DDBModel, C as ChangeEvent } from '../types-m1Ect6hG.js';
2
2
  import '@aws-sdk/client-dynamodb';
3
3
 
4
4
  /**
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  createCdcEmulator
3
- } from "../chunk-EMJHTUA4.js";
3
+ } from "../chunk-QBXLQNXY.js";
4
4
  import {
5
5
  ClientManager,
6
6
  MetadataRegistry,
7
7
  TableMapping,
8
8
  resolveModelClass
9
- } from "../chunk-B3GWIWT6.js";
9
+ } from "../chunk-W3GEJPPV.js";
10
+ import "../chunk-MCKGQKYU.js";
10
11
 
11
12
  // src/memory/memory-store.ts
12
13
  function deepClone(value) {