@sylphx/sdk 0.3.2 → 0.3.4

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
@@ -49,7 +49,6 @@ __export(index_exports, {
49
49
  WorkersClient: () => WorkersClient,
50
50
  acceptAllConsents: () => acceptAllConsents,
51
51
  acceptOrganizationInvitation: () => acceptOrganizationInvitation,
52
- addCustomDomain: () => addCustomDomain,
53
52
  batchIndex: () => batchIndex,
54
53
  canDeleteOrganization: () => canDeleteOrganization,
55
54
  canManageMembers: () => canManageMembers,
@@ -184,7 +183,6 @@ __export(index_exports, {
184
183
  kvZrange: () => kvZrange,
185
184
  leaveOrganization: () => leaveOrganization,
186
185
  linkAnonymousConsents: () => linkAnonymousConsents,
187
- listCustomDomains: () => listCustomDomains,
188
186
  listEnvVars: () => listEnvVars,
189
187
  listScheduledEmails: () => listScheduledEmails,
190
188
  listSecretKeys: () => listSecretKeys,
@@ -200,7 +198,6 @@ __export(index_exports, {
200
198
  regenerateReferralCode: () => regenerateReferralCode,
201
199
  registerPush: () => registerPush,
202
200
  registerPushServiceWorker: () => registerPushServiceWorker,
203
- removeCustomDomain: () => removeCustomDomain,
204
201
  removeOrganizationMember: () => removeOrganizationMember,
205
202
  replayWebhookDelivery: () => replayWebhookDelivery,
206
203
  rescheduleEmail: () => rescheduleEmail,
@@ -251,9 +248,7 @@ __export(index_exports, {
251
248
  module.exports = __toCommonJS(index_exports);
252
249
 
253
250
  // src/constants.ts
254
- var DEFAULT_PLATFORM_URL = "https://sylphx.com";
255
- var SDK_API_PATH = `/api/v1`;
256
- var SDK_API_PATH_NEW = `/v1`;
251
+ var SDK_API_PATH = `/v1`;
257
252
  var DEFAULT_SDK_API_HOST = "api.sylphx.com";
258
253
  var SDK_VERSION = "0.1.0";
259
254
  var SDK_PLATFORM = typeof window !== "undefined" ? "browser" : typeof process !== "undefined" && process.versions?.node ? "node" : "unknown";
@@ -745,7 +740,7 @@ function httpStatusToErrorCode(status) {
745
740
  return status >= 500 ? "INTERNAL_SERVER_ERROR" : "BAD_REQUEST";
746
741
  }
747
742
  }
748
- var REF_PATTERN = /^[a-z0-9]{16}$/;
743
+ var REF_PATTERN = /^[a-z0-9]{12}$/;
749
744
  function createConfig(input) {
750
745
  let secretKey;
751
746
  if (input.secretKey) {
@@ -761,32 +756,18 @@ function createConfig(input) {
761
756
  }
762
757
  secretKey = result.sanitizedKey;
763
758
  }
764
- if (input.ref !== void 0) {
765
- const trimmedRef = input.ref.trim();
766
- if (!REF_PATTERN.test(trimmedRef)) {
767
- throw new SylphxError(
768
- `[Sylphx] Invalid project ref format: "${input.ref}". Expected a 16-character lowercase alphanumeric string (e.g. "abc123def456ghij"). Get your ref from Platform Console \u2192 Projects \u2192 Your Project \u2192 Overview.`,
769
- { code: "BAD_REQUEST" }
770
- );
771
- }
772
- }
773
- let platformUrl;
774
- let apiBasePath;
775
- if (input.platformUrl) {
776
- platformUrl = input.platformUrl.trim();
777
- apiBasePath = SDK_API_PATH;
778
- } else if (input.ref) {
779
- platformUrl = `https://${input.ref.trim()}.${DEFAULT_SDK_API_HOST}`;
780
- apiBasePath = SDK_API_PATH_NEW;
781
- } else {
782
- platformUrl = DEFAULT_PLATFORM_URL;
783
- apiBasePath = SDK_API_PATH;
759
+ const trimmedRef = input.ref.trim();
760
+ if (!REF_PATTERN.test(trimmedRef)) {
761
+ throw new SylphxError(
762
+ `[Sylphx] Invalid project ref format: "${input.ref}". Expected a 12-character lowercase alphanumeric string (e.g. "abc123def456"). Get your ref from Platform Console \u2192 Projects \u2192 Your Project \u2192 Overview.`,
763
+ { code: "BAD_REQUEST" }
764
+ );
784
765
  }
766
+ const baseUrl = `https://${trimmedRef}.${DEFAULT_SDK_API_HOST}${SDK_API_PATH}`;
785
767
  return Object.freeze({
786
768
  secretKey,
787
- platformUrl,
788
- ref: input.ref,
789
- apiBasePath,
769
+ ref: trimmedRef,
770
+ baseUrl,
790
771
  accessToken: input.accessToken
791
772
  });
792
773
  }
@@ -794,7 +775,7 @@ function withToken(config, accessToken) {
794
775
  return Object.freeze({
795
776
  ...config,
796
777
  accessToken
797
- // Preserve apiBasePath and ref from original config
778
+ // Preserve baseUrl and ref from original config
798
779
  });
799
780
  }
800
781
  function buildHeaders(config) {
@@ -810,9 +791,9 @@ function buildHeaders(config) {
810
791
  return headers;
811
792
  }
812
793
  function buildApiUrl(config, path) {
813
- const base = config.platformUrl.replace(/\/$/, "");
794
+ const base = config.baseUrl.replace(/\/$/, "");
814
795
  const cleanPath = path.startsWith("/") ? path : `/${path}`;
815
- return `${base}${config.apiBasePath ?? SDK_API_PATH}${cleanPath}`;
796
+ return `${base}${cleanPath}`;
816
797
  }
817
798
  async function callApi(config, path, options = {}) {
818
799
  const {
@@ -1366,7 +1347,7 @@ function createRetryMiddleware(retryConfig) {
1366
1347
  function validateClientConfig(config) {
1367
1348
  return {
1368
1349
  secretKey: validateAndSanitizeSecretKey(config.secretKey),
1369
- baseUrl: (config.platformUrl || DEFAULT_PLATFORM_URL).trim()
1350
+ baseUrl: (config.platformUrl || `https://${DEFAULT_SDK_API_HOST}`).trim()
1370
1351
  };
1371
1352
  }
1372
1353
  function createRestClient(config) {
@@ -1492,7 +1473,7 @@ async function verifyTwoFactor(config, userId, code) {
1492
1473
  });
1493
1474
  }
1494
1475
  async function introspectToken(config, token, tokenTypeHint) {
1495
- const response = await fetch(`${config.platformUrl}/api/v1/auth/introspect`, {
1476
+ const response = await fetch(buildApiUrl(config, "/auth/introspect"), {
1496
1477
  method: "POST",
1497
1478
  headers: { "Content-Type": "application/json" },
1498
1479
  body: JSON.stringify({
@@ -1507,7 +1488,7 @@ async function introspectToken(config, token, tokenTypeHint) {
1507
1488
  return response.json();
1508
1489
  }
1509
1490
  async function revokeToken(config, token, options) {
1510
- await fetch(`${config.platformUrl}/api/v1/auth/revoke`, {
1491
+ await fetch(buildApiUrl(config, "/auth/revoke"), {
1511
1492
  method: "POST",
1512
1493
  headers: { "Content-Type": "application/json" },
1513
1494
  body: JSON.stringify({
@@ -1658,7 +1639,7 @@ function createTracker(config, defaultAnonymousId) {
1658
1639
 
1659
1640
  // src/ai.ts
1660
1641
  async function chat(config, input) {
1661
- const response = await fetch(`${config.platformUrl}/api/v1/chat/completions`, {
1642
+ const response = await fetch(buildApiUrl(config, "/chat/completions"), {
1662
1643
  method: "POST",
1663
1644
  headers: {
1664
1645
  ...buildHeaders(config),
@@ -1706,7 +1687,7 @@ async function chat(config, input) {
1706
1687
  function chatStream(config, input) {
1707
1688
  return {
1708
1689
  [Symbol.asyncIterator]: async function* () {
1709
- const response = await fetch(`${config.platformUrl}/api/v1/chat/completions`, {
1690
+ const response = await fetch(buildApiUrl(config, "/chat/completions"), {
1710
1691
  method: "POST",
1711
1692
  headers: {
1712
1693
  ...buildHeaders(config),
@@ -1778,7 +1759,7 @@ function chatStream(config, input) {
1778
1759
  };
1779
1760
  }
1780
1761
  async function embed(config, input) {
1781
- const response = await fetch(`${config.platformUrl}/api/v1/embeddings`, {
1762
+ const response = await fetch(buildApiUrl(config, "/embeddings"), {
1782
1763
  method: "POST",
1783
1764
  headers: {
1784
1765
  ...buildHeaders(config),
@@ -1908,7 +1889,7 @@ async function uploadFile(config, file, options) {
1908
1889
  let lastError = null;
1909
1890
  for (let attempt = 0; attempt <= UPLOAD_RETRY_CONFIG.maxRetries; attempt++) {
1910
1891
  try {
1911
- tokenResponse = await fetch(`${config.platformUrl}/api/v1/storage/upload`, {
1892
+ tokenResponse = await fetch(buildApiUrl(config, "/storage/upload"), {
1912
1893
  method: "POST",
1913
1894
  headers: buildHeaders(config),
1914
1895
  body: JSON.stringify({
@@ -2636,7 +2617,7 @@ async function getConsentHistory(config, input) {
2636
2617
  userId: input.userId,
2637
2618
  anonymousId: input.anonymousId,
2638
2619
  limit: input.limit?.toString(),
2639
- offset: input.offset?.toString()
2620
+ cursor: input.cursor
2640
2621
  }
2641
2622
  });
2642
2623
  }
@@ -3209,27 +3190,6 @@ async function deleteEnvVar(config, envId, key) {
3209
3190
  { method: "DELETE" }
3210
3191
  );
3211
3192
  }
3212
- async function listCustomDomains(config, envId) {
3213
- const result = await callApi(
3214
- config,
3215
- `/sdk/deploy/domains/${encodeURIComponent(envId)}`,
3216
- { method: "GET" }
3217
- );
3218
- return result.domains;
3219
- }
3220
- async function addCustomDomain(config, envId, request) {
3221
- return callApi(config, `/sdk/deploy/domains/${encodeURIComponent(envId)}`, {
3222
- method: "POST",
3223
- body: request
3224
- });
3225
- }
3226
- async function removeCustomDomain(config, envId, domain) {
3227
- return callApi(
3228
- config,
3229
- `/sdk/deploy/domains/${encodeURIComponent(envId)}/${encodeURIComponent(domain)}`,
3230
- { method: "DELETE" }
3231
- );
3232
- }
3233
3193
 
3234
3194
  // src/monitoring.ts
3235
3195
  function errorToExceptionValue(error) {
@@ -3289,13 +3249,67 @@ async function captureMessage(config, message, options = {}) {
3289
3249
  }
3290
3250
 
3291
3251
  // src/sandbox.ts
3292
- var DEFAULT_IMAGE = "registry.sylphx.com/library/exec-server:latest";
3252
+ var SandboxFiles = class {
3253
+ constructor(endpoint, token) {
3254
+ this.endpoint = endpoint;
3255
+ this.token = token;
3256
+ }
3257
+ authHeader() {
3258
+ return { Authorization: `Bearer ${this.token}` };
3259
+ }
3260
+ /** Write a file to the sandbox filesystem. */
3261
+ async write(path, content, encoding = "utf8") {
3262
+ const contentStr = Buffer.isBuffer(content) ? content.toString("base64") : content;
3263
+ const effectiveEncoding = Buffer.isBuffer(content) ? "base64" : encoding;
3264
+ const res = await fetch(`${this.endpoint}/files`, {
3265
+ method: "POST",
3266
+ headers: { ...this.authHeader(), "Content-Type": "application/json" },
3267
+ body: JSON.stringify({ path, content: contentStr, encoding: effectiveEncoding })
3268
+ });
3269
+ if (!res.ok) throw new Error(`files.write failed: ${await res.text()}`);
3270
+ }
3271
+ /** Read a file from the sandbox filesystem. Returns content as string. */
3272
+ async read(path) {
3273
+ const res = await fetch(`${this.endpoint}/files?path=${encodeURIComponent(path)}`, {
3274
+ headers: this.authHeader()
3275
+ });
3276
+ if (!res.ok) throw new Error(`files.read failed: ${await res.text()}`);
3277
+ const data = await res.json();
3278
+ return data.content;
3279
+ }
3280
+ /** Delete a file from the sandbox filesystem. */
3281
+ async delete(path) {
3282
+ const res = await fetch(`${this.endpoint}/files?path=${encodeURIComponent(path)}`, {
3283
+ method: "DELETE",
3284
+ headers: this.authHeader()
3285
+ });
3286
+ if (!res.ok) throw new Error(`files.delete failed: ${await res.text()}`);
3287
+ }
3288
+ /** List files in a directory. */
3289
+ async list(path = "/") {
3290
+ const res = await fetch(`${this.endpoint}/list?path=${encodeURIComponent(path)}`, {
3291
+ headers: this.authHeader()
3292
+ });
3293
+ if (!res.ok) throw new Error(`files.list failed: ${await res.text()}`);
3294
+ const data = await res.json();
3295
+ return data.files;
3296
+ }
3297
+ };
3293
3298
  var SandboxClient = class _SandboxClient {
3294
3299
  id;
3295
3300
  config;
3296
- constructor(id, config) {
3301
+ /** Public endpoint from Platform (may be null for sandboxes from pool pre-v2) */
3302
+ endpoint;
3303
+ /** Per-sandbox JWT for direct exec-server auth */
3304
+ token;
3305
+ /** File operations (direct to exec-server) */
3306
+ files;
3307
+ constructor(id, config, endpoint, token) {
3297
3308
  this.id = id;
3298
3309
  this.config = config;
3310
+ this.endpoint = endpoint;
3311
+ this.token = token;
3312
+ this.files = endpoint && token ? new SandboxFiles(endpoint, token) : null;
3299
3313
  }
3300
3314
  // ---------------------------------------------------------------------------
3301
3315
  // Factory
@@ -3303,130 +3317,153 @@ var SandboxClient = class _SandboxClient {
3303
3317
  /**
3304
3318
  * Create a new sandbox.
3305
3319
  *
3306
- * The sandbox pod starts asynchronously it will be in `starting` status
3307
- * after creation. File/run operations will block until the pod is ready.
3308
- *
3309
- * @param config - Sylphx config with a secret key (sk_*) and project ref
3310
- * @param options - Sandbox creation options
3320
+ * Platform provisions the K8s pod, waits for readiness, and returns
3321
+ * { endpoint, token } once the sandbox is fully ready to accept traffic.
3322
+ * No client-side polling required.
3311
3323
  */
3312
3324
  static async create(config, options) {
3313
- const record = await callApi(config, `/sandboxes`, {
3325
+ const record = await callApi(config, "/sandboxes", {
3314
3326
  method: "POST",
3315
3327
  body: {
3316
- image: options?.image ?? DEFAULT_IMAGE,
3328
+ image: options?.image,
3317
3329
  idleTimeoutMs: options?.idleTimeoutMs ?? 3e5,
3318
3330
  resources: options?.resources,
3319
3331
  env: options?.env,
3320
3332
  storage: options?.storageGi !== void 0 ? { enabled: true, sizeGi: options.storageGi } : void 0
3321
3333
  }
3322
3334
  });
3323
- return new _SandboxClient(record.id, config);
3335
+ return new _SandboxClient(record.id, config, record.endpoint, record.token);
3324
3336
  }
3325
3337
  /**
3326
3338
  * Reconnect to an existing sandbox by ID.
3327
- *
3328
- * Use this to resume operations on a sandbox created in a previous request.
3339
+ * Fetches the current status to get the endpoint + token.
3329
3340
  */
3330
- static fromId(config, sandboxId) {
3331
- return new _SandboxClient(sandboxId, config);
3341
+ static async fromId(config, sandboxId) {
3342
+ const record = await callApi(config, `/sandboxes/${sandboxId}`, {
3343
+ method: "GET"
3344
+ });
3345
+ return new _SandboxClient(record.id, config, record.endpoint, record.token);
3332
3346
  }
3333
3347
  // ---------------------------------------------------------------------------
3334
3348
  // Lifecycle
3335
3349
  // ---------------------------------------------------------------------------
3336
- /**
3337
- * Get the current status of this sandbox.
3338
- */
3339
3350
  async getStatus() {
3340
3351
  return callApi(this.config, `/sandboxes/${this.id}`, { method: "GET" });
3341
3352
  }
3342
- /**
3343
- * Terminate the sandbox immediately.
3344
- *
3345
- * Deletes the K8s Pod and Service. PVC (storage) is preserved for reuse.
3346
- * This operation is idempotent — safe to call multiple times.
3347
- */
3348
3353
  async terminate() {
3349
3354
  await callApi(this.config, `/sandboxes/${this.id}`, { method: "DELETE" });
3350
3355
  }
3351
3356
  // ---------------------------------------------------------------------------
3352
- // File Operations
3357
+ // Exec — SSE streaming (primary)
3353
3358
  // ---------------------------------------------------------------------------
3354
3359
  /**
3355
- * Write a file to the sandbox filesystem.
3360
+ * Execute a command and stream output as async iterable events.
3356
3361
  *
3357
- * @param path - Absolute path inside the sandbox (e.g. '/workspace/file.py')
3358
- * @param content - File content as string or Buffer
3359
- * @param encoding - 'utf8' (default) or 'base64' for binary files
3360
- */
3361
- async writeFile(path, content, encoding = "utf8") {
3362
- const contentStr = Buffer.isBuffer(content) ? content.toString("base64") : content;
3363
- const effectiveEncoding = Buffer.isBuffer(content) ? "base64" : encoding;
3364
- await callApi(this.config, `/sandboxes/${this.id}/files`, {
3365
- method: "POST",
3366
- body: { path, content: contentStr, encoding: effectiveEncoding }
3367
- });
3368
- }
3369
- /**
3370
- * Read a file from the sandbox filesystem.
3362
+ * Uses Server-Sent Events (SSE) for real-time stdout/stderr streaming.
3363
+ * Communicates DIRECTLY with exec-server (Platform not in data path).
3371
3364
  *
3372
- * @param path - Absolute path inside the sandbox
3373
- * @returns File content as a string
3374
- */
3375
- async readFile(path) {
3376
- const result = await callApi(this.config, `/sandboxes/${this.id}/files`, {
3377
- method: "GET",
3378
- query: { path }
3379
- });
3380
- return result.content;
3381
- }
3382
- /**
3383
- * Delete a file from the sandbox filesystem.
3384
- *
3385
- * @param path - Absolute path inside the sandbox
3365
+ * @example
3366
+ * ```typescript
3367
+ * for await (const event of sandbox.exec(['npm', 'install'])) {
3368
+ * if (event.type === 'stdout') process.stdout.write(event.data)
3369
+ * if (event.type === 'exit') console.log('Done:', event.exitCode)
3370
+ * }
3371
+ * ```
3386
3372
  */
3387
- async deleteFile(path) {
3388
- await callApi(this.config, `/sandboxes/${this.id}/files`, {
3389
- method: "DELETE",
3390
- query: { path }
3373
+ async *exec(command, options) {
3374
+ this.assertDirect();
3375
+ const res = await fetch(`${this.endpoint}/exec/stream`, {
3376
+ method: "POST",
3377
+ headers: {
3378
+ Authorization: `Bearer ${this.token}`,
3379
+ "Content-Type": "application/json"
3380
+ },
3381
+ body: JSON.stringify({ command, ...options })
3391
3382
  });
3383
+ if (!res.ok) {
3384
+ throw new Error(`exec failed (${res.status}): ${await res.text()}`);
3385
+ }
3386
+ if (!res.body) throw new Error("exec: no response body");
3387
+ const decoder = new TextDecoder();
3388
+ const reader = res.body.getReader();
3389
+ let buffer = "";
3390
+ try {
3391
+ while (true) {
3392
+ const { done, value } = await reader.read();
3393
+ if (done) break;
3394
+ buffer += decoder.decode(value, { stream: true });
3395
+ const lines = buffer.split("\n");
3396
+ buffer = lines.pop() ?? "";
3397
+ for (const line of lines) {
3398
+ if (line.startsWith("data: ")) {
3399
+ try {
3400
+ const event = JSON.parse(line.slice(6));
3401
+ yield event;
3402
+ if (event.type === "exit" || event.type === "error") return;
3403
+ } catch {
3404
+ }
3405
+ }
3406
+ }
3407
+ }
3408
+ } finally {
3409
+ reader.releaseLock();
3410
+ }
3392
3411
  }
3393
3412
  /**
3394
- * List files in a directory.
3413
+ * Execute a command and collect all output (non-streaming).
3414
+ * Convenience wrapper over exec() for simple use cases.
3395
3415
  *
3396
- * @param path - Directory path inside the sandbox (default: '/')
3397
- * @returns Array of file/directory paths
3416
+ * For long-running commands, prefer exec() to stream output incrementally.
3398
3417
  */
3399
- async listFiles(path = "/") {
3400
- const result = await callApi(this.config, `/sandboxes/${this.id}/list`, {
3401
- method: "GET",
3402
- query: { path }
3403
- });
3404
- return result.files;
3418
+ async run(command, options) {
3419
+ let stdout = "";
3420
+ let stderr = "";
3421
+ let exitCode = 1;
3422
+ let durationMs = 0;
3423
+ for await (const event of this.exec(command, options)) {
3424
+ if (event.type === "stdout") stdout += event.data;
3425
+ else if (event.type === "stderr") stderr += event.data;
3426
+ else if (event.type === "exit") {
3427
+ exitCode = event.exitCode;
3428
+ durationMs = event.durationMs;
3429
+ }
3430
+ }
3431
+ return { stdout, stderr, exitCode, durationMs };
3405
3432
  }
3406
3433
  // ---------------------------------------------------------------------------
3407
- // Command Execution
3434
+ // PTY — Interactive terminal (WebSocket)
3408
3435
  // ---------------------------------------------------------------------------
3409
3436
  /**
3410
- * Run a command inside the sandbox.
3437
+ * Open an interactive PTY session (WebSocket).
3411
3438
  *
3412
- * The command runs synchronously inside the exec pod and returns when complete.
3413
- *
3414
- * @param command - Full command + args as array (e.g. ['python3', 'script.py'])
3415
- * @param options - Optional cwd, env, timeout, stdin
3416
- * @returns { stdout, stderr, exitCode, durationMs }
3439
+ * Returns a WebSocket connected to a bash shell in the sandbox.
3440
+ * Token is passed as a query param (WebSocket doesn't support custom headers in browsers).
3417
3441
  *
3418
3442
  * @example
3419
3443
  * ```typescript
3420
- * const { stdout, exitCode } = await sandbox.run(['python3', '-c', 'print(1+1)'])
3421
- * console.log(stdout) // "2\n"
3422
- * console.log(exitCode) // 0
3444
+ * const ws = await sandbox.pty()
3445
+ * ws.on('message', (data) => process.stdout.write(JSON.parse(data).data))
3446
+ * ws.send(JSON.stringify({ type: 'input', data: 'ls -la\n' }))
3447
+ * ws.send(JSON.stringify({ type: 'resize', cols: 120, rows: 40 }))
3423
3448
  * ```
3424
3449
  */
3425
- async run(command, options) {
3426
- return callApi(this.config, `/sandboxes/${this.id}/run`, {
3427
- method: "POST",
3428
- body: { command, ...options }
3429
- });
3450
+ pty() {
3451
+ this.assertDirect();
3452
+ const wsEndpoint = this.endpoint.replace(/^https:\/\//, "wss://").replace(
3453
+ /^http:\/\//,
3454
+ "ws://"
3455
+ );
3456
+ return new WebSocket(`${wsEndpoint}/pty?token=${encodeURIComponent(this.token)}`);
3457
+ }
3458
+ // ---------------------------------------------------------------------------
3459
+ // Private
3460
+ // ---------------------------------------------------------------------------
3461
+ assertDirect() {
3462
+ if (!this.endpoint || !this.token) {
3463
+ throw new Error(
3464
+ "Sandbox endpoint/token not available. This sandbox was created with an older SDK version or does not have a public endpoint."
3465
+ );
3466
+ }
3430
3467
  }
3431
3468
  };
3432
3469
 
@@ -3648,7 +3685,6 @@ function sleep2(ms) {
3648
3685
  WorkersClient,
3649
3686
  acceptAllConsents,
3650
3687
  acceptOrganizationInvitation,
3651
- addCustomDomain,
3652
3688
  batchIndex,
3653
3689
  canDeleteOrganization,
3654
3690
  canManageMembers,
@@ -3783,7 +3819,6 @@ function sleep2(ms) {
3783
3819
  kvZrange,
3784
3820
  leaveOrganization,
3785
3821
  linkAnonymousConsents,
3786
- listCustomDomains,
3787
3822
  listEnvVars,
3788
3823
  listScheduledEmails,
3789
3824
  listSecretKeys,
@@ -3799,7 +3834,6 @@ function sleep2(ms) {
3799
3834
  regenerateReferralCode,
3800
3835
  registerPush,
3801
3836
  registerPushServiceWorker,
3802
- removeCustomDomain,
3803
3837
  removeOrganizationMember,
3804
3838
  replayWebhookDelivery,
3805
3839
  rescheduleEmail,