@gravity-rail/sdk 0.47.0 → 0.50.0

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.
Files changed (47) hide show
  1. package/README.md +117 -9
  2. package/dist/agui.cjs +17 -2
  3. package/dist/agui.cjs.map +1 -1
  4. package/dist/agui.d.cts +9 -1
  5. package/dist/agui.d.ts +9 -1
  6. package/dist/agui.js +15 -1
  7. package/dist/agui.js.map +1 -1
  8. package/dist/{chat-interaction-Bqj3Vbst.d.cts → chat-interaction-CmGKKlnL.d.ts} +244 -37
  9. package/dist/{chat-interaction-DiZVtDRE.d.ts → chat-interaction-THDGF4ko.d.cts} +244 -37
  10. package/dist/{chunk-72SWNLVD.js → chunk-MMDSZ25F.js} +1 -1
  11. package/dist/chunk-MMDSZ25F.js.map +1 -0
  12. package/dist/{chunk-N4GQWNGU.js → chunk-QRZVXPR4.js} +204 -50
  13. package/dist/chunk-QRZVXPR4.js.map +1 -0
  14. package/dist/{chunk-67QXTQVL.js → chunk-TGL72KPS.js} +59 -118
  15. package/dist/chunk-TGL72KPS.js.map +1 -0
  16. package/dist/helpers.cjs.map +1 -1
  17. package/dist/helpers.d.cts +4 -4
  18. package/dist/helpers.d.ts +4 -4
  19. package/dist/helpers.js +1 -1
  20. package/dist/index.cjs +262 -164
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +7 -6
  23. package/dist/index.d.ts +7 -6
  24. package/dist/index.js +9 -3
  25. package/dist/index.js.map +1 -1
  26. package/dist/internal.cjs +262 -164
  27. package/dist/internal.cjs.map +1 -1
  28. package/dist/internal.d.cts +148 -6
  29. package/dist/internal.d.ts +148 -6
  30. package/dist/internal.js +9 -3
  31. package/dist/internal.js.map +1 -1
  32. package/dist/{member-import-D7U4kDIy.d.cts → member-import-9zHkUjcn.d.cts} +1 -1
  33. package/dist/{member-import-C2Xt_o5d.d.ts → member-import-ocJ_K474.d.ts} +1 -1
  34. package/dist/{revision-state-ZC4qP3CS.d.cts → path-BQgkft9c.d.ts} +64 -3
  35. package/dist/{revision-state-DaVz2528.d.ts → path-DZbDwvpS.d.cts} +64 -3
  36. package/dist/schemas.cjs +59 -16
  37. package/dist/schemas.cjs.map +1 -1
  38. package/dist/schemas.d.cts +22 -3
  39. package/dist/schemas.d.ts +22 -3
  40. package/dist/schemas.js +59 -17
  41. package/dist/schemas.js.map +1 -1
  42. package/dist/{tasks-Ca6yfsj2.d.cts → tasks-DsNsbco5.d.cts} +66 -14
  43. package/dist/{tasks-Ca6yfsj2.d.ts → tasks-DsNsbco5.d.ts} +66 -14
  44. package/package.json +2 -2
  45. package/dist/chunk-67QXTQVL.js.map +0 -1
  46. package/dist/chunk-72SWNLVD.js.map +0 -1
  47. package/dist/chunk-N4GQWNGU.js.map +0 -1
