@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.js CHANGED
@@ -14783,6 +14783,15 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
14783
14783
  is_final: Boolean!
14784
14784
  history: [StateMachineTransitionEvent!]!
14785
14785
  instances_in_state(state: String!): [Model!]!
14786
+ instance_population(state: String!, page: Int = 1, per_page: Int = 50): StateMachineInstancePopulation!
14787
+ }
14788
+
14789
+ type StateMachineInstancePopulation {
14790
+ count: Int!
14791
+ instances: [Model!]!
14792
+ page: Int!
14793
+ per_page: Int!
14794
+ has_more: Boolean!
14786
14795
  }
14787
14796
 
14788
14797
  type StateMachineState {
@@ -14991,6 +15000,13 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
14991
15000
  value.model.target || value.model,
14992
15001
  value.name,
14993
15002
  state
15003
+ ),
15004
+ instance_population: async (value, { state, page, per_page }) => await stateMachines.instancePopulation(
15005
+ value.model.target || value.model,
15006
+ value.name,
15007
+ state,
15008
+ page,
15009
+ per_page
14994
15010
  )
14995
15011
  }
14996
15012
  };
@@ -15337,7 +15353,6 @@ function buildEffectMetamodelMutations(toolPath, spec) {
15337
15353
  // src/client.ts
15338
15354
  var DEFAULT_CONVERSATION_SESSION_LIST_LIMIT = 100;
15339
15355
  var MAX_CONVERSATION_SESSION_LIST_LIMIT = 500;
15340
- var MAX_CONVERSATION_SESSION_LIST_OFFSET = 1e5;
15341
15356
  function requireUserEnvironmentSequence(value, field) {
15342
15357
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
15343
15358
  throw new Error(
@@ -15717,6 +15732,10 @@ var Environment = class _Environment {
15717
15732
  get sessions() {
15718
15733
  return {
15719
15734
  list: async (options = {}) => this.listSessions(options),
15735
+ page: async (options = {}) => this.granular.listSessionsPage({
15736
+ ...options,
15737
+ environmentId: this.environmentId
15738
+ }),
15720
15739
  create: async (options) => this.createSession(options),
15721
15740
  connect: async (sessionId, options) => this.connectSession(sessionId, options),
15722
15741
  reopen: async (sessionId, options) => this.reopenSession(sessionId, options),
@@ -15972,7 +15991,6 @@ var Environment = class _Environment {
15972
15991
  headers: {
15973
15992
  Authorization: `Bearer ${this._apiKey}`,
15974
15993
  "Content-Type": "application/json",
15975
- Connection: "close",
15976
15994
  ...options.headers
15977
15995
  }
15978
15996
  });
@@ -17496,8 +17514,7 @@ var EnvironmentSession = class extends Session {
17496
17514
  method: "POST",
17497
17515
  headers: {
17498
17516
  "Content-Type": "application/json",
17499
- Authorization: `Bearer ${this.environment.authToken}`,
17500
- Connection: "close"
17517
+ Authorization: `Bearer ${this.environment.authToken}`
17501
17518
  },
17502
17519
  body: JSON.stringify({
17503
17520
  reason: "sdk_disconnect_http_fallback",
@@ -18025,11 +18042,16 @@ var Granular = class _Granular {
18025
18042
  `${methodName}() requires at least one permission so the SDK can ensure assignments for new users.`
18026
18043
  );
18027
18044
  }
18028
- for (const profileName of user.permissions) {
18029
- const profileId = await this.ensurePermissionProfile(
18030
- sandbox.sandboxId,
18031
- profileName
18045
+ const permissionProfileIds = [];
18046
+ for (const profileReference of user.permissions) {
18047
+ permissionProfileIds.push(
18048
+ await this.ensurePermissionProfile(
18049
+ sandbox.sandboxId,
18050
+ profileReference
18051
+ )
18032
18052
  );
18053
+ }
18054
+ for (const profileId of permissionProfileIds) {
18033
18055
  await this.ensureAssignment(
18034
18056
  user.granularId,
18035
18057
  sandbox.sandboxId,
@@ -18194,6 +18216,21 @@ var Granular = class _Granular {
18194
18216
  * List indexed sessions using ownership filters and bounded pagination.
18195
18217
  */
18196
18218
  async listSessions(options) {
18219
+ const items = [];
18220
+ let cursor = options.cursor?.trim() || void 0;
18221
+ let pageCount = 0;
18222
+ do {
18223
+ const page = await this.listSessionsPage({ ...options, cursor });
18224
+ items.push(...page.items);
18225
+ cursor = page.nextCursor || void 0;
18226
+ pageCount += 1;
18227
+ if (pageCount > 1e4) {
18228
+ throw new Error("Session pagination exceeded the safe page limit");
18229
+ }
18230
+ } while (cursor);
18231
+ return items;
18232
+ }
18233
+ async listSessionsPage(options) {
18197
18234
  const environmentId = options.environmentId?.trim();
18198
18235
  const sandboxId = options.sandboxId?.trim();
18199
18236
  const subjectId = options.subjectId?.trim();
@@ -18221,17 +18258,14 @@ var Granular = class _Granular {
18221
18258
  1,
18222
18259
  MAX_CONVERSATION_SESSION_LIST_LIMIT
18223
18260
  );
18224
- const offset = boundedSessionListInteger(
18225
- options.offset,
18226
- "offset",
18227
- 0,
18228
- 0,
18229
- MAX_CONVERSATION_SESSION_LIST_OFFSET
18230
- );
18261
+ const cursor = options.cursor?.trim();
18262
+ if (options.cursor !== void 0 && !cursor) {
18263
+ throw new Error("Session list cursor must be a non-empty string.");
18264
+ }
18231
18265
  const query = new URLSearchParams({
18232
- limit: String(limit),
18233
- offset: String(offset)
18266
+ limit: String(limit)
18234
18267
  });
18268
+ if (cursor) query.set("cursor", cursor);
18235
18269
  if (environmentId) query.set("environmentId", environmentId);
18236
18270
  if (sandboxId) query.set("sandboxId", sandboxId);
18237
18271
  if (subjectId) query.set("userId", subjectId);
@@ -18239,11 +18273,13 @@ var Granular = class _Granular {
18239
18273
  query.set("sessionScope", options.sessionScope.trim());
18240
18274
  }
18241
18275
  if (status !== "all") query.set("status", status);
18242
- const res = await this.request(
18243
- `/control/sessions?${query.toString()}`
18244
- );
18245
- const items = Array.isArray(res.items) ? res.items : [];
18246
- return items.map((row) => this.normalizeConversationSession(row));
18276
+ const res = await this.request(`/control/sessions?${query.toString()}`);
18277
+ const items = Array.isArray(res.items) ? res.items.map((row) => this.normalizeConversationSession(row)) : [];
18278
+ const nextCursor = res.nextCursor ?? null;
18279
+ if (nextCursor === cursor) {
18280
+ throw new Error("Session pagination cursor did not advance");
18281
+ }
18282
+ return { items, nextCursor };
18247
18283
  }
18248
18284
  /**
18249
18285
  * List active (open) sessions for an environment.
@@ -18270,9 +18306,6 @@ var Granular = class _Granular {
18270
18306
  if (typeof options.limit === "number") {
18271
18307
  query.set("limit", String(options.limit));
18272
18308
  }
18273
- if (typeof options.offset === "number") {
18274
- query.set("offset", String(options.offset));
18275
- }
18276
18309
  const state = await this.request(
18277
18310
  `/sdk/user-environment-state?${query.toString()}`
18278
18311
  );
@@ -19034,25 +19067,37 @@ var Granular = class _Granular {
19034
19067
  }
19035
19068
  }
19036
19069
  /**
19037
- * Ensure a permission profile exists for a sandbox, creating it if needed.
19038
- * If profileName matches an existing profile name, returns its ID.
19039
- * Otherwise, creates a v1 source-profile file shape with an allow default.
19070
+ * Resolve an existing permission profile by exact name or ID.
19071
+ *
19072
+ * `allow-all` is the sole compatibility profile that the SDK may provision
19073
+ * automatically. Every other missing reference fails closed so a typo or
19074
+ * untrusted role value cannot become an allow-default profile.
19040
19075
  */
19041
- async ensurePermissionProfile(sandboxId, profileName) {
19042
- try {
19043
- const profiles = await this.permissionProfiles.list(sandboxId);
19044
- const existing = profiles.find((p) => p.name === profileName);
19045
- if (existing) {
19046
- return existing.permissionProfileId;
19047
- }
19048
- } catch {
19076
+ async ensurePermissionProfile(sandboxId, profileReference) {
19077
+ const normalizedReference = typeof profileReference === "string" ? profileReference.trim() : "";
19078
+ if (!normalizedReference) {
19079
+ throw new Error(
19080
+ "Permission profile references must be non-empty names or IDs."
19081
+ );
19082
+ }
19083
+ const profiles = await this.permissionProfiles.list(sandboxId);
19084
+ const existing = profiles.find(
19085
+ (profile) => profile.name === normalizedReference || profile.permissionProfileId === normalizedReference
19086
+ );
19087
+ if (existing) {
19088
+ return existing.permissionProfileId;
19089
+ }
19090
+ if (normalizedReference !== "allow-all") {
19091
+ throw new Error(
19092
+ `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.`
19093
+ );
19049
19094
  }
19050
19095
  const created = await this.permissionProfiles.create(sandboxId, {
19051
- name: profileName,
19096
+ name: normalizedReference,
19052
19097
  rules: {
19053
19098
  schemaVersion: 1,
19054
- name: profileName,
19055
- description: profileName === "allow-all" ? "Every declared action is visible unless a manifest policy denies it." : `Generated permission profile ${profileName}`,
19099
+ name: normalizedReference,
19100
+ description: "Every declared action is visible unless a manifest policy denies it.",
19056
19101
  defaults: { actionPolicy: "allow" },
19057
19102
  actions: []
19058
19103
  }
@@ -19194,10 +19239,20 @@ var Granular = class _Granular {
19194
19239
  get environments() {
19195
19240
  return {
19196
19241
  list: async (sandboxId) => {
19197
- const result = await this.request(
19198
- `/control/sandboxes/${sandboxId}/environments`
19199
- );
19200
- return result.items.map(normalizeEnvironmentData);
19242
+ const environments = [];
19243
+ let cursor = null;
19244
+ do {
19245
+ const query = cursor ? `?limit=100&cursor=${encodeURIComponent(cursor)}` : "";
19246
+ const result = await this.request(
19247
+ `/control/sandboxes/${sandboxId}/environments${query}`
19248
+ );
19249
+ environments.push(...result.items.map(normalizeEnvironmentData));
19250
+ if (result.nextCursor && result.nextCursor === cursor) {
19251
+ throw new Error("Environment pagination cursor did not advance");
19252
+ }
19253
+ cursor = result.nextCursor;
19254
+ } while (cursor);
19255
+ return environments;
19201
19256
  },
19202
19257
  get: async (environmentId) => {
19203
19258
  return normalizeEnvironmentData(
@@ -19407,7 +19462,6 @@ var Granular = class _Granular {
19407
19462
  headers: {
19408
19463
  Authorization: `Bearer ${this.apiKey}`,
19409
19464
  "Content-Type": "application/json",
19410
- Connection: "close",
19411
19465
  ...options.headers
19412
19466
  }
19413
19467
  });