@granular-software/sdk 0.4.30 → 0.4.31
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 +25 -20
- package/dist/agent-evals.d.mts +7 -6
- package/dist/agent-evals.d.ts +7 -6
- package/dist/agent-evals.js +681 -277
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +681 -277
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/cli/index.js +526 -271
- package/dist/{client-BVvOMfln.d.mts → client-CTH1hfwe.d.mts} +254 -123
- package/dist/{client-BVvOMfln.d.ts → client-CTH1hfwe.d.ts} +254 -123
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +439 -187
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +438 -188
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -6597,9 +6597,9 @@ async function main() {
|
|
|
6597
6597
|
});
|
|
6598
6598
|
|
|
6599
6599
|
// Connect as one app user so the SDK can create an environment for the seed run.
|
|
6600
|
-
const env = await granular.
|
|
6600
|
+
const env = await granular.openEnvironment({
|
|
6601
6601
|
ontology: SANDBOX_ID,
|
|
6602
|
-
|
|
6602
|
+
tag: 'dev',
|
|
6603
6603
|
userId: '${template.seedUser.userId}',
|
|
6604
6604
|
name: '${template.seedUser.name}',
|
|
6605
6605
|
email: '${template.seedUser.email}',
|
|
@@ -6621,7 +6621,7 @@ async function main() {
|
|
|
6621
6621
|
const updatedCount = results.length - createdCount;
|
|
6622
6622
|
console.log(\`[Seed] Created \${createdCount} records, updated \${updatedCount} records.\`);
|
|
6623
6623
|
} finally {
|
|
6624
|
-
await
|
|
6624
|
+
await session.disconnect();
|
|
6625
6625
|
}
|
|
6626
6626
|
|
|
6627
6627
|
console.log(\`Seeded \${records.length} records into \${SANDBOX_ID}\`);
|
|
@@ -6670,7 +6670,7 @@ async function main() {
|
|
|
6670
6670
|
apiUrl: process.env.GRANULAR_API_URL ?? API_URL,
|
|
6671
6671
|
});
|
|
6672
6672
|
|
|
6673
|
-
await granular.
|
|
6673
|
+
await granular.ontology(SANDBOX_ID).effects.registerMany([
|
|
6674
6674
|
${registrations}
|
|
6675
6675
|
]);
|
|
6676
6676
|
|
|
@@ -6688,7 +6688,7 @@ ${registrations}
|
|
|
6688
6688
|
shuttingDown = true;
|
|
6689
6689
|
clearInterval(keepAliveTimer);
|
|
6690
6690
|
console.log(\`Shutting down after \${signal}...\`);
|
|
6691
|
-
await granular.
|
|
6691
|
+
await granular.ontology(SANDBOX_ID).effects.disconnect();
|
|
6692
6692
|
resolve();
|
|
6693
6693
|
process.exit(0);
|
|
6694
6694
|
};
|
|
@@ -6738,9 +6738,9 @@ test('granular connect + submitJob smoke test', {
|
|
|
6738
6738
|
apiUrl: process.env.GRANULAR_API_URL ?? rc.apiUrl ?? DEFAULT_API_URL,
|
|
6739
6739
|
});
|
|
6740
6740
|
|
|
6741
|
-
const environment = await granular.
|
|
6741
|
+
const environment = await granular.openEnvironment({
|
|
6742
6742
|
ontology: rc.sandboxId,
|
|
6743
|
-
|
|
6743
|
+
tag: 'dev',
|
|
6744
6744
|
userId: '${template.seedUser.userId}',
|
|
6745
6745
|
name: '${template.seedUser.name}',
|
|
6746
6746
|
email: '${template.seedUser.email}',
|
|
@@ -6751,7 +6751,8 @@ test('granular connect + submitJob smoke test', {
|
|
|
6751
6751
|
assert.ok(environment.environmentId);
|
|
6752
6752
|
assert.ok(environment.sessionId);
|
|
6753
6753
|
|
|
6754
|
-
const
|
|
6754
|
+
const session = await environment.sessions.create();
|
|
6755
|
+
const job = await session.submitJob(\`
|
|
6755
6756
|
return {
|
|
6756
6757
|
ok: true,
|
|
6757
6758
|
template: '${template.id}',
|
|
@@ -6762,7 +6763,7 @@ return {
|
|
|
6762
6763
|
assert.equal(result.ok, true);
|
|
6763
6764
|
assert.equal(result.template, '${template.id}');
|
|
6764
6765
|
} finally {
|
|
6765
|
-
await
|
|
6766
|
+
await session.disconnect();
|
|
6766
6767
|
}
|
|
6767
6768
|
});
|
|
6768
6769
|
`;
|
|
@@ -8960,7 +8961,7 @@ function manifestGuideGranularProductSection() {
|
|
|
8960
8961
|
2. **Build** that declaration from \`granular.json\` so the service compiles types and tooling for a **sandbox** (a workspace identified by \`sbx_\u2026\`).
|
|
8961
8962
|
3. **Store** **records** (instances of your classes) and **run jobs** (code executed in Granular\u2019s **sandbox runtime**) that call generated helpers and effects.
|
|
8962
8963
|
|
|
8963
|
-
**Split of responsibility:** Data and domain rules live in Granular; **secrets, payment providers, email, and arbitrary HTTP** stay in **your** server via **effect handlers** you register with \`
|
|
8964
|
+
**Split of responsibility:** Data and domain rules live in Granular; **secrets, payment providers, email, and arbitrary HTTP** stay in **your** server via **effect handlers** you register with \`granular.ontology(sandboxId).effects.registerMany\`.
|
|
8964
8965
|
|
|
8965
8966
|
---
|
|
8966
8967
|
|
|
@@ -8985,10 +8986,10 @@ The rest of this guide assumes these terms.
|
|
|
8985
8986
|
| **Manifest** | \`granular.json\` (definition under \`manifest\`). **Source** in the repo until you create a new ontology **version** from it. |
|
|
8986
8987
|
| **Version** | Immutable ontology state derived from one manifest revision. Tags like \`dev\` and \`prod\` point to versions. |
|
|
8987
8988
|
| **Build run** | The CI-style compilation process. \`granular build\` creates or reuses the ontology version, then runs a build for it. |
|
|
8988
|
-
| **Environment** | Return value of \`granular.
|
|
8989
|
-
| **Session** |
|
|
8990
|
-
| **Job** | Code string passed to \`
|
|
8991
|
-
| **Effect** | Declared with \`withEffect\`; **handler** registered
|
|
8989
|
+
| **Environment** | Return value of \`granular.openEnvironment({ ontology, tag, userId, \u2026 })\`. It is your **server-side** handle for \`recordObject\`, \`recordObjects\`, \`graphql\`, and \`sessions.create()\`. |
|
|
8990
|
+
| **Session** | Live runtime connection opened from an environment with \`environment.sessions.create()\` or \`environment.sessions.connect()\`. Job, prompt, and streaming APIs live here. |
|
|
8991
|
+
| **Job** | Code string passed to \`session.submitJob(code)\`. Runs in Granular\u2019s **sandbox runtime** with access to \`./sandbox-tools\` (generated classes + effect entrypoints). |
|
|
8992
|
+
| **Effect** | Declared with \`withEffect\`; **handler** registered in **your** process with \`granular.ontology(sandboxId).effects.registerMany(...)\`. Jobs invoke effects; handlers do IO outside Granular. |
|
|
8992
8993
|
| **Class** | Entity **kind** in the domain (e.g. \`book\`) with \`has\` fields in the manifest. |
|
|
8993
8994
|
| **Record / object** | One **instance**: \`className\`, \`id\`, \`fields\`, \`relationships\`. Use \`recordObject\` for one upsert, \`recordObjects\` for several immediate upserts, and record-import APIs for async bulk loads. |
|
|
8994
8995
|
| **Relationship** | Declared link between two classes; defines **property names** and cardinality. Keys appear in \`recordObject({ relationships })\`. |
|
|
@@ -9007,10 +9008,10 @@ function manifestGuideEndToEndSection() {
|
|
|
9007
9008
|
|------|--------|---------|
|
|
9008
9009
|
| 1 | Edit \`granular.json\` (\`manifest\` \u2192 \`volumes\` \u2192 \`operations\`) | Domain **source** in the repo |
|
|
9009
9010
|
| 2 | \`granular build\` | Manifest **uploaded**; ontology version created or reused; build run compiles it; errors surface here |
|
|
9010
|
-
| 3 | (Optional) Run your **effects host** \u2014 e.g. \`npx tsx granular-effects.ts\` \u2014 calling \`
|
|
9011
|
-
| 4 | \`new Granular({ apiKey })\` then \`
|
|
9011
|
+
| 3 | (Optional) Run your **effects host** \u2014 e.g. \`npx tsx granular-effects.ts\` \u2014 calling \`granular.ontology(sandboxId).effects.registerMany(...)\` | Effect **handlers** attached in **your** process |
|
|
9012
|
+
| 4 | \`new Granular({ apiKey })\` then \`openEnvironment({ ontology, tag, userId, permissions })\` | **\`Environment\`** handle for that ontology/user pair |
|
|
9012
9013
|
| 5 | \`recordObject\` / \`recordObjects\` | **Records** stored with correct fields and relationship keys. Use \`recordObject\` for one targeted write. Use \`recordObjects\` for one synchronous multi-record write with chunking (default 100 rows/request), retries, and optional \`onChunkComplete\` / \`concurrency\` progress. For async bulk loads use \`enqueueRecordImport\` + import status APIs. |
|
|
9013
|
-
| 6 | \`submitJob(\`\u2026\`)\`
|
|
9014
|
+
| 6 | \`const session = await environment.sessions.create();\` then \`session.submitJob(\`\u2026\`)\` | **Jobs** run; may call **effects** \u2192 your handlers execute and return results |
|
|
9014
9015
|
|
|
9015
9016
|
**Accuracy tip:** After changing the manifest, always **re-build** before assuming generated types, \`./sandbox-tools\` names, or effect signatures match the file on disk.`;
|
|
9016
9017
|
}
|
|
@@ -9024,9 +9025,9 @@ function sandboxDocMainConceptsSection() {
|
|
|
9024
9025
|
| **Manifest** | \`granular.json\` \u2014 **source**; edit here, then \`granular build\`. |
|
|
9025
9026
|
| **Version** | Immutable ontology state created from one manifest revision. |
|
|
9026
9027
|
| **Build run** | Compilation run that validates and materializes a version. |
|
|
9027
|
-
| **Environment** | \`
|
|
9028
|
-
| **Session** |
|
|
9029
|
-
| **Job** | \`submitJob\` code using \`./sandbox-tools\`. |
|
|
9028
|
+
| **Environment** | \`openEnvironment()\` result \u2014 **record**, **recordObjects**, **graphql**, and **session lifecycle** for this sandbox. |
|
|
9029
|
+
| **Session** | Live runtime connection created from an environment; job and prompt APIs live here. |
|
|
9030
|
+
| **Job** | \`session.submitJob(...)\` code using \`./sandbox-tools\`. |
|
|
9030
9031
|
| **Effect** | Declared in manifest; **handler** in your process. |
|
|
9031
9032
|
|
|
9032
9033
|
**Full product + manifest how-to:** [docs/granular-manifest.md](docs/granular-manifest.md).`;
|
|
@@ -14860,7 +14861,7 @@ function generateManifestAgentGuide(options) {
|
|
|
14860
14861
|
);
|
|
14861
14862
|
return `# Granular manifest guide (for coding agents)
|
|
14862
14863
|
|
|
14863
|
-
This guide is for **coding agents** who may have **no prior context on Granular**. It explains the product, core terms, how to **author** \`granular.json\`, **build** the domain, and use the SDK (\`
|
|
14864
|
+
This guide is for **coding agents** who may have **no prior context on Granular**. It explains the product, core terms, how to **author** \`granular.json\`, **build** the domain, and use the SDK (\`openEnvironment\` \u2192 **environment**, \`environment.sessions.create()\` \u2192 **session**, \`recordObject\`, **effects**). For **this repository\u2019s** exact class names, relationship keys, and effect payloads only, see [GRANULAR_SANDBOX.md](../GRANULAR_SANDBOX.md).
|
|
14864
14865
|
|
|
14865
14866
|
**Precedence:** User instructions in chat override this file. When in doubt, read \`granular.json\` and [AGENTS.md](../AGENTS.md).
|
|
14866
14867
|
|
|
@@ -15118,14 +15119,14 @@ Example:
|
|
|
15118
15119
|
|
|
15119
15120
|
| Field | Meaning |
|
|
15120
15121
|
|-------|---------|
|
|
15121
|
-
| \`name\` | Must match the
|
|
15122
|
+
| \`name\` | Must match the handler name you register from your effect host. |
|
|
15122
15123
|
| \`attachedClass\` | Omit for **global** effects. Set for class-bound effects. |
|
|
15123
15124
|
| \`isStatic\` | \`true\` \u2192 static method; \`false\` or omit \u2192 **instance** method (handler receives the object **id** first). |
|
|
15124
15125
|
| \`inputSchema\` / \`outputSchema\` | JSON Schema; used for codegen and validation. |
|
|
15125
15126
|
|
|
15126
|
-
**Lifecycle:** declare in manifest \u2192 \`granular build\` creates or reuses a version and runs the build \u2192 implement handlers \u2192 \`granular.
|
|
15127
|
+
**Lifecycle:** declare in manifest \u2192 \`granular build\` creates or reuses a version and runs the build \u2192 implement handlers \u2192 \`granular.ontology(sandboxId).effects.registerMany([...])\` \u2192 jobs call generated methods \u2192 your handler runs and returns the result to the job.
|
|
15127
15128
|
|
|
15128
|
-
**Permissions:** \`
|
|
15129
|
+
**Permissions:** \`openEnvironment({ permissions: [...] })\` assigns profiles (e.g. \`default\`) that can allow or deny which effects a user may call.
|
|
15129
15130
|
|
|
15130
15131
|
### Effect metamodels
|
|
15131
15132
|
|
|
@@ -15191,30 +15192,38 @@ ${effectMetamodelTable}
|
|
|
15191
15192
|
| API | Purpose |
|
|
15192
15193
|
|-----|---------|
|
|
15193
15194
|
| \`new Granular({ apiKey, apiUrl?, endpointMode?, token?, tokenProvider?, \u2026 })\` | Auth. Env: \`GRANULAR_API_KEY\`, \`GRANULAR_API_URL\`, \`GRANULAR_ENDPOINT_MODE\`. |
|
|
15194
|
-
| \`recordUser({ userId, name?, email?, permissions? })\` | Upsert user for later \`
|
|
15195
|
-
| \`
|
|
15196
|
-
| \`
|
|
15197
|
-
| \`
|
|
15195
|
+
| \`recordUser({ userId, name?, email?, permissions? })\` | Upsert user for later \`openEnvironment\`. |
|
|
15196
|
+
| \`openEnvironment({ ontology, tag?, userId?, granularId?, user?, permissions, createFreshIfOutdated?, ... })\` | Resolves or creates an **\`Environment\`** handle. |
|
|
15197
|
+
| \`granular.ontology(sandboxId).effects.registerMany(effects)\` / \`.register(effect)\` | Register handlers for manifest \`withEffect\` declarations. |
|
|
15198
|
+
| \`granular.ontology(sandboxId).effects.unregister(name)\` / \`.clear()\` / \`.disconnect()\` | Stop effect handlers for a sandbox. |
|
|
15198
15199
|
| \`granular.sandboxes\` | \`.list()\`, \`.get\`, \`.create\`, \`.update\`, \`.delete\` |
|
|
15199
15200
|
| \`granular.permissionProfiles\` | Permission profiles per sandbox. |
|
|
15200
|
-
| \`granular.environments\` | List/create/delete environments (
|
|
15201
|
+
| \`granular.environments\` | List/create/delete environments (advanced control-plane API). |
|
|
15201
15202
|
| \`granular.subjects\` | Subjects / assignments (see typings). |
|
|
15202
15203
|
|
|
15203
|
-
### \`Environment\` (
|
|
15204
|
+
### \`Environment\` (sessionless environment handle)
|
|
15204
15205
|
|
|
15205
15206
|
| API | Purpose |
|
|
15206
15207
|
|-----|---------|
|
|
15207
|
-
| \`environmentId\`, \`sandboxId\`, \`apiEndpoint\`, \u2026 |
|
|
15208
|
+
| \`environmentId\`, \`sandboxId\`, \`apiEndpoint\`, \u2026 | Environment context. |
|
|
15208
15209
|
| \`applyManifest(manifest)\` | Apply manifest operations at runtime (alternative to CLI build for dynamic ontologies). |
|
|
15209
15210
|
| \`recordObject\` / \`recordObjects\` | Upsert instances and relationships. Use \`recordObject\` for one object or a targeted patch. Use \`recordObjects\` for synchronous multi-record ingestion with chunked HTTP writes (default 100 rows/chunk), retries, and optional \`onChunkComplete\`, \`batchSize\`, \`concurrency\`. |
|
|
15210
15211
|
| \`enqueueRecordImport\`, \`listRecordImports\`, \`getRecordImport\`, \`getRecordImportSummary\`, \u2026 | **Async** bulk import (worker queue + aggregate progress). Prefer when loads are huge, returning an \`importId\` is enough up front, and background processing is acceptable. |
|
|
15211
15212
|
| \`graphql(query, variables?)\` | **GraphQL** \u2014 see dedicated subsection below. |
|
|
15212
15213
|
| \`defineRelationship\`, \`getRelationships\`, \`attach\`, \`detach\`, \`listRelated\` | Imperative relationship operations (same ideas as manifest \`defineRelationship\`). |
|
|
15214
|
+
| \`sessions.list()\`, \`sessions.create()\`, \`sessions.connect()\`, \`sessions.reopen()\`, \`sessions.close()\` | Session lifecycle for this environment. |
|
|
15215
|
+
|
|
15216
|
+
### \`Session\` (live runtime connection)
|
|
15217
|
+
|
|
15218
|
+
| API | Purpose |
|
|
15219
|
+
|-----|---------|
|
|
15213
15220
|
| \`submitJob(code)\` | Run code in the sandbox; import from \`./sandbox-tools\`. |
|
|
15221
|
+
| \`answerPrompt(...)\`, \`appendMessage(...)\` | Human-in-the-loop and conversation APIs. |
|
|
15214
15222
|
| \`getDomain()\`, \`getDomainTypes()\`, \`getDomainDocs()\`, \`getDomainDocumentation()\` | Domain summary and generated TypeScript / docs. |
|
|
15215
|
-
| \`getEffects()\` / \`getTools()\`, \`
|
|
15216
|
-
| \`checkReadiness()\`, \`on('readiness',
|
|
15223
|
+
| \`getEffects()\` / \`getTools()\`, \`session.on("effects:changed", ...)\` | Effect catalog and live updates. |
|
|
15224
|
+
| \`checkReadiness()\`, \`on('readiness', ...)\` | Runtime readiness. |
|
|
15217
15225
|
| \`getHeap()\` | Session state snapshot (advanced). |
|
|
15226
|
+
| \`disconnect()\` | Close the live runtime session. |
|
|
15218
15227
|
| \`rpc(method, params)\` | Low-level session RPC (advanced). |
|
|
15219
15228
|
| \`disconnect()\` | End the session. |
|
|
15220
15229
|
|
|
@@ -15414,9 +15423,9 @@ function generateSandboxAgentDoc(manifest, meta) {
|
|
|
15414
15423
|
lines.push(` // apiUrl: process.env.GRANULAR_API_URL, // optional`);
|
|
15415
15424
|
lines.push(`});`);
|
|
15416
15425
|
lines.push("");
|
|
15417
|
-
lines.push(`const env = await granular.
|
|
15426
|
+
lines.push(`const env = await granular.openEnvironment({`);
|
|
15418
15427
|
lines.push(` ontology: '${meta.sandboxId}',`);
|
|
15419
|
-
lines.push(`
|
|
15428
|
+
lines.push(` tag: 'dev',`);
|
|
15420
15429
|
lines.push(` userId: 'your_app_user_id',`);
|
|
15421
15430
|
lines.push(` permissions: ['default'],`);
|
|
15422
15431
|
lines.push(`});`);
|
|
@@ -15535,7 +15544,7 @@ function generateSandboxAgentDoc(manifest, meta) {
|
|
|
15535
15544
|
"1. **Build** the manifest so the domain package includes the effect (`granular build`)."
|
|
15536
15545
|
);
|
|
15537
15546
|
lines.push(
|
|
15538
|
-
"2. **Register** a handler whose `name` (and `className` / `static` when applicable) matches \u2014 use `granular.
|
|
15547
|
+
"2. **Register** a handler whose `name` (and `className` / `static` when applicable) matches \u2014 use `granular.ontology('" + meta.sandboxId + "').effects.registerMany([...])` in your host process (see `granular-effects.ts` in starter projects)."
|
|
15539
15548
|
);
|
|
15540
15549
|
lines.push(
|
|
15541
15550
|
"3. **Invoke** from sandbox code via `./sandbox-tools` inside `submitJob`; the handler you registered runs in your process and the result returns to the job."
|
|
@@ -15603,7 +15612,8 @@ function generateSandboxAgentDoc(manifest, meta) {
|
|
|
15603
15612
|
const globalEffects = effects2.filter((e) => !e.attachedClass);
|
|
15604
15613
|
const firstGlobal = globalEffects[0]?.name;
|
|
15605
15614
|
lines.push("```typescript");
|
|
15606
|
-
lines.push(`const
|
|
15615
|
+
lines.push(`const session = await env.sessions.create();
|
|
15616
|
+
const job = await session.submitJob(\``);
|
|
15607
15617
|
const importList = [...pascalImports, ...effectNames].filter(
|
|
15608
15618
|
(v, i, a) => a.indexOf(v) === i
|
|
15609
15619
|
);
|
|
@@ -15682,7 +15692,7 @@ function generateSandboxAgentDoc(manifest, meta) {
|
|
|
15682
15692
|
"| Domain | `getDomain`, `getDomainTypes`, `getDomainDocumentation` |"
|
|
15683
15693
|
);
|
|
15684
15694
|
lines.push(
|
|
15685
|
-
|
|
15695
|
+
'| Effects | `granular.ontology(...).effects.registerMany`, `session.getEffects()`, `session.on("effects:changed", ...)` |'
|
|
15686
15696
|
);
|
|
15687
15697
|
lines.push("| Ops | `checkReadiness`, `getHeap`, `rpc` |");
|
|
15688
15698
|
lines.push("");
|
|
@@ -18433,27 +18443,27 @@ var Session = class {
|
|
|
18433
18443
|
}
|
|
18434
18444
|
async publishTools(tools, revision = "1.0.0") {
|
|
18435
18445
|
throw new Error(
|
|
18436
|
-
"Environment-scoped effect publication was removed. Declare effects in the manifest and register live handlers with granular.
|
|
18446
|
+
"Environment-scoped effect publication was removed. Declare effects in the manifest and register live handlers with granular.ontology(environment.sandboxId).effects.registerMany(effects)."
|
|
18437
18447
|
);
|
|
18438
18448
|
}
|
|
18439
18449
|
async publishEffect(effect) {
|
|
18440
18450
|
throw new Error(
|
|
18441
|
-
"Environment-scoped effect publication was removed. Use granular.
|
|
18451
|
+
"Environment-scoped effect publication was removed. Use granular.ontology(environment.sandboxId).effects.register(effect)."
|
|
18442
18452
|
);
|
|
18443
18453
|
}
|
|
18444
18454
|
async publishEffects(effects2) {
|
|
18445
18455
|
throw new Error(
|
|
18446
|
-
"Environment-scoped effect publication was removed. Use granular.
|
|
18456
|
+
"Environment-scoped effect publication was removed. Use granular.ontology(environment.sandboxId).effects.registerMany(effects)."
|
|
18447
18457
|
);
|
|
18448
18458
|
}
|
|
18449
18459
|
async unpublishEffect(name) {
|
|
18450
18460
|
throw new Error(
|
|
18451
|
-
"Environment-scoped effect publication was removed. Use granular.
|
|
18461
|
+
"Environment-scoped effect publication was removed. Use granular.ontology(environment.sandboxId).effects.unregister(effectName)."
|
|
18452
18462
|
);
|
|
18453
18463
|
}
|
|
18454
18464
|
async unpublishAllEffects() {
|
|
18455
18465
|
throw new Error(
|
|
18456
|
-
"Environment-scoped effect publication was removed. Use granular.
|
|
18466
|
+
"Environment-scoped effect publication was removed. Use granular.ontology(environment.sandboxId).effects.clear()."
|
|
18457
18467
|
);
|
|
18458
18468
|
}
|
|
18459
18469
|
/**
|
|
@@ -19634,6 +19644,22 @@ function normalizeHeapSnapshot(raw) {
|
|
|
19634
19644
|
updatedAt: typeof heap.updatedAt === "number" ? heap.updatedAt : Date.now()
|
|
19635
19645
|
};
|
|
19636
19646
|
}
|
|
19647
|
+
function deriveRuntimeBaseUrl(apiEndpoint) {
|
|
19648
|
+
try {
|
|
19649
|
+
const endpoint = new URL(apiEndpoint);
|
|
19650
|
+
const graphqlSuffix = "/orchestrator/graphql";
|
|
19651
|
+
if (endpoint.pathname.endsWith(graphqlSuffix)) {
|
|
19652
|
+
endpoint.pathname = endpoint.pathname.slice(0, -graphqlSuffix.length);
|
|
19653
|
+
} else if (endpoint.pathname.endsWith("/graphql")) {
|
|
19654
|
+
endpoint.pathname = endpoint.pathname.slice(0, -"/graphql".length);
|
|
19655
|
+
}
|
|
19656
|
+
endpoint.search = "";
|
|
19657
|
+
endpoint.hash = "";
|
|
19658
|
+
return endpoint.toString().replace(/\/$/, "");
|
|
19659
|
+
} catch {
|
|
19660
|
+
return apiEndpoint.replace(/\/orchestrator\/graphql$/, "").replace(/\/$/, "");
|
|
19661
|
+
}
|
|
19662
|
+
}
|
|
19637
19663
|
function normalizeSubject(subject) {
|
|
19638
19664
|
const granularId = subject.granularId || subject.subjectId;
|
|
19639
19665
|
const userId = subject.userId || subject.identityId || granularId;
|
|
@@ -19673,12 +19699,13 @@ function normalizeEnvironmentData(environment) {
|
|
|
19673
19699
|
tracking: environment.tracking || buildPolicy
|
|
19674
19700
|
};
|
|
19675
19701
|
}
|
|
19676
|
-
var Environment = class
|
|
19702
|
+
var Environment = class {
|
|
19703
|
+
granular;
|
|
19677
19704
|
envData;
|
|
19678
19705
|
_apiKey;
|
|
19679
19706
|
_apiEndpoint;
|
|
19680
|
-
constructor(
|
|
19681
|
-
|
|
19707
|
+
constructor(granular, envData, apiKey, apiEndpoint) {
|
|
19708
|
+
this.granular = granular;
|
|
19682
19709
|
this.envData = envData;
|
|
19683
19710
|
this._apiKey = apiKey;
|
|
19684
19711
|
this._apiEndpoint = apiEndpoint;
|
|
@@ -19719,35 +19746,126 @@ var Environment = class extends Session {
|
|
|
19719
19746
|
get permissionProfileId() {
|
|
19720
19747
|
return this.envData.permissionProfileId;
|
|
19721
19748
|
}
|
|
19749
|
+
/** The current build policy backing this environment */
|
|
19750
|
+
get buildPolicy() {
|
|
19751
|
+
return this.envData.buildPolicy;
|
|
19752
|
+
}
|
|
19753
|
+
/** The current update state relative to the followed tag */
|
|
19754
|
+
get updateState() {
|
|
19755
|
+
return this.envData.updateState;
|
|
19756
|
+
}
|
|
19757
|
+
/** Convenience flag for whether this environment trails the current tag target */
|
|
19758
|
+
get isOutdated() {
|
|
19759
|
+
return this.envData.updateState === "update_available";
|
|
19760
|
+
}
|
|
19761
|
+
/** The followed tag name when this environment is tag-tracked */
|
|
19762
|
+
get tag() {
|
|
19763
|
+
return this.envData.tag?.name || this.envData.buildPolicy.tagName || null;
|
|
19764
|
+
}
|
|
19722
19765
|
/** The GraphQL API endpoint URL */
|
|
19723
19766
|
get apiEndpoint() {
|
|
19724
19767
|
return this._apiEndpoint;
|
|
19725
19768
|
}
|
|
19769
|
+
/** Internal auth token used for control-plane and runtime fallback requests */
|
|
19770
|
+
get authToken() {
|
|
19771
|
+
return this._apiKey;
|
|
19772
|
+
}
|
|
19773
|
+
/** Base runtime URL derived from the GraphQL endpoint */
|
|
19774
|
+
get runtimeBaseUrl() {
|
|
19775
|
+
return this.getRuntimeBaseUrl();
|
|
19776
|
+
}
|
|
19777
|
+
get sessions() {
|
|
19778
|
+
return {
|
|
19779
|
+
list: async (options) => this.listSessions(options?.status || "active"),
|
|
19780
|
+
create: async (options) => this.createSession(options),
|
|
19781
|
+
connect: async (sessionId, options) => this.connectSession(sessionId, options),
|
|
19782
|
+
reopen: async (sessionId, options) => this.reopenSession(sessionId, options),
|
|
19783
|
+
close: async (sessionId, session2) => this.closeSession(sessionId, session2)
|
|
19784
|
+
};
|
|
19785
|
+
}
|
|
19786
|
+
get data() {
|
|
19787
|
+
return {
|
|
19788
|
+
record: async (record) => this.recordObject(record),
|
|
19789
|
+
recordMany: async (records, options) => this.recordObjects(records, options),
|
|
19790
|
+
import: async (records, options) => this.enqueueRecordImport(records, options),
|
|
19791
|
+
listImports: async (status) => this.listRecordImports(status),
|
|
19792
|
+
getImport: async (importId) => this.getRecordImport(importId),
|
|
19793
|
+
getImportSummary: async () => this.getRecordImportSummary(),
|
|
19794
|
+
cancelImport: async (importId) => this.cancelRecordImport(importId),
|
|
19795
|
+
getAwaitingCount: async () => this.getAwaitingRecordCount()
|
|
19796
|
+
};
|
|
19797
|
+
}
|
|
19798
|
+
get feedback() {
|
|
19799
|
+
return {
|
|
19800
|
+
list: async () => this.listFeedback()
|
|
19801
|
+
};
|
|
19802
|
+
}
|
|
19726
19803
|
/**
|
|
19727
|
-
*
|
|
19728
|
-
*
|
|
19729
|
-
*
|
|
19730
|
-
*
|
|
19804
|
+
* Sessionless environments do not own a live transport, so disconnecting the
|
|
19805
|
+
* environment handle itself is a no-op. This keeps the public surface
|
|
19806
|
+
* symmetric with `EnvironmentSession.disconnect()` and lets callers always
|
|
19807
|
+
* clean up safely without tracking whether they currently hold an environment
|
|
19808
|
+
* or a session.
|
|
19731
19809
|
*/
|
|
19732
|
-
|
|
19733
|
-
const doc = this.document;
|
|
19734
|
-
return normalizeHeapSnapshot(doc?.heap);
|
|
19810
|
+
async disconnect() {
|
|
19735
19811
|
}
|
|
19736
|
-
|
|
19737
|
-
|
|
19738
|
-
const
|
|
19739
|
-
|
|
19740
|
-
|
|
19741
|
-
|
|
19742
|
-
|
|
19743
|
-
|
|
19744
|
-
|
|
19745
|
-
endpoint.search = "";
|
|
19746
|
-
endpoint.hash = "";
|
|
19747
|
-
return endpoint.toString().replace(/\/$/, "");
|
|
19748
|
-
} catch {
|
|
19749
|
-
return this._apiEndpoint.replace(/\/orchestrator\/graphql$/, "").replace(/\/$/, "");
|
|
19812
|
+
async listSessions(status = "active") {
|
|
19813
|
+
if (status === "all") {
|
|
19814
|
+
const [active, closed] = await Promise.all([
|
|
19815
|
+
this.granular.listOpenSessions({ environmentId: this.environmentId }),
|
|
19816
|
+
this.granular.listClosedSessions({ environmentId: this.environmentId })
|
|
19817
|
+
]);
|
|
19818
|
+
return [...active, ...closed].sort(
|
|
19819
|
+
(left, right) => Date.parse(right.lastSeenAt) - Date.parse(left.lastSeenAt)
|
|
19820
|
+
);
|
|
19750
19821
|
}
|
|
19822
|
+
return status === "closed" ? this.granular.listClosedSessions({ environmentId: this.environmentId }) : this.granular.listOpenSessions({ environmentId: this.environmentId });
|
|
19823
|
+
}
|
|
19824
|
+
async createSession(options) {
|
|
19825
|
+
return this.granular.createSession({
|
|
19826
|
+
environmentId: this.environmentId,
|
|
19827
|
+
clientId: options?.clientId,
|
|
19828
|
+
initialHeap: options?.initialHeap
|
|
19829
|
+
});
|
|
19830
|
+
}
|
|
19831
|
+
async connectSession(sessionId, options) {
|
|
19832
|
+
const session2 = await this.granular["connectSession"]({
|
|
19833
|
+
sessionId,
|
|
19834
|
+
clientId: options?.clientId
|
|
19835
|
+
});
|
|
19836
|
+
if (session2.environmentId !== this.environmentId) {
|
|
19837
|
+
await session2.disconnect().catch(() => {
|
|
19838
|
+
session2.disconnectTransport();
|
|
19839
|
+
});
|
|
19840
|
+
throw new Error(
|
|
19841
|
+
`Session ${sessionId} belongs to environment ${session2.environmentId}, not ${this.environmentId}.`
|
|
19842
|
+
);
|
|
19843
|
+
}
|
|
19844
|
+
return session2;
|
|
19845
|
+
}
|
|
19846
|
+
async reopenSession(sessionId, options) {
|
|
19847
|
+
const session2 = await this.granular.reopenSession(sessionId, {
|
|
19848
|
+
clientId: options?.clientId
|
|
19849
|
+
});
|
|
19850
|
+
if (session2.environmentId !== this.environmentId) {
|
|
19851
|
+
await session2.disconnect().catch(() => {
|
|
19852
|
+
session2.disconnectTransport();
|
|
19853
|
+
});
|
|
19854
|
+
throw new Error(
|
|
19855
|
+
`Session ${sessionId} belongs to environment ${session2.environmentId}, not ${this.environmentId}.`
|
|
19856
|
+
);
|
|
19857
|
+
}
|
|
19858
|
+
return session2;
|
|
19859
|
+
}
|
|
19860
|
+
async closeSession(sessionId, session2) {
|
|
19861
|
+
await this.granular.closeSession(sessionId, session2);
|
|
19862
|
+
}
|
|
19863
|
+
async listFeedback() {
|
|
19864
|
+
const response = await this.controlPlaneRequest(`/control/environments/${this.environmentId}/feedback`);
|
|
19865
|
+
return Array.isArray(response.items) ? response.items : [];
|
|
19866
|
+
}
|
|
19867
|
+
getRuntimeBaseUrl() {
|
|
19868
|
+
return deriveRuntimeBaseUrl(this._apiEndpoint);
|
|
19751
19869
|
}
|
|
19752
19870
|
async controlPlaneRequest(path6, options = {}) {
|
|
19753
19871
|
const runtimeBase = this.getRuntimeBaseUrl();
|
|
@@ -19768,95 +19886,6 @@ var Environment = class extends Session {
|
|
|
19768
19886
|
}
|
|
19769
19887
|
return response.json();
|
|
19770
19888
|
}
|
|
19771
|
-
/**
|
|
19772
|
-
* Close the session and disconnect from the sandbox.
|
|
19773
|
-
*
|
|
19774
|
-
* Sends `client.goodbye` over WebSocket first, then issues an HTTP fallback
|
|
19775
|
-
* to the runtime goodbye endpoint if no definitive WS-side runtime notify
|
|
19776
|
-
* acknowledgement was observed.
|
|
19777
|
-
*/
|
|
19778
|
-
async disconnect() {
|
|
19779
|
-
let wsNotifiedRuntime = false;
|
|
19780
|
-
try {
|
|
19781
|
-
const goodbye = await this.rpc(
|
|
19782
|
-
"client.goodbye",
|
|
19783
|
-
{
|
|
19784
|
-
timestamp: Date.now()
|
|
19785
|
-
}
|
|
19786
|
-
);
|
|
19787
|
-
wsNotifiedRuntime = Boolean(goodbye?.ok && goodbye?.via);
|
|
19788
|
-
} catch {
|
|
19789
|
-
wsNotifiedRuntime = false;
|
|
19790
|
-
}
|
|
19791
|
-
if (!wsNotifiedRuntime) {
|
|
19792
|
-
try {
|
|
19793
|
-
const runtimeBase = this.getRuntimeBaseUrl();
|
|
19794
|
-
await fetch(
|
|
19795
|
-
`${runtimeBase}/orchestrator/runtime/environments/${this.environmentId}/session-goodbye`,
|
|
19796
|
-
{
|
|
19797
|
-
method: "POST",
|
|
19798
|
-
headers: {
|
|
19799
|
-
"Content-Type": "application/json",
|
|
19800
|
-
Authorization: `Bearer ${this._apiKey}`,
|
|
19801
|
-
Connection: "close"
|
|
19802
|
-
},
|
|
19803
|
-
body: JSON.stringify({
|
|
19804
|
-
reason: "sdk_disconnect_http_fallback",
|
|
19805
|
-
sessionId: this.client.currentSessionId
|
|
19806
|
-
})
|
|
19807
|
-
}
|
|
19808
|
-
);
|
|
19809
|
-
} catch {
|
|
19810
|
-
}
|
|
19811
|
-
}
|
|
19812
|
-
this.client.disconnect();
|
|
19813
|
-
}
|
|
19814
|
-
/**
|
|
19815
|
-
* Close only the socket transport without sending `client.goodbye`.
|
|
19816
|
-
*
|
|
19817
|
-
* Use this when the caller intends to immediately reattach to the same
|
|
19818
|
-
* session after an unexpected disconnect.
|
|
19819
|
-
*/
|
|
19820
|
-
disconnectTransport() {
|
|
19821
|
-
this.client.disconnect();
|
|
19822
|
-
}
|
|
19823
|
-
// ==================== GRAPH CONTAINER READINESS ====================
|
|
19824
|
-
/** The last known graph container status, updated by checkReadiness() or on heartbeat */
|
|
19825
|
-
graphContainerStatus = null;
|
|
19826
|
-
/**
|
|
19827
|
-
* Check if the graph container is ready and warm.
|
|
19828
|
-
*
|
|
19829
|
-
* Sends a lightweight heartbeat RPC to the Session DO which internally
|
|
19830
|
-
* pings the FalkorDB container. The response includes `graphContainerStatus`,
|
|
19831
|
-
* which is stored locally and emitted as a `readiness` event.
|
|
19832
|
-
*
|
|
19833
|
-
* Use this method to proactively warm the graph container before any
|
|
19834
|
-
* GraphQL query that requires it, or to poll the container's state in
|
|
19835
|
-
* the background.
|
|
19836
|
-
*
|
|
19837
|
-
* @returns The current graph container status object
|
|
19838
|
-
*
|
|
19839
|
-
* @example
|
|
19840
|
-
* ```typescript
|
|
19841
|
-
* const status = await env.checkReadiness();
|
|
19842
|
-
* console.log(status.status); // 'hot' | 'warming' | 'unknown'
|
|
19843
|
-
*
|
|
19844
|
-
* // Or listen for live updates
|
|
19845
|
-
* env.on('readiness', (status) => {
|
|
19846
|
-
* console.log('Graph is now:', status.status);
|
|
19847
|
-
* });
|
|
19848
|
-
* ```
|
|
19849
|
-
*/
|
|
19850
|
-
async checkReadiness() {
|
|
19851
|
-
const result = await this.client.call("client.heartbeat", {});
|
|
19852
|
-
const containerStatus = result?.graphContainerStatus ?? {
|
|
19853
|
-
lastKeepAliveAt: Date.now(),
|
|
19854
|
-
status: "unknown"
|
|
19855
|
-
};
|
|
19856
|
-
this.graphContainerStatus = containerStatus;
|
|
19857
|
-
this.emit("readiness", containerStatus);
|
|
19858
|
-
return containerStatus;
|
|
19859
|
-
}
|
|
19860
19889
|
// ==================== ID ↔ GRAPH PATH MAPPING ====================
|
|
19861
19890
|
/**
|
|
19862
19891
|
* Convert a class name + real-world ID into a unique graph path.
|
|
@@ -20717,36 +20746,186 @@ var Environment = class extends Session {
|
|
|
20717
20746
|
}
|
|
20718
20747
|
);
|
|
20719
20748
|
}
|
|
20720
|
-
|
|
20749
|
+
};
|
|
20750
|
+
var EnvironmentSession = class extends Session {
|
|
20751
|
+
environment;
|
|
20752
|
+
/** The last known graph container status, updated by checkReadiness() or on heartbeat */
|
|
20753
|
+
graphContainerStatus = null;
|
|
20754
|
+
constructor(client, environment, clientId) {
|
|
20755
|
+
super(client, clientId);
|
|
20756
|
+
this.environment = environment;
|
|
20757
|
+
}
|
|
20758
|
+
get environmentId() {
|
|
20759
|
+
return this.environment.environmentId;
|
|
20760
|
+
}
|
|
20761
|
+
get sandboxId() {
|
|
20762
|
+
return this.environment.sandboxId;
|
|
20763
|
+
}
|
|
20764
|
+
get ontologyId() {
|
|
20765
|
+
return this.environment.ontologyId;
|
|
20766
|
+
}
|
|
20767
|
+
get subjectId() {
|
|
20768
|
+
return this.environment.subjectId;
|
|
20769
|
+
}
|
|
20770
|
+
get envName() {
|
|
20771
|
+
return this.environment.envName;
|
|
20772
|
+
}
|
|
20773
|
+
get versionId() {
|
|
20774
|
+
return this.environment.versionId;
|
|
20775
|
+
}
|
|
20776
|
+
get granularId() {
|
|
20777
|
+
return this.environment.granularId;
|
|
20778
|
+
}
|
|
20779
|
+
get permissionProfileId() {
|
|
20780
|
+
return this.environment.permissionProfileId;
|
|
20781
|
+
}
|
|
20782
|
+
get apiEndpoint() {
|
|
20783
|
+
return this.environment.apiEndpoint;
|
|
20784
|
+
}
|
|
20785
|
+
get data() {
|
|
20786
|
+
return this.environment.data;
|
|
20787
|
+
}
|
|
20788
|
+
get feedback() {
|
|
20789
|
+
return this.environment.feedback;
|
|
20790
|
+
}
|
|
20721
20791
|
/**
|
|
20722
|
-
*
|
|
20792
|
+
* Return a plain JS snapshot of the synced session heap.
|
|
20723
20793
|
*/
|
|
20724
|
-
|
|
20725
|
-
|
|
20794
|
+
getHeap() {
|
|
20795
|
+
const doc = this.document;
|
|
20796
|
+
return normalizeHeapSnapshot(doc?.heap);
|
|
20797
|
+
}
|
|
20798
|
+
async graphql(query, variables) {
|
|
20799
|
+
return this.environment.graphql(query, variables);
|
|
20800
|
+
}
|
|
20801
|
+
async defineRelationship(options) {
|
|
20802
|
+
return this.environment.defineRelationship(options);
|
|
20803
|
+
}
|
|
20804
|
+
async getRelationships(modelPath) {
|
|
20805
|
+
return this.environment.getRelationships(modelPath);
|
|
20806
|
+
}
|
|
20807
|
+
async attach(modelPath, submodelPath, targetPath) {
|
|
20808
|
+
return this.environment.attach(modelPath, submodelPath, targetPath);
|
|
20809
|
+
}
|
|
20810
|
+
async detach(modelPath, submodelPath, targetPath) {
|
|
20811
|
+
return this.environment.detach(modelPath, submodelPath, targetPath);
|
|
20812
|
+
}
|
|
20813
|
+
async listRelated(modelPath, submodelPath) {
|
|
20814
|
+
return this.environment.listRelated(modelPath, submodelPath);
|
|
20815
|
+
}
|
|
20816
|
+
async applyManifest(manifest) {
|
|
20817
|
+
return this.environment.applyManifest(manifest);
|
|
20818
|
+
}
|
|
20819
|
+
async recordObject(options) {
|
|
20820
|
+
return this.environment.recordObject(options);
|
|
20821
|
+
}
|
|
20822
|
+
async recordObjects(records, options) {
|
|
20823
|
+
return this.environment.recordObjects(records, options);
|
|
20824
|
+
}
|
|
20825
|
+
async enqueueRecordImport(records, options = {}) {
|
|
20826
|
+
return this.environment.enqueueRecordImport(records, options);
|
|
20827
|
+
}
|
|
20828
|
+
async listRecordImports(status) {
|
|
20829
|
+
return this.environment.listRecordImports(status);
|
|
20830
|
+
}
|
|
20831
|
+
async getRecordImportSummary() {
|
|
20832
|
+
return this.environment.getRecordImportSummary();
|
|
20833
|
+
}
|
|
20834
|
+
async getAwaitingRecordCount() {
|
|
20835
|
+
return this.environment.getAwaitingRecordCount();
|
|
20836
|
+
}
|
|
20837
|
+
async getRecordImport(importId) {
|
|
20838
|
+
return this.environment.getRecordImport(importId);
|
|
20839
|
+
}
|
|
20840
|
+
async cancelRecordImport(importId) {
|
|
20841
|
+
return this.environment.cancelRecordImport(importId);
|
|
20842
|
+
}
|
|
20843
|
+
async listFeedback() {
|
|
20844
|
+
return this.environment.listFeedback();
|
|
20726
20845
|
}
|
|
20727
20846
|
/**
|
|
20728
|
-
*
|
|
20847
|
+
* Close the session and disconnect from the sandbox.
|
|
20848
|
+
*
|
|
20849
|
+
* Sends `client.goodbye` over WebSocket first, then issues an HTTP fallback
|
|
20850
|
+
* to the runtime goodbye endpoint if no definitive WS-side runtime notify
|
|
20851
|
+
* acknowledgement was observed.
|
|
20729
20852
|
*/
|
|
20730
|
-
async
|
|
20731
|
-
|
|
20853
|
+
async disconnect() {
|
|
20854
|
+
let wsNotifiedRuntime = false;
|
|
20855
|
+
try {
|
|
20856
|
+
const goodbye = await this.rpc(
|
|
20857
|
+
"client.goodbye",
|
|
20858
|
+
{
|
|
20859
|
+
timestamp: Date.now()
|
|
20860
|
+
}
|
|
20861
|
+
);
|
|
20862
|
+
wsNotifiedRuntime = Boolean(goodbye?.ok && goodbye?.via);
|
|
20863
|
+
} catch {
|
|
20864
|
+
wsNotifiedRuntime = false;
|
|
20865
|
+
}
|
|
20866
|
+
if (!wsNotifiedRuntime) {
|
|
20867
|
+
try {
|
|
20868
|
+
await fetch(
|
|
20869
|
+
`${this.environment.runtimeBaseUrl}/orchestrator/runtime/environments/${this.environmentId}/session-goodbye`,
|
|
20870
|
+
{
|
|
20871
|
+
method: "POST",
|
|
20872
|
+
headers: {
|
|
20873
|
+
"Content-Type": "application/json",
|
|
20874
|
+
Authorization: `Bearer ${this.environment.authToken}`,
|
|
20875
|
+
Connection: "close"
|
|
20876
|
+
},
|
|
20877
|
+
body: JSON.stringify({
|
|
20878
|
+
reason: "sdk_disconnect_http_fallback",
|
|
20879
|
+
sessionId: this.client.currentSessionId
|
|
20880
|
+
})
|
|
20881
|
+
}
|
|
20882
|
+
);
|
|
20883
|
+
} catch {
|
|
20884
|
+
}
|
|
20885
|
+
}
|
|
20886
|
+
this.client.disconnect();
|
|
20732
20887
|
}
|
|
20733
20888
|
/**
|
|
20734
|
-
*
|
|
20889
|
+
* Close only the socket transport without sending `client.goodbye`.
|
|
20735
20890
|
*/
|
|
20736
|
-
|
|
20737
|
-
|
|
20891
|
+
disconnectTransport() {
|
|
20892
|
+
this.client.disconnect();
|
|
20738
20893
|
}
|
|
20739
20894
|
/**
|
|
20740
|
-
*
|
|
20895
|
+
* Backwards-compatible alias for `disconnect()`.
|
|
20741
20896
|
*/
|
|
20742
|
-
async
|
|
20743
|
-
|
|
20897
|
+
async close() {
|
|
20898
|
+
await this.disconnect();
|
|
20744
20899
|
}
|
|
20745
20900
|
/**
|
|
20746
|
-
*
|
|
20901
|
+
* Check if the graph container is ready and warm.
|
|
20747
20902
|
*/
|
|
20748
|
-
async
|
|
20749
|
-
|
|
20903
|
+
async checkReadiness() {
|
|
20904
|
+
const result = await this.client.call("client.heartbeat", {});
|
|
20905
|
+
const containerStatus = result?.graphContainerStatus ?? {
|
|
20906
|
+
lastKeepAliveAt: Date.now(),
|
|
20907
|
+
status: "unknown"
|
|
20908
|
+
};
|
|
20909
|
+
this.graphContainerStatus = containerStatus;
|
|
20910
|
+
this.emit("readiness", containerStatus);
|
|
20911
|
+
return containerStatus;
|
|
20912
|
+
}
|
|
20913
|
+
};
|
|
20914
|
+
var OntologyHandle = class {
|
|
20915
|
+
granular;
|
|
20916
|
+
ontologyNameOrId;
|
|
20917
|
+
constructor(granular, ontologyNameOrId) {
|
|
20918
|
+
this.granular = granular;
|
|
20919
|
+
this.ontologyNameOrId = ontologyNameOrId;
|
|
20920
|
+
}
|
|
20921
|
+
get effects() {
|
|
20922
|
+
return {
|
|
20923
|
+
register: async (effect) => this.granular.registerEffect(this.ontologyNameOrId, effect),
|
|
20924
|
+
registerMany: async (effects2) => this.granular.registerEffects(this.ontologyNameOrId, effects2),
|
|
20925
|
+
unregister: async (name) => this.granular.unregisterEffect(this.ontologyNameOrId, name),
|
|
20926
|
+
clear: async () => this.granular.unregisterAllEffects(this.ontologyNameOrId),
|
|
20927
|
+
disconnect: async () => this.granular.disconnectEffects(this.ontologyNameOrId)
|
|
20928
|
+
};
|
|
20750
20929
|
}
|
|
20751
20930
|
};
|
|
20752
20931
|
var Granular = class _Granular {
|
|
@@ -20783,6 +20962,12 @@ var Granular = class _Granular {
|
|
|
20783
20962
|
this.onReconnectError = options.onReconnectError;
|
|
20784
20963
|
this.httpUrl = this.apiUrl.replace(/^wss:\/\//, "https://").replace(/^ws:\/\//, "http://").replace(/\/ws$/, "");
|
|
20785
20964
|
}
|
|
20965
|
+
/**
|
|
20966
|
+
* Return an ontology-scoped handle for effects and other ontology-level APIs.
|
|
20967
|
+
*/
|
|
20968
|
+
ontology(ontologyNameOrId) {
|
|
20969
|
+
return new OntologyHandle(this, ontologyNameOrId);
|
|
20970
|
+
}
|
|
20786
20971
|
/**
|
|
20787
20972
|
* Records/upserts a user and prepares them for sandbox connections
|
|
20788
20973
|
*
|
|
@@ -20819,7 +21004,23 @@ var Granular = class _Granular {
|
|
|
20819
21004
|
permissions: options.permissions || []
|
|
20820
21005
|
});
|
|
20821
21006
|
}
|
|
21007
|
+
/**
|
|
21008
|
+
* Alias for `recordUser()` with user-facing naming that matches upsert semantics.
|
|
21009
|
+
*/
|
|
21010
|
+
async upsertUser(options) {
|
|
21011
|
+
return this.recordUser(options);
|
|
21012
|
+
}
|
|
20822
21013
|
async resolveConnectUser(options) {
|
|
21014
|
+
const providedIdentityCount = [
|
|
21015
|
+
Boolean(options.user),
|
|
21016
|
+
Boolean(options.userId),
|
|
21017
|
+
Boolean(options.granularId)
|
|
21018
|
+
].filter(Boolean).length;
|
|
21019
|
+
if (providedIdentityCount !== 1) {
|
|
21020
|
+
throw new Error(
|
|
21021
|
+
"openEnvironment() requires exactly one of userId, granularId, or a user object returned by recordUser()."
|
|
21022
|
+
);
|
|
21023
|
+
}
|
|
20823
21024
|
if (options.user) {
|
|
20824
21025
|
const user = normalizeUser(options.user);
|
|
20825
21026
|
return {
|
|
@@ -20856,56 +21057,85 @@ var Granular = class _Granular {
|
|
|
20856
21057
|
};
|
|
20857
21058
|
}
|
|
20858
21059
|
throw new Error(
|
|
20859
|
-
"
|
|
21060
|
+
"openEnvironment() requires either userId, granularId, or a user object returned by recordUser()."
|
|
20860
21061
|
);
|
|
20861
21062
|
}
|
|
20862
21063
|
/**
|
|
20863
|
-
*
|
|
20864
|
-
*
|
|
20865
|
-
* Effects are registered at the sandbox level via `granular.registerEffect()`
|
|
20866
|
-
* or `granular.registerEffects()`. Sessions pick up live availability from
|
|
20867
|
-
* the sandbox registry automatically.
|
|
20868
|
-
*
|
|
20869
|
-
* @param options - Connection options
|
|
20870
|
-
* @returns An active environment session
|
|
21064
|
+
* Open or resolve an ontology environment for one user without opening a session.
|
|
20871
21065
|
*
|
|
20872
21066
|
* @example
|
|
20873
21067
|
* ```typescript
|
|
20874
|
-
* const environment = await granular.
|
|
21068
|
+
* const environment = await granular.openEnvironment({
|
|
20875
21069
|
* ontology: 'my-ontology',
|
|
20876
|
-
*
|
|
21070
|
+
* tag: 'dev',
|
|
20877
21071
|
* userId: 'user_123',
|
|
20878
21072
|
* permissions: ['agent'],
|
|
20879
21073
|
* });
|
|
20880
21074
|
*
|
|
20881
|
-
* await
|
|
20882
|
-
*
|
|
20883
|
-
*
|
|
20884
|
-
*
|
|
20885
|
-
* handler: async () => 'Hello!',
|
|
21075
|
+
* await environment.data.record({
|
|
21076
|
+
* className: 'customer',
|
|
21077
|
+
* id: 'acme',
|
|
21078
|
+
* fields: { name: 'Acme' },
|
|
20886
21079
|
* });
|
|
20887
21080
|
*
|
|
20888
|
-
*
|
|
20889
|
-
* const job = await
|
|
20890
|
-
*
|
|
20891
|
-
* return await tools.greet({});
|
|
20892
|
-
* `);
|
|
20893
|
-
*
|
|
20894
|
-
* console.log(await job.result); // 'Hello!'
|
|
21081
|
+
* const session = await environment.sessions.create();
|
|
21082
|
+
* const job = await session.submitJob(`return "hello";`);
|
|
21083
|
+
* console.log(await job.result);
|
|
20895
21084
|
* ```
|
|
20896
21085
|
*/
|
|
21086
|
+
async openEnvironment(options) {
|
|
21087
|
+
const envData = await this.resolveOpenEnvironmentData(
|
|
21088
|
+
options,
|
|
21089
|
+
"openEnvironment"
|
|
21090
|
+
);
|
|
21091
|
+
return this.bindEnvironmentHandle(envData);
|
|
21092
|
+
}
|
|
21093
|
+
/**
|
|
21094
|
+
* Deprecated compatibility alias for `openEnvironment()`.
|
|
21095
|
+
*
|
|
21096
|
+
* `connect()` no longer opens a runtime session automatically.
|
|
21097
|
+
*/
|
|
20897
21098
|
async connect(options) {
|
|
20898
|
-
|
|
21099
|
+
return this.openEnvironment({
|
|
21100
|
+
...options,
|
|
21101
|
+
tag: this.resolveRequestedTag(options, "connect"),
|
|
21102
|
+
permissions: options.permissions || options.user?.permissions || []
|
|
21103
|
+
});
|
|
21104
|
+
}
|
|
21105
|
+
resolveRequestedTag(options, methodName) {
|
|
21106
|
+
const tag2 = options.tag?.trim() || options.tagName?.trim() || options.environment?.trim();
|
|
21107
|
+
if (!tag2) {
|
|
21108
|
+
throw new Error(`${methodName}() requires \`tag\`.`);
|
|
21109
|
+
}
|
|
21110
|
+
return tag2;
|
|
21111
|
+
}
|
|
21112
|
+
buildManagedEnvironmentName(tag2, versionId) {
|
|
21113
|
+
return `__sdk__${tag2}__${versionId}`;
|
|
21114
|
+
}
|
|
21115
|
+
matchesTagTrackedEnvironment(environment, tagName, tagId) {
|
|
21116
|
+
const environmentTagName = environment.tag?.name || environment.buildPolicy.tagName || null;
|
|
21117
|
+
return environment.tagId === tagId || environmentTagName === tagName || environment.environment === tagName || environment.envName === tagName || environment.environment === this.buildManagedEnvironmentName(tagName, environment.versionId) || environment.envName === this.buildManagedEnvironmentName(tagName, environment.versionId);
|
|
21118
|
+
}
|
|
21119
|
+
sortEnvironmentsByRecency(environments) {
|
|
21120
|
+
return [...environments].sort(
|
|
21121
|
+
(left, right) => right.updatedAt - left.updatedAt
|
|
21122
|
+
);
|
|
21123
|
+
}
|
|
21124
|
+
async resolveOpenEnvironmentData(options, methodName) {
|
|
20899
21125
|
const ontology = options.ontology;
|
|
20900
21126
|
if (!ontology) {
|
|
20901
|
-
throw new Error(
|
|
21127
|
+
throw new Error(`${methodName}() requires \`ontology\`.`);
|
|
20902
21128
|
}
|
|
20903
|
-
const
|
|
20904
|
-
if (!
|
|
20905
|
-
throw new Error(
|
|
21129
|
+
const tagName = options.tag?.trim();
|
|
21130
|
+
if (!tagName) {
|
|
21131
|
+
throw new Error(`${methodName}() requires \`tag\`.`);
|
|
20906
21132
|
}
|
|
20907
|
-
const tagName = options.tagName?.trim() || void 0;
|
|
20908
21133
|
const user = await this.resolveConnectUser(options);
|
|
21134
|
+
if (!Array.isArray(user.permissions) || user.permissions.length === 0) {
|
|
21135
|
+
throw new Error(
|
|
21136
|
+
`${methodName}() requires at least one permission so the SDK can ensure assignments for new users.`
|
|
21137
|
+
);
|
|
21138
|
+
}
|
|
20909
21139
|
const sandbox = await this.findOrCreateSandbox(ontology);
|
|
20910
21140
|
for (const profileName of user.permissions) {
|
|
20911
21141
|
const profileId = await this.ensurePermissionProfile(
|
|
@@ -20918,22 +21148,49 @@ var Granular = class _Granular {
|
|
|
20918
21148
|
profileId
|
|
20919
21149
|
);
|
|
20920
21150
|
}
|
|
20921
|
-
const
|
|
21151
|
+
const tags = await this.request(
|
|
21152
|
+
`/control/sandboxes/${sandbox.sandboxId}/tags`
|
|
21153
|
+
);
|
|
21154
|
+
const tag2 = (tags.items || []).find(
|
|
21155
|
+
(candidate) => Boolean(candidate?.name === tagName)
|
|
21156
|
+
);
|
|
21157
|
+
if (!tag2) {
|
|
21158
|
+
throw new Error(
|
|
21159
|
+
`Tag "${tagName}" was not found for ontology ${sandbox.sandboxId}.`
|
|
21160
|
+
);
|
|
21161
|
+
}
|
|
21162
|
+
const targetVersionId = tag2.targetVersionId || tag2.targetBuildId;
|
|
21163
|
+
if (!targetVersionId) {
|
|
21164
|
+
throw new Error(
|
|
21165
|
+
`Tag "${tagName}" does not currently point to a build/version.`
|
|
21166
|
+
);
|
|
21167
|
+
}
|
|
21168
|
+
const allEnvironments = await this.environments.list(sandbox.sandboxId);
|
|
21169
|
+
const userEnvironments = allEnvironments.filter(
|
|
21170
|
+
(environment) => environment.subjectId === user.granularId
|
|
21171
|
+
);
|
|
21172
|
+
const currentMatches = this.sortEnvironmentsByRecency(
|
|
21173
|
+
userEnvironments.filter(
|
|
21174
|
+
(environment) => this.matchesTagTrackedEnvironment(environment, tagName, tag2.tagId) && environment.versionId === targetVersionId
|
|
21175
|
+
)
|
|
21176
|
+
);
|
|
21177
|
+
if (currentMatches.length > 0) {
|
|
21178
|
+
return currentMatches[0];
|
|
21179
|
+
}
|
|
21180
|
+
const outdatedMatches = this.sortEnvironmentsByRecency(
|
|
21181
|
+
userEnvironments.filter(
|
|
21182
|
+
(environment) => this.matchesTagTrackedEnvironment(environment, tagName, tag2.tagId)
|
|
21183
|
+
)
|
|
21184
|
+
);
|
|
21185
|
+
if (outdatedMatches.length > 0 && options.createFreshIfOutdated !== true) {
|
|
21186
|
+
return outdatedMatches[0];
|
|
21187
|
+
}
|
|
21188
|
+
return this.environments.create(sandbox.sandboxId, {
|
|
20922
21189
|
subjectId: user.granularId,
|
|
20923
|
-
environment:
|
|
20924
|
-
|
|
21190
|
+
environment: this.buildManagedEnvironmentName(tagName, targetVersionId),
|
|
21191
|
+
tagId: tag2.tagId,
|
|
20925
21192
|
permissionProfileId: null
|
|
20926
21193
|
});
|
|
20927
|
-
await this.activateEnvironment(envData.environmentId);
|
|
20928
|
-
const session2 = await this.request("/ws/sessions", {
|
|
20929
|
-
method: "POST",
|
|
20930
|
-
body: JSON.stringify({
|
|
20931
|
-
environmentId: envData.environmentId,
|
|
20932
|
-
clientId,
|
|
20933
|
-
initialHeap: options.initialHeap
|
|
20934
|
-
})
|
|
20935
|
-
});
|
|
20936
|
-
return this.bindWebSocketEnvironment(envData, clientId, session2);
|
|
20937
21194
|
}
|
|
20938
21195
|
/**
|
|
20939
21196
|
* List active (open) sessions for an environment — each session is one agent conversation thread.
|
|
@@ -20996,6 +21253,7 @@ var Granular = class _Granular {
|
|
|
20996
21253
|
const clientId = options.clientId || `client_${Date.now()}`;
|
|
20997
21254
|
await this.activateEnvironment(options.environmentId);
|
|
20998
21255
|
const envData = await this.environments.get(options.environmentId);
|
|
21256
|
+
const environment = this.bindEnvironmentHandle(envData);
|
|
20999
21257
|
const session2 = await this.request("/ws/sessions", {
|
|
21000
21258
|
method: "POST",
|
|
21001
21259
|
body: JSON.stringify({
|
|
@@ -21004,7 +21262,7 @@ var Granular = class _Granular {
|
|
|
21004
21262
|
initialHeap: options.initialHeap
|
|
21005
21263
|
})
|
|
21006
21264
|
});
|
|
21007
|
-
return this.
|
|
21265
|
+
return this.bindWebSocketEnvironmentSession(environment, clientId, session2);
|
|
21008
21266
|
}
|
|
21009
21267
|
/**
|
|
21010
21268
|
* Connect to an existing open session (same conversation thread) using a freshly minted WebSocket token.
|
|
@@ -21016,7 +21274,8 @@ var Granular = class _Granular {
|
|
|
21016
21274
|
body: JSON.stringify({})
|
|
21017
21275
|
});
|
|
21018
21276
|
const envData = await this.environments.get(minted.environmentId);
|
|
21019
|
-
|
|
21277
|
+
const environment = this.bindEnvironmentHandle(envData);
|
|
21278
|
+
return this.bindWebSocketEnvironmentSession(environment, clientId, minted);
|
|
21020
21279
|
}
|
|
21021
21280
|
/**
|
|
21022
21281
|
* Mark a session closed in the control plane. If `environment` is the connected handle for that
|
|
@@ -21048,7 +21307,11 @@ var Granular = class _Granular {
|
|
|
21048
21307
|
});
|
|
21049
21308
|
return this.connectSession({ sessionId, clientId: options?.clientId });
|
|
21050
21309
|
}
|
|
21051
|
-
|
|
21310
|
+
bindEnvironmentHandle(envData) {
|
|
21311
|
+
const graphqlEndpoint = `${this.httpUrl}/orchestrator/graphql`;
|
|
21312
|
+
return new Environment(this, envData, this.apiKey, graphqlEndpoint);
|
|
21313
|
+
}
|
|
21314
|
+
async bindWebSocketEnvironmentSession(environment, clientId, session2) {
|
|
21052
21315
|
const client = new WSClient({
|
|
21053
21316
|
url: session2.wsUrl,
|
|
21054
21317
|
sessionId: session2.sessionId,
|
|
@@ -21059,16 +21322,13 @@ var Granular = class _Granular {
|
|
|
21059
21322
|
onReconnectError: this.onReconnectError
|
|
21060
21323
|
});
|
|
21061
21324
|
await client.connect();
|
|
21062
|
-
const
|
|
21063
|
-
const environment = new Environment(
|
|
21325
|
+
const environmentSession = new EnvironmentSession(
|
|
21064
21326
|
client,
|
|
21065
|
-
|
|
21066
|
-
clientId
|
|
21067
|
-
this.apiKey,
|
|
21068
|
-
graphqlEndpoint
|
|
21327
|
+
environment,
|
|
21328
|
+
clientId
|
|
21069
21329
|
);
|
|
21070
|
-
await
|
|
21071
|
-
return
|
|
21330
|
+
await environmentSession.hello();
|
|
21331
|
+
return environmentSession;
|
|
21072
21332
|
}
|
|
21073
21333
|
async activateEnvironment(environmentId) {
|
|
21074
21334
|
await this.request(`/orchestrator/runtime/environments/${environmentId}/activate`, {
|
|
@@ -21786,7 +22046,7 @@ async function resolveEnvironmentData(granular, options) {
|
|
|
21786
22046
|
const ontologyId = await resolveOntologyId(granular, options.ontology);
|
|
21787
22047
|
const environmentName = options.environment ?? "dev";
|
|
21788
22048
|
const environments = await granular.environments.list(ontologyId);
|
|
21789
|
-
const existing = environments.find((
|
|
22049
|
+
const existing = environments.find((environment2) => matchesEnvironmentName(environment2, environmentName));
|
|
21790
22050
|
if (existing) {
|
|
21791
22051
|
return existing;
|
|
21792
22052
|
}
|
|
@@ -21795,21 +22055,13 @@ async function resolveEnvironmentData(granular, options) {
|
|
|
21795
22055
|
`No environment named \`${environmentName}\` found for ontology \`${ontologyId}\`. Run \`granular connect test\` or \`granular session create\` first, or pass \`--environment-id\`.`
|
|
21796
22056
|
);
|
|
21797
22057
|
}
|
|
21798
|
-
const
|
|
22058
|
+
const environment = await granular.openEnvironment({
|
|
21799
22059
|
ontology: ontologyId,
|
|
21800
|
-
|
|
22060
|
+
tag: environmentName,
|
|
21801
22061
|
userId: options.userId ?? "granular-cli",
|
|
21802
22062
|
permissions: options.permissions ?? ["default"]
|
|
21803
22063
|
});
|
|
21804
|
-
|
|
21805
|
-
return await granular.environments.get(connection.environmentId);
|
|
21806
|
-
} finally {
|
|
21807
|
-
try {
|
|
21808
|
-
await connection.disconnect();
|
|
21809
|
-
} catch {
|
|
21810
|
-
connection?.client?.disconnect?.();
|
|
21811
|
-
}
|
|
21812
|
-
}
|
|
22064
|
+
return await granular.environments.get(environment.environmentId);
|
|
21813
22065
|
}
|
|
21814
22066
|
async function listSessionsForEnvironment(granular, environmentId, status) {
|
|
21815
22067
|
if (status === "all") {
|
|
@@ -21826,11 +22078,12 @@ async function listSessionsForEnvironment(granular, environmentId, status) {
|
|
|
21826
22078
|
async function connectRuntime(options) {
|
|
21827
22079
|
if (options.sessionId) {
|
|
21828
22080
|
const { granular: granular2 } = createGranularClient();
|
|
21829
|
-
const
|
|
22081
|
+
const session3 = await granular2["connectSession"]({ sessionId: options.sessionId });
|
|
21830
22082
|
return {
|
|
21831
22083
|
granular: granular2,
|
|
21832
|
-
environment:
|
|
21833
|
-
|
|
22084
|
+
environment: session3.environment,
|
|
22085
|
+
session: session3,
|
|
22086
|
+
ontologyId: session3.ontologyId || session3.sandboxId
|
|
21834
22087
|
};
|
|
21835
22088
|
}
|
|
21836
22089
|
const { granular, config } = createGranularClient();
|
|
@@ -21838,15 +22091,17 @@ async function connectRuntime(options) {
|
|
|
21838
22091
|
if (!ontologyId) {
|
|
21839
22092
|
throw new Error("No ontology configured. Run `granular init` first or pass `--ontology`.");
|
|
21840
22093
|
}
|
|
21841
|
-
const environment = await granular.
|
|
22094
|
+
const environment = await granular.openEnvironment({
|
|
21842
22095
|
ontology: ontologyId,
|
|
21843
|
-
|
|
22096
|
+
tag: options.environment ?? "dev",
|
|
21844
22097
|
userId: options.userId ?? "granular-cli",
|
|
21845
22098
|
permissions: options.permissions ?? ["default"]
|
|
21846
22099
|
});
|
|
22100
|
+
const session2 = await environment.sessions.create();
|
|
21847
22101
|
return {
|
|
21848
22102
|
granular,
|
|
21849
22103
|
environment,
|
|
22104
|
+
session: session2,
|
|
21850
22105
|
ontologyId
|
|
21851
22106
|
};
|
|
21852
22107
|
}
|
|
@@ -21856,9 +22111,9 @@ async function withRuntimeConnection(options, callback) {
|
|
|
21856
22111
|
return await callback(connection);
|
|
21857
22112
|
} finally {
|
|
21858
22113
|
try {
|
|
21859
|
-
await connection.
|
|
22114
|
+
await connection.session.disconnect();
|
|
21860
22115
|
} catch {
|
|
21861
|
-
connection.
|
|
22116
|
+
connection.session.disconnectTransport();
|
|
21862
22117
|
}
|
|
21863
22118
|
}
|
|
21864
22119
|
}
|
|
@@ -21895,14 +22150,14 @@ async function connectTestCommand(options) {
|
|
|
21895
22150
|
userId: options.user,
|
|
21896
22151
|
permissions: normalizePermissions(options.permissions)
|
|
21897
22152
|
},
|
|
21898
|
-
async ({ environment, ontologyId }) => {
|
|
22153
|
+
async ({ environment, session: session2, ontologyId }) => {
|
|
21899
22154
|
const payload = {
|
|
21900
22155
|
ok: true,
|
|
21901
22156
|
ontologyId,
|
|
21902
22157
|
sandboxId: environment.sandboxId,
|
|
21903
22158
|
environmentId: environment.environmentId,
|
|
21904
22159
|
environment: environment.environment,
|
|
21905
|
-
sessionId:
|
|
22160
|
+
sessionId: session2.sessionId,
|
|
21906
22161
|
subjectId: environment.subjectId,
|
|
21907
22162
|
versionId: environment.versionId
|
|
21908
22163
|
};
|
|
@@ -21948,12 +22203,12 @@ async function sessionHeapCommand(options) {
|
|
|
21948
22203
|
permissions: normalizePermissions(options.permissions),
|
|
21949
22204
|
sessionId: options.session
|
|
21950
22205
|
},
|
|
21951
|
-
async ({ environment, ontologyId }) => {
|
|
22206
|
+
async ({ environment, session: session2, ontologyId }) => {
|
|
21952
22207
|
const payload = {
|
|
21953
22208
|
ontologyId,
|
|
21954
|
-
sessionId:
|
|
22209
|
+
sessionId: session2.sessionId,
|
|
21955
22210
|
environmentId: environment.environmentId,
|
|
21956
|
-
heap:
|
|
22211
|
+
heap: session2.getHeap()
|
|
21957
22212
|
};
|
|
21958
22213
|
if (!emitJson) {
|
|
21959
22214
|
step("Session heap");
|
|
@@ -21976,12 +22231,12 @@ async function sessionDocCommand(options) {
|
|
|
21976
22231
|
permissions: normalizePermissions(options.permissions),
|
|
21977
22232
|
sessionId: options.session
|
|
21978
22233
|
},
|
|
21979
|
-
async ({ environment, ontologyId }) => {
|
|
22234
|
+
async ({ environment, session: session2, ontologyId }) => {
|
|
21980
22235
|
const payload = {
|
|
21981
22236
|
ontologyId,
|
|
21982
|
-
sessionId:
|
|
22237
|
+
sessionId: session2.sessionId,
|
|
21983
22238
|
environmentId: environment.environmentId,
|
|
21984
|
-
document: documentToJson(
|
|
22239
|
+
document: documentToJson(session2.document)
|
|
21985
22240
|
};
|
|
21986
22241
|
if (!emitJson) {
|
|
21987
22242
|
step("Session document");
|
|
@@ -22006,18 +22261,18 @@ async function sessionCreateCommand(options) {
|
|
|
22006
22261
|
permissions,
|
|
22007
22262
|
createIfMissing: true
|
|
22008
22263
|
});
|
|
22009
|
-
const
|
|
22264
|
+
const session2 = await granular.createSession({
|
|
22010
22265
|
environmentId: envData.environmentId
|
|
22011
22266
|
});
|
|
22012
22267
|
try {
|
|
22013
22268
|
const payload = {
|
|
22014
22269
|
ok: true,
|
|
22015
22270
|
ontologyId: envData.sandboxId,
|
|
22016
|
-
environmentId:
|
|
22017
|
-
environment: environment.environment,
|
|
22018
|
-
sessionId:
|
|
22019
|
-
subjectId:
|
|
22020
|
-
versionId:
|
|
22271
|
+
environmentId: session2.environmentId,
|
|
22272
|
+
environment: session2.environment.environment,
|
|
22273
|
+
sessionId: session2.sessionId,
|
|
22274
|
+
subjectId: session2.subjectId,
|
|
22275
|
+
versionId: session2.versionId
|
|
22021
22276
|
};
|
|
22022
22277
|
if (emitJson) {
|
|
22023
22278
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -22036,9 +22291,9 @@ async function sessionCreateCommand(options) {
|
|
|
22036
22291
|
console.log();
|
|
22037
22292
|
} finally {
|
|
22038
22293
|
try {
|
|
22039
|
-
await
|
|
22294
|
+
await session2.disconnect();
|
|
22040
22295
|
} catch {
|
|
22041
|
-
|
|
22296
|
+
session2.disconnectTransport();
|
|
22042
22297
|
}
|
|
22043
22298
|
}
|
|
22044
22299
|
}
|
|
@@ -22116,13 +22371,13 @@ async function graphqlCommand(options) {
|
|
|
22116
22371
|
permissions: normalizePermissions(options.permissions),
|
|
22117
22372
|
sessionId: options.session
|
|
22118
22373
|
},
|
|
22119
|
-
async ({ environment, ontologyId }) => {
|
|
22374
|
+
async ({ environment, session: session2, ontologyId }) => {
|
|
22120
22375
|
const result = await environment.graphql(options.query, variables);
|
|
22121
22376
|
const payload = {
|
|
22122
22377
|
ok: !result.errors || result.errors.length === 0,
|
|
22123
22378
|
ontologyId,
|
|
22124
22379
|
environmentId: environment.environmentId,
|
|
22125
|
-
sessionId:
|
|
22380
|
+
sessionId: session2.sessionId,
|
|
22126
22381
|
query: options.query,
|
|
22127
22382
|
variables: variables ?? null,
|
|
22128
22383
|
result
|
|
@@ -22163,12 +22418,12 @@ async function effectsListCommand(options) {
|
|
|
22163
22418
|
permissions: normalizePermissions(options.permissions),
|
|
22164
22419
|
sessionId: options.session
|
|
22165
22420
|
},
|
|
22166
|
-
async ({ environment, ontologyId }) => {
|
|
22167
|
-
const effects2 = sortEffects(
|
|
22421
|
+
async ({ environment, session: session2, ontologyId }) => {
|
|
22422
|
+
const effects2 = sortEffects(session2.getEffects());
|
|
22168
22423
|
const payload = {
|
|
22169
22424
|
ontologyId,
|
|
22170
22425
|
environmentId: environment.environmentId,
|
|
22171
|
-
sessionId:
|
|
22426
|
+
sessionId: session2.sessionId,
|
|
22172
22427
|
items: effects2
|
|
22173
22428
|
};
|
|
22174
22429
|
if (emitJson) {
|
|
@@ -22208,8 +22463,8 @@ async function effectsDiffCommand(options) {
|
|
|
22208
22463
|
permissions: normalizePermissions(options.permissions),
|
|
22209
22464
|
sessionId: options.session
|
|
22210
22465
|
},
|
|
22211
|
-
async ({ environment, ontologyId }) => {
|
|
22212
|
-
const effects2 = sortEffects(
|
|
22466
|
+
async ({ environment, session: session2, ontologyId }) => {
|
|
22467
|
+
const effects2 = sortEffects(session2.getEffects());
|
|
22213
22468
|
const declared = effects2.map((effect) => effect.name);
|
|
22214
22469
|
const liveReady = effects2.filter((effect) => effect.ready).map((effect) => effect.name);
|
|
22215
22470
|
const declaredOnly = effects2.filter((effect) => !effect.ready).map((effect) => effect.name);
|
|
@@ -22217,7 +22472,7 @@ async function effectsDiffCommand(options) {
|
|
|
22217
22472
|
const payload = {
|
|
22218
22473
|
ontologyId,
|
|
22219
22474
|
environmentId: environment.environmentId,
|
|
22220
|
-
sessionId:
|
|
22475
|
+
sessionId: session2.sessionId,
|
|
22221
22476
|
summary: {
|
|
22222
22477
|
declaredCount: declared.length,
|
|
22223
22478
|
liveReadyCount: liveReady.length,
|
|
@@ -22271,8 +22526,8 @@ async function jobRunCommand(options) {
|
|
|
22271
22526
|
permissions: normalizePermissions(options.permissions),
|
|
22272
22527
|
sessionId: options.session
|
|
22273
22528
|
},
|
|
22274
|
-
async ({ environment, ontologyId }) => {
|
|
22275
|
-
const job2 = await
|
|
22529
|
+
async ({ environment, session: session2, ontologyId }) => {
|
|
22530
|
+
const job2 = await session2.submitJob(code);
|
|
22276
22531
|
const stdout = [];
|
|
22277
22532
|
const stderr = [];
|
|
22278
22533
|
job2.on("stdout", (line) => {
|
|
@@ -22296,7 +22551,7 @@ async function jobRunCommand(options) {
|
|
|
22296
22551
|
ok: true,
|
|
22297
22552
|
ontologyId,
|
|
22298
22553
|
environmentId: environment.environmentId,
|
|
22299
|
-
sessionId:
|
|
22554
|
+
sessionId: session2.sessionId,
|
|
22300
22555
|
jobId: job2.id,
|
|
22301
22556
|
status: job2.status,
|
|
22302
22557
|
stdout,
|