@granular-software/sdk 0.4.11 → 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/cli/index.js +124 -0
- package/dist/index.d.mts +130 -3
- package/dist/index.d.ts +130 -3
- package/dist/index.js +354 -68
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +353 -69
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
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;
|
|
@@ -4628,7 +4630,7 @@ var Session = class {
|
|
|
4628
4630
|
* Respond to a prompt request from the sandbox
|
|
4629
4631
|
*/
|
|
4630
4632
|
async answerPrompt(promptId, answer) {
|
|
4631
|
-
await this.client.call("prompt.answer", { promptId, value: answer });
|
|
4633
|
+
await this.client.call("prompt.answer", { promptId, answer, value: answer });
|
|
4632
4634
|
}
|
|
4633
4635
|
/**
|
|
4634
4636
|
* Get the current list of available effects.
|
|
@@ -4945,13 +4947,31 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
4945
4947
|
});
|
|
4946
4948
|
}
|
|
4947
4949
|
setupEventHandlers() {
|
|
4950
|
+
this.client.on("open", (payload) => this.emit("open", payload || {}));
|
|
4948
4951
|
this.client.on("sync", (doc) => {
|
|
4949
4952
|
this.currentDomainRevision = this.extractDomainRevisionFromDoc(doc);
|
|
4950
4953
|
this.emit("sync", doc);
|
|
4951
4954
|
this.checkForToolChanges();
|
|
4952
4955
|
});
|
|
4953
|
-
|
|
4956
|
+
const emitPrompt = (payload) => {
|
|
4957
|
+
const raw = payload;
|
|
4958
|
+
const prompt = raw.prompt || {
|
|
4959
|
+
id: typeof raw.id === "string" ? raw.id : String(raw.promptId || ""),
|
|
4960
|
+
type: raw.type === "confirm" || raw.type === "choice" || raw.type === "input" ? raw.type : raw.promptType === "confirm" || raw.promptType === "choice" ? raw.promptType : "input",
|
|
4961
|
+
title: typeof raw.title === "string" ? raw.title : "Input required",
|
|
4962
|
+
message: typeof raw.message === "string" ? raw.message : "",
|
|
4963
|
+
options: raw.options,
|
|
4964
|
+
defaultValue: raw.defaultValue,
|
|
4965
|
+
placeholder: raw.placeholder,
|
|
4966
|
+
allowEmpty: raw.allowEmpty,
|
|
4967
|
+
metadata: raw.metadata
|
|
4968
|
+
};
|
|
4969
|
+
this.emit("prompt", prompt);
|
|
4970
|
+
};
|
|
4971
|
+
this.client.on("prompt", emitPrompt);
|
|
4972
|
+
this.client.on("prompt.request", emitPrompt);
|
|
4954
4973
|
this.client.on("disconnect", (payload) => this.emit("disconnect", payload || {}));
|
|
4974
|
+
this.client.on("reconnect_error", (payload) => this.emit("reconnect_error", payload || {}));
|
|
4955
4975
|
this.client.on("job.status", (data) => {
|
|
4956
4976
|
this.emit("job:status", data);
|
|
4957
4977
|
});
|
|
@@ -5023,6 +5043,8 @@ function normalizeJobStatus(status) {
|
|
|
5023
5043
|
case "failed":
|
|
5024
5044
|
case "running":
|
|
5025
5045
|
case "queued":
|
|
5046
|
+
case "awaitingTool":
|
|
5047
|
+
case "awaitingHuman":
|
|
5026
5048
|
case "succeeded":
|
|
5027
5049
|
case "timeout":
|
|
5028
5050
|
case "canceled":
|
|
@@ -5157,6 +5179,19 @@ var JobImplementation = class {
|
|
|
5157
5179
|
this.client.on(`job.${id}.error`, (error) => {
|
|
5158
5180
|
this.finalize("failed", void 0, error);
|
|
5159
5181
|
});
|
|
5182
|
+
this.client.on("job.status", (data) => {
|
|
5183
|
+
const jobData = data;
|
|
5184
|
+
if (jobData.jobId !== id) {
|
|
5185
|
+
return;
|
|
5186
|
+
}
|
|
5187
|
+
const normalizedStatus = normalizeJobStatus(jobData.status);
|
|
5188
|
+
this.status = normalizedStatus;
|
|
5189
|
+
this.metadata.status = normalizedStatus;
|
|
5190
|
+
if (normalizedStatus === "running") {
|
|
5191
|
+
this.markStarted();
|
|
5192
|
+
}
|
|
5193
|
+
this.emit("status", normalizedStatus);
|
|
5194
|
+
});
|
|
5160
5195
|
this.client.on("job.completed", (data) => {
|
|
5161
5196
|
const jobData = data;
|
|
5162
5197
|
if (jobData.jobId === id) {
|
|
@@ -5350,6 +5385,123 @@ function resolveApiUrl(explicitApiUrl, mode) {
|
|
|
5350
5385
|
}
|
|
5351
5386
|
return resolveEndpointMode(mode) === "local" ? LOCAL_API_URL : PRODUCTION_API_URL;
|
|
5352
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
|
+
}
|
|
5353
5505
|
|
|
5354
5506
|
// src/client.ts
|
|
5355
5507
|
var STANDARD_MODULES_OPERATIONS = [
|
|
@@ -5365,7 +5517,7 @@ var STANDARD_MODULES_OPERATIONS = [
|
|
|
5365
5517
|
var BUILTIN_MODULES = {
|
|
5366
5518
|
"standard_modules": STANDARD_MODULES_OPERATIONS
|
|
5367
5519
|
};
|
|
5368
|
-
function
|
|
5520
|
+
function computeEffectKey2(effect) {
|
|
5369
5521
|
const attachedClass = effect.className?.trim();
|
|
5370
5522
|
if (!attachedClass) {
|
|
5371
5523
|
return `global:${effect.name}`;
|
|
@@ -5942,6 +6094,87 @@ var Environment = class extends Session {
|
|
|
5942
6094
|
}
|
|
5943
6095
|
return ref;
|
|
5944
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
|
+
}
|
|
5945
6178
|
/**
|
|
5946
6179
|
* Apply a single manifest operation via GraphQL
|
|
5947
6180
|
*/
|
|
@@ -5964,24 +6197,32 @@ var Environment = class extends Session {
|
|
|
5964
6197
|
const extendsRef = op.extends ? this._resolveAlias(op.extends, aliasMap) : void 0;
|
|
5965
6198
|
const instanceOfRef = op.instanceOf ? this._resolveAlias(op.instanceOf, aliasMap) : void 0;
|
|
5966
6199
|
if (extendsRef) {
|
|
5967
|
-
await this.
|
|
5968
|
-
`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}`
|
|
5969
6203
|
);
|
|
5970
|
-
await this.
|
|
5971
|
-
`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}`
|
|
5972
6207
|
);
|
|
5973
6208
|
} else if (instanceOfRef) {
|
|
5974
|
-
await this.
|
|
5975
|
-
`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}`
|
|
5976
6212
|
);
|
|
5977
6213
|
} else {
|
|
5978
|
-
await this.
|
|
5979
|
-
`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}`
|
|
5980
6217
|
);
|
|
5981
6218
|
}
|
|
5982
6219
|
if (op.has) {
|
|
5983
6220
|
await this._applyFields(op.create, op.has);
|
|
5984
6221
|
}
|
|
6222
|
+
await this._applyModelMetamodels(op.create, op);
|
|
6223
|
+
if (op.withEffect) {
|
|
6224
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6225
|
+
}
|
|
5985
6226
|
return;
|
|
5986
6227
|
}
|
|
5987
6228
|
if (op.on) {
|
|
@@ -5989,8 +6230,15 @@ var Environment = class extends Session {
|
|
|
5989
6230
|
if (op.has) {
|
|
5990
6231
|
await this._applyFields(target, op.has);
|
|
5991
6232
|
}
|
|
6233
|
+
await this._applyModelMetamodels(target, op);
|
|
6234
|
+
if (op.withEffect) {
|
|
6235
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6236
|
+
}
|
|
5992
6237
|
return;
|
|
5993
6238
|
}
|
|
6239
|
+
if (op.withEffect) {
|
|
6240
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6241
|
+
}
|
|
5994
6242
|
}
|
|
5995
6243
|
/**
|
|
5996
6244
|
* Apply field definitions (has) to a model via GraphQL
|
|
@@ -5998,81 +6246,91 @@ var Environment = class extends Session {
|
|
|
5998
6246
|
async _applyFields(modelPath, fields) {
|
|
5999
6247
|
for (const [fieldName, spec] of Object.entries(fields)) {
|
|
6000
6248
|
const fieldLabel = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
|
|
6001
|
-
await this.
|
|
6249
|
+
await this._runGraphql(
|
|
6002
6250
|
`mutation {
|
|
6003
|
-
at(path:
|
|
6004
|
-
create_submodel(subpath:
|
|
6251
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6252
|
+
create_submodel(subpath: ${JSON.stringify(fieldName)}, label: ${JSON.stringify(fieldLabel)}) {
|
|
6005
6253
|
model { path }
|
|
6006
6254
|
}
|
|
6007
6255
|
}
|
|
6008
|
-
}
|
|
6009
|
-
|
|
6256
|
+
}`,
|
|
6257
|
+
`create field ${modelPath}.${fieldName}`
|
|
6258
|
+
).catch((error) => {
|
|
6259
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6260
|
+
});
|
|
6010
6261
|
if (spec.type) {
|
|
6011
|
-
await this.
|
|
6262
|
+
await this._runGraphql(
|
|
6012
6263
|
`mutation {
|
|
6013
|
-
at(path:
|
|
6014
|
-
at(submodel:
|
|
6015
|
-
add_prototype(prototype:
|
|
6264
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6265
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6266
|
+
add_prototype(prototype: ${JSON.stringify(spec.type)}) { done }
|
|
6016
6267
|
}
|
|
6017
6268
|
}
|
|
6018
|
-
}
|
|
6269
|
+
}`,
|
|
6270
|
+
`set prototype on ${modelPath}:${fieldName}`
|
|
6019
6271
|
);
|
|
6020
6272
|
}
|
|
6021
6273
|
if (spec.description) {
|
|
6022
|
-
await this.
|
|
6274
|
+
await this._runGraphql(
|
|
6023
6275
|
`mutation {
|
|
6024
|
-
at(path:
|
|
6025
|
-
at(submodel:
|
|
6026
|
-
set_description(description:
|
|
6276
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6277
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6278
|
+
set_description(description: ${JSON.stringify(spec.description)}) { done }
|
|
6027
6279
|
}
|
|
6028
6280
|
}
|
|
6029
|
-
}
|
|
6281
|
+
}`,
|
|
6282
|
+
`set description on ${modelPath}:${fieldName}`
|
|
6030
6283
|
);
|
|
6031
6284
|
}
|
|
6032
6285
|
if (spec.value !== void 0 && spec.value !== null) {
|
|
6033
6286
|
if (typeof spec.value === "string") {
|
|
6034
|
-
await this.
|
|
6287
|
+
await this._runGraphql(
|
|
6035
6288
|
`mutation {
|
|
6036
|
-
at(path:
|
|
6037
|
-
at(submodel:
|
|
6038
|
-
set_string_value(value:
|
|
6289
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6290
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6291
|
+
set_string_value(value: ${JSON.stringify(spec.value)}) { done }
|
|
6039
6292
|
}
|
|
6040
6293
|
}
|
|
6041
|
-
}
|
|
6294
|
+
}`,
|
|
6295
|
+
`set string value on ${modelPath}:${fieldName}`
|
|
6042
6296
|
);
|
|
6043
6297
|
} else if (typeof spec.value === "number") {
|
|
6044
|
-
await this.
|
|
6298
|
+
await this._runGraphql(
|
|
6045
6299
|
`mutation {
|
|
6046
|
-
at(path:
|
|
6047
|
-
at(submodel:
|
|
6300
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6301
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6048
6302
|
set_number_value(value: ${spec.value}) { done }
|
|
6049
6303
|
}
|
|
6050
6304
|
}
|
|
6051
|
-
}
|
|
6305
|
+
}`,
|
|
6306
|
+
`set number value on ${modelPath}:${fieldName}`
|
|
6052
6307
|
);
|
|
6053
6308
|
} else if (typeof spec.value === "boolean") {
|
|
6054
|
-
await this.
|
|
6309
|
+
await this._runGraphql(
|
|
6055
6310
|
`mutation {
|
|
6056
|
-
at(path:
|
|
6057
|
-
at(submodel:
|
|
6311
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6312
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6058
6313
|
set_boolean_value(value: ${spec.value}) { done }
|
|
6059
6314
|
}
|
|
6060
6315
|
}
|
|
6061
|
-
}
|
|
6316
|
+
}`,
|
|
6317
|
+
`set boolean value on ${modelPath}:${fieldName}`
|
|
6062
6318
|
);
|
|
6063
6319
|
}
|
|
6064
6320
|
}
|
|
6065
6321
|
if (spec.ref) {
|
|
6066
|
-
await this.
|
|
6322
|
+
await this._runGraphql(
|
|
6067
6323
|
`mutation {
|
|
6068
|
-
at(path:
|
|
6069
|
-
at(submodel:
|
|
6070
|
-
set_reference(reference:
|
|
6324
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6325
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6326
|
+
set_reference(reference: ${JSON.stringify(spec.ref)}) { done }
|
|
6071
6327
|
}
|
|
6072
6328
|
}
|
|
6073
|
-
}
|
|
6329
|
+
}`,
|
|
6330
|
+
`set reference on ${modelPath}:${fieldName}`
|
|
6074
6331
|
);
|
|
6075
6332
|
}
|
|
6333
|
+
await this._applyFieldMetamodels(`${modelPath}:${fieldName}`, spec);
|
|
6076
6334
|
if (spec.has) {
|
|
6077
6335
|
await this._applyFields(`${modelPath}:${fieldName}`, spec.has);
|
|
6078
6336
|
}
|
|
@@ -6412,7 +6670,7 @@ var Granular = class {
|
|
|
6412
6670
|
}
|
|
6413
6671
|
serializeEffect(effect) {
|
|
6414
6672
|
return {
|
|
6415
|
-
effectKey:
|
|
6673
|
+
effectKey: computeEffectKey2(effect),
|
|
6416
6674
|
name: effect.name,
|
|
6417
6675
|
description: effect.description,
|
|
6418
6676
|
inputSchema: effect.inputSchema,
|
|
@@ -6448,23 +6706,54 @@ var Granular = class {
|
|
|
6448
6706
|
const host = await this.ensureSandboxEffectHost(sandboxId);
|
|
6449
6707
|
await this.publishSandboxEffectCatalog(host);
|
|
6450
6708
|
}
|
|
6451
|
-
|
|
6452
|
-
if (host.
|
|
6453
|
-
|
|
6709
|
+
recoverEffectHost(host, error) {
|
|
6710
|
+
if (host.recovering) {
|
|
6711
|
+
return;
|
|
6712
|
+
}
|
|
6713
|
+
if (this.sandboxEffectHosts.get(host.sandboxId) !== host) {
|
|
6714
|
+
return;
|
|
6454
6715
|
}
|
|
6455
|
-
host.
|
|
6716
|
+
host.recovering = true;
|
|
6717
|
+
this.stopEffectHostHeartbeat(host);
|
|
6718
|
+
this.sandboxEffectHosts.delete(host.sandboxId);
|
|
6719
|
+
try {
|
|
6720
|
+
host.wsClient.disconnect();
|
|
6721
|
+
} catch (disconnectError) {
|
|
6456
6722
|
console.warn(
|
|
6457
|
-
`[Granular]
|
|
6458
|
-
|
|
6723
|
+
`[Granular] Failed to disconnect stale effect host for sandbox ${host.sandboxId}:`,
|
|
6724
|
+
disconnectError
|
|
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
|
|
6459
6731
|
);
|
|
6732
|
+
console.error("[Granular] Original heartbeat failure:", error);
|
|
6460
6733
|
});
|
|
6461
|
-
|
|
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;
|
|
6462
6745
|
host.wsClient.call("client.heartbeat", {}).catch((error) => {
|
|
6463
|
-
console.warn(
|
|
6464
|
-
|
|
6465
|
-
error
|
|
6466
|
-
|
|
6746
|
+
console.warn(`${failureLabel} ${host.sandboxId}:`, error);
|
|
6747
|
+
if (recoverOnFailure) {
|
|
6748
|
+
this.recoverEffectHost(host, error);
|
|
6749
|
+
}
|
|
6750
|
+
}).finally(() => {
|
|
6751
|
+
host.heartbeatInFlight = false;
|
|
6467
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);
|
|
6468
6757
|
}, 1e4);
|
|
6469
6758
|
}
|
|
6470
6759
|
stopEffectHostHeartbeat(host) {
|
|
@@ -6473,6 +6762,7 @@ var Granular = class {
|
|
|
6473
6762
|
}
|
|
6474
6763
|
clearInterval(host.heartbeatTimer);
|
|
6475
6764
|
host.heartbeatTimer = null;
|
|
6765
|
+
host.heartbeatInFlight = false;
|
|
6476
6766
|
}
|
|
6477
6767
|
async synchronizeEffectHost(host) {
|
|
6478
6768
|
await host.wsClient.call("client.hello", {
|
|
@@ -6508,19 +6798,13 @@ var Granular = class {
|
|
|
6508
6798
|
effectClientId,
|
|
6509
6799
|
clientId,
|
|
6510
6800
|
wsClient,
|
|
6511
|
-
heartbeatTimer: null
|
|
6801
|
+
heartbeatTimer: null,
|
|
6802
|
+
heartbeatInFlight: false,
|
|
6803
|
+
recovering: false
|
|
6512
6804
|
};
|
|
6513
6805
|
wsClient.registerRpcHandler("effect.invoke", async (params) => {
|
|
6514
6806
|
const request = params;
|
|
6515
|
-
|
|
6516
|
-
if (!effect) {
|
|
6517
|
-
throw new Error(`Effect handler not found: ${request.effectKey}`);
|
|
6518
|
-
}
|
|
6519
|
-
if (effect.className && !effect.static && request.input && typeof request.input === "object" && "_objectId" in request.input) {
|
|
6520
|
-
const { _objectId, ...rest } = request.input;
|
|
6521
|
-
return effect.handler(_objectId, rest, request.context);
|
|
6522
|
-
}
|
|
6523
|
-
return effect.handler(request.input, request.context);
|
|
6807
|
+
return invokeRegisteredEffect(this.getSandboxEffectMap(sandboxId), request);
|
|
6524
6808
|
});
|
|
6525
6809
|
wsClient.on("open", () => {
|
|
6526
6810
|
void this.synchronizeEffectHost(host).catch((error) => {
|
|
@@ -6563,7 +6847,7 @@ var Granular = class {
|
|
|
6563
6847
|
async registerEffect(sandboxNameOrId, effect) {
|
|
6564
6848
|
const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
|
|
6565
6849
|
const sandboxId = sandbox.sandboxId;
|
|
6566
|
-
this.getSandboxEffectMap(sandboxId).set(
|
|
6850
|
+
this.getSandboxEffectMap(sandboxId).set(computeEffectKey2(effect), effect);
|
|
6567
6851
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6568
6852
|
}
|
|
6569
6853
|
/**
|
|
@@ -6576,7 +6860,7 @@ var Granular = class {
|
|
|
6576
6860
|
const sandboxId = sandbox.sandboxId;
|
|
6577
6861
|
const map = this.getSandboxEffectMap(sandboxId);
|
|
6578
6862
|
for (const effect of effects) {
|
|
6579
|
-
map.set(
|
|
6863
|
+
map.set(computeEffectKey2(effect), effect);
|
|
6580
6864
|
}
|
|
6581
6865
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6582
6866
|
}
|
|
@@ -6853,6 +7137,6 @@ var Granular = class {
|
|
|
6853
7137
|
}
|
|
6854
7138
|
};
|
|
6855
7139
|
|
|
6856
|
-
export { Environment, Granular, Session, WSClient };
|
|
7140
|
+
export { Environment, Granular, Session, WSClient, invokeRegisteredEffect, normalizeEffectBehaviors };
|
|
6857
7141
|
//# sourceMappingURL=index.mjs.map
|
|
6858
7142
|
//# sourceMappingURL=index.mjs.map
|