@granular-software/sdk 0.4.12 → 0.4.13

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.mjs CHANGED
@@ -1,4 +1,6 @@
1
1
  import * as Automerge from '@automerge/automerge';
2
+ import { normalizeEffectBehaviorSummary } from '@granular-software/metamodel-effect-behaviors';
3
+ import { DEFAULT_METAMODEL_PACKAGES } from '@granular-software/metamodel-preset-default';
2
4
 
3
5
  var __create = Object.create;
4
6
  var __defProp = Object.defineProperty;
@@ -5383,6 +5385,123 @@ function resolveApiUrl(explicitApiUrl, mode) {
5383
5385
  }
5384
5386
  return resolveEndpointMode(mode) === "local" ? LOCAL_API_URL : PRODUCTION_API_URL;
5385
5387
  }
5388
+ function computeEffectKey(effect) {
5389
+ const attachedClass = effect.className?.trim();
5390
+ if (!attachedClass) {
5391
+ return `global:${effect.name}`;
5392
+ }
5393
+ return effect.static ? `class:${attachedClass}:static:${effect.name}` : `class:${attachedClass}:instance:${effect.name}`;
5394
+ }
5395
+ function normalizeEffectBehaviors(value) {
5396
+ return normalizeEffectBehaviorSummary(
5397
+ value
5398
+ ) || {};
5399
+ }
5400
+ function resolveInvocationMode(context) {
5401
+ const mode = context?.invocation?.mode;
5402
+ if (mode === "dryRun" || mode === "reverse") {
5403
+ return mode;
5404
+ }
5405
+ return "execute";
5406
+ }
5407
+ function resolveReverseEffect(effectMap, currentEffect, request, behaviors) {
5408
+ const explicitReverseHandler = request.context?.invocation?.reverseHandler?.trim();
5409
+ const configuredReverseHandler = behaviors.reverse?.handler?.trim();
5410
+ const reverseHandler = explicitReverseHandler || configuredReverseHandler;
5411
+ if (!reverseHandler) {
5412
+ return void 0;
5413
+ }
5414
+ if (reverseHandler.includes(":")) {
5415
+ return effectMap.get(reverseHandler);
5416
+ }
5417
+ const directMatch = effectMap.get(reverseHandler);
5418
+ if (directMatch) {
5419
+ return directMatch;
5420
+ }
5421
+ const candidateKeys = [
5422
+ computeEffectKey({
5423
+ name: reverseHandler,
5424
+ className: currentEffect.className,
5425
+ static: currentEffect.static
5426
+ }),
5427
+ computeEffectKey({
5428
+ name: reverseHandler
5429
+ })
5430
+ ];
5431
+ for (const candidateKey of candidateKeys) {
5432
+ const candidate = effectMap.get(candidateKey);
5433
+ if (candidate) {
5434
+ return candidate;
5435
+ }
5436
+ }
5437
+ return void 0;
5438
+ }
5439
+ function resolveHandlerForMode(effectMap, effect, request) {
5440
+ const behaviors = normalizeEffectBehaviors(request.context?.behaviors || effect.metamodels || void 0);
5441
+ const mode = resolveInvocationMode(request.context);
5442
+ if (mode === "dryRun") {
5443
+ if (effect.dryRunHandler) {
5444
+ return { effect, mode, handler: effect.dryRunHandler };
5445
+ }
5446
+ if (behaviors.dryRun?.enabled) {
5447
+ return { effect, mode, handler: effect.handler };
5448
+ }
5449
+ throw new Error(`Dry run is not supported for ${request.effectKey}`);
5450
+ }
5451
+ if (mode === "reverse") {
5452
+ if (effect.reverseHandler) {
5453
+ return { effect, mode, handler: effect.reverseHandler };
5454
+ }
5455
+ const reverseEffect = resolveReverseEffect(effectMap, effect, request, behaviors);
5456
+ if (reverseEffect) {
5457
+ return {
5458
+ effect: reverseEffect,
5459
+ mode,
5460
+ handler: reverseEffect.reverseHandler || reverseEffect.handler
5461
+ };
5462
+ }
5463
+ throw new Error(`Reverse execution is not supported for ${request.effectKey}`);
5464
+ }
5465
+ return { effect, mode, handler: effect.handler };
5466
+ }
5467
+ async function invokeRegisteredEffect(effectMap, request) {
5468
+ const effect = effectMap.get(request.effectKey);
5469
+ if (!effect) {
5470
+ throw new Error(`Effect handler not found: ${request.effectKey}`);
5471
+ }
5472
+ const resolved = resolveHandlerForMode(effectMap, effect, request);
5473
+ const context = {
5474
+ ...request.context || {},
5475
+ behaviors: normalizeEffectBehaviors(request.context?.behaviors || effect.metamodels || void 0),
5476
+ invocation: {
5477
+ mode: resolved.mode,
5478
+ sourceEffectKey: request.effectKey,
5479
+ sourceEffectName: request.effectName,
5480
+ ...request.context?.invocation?.reverseHandler ? { reverseHandler: request.context.invocation.reverseHandler } : {}
5481
+ }
5482
+ };
5483
+ if (resolved.effect.className && !resolved.effect.static && request.input && typeof request.input === "object" && "_objectId" in request.input) {
5484
+ const { _objectId, ...rest } = request.input;
5485
+ return resolved.handler(_objectId, rest, context);
5486
+ }
5487
+ return resolved.handler(request.input, context);
5488
+ }
5489
+ function buildFieldMetamodelMutations(fieldPath, spec) {
5490
+ return DEFAULT_METAMODEL_PACKAGES.flatMap(
5491
+ (pkg) => pkg.manifest?.buildFieldMutations?.(fieldPath, spec) || []
5492
+ );
5493
+ }
5494
+ function buildModelMetamodelMutations(modelPath, spec) {
5495
+ return DEFAULT_METAMODEL_PACKAGES.flatMap(
5496
+ (pkg) => pkg.manifest?.buildModelMutations?.(modelPath, spec) || []
5497
+ );
5498
+ }
5499
+ function buildEffectMetamodelMutations(toolPath, spec) {
5500
+ if (!spec) return [];
5501
+ return DEFAULT_METAMODEL_PACKAGES.flatMap(
5502
+ (pkg) => pkg.manifest?.buildEffectMutations?.(toolPath, spec) || []
5503
+ );
5504
+ }
5386
5505
 
