@granular-software/sdk 0.4.61 → 0.4.63

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/index.mjs CHANGED
@@ -14761,6 +14761,15 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
14761
14761
  is_final: Boolean!
14762
14762
  history: [StateMachineTransitionEvent!]!
14763
14763
  instances_in_state(state: String!): [Model!]!
14764
+ instance_population(state: String!, page: Int = 1, per_page: Int = 50): StateMachineInstancePopulation!
14765
+ }
14766
+
14767
+ type StateMachineInstancePopulation {
14768
+ count: Int!
14769
+ instances: [Model!]!
14770
+ page: Int!
14771
+ per_page: Int!
14772
+ has_more: Boolean!
14764
14773
  }
14765
14774
 
14766
14775
  type StateMachineState {
@@ -14969,6 +14978,13 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
14969
14978
  value.model.target || value.model,
14970
14979
  value.name,
14971
14980
  state
14981
+ ),
14982
+ instance_population: async (value, { state, page, per_page }) => await stateMachines.instancePopulation(
14983
+ value.model.target || value.model,
14984
+ value.name,
14985
+ state,
14986
+ page,
14987
+ per_page
14972
14988
  )
14973
14989
  }
14974
14990
  };
@@ -15315,7 +15331,6 @@ function buildEffectMetamodelMutations(toolPath, spec) {
15315
15331
  // src/client.ts
15316
15332
  var DEFAULT_CONVERSATION_SESSION_LIST_LIMIT = 100;
15317
15333
  var MAX_CONVERSATION_SESSION_LIST_LIMIT = 500;
15318
- var MAX_CONVERSATION_SESSION_LIST_OFFSET = 1e5;
15319
15334
  function requireUserEnvironmentSequence(value, field) {
15320
15335
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
15321
15336
  throw new Error(
@@ -15695,6 +15710,10 @@ var Environment = class _Environment {
15695
15710
  get sessions() {
15696
15711
  return {
15697
15712
  list: async (options = {}) => this.listSessions(options),
15713
+ page: async (options = {}) => this.granular.listSessionsPage({
15714
+ ...options,
15715
+ environmentId: this.environmentId
15716
+ }),
15698
15717
  create: async (options) => this.createSession(options),
15699
15718
  connect: async (sessionId, options) => this.connectSession(sessionId, options),
15700
15719
  reopen: async (sessionId, options) => this.reopenSession(sessionId, options),
@@ -15950,7 +15969,6 @@ var Environment = class _Environment {
15950
15969
  headers: {
15951
15970
  Authorization: `Bearer ${this._apiKey}`,
15952
15971
  "Content-Type": "application/json",
15953
- Connection: "close",
15954
15972
  ...options.headers
15955
15973
  }
15956
15974
  });
@@ -17474,8 +17492,7 @@ var EnvironmentSession = class extends Session {
17474
17492
  method: "POST",
17475
17493
  headers: {
17476
17494
  "Content-Type": "application/json",
17477
- Authorization: `Bearer ${this.environment.authToken}`,
17478
- Connection: "close"
17495
+ Authorization: `Bearer ${this.environment.authToken}`
17479
17496
  },
17480
17497
  body: JSON.stringify({
17481
17498
  reason: "sdk_disconnect_http_fallback",
@@ -18003,11 +18020,16 @@ var Granular = class _Granular {
18003
18020
  `${methodName}() requires at least one permission so the SDK can ensure assignments for new users.`
18004
18021
  );
18005
18022
  }
18006
- for (const profileName of user.permissions) {
18007
- const profileId = await this.ensurePermissionProfile(
18008
- sandbox.sandboxId,
18009
- profileName
18023
+ const permissionProfileIds = [];
18024
+ for (const profileReference of user.permissions) {
18025
+ permissionProfileIds.push(
18026
+ await this.ensurePermissionProfile(
18027
+ sandbox.sandboxId,
18028
+ profileReference
18029
+ )
18010
18030
  );
18031
+ }
18032
+ for (const profileId of permissionProfileIds) {
18011
18033
  await this.ensureAssignment(
18012
18034
  user.granularId,
18013
18035
  sandbox.sandboxId,
@@ -18172,6 +18194,21 @@ var Granular = class _Granular {
18172
18194
  * List indexed sessions using ownership filters and bounded pagination.
18173
18195
  */
18174
18196
  async listSessions(options) {
18197
+ const items = [];
18198
+ let cursor = options.cursor?.trim() || void 0;
18199
+ let pageCount = 0;
18200
+ do {
18201
+ const page = await this.listSessionsPage({ ...options, cursor });
18202
+ items.push(...page.items);
18203
+ cursor = page.nextCursor || void 0;
18204
+ pageCount += 1;
18205
+ if (pageCount > 1e4) {
18206
+ throw new Error("Session pagination exceeded the safe page limit");
18207
+ }
18208
+ } while (cursor);
18209
+ return items;
18210
+ }
18211
+ async listSessionsPage(options) {
18175
18212
  const environmentId = options.environmentId?.trim();
18176
18213
  const sandboxId = options.sandboxId?.trim();
18177
18214
  const subjectId = options.subjectId?.trim();
@@ -18199,17 +18236,14 @@ var Granular = class _Granular {
18199
18236
  1,
18200
18237
  MAX_CONVERSATION_SESSION_LIST_LIMIT
18201
18238
  );
18202
- const offset = boundedSessionListInteger(
18203
- options.offset,
18204
- "offset",
18205
- 0,
18206
- 0,
18207
- MAX_CONVERSATION_SESSION_LIST_OFFSET
18208
- );
18239
+ const cursor = options.cursor?.trim();
18240
+ if (options.cursor !== void 0 && !cursor) {
18241
+ throw new Error("Session list cursor must be a non-empty string.");
18242
+ }
18209
18243
  const query = new URLSearchParams({
18210
- limit: String(limit),
18211
- offset: String(offset)
18244
+ limit: String(limit)
18212
18245
  });
18246
+ if (cursor) query.set("cursor", cursor);
18213
18247
  if (environmentId) query.set("environmentId", environmentId);
18214
18248
  if (sandboxId) query.set("sandboxId", sandboxId);
18215
18249
  if (subjectId) query.set("userId", subjectId);
@@ -18217,11 +18251,13 @@ var Granular = class _Granular {
18217
18251
  query.set("sessionScope", options.sessionScope.trim());
18218
18252
  }
18219
18253
  if (status !== "all") query.set("status", status);
18220
- const res = await this.request(
18221
- `/control/sessions?${query.toString()}`
18222
- );
18223
- const items = Array.isArray(res.items) ? res.items : [];
18224
- return items.map((row) => this.normalizeConversationSession(row));
18254
+ const res = await this.request(`/control/sessions?${query.toString()}`);
18255
+ const items = Array.isArray(res.items) ? res.items.map((row) => this.normalizeConversationSession(row)) : [];
18256
+ const nextCursor = res.nextCursor ?? null;
18257
+ if (nextCursor === cursor) {
18258
+ throw new Error("Session pagination cursor did not advance");
18259
+ }
18260
+ return { items, nextCursor };
18225
18261
  }
18226
18262
  /**
18227
18263
  * List active (open) sessions for an environment.
@@ -18248,9 +18284,6 @@ var Granular = class _Granular {
18248
18284
  if (typeof options.limit === "number") {
18249
18285
  query.set("limit", String(options.limit));
18250
18286
  }
18251
- if (typeof options.offset === "number") {
18252
- query.set("offset", String(options.offset));
18253
- }
18254
18287
  const state = await this.request(
18255
18288
  `/sdk/user-environment-state?${query.toString()}`
18256
18289
  );
@@ -19012,25 +19045,37 @@ var Granular = class _Granular {
19012
19045
  }
19013
19046
  }
19014
19047
  /**
19015
- * Ensure a permission profile exists for a sandbox, creating it if needed.
19016
- * If profileName matches an existing profile name, returns its ID.
19017
- * Otherwise, creates a v1 source-profile file shape with an allow default.
19048
+ * Resolve an existing permission profile by exact name or ID.
19049
+ *
19050
+ * `allow-all` is the sole compatibility profile that the SDK may provision
19051
+ * automatically. Every other missing reference fails closed so a typo or
19052
+ * untrusted role value cannot become an allow-default profile.
19018
19053
  */
19019
- async ensurePermissionProfile(sandboxId, profileName) {
19020
- try {
19021
- const profiles = await this.permissionProfiles.list(sandboxId);
19022
- const existing = profiles.find((p) => p.name === profileName);
19023
- if (existing) {
19024
- return existing.permissionProfileId;
19025
- }
19026
- } catch {
19054
+ async ensurePermissionProfile(sandboxId, profileReference) {
19055
+ const normalizedReference = typeof profileReference === "string" ? profileReference.trim() : "";
19056
+ if (!normalizedReference) {
19057
+ throw new Error(
19058
+ "Permission profile references must be non-empty names or IDs."
19059
+ );
19060
+ }
19061
+ const profiles = await this.permissionProfiles.list(sandboxId);
19062
+ const existing = profiles.find(
19063
+ (profile) => profile.name === normalizedReference || profile.permissionProfileId === normalizedReference
19064
+ );
19065
+ if (existing) {
19066
+ return existing.permissionProfileId;
19067
+ }
19068
+ if (normalizedReference !== "allow-all") {
19069
+ throw new Error(
19070
+ `Permission profile "${normalizedReference}" was not found in sandbox ${sandboxId}. Provision it with granular build or granular deploy before calling openEnvironment(). Only the reserved "allow-all" profile can be created automatically.`
19071
+ );
19027
19072
  }
19028
19073
  const created = await this.permissionProfiles.create(sandboxId, {
19029
- name: profileName,
19074
+ name: normalizedReference,
19030
19075
  rules: {
19031
19076
  schemaVersion: 1,
19032
- name: profileName,
19033
- description: profileName === "allow-all" ? "Every declared action is visible unless a manifest policy denies it." : `Generated permission profile ${profileName}`,
19077
+ name: normalizedReference,
19078
+ description: "Every declared action is visible unless a manifest policy denies it.",
19034
19079
  defaults: { actionPolicy: "allow" },
19035
19080
  actions: []
19036
19081
  }
@@ -19172,10 +19217,20 @@ var Granular = class _Granular {
19172
19217
  get environments() {
19173
19218
  return {
19174
19219
  list: async (sandboxId) => {
19175
- const result = await this.request(
19176
- `/control/sandboxes/${sandboxId}/environments`
19177
- );
19178
- return result.items.map(normalizeEnvironmentData);
19220
+ const environments = [];
19221
+ let cursor = null;
19222
+ do {
19223
+ const query = cursor ? `?limit=100&cursor=${encodeURIComponent(cursor)}` : "";
19224
+ const result = await this.request(
19225
+ `/control/sandboxes/${sandboxId}/environments${query}`
19226
+ );
19227
+ environments.push(...result.items.map(normalizeEnvironmentData));
19228
+ if (result.nextCursor && result.nextCursor === cursor) {
19229
+ throw new Error("Environment pagination cursor did not advance");
19230
+ }
19231
+ cursor = result.nextCursor;
19232
+ } while (cursor);
19233
+ return environments;
19179
19234
  },
19180
19235
  get: async (environmentId) => {
19181
19236
  return normalizeEnvironmentData(
@@ -19385,7 +19440,6 @@ var Granular = class _Granular {
19385
19440
  headers: {
19386
19441
  Authorization: `Bearer ${this.apiKey}`,
19387
19442
  "Content-Type": "application/json",
19388
- Connection: "close",
19389
19443
  ...options.headers
19390
19444
  }
19391
19445
  });