@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.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
|
|
5520
|
+
function computeEffectKey2(effect) {
|
|
5402
5521
|
const attachedClass = effect.className?.trim();
|
|
5403
5522
|
if (!attachedClass) {
|
|
5404
5523
|
return `global:${effect.name}`;
|
|
@@ -5472,6 +5591,19 @@ function normalizeUser(user) {
|
|
|
5472
5591
|
permissions: Array.isArray(user.permissions) ? user.permissions : []
|
|
5473
5592
|
};
|
|
5474
5593
|
}
|
|
5594
|
+
function normalizeEnvironmentData(environment) {
|
|
5595
|
+
const buildPolicy = environment.buildPolicy || environment.tracking || (environment.tagId ? { mode: "tag", tagId: environment.tagId } : { mode: "pinned", versionId: environment.versionId || environment.buildId });
|
|
5596
|
+
const environmentName = environment.environment || environment.envName || "prod";
|
|
5597
|
+
return {
|
|
5598
|
+
...environment,
|
|
5599
|
+
ontologyId: environment.ontologyId || environment.sandboxId,
|
|
5600
|
+
versionId: environment.versionId || environment.buildId,
|
|
5601
|
+
envName: environmentName,
|
|
5602
|
+
environment: environmentName,
|
|
5603
|
+
buildPolicy,
|
|
5604
|
+
tracking: environment.tracking || buildPolicy
|
|
5605
|
+
};
|
|
5606
|
+
}
|
|
5475
5607
|
var Environment = class extends Session {
|
|
5476
5608
|
envData;
|
|
5477
5609
|
_apiKey;
|
|
@@ -5490,10 +5622,26 @@ var Environment = class extends Session {
|
|
|
5490
5622
|
get sandboxId() {
|
|
5491
5623
|
return this.envData.sandboxId;
|
|
5492
5624
|
}
|
|
5625
|
+
/** The ontology ID */
|
|
5626
|
+
get ontologyId() {
|
|
5627
|
+
return this.envData.ontologyId || this.envData.sandboxId;
|
|
5628
|
+
}
|
|
5493
5629
|
/** The subject ID */
|
|
5494
5630
|
get subjectId() {
|
|
5495
5631
|
return this.envData.subjectId;
|
|
5496
5632
|
}
|
|
5633
|
+
/** The named environment slot, such as dev or prod */
|
|
5634
|
+
get envName() {
|
|
5635
|
+
return this.envData.envName;
|
|
5636
|
+
}
|
|
5637
|
+
/** The named environment slot, such as dev or prod */
|
|
5638
|
+
get environment() {
|
|
5639
|
+
return this.envData.environment || this.envData.envName;
|
|
5640
|
+
}
|
|
5641
|
+
/** The resolved ontology version backing this environment */
|
|
5642
|
+
get versionId() {
|
|
5643
|
+
return this.envData.versionId || this.envData.buildId;
|
|
5644
|
+
}
|
|
5497
5645
|
/** Internal Granular user identifier for this environment */
|
|
5498
5646
|
get granularId() {
|
|
5499
5647
|
return this.envData.subjectId;
|
|
@@ -5975,6 +6123,87 @@ var Environment = class extends Session {
|
|
|
5975
6123
|
}
|
|
5976
6124
|
return ref;
|
|
5977
6125
|
}
|
|
6126
|
+
async _runGraphql(query, label) {
|
|
6127
|
+
const result = await this.graphql(query);
|
|
6128
|
+
if (result.errors?.length) {
|
|
6129
|
+
throw new Error(`${label}: ${result.errors[0].message}`);
|
|
6130
|
+
}
|
|
6131
|
+
return result.data;
|
|
6132
|
+
}
|
|
6133
|
+
async _applyFieldMetamodels(fieldPath, spec) {
|
|
6134
|
+
for (const mutation of buildFieldMetamodelMutations(fieldPath, spec)) {
|
|
6135
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6136
|
+
}
|
|
6137
|
+
}
|
|
6138
|
+
async _applyModelMetamodels(modelPath, op) {
|
|
6139
|
+
for (const mutation of buildModelMetamodelMutations(modelPath, op)) {
|
|
6140
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
async _ensureWorkspaceToolsRoot() {
|
|
6144
|
+
await this._runGraphql(
|
|
6145
|
+
`mutation { create_model(path: "workspace", label: "workspace") { model { path } } }`,
|
|
6146
|
+
"ensure workspace"
|
|
6147
|
+
).catch((error) => {
|
|
6148
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6149
|
+
});
|
|
6150
|
+
await this._runGraphql(
|
|
6151
|
+
`mutation { at(path: "workspace") { create_submodel(subpath: "tools", label: "Tools") { model { path } } } }`,
|
|
6152
|
+
"ensure workspace:tools"
|
|
6153
|
+
).catch((error) => {
|
|
6154
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6155
|
+
});
|
|
6156
|
+
await this._runGraphql(
|
|
6157
|
+
`mutation { at(path: "workspace:tools") { create_submodel(subpath: "declared", label: "Declared") { model { path } } } }`,
|
|
6158
|
+
"ensure workspace:tools:declared"
|
|
6159
|
+
).catch((error) => {
|
|
6160
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6161
|
+
});
|
|
6162
|
+
}
|
|
6163
|
+
async _storeEffectSchemas(toolPath, effect) {
|
|
6164
|
+
await this._runGraphql(
|
|
6165
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "inputSchema", label: "inputSchema") { set_string_value(value: ${JSON.stringify(JSON.stringify(effect.inputSchema))}) { done } } } }`,
|
|
6166
|
+
`store inputSchema on ${toolPath}`
|
|
6167
|
+
).catch((error) => {
|
|
6168
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6169
|
+
});
|
|
6170
|
+
if (effect.outputSchema) {
|
|
6171
|
+
await this._runGraphql(
|
|
6172
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "outputSchema", label: "outputSchema") { set_string_value(value: ${JSON.stringify(JSON.stringify(effect.outputSchema))}) { done } } } }`,
|
|
6173
|
+
`store outputSchema on ${toolPath}`
|
|
6174
|
+
).catch((error) => {
|
|
6175
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6176
|
+
});
|
|
6177
|
+
}
|
|
6178
|
+
}
|
|
6179
|
+
async _applyEffectMetamodels(toolPath, metamodels) {
|
|
6180
|
+
for (const mutation of buildEffectMetamodelMutations(toolPath, metamodels)) {
|
|
6181
|
+
await this._runGraphql(mutation.query, mutation.label);
|
|
6182
|
+
}
|
|
6183
|
+
}
|
|
6184
|
+
async _applyEffectDeclaration(effect, aliasMap) {
|
|
6185
|
+
let containerPath = "workspace:tools:declared";
|
|
6186
|
+
if (effect.attachedClass) {
|
|
6187
|
+
containerPath = this._resolveAlias(effect.attachedClass, aliasMap);
|
|
6188
|
+
} else {
|
|
6189
|
+
await this._ensureWorkspaceToolsRoot();
|
|
6190
|
+
}
|
|
6191
|
+
await this._runGraphql(
|
|
6192
|
+
`mutation { at(path: ${JSON.stringify(containerPath)}) { create_submodel(subpath: ${JSON.stringify(effect.name)}, label: ${JSON.stringify(effect.name)}) { model { path } } } }`,
|
|
6193
|
+
`create effect model ${containerPath}:${effect.name}`
|
|
6194
|
+
).catch((error) => {
|
|
6195
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6196
|
+
});
|
|
6197
|
+
const toolPath = `${containerPath}:${effect.name}`;
|
|
6198
|
+
if (effect.description) {
|
|
6199
|
+
await this._runGraphql(
|
|
6200
|
+
`mutation { at(path: ${JSON.stringify(toolPath)}) { set_description(description: ${JSON.stringify(effect.description)}) { done } } }`,
|
|
6201
|
+
`set effect description on ${toolPath}`
|
|
6202
|
+
);
|
|
6203
|
+
}
|
|
6204
|
+
await this._storeEffectSchemas(toolPath, effect);
|
|
6205
|
+
await this._applyEffectMetamodels(toolPath, effect.metamodels);
|
|
6206
|
+
}
|
|
5978
6207
|
/**
|
|
5979
6208
|
* Apply a single manifest operation via GraphQL
|
|
5980
6209
|
*/
|
|
@@ -5997,24 +6226,32 @@ var Environment = class extends Session {
|
|
|
5997
6226
|
const extendsRef = op.extends ? this._resolveAlias(op.extends, aliasMap) : void 0;
|
|
5998
6227
|
const instanceOfRef = op.instanceOf ? this._resolveAlias(op.instanceOf, aliasMap) : void 0;
|
|
5999
6228
|
if (extendsRef) {
|
|
6000
|
-
await this.
|
|
6001
|
-
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }
|
|
6229
|
+
await this._runGraphql(
|
|
6230
|
+
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`,
|
|
6231
|
+
`create model ${op.create}`
|
|
6002
6232
|
);
|
|
6003
|
-
await this.
|
|
6004
|
-
`mutation { at(path: "${op.create}") { add_superclass(superclass: "${extendsRef}") { model { path } } } }
|
|
6233
|
+
await this._runGraphql(
|
|
6234
|
+
`mutation { at(path: "${op.create}") { add_superclass(superclass: "${extendsRef}") { model { path } } } }`,
|
|
6235
|
+
`add superclass ${extendsRef} to ${op.create}`
|
|
6005
6236
|
);
|
|
6006
6237
|
} else if (instanceOfRef) {
|
|
6007
|
-
await this.
|
|
6008
|
-
`mutation { at(path: "${instanceOfRef}") { instantiate(path: "${op.create}", label: "${label}") { model { path } } } }
|
|
6238
|
+
await this._runGraphql(
|
|
6239
|
+
`mutation { at(path: "${instanceOfRef}") { instantiate(path: "${op.create}", label: "${label}") { model { path } } } }`,
|
|
6240
|
+
`instantiate ${op.create} from ${instanceOfRef}`
|
|
6009
6241
|
);
|
|
6010
6242
|
} else {
|
|
6011
|
-
await this.
|
|
6012
|
-
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }
|
|
6243
|
+
await this._runGraphql(
|
|
6244
|
+
`mutation { create_model(path: "${op.create}", label: "${label}") { model { path } } }`,
|
|
6245
|
+
`create model ${op.create}`
|
|
6013
6246
|
);
|
|
6014
6247
|
}
|
|
6015
6248
|
if (op.has) {
|
|
6016
6249
|
await this._applyFields(op.create, op.has);
|
|
6017
6250
|
}
|
|
6251
|
+
await this._applyModelMetamodels(op.create, op);
|
|
6252
|
+
if (op.withEffect) {
|
|
6253
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6254
|
+
}
|
|
6018
6255
|
return;
|
|
6019
6256
|
}
|
|
6020
6257
|
if (op.on) {
|
|
@@ -6022,8 +6259,15 @@ var Environment = class extends Session {
|
|
|
6022
6259
|
if (op.has) {
|
|
6023
6260
|
await this._applyFields(target, op.has);
|
|
6024
6261
|
}
|
|
6262
|
+
await this._applyModelMetamodels(target, op);
|
|
6263
|
+
if (op.withEffect) {
|
|
6264
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6265
|
+
}
|
|
6025
6266
|
return;
|
|
6026
6267
|
}
|
|
6268
|
+
if (op.withEffect) {
|
|
6269
|
+
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
6270
|
+
}
|
|
6027
6271
|
}
|
|
6028
6272
|
/**
|
|
6029
6273
|
* Apply field definitions (has) to a model via GraphQL
|
|
@@ -6031,81 +6275,91 @@ var Environment = class extends Session {
|
|
|
6031
6275
|
async _applyFields(modelPath, fields) {
|
|
6032
6276
|
for (const [fieldName, spec] of Object.entries(fields)) {
|
|
6033
6277
|
const fieldLabel = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
|
|
6034
|
-
await this.
|
|
6278
|
+
await this._runGraphql(
|
|
6035
6279
|
`mutation {
|
|
6036
|
-
at(path:
|
|
6037
|
-
create_submodel(subpath:
|
|
6280
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6281
|
+
create_submodel(subpath: ${JSON.stringify(fieldName)}, label: ${JSON.stringify(fieldLabel)}) {
|
|
6038
6282
|
model { path }
|
|
6039
6283
|
}
|
|
6040
6284
|
}
|
|
6041
|
-
}
|
|
6042
|
-
|
|
6285
|
+
}`,
|
|
6286
|
+
`create field ${modelPath}.${fieldName}`
|
|
6287
|
+
).catch((error) => {
|
|
6288
|
+
if (!error.message.includes("already exists")) throw error;
|
|
6289
|
+
});
|
|
6043
6290
|
if (spec.type) {
|
|
6044
|
-
await this.
|
|
6291
|
+
await this._runGraphql(
|
|
6045
6292
|
`mutation {
|
|
6046
|
-
at(path:
|
|
6047
|
-
at(submodel:
|
|
6048
|
-
add_prototype(prototype:
|
|
6293
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6294
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6295
|
+
add_prototype(prototype: ${JSON.stringify(spec.type)}) { done }
|
|
6049
6296
|
}
|
|
6050
6297
|
}
|
|
6051
|
-
}
|
|
6298
|
+
}`,
|
|
6299
|
+
`set prototype on ${modelPath}:${fieldName}`
|
|
6052
6300
|
);
|
|
6053
6301
|
}
|
|
6054
6302
|
if (spec.description) {
|
|
6055
|
-
await this.
|
|
6303
|
+
await this._runGraphql(
|
|
6056
6304
|
`mutation {
|
|
6057
|
-
at(path:
|
|
6058
|
-
at(submodel:
|
|
6059
|
-
set_description(description:
|
|
6305
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6306
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6307
|
+
set_description(description: ${JSON.stringify(spec.description)}) { done }
|
|
6060
6308
|
}
|
|
6061
6309
|
}
|
|
6062
|
-
}
|
|
6310
|
+
}`,
|
|
6311
|
+
`set description on ${modelPath}:${fieldName}`
|
|
6063
6312
|
);
|
|
6064
6313
|
}
|
|
6065
6314
|
if (spec.value !== void 0 && spec.value !== null) {
|
|
6066
6315
|
if (typeof spec.value === "string") {
|
|
6067
|
-
await this.
|
|
6316
|
+
await this._runGraphql(
|
|
6068
6317
|
`mutation {
|
|
6069
|
-
at(path:
|
|
6070
|
-
at(submodel:
|
|
6071
|
-
set_string_value(value:
|
|
6318
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6319
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6320
|
+
set_string_value(value: ${JSON.stringify(spec.value)}) { done }
|
|
6072
6321
|
}
|
|
6073
6322
|
}
|
|
6074
|
-
}
|
|
6323
|
+
}`,
|
|
6324
|
+
`set string value on ${modelPath}:${fieldName}`
|
|
6075
6325
|
);
|
|
6076
6326
|
} else if (typeof spec.value === "number") {
|
|
6077
|
-
await this.
|
|
6327
|
+
await this._runGraphql(
|
|
6078
6328
|
`mutation {
|
|
6079
|
-
at(path:
|
|
6080
|
-
at(submodel:
|
|
6329
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6330
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6081
6331
|
set_number_value(value: ${spec.value}) { done }
|
|
6082
6332
|
}
|
|
6083
6333
|
}
|
|
6084
|
-
}
|
|
6334
|
+
}`,
|
|
6335
|
+
`set number value on ${modelPath}:${fieldName}`
|
|
6085
6336
|
);
|
|
6086
6337
|
} else if (typeof spec.value === "boolean") {
|
|
6087
|
-
await this.
|
|
6338
|
+
await this._runGraphql(
|
|
6088
6339
|
`mutation {
|
|
6089
|
-
at(path:
|
|
6090
|
-
at(submodel:
|
|
6340
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6341
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6091
6342
|
set_boolean_value(value: ${spec.value}) { done }
|
|
6092
6343
|
}
|
|
6093
6344
|
}
|
|
6094
|
-
}
|
|
6345
|
+
}`,
|
|
6346
|
+
`set boolean value on ${modelPath}:${fieldName}`
|
|
6095
6347
|
);
|
|
6096
6348
|
}
|
|
6097
6349
|
}
|
|
6098
6350
|
if (spec.ref) {
|
|
6099
|
-
await this.
|
|
6351
|
+
await this._runGraphql(
|
|
6100
6352
|
`mutation {
|
|
6101
|
-
at(path:
|
|
6102
|
-
at(submodel:
|
|
6103
|
-
set_reference(reference:
|
|
6353
|
+
at(path: ${JSON.stringify(modelPath)}) {
|
|
6354
|
+
at(submodel: ${JSON.stringify(fieldName)}) {
|
|
6355
|
+
set_reference(reference: ${JSON.stringify(spec.ref)}) { done }
|
|
6104
6356
|
}
|
|
6105
6357
|
}
|
|
6106
|
-
}
|
|
6358
|
+
}`,
|
|
6359
|
+
`set reference on ${modelPath}:${fieldName}`
|
|
6107
6360
|
);
|
|
6108
6361
|
}
|
|
6362
|
+
await this._applyFieldMetamodels(`${modelPath}:${fieldName}`, spec);
|
|
6109
6363
|
if (spec.has) {
|
|
6110
6364
|
await this._applyFields(`${modelPath}:${fieldName}`, spec.has);
|
|
6111
6365
|
}
|
|
@@ -6359,7 +6613,7 @@ var Granular = class {
|
|
|
6359
6613
|
throw new Error("connect() requires either userId, granularId, or a user object returned by recordUser().");
|
|
6360
6614
|
}
|
|
6361
6615
|
/**
|
|
6362
|
-
* Connect to
|
|
6616
|
+
* Connect to an ontology environment and establish a real-time session.
|
|
6363
6617
|
*
|
|
6364
6618
|
* Effects are registered at the sandbox level via `granular.registerEffect()`
|
|
6365
6619
|
* or `granular.registerEffects()`. Sessions pick up live availability from
|
|
@@ -6371,7 +6625,8 @@ var Granular = class {
|
|
|
6371
6625
|
* @example
|
|
6372
6626
|
* ```typescript
|
|
6373
6627
|
* const environment = await granular.connect({
|
|
6374
|
-
*
|
|
6628
|
+
* ontology: 'my-ontology',
|
|
6629
|
+
* environment: 'dev',
|
|
6375
6630
|
* userId: 'user_123',
|
|
6376
6631
|
* permissions: ['agent'],
|
|
6377
6632
|
* });
|
|
@@ -6391,17 +6646,28 @@ var Granular = class {
|
|
|
6391
6646
|
*
|
|
6392
6647
|
* console.log(await job.result); // 'Hello!'
|
|
6393
6648
|
* ```
|
|
6394
|
-
|
|
6649
|
+
*/
|
|
6395
6650
|
async connect(options) {
|
|
6396
6651
|
const clientId = options.clientId || `client_${Date.now()}`;
|
|
6652
|
+
const ontology = options.ontology;
|
|
6653
|
+
if (!ontology) {
|
|
6654
|
+
throw new Error("connect() requires `ontology`.");
|
|
6655
|
+
}
|
|
6656
|
+
const environmentName = options.environment;
|
|
6657
|
+
if (!environmentName) {
|
|
6658
|
+
throw new Error("connect() requires `environment`.");
|
|
6659
|
+
}
|
|
6660
|
+
const tagName = options.tagName?.trim() || void 0;
|
|
6397
6661
|
const user = await this.resolveConnectUser(options);
|
|
6398
|
-
const sandbox = await this.findOrCreateSandbox(
|
|
6662
|
+
const sandbox = await this.findOrCreateSandbox(ontology);
|
|
6399
6663
|
for (const profileName of user.permissions) {
|
|
6400
6664
|
const profileId = await this.ensurePermissionProfile(sandbox.sandboxId, profileName);
|
|
6401
6665
|
await this.ensureAssignment(user.granularId, sandbox.sandboxId, profileId);
|
|
6402
6666
|
}
|
|
6403
6667
|
const envData = await this.environments.create(sandbox.sandboxId, {
|
|
6404
6668
|
subjectId: user.granularId,
|
|
6669
|
+
environment: environmentName,
|
|
6670
|
+
tagName,
|
|
6405
6671
|
permissionProfileId: null
|
|
6406
6672
|
});
|
|
6407
6673
|
await this.activateEnvironment(envData.environmentId);
|
|
@@ -6445,7 +6711,7 @@ var Granular = class {
|
|
|
6445
6711
|
}
|
|
6446
6712
|
serializeEffect(effect) {
|
|
6447
6713
|
return {
|
|
6448
|
-
effectKey:
|
|
6714
|
+
effectKey: computeEffectKey2(effect),
|
|
6449
6715
|
name: effect.name,
|
|
6450
6716
|
description: effect.description,
|
|
6451
6717
|
inputSchema: effect.inputSchema,
|
|
@@ -6481,23 +6747,54 @@ var Granular = class {
|
|
|
6481
6747
|
const host = await this.ensureSandboxEffectHost(sandboxId);
|
|
6482
6748
|
await this.publishSandboxEffectCatalog(host);
|
|
6483
6749
|
}
|
|
6484
|
-
|
|
6485
|
-
if (host.
|
|
6486
|
-
|
|
6750
|
+
recoverEffectHost(host, error) {
|
|
6751
|
+
if (host.recovering) {
|
|
6752
|
+
return;
|
|
6753
|
+
}
|
|
6754
|
+
if (this.sandboxEffectHosts.get(host.sandboxId) !== host) {
|
|
6755
|
+
return;
|
|
6487
6756
|
}
|
|
6488
|
-
host.
|
|
6757
|
+
host.recovering = true;
|
|
6758
|
+
this.stopEffectHostHeartbeat(host);
|
|
6759
|
+
this.sandboxEffectHosts.delete(host.sandboxId);
|
|
6760
|
+
try {
|
|
6761
|
+
host.wsClient.disconnect();
|
|
6762
|
+
} catch (disconnectError) {
|
|
6489
6763
|
console.warn(
|
|
6490
|
-
`[Granular]
|
|
6491
|
-
|
|
6764
|
+
`[Granular] Failed to disconnect stale effect host for sandbox ${host.sandboxId}:`,
|
|
6765
|
+
disconnectError
|
|
6766
|
+
);
|
|
6767
|
+
}
|
|
6768
|
+
void this.ensureSandboxEffectHost(host.sandboxId).catch((reconnectError) => {
|
|
6769
|
+
console.error(
|
|
6770
|
+
`[Granular] Failed to recover effect host for sandbox ${host.sandboxId} after heartbeat failure:`,
|
|
6771
|
+
reconnectError
|
|
6492
6772
|
);
|
|
6773
|
+
console.error("[Granular] Original heartbeat failure:", error);
|
|
6493
6774
|
});
|
|
6494
|
-
|
|
6775
|
+
}
|
|
6776
|
+
startEffectHostHeartbeat(host) {
|
|
6777
|
+
if (host.heartbeatTimer) {
|
|
6778
|
+
clearInterval(host.heartbeatTimer);
|
|
6779
|
+
}
|
|
6780
|
+
host.heartbeatInFlight = false;
|
|
6781
|
+
const sendHeartbeat = (failureLabel, recoverOnFailure) => {
|
|
6782
|
+
if (host.heartbeatInFlight || host.recovering) {
|
|
6783
|
+
return;
|
|
6784
|
+
}
|
|
6785
|
+
host.heartbeatInFlight = true;
|
|
6495
6786
|
host.wsClient.call("client.heartbeat", {}).catch((error) => {
|
|
6496
|
-
console.warn(
|
|
6497
|
-
|
|
6498
|
-
error
|
|
6499
|
-
|
|
6787
|
+
console.warn(`${failureLabel} ${host.sandboxId}:`, error);
|
|
6788
|
+
if (recoverOnFailure) {
|
|
6789
|
+
this.recoverEffectHost(host, error);
|
|
6790
|
+
}
|
|
6791
|
+
}).finally(() => {
|
|
6792
|
+
host.heartbeatInFlight = false;
|
|
6500
6793
|
});
|
|
6794
|
+
};
|
|
6795
|
+
sendHeartbeat("[Granular] Initial effect host heartbeat failed for sandbox", false);
|
|
6796
|
+
host.heartbeatTimer = setInterval(() => {
|
|
6797
|
+
sendHeartbeat("[Granular] Effect host heartbeat failed for sandbox", true);
|
|
6501
6798
|
}, 1e4);
|
|
6502
6799
|
}
|
|
6503
6800
|
stopEffectHostHeartbeat(host) {
|
|
@@ -6506,6 +6803,7 @@ var Granular = class {
|
|
|
6506
6803
|
}
|
|
6507
6804
|
clearInterval(host.heartbeatTimer);
|
|
6508
6805
|
host.heartbeatTimer = null;
|
|
6806
|
+
host.heartbeatInFlight = false;
|
|
6509
6807
|
}
|
|
6510
6808
|
async synchronizeEffectHost(host) {
|
|
6511
6809
|
await host.wsClient.call("client.hello", {
|
|
@@ -6541,19 +6839,13 @@ var Granular = class {
|
|
|
6541
6839
|
effectClientId,
|
|
6542
6840
|
clientId,
|
|
6543
6841
|
wsClient,
|
|
6544
|
-
heartbeatTimer: null
|
|
6842
|
+
heartbeatTimer: null,
|
|
6843
|
+
heartbeatInFlight: false,
|
|
6844
|
+
recovering: false
|
|
6545
6845
|
};
|
|
6546
6846
|
wsClient.registerRpcHandler("effect.invoke", async (params) => {
|
|
6547
6847
|
const request = params;
|
|
6548
|
-
|
|
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);
|
|
6848
|
+
return invokeRegisteredEffect(this.getSandboxEffectMap(sandboxId), request);
|
|
6557
6849
|
});
|
|
6558
6850
|
wsClient.on("open", () => {
|
|
6559
6851
|
void this.synchronizeEffectHost(host).catch((error) => {
|
|
@@ -6596,7 +6888,7 @@ var Granular = class {
|
|
|
6596
6888
|
async registerEffect(sandboxNameOrId, effect) {
|
|
6597
6889
|
const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
|
|
6598
6890
|
const sandboxId = sandbox.sandboxId;
|
|
6599
|
-
this.getSandboxEffectMap(sandboxId).set(
|
|
6891
|
+
this.getSandboxEffectMap(sandboxId).set(computeEffectKey2(effect), effect);
|
|
6600
6892
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6601
6893
|
}
|
|
6602
6894
|
/**
|
|
@@ -6609,7 +6901,7 @@ var Granular = class {
|
|
|
6609
6901
|
const sandboxId = sandbox.sandboxId;
|
|
6610
6902
|
const map = this.getSandboxEffectMap(sandboxId);
|
|
6611
6903
|
for (const effect of effects) {
|
|
6612
|
-
map.set(
|
|
6904
|
+
map.set(computeEffectKey2(effect), effect);
|
|
6613
6905
|
}
|
|
6614
6906
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6615
6907
|
}
|
|
@@ -6810,16 +7102,22 @@ var Granular = class {
|
|
|
6810
7102
|
const result = await this.request(
|
|
6811
7103
|
`/control/sandboxes/${sandboxId}/environments`
|
|
6812
7104
|
);
|
|
6813
|
-
return result.items;
|
|
7105
|
+
return result.items.map(normalizeEnvironmentData);
|
|
6814
7106
|
},
|
|
6815
7107
|
get: async (environmentId) => {
|
|
6816
|
-
return
|
|
7108
|
+
return normalizeEnvironmentData(
|
|
7109
|
+
await this.request(`/control/environments/${environmentId}`)
|
|
7110
|
+
);
|
|
6817
7111
|
},
|
|
6818
7112
|
create: async (sandboxId, data) => {
|
|
6819
|
-
|
|
7113
|
+
const environmentName = data.environment || data.envName;
|
|
7114
|
+
return normalizeEnvironmentData(await this.request(`/control/sandboxes/${sandboxId}/environments`, {
|
|
6820
7115
|
method: "POST",
|
|
6821
|
-
body: JSON.stringify(
|
|
6822
|
-
|
|
7116
|
+
body: JSON.stringify({
|
|
7117
|
+
...data,
|
|
7118
|
+
envName: environmentName
|
|
7119
|
+
})
|
|
7120
|
+
}));
|
|
6823
7121
|
},
|
|
6824
7122
|
delete: async (environmentId) => {
|
|
6825
7123
|
return this.request(`/control/environments/${environmentId}`, {
|
|
@@ -6886,6 +7184,6 @@ var Granular = class {
|
|
|
6886
7184
|
}
|
|
6887
7185
|
};
|
|
6888
7186
|
|
|
6889
|
-
export { Environment, Granular, Session, WSClient };
|
|
7187
|
+
export { Environment, Granular, Session, WSClient, invokeRegisteredEffect, normalizeEffectBehaviors };
|
|
6890
7188
|
//# sourceMappingURL=index.mjs.map
|
|
6891
7189
|
//# sourceMappingURL=index.mjs.map
|