@granular-software/sdk 0.4.72 → 0.4.74

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.
@@ -13146,6 +13146,31 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
13146
13146
  }
13147
13147
  }
13148
13148
  });
13149
+ function assertRecordSnapshotTransitionMapping(transition) {
13150
+ if (!transition)
13151
+ throw new Error("A transition commit has no authored transition context.");
13152
+ if (!transition.outcomes || !Object.keys(transition.outcomes).length) {
13153
+ throw new Error(
13154
+ "Automatic product-state mapping requires at least one declared outcome."
13155
+ );
13156
+ }
13157
+ const destinations = /* @__PURE__ */ new Map();
13158
+ for (const [key, outcome] of Object.entries(transition.outcomes)) {
13159
+ if (!outcome || typeof outcome.to !== "string" || !outcome.to) {
13160
+ throw new Error(
13161
+ `Automatic product-state mapping requires a destination for outcome ${key}.`
13162
+ );
13163
+ }
13164
+ const destination = outcome.to === "$current" ? transition.from : outcome.to;
13165
+ const previous = destinations.get(destination);
13166
+ if (previous !== void 0) {
13167
+ throw new Error(
13168
+ `Ambiguous product-state mapping for ${transition.machine}.${transition.transition}: outcomes ${previous} and ${key} both resolve to ${destination}; automatic mapping requires distinct outcome destinations.`
13169
+ );
13170
+ }
13171
+ destinations.set(destination, key);
13172
+ }
13173
+ }
13149
13174
 
13150
13175
  // src/commit.ts
13151
13176
  var MAX_PROJECTION_CHANGES = 1e3;
@@ -13704,6 +13729,11 @@ async function invokeRegisteredEffect(effectMap, request, options = {}) {
13704
13729
  `Transition effect ${request.effectKey} has no resolved transition context; customer code was not invoked`
13705
13730
  );
13706
13731
  }
13732
+ if (commitRequired && declaration?.kind === "transition" && declaration.outcomeSelection === "product_state") {
13733
+ assertRecordSnapshotTransitionMapping(
13734
+ request.context?.invocation?.transition
13735
+ );
13736
+ }
13707
13737
  const idempotencyKey = commitRequired ? await resolveInvocationIdempotencyKey(request) : request.context?.idempotencyKey;
13708
13738
  let commitStarted = false;
13709
13739
  let commitPromise = null;
@@ -15082,7 +15112,7 @@ function buildMachineTypes(classSummary, machine) {
15082
15112
  ];
15083
15113
  }
