@granular-software/sdk 0.4.56 → 0.4.58

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.
@@ -1,5 +1,5 @@
1
- import { a as EnvironmentSession, G as Granular } from './client-DL4S9uRc.mjs';
2
- import { G as GranularSpendContext, h as OpenAITokenSpend, P as Prompt, bW as RecordObjectOptions, cL as ManifestContent, c as SessionHeapSnapshot, T as ToolWithHandler, K as ConnectOptions, ag as CreateEnvironmentData, y as GranularOptions } from './spend-DpRRCrAr.mjs';
1
+ import { a as EnvironmentSession, G as Granular } from './client-DFaCRSto.mjs';
2
+ import { G as GranularSpendContext, h as OpenAITokenSpend, P as Prompt, bW as RecordObjectOptions, cL as ManifestContent, c as SessionHeapSnapshot, T as ToolWithHandler, K as ConnectOptions, ag as CreateEnvironmentData, y as GranularOptions } from './spend-czRX7l0X.mjs';
3
3
  import { GranularAgentToolInfo, GeneratedJobCodeIssue, BuildGranularAgentSystemPromptInput, HarnessRenderedPrompt, HarnessRenderedContinuation, HarnessControllerBudgets } from './agent-harness.mjs';
4
4
  import '@automerge/automerge';
5
5
  import '@automerge/automerge/slim';
@@ -1,5 +1,5 @@
1
- import { a as EnvironmentSession, G as Granular } from './client-BKde5VzV.js';
2
- import { G as GranularSpendContext, h as OpenAITokenSpend, P as Prompt, bW as RecordObjectOptions, cL as ManifestContent, c as SessionHeapSnapshot, T as ToolWithHandler, K as ConnectOptions, ag as CreateEnvironmentData, y as GranularOptions } from './spend-DpRRCrAr.js';
1
+ import { a as EnvironmentSession, G as Granular } from './client-UdGt44dF.js';
2
+ import { G as GranularSpendContext, h as OpenAITokenSpend, P as Prompt, bW as RecordObjectOptions, cL as ManifestContent, c as SessionHeapSnapshot, T as ToolWithHandler, K as ConnectOptions, ag as CreateEnvironmentData, y as GranularOptions } from './spend-czRX7l0X.js';
3
3
  import { GranularAgentToolInfo, GeneratedJobCodeIssue, BuildGranularAgentSystemPromptInput, HarnessRenderedPrompt, HarnessRenderedContinuation, HarnessControllerBudgets } from './agent-harness.js';
4
4
  import '@automerge/automerge';
5
5
  import '@automerge/automerge/slim';