package/dist/internal.cjs CHANGED
@@ -342,6 +342,7 @@ __export(internal_exports, {
342
342
  getFeaturesByCategory: () => getFeaturesByCategory,
343
343
  getFeaturesByVisibility: () => getFeaturesByVisibility,
344
344
  getMissingDependencies: () => getMissingDependencies,
345
+ getPathDefinition: () => getPathDefinition,
345
346
  getResourceMetadata: () => getResourceMetadata,
346
347
  getRevisionState: () => getRevisionState,
347
348
  getTTSProvider: () => getTTSProvider,
@@ -359,6 +360,8 @@ __export(internal_exports, {
359
360
  isSMSDeliveryFailureStatus: () => isSMSDeliveryFailureStatus,
360
361
  parseExperimentStatCount: () => parseExperimentStatCount,
361
362
  parseOrgAuthChallenge: () => parseOrgAuthChallenge,
363
+ pathDraftFromStorage: () => pathDraftFromStorage,
364
+ pathDraftToStorage: () => pathDraftToStorage,
362
365
  requiresAssistantParticipant: () => requiresAssistantParticipant,
363
366
  usesBuiltinAssistant: () => usesBuiltinAssistant,
364
367
  validateFeatureDependencies: () => validateFeatureDependencies
@@ -3090,27 +3093,16 @@ function parseOrgAuthChallenge(wwwAuthenticate) {
3090
3093
  if (!wwwAuthenticate) return null;
3091
3094
  if (!wwwAuthenticate.includes('realm="org"')) return null;
3092
3095
  const orgUuidMatch = wwwAuthenticate.match(/org_uuid="([^"]+)"/);
3093
- const cookieNameMatch = wwwAuthenticate.match(/cookie_name="([^"]+)"/);
3094
3096
  const authUrlMatch = wwwAuthenticate.match(/auth_url="([^"]+)"/);
3095
- if (!orgUuidMatch?.[1] || !cookieNameMatch?.[1] || !authUrlMatch?.[1]) {
3097
+ if (!orgUuidMatch?.[1] || !authUrlMatch?.[1]) {
3096
3098
  console.warn("Invalid org auth challenge header: missing required fields");
3097
3099
  return null;
3098
3100
  }
3099
3101
  return {
3100
3102
  orgUuid: orgUuidMatch[1],
3101
- cookieName: cookieNameMatch[1],
3102
3103
  authUrl: authUrlMatch[1]
3103
3104
  };
3104
3105
  }
3105
- function getRequestOrgCookieName(cookieName) {
3106
- if (cookieName.startsWith("orgToken")) {
3107
- return cookieName.replace(/^orgToken/, "requestOrgToken");
3108
- }
3109
- if (cookieName.startsWith("orgSession")) {
3110
- return cookieName.replace(/^orgSession/, "requestOrgSession");
3111
- }
3112
- return null;
3113
- }
3114
3106
  function orgAuthHeaderName(token) {
3115
3107
  return token.startsWith("gr_sess_") ? "X-Org-Session" : "X-Org-Token";
3116
3108
  }
@@ -3167,7 +3159,7 @@ var BaseApiClient = class {
3167
3159
  this.apiKey = newApiKey;
3168
3160
  }
3169
3161
  /**
3170
- * Set the opaque org session credential for cross-domain requests.
3162
+ * Set the opaque org session credential a bearer client sends as `X-Org-Session`.
3171
3163
  * Opaque gr_sess_ values use X-Org-Session. Legacy orgToken JWE values still
3172
3164
  * use X-Org-Token through setOrgToken() during the migration window.
3173
3165
  *
@@ -3187,7 +3179,42 @@ var BaseApiClient = class {
3187
3179
  setOrgToken(token, orgUuid) {
3188
3180
  this.setOrgSession(token, orgUuid);
3189
3181
  }
3190
- async fetch(endpoint, options) {
3182
+ /**
3183
+ * The `credentials` a request carries: none for a bearer client (the fetch
3184
+ * default), the page's own-origin cookies for a same-origin session.
3185
+ */
3186
+ credentialsInit() {
3187
+ return this.apiKey ? {} : { credentials: "same-origin" };
3188
+ }
3189
+ /**
3190
+ * Run the org-auth handler once for concurrent challenges. A bearer client's
3191
+ * handler sets the org session with `setOrgSession`; a same-origin session's
3192
+ * handler leaves an httpOnly org-session cookie on the page's origin instead,
3193
+ * which the retry presents. A bearer client whose handler issued nothing has
3194
+ * nothing to retry with.
3195
+ */
3196
+ async answerOrgAuthChallenge(orgAuthInfo) {
3197
+ const handler = this.orgAuthHandler;
3198
+ if (!handler) return;
3199
+ if (!this.orgAuthInProgress) {
3200
+ this.orgAuthInProgress = (async () => {
3201
+ try {
3202
+ await handler(orgAuthInfo);
3203
+ } finally {
3204
+ this.orgAuthInProgress = null;
3205
+ }
3206
+ })();
3207
+ }
3208
+ await this.orgAuthInProgress;
3209
+ if (this.orgSession) {
3210
+ this.orgSessionOrgUuid = orgAuthInfo.orgUuid;
3211
+ return;
3212
+ }
3213
+ if (this.apiKey) {
3214
+ throw new ApiError("Organization authentication did not issue a session", 401);
3215
+ }
3216
+ }
3217
+ async fetch(endpoint, options, orgAuthRetry = false) {
3191
3218
  try {
3192
3219
  const headers = new Headers({
3193
3220
  // Don't set Content-Type for FormData — the browser must set it
@@ -3197,17 +3224,12 @@ var BaseApiClient = class {
3197
3224
  });
3198
3225
  if (this.apiKey) {
3199
3226
  headers.set("Authorization", `Bearer ${this.apiKey}`);
3200
- } else if (this.isCrossDomain) {
3201
- const requestToken = getCookieValue("requestToken");
3202
- if (requestToken) {
3203
- headers.set("Authorization", `Bearer ${requestToken}`);
3204
- }
3205
3227
  }
3206
3228
  setOrgAuthHeader(headers, this.orgSession);
3207
3229
  const fullUrl = `${this.baseUrl}/api/v2/${endpoint}`;
3208
3230
  const response = await this.fetchFunction(fullUrl, {
3209
3231
  ...options,
3210
- ...this.apiKey ? {} : { credentials: "include" },
3232
+ ...this.credentialsInit(),
3211
3233
  ...this.isCrossDomain ? { mode: "cors" } : {},
3212
3234
  headers
3213
3235
  });
@@ -3238,48 +3260,14 @@ var BaseApiClient = class {
3238
3260
  this.orgSession = void 0;
3239
3261
  this.orgSessionOrgUuid = void 0;
3240
3262
  }
3241
- if (orgAuthInfo && !this.orgSession) {
3242
- const requestCookieName = getRequestOrgCookieName(orgAuthInfo.cookieName);
3243
- const cachedOrgSession = requestCookieName ? getCookieValue(requestCookieName) : void 0;
3244
- if (cachedOrgSession) {
3245
- this.orgSession = cachedOrgSession;
3246
- this.orgSessionOrgUuid = orgAuthInfo.orgUuid;
3247
- try {
3248
- return await this.fetch(endpoint, options);
3249
- } catch (retryError) {
3250
- this.orgSession = void 0;
3251
- this.orgSessionOrgUuid = void 0;
3252
- throw retryError;
3253
- }
3254
- }
3255
- if (this.orgAuthHandler) {
3256
- if (!this.orgAuthInProgress) {
3257
- const handler = this.orgAuthHandler;
3258
- this.orgAuthInProgress = (async () => {
3259
- try {
3260
- await handler(orgAuthInfo);
3261
- } finally {
3262
- this.orgAuthInProgress = null;
3263
- }
3264
- })();
3265
- }
3266
- await this.orgAuthInProgress;
3267
- const postHandlerSession = (requestCookieName ? getCookieValue(requestCookieName) : void 0) ?? this.orgSession;
3268
- if (!postHandlerSession) {
3269
- throw new ApiError(
3270
- "Organization authentication did not issue a session",
3271
- 401
3272
- );
3273
- }
3274
- this.orgSession = postHandlerSession;
3275
- this.orgSessionOrgUuid = orgAuthInfo.orgUuid;
3276
- try {
3277
- return await this.fetch(endpoint, options);
3278
- } catch (retryError) {
3279
- this.orgSession = void 0;
3280
- this.orgSessionOrgUuid = void 0;
3281
- throw retryError;
3282
- }
3263
+ if (orgAuthInfo && !this.orgSession && !orgAuthRetry && this.orgAuthHandler) {
3264
+ await this.answerOrgAuthChallenge(orgAuthInfo);
3265
+ try {
3266
+ return await this.fetch(endpoint, options, true);
3267
+ } catch (retryError) {
3268
+ this.orgSession = void 0;
3269
+ this.orgSessionOrgUuid = void 0;
3270
+ throw retryError;
3283
3271
  }
3284
3272
  }
3285
3273
  }
@@ -3341,23 +3329,18 @@ ${formattedErrors}`, response.status);
3341
3329
  throw error;
3342
3330
  }
3343
3331
  }
3344
- async fetchRaw(endpoint, options, allowedErrorStatuses = []) {
3332
+ async fetchRaw(endpoint, options, allowedErrorStatuses = [], orgAuthRetry = false) {
3345
3333
  try {
3346
3334
  const headers = new Headers({
3347
3335
  ...options?.headers || {}
3348
3336
  });
3349
3337
  if (this.apiKey) {
3350
3338
  headers.set("Authorization", `Bearer ${this.apiKey}`);
3351
- } else if (this.isCrossDomain) {
3352
- const requestToken = getCookieValue("requestToken");
3353
- if (requestToken) {
3354
- headers.set("Authorization", `Bearer ${requestToken}`);
3355
- }
3356
3339
  }
3357
3340
  setOrgAuthHeader(headers, this.orgSession);
3358
3341
  const response = await this.fetchFunction(`${this.baseUrl}/api/v2/${endpoint}`, {
3359
3342
  ...options,
3360
- ...this.apiKey ? {} : { credentials: "include" },
3343
+ ...this.credentialsInit(),
3361
3344
  ...this.isCrossDomain ? { mode: "cors" } : {},
3362
3345
  headers
3363
3346
  });
@@ -3388,48 +3371,14 @@ ${formattedErrors}`, response.status);
3388
3371
  this.orgSession = void 0;
3389
3372
  this.orgSessionOrgUuid = void 0;
3390
3373
  }
3391
- if (orgAuthInfo && !this.orgSession) {
3392
- const requestCookieName = getRequestOrgCookieName(orgAuthInfo.cookieName);
3393
- const cachedOrgSession = requestCookieName ? getCookieValue(requestCookieName) : void 0;
3394
- if (cachedOrgSession) {
3395
- this.orgSession = cachedOrgSession;
3396
- this.orgSessionOrgUuid = orgAuthInfo.orgUuid;
3397
- try {
3398
- return await this.fetchRaw(endpoint, options, allowedErrorStatuses);
3399
- } catch (retryError) {
3400
- this.orgSession = void 0;
3401
- this.orgSessionOrgUuid = void 0;
3402
- throw retryError;
3403
- }
3404
- }
3405
- if (this.orgAuthHandler) {
3406
- if (!this.orgAuthInProgress) {
3407
- const handler = this.orgAuthHandler;
3408
- this.orgAuthInProgress = (async () => {
3409
- try {
3410
- await handler(orgAuthInfo);
3411
- } finally {
3412
- this.orgAuthInProgress = null;
3413
- }
3414
- })();
3415
- }
3416
- await this.orgAuthInProgress;
3417
- const postHandlerSession = (requestCookieName ? getCookieValue(requestCookieName) : void 0) ?? this.orgSession;
3418
- if (!postHandlerSession) {
3419
- throw new ApiError(
3420
- "Organization authentication did not issue a session",
3421
- 401
3422
- );
3423
- }
3424
- this.orgSession = postHandlerSession;
3425
- this.orgSessionOrgUuid = orgAuthInfo.orgUuid;
3426
- try {
3427
- return await this.fetchRaw(endpoint, options, allowedErrorStatuses);
3428
- } catch (retryError) {
3429
- this.orgSession = void 0;
3430
- this.orgSessionOrgUuid = void 0;
3431
- throw retryError;
3432
- }
3374
+ if (orgAuthInfo && !this.orgSession && !orgAuthRetry && this.orgAuthHandler) {
3375
+ await this.answerOrgAuthChallenge(orgAuthInfo);
3376
+ try {
3377
+ return await this.fetchRaw(endpoint, options, allowedErrorStatuses, true);
3378
+ } catch (retryError) {
3379
+ this.orgSession = void 0;
3380
+ this.orgSessionOrgUuid = void 0;
3381
+ throw retryError;
3433
3382
  }
3434
3383
  }
3435
3384
  }
@@ -3457,17 +3406,12 @@ ${formattedErrors}`, response.status);
3457
3406
  });
3458
3407
  if (this.apiKey) {
3459
3408
  headers.set("Authorization", `Bearer ${this.apiKey}`);
3460
- } else if (this.isCrossDomain) {
3461
- const requestToken = getCookieValue("requestToken");
3462
- if (requestToken) {
3463
- headers.set("Authorization", `Bearer ${requestToken}`);
3464
- }
3465
3409
  }
3466
3410
  setOrgAuthHeader(headers, this.orgSession);
3467
3411
  const fullUrl = `${this.baseUrl}/${path}`;
3468
3412
  const response = await this.fetchFunction(fullUrl, {
3469
3413
  ...options,
3470
- ...this.apiKey ? {} : { credentials: "include" },
3414
+ ...this.credentialsInit(),
3471
3415
  ...this.isCrossDomain ? { mode: "cors" } : {},
3472
3416
  headers
3473
3417
  });
@@ -4515,18 +4459,13 @@ var AuthApi = class extends BaseApiClient {
4515
4459
  }
4516
4460
  return await response.json();
4517
4461
  }
4518
- /** Request a cross-domain authentication token for single sign-on across domains. */
4462
+ /** @deprecated Browser continuity uses top-level /auth/continue navigation. */
4519
4463
  async requestCrossDomainToken() {
4520
- return this.fetch("auth/cross-domain-token", {
4521
- method: "POST"
4522
- });
4464
+ throw new Error("Use top-level /auth/continue navigation. CLI login uses OAuth with PKCE.");
4523
4465
  }
4524
- /** Exchange a cross-domain token for an authenticated session token. */
4525
- async exchangeToken(token) {
4526
- return this.fetch("auth/exchange-token", {
4527
- method: "POST",
4528
- body: JSON.stringify({ token })
4529
- });
4466
+ /** @deprecated Browser handoffs redeem only at the destination Next server. */
4467
+ async exchangeToken(_token) {
4468
+ throw new Error("Use top-level /auth/continue navigation. CLI login uses OAuth with PKCE.");
4530
4469
  }
4531
4470
  /** Exchange a global Account login for an opaque org-scoped session handle. */
4532
4471
  async exchangeSession(request) {
@@ -4707,9 +4646,17 @@ var AuthApi = class extends BaseApiClient {
4707
4646
  );
4708
4647
  }
4709
4648
  // ===== ORGANIZATION MEMBERSHIP METHODS =====
4710
- /** List all organizations the current account belongs to. */
4711
- async getMyOrganizations() {
4712
- return this.fetch("o/mine");
4649
+ /** A searchable page of the current account's organizations. */
4650
+ async getMyOrganizations(options) {
4651
+ const params = new URLSearchParams();
4652
+ if (options?.page) params.set("page", String(options.page));
4653
+ if (options?.pageSize) params.set("pageSize", String(options.pageSize));
4654
+ if (options?.canCreateWorkspace) params.set("canCreateWorkspace", "true");
4655
+ if (options?.search) params.set("search", options.search);
4656
+ if (options?.organizationSlug !== void 0)
4657
+ params.set("organizationSlug", options.organizationSlug);
4658
+ for (const uuid of options?.organizationUuids ?? []) params.append("organizationUuids", uuid);
4659
+ return this.fetch(`o/mine?${params}`);
4713
4660
  }
4714
4661
  // ===== CREDENTIAL CHANGE METHODS =====
4715
4662
  /**
@@ -7904,14 +7851,7 @@ var InquiriesApi = class extends BaseApiClient {
7904
7851
  }
7905
7852
  const queryString = params.toString();
7906
7853
  const url = queryString ? `inquiries/export/csv?${queryString}` : "inquiries/export/csv";
7907
- const response = await fetch(`${this.baseUrl}/api/v2/${url}`, {
7908
- method: "GET",
7909
- credentials: "include"
7910
- });
7911
- if (!response.ok) {
7912
- const error = await response.json();
7913
- throw new Error(error.detail || "Export failed");
7914
- }
7854
+ const response = await this.fetchRaw(url, { method: "GET" });
7915
7855
  return response.blob();
7916
7856
  }
7917
7857
  };
@@ -9479,8 +9419,12 @@ var OrgApi = class extends BaseApiClient {
9479
9419
  * figure — the caps belong to the organization, so `cap - oneWorkspace`
9480
9420
  * describes nothing.
9481
9421
  */
9482
- async getOrgWorkspaceUsage(orgIdOrUuid) {
9483
- return this.fetch(`o/${orgIdOrUuid}/usage/workspaces`);
9422
+ async getOrgWorkspaceUsage(orgIdOrUuid, options) {
9423
+ const params = new URLSearchParams();
9424
+ if (options?.page) params.set("page", String(options.page));
9425
+ if (options?.pageSize) params.set("pageSize", String(options.pageSize));
9426
+ if (options?.search) params.set("search", options.search);
9427
+ return this.fetch(`o/${orgIdOrUuid}/usage/workspaces?${params}`);
9484
9428
  }
9485
9429
  /**
9486
9430
  * List members of an organization.
@@ -9604,8 +9548,14 @@ var OrgApi = class extends BaseApiClient {
9604
9548
  * counts. Any org member may call it — members get the workspaces they
9605
9549
  * belong to, org:read holders get all of them.
9606
9550
  */
9607
- async getOrganizationWorkspaceSummaries(orgIdOrUuid) {
9608
- return this.fetch(`o/${orgIdOrUuid}/workspaces/summary`);
9551
+ async getOrganizationWorkspaceSummaries(orgIdOrUuid, options) {
9552
+ const params = new URLSearchParams();
9553
+ if (options?.page) params.set("page", String(options.page));
9554
+ if (options?.pageSize) params.set("pageSize", String(options.pageSize));
9555
+ if (options?.search) params.set("search", options.search);
9556
+ return this.fetch(
9557
+ `o/${orgIdOrUuid}/workspaces/summary?${params}`
9558
+ );
9609
9559
  }
9610
9560
  /**
9611
9561
  * Workspace-schema aggregates for one card, plus the caller's own member
@@ -10342,18 +10292,18 @@ function businessProfilePath(orgUuid, legalEntityUuid) {
10342
10292
  // src/api/oauth.ts
10343
10293
  function getOAuthPath(providerSlug, action) {
10344
10294
  if (providerSlug === "google_calendar") {
10345
- return `oauth/google/calendar/${action}`;
10295
+ return `api/v2/oauth/google/calendar/${action}`;
10346
10296
  }
10347
10297
  if (providerSlug === "gmail") {
10348
- return `oauth/google/gmail/${action}`;
10298
+ return `api/v2/oauth/google/gmail/${action}`;
10349
10299
  }
10350
10300
  if (providerSlug === "gdrive") {
10351
- return `oauth/google/drive/${action}`;
10301
+ return `api/v2/oauth/google/drive/${action}`;
10352
10302
  }
10353
10303
  if (providerSlug === "gsheets") {
10354
- return `oauth/google/sheets/${action}`;
10304
+ return `api/v2/oauth/google/sheets/${action}`;
10355
10305
  }
10356
- return `oauth/${providerSlug}/${action}`;
10306
+ return `api/v2/oauth/${providerSlug}/${action}`;
10357
10307
  }
10358
10308
  function buildAuthorizeQuery(options) {
10359
10309
  if (!options) return "";
@@ -13173,7 +13123,8 @@ var WorkflowsApi = class extends BaseApiClient {
13173
13123
  /**
13174
13124
  * Classify the prompts of a Workflow's draft revision.
13175
13125
  *
13176
- * A decision model reads each Task that has a prompt and reports which
13126
+ * A decision model reads each live Task with Workflow or Task instructions
13127
+ * and reports which
13177
13128
  * prompt classifications probably apply. Each call asks the model again.
13178
13129
  */
13179
13130
  async getWorkflowPromptClassifications(wid, workflowId) {
@@ -13549,22 +13500,32 @@ function planFields(options) {
13549
13500
  }
13550
13501
  return fields;
13551
13502
  }
13503
+ function workspaceDirectoryParams(options = {}) {
13504
+ const params = new URLSearchParams();
13505
+ if (options.page !== void 0) params.set("page", String(options.page));
13506
+ if (options.pageSize !== void 0) params.set("pageSize", String(options.pageSize));
13507
+ if (options.search) params.set("search", options.search);
13508
+ if (options.organizationUuid) params.set("organizationUuid", options.organizationUuid);
13509
+ for (const uuid of options.workspaceUuids ?? []) params.append("workspaceUuids", uuid);
13510
+ for (const id of options.workspaceIds ?? []) params.append("workspaceIds", String(id));
13511
+ return params;
13512
+ }
13552
13513
  var WorkspacesApi = class extends BaseApiClient {
13553
- /** List all workspaces accessible to the current user. */
13554
- async getWorkspaces() {
13555
- return this.fetch("w/");
13514
+ /** A bounded page of workspaces accessible to the current account. */
13515
+ async getWorkspaces(options) {
13516
+ return this.fetch(`w/?${workspaceDirectoryParams(options)}`);
13556
13517
  }
13557
- /**
13558
- * Compact rows for the workspaces a companion device could enter — the
13559
- * Lantern picker. Filtered by the same admission policy a device
13560
- * credential is gated by, without needing the device credential.
13561
- */
13562
- async getDeviceAdmissibleWorkspaces() {
13563
- return this.fetch("w/?can_use_device=1");
13518
+ /** A bounded page of companion-device candidates, with admission checked per row. */
13519
+ async getDeviceAdmissibleWorkspaces(options) {
13520
+ const params = workspaceDirectoryParams(options);
13521
+ params.set("can_use_device", "1");
13522
+ return this.fetch(`w/?${params}`);
13564
13523
  }
13565
- /** List all publicly visible workspaces. */
13566
- async getPublicWorkspaces() {
13567
- return this.fetch("w/public");
13524
+ /** A bounded page of publicly visible workspaces. */
13525
+ async getPublicWorkspaces(options) {
13526
+ return this.fetch(
13527
+ `w/public?${workspaceDirectoryParams(options)}`
13528
+ );
13568
13529
  }
13569
13530
  /** Get a single workspace by ID. */
13570
13531
  async getWorkspace(wid) {
@@ -13847,13 +13808,22 @@ var WorkspacesApi = class extends BaseApiClient {
13847
13808
  * @param scope - Export scope ("workflows" for all workflows only). Cannot be combined with workflowId.
13848
13809
  * @param exclude - Comma-separated entity categories to exclude (e.g. "channels")
13849
13810
  */
13850
- async exportWorkspace(wid, workflowId, scope, exclude) {
13811
+ async exportWorkspace(wid, workflowId, scope, exclude, options) {
13851
13812
  const searchParams = new URLSearchParams();
13852
13813
  if (workflowId !== void 0) searchParams.set("workflow_id", String(workflowId));
13853
13814
  if (scope !== void 0) searchParams.set("scope", scope);
13854
13815
  if (exclude !== void 0) searchParams.set("exclude", exclude);
13816
+ if (options?.revisionId !== void 0)
13817
+ searchParams.set("revision_id", String(options.revisionId));
13818
+ if (options?.revisionMode !== void 0) {
13819
+ searchParams.set("revision_mode", options.revisionMode);
13820
+ } else if (options?.revisionId === void 0) {
13821
+ searchParams.set("revision_mode", "active");
13822
+ }
13855
13823
  const qs = searchParams.toString();
13856
- return this.fetch(`w/${wid}/export${qs ? `?${qs}` : ""}`);
13824
+ const data = await this.fetch(`w/${wid}/export${qs ? `?${qs}` : ""}`);
13825
+ this.verifyExportSelection(data, workflowId, options);
13826
+ return data;
13857
13827
  }
13858
13828
  /** Preview the result of importing workspace configuration without applying changes.
13859
13829
  *
@@ -13912,15 +13882,60 @@ var WorkspacesApi = class extends BaseApiClient {
13912
13882
  * target workspace.
13913
13883
  */
13914
13884
  /** Download a workspace export ZIP (``export.json`` + file blobs). */
13915
- async exportWorkspaceZip(wid, workflowId, scope, exclude) {
13885
+ async exportWorkspaceZip(wid, workflowId, scope, exclude, options) {
13916
13886
  const searchParams = new URLSearchParams();
13917
13887
  if (workflowId !== void 0) searchParams.set("workflow_id", String(workflowId));
13918
13888
  if (scope !== void 0) searchParams.set("scope", scope);
13919
13889
  if (exclude !== void 0) searchParams.set("exclude", exclude);
13890
+ if (options?.revisionId !== void 0)
13891
+ searchParams.set("revision_id", String(options.revisionId));
13892
+ if (options?.revisionMode !== void 0) {
13893
+ searchParams.set("revision_mode", options.revisionMode);
13894
+ } else if (options?.revisionId === void 0) {
13895
+ searchParams.set("revision_mode", "active");
13896
+ }
13920
13897
  const qs = searchParams.toString();
13921
13898
  const response = await this.fetchRaw(`w/${wid}/export.zip${qs ? `?${qs}` : ""}`);
13899
+ if (options?.revisionId !== void 0 || options?.revisionMode === "all") {
13900
+ const version = response.headers.get("X-Gravityrail-Export-Version");
13901
+ const selection = response.headers.get("X-Gravityrail-Export-Selection");
13902
+ const selected = options?.revisionId !== void 0;
13903
+ if (version !== (selected ? "1.0" : "2.0") || selection !== (selected ? "selected" : "all") || selected && (workflowId === void 0 || !response.headers.get("X-Gravityrail-Export-Revision-Uuid")?.trim() || !response.headers.get("X-Gravityrail-Export-Workflow-Uuid")?.trim())) {
13904
+ try {
13905
+ await response.body?.cancel();
13906
+ } catch {
13907
+ }
13908
+ throw new Error(
13909
+ "Server did not return verified Workflow revision export headers. Request an explicit active snapshot or use a server that supports export provenance."
13910
+ );
13911
+ }
13912
+ }
13922
13913
  return response.arrayBuffer();
13923
13914
  }
13915
+ // Compatibility shape check only. The backend WorkspaceExportData
13916
+ // _validate_revision_archive owns full graph/publication invariants.
13917
+ verifyExportSelection(data, workflowId, options) {
13918
+ const hasUuid = (value) => typeof value === "string" && value.trim().length > 0;
13919
+ if (options?.revisionId !== void 0) {
13920
+ const revisions = data?.workflowRevisions;
13921
+ if (workflowId === void 0 || data?.version !== "1.0" || data.workflowRevisionSelection !== "selected" || !Array.isArray(revisions) || revisions.length !== 1) {
13922
+ throw new Error(
13923
+ "Server did not return the requested Workflow revision. Use a server that supports revision selection."
13924
+ );
13925
+ }
13926
+ if (!hasUuid(revisions[0]?.uuid) || !hasUuid(revisions[0]?.workflow?.uuid) || !hasUuid(data.workflows?.[0]?.uuid) || data.workflows?.length !== 1 || revisions[0]?.workflow?.uuid !== data.workflows[0]?.uuid) {
13927
+ throw new Error("Server export does not match the requested Workflow revision.");
13928
+ }
13929
+ } else if (options?.revisionMode === "all" && (data?.version !== "2.0" || data.workflowRevisionSelection !== "all" || !Array.isArray(data.workflowRevisions) || !Array.isArray(data.workflows) || data.workflows.some(
13930
+ (workflow) => !hasUuid(workflow?.uuid) || !data.workflowRevisions?.some(
13931
+ (revision) => hasUuid(revision?.uuid) && revision?.workflow?.uuid === workflow.uuid
13932
+ )
13933
+ ))) {
13934
+ throw new Error(
13935
+ "Server did not return all Workflow revisions. Request an explicit active snapshot or use a server that supports revision archives."
13936
+ );
13937
+ }
13938
+ }
13924
13939
  /** Import workspace configuration from exported JSON, or from a ZIP archive.
13925
13940
  * Pass ``archive`` (the ZIP from ``exportWorkspaceZip``) to restore file
13926
13941
  * contents. ``exportData`` may be omitted when the ZIP contains it.
@@ -17789,6 +17804,86 @@ var ChatInteractionController = class {
17789
17804
  this.pending = void 0;
17790
17805
  }
17791
17806
  };
17807
+
17808
+ // src/workflows/path.ts
17809
+ function getPathDefinition(path) {
17810
+ if (path.routing != null) {
17811
+ const routing = path.routing;
17812
+ if (typeof routing !== "object" || Array.isArray(routing)) return null;
17813
+ const fields = routing;
17814
+ if (fields.kind !== void 0 && fields.kind !== "outcome" || typeof fields.outcome !== "string" || !/^[a-z][a-z0-9_]{0,31}$/.test(fields.outcome) || Object.keys(fields).some((key) => key !== "kind" && key !== "outcome"))
17815
+ return null;
17816
+ return {
17817
+ availability: { kind: "always", expression: null, decisionPrompt: null },
17818
+ selection: {
17819
+ mode: "automatic",
17820
+ rule: "task_outcome",
17821
+ choicePrompt: null,
17822
+ condition: null,
17823
+ outcome: fields.outcome,
17824
+ policy: "matching_outcome",
17825
+ priority: null
17826
+ }
17827
+ };
17828
+ }
17829
+ const expression = path.celCondition?.trim() ? path.celCondition : null;
17830
+ const automatic = expression !== null && Boolean(path.required || path.autoNext);
17831
+ return {
17832
+ availability: {
17833
+ kind: expression === null ? "always" : "cel",
17834
+ expression,
17835
+ decisionPrompt: null
17836
+ },
17837
+ selection: {
17838
+ mode: automatic ? "automatic" : "choice",
17839
+ rule: automatic ? "when_available" : "choice",
17840
+ choicePrompt: automatic ? null : path.choicePrompt?.trim() || null,
17841
+ condition: null,
17842
+ outcome: null,
17843
+ policy: automatic ? "first_match" : "choose_one",
17844
+ priority: automatic ? path.order ?? 0 : null
17845
+ }
17846
+ };
17847
+ }
17848
+ function pathDraftFromStorage(path) {
17849
+ const definition = getPathDefinition(path);
17850
+ if (!definition || definition.selection.rule === "task_outcome") {
17851
+ throw new Error("This Path requires its dedicated routing editor.");
17852
+ }
17853
+ return {
17854
+ availabilityCondition: path.celCondition ?? "",
17855
+ selectionMode: definition.selection.mode,
17856
+ choicePrompt: path.choicePrompt ?? "",
17857
+ selectionPriority: path.order ?? 0
17858
+ };
17859
+ }
17860
+ function pathDraftToStorage(draft, original) {
17861
+ const initial = pathDraftFromStorage(original);
17862
+ const hasCondition = draft.availabilityCondition.trim() !== "";
17863
+ if (draft.selectionMode === "automatic" && !hasCondition) {
17864
+ throw new Error("Automatic Path selection requires a CEL condition.");
17865
+ }
17866
+ if (draft.availabilityCondition === initial.availabilityCondition && draft.selectionMode === initial.selectionMode && draft.choicePrompt === initial.choicePrompt && draft.selectionPriority === initial.selectionPriority)
17867
+ return original;
17868
+ const celCondition = draft.availabilityCondition === initial.availabilityCondition ? original.celCondition : draft.availabilityCondition.trim() ? draft.availabilityCondition : null;
17869
+ const choicePrompt = draft.choicePrompt === initial.choicePrompt ? original.choicePrompt : draft.choicePrompt.trim() ? draft.choicePrompt : null;
17870
+ let autoNext = original.autoNext;
17871
+ let required = original.required;
17872
+ if (draft.selectionMode === "automatic" && initial.selectionMode !== "automatic") {
17873
+ autoNext = true;
17874
+ } else if (draft.selectionMode === "choice" && (hasCondition || initial.availabilityCondition.trim() !== "") && Boolean(autoNext || required)) {
17875
+ autoNext = false;
17876
+ required = false;
17877
+ }
17878
+ return {
17879
+ ...original,
17880
+ celCondition,
17881
+ choicePrompt,
17882
+ autoNext,
17883
+ required,
17884
+ ...draft.selectionPriority === initial.selectionPriority ? {} : { order: draft.selectionPriority }
17885
+ };
17886
+ }
17792
17887
  // Annotate the CommonJS export names for ESM import in node:
17793
17888
  0 && (module.exports = {
17794
17889
  AGENT_NOTE_ORIGINS,
@@ -18113,6 +18208,7 @@ var ChatInteractionController = class {
18113
18208
  getFeaturesByCategory,
18114
18209
  getFeaturesByVisibility,
18115
18210
  getMissingDependencies,
18211
+ getPathDefinition,
18116
18212
  getResourceMetadata,
18117
18213
  getRevisionState,
18118
18214
  getTTSProvider,
@@ -18130,6 +18226,8 @@ var ChatInteractionController = class {
18130
18226
  isSMSDeliveryFailureStatus,
18131
18227
  parseExperimentStatCount,
18132
18228
  parseOrgAuthChallenge,
18229
+ pathDraftFromStorage,
18230
+ pathDraftToStorage,
18133
18231
  requiresAssistantParticipant,
18134
18232
  usesBuiltinAssistant,
18135
18233
  validateFeatureDependencies