15084
15114
  function buildMachineMethods(classSummary, machine) {
15085
- const stateName = stateTypeName(classSummary.name, machine.name);
15115
+ const stateName2 = stateTypeName(classSummary.name, machine.name);
15086
15116
  const transitionName = transitionTypeName(classSummary.name, machine.name);
15087
15117
  pathTypeName(classSummary.name, machine.name);
15088
15118
  const docsPrefix = `${classSummary.name}.${machine.name}`;
@@ -15092,12 +15122,12 @@ function buildMachineMethods(classSummary, machine) {
15092
15122
  docs: [`Get the current ${docsPrefix} state.`],
15093
15123
  static: false,
15094
15124
  params: [],
15095
- returnType: `Promise<${stateName} | null>`,
15125
+ returnType: `Promise<${stateName2} | null>`,
15096
15126
  runtime: {
15097
15127
  kind: "state_machine",
15098
15128
  machineName: machine.name,
15099
15129
  className: classSummary.name,
15100
- stateTypeName: stateName,
15130
+ stateTypeName: stateName2,
15101
15131
  transitionTypeName: transitionName,
15102
15132
  operation: "get_current"
15103
15133
  }
@@ -15108,13 +15138,13 @@ function buildMachineMethods(classSummary, machine) {
15108
15138
  `Reach a ${docsPrefix} state through the shortest allowed transition path.`
15109
15139
  ],
15110
15140
  static: false,
15111
- params: [{ name: "target", type: stateName }],
15141
+ params: [{ name: "target", type: stateName2 }],
15112
15142
  returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
15113
15143
  runtime: {
15114
15144
  kind: "state_machine",
15115
15145
  machineName: machine.name,
15116
15146
  className: classSummary.name,
15117
- stateTypeName: stateName,
15147
+ stateTypeName: stateName2,
15118
15148
  transitionTypeName: transitionName,
15119
15149
  operation: "reach"
15120
15150
  }
@@ -15129,7 +15159,7 @@ function buildMachineMethods(classSummary, machine) {
15129
15159
  kind: "state_machine",
15130
15160
  machineName: machine.name,
15131
15161
  className: classSummary.name,
15132
- stateTypeName: stateName,
15162
+ stateTypeName: stateName2,
15133
15163
  transitionTypeName: transitionName,
15134
15164
  operation: "list_transitions"
15135
15165
  }
@@ -15139,12 +15169,12 @@ function buildMachineMethods(classSummary, machine) {
15139
15169
  docs: [`List reachable states for ${docsPrefix} from the current state.`],
15140
15170
  static: false,
15141
15171
  params: [],
15142
- returnType: `Promise<${stateName}[]>`,
15172
+ returnType: `Promise<${stateName2}[]>`,
15143
15173
  runtime: {
15144
15174
  kind: "state_machine",
15145
15175
  machineName: machine.name,
15146
15176
  className: classSummary.name,
15147
- stateTypeName: stateName,
15177
+ stateTypeName: stateName2,
15148
15178
  transitionTypeName: transitionName,
15149
15179
  operation: "list_reachable_states"
15150
15180
  }
@@ -15159,7 +15189,7 @@ function buildMachineMethods(classSummary, machine) {
15159
15189
  kind: "state_machine",
15160
15190
  machineName: machine.name,
15161
15191
  className: classSummary.name,
15162
- stateTypeName: stateName,
15192
+ stateTypeName: stateName2,
15163
15193
  transitionTypeName: transitionName,
15164
15194
  operation: "is_final"
15165
15195
  }
@@ -15170,13 +15200,13 @@ function buildMachineMethods(classSummary, machine) {
15170
15200
  `List shortest transition paths from the current ${docsPrefix} state to a target state.`
15171
15201
  ],
15172
15202
  static: false,
15173
- params: [{ name: "target", type: stateName }],
15174
- returnType: `Promise<Array<{ states: ${stateName}[]; transitions: ${transitionName}[] }>>`,
15203
+ params: [{ name: "target", type: stateName2 }],
15204
+ returnType: `Promise<Array<{ states: ${stateName2}[]; transitions: ${transitionName}[] }>>`,
15175
15205
  runtime: {
15176
15206
  kind: "state_machine",
15177
15207
  machineName: machine.name,
15178
15208
  className: classSummary.name,
15179
- stateTypeName: stateName,
15209
+ stateTypeName: stateName2,
15180
15210
  transitionTypeName: transitionName,
15181
15211
  operation: "paths_to"
15182
15212
  }
@@ -15200,7 +15230,7 @@ function buildMachineMethods(classSummary, machine) {
15200
15230
  kind: "state_machine",
15201
15231
  machineName: machine.name,
15202
15232
  className: classSummary.name,
15203
- stateTypeName: stateName,
15233
+ stateTypeName: stateName2,
15204
15234
  transitionTypeName: transitionName,
15205
15235
  operation: "reach",
15206
15236
  targetState: stateNameValue,
@@ -15219,7 +15249,7 @@ function buildMachineMethods(classSummary, machine) {
15219
15249
  kind: "state_machine",
15220
15250
  machineName: machine.name,
15221
15251
  className: classSummary.name,
15222
- stateTypeName: stateName,
15252
+ stateTypeName: stateName2,
15223
15253
  transitionTypeName: transitionName,
15224
15254
  operation: "prepare_reach",
15225
15255
  targetState: stateNameValue,
@@ -15232,7 +15262,7 @@ function buildMachineMethods(classSummary, machine) {
15232
15262
  kind: "state_machine",
15233
15263
  machineName: machine.name,
15234
15264
  className: classSummary.name,
15235
- stateTypeName: stateName,
15265
+ stateTypeName: stateName2,
15236
15266
  transitionTypeName: transitionName,
15237
15267
  operation: "prepare_create_reach",
15238
15268
  targetState: stateNameValue,
@@ -16400,13 +16430,15 @@ var Environment = class _Environment {
16400
16430
  _apiEndpoint;
16401
16431
  _tokenProvider;
16402
16432
  _beforeMutationSend;
16403
- constructor(granular, envData, apiKey, apiEndpoint, tokenProvider, beforeMutationSend) {
16433
+ _graphqlIdempotencyKey;
16434
+ constructor(granular, envData, apiKey, apiEndpoint, tokenProvider, beforeMutationSend, graphqlIdempotencyKey) {
16404
16435
  this.granular = granular;
16405
16436
  this.envData = envData;
16406
16437
  this._apiKey = apiKey;
16407
16438
  this._apiEndpoint = apiEndpoint;
16408
16439
  this._tokenProvider = tokenProvider;
16409
16440
  this._beforeMutationSend = beforeMutationSend;
16441
+ this._graphqlIdempotencyKey = graphqlIdempotencyKey;
16410
16442
  }
16411
16443
  /** The environment ID */
16412
16444
  get environmentId() {
@@ -16688,8 +16720,8 @@ var Environment = class _Environment {
16688
16720
  * `await env.recordState({ className: "spend_request", id, machine: "lifecycle", state: "policy_review", source: "customer_backend" })`
16689
16721
  */
16690
16722
  state(target) {
16691
- const observe = async (machineName, stateName, input = {}) => {
16692
- const observedState = input.observedState || input.state || stateName;
16723
+ const observe = async (machineName, stateName2, input = {}) => {
16724
+ const observedState = input.observedState || input.state || stateName2;
16693
16725
  if (!observedState) {
16694
16726
  throw new Error("State observation requires a target state");
16695
16727
  }
@@ -16715,7 +16747,7 @@ var Environment = class _Environment {
16715
16747
  {
16716
16748
  get: (_machineTarget, stateProperty) => {
16717
16749
  if (stateProperty === "to") {
16718
- return (stateName, input) => observe(machineProperty, stateName, input || {});
16750
+ return (stateName2, input) => observe(machineProperty, stateName2, input || {});
16719
16751
  }
16720
16752
  if (typeof stateProperty !== "string") return void 0;
16721
16753
  return (input) => observe(
@@ -16949,11 +16981,13 @@ var Environment = class _Environment {
16949
16981
  if (this._beforeMutationSend && isGraphQLMutationDocument(query)) {
16950
16982
  this._beforeMutationSend?.();
16951
16983
  }
16984
+ const idempotencyKey = this._graphqlIdempotencyKey?.(query, variables);
16952
16985
  const response = await fetch(this._apiEndpoint, {
16953
16986
  method: "POST",
16954
16987
  headers: {
16955
16988
  "Content-Type": "application/json",
16956
- Authorization: `Bearer ${authToken}`
16989
+ Authorization: `Bearer ${authToken}`,
16990
+ ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
16957
16991
  },
16958
16992
  body: JSON.stringify({
16959
16993
  environmentId: this.environmentId,
@@ -17008,6 +17042,11 @@ var Environment = class _Environment {
17008
17042
  classNames: options.classNames?.length ? options.classNames : []
17009
17043
  }
17010
17044
  );
17045
+ if (response.errors?.length) {
17046
+ throw new Error(
17047
+ `Record search failed: ${response.errors.map((error) => error.message).join("; ")}`
17048
+ );
17049
+ }
17011
17050
  const seen = /* @__PURE__ */ new Set();
17012
17051
  const results = (response.data?.record_search || []).flatMap((entry) => {
17013
17052
  const className = entry.className?.trim();
@@ -18522,6 +18561,7 @@ var Granular = class _Granular {
18522
18561
  onUnexpectedClose;
18523
18562
  onReconnectError;
18524
18563
  effectHostUrl;
18564
+ graphqlIdempotencyKey;
18525
18565
  debugHttp = process.env.GRANULAR_DEBUG_HTTP === "1";
18526
18566
  /** Sandbox-level effect registry: sandboxId → (effectKey@selector → ToolWithHandler) */
18527
18567
  sandboxEffects = /* @__PURE__ */ new Map();
@@ -18551,6 +18591,7 @@ var Granular = class _Granular {
18551
18591
  this.onUnexpectedClose = options.onUnexpectedClose;
18552
18592
  this.onReconnectError = options.onReconnectError;
18553
18593
  this.effectHostUrl = options.effectHostUrl;
18594
+ this.graphqlIdempotencyKey = options.graphqlIdempotencyKey;
18554
18595
  this.httpUrl = this.apiUrl.replace(/^wss:\/\//, "https://").replace(/^ws:\/\//, "http://").replace(/\/ws$/, "");
18555
18596
  }
18556
18597
  /**
@@ -19566,7 +19607,9 @@ var Granular = class _Granular {
19566
19607
  envData,
19567
19608
  this.apiKey,
19568
19609
  graphqlEndpoint,
19569
- this.tokenProvider
19610
+ this.tokenProvider,
19611
+ void 0,
19612
+ this.graphqlIdempotencyKey
19570
19613
  );
19571
19614
  }
19572
19615
  async bindWebSocketEnvironmentSession(environment, clientId, session, transportOptions = {}) {