@@ -16537,24 +16537,72 @@ var Granular = class _Granular {
16537
16537
  if (!tagName) {
16538
16538
  throw new Error(`${methodName}() requires \`tag\`.`);
16539
16539
  }
16540
- const user = await this.resolveConnectUser(options);
16541
- if (!Array.isArray(user.permissions) || user.permissions.length === 0) {
16540
+ const assignmentMode = options.assignmentMode ?? "ensure";
16541
+ if (assignmentMode !== "ensure" && assignmentMode !== "require-existing") {
16542
16542
  throw new Error(
16543
- `${methodName}() requires at least one permission so the SDK can ensure assignments for new users.`
16543
+ `${methodName}() received an unsupported assignmentMode: ${String(options.assignmentMode)}.`
16544
16544
  );
16545
16545
  }
16546
- const sandbox = await this.findOrCreateSandbox(ontology);
16547
- for (const profileName of user.permissions) {
16548
- const profileId = await this.ensurePermissionProfile(
16549
- sandbox.sandboxId,
16550
- profileName
16546
+ const requiredGranularId = options.granularId?.trim();
16547
+ if (assignmentMode === "require-existing" && (!requiredGranularId || options.userId || options.user)) {
16548
+ throw new Error(
16549
+ `${methodName}() with assignmentMode "require-existing" requires granularId and does not accept userId or user.`
16551
16550
  );
16552
- await this.ensureAssignment(
16553
- user.granularId,
16554
- sandbox.sandboxId,
16555
- profileId
16551
+ }
16552
+ const user = await this.resolveConnectUser(
16553
+ assignmentMode === "require-existing" ? { ...options, granularId: requiredGranularId } : options
16554
+ );
16555
+ let requiredPermissionProfileId = null;
16556
+ const sandbox = assignmentMode === "require-existing" ? { sandboxId: await this._resolveSandboxId(ontology) } : await this.findOrCreateSandbox(ontology);
16557
+ if (assignmentMode === "require-existing") {
16558
+ const assignments = await this.subjects.listAssignments(user.granularId);
16559
+ const assignment = assignments.items.find(
16560
+ (item) => item.sandboxId === sandbox.sandboxId
16556
16561
  );
16562
+ if (!assignment) {
16563
+ throw new Error(
16564
+ `${methodName}() requires an existing assignment for subject ${user.granularId} in ontology ${sandbox.sandboxId}.`
16565
+ );
16566
+ }
16567
+ const assignedPermissionProfileId = assignment.permissionProfileId?.trim();
16568
+ if (!assignedPermissionProfileId) {
16569
+ throw new Error(
16570
+ `${methodName}() found an invalid assignment without a permission profile for subject ${user.granularId} in ontology ${sandbox.sandboxId}.`
16571
+ );
16572
+ }
16573
+ const expectedPermissionProfileId = options.expectedPermissionProfileId?.trim();
16574
+ if (expectedPermissionProfileId && assignedPermissionProfileId !== expectedPermissionProfileId) {
16575
+ throw new Error(
16576
+ `${methodName}() assignment mismatch for subject ${user.granularId}: expected permission profile ${expectedPermissionProfileId}, received ${assignedPermissionProfileId}.`
16577
+ );
16578
+ }
16579
+ requiredPermissionProfileId = assignedPermissionProfileId;
16580
+ } else {
16581
+ if (!Array.isArray(user.permissions) || user.permissions.length === 0) {
16582
+ throw new Error(
16583
+ `${methodName}() requires at least one permission so the SDK can ensure assignments for new users.`
16584
+ );
16585
+ }
16586
+ for (const profileName of user.permissions) {
16587
+ const profileId = await this.ensurePermissionProfile(
16588
+ sandbox.sandboxId,
16589
+ profileName
16590
+ );
16591
+ await this.ensureAssignment(
16592
+ user.granularId,
16593
+ sandbox.sandboxId,
16594
+ profileId
16595
+ );
16596
+ }
16557
16597
  }
16598
+ const requireMatchingEnvironmentProfile = (environment2) => {
16599
+ if (requiredPermissionProfileId && environment2.permissionProfileId !== requiredPermissionProfileId) {
16600
+ throw new Error(
16601
+ `${methodName}() resolved environment ${environment2.environmentId} with permission profile ${environment2.permissionProfileId || "none"}; current assignment requires ${requiredPermissionProfileId}.`
16602
+ );
16603
+ }
16604
+ return environment2;
16605
+ };
16558
16606
  const tags = await this.request(
16559
16607
  `/control/sandboxes/${sandbox.sandboxId}/tags`
16560
16608
  );
@@ -16577,6 +16625,9 @@ var Granular = class _Granular {
16577
16625
  const resolveActive = async (operationKey) => {
16578
16626
  const query = new URLSearchParams({ tagId: tag.tagId, slot });
16579
16627
  if (operationKey) query.set("operationKey", operationKey);
16628
+ if (requiredPermissionProfileId) {
16629
+ query.set("expectedPermissionProfileId", requiredPermissionProfileId);
16630
+ }
16580
16631
  try {
16581
16632
  const payload = await this.request(
16582
16633
  `/control/sandboxes/${encodeURIComponent(sandbox.sandboxId)}/subjects/${encodeURIComponent(user.granularId)}/active-environment?${query.toString()}`
@@ -16600,7 +16651,8 @@ var Granular = class _Granular {
16600
16651
  tagId: tag.tagId,
16601
16652
  slot,
16602
16653
  operationKey: resetKey,
16603
- operation: resetKey ? "explicit_reset" : void 0
16654
+ operation: resetKey ? "explicit_reset" : void 0,
16655
+ expectedPermissionProfileId: requiredPermissionProfileId || void 0
16604
16656
  })
16605
16657
  }
16606
16658
  );
@@ -16610,7 +16662,7 @@ var Granular = class _Granular {
16610
16662
  const resetEnvironment = await resolveActive(resetKey);
16611
16663
  if (resetEnvironment) {
16612
16664
  return {
16613
- environment: resetEnvironment,
16665
+ environment: requireMatchingEnvironmentProfile(resetEnvironment),
16614
16666
  requestedOntology: ontology,
16615
16667
  sandboxId: sandbox.sandboxId,
16616
16668
  subjectId: user.granularId,
@@ -16626,7 +16678,7 @@ var Granular = class _Granular {
16626
16678
  const active = await resolveActive();
16627
16679
  if (active && (active.versionId === targetVersionId || options.createFreshIfOutdated !== true)) {
16628
16680
  return {
16629
- environment: active,
16681
+ environment: requireMatchingEnvironmentProfile(active),
16630
16682
  requestedOntology: ontology,
16631
16683
  sandboxId: sandbox.sandboxId,
16632
16684
  subjectId: user.granularId,
@@ -16644,7 +16696,10 @@ var Granular = class _Granular {
16644
16696
  )
16645
16697
  );
16646
16698
  if (!resetKey && currentMatches.length > 0) {
16647
- const environment2 = await activate(currentMatches[0]);
16699
+ requireMatchingEnvironmentProfile(currentMatches[0]);
16700
+ const environment2 = requireMatchingEnvironmentProfile(
16701
+ await activate(currentMatches[0])
16702
+ );
16648
16703
  return {
16649
16704
  environment: environment2,
16650
16705
  requestedOntology: ontology,
@@ -16657,7 +16712,10 @@ var Granular = class _Granular {
16657
16712
  userEnvironments.filter((environment2) => environment2.tagId === tag.tagId)
16658
16713
  );
16659
16714
  if (outdatedMatches.length > 0 && options.createFreshIfOutdated !== true) {
16660
- const environment2 = await activate(outdatedMatches[0]);
16715
+ requireMatchingEnvironmentProfile(outdatedMatches[0]);
16716
+ const environment2 = requireMatchingEnvironmentProfile(
16717
+ await activate(outdatedMatches[0])
16718
+ );
16661
16719
  return {
16662
16720
  environment: environment2,
16663
16721
  requestedOntology: ontology,
@@ -16676,7 +16734,10 @@ var Granular = class _Granular {
16676
16734
  tagId: tag.tagId,
16677
16735
  permissionProfileId: null
16678
16736
  });
16679
- const environment = await activate(created);
16737
+ requireMatchingEnvironmentProfile(created);
16738
+ const environment = requireMatchingEnvironmentProfile(
16739
+ await activate(created)
16740
+ );
16680
16741
  return {
16681
16742
  environment,
16682
16743
  requestedOntology: ontology,
@@ -16886,22 +16947,16 @@ var Granular = class _Granular {
16886
16947
  metadata: options?.metadata
16887
16948
  });
16888
16949
  }
16889
- /**
16890
- * Mark a session closed in the control plane. If `environment` is the connected handle for that
16891
- * `sessionId`, disconnects the WebSocket so the runtime tears down cleanly.
16892
- */
16950
+ /** End a session through the runtime, or disconnect its connected handle. */
16893
16951
  async closeSession(sessionId, environment) {
16894
16952
  if (environment && environment.sessionId === sessionId) {
16895
16953
  await environment.disconnect();
16896
16954
  return;
16897
16955
  }
16898
- await this.request(`/control/sessions/${encodeURIComponent(sessionId)}`, {
16899
- method: "PATCH",
16900
- body: JSON.stringify({
16901
- status: "closed",
16902
- lastSeenAt: (/* @__PURE__ */ new Date()).toISOString()
16903
- })
16904
- });
16956
+ await this.request(
16957
+ `/control/sessions/${encodeURIComponent(sessionId)}/close`,
16958
+ { method: "POST" }
16959
+ );
16905
16960
  }
16906
16961
  /**
16907
16962
  * Re-open a closed session in the index and connect to its existing runtime document.