@granular-software/sdk 0.4.51 → 0.4.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-evals.d.mts +2 -2
- package/dist/agent-evals.d.ts +2 -2
- package/dist/agent-evals.js +285 -31
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +285 -31
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/cli/index.js +316 -50
- package/dist/{client-djorlOpn.d.mts → client-CfTDojJF.d.mts} +31 -3
- package/dist/{client-NSH-tpNU.d.ts → client-DcRzwuGp.d.ts} +31 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +285 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +285 -31
- package/dist/index.mjs.map +1 -1
- package/dist/{spend-BA-jZwZ0.d.mts → spend-DpRRCrAr.d.mts} +37 -2
- package/dist/{spend-BA-jZwZ0.d.ts → spend-DpRRCrAr.d.ts} +37 -2
- package/dist/spend.d.mts +1 -1
- package/dist/spend.d.ts +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -7898,14 +7898,14 @@ var ApiClient = class {
|
|
|
7898
7898
|
async getVersion(versionId) {
|
|
7899
7899
|
return this.request(`/control/versions/${versionId}`);
|
|
7900
7900
|
}
|
|
7901
|
-
async triggerBuild(sandboxId, manifestId) {
|
|
7901
|
+
async triggerBuild(sandboxId, manifestId, releaseKey) {
|
|
7902
7902
|
return this.request(`/control/sandboxes/${sandboxId}/builds`, {
|
|
7903
7903
|
method: "POST",
|
|
7904
|
-
body: JSON.stringify({ manifestId })
|
|
7904
|
+
body: JSON.stringify({ manifestId, releaseKey })
|
|
7905
7905
|
});
|
|
7906
7906
|
}
|
|
7907
|
-
async createVersion(sandboxId, manifestId) {
|
|
7908
|
-
return this.triggerBuild(sandboxId, manifestId);
|
|
7907
|
+
async createVersion(sandboxId, manifestId, releaseKey) {
|
|
7908
|
+
return this.triggerBuild(sandboxId, manifestId, releaseKey);
|
|
7909
7909
|
}
|
|
7910
7910
|
async listTags(sandboxId) {
|
|
7911
7911
|
const result = await this.request(
|
|
@@ -18947,7 +18947,7 @@ async function deployCommand(options = {}) {
|
|
|
18947
18947
|
]);
|
|
18948
18948
|
const devTag = tags.find((tag2) => tag2.name === "dev");
|
|
18949
18949
|
const prodTag = tags.find((tag2) => tag2.name === "prod");
|
|
18950
|
-
const existingVersion = versions.find(
|
|
18950
|
+
const existingVersion = options.releaseKey ? null : versions.find(
|
|
18951
18951
|
(version2) => version2.manifestDigest === uploadedManifest.digest
|
|
18952
18952
|
) || null;
|
|
18953
18953
|
const existingVersionId = existingVersion?.buildId || null;
|
|
@@ -18965,19 +18965,27 @@ async function deployCommand(options = {}) {
|
|
|
18965
18965
|
} else {
|
|
18966
18966
|
const version2 = await api.createVersion(
|
|
18967
18967
|
config.sandboxId,
|
|
18968
|
-
uploadedManifest.manifestId
|
|
18969
|
-
|
|
18970
|
-
const startTime = Date.now();
|
|
18971
|
-
building.text = ` Running build for version... ${brand.muted(version2.buildId)}`;
|
|
18972
|
-
completed = await api.waitForVersionBuild(version2.buildId, (status) => {
|
|
18973
|
-
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
18974
|
-
building.text = ` Running build for version... ${brand.muted(`${status} (${elapsed}s)`)}`;
|
|
18975
|
-
});
|
|
18976
|
-
totalTime = Math.round((Date.now() - startTime) / 1e3);
|
|
18977
|
-
deployedToDev = true;
|
|
18978
|
-
building.succeed(
|
|
18979
|
-
` Dev now points to ${brand.secondary(completed.buildId)} (${totalTime}s)`
|
|
18968
|
+
uploadedManifest.manifestId,
|
|
18969
|
+
options.releaseKey
|
|
18980
18970
|
);
|
|
18971
|
+
if (version2.createdNewVersion === false && version2.status === "completed") {
|
|
18972
|
+
completed = version2;
|
|
18973
|
+
building.succeed(
|
|
18974
|
+
` Reused ${brand.secondary(version2.buildId)}; the release key is unchanged.`
|
|
18975
|
+
);
|
|
18976
|
+
} else {
|
|
18977
|
+
const startTime = Date.now();
|
|
18978
|
+
building.text = ` Running build for version... ${brand.muted(version2.buildId)}`;
|
|
18979
|
+
completed = await api.waitForVersionBuild(version2.buildId, (status) => {
|
|
18980
|
+
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
18981
|
+
building.text = ` Running build for version... ${brand.muted(`${status} (${elapsed}s)`)}`;
|
|
18982
|
+
});
|
|
18983
|
+
totalTime = Math.round((Date.now() - startTime) / 1e3);
|
|
18984
|
+
deployedToDev = true;
|
|
18985
|
+
building.succeed(
|
|
18986
|
+
` Dev now points to ${brand.secondary(completed.buildId)} (${totalTime}s)`
|
|
18987
|
+
);
|
|
18988
|
+
}
|
|
18981
18989
|
}
|
|
18982
18990
|
if (!completed) {
|
|
18983
18991
|
throw new Error("Could not resolve the current ontology version.");
|
|
@@ -19008,6 +19016,7 @@ async function deployCommand(options = {}) {
|
|
|
19008
19016
|
Release: options.prod ? deployedToDev ? "dev and prod now point to this version" : "prod promoted to the version already on dev" : "dev updated to this version",
|
|
19009
19017
|
"Agent doc": "GRANULAR_SANDBOX.md"
|
|
19010
19018
|
});
|
|
19019
|
+
console.log(`GRANULAR_RELEASE_CHANGED=${deployedToDev ? "true" : "false"}`);
|
|
19011
19020
|
console.log();
|
|
19012
19021
|
if (options.prod) {
|
|
19013
19022
|
info(
|
|
@@ -23201,7 +23210,8 @@ function normalizeEnvironmentSetupSummary(setup) {
|
|
|
23201
23210
|
environmentId: String(setup.environmentId || ""),
|
|
23202
23211
|
sandboxId: String(setup.sandboxId || ""),
|
|
23203
23212
|
subjectId: String(setup.subjectId || ""),
|
|
23204
|
-
triggerReason: setup.triggerReason === "fresh_after_version_update" ? "fresh_after_version_update" : "new_environment",
|
|
23213
|
+
triggerReason: setup.triggerReason === "fresh_after_version_update" ? "fresh_after_version_update" : setup.triggerReason === "explicit_reset" ? "explicit_reset" : "new_environment",
|
|
23214
|
+
operationKey: typeof setup.operationKey === "string" ? setup.operationKey : null,
|
|
23205
23215
|
lifecycleStatus: setup.lifecycleStatus === "completed" || setup.lifecycleStatus === "failed" ? setup.lifecycleStatus : "running",
|
|
23206
23216
|
stage: typeof setup.stage === "string" ? setup.stage : null,
|
|
23207
23217
|
totalObjectsToImport: Number(setup.totalObjectsToImport || 0),
|
|
@@ -24483,6 +24493,7 @@ var Environment = class _Environment {
|
|
|
24483
24493
|
records: recordsToImport,
|
|
24484
24494
|
batchSize: options.batchSize,
|
|
24485
24495
|
setupRunId: options.setupRunId,
|
|
24496
|
+
operationKey: options.operationKey,
|
|
24486
24497
|
writeMode: options.writeMode
|
|
24487
24498
|
})
|
|
24488
24499
|
}
|
|
@@ -25287,6 +25298,156 @@ var Granular = class _Granular {
|
|
|
25287
25298
|
await this.maybeRunEnvironmentImporter(resolved, environment);
|
|
25288
25299
|
return environment;
|
|
25289
25300
|
}
|
|
25301
|
+
/**
|
|
25302
|
+
* Read the active environment selected by Granular for an already-recorded
|
|
25303
|
+
* external user. This is intentionally read-only: browser/login code must
|
|
25304
|
+
* not create subjects or environments as a side effect.
|
|
25305
|
+
*/
|
|
25306
|
+
async getActiveEnvironmentForUser(options) {
|
|
25307
|
+
const sandboxId = options.sandboxId.trim();
|
|
25308
|
+
const tagName = options.tag.trim();
|
|
25309
|
+
const userId = options.userId.trim();
|
|
25310
|
+
if (!sandboxId || !tagName || !userId) {
|
|
25311
|
+
throw new Error(
|
|
25312
|
+
"getActiveEnvironmentForUser() requires sandboxId, tag, and userId."
|
|
25313
|
+
);
|
|
25314
|
+
}
|
|
25315
|
+
const subjects = await this.request(
|
|
25316
|
+
`/control/subjects?identityId=${encodeURIComponent(userId)}`
|
|
25317
|
+
);
|
|
25318
|
+
const subject = (subjects.items || []).find(
|
|
25319
|
+
(item) => item.identityId === userId || item.userId === userId
|
|
25320
|
+
);
|
|
25321
|
+
if (!subject?.subjectId && !subject?.granularId) {
|
|
25322
|
+
return null;
|
|
25323
|
+
}
|
|
25324
|
+
const subjectId = subject.subjectId || subject.granularId;
|
|
25325
|
+
const tags = await this.request(
|
|
25326
|
+
`/control/sandboxes/${encodeURIComponent(sandboxId)}/tags`
|
|
25327
|
+
);
|
|
25328
|
+
const tag2 = (tags.items || []).find(
|
|
25329
|
+
(item) => item?.name === tagName
|
|
25330
|
+
);
|
|
25331
|
+
if (!tag2) return null;
|
|
25332
|
+
const query = new URLSearchParams({
|
|
25333
|
+
tagId: tag2.tagId,
|
|
25334
|
+
slot: options.slot?.trim() || "default"
|
|
25335
|
+
});
|
|
25336
|
+
try {
|
|
25337
|
+
const payload = await this.request(
|
|
25338
|
+
`/control/sandboxes/${encodeURIComponent(sandboxId)}/subjects/${encodeURIComponent(subjectId)}/active-environment?${query.toString()}`
|
|
25339
|
+
);
|
|
25340
|
+
return payload.environment ? this.bindEnvironmentHandle(
|
|
25341
|
+
normalizeEnvironmentData(payload.environment)
|
|
25342
|
+
) : null;
|
|
25343
|
+
} catch (error2) {
|
|
25344
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25345
|
+
if (message.includes("404") || message.includes("not found")) {
|
|
25346
|
+
return null;
|
|
25347
|
+
}
|
|
25348
|
+
throw error2;
|
|
25349
|
+
}
|
|
25350
|
+
}
|
|
25351
|
+
/**
|
|
25352
|
+
* Resolve one exact environment only when Granular confirms that it belongs
|
|
25353
|
+
* to the given external user in the requested sandbox (and, optionally,
|
|
25354
|
+
* tag). This is deliberately read-only: callers use it to keep an already
|
|
25355
|
+
* opened delegated workspace stable while a newer active environment is
|
|
25356
|
+
* being prepared in the background.
|
|
25357
|
+
*/
|
|
25358
|
+
async getEnvironmentForUser(options) {
|
|
25359
|
+
const sandboxId = options.sandboxId.trim();
|
|
25360
|
+
const userId = options.userId.trim();
|
|
25361
|
+
const environmentId = options.environmentId.trim();
|
|
25362
|
+
const tagName = options.tag?.trim();
|
|
25363
|
+
if (!sandboxId || !userId || !environmentId) {
|
|
25364
|
+
throw new Error(
|
|
25365
|
+
"getEnvironmentForUser() requires sandboxId, userId, and environmentId."
|
|
25366
|
+
);
|
|
25367
|
+
}
|
|
25368
|
+
const subjects = await this.request(
|
|
25369
|
+
`/control/subjects?identityId=${encodeURIComponent(userId)}`
|
|
25370
|
+
);
|
|
25371
|
+
const subject = (subjects.items || []).find(
|
|
25372
|
+
(item) => item.identityId === userId || item.userId === userId
|
|
25373
|
+
);
|
|
25374
|
+
const subjectId = subject?.subjectId || subject?.granularId;
|
|
25375
|
+
if (!subjectId) return null;
|
|
25376
|
+
let environment;
|
|
25377
|
+
try {
|
|
25378
|
+
environment = await this.environments.get(environmentId);
|
|
25379
|
+
} catch (error2) {
|
|
25380
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25381
|
+
if (message.includes("404") || message.includes("not found")) {
|
|
25382
|
+
return null;
|
|
25383
|
+
}
|
|
25384
|
+
throw error2;
|
|
25385
|
+
}
|
|
25386
|
+
if (environment.sandboxId !== sandboxId || environment.subjectId !== subjectId) {
|
|
25387
|
+
return null;
|
|
25388
|
+
}
|
|
25389
|
+
if (tagName) {
|
|
25390
|
+
const tags = await this.request(`/control/sandboxes/${encodeURIComponent(sandboxId)}/tags`);
|
|
25391
|
+
const tag2 = (tags.items || []).find(
|
|
25392
|
+
(candidate) => candidate?.name === tagName
|
|
25393
|
+
);
|
|
25394
|
+
if (!tag2 || environment.tagId !== tag2.tagId) {
|
|
25395
|
+
return null;
|
|
25396
|
+
}
|
|
25397
|
+
}
|
|
25398
|
+
return this.bindEnvironmentHandle(environment);
|
|
25399
|
+
}
|
|
25400
|
+
/**
|
|
25401
|
+
* Register one reviewed, pre-existing environment as the active workspace
|
|
25402
|
+
* for an external user. This is for a controlled migration only: it does
|
|
25403
|
+
* not create an environment and it does not run an importer.
|
|
25404
|
+
*/
|
|
25405
|
+
async adoptEnvironmentForUser(options) {
|
|
25406
|
+
const sandboxId = options.sandboxId.trim();
|
|
25407
|
+
const tagName = options.tag.trim();
|
|
25408
|
+
const userId = options.userId.trim();
|
|
25409
|
+
const environmentId = options.environmentId.trim();
|
|
25410
|
+
if (!sandboxId || !tagName || !userId || !environmentId) {
|
|
25411
|
+
throw new Error(
|
|
25412
|
+
"adoptEnvironmentForUser() requires sandboxId, tag, userId, and environmentId."
|
|
25413
|
+
);
|
|
25414
|
+
}
|
|
25415
|
+
const subjects = await this.request(
|
|
25416
|
+
`/control/subjects?identityId=${encodeURIComponent(userId)}`
|
|
25417
|
+
);
|
|
25418
|
+
const subject = (subjects.items || []).find(
|
|
25419
|
+
(item) => item.identityId === userId || item.userId === userId
|
|
25420
|
+
);
|
|
25421
|
+
if (!subject?.subjectId && !subject?.granularId) {
|
|
25422
|
+
throw new Error(`No Granular subject exists for user ${userId}.`);
|
|
25423
|
+
}
|
|
25424
|
+
const tags = await this.request(`/control/sandboxes/${encodeURIComponent(sandboxId)}/tags`);
|
|
25425
|
+
const tag2 = (tags.items || []).find(
|
|
25426
|
+
(item) => item?.name === tagName
|
|
25427
|
+
);
|
|
25428
|
+
if (!tag2) {
|
|
25429
|
+
throw new Error(`Tag ${tagName} was not found in sandbox ${sandboxId}.`);
|
|
25430
|
+
}
|
|
25431
|
+
const payload = await this.request(
|
|
25432
|
+
"/control/environment-activations/adopt",
|
|
25433
|
+
{
|
|
25434
|
+
method: "POST",
|
|
25435
|
+
body: JSON.stringify({
|
|
25436
|
+
environmentId,
|
|
25437
|
+
subjectId: subject.subjectId || subject.granularId,
|
|
25438
|
+
tagId: tag2.tagId,
|
|
25439
|
+
slot: options.slot?.trim() || "default",
|
|
25440
|
+
confirmExistingData: true
|
|
25441
|
+
})
|
|
25442
|
+
}
|
|
25443
|
+
);
|
|
25444
|
+
if (!payload.environment) {
|
|
25445
|
+
throw new Error("Granular did not return the adopted environment.");
|
|
25446
|
+
}
|
|
25447
|
+
return this.bindEnvironmentHandle(
|
|
25448
|
+
normalizeEnvironmentData(payload.environment)
|
|
25449
|
+
);
|
|
25450
|
+
}
|
|
25290
25451
|
/**
|
|
25291
25452
|
* Deprecated compatibility alias for `openEnvironment()`.
|
|
25292
25453
|
*
|
|
@@ -25318,7 +25479,9 @@ var Granular = class _Granular {
|
|
|
25318
25479
|
requestedOntology,
|
|
25319
25480
|
sandboxId: environmentData.sandboxId,
|
|
25320
25481
|
subjectId: environmentData.subjectId,
|
|
25321
|
-
|
|
25482
|
+
externalUserId: environmentData.subjectId,
|
|
25483
|
+
setupTriggerReason: options.reason || "new_environment",
|
|
25484
|
+
setupOperationKey: options.operationKey
|
|
25322
25485
|
},
|
|
25323
25486
|
environment
|
|
25324
25487
|
);
|
|
@@ -25330,20 +25493,17 @@ var Granular = class _Granular {
|
|
|
25330
25493
|
}
|
|
25331
25494
|
return tag2;
|
|
25332
25495
|
}
|
|
25333
|
-
buildManagedEnvironmentName(tag2, versionId) {
|
|
25334
|
-
|
|
25496
|
+
buildManagedEnvironmentName(tag2, versionId, resetKey) {
|
|
25497
|
+
if (!resetKey) {
|
|
25498
|
+
return `__sdk__${tag2}__${versionId}__tracked`;
|
|
25499
|
+
}
|
|
25500
|
+
const safeResetKey = resetKey.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 80);
|
|
25501
|
+
return `__sdk__${tag2}__${versionId}__reset__${safeResetKey}`;
|
|
25335
25502
|
}
|
|
25336
25503
|
isManagedEnvironmentName(environment, tagName) {
|
|
25337
25504
|
const name = environment.environment || environment.envName || "";
|
|
25338
25505
|
return name.startsWith(`__sdk__${tagName}__`);
|
|
25339
25506
|
}
|
|
25340
|
-
isPinnedToVersion(environment, versionId) {
|
|
25341
|
-
return environment.buildPolicy.mode === "pinned" && (environment.versionId === versionId || environment.buildPolicy.versionId === versionId || environment.buildPolicy.buildId === versionId);
|
|
25342
|
-
}
|
|
25343
|
-
matchesTagTrackedEnvironment(environment, tagName, tagId) {
|
|
25344
|
-
const environmentTagName = environment.tag?.name || environment.buildPolicy.tagName || null;
|
|
25345
|
-
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);
|
|
25346
|
-
}
|
|
25347
25507
|
sortEnvironmentsByRecency(environments) {
|
|
25348
25508
|
return [...environments].sort(
|
|
25349
25509
|
(left, right) => right.updatedAt - left.updatedAt
|
|
@@ -25393,48 +25553,119 @@ var Granular = class _Granular {
|
|
|
25393
25553
|
`Tag "${tagName}" does not currently point to a build/version.`
|
|
25394
25554
|
);
|
|
25395
25555
|
}
|
|
25556
|
+
const slot = options.slot?.trim() || "default";
|
|
25557
|
+
const resetKey = options.resetKey?.trim() || void 0;
|
|
25558
|
+
const resolveActive = async (operationKey) => {
|
|
25559
|
+
const query = new URLSearchParams({ tagId: tag2.tagId, slot });
|
|
25560
|
+
if (operationKey) query.set("operationKey", operationKey);
|
|
25561
|
+
try {
|
|
25562
|
+
const payload = await this.request(
|
|
25563
|
+
`/control/sandboxes/${encodeURIComponent(sandbox.sandboxId)}/subjects/${encodeURIComponent(user.granularId)}/active-environment?${query.toString()}`
|
|
25564
|
+
);
|
|
25565
|
+
return payload.environment ? normalizeEnvironmentData(payload.environment) : null;
|
|
25566
|
+
} catch (error2) {
|
|
25567
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25568
|
+
if (message.includes("404") || message.includes("not found")) {
|
|
25569
|
+
return null;
|
|
25570
|
+
}
|
|
25571
|
+
throw error2;
|
|
25572
|
+
}
|
|
25573
|
+
};
|
|
25574
|
+
const activate = async (environment2) => {
|
|
25575
|
+
const payload = await this.request(
|
|
25576
|
+
"/control/environment-activations",
|
|
25577
|
+
{
|
|
25578
|
+
method: "POST",
|
|
25579
|
+
body: JSON.stringify({
|
|
25580
|
+
environmentId: environment2.environmentId,
|
|
25581
|
+
tagId: tag2.tagId,
|
|
25582
|
+
slot,
|
|
25583
|
+
operationKey: resetKey,
|
|
25584
|
+
operation: resetKey ? "explicit_reset" : void 0
|
|
25585
|
+
})
|
|
25586
|
+
}
|
|
25587
|
+
);
|
|
25588
|
+
return normalizeEnvironmentData(payload.environment);
|
|
25589
|
+
};
|
|
25590
|
+
if (resetKey) {
|
|
25591
|
+
const resetEnvironment = await resolveActive(resetKey);
|
|
25592
|
+
if (resetEnvironment) {
|
|
25593
|
+
return {
|
|
25594
|
+
environment: resetEnvironment,
|
|
25595
|
+
requestedOntology: ontology,
|
|
25596
|
+
sandboxId: sandbox.sandboxId,
|
|
25597
|
+
subjectId: user.granularId,
|
|
25598
|
+
externalUserId: user.userId,
|
|
25599
|
+
// Retrying an explicit reset must also resume its durable setup run.
|
|
25600
|
+
// Otherwise a Container crash after queue submission would leave a
|
|
25601
|
+
// valid environment permanently marked as "running".
|
|
25602
|
+
setupTriggerReason: "explicit_reset",
|
|
25603
|
+
setupOperationKey: resetKey
|
|
25604
|
+
};
|
|
25605
|
+
}
|
|
25606
|
+
} else {
|
|
25607
|
+
const active = await resolveActive();
|
|
25608
|
+
if (active && (active.versionId === targetVersionId || options.createFreshIfOutdated !== true)) {
|
|
25609
|
+
return {
|
|
25610
|
+
environment: active,
|
|
25611
|
+
requestedOntology: ontology,
|
|
25612
|
+
sandboxId: sandbox.sandboxId,
|
|
25613
|
+
subjectId: user.granularId,
|
|
25614
|
+
externalUserId: user.userId
|
|
25615
|
+
};
|
|
25616
|
+
}
|
|
25617
|
+
}
|
|
25396
25618
|
const allEnvironments = await this.environments.list(sandbox.sandboxId);
|
|
25397
25619
|
const userEnvironments = allEnvironments.filter(
|
|
25398
|
-
(
|
|
25620
|
+
(environment2) => environment2.subjectId === user.granularId
|
|
25399
25621
|
);
|
|
25400
25622
|
const currentMatches = this.sortEnvironmentsByRecency(
|
|
25401
25623
|
userEnvironments.filter(
|
|
25402
|
-
(
|
|
25624
|
+
(environment2) => environment2.tagId === tag2.tagId && environment2.versionId === targetVersionId
|
|
25403
25625
|
)
|
|
25404
25626
|
);
|
|
25405
|
-
if (currentMatches.length > 0) {
|
|
25627
|
+
if (!resetKey && currentMatches.length > 0) {
|
|
25628
|
+
const environment2 = await activate(currentMatches[0]);
|
|
25406
25629
|
return {
|
|
25407
|
-
environment:
|
|
25630
|
+
environment: environment2,
|
|
25408
25631
|
requestedOntology: ontology,
|
|
25409
25632
|
sandboxId: sandbox.sandboxId,
|
|
25410
|
-
subjectId: user.granularId
|
|
25633
|
+
subjectId: user.granularId,
|
|
25634
|
+
externalUserId: user.userId
|
|
25411
25635
|
};
|
|
25412
25636
|
}
|
|
25413
25637
|
const outdatedMatches = this.sortEnvironmentsByRecency(
|
|
25414
|
-
userEnvironments.filter(
|
|
25415
|
-
(environment) => this.matchesTagTrackedEnvironment(environment, tagName, tag2.tagId)
|
|
25416
|
-
)
|
|
25638
|
+
userEnvironments.filter((environment2) => environment2.tagId === tag2.tagId)
|
|
25417
25639
|
);
|
|
25418
25640
|
if (outdatedMatches.length > 0 && options.createFreshIfOutdated !== true) {
|
|
25641
|
+
const environment2 = await activate(outdatedMatches[0]);
|
|
25419
25642
|
return {
|
|
25420
|
-
environment:
|
|
25643
|
+
environment: environment2,
|
|
25421
25644
|
requestedOntology: ontology,
|
|
25422
25645
|
sandboxId: sandbox.sandboxId,
|
|
25423
|
-
subjectId: user.granularId
|
|
25646
|
+
subjectId: user.granularId,
|
|
25647
|
+
externalUserId: user.userId
|
|
25424
25648
|
};
|
|
25425
25649
|
}
|
|
25650
|
+
const created = await this.environments.create(sandbox.sandboxId, {
|
|
25651
|
+
subjectId: user.granularId,
|
|
25652
|
+
environment: this.buildManagedEnvironmentName(
|
|
25653
|
+
tagName,
|
|
25654
|
+
targetVersionId,
|
|
25655
|
+
resetKey
|
|
25656
|
+
),
|
|
25657
|
+
tagId: tag2.tagId,
|
|
25658
|
+
permissionProfileId: null
|
|
25659
|
+
});
|
|
25660
|
+
const environment = await activate(created);
|
|
25426
25661
|
return {
|
|
25427
|
-
environment
|
|
25428
|
-
subjectId: user.granularId,
|
|
25429
|
-
environment: this.buildManagedEnvironmentName(tagName, targetVersionId),
|
|
25430
|
-
tagId: tag2.tagId,
|
|
25431
|
-
versionId: targetVersionId,
|
|
25432
|
-
permissionProfileId: null
|
|
25433
|
-
}),
|
|
25662
|
+
environment,
|
|
25434
25663
|
requestedOntology: ontology,
|
|
25435
25664
|
sandboxId: sandbox.sandboxId,
|
|
25436
25665
|
subjectId: user.granularId,
|
|
25437
|
-
|
|
25666
|
+
externalUserId: user.userId,
|
|
25667
|
+
setupTriggerReason: resetKey ? "explicit_reset" : outdatedMatches.length > 0 ? "fresh_after_version_update" : "new_environment",
|
|
25668
|
+
setupOperationKey: resetKey
|
|
25438
25669
|
};
|
|
25439
25670
|
}
|
|
25440
25671
|
/**
|
|
@@ -25713,11 +25944,24 @@ var Granular = class _Granular {
|
|
|
25713
25944
|
{
|
|
25714
25945
|
method: "POST",
|
|
25715
25946
|
body: JSON.stringify({
|
|
25716
|
-
triggerReason: resolved.setupTriggerReason
|
|
25947
|
+
triggerReason: resolved.setupTriggerReason,
|
|
25948
|
+
operationKey: resolved.setupOperationKey
|
|
25717
25949
|
})
|
|
25718
25950
|
}
|
|
25719
25951
|
);
|
|
25720
25952
|
const setupRunId = setupRun.setupRunId;
|
|
25953
|
+
let claim = null;
|
|
25954
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
25955
|
+
claim = await this.request(
|
|
25956
|
+
`/control/environment-setup-runs/${setupRunId}/importer-claim`,
|
|
25957
|
+
{ method: "POST", body: JSON.stringify({}) }
|
|
25958
|
+
);
|
|
25959
|
+
if (claim.action !== "busy") break;
|
|
25960
|
+
await sleep(Math.min(3e4, Math.max(250, claim.retryAfterMs || 1e3)));
|
|
25961
|
+
}
|
|
25962
|
+
if (!claim) {
|
|
25963
|
+
throw new Error(`Unable to claim environment setup run ${setupRunId}.`);
|
|
25964
|
+
}
|
|
25721
25965
|
const updateSetupRun = async (patch) => {
|
|
25722
25966
|
await this.request(
|
|
25723
25967
|
`/control/environment-setup-runs/${setupRunId}`,
|
|
@@ -25727,10 +25971,26 @@ var Granular = class _Granular {
|
|
|
25727
25971
|
}
|
|
25728
25972
|
);
|
|
25729
25973
|
};
|
|
25974
|
+
if (claim.action === "submitted") {
|
|
25975
|
+
const completedSetupRun = await this.request(
|
|
25976
|
+
`/control/environment-setup-runs/${setupRunId}`,
|
|
25977
|
+
{ method: "PATCH", body: JSON.stringify({ markHookCompleted: true }) }
|
|
25978
|
+
);
|
|
25979
|
+
const refreshedEnvironment = await this.environments.get(
|
|
25980
|
+
environment.environmentId
|
|
25981
|
+
);
|
|
25982
|
+
environment.syncEnvironmentData(refreshedEnvironment);
|
|
25983
|
+
return completedSetupRun;
|
|
25984
|
+
}
|
|
25985
|
+
if (claim.action === "busy" || claim.action === "terminal") {
|
|
25986
|
+
return claim.summary;
|
|
25987
|
+
}
|
|
25988
|
+
let importSequence = 0;
|
|
25730
25989
|
const importerContext = {
|
|
25731
25990
|
environmentId: environment.environmentId,
|
|
25732
25991
|
sandboxId: environment.sandboxId,
|
|
25733
25992
|
subjectId: environment.subjectId,
|
|
25993
|
+
externalUserId: resolved.externalUserId,
|
|
25734
25994
|
reason: resolved.setupTriggerReason,
|
|
25735
25995
|
incrementTotalObjectsToImportCount: async (n) => {
|
|
25736
25996
|
const safeIncrement = Math.max(0, Math.trunc(n));
|
|
@@ -25747,7 +26007,10 @@ var Granular = class _Granular {
|
|
|
25747
26007
|
importRecords: async (records, options) => environment.enqueueRecordImport(records, {
|
|
25748
26008
|
batchSize: options?.batchSize,
|
|
25749
26009
|
writeMode: options?.writeMode,
|
|
25750
|
-
setupRunId
|
|
26010
|
+
setupRunId,
|
|
26011
|
+
// Sequence is deterministic for a retry of one importer hook. It
|
|
26012
|
+
// prevents a Container restart from creating a second queue import.
|
|
26013
|
+
operationKey: `${setupRunId}:import:${importSequence++}`
|
|
25751
26014
|
})
|
|
25752
26015
|
};
|
|
25753
26016
|
try {
|
|
@@ -27964,9 +28227,12 @@ program2.command("build").description(
|
|
|
27964
28227
|
});
|
|
27965
28228
|
program2.command("deploy").description(
|
|
27966
28229
|
"Push the current revision to dev; use --prod to move prod there too"
|
|
27967
|
-
).option("--prod", "Also point prod to the current version").
|
|
28230
|
+
).option("--prod", "Also point prod to the current version").option(
|
|
28231
|
+
"--release-key <key>",
|
|
28232
|
+
"Version data/importer changes with this immutable release key"
|
|
28233
|
+
).action(async (opts) => {
|
|
27968
28234
|
try {
|
|
27969
|
-
await deployCommand({ prod: opts.prod });
|
|
28235
|
+
await deployCommand({ prod: opts.prod, releaseKey: opts.releaseKey });
|
|
27970
28236
|
} catch (err) {
|
|
27971
28237
|
error(err.message);
|
|
27972
28238
|
process.exit(1);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { bM as WSClientOptions, a2 as GranularQuotaProgress, T as ToolWithHandler, f as PublishToolsResult, aO as Job, g as ToolHandler, I as InstanceToolHandler, aY as ConversationMessageInput, aZ as ConversationAppendResult, aB as EffectInfo, P as Prompt, aA as ToolInfo, aD as EffectsChangedEvent, aC as ToolsChangedEvent, D as DomainState, y as GranularOptions, ci as EnvironmentImporter, B as RecordUserOptions, U as User, H as OpenEnvironmentOptions, af as EnvironmentData, ac as BuildPolicy, cf as EnvironmentSetupSummary, W as ConversationSessionListOptions, Q as ConversationSessionInfo, L as CreateSessionOptions, bW as RecordObjectOptions, c1 as RecordObjectResult, c3 as RecordObjectsOptions, ca as RecordImport, c6 as RecordImportStatus, cb as EnvironmentRecordImportSummary, aM as EnvironmentFeedbackRecord, c as SessionHeapSnapshot, bA as SessionDocumentResult, bB as SessionCollectionListOptions, bD as SessionCollectionListResult, a_ as SessionConversationMessage, a$ as SessionTimelineEvent, bC as SessionJobListOptions, bt as SessionJobRecord, b8 as SessionArtifactListOptions, b7 as SessionArtifactRecord, b9 as SessionArtifactValidationResult, bb as SessionArtifactExecutionOptions, ba as SessionArtifactExecutionResult, bc as SessionArtifactApprovalOptions, bm as RecordManualActionInput, bo as ManualActionRecordResult, bp as ManualActionListOptions, bn as ManualActionOccurrence, br as ManualActionSuggestionOptions, bq as ManualActionSuggestion, bf as ArtifactApprovalTaskListOptions, be as ArtifactApprovalTask, bg as ArtifactApprovalDecisionInput, bh as ArtifactApprovalDecisionResult, b3 as SessionFileRecord, bs as SessionFileUploadOptions, S as SessionHeapEntry, b as SessionHeapList, bw as SessionHeapVariable, d as SessionTranscriptEntry, cM as GraphQLResult, by as RecordSearchOptions, bx as RecordSearchResult, bz as RecordMentionInput, bV as DefineRelationshipOptions, bU as RelationshipInfo, bT as ModelRef, cL as ManifestContent, b_ as EnvironmentStateUpdateInput, bY as EnvironmentStateTarget, c0 as EnvironmentStateProxy, c5 as RecordImportOptions, bI as UserEnvironmentStateOptions, bH as UserEnvironmentState, bJ as MarkUserEnvironmentReadOptions, J as AdoptEnvironmentOptions, K as ConnectOptions, cd as RunEnvironmentImporterOptions, l as OpenAIUsageSpendEvent, G as GranularSpendContext, o as RecordOpenAIUsageSpendResult, a5 as SandboxListResponse, a3 as Sandbox, a4 as CreateSandboxData, cO as DeleteResponse, a7 as PermissionProfile, a8 as CreatePermissionProfileData, ag as CreateEnvironmentData, cP as StreamEvent, cQ as StreamSubscription, cR as StreamStats, F as Subject, ab as AssignmentListResponse } from './spend-DpRRCrAr.mjs';
|
|
2
2
|
import * as Automerge from '@automerge/automerge';
|
|
3
3
|
import { Doc } from '@automerge/automerge/slim';
|
|
4
4
|
|
|
@@ -952,6 +952,36 @@ declare class Granular {
|
|
|
952
952
|
* ```
|
|
953
953
|
*/
|
|
954
954
|
openEnvironment(options: OpenEnvironmentOptions): Promise<Environment>;
|
|
955
|
+
/**
|
|
956
|
+
* Read the active environment selected by Granular for an already-recorded
|
|
957
|
+
* external user. This is intentionally read-only: browser/login code must
|
|
958
|
+
* not create subjects or environments as a side effect.
|
|
959
|
+
*/
|
|
960
|
+
getActiveEnvironmentForUser(options: {
|
|
961
|
+
sandboxId: string;
|
|
962
|
+
tag: string;
|
|
963
|
+
userId: string;
|
|
964
|
+
slot?: string;
|
|
965
|
+
}): Promise<Environment | null>;
|
|
966
|
+
/**
|
|
967
|
+
* Resolve one exact environment only when Granular confirms that it belongs
|
|
968
|
+
* to the given external user in the requested sandbox (and, optionally,
|
|
969
|
+
* tag). This is deliberately read-only: callers use it to keep an already
|
|
970
|
+
* opened delegated workspace stable while a newer active environment is
|
|
971
|
+
* being prepared in the background.
|
|
972
|
+
*/
|
|
973
|
+
getEnvironmentForUser(options: {
|
|
974
|
+
sandboxId: string;
|
|
975
|
+
userId: string;
|
|
976
|
+
environmentId: string;
|
|
977
|
+
tag?: string;
|
|
978
|
+
}): Promise<Environment | null>;
|
|
979
|
+
/**
|
|
980
|
+
* Register one reviewed, pre-existing environment as the active workspace
|
|
981
|
+
* for an external user. This is for a controlled migration only: it does
|
|
982
|
+
* not create an environment and it does not run an importer.
|
|
983
|
+
*/
|
|
984
|
+
adoptEnvironmentForUser(options: AdoptEnvironmentOptions): Promise<Environment>;
|
|
955
985
|
/**
|
|
956
986
|
* Deprecated compatibility alias for `openEnvironment()`.
|
|
957
987
|
*
|
|
@@ -971,8 +1001,6 @@ declare class Granular {
|
|
|
971
1001
|
private resolveRequestedTag;
|
|
972
1002
|
private buildManagedEnvironmentName;
|
|
973
1003
|
private isManagedEnvironmentName;
|
|
974
|
-
private isPinnedToVersion;
|
|
975
|
-
private matchesTagTrackedEnvironment;
|
|
976
1004
|
private sortEnvironmentsByRecency;
|
|
977
1005
|
private resolveOpenEnvironmentData;
|
|
978
1006
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { bM as WSClientOptions, a2 as GranularQuotaProgress, T as ToolWithHandler, f as PublishToolsResult, aO as Job, g as ToolHandler, I as InstanceToolHandler, aY as ConversationMessageInput, aZ as ConversationAppendResult, aB as EffectInfo, P as Prompt, aA as ToolInfo, aD as EffectsChangedEvent, aC as ToolsChangedEvent, D as DomainState, y as GranularOptions, ci as EnvironmentImporter, B as RecordUserOptions, U as User, H as OpenEnvironmentOptions, af as EnvironmentData, ac as BuildPolicy, cf as EnvironmentSetupSummary, W as ConversationSessionListOptions, Q as ConversationSessionInfo, L as CreateSessionOptions, bW as RecordObjectOptions, c1 as RecordObjectResult, c3 as RecordObjectsOptions, ca as RecordImport, c6 as RecordImportStatus, cb as EnvironmentRecordImportSummary, aM as EnvironmentFeedbackRecord, c as SessionHeapSnapshot, bA as SessionDocumentResult, bB as SessionCollectionListOptions, bD as SessionCollectionListResult, a_ as SessionConversationMessage, a$ as SessionTimelineEvent, bC as SessionJobListOptions, bt as SessionJobRecord, b8 as SessionArtifactListOptions, b7 as SessionArtifactRecord, b9 as SessionArtifactValidationResult, bb as SessionArtifactExecutionOptions, ba as SessionArtifactExecutionResult, bc as SessionArtifactApprovalOptions, bm as RecordManualActionInput, bo as ManualActionRecordResult, bp as ManualActionListOptions, bn as ManualActionOccurrence, br as ManualActionSuggestionOptions, bq as ManualActionSuggestion, bf as ArtifactApprovalTaskListOptions, be as ArtifactApprovalTask, bg as ArtifactApprovalDecisionInput, bh as ArtifactApprovalDecisionResult, b3 as SessionFileRecord, bs as SessionFileUploadOptions, S as SessionHeapEntry, b as SessionHeapList, bw as SessionHeapVariable, d as SessionTranscriptEntry, cM as GraphQLResult, by as RecordSearchOptions, bx as RecordSearchResult, bz as RecordMentionInput, bV as DefineRelationshipOptions, bU as RelationshipInfo, bT as ModelRef, cL as ManifestContent, b_ as EnvironmentStateUpdateInput, bY as EnvironmentStateTarget, c0 as EnvironmentStateProxy, c5 as RecordImportOptions, bI as UserEnvironmentStateOptions, bH as UserEnvironmentState, bJ as MarkUserEnvironmentReadOptions, J as AdoptEnvironmentOptions, K as ConnectOptions, cd as RunEnvironmentImporterOptions, l as OpenAIUsageSpendEvent, G as GranularSpendContext, o as RecordOpenAIUsageSpendResult, a5 as SandboxListResponse, a3 as Sandbox, a4 as CreateSandboxData, cO as DeleteResponse, a7 as PermissionProfile, a8 as CreatePermissionProfileData, ag as CreateEnvironmentData, cP as StreamEvent, cQ as StreamSubscription, cR as StreamStats, F as Subject, ab as AssignmentListResponse } from './spend-DpRRCrAr.js';
|
|
2
2
|
import * as Automerge from '@automerge/automerge';
|
|
3
3
|
import { Doc } from '@automerge/automerge/slim';
|
|
4
4
|
|
|
@@ -952,6 +952,36 @@ declare class Granular {
|
|
|
952
952
|
* ```
|
|
953
953
|
*/
|
|
954
954
|
openEnvironment(options: OpenEnvironmentOptions): Promise<Environment>;
|
|
955
|
+
/**
|
|
956
|
+
* Read the active environment selected by Granular for an already-recorded
|
|
957
|
+
* external user. This is intentionally read-only: browser/login code must
|
|
958
|
+
* not create subjects or environments as a side effect.
|
|
959
|
+
*/
|
|
960
|
+
getActiveEnvironmentForUser(options: {
|
|
961
|
+
sandboxId: string;
|
|
962
|
+
tag: string;
|
|
963
|
+
userId: string;
|
|
964
|
+
slot?: string;
|
|
965
|
+
}): Promise<Environment | null>;
|
|
966
|
+
/**
|
|
967
|
+
* Resolve one exact environment only when Granular confirms that it belongs
|
|
968
|
+
* to the given external user in the requested sandbox (and, optionally,
|
|
969
|
+
* tag). This is deliberately read-only: callers use it to keep an already
|
|
970
|
+
* opened delegated workspace stable while a newer active environment is
|
|
971
|
+
* being prepared in the background.
|
|
972
|
+
*/
|
|
973
|
+
getEnvironmentForUser(options: {
|
|
974
|
+
sandboxId: string;
|
|
975
|
+
userId: string;
|
|
976
|
+
environmentId: string;
|
|
977
|
+
tag?: string;
|
|
978
|
+
}): Promise<Environment | null>;
|
|
979
|
+
/**
|
|
980
|
+
* Register one reviewed, pre-existing environment as the active workspace
|
|
981
|
+
* for an external user. This is for a controlled migration only: it does
|
|
982
|
+
* not create an environment and it does not run an importer.
|
|
983
|
+
*/
|
|
984
|
+
adoptEnvironmentForUser(options: AdoptEnvironmentOptions): Promise<Environment>;
|
|
955
985
|
/**
|
|
956
986
|
* Deprecated compatibility alias for `openEnvironment()`.
|
|
957
987
|
*
|
|
@@ -971,8 +1001,6 @@ declare class Granular {
|
|
|
971
1001
|
private resolveRequestedTag;
|
|
972
1002
|
private buildManagedEnvironmentName;
|
|
973
1003
|
private isManagedEnvironmentName;
|
|
974
|
-
private isPinnedToVersion;
|
|
975
|
-
private matchesTagTrackedEnvironment;
|
|
976
1004
|
private sortEnvironmentsByRecency;
|
|
977
1005
|
private resolveOpenEnvironmentData;
|
|
978
1006
|
/**
|