5387
5506
  // src/client.ts
5388
5507
  var STANDARD_MODULES_OPERATIONS = [
@@ -5398,7 +5517,7 @@ var STANDARD_MODULES_OPERATIONS = [
5398
5517
  var BUILTIN_MODULES = {
5399
5518
  "standard_modules": STANDARD_MODULES_OPERATIONS
5400
5519
  };
5401
- function computeEffectKey(effect) {
5520
+ function computeEffectKey2(effect) {
5402
5521
  const attachedClass = effect.className?.trim();
5403
5522
  if (!attachedClass) {
5404
5523
  return `global:${effect.name}`;
@@ -5975,6 +6094,87 @@ var Environment = class extends Session {
5975
6094
  }
5976
6095
  return ref;
5977
6096
  }
6097
+ async _runGraphql(query, label) {
6098
+ const result = await this.graphql(query);
6099
+ if (result.errors?.length) {
6100
+ throw new Error(`${label}: ${result.errors[0].message}`);
6101
+ }
6102
+ return result.data;
6103
+ }
6104
+ async _applyFieldMetamodels(fieldPath, spec) {
6105
+ for (const mutation of buildFieldMetamodelMutations(fieldPath, spec)) {
6106
+ await this._runGraphql(mutation.query, mutation.label);
6107
+ }
6108
+ }
6109
+ async _applyModelMetamodels(modelPath, op) {
6110
+ for (const mutation of buildModelMetamodelMutations(modelPath, op)) {
6111
+ await this._runGraphql(mutation.query, mutation.label);
6112
+ }
6113
+ }
6114
+ async _ensureWorkspaceToolsRoot() {
6115
+ await this._runGraphql(
6116
+ `mutation { create_model(path: "workspace", label: "workspace") { model { path } } }`,
6117
+ "ensure workspace"
6118
+ ).catch((error) => {
6119
+ if (!error.message.includes("already exists")) throw error;
6120
+ });
6121
+ await this._runGraphql(
6122
+ `mutation { at(path: "workspace") { create_submodel(subpath: "tools", label: "Tools") { model { path } } } }`,
6123
+ "ensure workspace:tools"
6124
+ ).catch((error) => {
6125
+ if (!error.message.includes("already exists")) throw error;
6126
+ });
6127
+ await this._runGraphql(
6128
+ `mutation { at(path: "workspace:tools") { create_submodel(subpath: "declared", label: "Declared") { model { path } } } }`,
6129
+ "ensure workspace:tools:declared"
6130
+ ).catch((error) => {
6131
+ if (!error.message.includes("already exists")) throw error;
6132
+ });
6133
+ }
6134
+ async _storeEffectSchemas(toolPath, effect) {
6135
+ await this._runGraphql(
6136
+ `mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "inputSchema", label: "inputSchema") { set_string_value(value: ${JSON.stringify(JSON.stringify(effect.inputSchema))}) { done } } } }`,
6137
+ `store inputSchema on ${toolPath}`
6138
+ ).catch((error) => {
6139
+ if (!error.message.includes("already exists")) throw error;
6140
+ });
6141
+ if (effect.outputSchema) {
6142
+ await this._runGraphql(
6143
+ `mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "outputSchema", label: "outputSchema") { set_string_value(value: ${JSON.stringify(JSON.stringify(effect.outputSchema))}) { done } } } }`,
6144
+ `store outputSchema on ${toolPath}`
6145
+ ).catch((error) => {
6146
+ if (!error.message.includes("already exists")) throw error;
6147
+ });
6148
+ }
6149
+ }
6150
+ async _applyEffectMetamodels(toolPath, metamodels) {
6151
+ for (const mutation of buildEffectMetamodelMutations(toolPath, metamodels)) {
6152
+ await this._runGraphql(mutation.query, mutation.label);
6153
+ }
6154
+ }
6155
+ async _applyEffectDeclaration(effect, aliasMap) {
6156
+ let containerPath = "workspace:tools:declared";
6157
+ if (effect.attachedClass) {
6158
+ containerPath = this._resolveAlias(effect.attachedClass, aliasMap);
6159
+ } else {
6160
+ await this._ensureWorkspaceToolsRoot();
6161
+ }
6162
+ await this._runGraphql(
6163
+ `mutation { at(path: ${JSON.stringify(containerPath)}) { create_submodel(subpath: ${JSON.stringify(effect.name)}, label: ${JSON.stringify(effect.name)}) { model { path } } } }`,
6164
+ `create effect model ${containerPath}:${effect.name}`
6165
+ ).catch((error) => {
6166
+ if (!error.message.includes("already exists")) throw error;
6167
+ });
6168
+ const toolPath = `${containerPath}:${effect.name}`;
6169
+ if (effect.description) {
6170
+ await this._runGraphql(
6171
+ `mutation { at(path: ${JSON.stringify(toolPath)}) { set_description(description: ${JSON.stringify(effect.description)}) { done } } }`,
6172
+ `set effect description on ${toolPath}`
6173
+ );
6174
+ }
6175
+ await this._storeEffectSchemas(toolPath, effect);
6176
+ await this._applyEffectMetamodels(toolPath, effect.metamodels);
6177
+ }
5978
6178
  /**
5979
6179
  * Apply a single manifest operation via GraphQL
5980
6180
  */
@@ -5997,24 +6197,32 @@ var Environment = class extends Session {
5997
6197
  const extendsRef = op.extends ? this._resolveAlias(op.extends, aliasMap) : void 0;
5998
6198
  const instanceOfRef = op.instanceOf ? this._resolveAlias(op.instanceOf, aliasMap) : void 0;
5999
6199
  if (extendsRef) {
6000
- await this.graphql(
6001
- `mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`
6200
+ await this._runGraphql(
6201
+ `mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`,
6202
+ `create model ${op.create}`
6002
6203
  );
6003
- await this.graphql(
6004
- `mutation { at(path: "${op.create}") { add_superclass(superclass: "${extendsRef}") { model { path } } } }`
6204
+ await this._runGraphql(
6205
+ `mutation { at(path: "${op.create}") { add_superclass(superclass: "${extendsRef}") { model { path } } } }`,
6206
+ `add superclass ${extendsRef} to ${op.create}`
6005
6207
  );
6006
6208
  } else if (instanceOfRef) {
6007
- await this.graphql(
6008
- `mutation { at(path: "${instanceOfRef}") { instantiate(path: "${op.create}", label: "${label}") { model { path } } } }`
6209
+ await this._runGraphql(
6210
+ `mutation { at(path: "${instanceOfRef}") { instantiate(path: "${op.create}", label: "${label}") { model { path } } } }`,
6211
+ `instantiate ${op.create} from ${instanceOfRef}`
6009
6212
  );
6010
6213
  } else {
6011
- await this.graphql(
6012
- `mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`
6214
+ await this._runGraphql(
6215
+ `mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`,
6216
+ `create model ${op.create}`
6013
6217
  );
6014
6218
  }
6015
6219
  if (op.has) {
6016
6220
  await this._applyFields(op.create, op.has);
6017
6221
  }
6222
+ await this._applyModelMetamodels(op.create, op);
6223
+ if (op.withEffect) {
6224
+ await this._applyEffectDeclaration(op.withEffect, aliasMap);
6225
+ }
6018
6226
  return;
6019
6227
  }
6020
6228
  if (op.on) {
@@ -6022,8 +6230,15 @@ var Environment = class extends Session {
6022
6230
  if (op.has) {
6023
6231
  await this._applyFields(target, op.has);
6024
6232
  }
6233
+ await this._applyModelMetamodels(target, op);
6234
+ if (op.withEffect) {
6235
+ await this._applyEffectDeclaration(op.withEffect, aliasMap);
6236
+ }
6025
6237
  return;
6026
6238
  }
6239
+ if (op.withEffect) {
6240
+ await this._applyEffectDeclaration(op.withEffect, aliasMap);
6241
+ }
6027
6242
  }
6028
6243
  /**
6029
6244
  * Apply field definitions (has) to a model via GraphQL
@@ -6031,81 +6246,91 @@ var Environment = class extends Session {
6031
6246
  async _applyFields(modelPath, fields) {
6032
6247
  for (const [fieldName, spec] of Object.entries(fields)) {
6033
6248
  const fieldLabel = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
6034
- await this.graphql(
6249
+ await this._runGraphql(
6035
6250
  `mutation {
6036
- at(path: "${modelPath}") {
6037
- create_submodel(subpath: "${fieldName}", label: "${fieldLabel}") {
6251
+ at(path: ${JSON.stringify(modelPath)}) {
6252
+ create_submodel(subpath: ${JSON.stringify(fieldName)}, label: ${JSON.stringify(fieldLabel)}) {
6038
6253
  model { path }
6039
6254
  }
6040
6255
  }
6041
- }`
6042
- );
6256
+ }`,
6257
+ `create field ${modelPath}.${fieldName}`
6258
+ ).catch((error) => {
6259
+ if (!error.message.includes("already exists")) throw error;
6260
+ });
6043
6261
  if (spec.type) {
6044
- await this.graphql(
6262
+ await this._runGraphql(
6045
6263
  `mutation {
6046
- at(path: "${modelPath}") {
6047
- at(submodel: "${fieldName}") {
6048
- add_prototype(prototype: "${spec.type}") { done }
6264
+ at(path: ${JSON.stringify(modelPath)}) {
6265
+ at(submodel: ${JSON.stringify(fieldName)}) {
6266
+ add_prototype(prototype: ${JSON.stringify(spec.type)}) { done }
6049
6267
  }
6050
6268
  }
6051
- }`
6269
+ }`,
6270
+ `set prototype on ${modelPath}:${fieldName}`
6052
6271
  );
6053
6272
  }
6054
6273
  if (spec.description) {
6055
- await this.graphql(
6274
+ await this._runGraphql(
6056
6275
  `mutation {
6057
- at(path: "${modelPath}") {
6058
- at(submodel: "${fieldName}") {
6059
- set_description(description: "${spec.description}") { done }
6276
+ at(path: ${JSON.stringify(modelPath)}) {
6277
+ at(submodel: ${JSON.stringify(fieldName)}) {
6278
+ set_description(description: ${JSON.stringify(spec.description)}) { done }
6060
6279
  }
6061
6280
  }
6062
- }`
6281
+ }`,
6282
+ `set description on ${modelPath}:${fieldName}`
6063
6283
  );
6064
6284
  }
6065
6285
  if (spec.value !== void 0 && spec.value !== null) {
6066
6286
  if (typeof spec.value === "string") {
6067
- await this.graphql(
6287
+ await this._runGraphql(
6068
6288
  `mutation {
6069
- at(path: "${modelPath}") {
6070
- at(submodel: "${fieldName}") {
6071
- set_string_value(value: "${spec.value}") { done }
6289
+ at(path: ${JSON.stringify(modelPath)}) {
6290
+ at(submodel: ${JSON.stringify(fieldName)}) {
6291
+ set_string_value(value: ${JSON.stringify(spec.value)}) { done }
6072
6292
  }
6073
6293
  }
6074
- }`
6294
+ }`,
6295
+ `set string value on ${modelPath}:${fieldName}`
6075
6296
  );
6076
6297
  } else if (typeof spec.value === "number") {
6077
- await this.graphql(
6298
+ await this._runGraphql(
6078
6299
  `mutation {
6079
- at(path: "${modelPath}") {
6080
- at(submodel: "${fieldName}") {
6300
+ at(path: ${JSON.stringify(modelPath)}) {
6301
+ at(submodel: ${JSON.stringify(fieldName)}) {
6081
6302
  set_number_value(value: ${spec.value}) { done }
6082
6303
  }
6083
6304
  }
6084
- }`
6305
+ }`,
6306
+ `set number value on ${modelPath}:${fieldName}`
6085
6307
  );
6086
6308
  } else if (typeof spec.value === "boolean") {
6087
- await this.graphql(
6309
+ await this._runGraphql(
6088
6310
  `mutation {
6089
- at(path: "${modelPath}") {
6090
- at(submodel: "${fieldName}") {
6311
+ at(path: ${JSON.stringify(modelPath)}) {
6312
+ at(submodel: ${JSON.stringify(fieldName)}) {
6091
6313
  set_boolean_value(value: ${spec.value}) { done }
6092
6314
  }
6093
6315
  }
6094
- }`
6316
+ }`,
6317
+ `set boolean value on ${modelPath}:${fieldName}`
6095
6318
  );
6096
6319
  }
6097
6320
  }
6098
6321
  if (spec.ref) {
6099
- await this.graphql(
6322
+ await this._runGraphql(
6100
6323
  `mutation {
6101
- at(path: "${modelPath}") {
6102
- at(submodel: "${fieldName}") {
6103
- set_reference(reference: "${spec.ref}") { done }
6324
+ at(path: ${JSON.stringify(modelPath)}) {
6325
+ at(submodel: ${JSON.stringify(fieldName)}) {
6326
+ set_reference(reference: ${JSON.stringify(spec.ref)}) { done }
6104
6327
  }
6105
6328
  }
6106
- }`
6329
+ }`,
6330
+ `set reference on ${modelPath}:${fieldName}`
6107
6331
  );
6108
6332
  }
6333
+ await this._applyFieldMetamodels(`${modelPath}:${fieldName}`, spec);
6109
6334
  if (spec.has) {
6110
6335
  await this._applyFields(`${modelPath}:${fieldName}`, spec.has);
6111
6336
  }
@@ -6445,7 +6670,7 @@ var Granular = class {
6445
6670
  }
6446
6671
  serializeEffect(effect) {
6447
6672
  return {
6448
- effectKey: computeEffectKey(effect),
6673
+ effectKey: computeEffectKey2(effect),
6449
6674
  name: effect.name,
6450
6675
  description: effect.description,
6451
6676
  inputSchema: effect.inputSchema,
@@ -6481,23 +6706,54 @@ var Granular = class {
6481
6706
  const host = await this.ensureSandboxEffectHost(sandboxId);
6482
6707
  await this.publishSandboxEffectCatalog(host);
6483
6708
  }
6484
- startEffectHostHeartbeat(host) {
6485
- if (host.heartbeatTimer) {
6486
- clearInterval(host.heartbeatTimer);
6709
+ recoverEffectHost(host, error) {
6710
+ if (host.recovering) {
6711
+ return;
6712
+ }
6713
+ if (this.sandboxEffectHosts.get(host.sandboxId) !== host) {
6714
+ return;
6487
6715
  }
6488
- host.wsClient.call("client.heartbeat", {}).catch((error) => {
6716
+ host.recovering = true;
6717
+ this.stopEffectHostHeartbeat(host);
6718
+ this.sandboxEffectHosts.delete(host.sandboxId);
6719
+ try {
6720
+ host.wsClient.disconnect();
6721
+ } catch (disconnectError) {
6489
6722
  console.warn(
6490
- `[Granular] Initial effect host heartbeat failed for sandbox ${host.sandboxId}:`,
6491
- error
6723
+ `[Granular] Failed to disconnect stale effect host for sandbox ${host.sandboxId}:`,
6724
+ disconnectError
6492
6725
  );
6726
+ }
6727
+ void this.ensureSandboxEffectHost(host.sandboxId).catch((reconnectError) => {
6728
+ console.error(
6729
+ `[Granular] Failed to recover effect host for sandbox ${host.sandboxId} after heartbeat failure:`,
6730
+ reconnectError
6731
+ );
6732
+ console.error("[Granular] Original heartbeat failure:", error);
6493
6733
  });
6494
- host.heartbeatTimer = setInterval(() => {
6734
+ }
6735
+ startEffectHostHeartbeat(host) {
6736
+ if (host.heartbeatTimer) {
6737
+ clearInterval(host.heartbeatTimer);
6738
+ }
6739
+ host.heartbeatInFlight = false;
6740
+ const sendHeartbeat = (failureLabel, recoverOnFailure) => {
6741
+ if (host.heartbeatInFlight || host.recovering) {
6742
+ return;
6743
+ }
6744
+ host.heartbeatInFlight = true;
6495
6745
  host.wsClient.call("client.heartbeat", {}).catch((error) => {
6496
- console.warn(
6497
- `[Granular] Effect host heartbeat failed for sandbox ${host.sandboxId}:`,
6498
- error
6499
- );
6746
+ console.warn(`${failureLabel} ${host.sandboxId}:`, error);
6747
+ if (recoverOnFailure) {
6748
+ this.recoverEffectHost(host, error);
6749
+ }
6750
+ }).finally(() => {
6751
+ host.heartbeatInFlight = false;
6500
6752
  });
6753
+ };
6754
+ sendHeartbeat("[Granular] Initial effect host heartbeat failed for sandbox", false);
6755
+ host.heartbeatTimer = setInterval(() => {
6756
+ sendHeartbeat("[Granular] Effect host heartbeat failed for sandbox", true);
6501
6757
  }, 1e4);
6502
6758
  }
6503
6759
  stopEffectHostHeartbeat(host) {
@@ -6506,6 +6762,7 @@ var Granular = class {
6506
6762
  }
6507
6763
  clearInterval(host.heartbeatTimer);
6508
6764
  host.heartbeatTimer = null;
6765
+ host.heartbeatInFlight = false;
6509
6766
  }
6510
6767
  async synchronizeEffectHost(host) {
6511
6768
  await host.wsClient.call("client.hello", {
@@ -6541,19 +6798,13 @@ var Granular = class {
6541
6798
  effectClientId,
6542
6799
  clientId,
6543
6800
  wsClient,
6544
- heartbeatTimer: null
6801
+ heartbeatTimer: null,
6802
+ heartbeatInFlight: false,
6803
+ recovering: false
6545
6804
  };
6546
6805
  wsClient.registerRpcHandler("effect.invoke", async (params) => {
6547
6806
  const request = params;
6548
- const effect = this.getSandboxEffectMap(sandboxId).get(request.effectKey);
6549
- if (!effect) {
6550
- throw new Error(`Effect handler not found: ${request.effectKey}`);
6551
- }
6552
- if (effect.className && !effect.static && request.input && typeof request.input === "object" && "_objectId" in request.input) {
6553
- const { _objectId, ...rest } = request.input;
6554
- return effect.handler(_objectId, rest, request.context);
6555
- }
6556
- return effect.handler(request.input, request.context);
6807
+ return invokeRegisteredEffect(this.getSandboxEffectMap(sandboxId), request);
6557
6808
  });
6558
6809
  wsClient.on("open", () => {
6559
6810
  void this.synchronizeEffectHost(host).catch((error) => {
@@ -6596,7 +6847,7 @@ var Granular = class {
6596
6847
  async registerEffect(sandboxNameOrId, effect) {
6597
6848
  const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
6598
6849
  const sandboxId = sandbox.sandboxId;
6599
- this.getSandboxEffectMap(sandboxId).set(computeEffectKey(effect), effect);
6850
+ this.getSandboxEffectMap(sandboxId).set(computeEffectKey2(effect), effect);
6600
6851
  await this.syncSandboxEffectCatalog(sandboxId);
6601
6852
  }
6602
6853
  /**
@@ -6609,7 +6860,7 @@ var Granular = class {
6609
6860
  const sandboxId = sandbox.sandboxId;
6610
6861
  const map = this.getSandboxEffectMap(sandboxId);
6611
6862
  for (const effect of effects) {
6612
- map.set(computeEffectKey(effect), effect);
6863
+ map.set(computeEffectKey2(effect), effect);
6613
6864
  }
6614
6865
  await this.syncSandboxEffectCatalog(sandboxId);
6615
6866
  }
@@ -6886,6 +7137,6 @@ var Granular = class {
6886
7137
  }
6887
7138
  };
6888
7139
 
6889
- export { Environment, Granular, Session, WSClient };
7140
+ export { Environment, Granular, Session, WSClient, invokeRegisteredEffect, normalizeEffectBehaviors };
6890
7141
  //# sourceMappingURL=index.mjs.map
6891
7142
  //# sourceMappingURL=index.mjs.map