@granular-software/sdk 0.4.12 → 0.4.14
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/README.md +14 -12
- package/dist/cli/index.js +486 -75
- package/dist/index.d.mts +215 -12
- package/dist/index.d.ts +215 -12
- package/dist/index.js +375 -75
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +374 -76
- 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}`;
|
|
@@ -5494,6 +5613,19 @@ function normalizeUser(user) {
|
|
|
5494
5613
|
permissions: Array.isArray(user.permissions) ? user.permissions : []
|
|
5495
5614
|
};
|
|
5496
5615
|
}
|
|
5616
|
+
function normalizeEnvironmentData(environment) {
|
|
5617
|
+
const buildPolicy = environment.buildPolicy || environment.tracking || (environment.tagId ? { mode: "tag", tagId: environment.tagId } : { mode: "pinned", versionId: environment.versionId || environment.buildId });
|
|
5618
|
+
const environmentName = environment.environment || environment.envName || "prod";
|
|
5619
|
+
return {
|
|
5620
|
+
...environment,
|
|
5621
|
+
ontologyId: environment.ontologyId || environment.sandboxId,
|
|
5622
|
+
versionId: environment.versionId || environment.buildId,
|
|
5623
|
+
envName: environmentName,
|
|
5624
|
+
environment: environmentName,
|
|
5625
|
+
buildPolicy,
|
|
5626
|
+
tracking: environment.tracking || buildPolicy
|
|
5627
|
+
};
|
|
5628
|
+
}
|
|
5497
5629
|
var Environment = class extends Session {
|
|
5498
5630
|
envData;
|
|
5499
5631
|
_apiKey;
|
|
@@ -5512,10 +5644,26 @@ var Environment = class extends Session {
|
|
|
5512
5644
|
get sandboxId() {
|
|
5513
5645
|
return this.envData.sandboxId;
|
|
5514
5646
|
}
|
|
5647
|
+
/** The ontology ID */
|
|
5648
|
+
get ontologyId() {
|
|
5649
|
+
return this.envData.ontologyId || this.envData.sandboxId;
|
|
5650
|
+
}
|
|
5515
5651
|
/** The subject ID */
|
|
5516
5652
|
get subjectId() {
|
|
5517
5653
|
return this.envData.subjectId;
|
|
5518
5654
|
}
|
|
5655
|
+
/** The named environment slot, such as dev or prod */
|
|
5656
|
+
get envName() {
|
|
5657
|
+
return this.envData.envName;
|
|
5658
|
+
}
|
|
5659
|
+
/** The named environment slot, such as dev or prod */
|
|
5660
|
+
get environment() {
|
|
5661
|
+
return this.envData.environment || this.envData.envName;
|
|
5662
|
+
}
|
|
5663
|
+
/** The resolved ontology version backing this environment */
|
|
5664
|
+
get versionId() {
|
|
5665
|
+
return this.envData.versionId || this.envData.buildId;
|
|
5666
|
+
}
|
|
5519
5667
|
/** Internal Granular user identifier for this environment */
|
|
5520
5668
|
get granularId() {
|
|
5521
5669
|
return this.envData.subjectId;
|
|
@@ -5997,6 +6145,87 @@ var Environment = class extends Session {
|
|
|
5997
6145
|
}
|
|
5998
6146
|
return ref;
|
|
5999
6147
|
}
|
|
6148
|
+
async _runGraphql(query, label) {
|
|
6149
|
+
const result = await this.graphql(query);
|
|
6150
|
+
if (result.errors?.length) {
|
|
6151
|
+
throw new Error(`${label}: ${result.errors[0].message}`);
|
|
6152
|
+
}
|
|
6153
|
+
return result.data;
|
|
6154
|
+
}
|
|
6155
|
+
async _applyFieldMetamodels(fieldPath, spec) {
|
|
6156
|
+
for (const mutation of buildFieldMetamodelMutations(fieldPath, spec)) {
|
|
6157
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6158
|
+
}
|
|
6159
|
+
}
|
|
6160
|
+
async _applyModelMetamodels(modelPath, op) {
|
|
6161
|
+
for (const mutation of buildModelMetamodelMutations(modelPath, op)) {
|
|
6162
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
async _ensureWorkspaceToolsRoot() {
|
|
6166
|
+
await this._runGraphql(
|
|
6167
|
+
`mutation { create_model(path: "workspace", label: "workspace") { model { path } } }`,
|
|
6168
|
+
"ensure workspace"
|
|
6169
|
+
).catch((error) => {
|
|
6170
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6171
|
+
});
|
|
6172
|
+
await this._runGraphql(
|
|
6173
|
+
`mutation { at(path: "workspace") { create_submodel(subpath: "tools", label: "Tools") { model { path } } } }`,
|
|
6174
|
+
"ensure workspace:tools"
|
|
6175
|
+
).catch((error) => {
|
|
6176
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6177
|
+
});
|
|
6178
|
+
await this._runGraphql(
|
|
6179
|
+
`mutation { at(path: "workspace:tools") { create_submodel(subpath: "declared", label: "Declared") { model { path } } } }`,
|
|
6180
|
+
"ensure workspace:tools:declared"
|
|
6181
|
+
).catch((error) => {
|
|
6182
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6183
|
+
});
|
|
6184
|
+
}
|
|
6185
|
+
async _storeEffectSchemas(toolPath, effect) {
|
|
6186
|
+
await this._runGraphql(
|
|
6187
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "inputSchema", label: "inputSchema") { set_string_value(value: ${JSON.stringify(JSON.stringify(effect.inputSchema))}) { done } } } }`,
|
|
6188
|
+
`store inputSchema on ${toolPath}`
|
|
6189
|
+
).catch((error) => {
|
|
6190
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6191
|
+
});
|
|
6192
|
+
if (effect.outputSchema) {
|
|
6193
|
+
await this._runGraphql(
|
|
6194
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "outputSchema", label: "outputSchema") { set_string_value(value: ${JSON.stringify(JSON.stringify(effect.outputSchema))}) { done } } } }`,
|
|
6195
|
+
`store outputSchema on ${toolPath}`
|
|
6196
|
+
).catch((error) => {
|
|
6197
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6198
|
+
});
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
6201
|
+
async _applyEffectMetamodels(toolPath, metamodels) {
|
|
6202
|
+
for (const mutation of buildEffectMetamodelMutations(toolPath, metamodels)) {
|
|
6203
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6204
|
+
}
|
|
6205
|
+
}
|
|
6206
|
+
async _applyEffectDeclaration(effect, aliasMap) {
|
|
6207
|
+
let containerPath = "workspace:tools:declared";
|
|
6208
|
+
if (effect.attachedClass) {
|
|
6209
|
+
containerPath = this._resolveAlias(effect.attachedClass, aliasMap);
|
|
6210
|
+
} else {
|
|
6211
|
+
await this._ensureWorkspaceToolsRoot();
|
|
6212
|
+
}
|
|
6213
|
+
await this._runGraphql(
|
|
6214
|
+
`mutation { at(path: ${JSON.stringify(containerPath)}) { create_submodel(subpath: ${JSON.stringify(effect.name)}, label: ${JSON.stringify(effect.name)}) { model { path } } } }`,
|
|
6215
|
+
`create effect model ${containerPath}:${effect.name}`
|
|
6216
|
+
).catch((error) => {
|
|
6217
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6218
|
+
});
|
|
6219
|
+
const toolPath = `${containerPath}:${effect.name}`;
|
|
6220
|
+
if (effect.description) {
|
|
6221
|
+
await this._runGraphql(
|
|
6222
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { set_description(description: ${JSON.stringify(effect.description)}) { done } } }`,
|
|
6223
|
+
`set effect description on ${toolPath}`
|
|
6224
|
+
);
|
|
6225
|
+
}
|
|
6226
|
+
await this._storeEffectSchemas(toolPath, effect);
|
|
6227
|
+
await this._applyEffectMetamodels(toolPath, effect.metamodels);
|
|
6228
|
+
}
|
|
6000
6229
|
/**
|
|
6001
6230
|
* Apply a single manifest operation via GraphQL
|
|
6002
6231
|
*/
|
|
@@ -6019,24 +6248,32 @@ var Environment = class extends Session {
|
|
|
6019
6248
|
const extendsRef = op.extends ? this._resolveAlias(op.extends, aliasMap) : void 0;
|
|
6020
6249
|
const instanceOfRef = op.instanceOf ? this._resolveAlias(op.instanceOf, aliasMap) : void 0;
|
|
6021
6250
|
if (extendsRef) {
|
|
6022
|
-
await this.
|
|
6023
|
-
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }
|
|
6251
|
+
await this._runGraphql(
|
|
6252
|
+
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`,
|
|
6253
|
+
`create model ${op.create}`
|
|
6024
6254
|
);
|
|
6025
|
-
await this.
|
|
6026
|
-
`mutation { at(path: "${op.create}") { add_superclass(superclass: "${extendsRef}") { model { path } } } }
|
|
6255
|
+
await this._runGraphql(
|
|
6256
|
+
`mutation { at(path: "${op.create}") { add_superclass(superclass: "${extendsRef}") { model { path } } } }`,
|
|
6257
|
+
`add superclass ${extendsRef} to ${op.create}`
|
|
6027
6258
|
);
|
|
6028
6259
|
} else if (instanceOfRef) {
|
|
6029
|
-
await this.
|
|
6030
|
-
`mutation { at(path: "${instanceOfRef}") { instantiate(path: "${op.create}", label: "${label}") { model { path } } } }
|
|
6260
|
+
await this._runGraphql(
|
|
6261
|
+
`mutation { at(path: "${instanceOfRef}") { instantiate(path: "${op.create}", label: "${label}") { model { path } } } }`,
|
|
6262
|
+
`instantiate ${op.create} from ${instanceOfRef}`
|
|
6031
6263
|
);
|
|
6032
6264
|
} else {
|
|
6033
|
-
await this.
|
|
6034
|
-
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }
|
|
6265
|
+
await this._runGraphql(
|
|
6266
|
+
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`,
|
|
6267
|
+
`create model ${op.create}`
|
|
6035
6268
|
);
|
|
6036
6269
|
}
|
|
6037
6270
|
if (op.has) {
|
|
6038
6271
|
await this._applyFields(op.create, op.has);
|
|
6039
6272
|
}
|
|
6273
|
+
await this._applyModelMetamodels(op.create, op);
|
|
6274
|
+
if (op.withEffect) {
|
|
6275
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6276
|
+
}
|
|
6040
6277
|
return;
|
|
6041
6278
|
}
|
|
6042
6279
|
if (op.on) {
|
|
@@ -6044,8 +6281,15 @@ var Environment = class extends Session {
|
|
|
6044
6281
|
if (op.has) {
|
|
6045
6282
|
await this._applyFields(target, op.has);
|
|
6046
6283
|
}
|
|
6284
|
+
await this._applyModelMetamodels(target, op);
|
|
6285
|
+
if (op.withEffect) {
|
|
6286
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6287
|
+
}
|
|
6047
6288
|
return;
|
|
6048
6289
|
}
|
|
6290
|
+
if (op.withEffect) {
|
|
6291
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6292
|
+
}
|
|
6049
6293
|
}
|
|
6050
6294
|
/**
|
|
6051
6295
|
* Apply field definitions (has) to a model via GraphQL
|
|
@@ -6053,81 +6297,91 @@ var Environment = class extends Session {
|
|
|
6053
6297
|
async _applyFields(modelPath, fields) {
|
|
6054
6298
|
for (const [fieldName, spec] of Object.entries(fields)) {
|
|
6055
6299
|
const fieldLabel = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
|
|
6056
|
-
await this.
|
|
6300
|
+
await this._runGraphql(
|
|
6057
6301
|
`mutation {
|
|
6058
|
-
at(path:
|
|
6059
|
-
create_submodel(subpath:
|
|
6302
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6303
|
+
create_submodel(subpath: ${JSON.stringify(fieldName)}, label: ${JSON.stringify(fieldLabel)}) {
|
|
6060
6304
|
model { path }
|
|
6061
6305
|
}
|
|
6062
6306
|
}
|
|
6063
|
-
}
|
|
6064
|
-
|
|
6307
|
+
}`,
|
|
6308
|
+
`create field ${modelPath}.${fieldName}`
|
|
6309
|
+
).catch((error) => {
|
|
6310
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6311
|
+
});
|
|
6065
6312
|
if (spec.type) {
|
|
6066
|
-
await this.
|
|
6313
|
+
await this._runGraphql(
|
|
6067
6314
|
`mutation {
|
|
6068
|
-
at(path:
|
|
6069
|
-
at(submodel:
|
|
6070
|
-
add_prototype(prototype:
|
|
6315
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6316
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6317
|
+
add_prototype(prototype: ${JSON.stringify(spec.type)}) { done }
|
|
6071
6318
|
}
|
|
6072
6319
|
}
|
|
6073
|
-
}
|
|
6320
|
+
}`,
|
|
6321
|
+
`set prototype on ${modelPath}:${fieldName}`
|
|
6074
6322
|
);
|
|
6075
6323
|
}
|
|
6076
6324
|
if (spec.description) {
|
|
6077
|
-
await this.
|
|
6325
|
+
await this._runGraphql(
|
|
6078
6326
|
`mutation {
|
|
6079
|
-
at(path:
|
|
6080
|
-
at(submodel:
|
|
6081
|
-
set_description(description:
|
|
6327
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6328
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6329
|
+
set_description(description: ${JSON.stringify(spec.description)}) { done }
|
|
6082
6330
|
}
|
|
6083
6331
|
}
|
|
6084
|
-
}
|
|
6332
|
+
}`,
|
|
6333
|
+
`set description on ${modelPath}:${fieldName}`
|
|
6085
6334
|
);
|
|
6086
6335
|
}
|
|
6087
6336
|
if (spec.value !== void 0 && spec.value !== null) {
|
|
6088
6337
|
if (typeof spec.value === "string") {
|
|
6089
|
-
await this.
|
|
6338
|
+
await this._runGraphql(
|
|
6090
6339
|
`mutation {
|
|
6091
|
-
at(path:
|
|
6092
|
-
at(submodel:
|
|
6093
|
-
set_string_value(value:
|
|
6340
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6341
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6342
|
+
set_string_value(value: ${JSON.stringify(spec.value)}) { done }
|
|
6094
6343
|
}
|
|
6095
6344
|
}
|
|
6096
|
-
}
|
|
6345
|
+
}`,
|
|
6346
|
+
`set string value on ${modelPath}:${fieldName}`
|
|
6097
6347
|
);
|
|
6098
6348
|
} else if (typeof spec.value === "number") {
|
|
6099
|
-
await this.
|
|
6349
|
+
await this._runGraphql(
|
|
6100
6350
|
`mutation {
|
|
6101
|
-
at(path:
|
|
6102
|
-
at(submodel:
|
|
6351
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6352
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6103
6353
|
set_number_value(value: ${spec.value}) { done }
|
|
6104
6354
|
}
|
|
6105
6355
|
}
|
|
6106
|
-
}
|
|
6356
|
+
}`,
|
|
6357
|
+
`set number value on ${modelPath}:${fieldName}`
|
|
6107
6358
|
);
|
|
6108
6359
|
} else if (typeof spec.value === "boolean") {
|
|
6109
|
-
await this.
|
|
6360
|
+
await this._runGraphql(
|
|
6110
6361
|
`mutation {
|
|
6111
|
-
at(path:
|
|
6112
|
-
at(submodel:
|
|
6362
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6363
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6113
6364
|
set_boolean_value(value: ${spec.value}) { done }
|
|
6114
6365
|
}
|
|
6115
6366
|
}
|
|
6116
|
-
}
|
|
6367
|
+
}`,
|
|
6368
|
+
`set boolean value on ${modelPath}:${fieldName}`
|
|
6117
6369
|
);
|
|
6118
6370
|
}
|
|
6119
6371
|
}
|
|
6120
6372
|
if (spec.ref) {
|
|
6121
|
-
await this.
|
|
6373
|
+
await this._runGraphql(
|
|
6122
6374
|
`mutation {
|
|
6123
|
-
at(path:
|
|
6124
|
-
at(submodel:
|
|
6125
|
-
set_reference(reference:
|
|
6375
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6376
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6377
|
+
set_reference(reference: ${JSON.stringify(spec.ref)}) { done }
|
|
6126
6378
|
}
|
|
6127
6379
|
}
|
|
6128
|
-
}
|
|
6380
|
+
}`,
|
|
6381
|
+
`set reference on ${modelPath}:${fieldName}`
|
|
6129
6382
|
);
|
|
6130
6383
|
}
|
|
6384
|
+
await this._applyFieldMetamodels(`${modelPath}:${fieldName}`, spec);
|
|
6131
6385
|
if (spec.has) {
|
|
6132
6386
|
await this._applyFields(`${modelPath}:${fieldName}`, spec.has);
|
|
6133
6387
|
}
|
|
@@ -6381,7 +6635,7 @@ var Granular = class {
|
|
|
6381
6635
|
throw new Error("connect() requires either userId, granularId, or a user object returned by recordUser().");
|
|
6382
6636
|
}
|
|
6383
6637
|
/**
|
|
6384
|
-
* Connect to
|
|
6638
|
+
* Connect to an ontology environment and establish a real-time session.
|
|
6385
6639
|
*
|
|
6386
6640
|
* Effects are registered at the sandbox level via `granular.registerEffect()`
|
|
6387
6641
|
* or `granular.registerEffects()`. Sessions pick up live availability from
|
|
@@ -6393,7 +6647,8 @@ var Granular = class {
|
|
|
6393
6647
|
* @example
|
|
6394
6648
|
* ```typescript
|
|
6395
6649
|
* const environment = await granular.connect({
|
|
6396
|
-
*
|
|
6650
|
+
* ontology: 'my-ontology',
|
|
6651
|
+
* environment: 'dev',
|
|
6397
6652
|
* userId: 'user_123',
|
|
6398
6653
|
* permissions: ['agent'],
|
|
6399
6654
|
* });
|
|
@@ -6413,17 +6668,28 @@ var Granular = class {
|
|
|
6413
6668
|
*
|
|
6414
6669
|
* console.log(await job.result); // 'Hello!'
|
|
6415
6670
|
* ```
|
|
6416
|
-
|
|
6671
|
+
*/
|
|
6417
6672
|
async connect(options) {
|
|
6418
6673
|
const clientId = options.clientId || `client_${Date.now()}`;
|
|
6674
|
+
const ontology = options.ontology;
|
|
6675
|
+
if (!ontology) {
|
|
6676
|
+
throw new Error("connect() requires `ontology`.");
|
|
6677
|
+
}
|
|
6678
|
+
const environmentName = options.environment;
|
|
6679
|
+
if (!environmentName) {
|
|
6680
|
+
throw new Error("connect() requires `environment`.");
|
|
6681
|
+
}
|
|
6682
|
+
const tagName = options.tagName?.trim() || void 0;
|
|
6419
6683
|
const user = await this.resolveConnectUser(options);
|
|
6420
|
-
const sandbox = await this.findOrCreateSandbox(
|
|
6684
|
+
const sandbox = await this.findOrCreateSandbox(ontology);
|
|
6421
6685
|
for (const profileName of user.permissions) {
|
|
6422
6686
|
const profileId = await this.ensurePermissionProfile(sandbox.sandboxId, profileName);
|
|
6423
6687
|
await this.ensureAssignment(user.granularId, sandbox.sandboxId, profileId);
|
|
6424
6688
|
}
|
|
6425
6689
|
const envData = await this.environments.create(sandbox.sandboxId, {
|
|
6426
6690
|
subjectId: user.granularId,
|
|
6691
|
+
environment: environmentName,
|
|
6692
|
+
tagName,
|
|
6427
6693
|
permissionProfileId: null
|
|
6428
6694
|
});
|
|
6429
6695
|
await this.activateEnvironment(envData.environmentId);
|
|
@@ -6467,7 +6733,7 @@ var Granular = class {
|
|
|
6467
6733
|
}
|
|
6468
6734
|
serializeEffect(effect) {
|
|
6469
6735
|
return {
|
|
6470
|
-
effectKey:
|
|
6736
|
+
effectKey: computeEffectKey2(effect),
|
|
6471
6737
|
name: effect.name,
|
|
6472
6738
|
description: effect.description,
|
|
6473
6739
|
inputSchema: effect.inputSchema,
|
|
@@ -6503,23 +6769,54 @@ var Granular = class {
|
|
|
6503
6769
|
const host = await this.ensureSandboxEffectHost(sandboxId);
|
|
6504
6770
|
await this.publishSandboxEffectCatalog(host);
|
|
6505
6771
|
}
|
|
6506
|
-
|
|
6507
|
-
if (host.
|
|
6508
|
-
|
|
6772
|
+
recoverEffectHost(host, error) {
|
|
6773
|
+
if (host.recovering) {
|
|
6774
|
+
return;
|
|
6775
|
+
}
|
|
6776
|
+
if (this.sandboxEffectHosts.get(host.sandboxId) !== host) {
|
|
6777
|
+
return;
|
|
6509
6778
|
}
|
|
6510
|
-
host.
|
|
6779
|
+
host.recovering = true;
|
|
6780
|
+
this.stopEffectHostHeartbeat(host);
|
|
6781
|
+
this.sandboxEffectHosts.delete(host.sandboxId);
|
|
6782
|
+
try {
|
|
6783
|
+
host.wsClient.disconnect();
|
|
6784
|
+
} catch (disconnectError) {
|
|
6511
6785
|
console.warn(
|
|
6512
|
-
`[Granular]
|
|
6513
|
-
|
|
6786
|
+
`[Granular] Failed to disconnect stale effect host for sandbox ${host.sandboxId}:`,
|
|
6787
|
+
disconnectError
|
|
6788
|
+
);
|
|
6789
|
+
}
|
|
6790
|
+
void this.ensureSandboxEffectHost(host.sandboxId).catch((reconnectError) => {
|
|
6791
|
+
console.error(
|
|
6792
|
+
`[Granular] Failed to recover effect host for sandbox ${host.sandboxId} after heartbeat failure:`,
|
|
6793
|
+
reconnectError
|
|
6514
6794
|
);
|
|
6795
|
+
console.error("[Granular] Original heartbeat failure:", error);
|
|
6515
6796
|
});
|
|
6516
|
-
|
|
6797
|
+
}
|
|
6798
|
+
startEffectHostHeartbeat(host) {
|
|
6799
|
+
if (host.heartbeatTimer) {
|
|
6800
|
+
clearInterval(host.heartbeatTimer);
|
|
6801
|
+
}
|
|
6802
|
+
host.heartbeatInFlight = false;
|
|
6803
|
+
const sendHeartbeat = (failureLabel, recoverOnFailure) => {
|
|
6804
|
+
if (host.heartbeatInFlight || host.recovering) {
|
|
6805
|
+
return;
|
|
6806
|
+
}
|
|
6807
|
+
host.heartbeatInFlight = true;
|
|
6517
6808
|
host.wsClient.call("client.heartbeat", {}).catch((error) => {
|
|
6518
|
-
console.warn(
|
|
6519
|
-
|
|
6520
|
-
error
|
|
6521
|
-
|
|
6809
|
+
console.warn(`${failureLabel} ${host.sandboxId}:`, error);
|
|
6810
|
+
if (recoverOnFailure) {
|
|
6811
|
+
this.recoverEffectHost(host, error);
|
|
6812
|
+
}
|
|
6813
|
+
}).finally(() => {
|
|
6814
|
+
host.heartbeatInFlight = false;
|
|
6522
6815
|
});
|
|
6816
|
+
};
|
|
6817
|
+
sendHeartbeat("[Granular] Initial effect host heartbeat failed for sandbox", false);
|
|
6818
|
+
host.heartbeatTimer = setInterval(() => {
|
|
6819
|
+
sendHeartbeat("[Granular] Effect host heartbeat failed for sandbox", true);
|
|
6523
6820
|
}, 1e4);
|
|
6524
6821
|
}
|
|
6525
6822
|
stopEffectHostHeartbeat(host) {
|
|
@@ -6528,6 +6825,7 @@ var Granular = class {
|
|
|
6528
6825
|
}
|
|
6529
6826
|
clearInterval(host.heartbeatTimer);
|
|
6530
6827
|
host.heartbeatTimer = null;
|
|
6828
|
+
host.heartbeatInFlight = false;
|
|
6531
6829
|
}
|
|
6532
6830
|
async synchronizeEffectHost(host) {
|
|
6533
6831
|
await host.wsClient.call("client.hello", {
|
|
@@ -6563,19 +6861,13 @@ var Granular = class {
|
|
|
6563
6861
|
effectClientId,
|
|
6564
6862
|
clientId,
|
|
6565
6863
|
wsClient,
|
|
6566
|
-
heartbeatTimer: null
|
|
6864
|
+
heartbeatTimer: null,
|
|
6865
|
+
heartbeatInFlight: false,
|
|
6866
|
+
recovering: false
|
|
6567
6867
|
};
|
|
6568
6868
|
wsClient.registerRpcHandler("effect.invoke", async (params) => {
|
|
6569
6869
|
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);
|
|
6870
|
+
return invokeRegisteredEffect(this.getSandboxEffectMap(sandboxId), request);
|
|
6579
6871
|
});
|
|
6580
6872
|
wsClient.on("open", () => {
|
|
6581
6873
|
void this.synchronizeEffectHost(host).catch((error) => {
|
|
@@ -6618,7 +6910,7 @@ var Granular = class {
|
|
|
6618
6910
|
async registerEffect(sandboxNameOrId, effect) {
|
|
6619
6911
|
const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
|
|
6620
6912
|
const sandboxId = sandbox.sandboxId;
|
|
6621
|
-
this.getSandboxEffectMap(sandboxId).set(
|
|
6913
|
+
this.getSandboxEffectMap(sandboxId).set(computeEffectKey2(effect), effect);
|
|
6622
6914
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6623
6915
|
}
|
|
6624
6916
|
/**
|
|
@@ -6631,7 +6923,7 @@ var Granular = class {
|
|
|
6631
6923
|
const sandboxId = sandbox.sandboxId;
|
|
6632
6924
|
const map = this.getSandboxEffectMap(sandboxId);
|
|
6633
6925
|
for (const effect of effects) {
|
|
6634
|
-
map.set(
|
|
6926
|
+
map.set(computeEffectKey2(effect), effect);
|
|
6635
6927
|
}
|
|
6636
6928
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6637
6929
|
}
|
|
@@ -6832,16 +7124,22 @@ var Granular = class {
|
|
|
6832
7124
|
const result = await this.request(
|
|
6833
7125
|
`/control/sandboxes/${sandboxId}/environments`
|
|
6834
7126
|
);
|
|
6835
|
-
return result.items;
|
|
7127
|
+
return result.items.map(normalizeEnvironmentData);
|
|
6836
7128
|
},
|
|
6837
7129
|
get: async (environmentId) => {
|
|
6838
|
-
return
|
|
7130
|
+
return normalizeEnvironmentData(
|
|
7131
|
+
await this.request(`/control/environments/${environmentId}`)
|
|
7132
|
+
);
|
|
6839
7133
|
},
|
|
6840
7134
|
create: async (sandboxId, data) => {
|
|
6841
|
-
|
|
7135
|
+
const environmentName = data.environment || data.envName;
|
|
7136
|
+
return normalizeEnvironmentData(await this.request(`/control/sandboxes/${sandboxId}/environments`, {
|
|
6842
7137
|
method: "POST",
|
|
6843
|
-
body: JSON.stringify(
|
|
6844
|
-
|
|
7138
|
+
body: JSON.stringify({
|
|
7139
|
+
...data,
|
|
7140
|
+
envName: environmentName
|
|
7141
|
+
})
|
|
7142
|
+
}));
|
|
6845
7143
|
},
|
|
6846
7144
|
delete: async (environmentId) => {
|
|
6847
7145
|
return this.request(`/control/environments/${environmentId}`, {
|
|
@@ -6912,5 +7210,7 @@ exports.Environment = Environment;
|
|
|
6912
7210
|
exports.Granular = Granular;
|
|
6913
7211
|
exports.Session = Session;
|
|
6914
7212
|
exports.WSClient = WSClient;
|
|
7213
|
+
exports.invokeRegisteredEffect = invokeRegisteredEffect;
|
|
7214
|
+
exports.normalizeEffectBehaviors = normalizeEffectBehaviors;
|
|
6915
7215
|
//# sourceMappingURL=index.js.map
|
|
6916
7216
|
//# sourceMappingURL=index.js.map
|