graphddb 0.7.8 → 0.7.10

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/dist/index.js CHANGED
@@ -1,31 +1,17 @@
1
1
  import {
2
2
  queryBoundaryRule
3
3
  } from "./chunk-MMVHOUM4.js";
4
- import {
5
- CdcEmulator,
6
- MAINT_OUTBOX_PK_PREFIX,
7
- MaintenanceDrain,
8
- compareDesc,
9
- createCdcEmulator,
10
- createMaintenanceDrain,
11
- createMaintenanceDrainHandler,
12
- orderAndTrimCollection,
13
- pathField,
14
- projectFrom
15
- } from "./chunk-IA6MW2HP.js";
16
4
  import {
17
5
  BatchGetResult,
18
6
  DDBModel,
19
7
  EDGE_WRITES_MARKER,
20
8
  LOGICAL_EFFECT_CATEGORIES,
21
- MARKER_ROW_ENTITY,
22
9
  OLD_VALUE_NAMESPACE,
23
10
  PREPARED_FORMAT_VERSION,
24
11
  PREPARE_CACHE_MAX,
25
12
  PreparedReadStatement,
26
13
  PreparedWriteStatement,
27
14
  RELATION_TRAVERSAL_CONCURRENCY,
28
- SPEC_VERSION,
29
15
  assertBundleSerializable,
30
16
  assertContractBoundaries,
31
17
  assertContractN1Safe,
@@ -51,8 +37,6 @@ import {
51
37
  contractOfMethodSpec,
52
38
  decodeCursor,
53
39
  definePlan,
54
- defineTransaction,
55
- defineTransactions,
56
40
  deriveCompositionPlan,
57
41
  deriveEdgeWriteItems,
58
42
  deriveEdgeWriteItemsFor,
@@ -86,7 +70,6 @@ import {
86
70
  isPlannedCommandMethod,
87
71
  isPreparedParamRef,
88
72
  isQueryModelContract,
89
- isTransactionRef,
90
73
  mapWithConcurrency,
91
74
  mintContractKeyFieldRef,
92
75
  mintContractParamRef,
@@ -100,9 +83,57 @@ import {
100
83
  resolveRelations,
101
84
  serializeEffectParams,
102
85
  validateDepth,
103
- when,
104
86
  wholeKeysSentinel
105
- } from "./chunk-NZRCBEWS.js";
87
+ } from "./chunk-EOJDN3SA.js";
88
+ import {
89
+ CdcEmulator,
90
+ MAINT_OUTBOX_PK_PREFIX,
91
+ MaintenanceDrain,
92
+ compareDesc,
93
+ createCdcEmulator,
94
+ createMaintenanceDrain,
95
+ createMaintenanceDrainHandler,
96
+ orderAndTrimCollection,
97
+ pathField,
98
+ projectFrom
99
+ } from "./chunk-AD6ZQTTE.js";
100
+ import {
101
+ ENTITY_WRITES_MARKER,
102
+ LIFECYCLE_CONTRACT_MARKER,
103
+ buildMaintenanceGraph,
104
+ buildSubscribeHandler,
105
+ collectViewDefinitions,
106
+ detectRelationFields,
107
+ entityWrites,
108
+ getEntityWrites,
109
+ getImplicitKeyFields,
110
+ hydrate,
111
+ identity,
112
+ isEntityWritesDefinition,
113
+ isLifecycleContract,
114
+ isMaintainTrigger,
115
+ isSelectBuilder,
116
+ lifecyclePhaseForIntent,
117
+ maintainTrigger,
118
+ parseChange,
119
+ preview
120
+ } from "./chunk-DFUKGU2Q.js";
121
+ import {
122
+ EXPR_VERSION,
123
+ MARKER_ROW_ENTITY,
124
+ SCP_LOWERED_MARKER,
125
+ SPEC_VERSION,
126
+ SPEC_VERSION_SCP,
127
+ SPEC_VERSION_SUPPORTED,
128
+ canonicalizeExpressionSpec,
129
+ defineScpTransaction,
130
+ defineTransaction,
131
+ defineTransactions,
132
+ isTransactionRef,
133
+ operationsContainScpNodes,
134
+ operationsSpecVersion,
135
+ when
136
+ } from "./chunk-3UD3XIF2.js";
106
137
  import {
107
138
  BATCH_GET_MAX_KEYS,
108
139
  BATCH_WRITE_MAX_ITEMS,
@@ -110,8 +141,6 @@ import {
110
141
  DEFAULT_MAX_ATTEMPTS,
111
142
  DEFAULT_RETRY_POLICY,
112
143
  DynamoExecutor,
113
- ENTITY_WRITES_MARKER,
114
- LIFECYCLE_CONTRACT_MARKER,
115
144
  MAX_TRANSACT_ITEMS,
116
145
  MetadataRegistry,
117
146
  RetryingExecutor,
@@ -119,45 +148,28 @@ import {
119
148
  attachModelClass,
120
149
  buildConditionExpression,
121
150
  buildDeleteInput,
122
- buildMaintenanceGraph,
123
151
  buildPutInput,
124
- buildSubscribeHandler,
125
152
  buildUpdateExpression,
126
153
  buildUpdateInput,
127
154
  collapseSameKeyItems,
128
155
  collectRawConditionParams,
129
- collectViewDefinitions,
130
156
  commitTransaction,
131
157
  cond,
132
- detectRelationFields,
133
- entityWrites,
134
158
  execItemKeySignature,
135
159
  executeDelete,
136
160
  executePut,
137
161
  executeTransaction,
138
162
  executeUpdate,
139
- getEntityWrites,
140
- getImplicitKeyFields,
141
163
  gsi,
142
- hydrate,
143
- identity,
144
- isEntityWritesDefinition,
145
- isLifecycleContract,
146
- isMaintainTrigger,
147
164
  isParam,
148
165
  isRawCondition,
149
166
  isRetryableError,
150
167
  isRetryableTransactionCancellation,
151
- isSelectBuilder,
152
- lifecyclePhaseForIntent,
153
- maintainTrigger,
154
168
  param,
155
- parseChange,
156
- preview,
157
169
  resolveConditionTree,
158
170
  resolveModelClass,
159
171
  serializeFieldValue
160
- } from "./chunk-HFFIB77D.js";
172
+ } from "./chunk-3ZU2VW3L.js";
161
173
  import {
162
174
  Linter,
163
175
  TableMapping,
@@ -742,27 +754,129 @@ function cdcProjected() {
742
754
  };
743
755
  }
744
756
 
757
+ // src/operations/declarative-transaction.ts
758
+ import { renderTemplate, TemplateFailure } from "behavior-contracts";
759
+
760
+ // src/runtime/behavior-contracts-adapter.ts
761
+ function toSharedValue(v) {
762
+ if (v === null || v === void 0) return null;
763
+ switch (typeof v) {
764
+ case "string":
765
+ case "boolean":
766
+ case "bigint":
767
+ return v;
768
+ case "number":
769
+ return Number.isInteger(v) ? BigInt(v) : v;
770
+ default:
771
+ break;
772
+ }
773
+ if (v instanceof Date) return v.toJSON();
774
+ if (Array.isArray(v)) return v.map((e) => toSharedValue(e));
775
+ if (typeof v === "object") {
776
+ const out = {};
777
+ for (const [k2, field2] of Object.entries(v)) {
778
+ if (field2 === void 0) continue;
779
+ out[k2] = toSharedValue(field2);
780
+ }
781
+ return out;
782
+ }
783
+ return v;
784
+ }
785
+ function toSharedParams(params) {
786
+ const out = {};
787
+ for (const [name, value] of Object.entries(params)) {
788
+ if (value === void 0) continue;
789
+ out[name] = toSharedValue(value);
790
+ }
791
+ return out;
792
+ }
793
+
794
+ // src/runtime/guard-eval.ts
795
+ import { evaluateExpression, ExprFailure } from "behavior-contracts";
796
+ var GUARD_SCOPE_ROOTS = /* @__PURE__ */ new Set(["input", "item"]);
797
+ function assertGuardScopes(node, context) {
798
+ if (node === null || typeof node !== "object") return;
799
+ const obj = node;
800
+ const ref = obj.ref ?? obj.refOpt;
801
+ if (Array.isArray(ref)) {
802
+ const root = ref[0];
803
+ if (typeof root === "string" && !GUARD_SCOPE_ROOTS.has(root)) {
804
+ throw new Error(
805
+ `${context}: this guard references '${root}', but a client-side guard may only reference the transaction 'input' / fan-out 'item' scopes. An expression that reads a DynamoDB attribute must lower to a ConditionExpression (write-condition class), not be evaluated client-side (issue #265). Refusing to evaluate a stale check.`
806
+ );
807
+ }
808
+ return;
809
+ }
810
+ for (const value of Object.values(obj)) {
811
+ if (Array.isArray(value)) {
812
+ for (const child of value) assertGuardScopes(child, context);
813
+ } else if (value !== null && typeof value === "object") {
814
+ for (const child of Object.values(value)) {
815
+ assertGuardScopes(child, context);
816
+ }
817
+ }
818
+ }
819
+ }
820
+ function evaluateGuard(guard, params, element, context) {
821
+ assertGuardScopes(guard.expr, context);
822
+ const scope = { input: toSharedParams(params) };
823
+ if (element !== void 0) {
824
+ scope.item = toSharedValue(element);
825
+ }
826
+ let result;
827
+ try {
828
+ result = evaluateExpression(guard.expr, scope);
829
+ } catch (exc) {
830
+ if (exc instanceof ExprFailure) {
831
+ throw new Error(`${context}: guard evaluation failed (${exc.code}): ${exc.message}`);
832
+ }
833
+ throw exc;
834
+ }
835
+ if (typeof result !== "boolean") {
836
+ throw new Error(
837
+ `${context}: a guard expression must evaluate to a boolean, got ${result === null ? "null" : typeof result} (issue #265).`
838
+ );
839
+ }
840
+ return result;
841
+ }
842
+
745
843
  // src/operations/declarative-transaction.ts
746
844
  var PLACEHOLDER_RE = /\{[^{}]+\}/g;
845
+ function hasNonCoreScope(template) {
846
+ return (template.match(PLACEHOLDER_RE) ?? []).some((m) => {
847
+ const name = m.slice(1, -1);
848
+ return name.startsWith("item.") || name.startsWith("result.");
849
+ });
850
+ }
747
851
  function resolveTemplate(template, params, element) {
748
- return template.replace(PLACEHOLDER_RE, (match) => {
749
- const name = match.slice(1, -1);
750
- if (name.startsWith("item.")) {
751
- const field2 = name.slice("item.".length);
752
- if (!element || !(field2 in element)) {
852
+ if (hasNonCoreScope(template)) {
853
+ return template.replace(PLACEHOLDER_RE, (match) => {
854
+ const name = match.slice(1, -1);
855
+ if (name.startsWith("item.")) {
856
+ const field2 = name.slice("item.".length);
857
+ if (!element || !(field2 in element)) {
858
+ throw new Error(
859
+ `declarative transaction: element field '${field2}' is not bound; template '${template}' is only valid inside a forEach over the array param that supplies '${field2}'.`
860
+ );
861
+ }
862
+ return String(element[field2]);
863
+ }
864
+ if (!(name in params) || params[name] === void 0 || params[name] === null) {
753
865
  throw new Error(
754
- `declarative transaction: element field '${field2}' is not bound; template '${template}' is only valid inside a forEach over the array param that supplies '${field2}'.`
866
+ `declarative transaction: template '${template}' references unbound parameter '${name}'.`
755
867
  );
756
868
  }
757
- return String(element[field2]);
758
- }
759
- if (!(name in params) || params[name] === void 0 || params[name] === null) {
760
- throw new Error(
761
- `declarative transaction: template '${template}' references unbound parameter '${name}'.`
762
- );
869
+ return String(params[name]);
870
+ });
871
+ }
872
+ try {
873
+ return renderTemplate(template, toSharedParams(params));
874
+ } catch (exc) {
875
+ if (exc instanceof TemplateFailure && exc.code === "UNBOUND_PARAM") {
876
+ throw new Error(`declarative transaction: ${exc.message}.`);
763
877
  }
764
- return String(params[name]);
765
- });
878
+ throw exc;
879
+ }
766
880
  }
767
881
  function isWholePlaceholder(template) {
768
882
  return /^\{[^{}]+\}$/.test(template);
@@ -847,6 +961,11 @@ function applyCondition(condition, target, params, element) {
847
961
  target.ConditionExpression = condition.expression;
848
962
  return;
849
963
  }
964
+ if (condition.kind === "scpExpr") {
965
+ throw new Error(
966
+ "declarative transaction: this runtime does not evaluate scpExpr write conditions yet (spec 1.2 expression vocabulary, issue #261); evaluation lands with Phase 3 S5 (#265). Refusing to execute the write with its condition ignored."
967
+ );
968
+ }
850
969
  if (condition.kind === "expr") {
851
970
  const concrete = resolveConditionTree(
852
971
  condition.declarative,
@@ -1035,10 +1154,14 @@ function expandTransactionItems(spec, manifest, params) {
1035
1154
  }
1036
1155
  for (const element of source) {
1037
1156
  if (item.when && !whenHolds(item.when, params, element)) continue;
1157
+ if (item.guard !== void 0 && !evaluateGuard(item.guard, params, element, "declarative transaction guard"))
1158
+ continue;
1038
1159
  emit(item, element);
1039
1160
  }
1040
1161
  } else {
1041
1162
  if (item.when && !whenHolds(item.when, params, void 0)) continue;
1163
+ if (item.guard !== void 0 && !evaluateGuard(item.guard, params, void 0, "declarative transaction guard"))
1164
+ continue;
1042
1165
  emit(item, void 0);
1043
1166
  }
1044
1167
  }
@@ -1080,9 +1203,9 @@ async function executeDeclarativeTransaction(spec, manifest, params) {
1080
1203
  }
1081
1204
 
1082
1205
  // src/runtime/per-key-cursor.ts
1206
+ import { canonicalValue } from "behavior-contracts";
1083
1207
  function serializeContractKey(key2) {
1084
- const sortedEntries = Object.keys(key2).sort().map((field2) => [field2, key2[field2]]);
1085
- return JSON.stringify(Object.fromEntries(sortedEntries));
1208
+ return canonicalValue(toSharedValue(key2));
1086
1209
  }
1087
1210
  function encodePerKeyCursor(key2, inner) {
1088
1211
  if (inner === null) return null;
@@ -1291,6 +1414,7 @@ async function executeRangeFanout(op, keys, params = {}) {
1291
1414
  }
1292
1415
 
1293
1416
  // src/runtime/prepared-loader.ts
1417
+ import { validateEnvelope, EnvelopeFailure } from "behavior-contracts";
1294
1418
  var LOAD_LABEL = "graphddb.loadPreparedPlan";
1295
1419
  function slotOfBind(bind) {
1296
1420
  if ("param" in bind) return { kind: "param", name: bind.param };
@@ -1490,10 +1614,15 @@ function bindPlan(doc, planId) {
1490
1614
  `${LOAD_LABEL}: unsupported artifact format version '${String(doc.formatVersion)}' (this runtime supports '${PREPARED_FORMAT_VERSION}'). Regenerate the artifact: \`graphddb transform prepared --aot <artifact> --write\`.`
1491
1615
  );
1492
1616
  }
1493
- if (doc.specVersion !== SPEC_VERSION) {
1494
- throw new Error(
1495
- `${LOAD_LABEL}: the artifact was compiled against operation-IR version '${String(doc.specVersion)}' but this runtime speaks '${SPEC_VERSION}'. A version-skewed static plan never executes \u2014 regenerate the artifact.`
1496
- );
1617
+ try {
1618
+ validateEnvelope(doc, SPEC_VERSION_SUPPORTED, { field: "specVersion", label: LOAD_LABEL });
1619
+ } catch (exc) {
1620
+ if (exc instanceof EnvelopeFailure) {
1621
+ throw new Error(
1622
+ `${LOAD_LABEL}: the artifact was compiled against operation-IR version '${String(doc.specVersion)}' but this runtime speaks '${SPEC_VERSION_SUPPORTED}'. A version-skewed static plan never executes \u2014 regenerate the artifact.`
1623
+ );
1624
+ }
1625
+ throw exc;
1497
1626
  }
1498
1627
  const plan2 = doc.plans[planId];
1499
1628
  if (plan2 === void 0) {
@@ -1938,6 +2067,7 @@ function collectConditionParams(condition, out) {
1938
2067
  }
1939
2068
  const obj = condition;
1940
2069
  if (obj.notExists === true) return;
2070
+ if ("scpExpr" in obj) return;
1941
2071
  if (typeof obj.attributeExists === "string") return;
1942
2072
  if (typeof obj.attributeNotExists === "string") return;
1943
2073
  collectConditionTreeParams(obj, out);
@@ -2127,6 +2257,7 @@ export {
2127
2257
  DynamoExecutor,
2128
2258
  EDGE_WRITES_MARKER,
2129
2259
  ENTITY_WRITES_MARKER,
2260
+ EXPR_VERSION,
2130
2261
  LIFECYCLE_CONTRACT_MARKER,
2131
2262
  Linter,
2132
2263
  MAINT_OUTBOX_PK_PREFIX,
@@ -2139,7 +2270,9 @@ export {
2139
2270
  PreparedReadStatement,
2140
2271
  PreparedWriteStatement,
2141
2272
  RetryingExecutor,
2273
+ SCP_LOWERED_MARKER,
2142
2274
  SPEC_VERSION,
2275
+ SPEC_VERSION_SCP,
2143
2276
  TableMapping,
2144
2277
  TransactionContext,
2145
2278
  aggregate,
@@ -2168,6 +2301,7 @@ export {
2168
2301
  buildTransactions,
2169
2302
  buildUpdateExpression,
2170
2303
  buildUpdateInput,
2304
+ canonicalizeExpressionSpec,
2171
2305
  cdcProjected,
2172
2306
  collectContractBoundaryViolations,
2173
2307
  collectContractN1Violations,
@@ -2194,6 +2328,7 @@ export {
2194
2328
  definePut,
2195
2329
  defineQueries,
2196
2330
  defineQuery,
2331
+ defineScpTransaction,
2197
2332
  defineTransaction,
2198
2333
  defineTransactions,
2199
2334
  defineUpdate,
@@ -2276,6 +2411,8 @@ export {
2276
2411
  noScanRule,
2277
2412
  number,
2278
2413
  numberSet,
2414
+ operationsContainScpNodes,
2415
+ operationsSpecVersion,
2279
2416
  param,
2280
2417
  parseChange,
2281
2418
  plan,
@@ -1,8 +1,9 @@
1
- import { L as LintRule } from '../registry-pAnFcc62.js';
2
- export { a as LintResult, b as Linter } from '../registry-pAnFcc62.js';
3
- export { c as createDefaultLinter, g as gsiAmbiguityRule, m as missingGsiRule, n as noScanRule, q as queryBoundaryRule, r as relationDepthRule, a as requireLimitRule } from '../relation-depth-C9t4s9bt.js';
4
- import '../maintenance-view-adapter-BCbgKG5d.js';
1
+ import { L as LintRule } from '../registry-LWE54Sdc.js';
2
+ export { a as LintResult, b as Linter } from '../registry-LWE54Sdc.js';
3
+ export { c as createDefaultLinter, g as gsiAmbiguityRule, m as missingGsiRule, n as noScanRule, q as queryBoundaryRule, r as relationDepthRule, a as requireLimitRule } from '../relation-depth-BRS513Tq.js';
4
+ import '../maintenance-view-adapter-BAZ9uBGe.js';
5
5
  import '@aws-sdk/client-dynamodb';
6
+ import '../types-BQLzTEqh.js';
6
7
 
7
8
  /**
8
9
  * `samePartition` preset validator (Epic #118 child issue H).