@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/cli/index.js +124 -0
- package/dist/index.d.mts +121 -1
- package/dist/index.d.ts +121 -1
- package/dist/index.js +319 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +318 -67
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var Automerge = require('@automerge/automerge');
|
|
4
|
+
var metamodelEffectBehaviors = require('@granular-software/metamodel-effect-behaviors');
|
|
5
|
+
var metamodelPresetDefault = require('@granular-software/metamodel-preset-default');
|
|
4
6
|
|
|
5
7
|
function _interopNamespace(e) {
|
|
6
8
|
if (e && e.__esModule) return e;
|
|
@@ -5405,6 +5407,123 @@ function resolveApiUrl(explicitApiUrl, mode) {
|
|
|
5405
5407
|
}
|
|
5406
5408
|
return resolveEndpointMode(mode) === "local" ? LOCAL_API_URL : PRODUCTION_API_URL;
|
|
5407
5409
|
}
|
|
5410
|
+
function computeEffectKey(effect) {
|
|
5411
|
+
const attachedClass = effect.className?.trim();
|
|
5412
|
+
if (!attachedClass) {
|
|
5413
|
+
return `global:${effect.name}`;
|
|
5414
|
+
}
|
|
5415
|
+
return effect.static ? `class:${attachedClass}:static:${effect.name}` : `class:${attachedClass}:instance:${effect.name}`;
|
|
5416
|
+
}
|
|
5417
|
+
function normalizeEffectBehaviors(value) {
|
|
5418
|
+
return metamodelEffectBehaviors.normalizeEffectBehaviorSummary(
|
|
5419
|
+
value
|
|
5420
|
+
) || {};
|
|
5421
|
+
}
|
|
5422
|
+
function resolveInvocationMode(context) {
|
|
5423
|
+
const mode = context?.invocation?.mode;
|
|
5424
|
+
if (mode === "dryRun" || mode === "reverse") {
|
|
5425
|
+
return mode;
|
|
5426
|
+
}
|
|
5427
|
+
return "execute";
|
|
5428
|
+
}
|
|
5429
|
+
function resolveReverseEffect(effectMap, currentEffect, request, behaviors) {
|
|
5430
|
+
const explicitReverseHandler = request.context?.invocation?.reverseHandler?.trim();
|
|
5431
|
+
const configuredReverseHandler = behaviors.reverse?.handler?.trim();
|
|
5432
|
+
const reverseHandler = explicitReverseHandler || configuredReverseHandler;
|
|
5433
|
+
if (!reverseHandler) {
|
|
5434
|
+
return void 0;
|
|
5435
|
+
}
|
|
5436
|
+
if (reverseHandler.includes(":")) {
|
|
5437
|
+
return effectMap.get(reverseHandler);
|
|
5438
|
+
}
|
|
5439
|
+
const directMatch = effectMap.get(reverseHandler);
|
|
5440
|
+
if (directMatch) {
|
|
5441
|
+
return directMatch;
|
|
5442
|
+
}
|
|
5443
|
+
const candidateKeys = [
|
|
5444
|
+
computeEffectKey({
|
|
5445
|
+
name: reverseHandler,
|
|
5446
|
+
className: currentEffect.className,
|
|
5447
|
+
static: currentEffect.static
|
|
5448
|
+
}),
|
|
5449
|
+
computeEffectKey({
|
|
5450
|
+
name: reverseHandler
|
|
5451
|
+
})
|
|
5452
|
+
];
|
|
5453
|
+
for (const candidateKey of candidateKeys) {
|
|
5454
|
+
const candidate = effectMap.get(candidateKey);
|
|
5455
|
+
if (candidate) {
|
|
5456
|
+
return candidate;
|
|
5457
|
+
}
|
|
5458
|
+
}
|
|
5459
|
+
return void 0;
|
|
5460
|
+
}
|
|
5461
|
+
function resolveHandlerForMode(effectMap, effect, request) {
|
|
5462
|
+
const behaviors = normalizeEffectBehaviors(request.context?.behaviors || effect.metamodels || void 0);
|
|
5463
|
+
const mode = resolveInvocationMode(request.context);
|
|
5464
|
+
if (mode === "dryRun") {
|
|
5465
|
+
if (effect.dryRunHandler) {
|
|
5466
|
+
return { effect, mode, handler: effect.dryRunHandler };
|
|
5467
|
+
}
|
|
5468
|
+
if (behaviors.dryRun?.enabled) {
|
|
5469
|
+
return { effect, mode, handler: effect.handler };
|
|
5470
|
+
}
|
|
5471
|
+
throw new Error(`Dry run is not supported for ${request.effectKey}`);
|
|
5472
|
+
}
|
|
5473
|
+
if (mode === "reverse") {
|
|
5474
|
+
if (effect.reverseHandler) {
|
|
5475
|
+
return { effect, mode, handler: effect.reverseHandler };
|
|
5476
|
+
}
|
|
5477
|
+
const reverseEffect = resolveReverseEffect(effectMap, effect, request, behaviors);
|
|
5478
|
+
if (reverseEffect) {
|
|
5479
|
+
return {
|
|
5480
|
+
effect: reverseEffect,
|
|
5481
|
+
mode,
|
|
5482
|
+
handler: reverseEffect.reverseHandler || reverseEffect.handler
|
|
5483
|
+
};
|
|
5484
|
+
}
|
|
5485
|
+
throw new Error(`Reverse execution is not supported for ${request.effectKey}`);
|
|
5486
|
+
}
|
|
5487
|
+
return { effect, mode, handler: effect.handler };
|
|
5488
|
+
}
|
|
5489
|
+
async function invokeRegisteredEffect(effectMap, request) {
|
|
5490
|
+
const effect = effectMap.get(request.effectKey);
|
|
5491
|
+
if (!effect) {
|
|
5492
|
+
throw new Error(`Effect handler not found: ${request.effectKey}`);
|
|
5493
|
+
}
|
|
5494
|
+
const resolved = resolveHandlerForMode(effectMap, effect, request);
|
|
5495
|
+
const context = {
|
|
5496
|
+
...request.context || {},
|
|
5497
|
+
behaviors: normalizeEffectBehaviors(request.context?.behaviors || effect.metamodels || void 0),
|
|
5498
|
+
invocation: {
|
|
5499
|
+
mode: resolved.mode,
|
|
5500
|
+
sourceEffectKey: request.effectKey,
|
|
5501
|
+
sourceEffectName: request.effectName,
|
|
5502
|
+
...request.context?.invocation?.reverseHandler ? { reverseHandler: request.context.invocation.reverseHandler } : {}
|
|
5503
|
+
}
|
|
5504
|
+
};
|
|
5505
|
+
if (resolved.effect.className && !resolved.effect.static && request.input && typeof request.input === "object" && "_objectId" in request.input) {
|
|
5506
|
+
const { _objectId, ...rest } = request.input;
|
|
5507
|
+
return resolved.handler(_objectId, rest, context);
|
|
5508
|
+
}
|
|
5509
|
+
return resolved.handler(request.input, context);
|
|
5510
|
+
}
|
|
5511
|
+
function buildFieldMetamodelMutations(fieldPath, spec) {
|
|
5512
|
+
return metamodelPresetDefault.DEFAULT_METAMODEL_PACKAGES.flatMap(
|
|
5513
|
+
(pkg) => pkg.manifest?.buildFieldMutations?.(fieldPath, spec) || []
|
|
5514
|
+
);
|
|
5515
|
+
}
|
|
5516
|
+
function buildModelMetamodelMutations(modelPath, spec) {
|
|
5517
|
+
return metamodelPresetDefault.DEFAULT_METAMODEL_PACKAGES.flatMap(
|
|
5518
|
+
(pkg) => pkg.manifest?.buildModelMutations?.(modelPath, spec) || []
|
|
5519
|
+
);
|
|
5520
|
+
}
|
|
5521
|
+
function buildEffectMetamodelMutations(toolPath, spec) {
|
|
5522
|
+
if (!spec) return [];
|
|
5523
|
+
return metamodelPresetDefault.DEFAULT_METAMODEL_PACKAGES.flatMap(
|
|
5524
|
+
(pkg) => pkg.manifest?.buildEffectMutations?.(toolPath, spec) || []
|
|
5525
|
+
);
|
|
5526
|
+
}
|
|
5408
5527
|
|
|
5409
5528
|
// src/client.ts
|
|
5410
5529
|
var STANDARD_MODULES_OPERATIONS = [
|
|
@@ -5420,7 +5539,7 @@ var STANDARD_MODULES_OPERATIONS = [
|
|
|
5420
5539
|
var BUILTIN_MODULES = {
|
|
5421
5540
|
"standard_modules": STANDARD_MODULES_OPERATIONS
|
|
5422
5541
|
};
|
|
5423
|
-
function
|
|
5542
|
+
function computeEffectKey2(effect) {
|
|
5424
5543
|
const attachedClass = effect.className?.trim();
|
|
5425
5544
|
if (!attachedClass) {
|
|
5426
5545
|
return `global:${effect.name}`;
|
|
@@ -5997,6 +6116,87 @@ var Environment = class extends Session {
|
|
|
5997
6116
|
}
|
|
5998
6117
|
return ref;
|
|
5999
6118
|
}
|
|
6119
|
+
async _runGraphql(query, label) {
|
|
6120
|
+
const result = await this.graphql(query);
|
|
6121
|
+
if (result.errors?.length) {
|
|
6122
|
+
throw new Error(`${label}: ${result.errors[0].message}`);
|
|
6123
|
+
}
|
|
6124
|
+
return result.data;
|
|
6125
|
+
}
|
|
6126
|
+
async _applyFieldMetamodels(fieldPath, spec) {
|
|
6127
|
+
for (const mutation of buildFieldMetamodelMutations(fieldPath, spec)) {
|
|
6128
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6131
|
+
async _applyModelMetamodels(modelPath, op) {
|
|
6132
|
+
for (const mutation of buildModelMetamodelMutations(modelPath, op)) {
|
|
6133
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6134
|
+
}
|
|
6135
|
+
}
|
|
6136
|
+
async _ensureWorkspaceToolsRoot() {
|
|
6137
|
+
await this._runGraphql(
|
|
6138
|
+
`mutation { create_model(path: "workspace", label: "workspace") { model { path } } }`,
|
|
6139
|
+
"ensure workspace"
|
|
6140
|
+
).catch((error) => {
|
|
6141
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6142
|
+
});
|
|
6143
|
+
await this._runGraphql(
|
|
6144
|
+
`mutation { at(path: "workspace") { create_submodel(subpath: "tools", label: "Tools") { model { path } } } }`,
|
|
6145
|
+
"ensure workspace:tools"
|
|
6146
|
+
).catch((error) => {
|
|
6147
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6148
|
+
});
|
|
6149
|
+
await this._runGraphql(
|
|
6150
|
+
`mutation { at(path: "workspace:tools") { create_submodel(subpath: "declared", label: "Declared") { model { path } } } }`,
|
|
6151
|
+
"ensure workspace:tools:declared"
|
|
6152
|
+
).catch((error) => {
|
|
6153
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6154
|
+
});
|
|
6155
|
+
}
|
|
6156
|
+
async _storeEffectSchemas(toolPath, effect) {
|
|
6157
|
+
await this._runGraphql(
|
|
6158
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "inputSchema", label: "inputSchema") { set_string_value(value: ${JSON.stringify(JSON.stringify(effect.inputSchema))}) { done } } } }`,
|
|
6159
|
+
`store inputSchema on ${toolPath}`
|
|
6160
|
+
).catch((error) => {
|
|
6161
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6162
|
+
});
|
|
6163
|
+
if (effect.outputSchema) {
|
|
6164
|
+
await this._runGraphql(
|
|
6165
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "outputSchema", label: "outputSchema") { set_string_value(value: ${JSON.stringify(JSON.stringify(effect.outputSchema))}) { done } } } }`,
|
|
6166
|
+
`store outputSchema on ${toolPath}`
|
|
6167
|
+
).catch((error) => {
|
|
6168
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6169
|
+
});
|
|
6170
|
+
}
|
|
6171
|
+
}
|
|
6172
|
+
async _applyEffectMetamodels(toolPath, metamodels) {
|
|
6173
|
+
for (const mutation of buildEffectMetamodelMutations(toolPath, metamodels)) {
|
|
6174
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6177
|
+
async _applyEffectDeclaration(effect, aliasMap) {
|
|
6178
|
+
let containerPath = "workspace:tools:declared";
|
|
6179
|
+
if (effect.attachedClass) {
|
|
6180
|
+
containerPath = this._resolveAlias(effect.attachedClass, aliasMap);
|
|
6181
|
+
} else {
|
|
6182
|
+
await this._ensureWorkspaceToolsRoot();
|
|
6183
|
+
}
|
|
6184
|
+
await this._runGraphql(
|
|
6185
|
+
`mutation { at(path: ${JSON.stringify(containerPath)}) { create_submodel(subpath: ${JSON.stringify(effect.name)}, label: ${JSON.stringify(effect.name)}) { model { path } } } }`,
|
|
6186
|
+
`create effect model ${containerPath}:${effect.name}`
|
|
6187
|
+
).catch((error) => {
|
|
6188
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6189
|
+
});
|
|
6190
|
+
const toolPath = `${containerPath}:${effect.name}`;
|
|
6191
|
+
if (effect.description) {
|
|
6192
|
+
await this._runGraphql(
|
|
6193
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { set_description(description: ${JSON.stringify(effect.description)}) { done } } }`,
|
|
6194
|
+
`set effect description on ${toolPath}`
|
|
6195
|
+
);
|
|
6196
|
+
}
|
|
6197
|
+
await this._storeEffectSchemas(toolPath, effect);
|
|
6198
|
+
await this._applyEffectMetamodels(toolPath, effect.metamodels);
|
|
6199
|
+
}
|
|
6000
6200
|
/**
|
|
6001
6201
|
* Apply a single manifest operation via GraphQL
|
|
6002
6202
|
*/
|
|
@@ -6019,24 +6219,32 @@ var Environment = class extends Session {
|
|
|
6019
6219
|
const extendsRef = op.extends ? this._resolveAlias(op.extends, aliasMap) : void 0;
|
|
6020
6220
|
const instanceOfRef = op.instanceOf ? this._resolveAlias(op.instanceOf, aliasMap) : void 0;
|
|
6021
6221
|
if (extendsRef) {
|
|
6022
|
-
await this.
|
|
6023
|
-
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }
|
|
6222
|
+
await this._runGraphql(
|
|
6223
|
+
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`,
|
|
6224
|
+
`create model ${op.create}`
|
|
6024
6225
|
);
|
|
6025
|
-
await this.
|
|
6026
|
-
`mutation { at(path: "${op.create}") { add_superclass(superclass: "${extendsRef}") { model { path } } } }
|
|
6226
|
+
await this._runGraphql(
|
|
6227
|
+
`mutation { at(path: "${op.create}") { add_superclass(superclass: "${extendsRef}") { model { path } } } }`,
|
|
6228
|
+
`add superclass ${extendsRef} to ${op.create}`
|
|
6027
6229
|
);
|
|
6028
6230
|
} else if (instanceOfRef) {
|
|
6029
|
-
await this.
|
|
6030
|
-
`mutation { at(path: "${instanceOfRef}") { instantiate(path: "${op.create}", label: "${label}") { model { path } } } }
|
|
6231
|
+
await this._runGraphql(
|
|
6232
|
+
`mutation { at(path: "${instanceOfRef}") { instantiate(path: "${op.create}", label: "${label}") { model { path } } } }`,
|
|
6233
|
+
`instantiate ${op.create} from ${instanceOfRef}`
|
|
6031
6234
|
);
|
|
6032
6235
|
} else {
|
|
6033
|
-
await this.
|
|
6034
|
-
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }
|
|
6236
|
+
await this._runGraphql(
|
|
6237
|
+
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`,
|
|
6238
|
+
`create model ${op.create}`
|
|
6035
6239
|
);
|
|
6036
6240
|
}
|
|
6037
6241
|
if (op.has) {
|
|
6038
6242
|
await this._applyFields(op.create, op.has);
|
|
6039
6243
|
}
|
|
6244
|
+
await this._applyModelMetamodels(op.create, op);
|
|
6245
|
+
if (op.withEffect) {
|
|
6246
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6247
|
+
}
|
|
6040
6248
|
return;
|
|
6041
6249
|
}
|
|
6042
6250
|
if (op.on) {
|
|
@@ -6044,8 +6252,15 @@ var Environment = class extends Session {
|
|
|
6044
6252
|
if (op.has) {
|
|
6045
6253
|
await this._applyFields(target, op.has);
|
|
6046
6254
|
}
|
|
6255
|
+
await this._applyModelMetamodels(target, op);
|
|
6256
|
+
if (op.withEffect) {
|
|
6257
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6258
|
+
}
|
|
6047
6259
|
return;
|
|
6048
6260
|
}
|
|
6261
|
+
if (op.withEffect) {
|
|
6262
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6263
|
+
}
|
|
6049
6264
|
}
|
|
6050
6265
|
/**
|
|
6051
6266
|
* Apply field definitions (has) to a model via GraphQL
|
|
@@ -6053,81 +6268,91 @@ var Environment = class extends Session {
|
|
|
6053
6268
|
async _applyFields(modelPath, fields) {
|
|
6054
6269
|
for (const [fieldName, spec] of Object.entries(fields)) {
|
|
6055
6270
|
const fieldLabel = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
|
|
6056
|
-
await this.
|
|
6271
|
+
await this._runGraphql(
|
|
6057
6272
|
`mutation {
|
|
6058
|
-
at(path:
|
|
6059
|
-
create_submodel(subpath:
|
|
6273
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6274
|
+
create_submodel(subpath: ${JSON.stringify(fieldName)}, label: ${JSON.stringify(fieldLabel)}) {
|
|
6060
6275
|
model { path }
|
|
6061
6276
|
}
|
|
6062
6277
|
}
|
|
6063
|
-
}
|
|
6064
|
-
|
|
6278
|
+
}`,
|
|
6279
|
+
`create field ${modelPath}.${fieldName}`
|
|
6280
|
+
).catch((error) => {
|
|
6281
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6282
|
+
});
|
|
6065
6283
|
if (spec.type) {
|
|
6066
|
-
await this.
|
|
6284
|
+
await this._runGraphql(
|
|
6067
6285
|
`mutation {
|
|
6068
|
-
at(path:
|
|
6069
|
-
at(submodel:
|
|
6070
|
-
add_prototype(prototype:
|
|
6286
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6287
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6288
|
+
add_prototype(prototype: ${JSON.stringify(spec.type)}) { done }
|
|
6071
6289
|
}
|
|
6072
6290
|
}
|
|
6073
|
-
}
|
|
6291
|
+
}`,
|
|
6292
|
+
`set prototype on ${modelPath}:${fieldName}`
|
|
6074
6293
|
);
|
|
6075
6294
|
}
|
|
6076
6295
|
if (spec.description) {
|
|
6077
|
-
await this.
|
|
6296
|
+
await this._runGraphql(
|
|
6078
6297
|
`mutation {
|
|
6079
|
-
at(path:
|
|
6080
|
-
at(submodel:
|
|
6081
|
-
set_description(description:
|
|
6298
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6299
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6300
|
+
set_description(description: ${JSON.stringify(spec.description)}) { done }
|
|
6082
6301
|
}
|
|
6083
6302
|
}
|
|
6084
|
-
}
|
|
6303
|
+
}`,
|
|
6304
|
+
`set description on ${modelPath}:${fieldName}`
|
|
6085
6305
|
);
|
|
6086
6306
|
}
|
|
6087
6307
|
if (spec.value !== void 0 && spec.value !== null) {
|
|
6088
6308
|
if (typeof spec.value === "string") {
|
|
6089
|
-
await this.
|
|
6309
|
+
await this._runGraphql(
|
|
6090
6310
|
`mutation {
|
|
6091
|
-
at(path:
|
|
6092
|
-
at(submodel:
|
|
6093
|
-
set_string_value(value:
|
|
6311
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6312
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6313
|
+
set_string_value(value: ${JSON.stringify(spec.value)}) { done }
|
|
6094
6314
|
}
|
|
6095
6315
|
}
|
|
6096
|
-
}
|
|
6316
|
+
}`,
|
|
6317
|
+
`set string value on ${modelPath}:${fieldName}`
|
|
6097
6318
|
);
|
|
6098
6319
|
} else if (typeof spec.value === "number") {
|
|
6099
|
-
await this.
|
|
6320
|
+
await this._runGraphql(
|
|
6100
6321
|
`mutation {
|
|
6101
|
-
at(path:
|
|
6102
|
-
at(submodel:
|
|
6322
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6323
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6103
6324
|
set_number_value(value: ${spec.value}) { done }
|
|
6104
6325
|
}
|
|
6105
6326
|
}
|
|
6106
|
-
}
|
|
6327
|
+
}`,
|
|
6328
|
+
`set number value on ${modelPath}:${fieldName}`
|
|
6107
6329
|
);
|
|
6108
6330
|
} else if (typeof spec.value === "boolean") {
|
|
6109
|
-
await this.
|
|
6331
|
+
await this._runGraphql(
|
|
6110
6332
|
`mutation {
|
|
6111
|
-
at(path:
|
|
6112
|
-
at(submodel:
|
|
6333
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6334
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6113
6335
|
set_boolean_value(value: ${spec.value}) { done }
|
|
6114
6336
|
}
|
|
6115
6337
|
}
|
|
6116
|
-
}
|
|
6338
|
+
}`,
|
|
6339
|
+
`set boolean value on ${modelPath}:${fieldName}`
|
|
6117
6340
|
);
|
|
6118
6341
|
}
|
|
6119
6342
|
}
|
|
6120
6343
|
if (spec.ref) {
|
|
6121
|
-
await this.
|
|
6344
|
+
await this._runGraphql(
|
|
6122
6345
|
`mutation {
|
|
6123
|
-
at(path:
|
|
6124
|
-
at(submodel:
|
|
6125
|
-
set_reference(reference:
|
|
6346
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6347
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6348
|
+
set_reference(reference: ${JSON.stringify(spec.ref)}) { done }
|
|
6126
6349
|
}
|
|
6127
6350
|
}
|
|
6128
|
-
}
|
|
6351
|
+
}`,
|
|
6352
|
+
`set reference on ${modelPath}:${fieldName}`
|
|
6129
6353
|
);
|
|
6130
6354
|
}
|
|
6355
|
+
await this._applyFieldMetamodels(`${modelPath}:${fieldName}`, spec);
|
|
6131
6356
|
if (spec.has) {
|
|
6132
6357
|
await this._applyFields(`${modelPath}:${fieldName}`, spec.has);
|
|
6133
6358
|
}
|
|
@@ -6467,7 +6692,7 @@ var Granular = class {
|
|
|
6467
6692
|
}
|
|
6468
6693
|
serializeEffect(effect) {
|
|
6469
6694
|
return {
|
|
6470
|
-
effectKey:
|
|
6695
|
+
effectKey: computeEffectKey2(effect),
|
|
6471
6696
|
name: effect.name,
|
|
6472
6697
|
description: effect.description,
|
|
6473
6698
|
inputSchema: effect.inputSchema,
|
|
@@ -6503,23 +6728,54 @@ var Granular = class {
|
|
|
6503
6728
|
const host = await this.ensureSandboxEffectHost(sandboxId);
|
|
6504
6729
|
await this.publishSandboxEffectCatalog(host);
|
|
6505
6730
|
}
|
|
6506
|
-
|
|
6507
|
-
if (host.
|
|
6508
|
-
|
|
6731
|
+
recoverEffectHost(host, error) {
|
|
6732
|
+
if (host.recovering) {
|
|
6733
|
+
return;
|
|
6734
|
+
}
|
|
6735
|
+
if (this.sandboxEffectHosts.get(host.sandboxId) !== host) {
|
|
6736
|
+
return;
|
|
6509
6737
|
}
|
|
6510
|
-
host.
|
|
6738
|
+
host.recovering = true;
|
|
6739
|
+
this.stopEffectHostHeartbeat(host);
|
|
6740
|
+
this.sandboxEffectHosts.delete(host.sandboxId);
|
|
6741
|
+
try {
|
|
6742
|
+
host.wsClient.disconnect();
|
|
6743
|
+
} catch (disconnectError) {
|
|
6511
6744
|
console.warn(
|
|
6512
|
-
`[Granular]
|
|
6513
|
-
|
|
6745
|
+
`[Granular] Failed to disconnect stale effect host for sandbox ${host.sandboxId}:`,
|
|
6746
|
+
disconnectError
|
|
6514
6747
|
);
|
|
6748
|
+
}
|
|
6749
|
+
void this.ensureSandboxEffectHost(host.sandboxId).catch((reconnectError) => {
|
|
6750
|
+
console.error(
|
|
6751
|
+
`[Granular] Failed to recover effect host for sandbox ${host.sandboxId} after heartbeat failure:`,
|
|
6752
|
+
reconnectError
|
|
6753
|
+
);
|
|
6754
|
+
console.error("[Granular] Original heartbeat failure:", error);
|
|
6515
6755
|
});
|
|
6516
|
-
|
|
6756
|
+
}
|
|
6757
|
+
startEffectHostHeartbeat(host) {
|
|
6758
|
+
if (host.heartbeatTimer) {
|
|
6759
|
+
clearInterval(host.heartbeatTimer);
|
|
6760
|
+
}
|
|
6761
|
+
host.heartbeatInFlight = false;
|
|
6762
|
+
const sendHeartbeat = (failureLabel, recoverOnFailure) => {
|
|
6763
|
+
if (host.heartbeatInFlight || host.recovering) {
|
|
6764
|
+
return;
|
|
6765
|
+
}
|
|
6766
|
+
host.heartbeatInFlight = true;
|
|
6517
6767
|
host.wsClient.call("client.heartbeat", {}).catch((error) => {
|
|
6518
|
-
console.warn(
|
|
6519
|
-
|
|
6520
|
-
error
|
|
6521
|
-
|
|
6768
|
+
console.warn(`${failureLabel} ${host.sandboxId}:`, error);
|
|
6769
|
+
if (recoverOnFailure) {
|
|
6770
|
+
this.recoverEffectHost(host, error);
|
|
6771
|
+
}
|
|
6772
|
+
}).finally(() => {
|
|
6773
|
+
host.heartbeatInFlight = false;
|
|
6522
6774
|
});
|
|
6775
|
+
};
|
|
6776
|
+
sendHeartbeat("[Granular] Initial effect host heartbeat failed for sandbox", false);
|
|
6777
|
+
host.heartbeatTimer = setInterval(() => {
|
|
6778
|
+
sendHeartbeat("[Granular] Effect host heartbeat failed for sandbox", true);
|
|
6523
6779
|
}, 1e4);
|
|
6524
6780
|
}
|
|
6525
6781
|
stopEffectHostHeartbeat(host) {
|
|
@@ -6528,6 +6784,7 @@ var Granular = class {
|
|
|
6528
6784
|
}
|
|
6529
6785
|
clearInterval(host.heartbeatTimer);
|
|
6530
6786
|
host.heartbeatTimer = null;
|
|
6787
|
+
host.heartbeatInFlight = false;
|
|
6531
6788
|
}
|
|
6532
6789
|
async synchronizeEffectHost(host) {
|
|
6533
6790
|
await host.wsClient.call("client.hello", {
|
|
@@ -6563,19 +6820,13 @@ var Granular = class {
|
|
|
6563
6820
|
effectClientId,
|
|
6564
6821
|
clientId,
|
|
6565
6822
|
wsClient,
|
|
6566
|
-
heartbeatTimer: null
|
|
6823
|
+
heartbeatTimer: null,
|
|
6824
|
+
heartbeatInFlight: false,
|
|
6825
|
+
recovering: false
|
|
6567
6826
|
};
|
|
6568
6827
|
wsClient.registerRpcHandler("effect.invoke", async (params) => {
|
|
6569
6828
|
const request = params;
|
|
6570
|
-
|
|
6571
|
-
if (!effect) {
|
|
6572
|
-
throw new Error(`Effect handler not found: ${request.effectKey}`);
|
|
6573
|
-
}
|
|
6574
|
-
if (effect.className && !effect.static && request.input && typeof request.input === "object" && "_objectId" in request.input) {
|
|
6575
|
-
const { _objectId, ...rest } = request.input;
|
|
6576
|
-
return effect.handler(_objectId, rest, request.context);
|
|
6577
|
-
}
|
|
6578
|
-
return effect.handler(request.input, request.context);
|
|
6829
|
+
return invokeRegisteredEffect(this.getSandboxEffectMap(sandboxId), request);
|
|
6579
6830
|
});
|
|
6580
6831
|
wsClient.on("open", () => {
|
|
6581
6832
|
void this.synchronizeEffectHost(host).catch((error) => {
|
|
@@ -6618,7 +6869,7 @@ var Granular = class {
|
|
|
6618
6869
|
async registerEffect(sandboxNameOrId, effect) {
|
|
6619
6870
|
const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
|
|
6620
6871
|
const sandboxId = sandbox.sandboxId;
|
|
6621
|
-
this.getSandboxEffectMap(sandboxId).set(
|
|
6872
|
+
this.getSandboxEffectMap(sandboxId).set(computeEffectKey2(effect), effect);
|
|
6622
6873
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6623
6874
|
}
|
|
6624
6875
|
/**
|
|
@@ -6631,7 +6882,7 @@ var Granular = class {
|
|
|
6631
6882
|
const sandboxId = sandbox.sandboxId;
|
|
6632
6883
|
const map = this.getSandboxEffectMap(sandboxId);
|
|
6633
6884
|
for (const effect of effects) {
|
|
6634
|
-
map.set(
|
|
6885
|
+
map.set(computeEffectKey2(effect), effect);
|
|
6635
6886
|
}
|
|
6636
6887
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6637
6888
|
}
|
|
@@ -6912,5 +7163,7 @@ exports.Environment = Environment;
|
|
|
6912
7163
|
exports.Granular = Granular;
|
|
6913
7164
|
exports.Session = Session;
|
|
6914
7165
|
exports.WSClient = WSClient;
|
|
7166
|
+
exports.invokeRegisteredEffect = invokeRegisteredEffect;
|
|
7167
|
+
exports.normalizeEffectBehaviors = normalizeEffectBehaviors;
|
|
6915
7168
|
//# sourceMappingURL=index.js.map
|
|
6916
7169
|
//# sourceMappingURL=index.js.map
|