@blaxel/core 0.2.86 → 0.2.87-dev.173

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 (108) hide show
  1. package/README.md +37 -2
  2. package/dist/cjs/.tsbuildinfo +1 -1
  3. package/dist/cjs/authentication/credentials.js +11 -1
  4. package/dist/cjs/authentication/index.js +3 -1
  5. package/dist/cjs/client/sdk.gen.js +63 -12
  6. package/dist/cjs/common/credentials.test.js +71 -0
  7. package/dist/cjs/common/errors.js +15 -0
  8. package/dist/cjs/common/h2fetch.js +101 -50
  9. package/dist/cjs/common/h2pool.js +9 -0
  10. package/dist/cjs/common/pagination.js +87 -0
  11. package/dist/cjs/common/pagination.test.js +62 -0
  12. package/dist/cjs/common/settings.js +41 -3
  13. package/dist/cjs/common/settings.test.js +12 -3
  14. package/dist/cjs/drive/index.js +39 -3
  15. package/dist/cjs/index.js +1 -0
  16. package/dist/cjs/jobs/jobs.js +42 -9
  17. package/dist/cjs/sandbox/client/sdk.gen.js +1 -1
  18. package/dist/cjs/sandbox/preview.js +8 -3
  19. package/dist/cjs/sandbox/sandbox.js +41 -4
  20. package/dist/cjs/types/authentication/credentials.d.ts +9 -0
  21. package/dist/cjs/types/client/sdk.gen.d.ts +34 -19
  22. package/dist/cjs/types/client/types.gen.d.ts +704 -22
  23. package/dist/cjs/types/common/credentials.test.d.ts +1 -0
  24. package/dist/cjs/types/common/errors.d.ts +10 -0
  25. package/dist/cjs/types/common/h2fetch.d.ts +9 -4
  26. package/dist/cjs/types/common/pagination.d.ts +35 -0
  27. package/dist/cjs/types/common/pagination.test.d.ts +1 -0
  28. package/dist/cjs/types/common/settings.d.ts +9 -0
  29. package/dist/cjs/types/drive/index.d.ts +35 -4
  30. package/dist/cjs/types/index.d.ts +1 -0
  31. package/dist/cjs/types/jobs/jobs.d.ts +33 -3
  32. package/dist/cjs/types/sandbox/client/sdk.gen.d.ts +1 -1
  33. package/dist/cjs/types/sandbox/client/types.gen.d.ts +24 -0
  34. package/dist/cjs/types/sandbox/preview.d.ts +2 -2
  35. package/dist/cjs/types/sandbox/sandbox.d.ts +36 -2
  36. package/dist/cjs/types/volume/index.d.ts +37 -4
  37. package/dist/cjs/volume/index.js +41 -3
  38. package/dist/cjs-browser/.tsbuildinfo +1 -1
  39. package/dist/cjs-browser/authentication/credentials.js +11 -1
  40. package/dist/cjs-browser/authentication/index.js +3 -1
  41. package/dist/cjs-browser/client/sdk.gen.js +63 -12
  42. package/dist/cjs-browser/common/credentials.test.js +71 -0
  43. package/dist/cjs-browser/common/errors.js +15 -0
  44. package/dist/cjs-browser/common/pagination.js +87 -0
  45. package/dist/cjs-browser/common/pagination.test.js +62 -0
  46. package/dist/cjs-browser/common/settings.js +41 -3
  47. package/dist/cjs-browser/common/settings.test.js +12 -3
  48. package/dist/cjs-browser/drive/index.js +39 -3
  49. package/dist/cjs-browser/index.js +1 -0
  50. package/dist/cjs-browser/jobs/jobs.js +42 -9
  51. package/dist/cjs-browser/sandbox/client/sdk.gen.js +1 -1
  52. package/dist/cjs-browser/sandbox/preview.js +8 -3
  53. package/dist/cjs-browser/sandbox/sandbox.js +41 -4
  54. package/dist/cjs-browser/types/authentication/credentials.d.ts +9 -0
  55. package/dist/cjs-browser/types/client/sdk.gen.d.ts +34 -19
  56. package/dist/cjs-browser/types/client/types.gen.d.ts +704 -22
  57. package/dist/cjs-browser/types/common/credentials.test.d.ts +1 -0
  58. package/dist/cjs-browser/types/common/errors.d.ts +10 -0
  59. package/dist/cjs-browser/types/common/h2fetch.d.ts +9 -4
  60. package/dist/cjs-browser/types/common/pagination.d.ts +35 -0
  61. package/dist/cjs-browser/types/common/pagination.test.d.ts +1 -0
  62. package/dist/cjs-browser/types/common/settings.d.ts +9 -0
  63. package/dist/cjs-browser/types/drive/index.d.ts +35 -4
  64. package/dist/cjs-browser/types/index.d.ts +1 -0
  65. package/dist/cjs-browser/types/jobs/jobs.d.ts +33 -3
  66. package/dist/cjs-browser/types/sandbox/client/sdk.gen.d.ts +1 -1
  67. package/dist/cjs-browser/types/sandbox/client/types.gen.d.ts +24 -0
  68. package/dist/cjs-browser/types/sandbox/preview.d.ts +2 -2
  69. package/dist/cjs-browser/types/sandbox/sandbox.d.ts +36 -2
  70. package/dist/cjs-browser/types/volume/index.d.ts +37 -4
  71. package/dist/cjs-browser/volume/index.js +41 -3
  72. package/dist/esm/.tsbuildinfo +1 -1
  73. package/dist/esm/authentication/credentials.js +9 -0
  74. package/dist/esm/authentication/index.js +4 -2
  75. package/dist/esm/client/sdk.gen.js +57 -9
  76. package/dist/esm/common/credentials.test.js +69 -0
  77. package/dist/esm/common/errors.js +13 -0
  78. package/dist/esm/common/h2fetch.js +101 -50
  79. package/dist/esm/common/h2pool.js +9 -0
  80. package/dist/esm/common/pagination.js +83 -0
  81. package/dist/esm/common/pagination.test.js +60 -0
  82. package/dist/esm/common/settings.js +41 -3
  83. package/dist/esm/common/settings.test.js +12 -3
  84. package/dist/esm/drive/index.js +39 -3
  85. package/dist/esm/index.js +1 -0
  86. package/dist/esm/jobs/jobs.js +42 -9
  87. package/dist/esm/sandbox/client/sdk.gen.js +1 -1
  88. package/dist/esm/sandbox/preview.js +8 -3
  89. package/dist/esm/sandbox/sandbox.js +41 -4
  90. package/dist/esm/volume/index.js +41 -3
  91. package/dist/esm-browser/.tsbuildinfo +1 -1
  92. package/dist/esm-browser/authentication/credentials.js +9 -0
  93. package/dist/esm-browser/authentication/index.js +4 -2
  94. package/dist/esm-browser/client/sdk.gen.js +57 -9
  95. package/dist/esm-browser/common/credentials.test.js +69 -0
  96. package/dist/esm-browser/common/errors.js +13 -0
  97. package/dist/esm-browser/common/pagination.js +83 -0
  98. package/dist/esm-browser/common/pagination.test.js +60 -0
  99. package/dist/esm-browser/common/settings.js +41 -3
  100. package/dist/esm-browser/common/settings.test.js +12 -3
  101. package/dist/esm-browser/drive/index.js +39 -3
  102. package/dist/esm-browser/index.js +1 -0
  103. package/dist/esm-browser/jobs/jobs.js +42 -9
  104. package/dist/esm-browser/sandbox/client/sdk.gen.js +1 -1
  105. package/dist/esm-browser/sandbox/preview.js +8 -3
  106. package/dist/esm-browser/sandbox/sandbox.js +41 -4
  107. package/dist/esm-browser/volume/index.js +41 -3
  108. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Credentials = void 0;
3
+ exports.MissingCredentials = exports.Credentials = void 0;
4
4
  const env_js_1 = require("../common/env.js");
5
5
  class Credentials {
6
6
  async authenticate() { }
@@ -15,3 +15,13 @@ class Credentials {
15
15
  }
16
16
  }
17
17
  exports.Credentials = Credentials;
18
+ /**
19
+ * Marker returned by `authentication()` when no usable Blaxel credentials were
20
+ * resolved (no env vars, no matching config workspace). Construction is
21
+ * side-effect free so importing `@blaxel/core` never fails; the actionable
22
+ * error is raised when an authenticated request is actually attempted
23
+ * (see `Settings.assertCredentials`).
24
+ */
25
+ class MissingCredentials extends Credentials {
26
+ }
27
+ exports.MissingCredentials = MissingCredentials;
@@ -51,7 +51,9 @@ function getCredentials() {
51
51
  function authentication() {
52
52
  const credentials = getCredentials();
53
53
  if (!credentials) {
54
- return new credentials_js_1.Credentials();
54
+ // Never silently fall back to empty headers: a marker that triggers a
55
+ // clear CredentialsError when an authenticated request is attempted.
56
+ return new credentials_js_1.MissingCredentials();
55
57
  }
56
58
  if (credentials.apiKey) {
57
59
  return new apikey_js_1.ApiKey(credentials);
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  // This file is auto-generated by @hey-api/openapi-ts
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.createJob = exports.listJobs = exports.getIntegrationConnectionModel = exports.listIntegrationConnectionModels = exports.getIntegrationConnectionModelEndpointConfigurations = exports.updateIntegrationConnection = exports.getIntegrationConnection = exports.deleteIntegrationConnection = exports.createIntegrationConnection = exports.listIntegrationConnections = exports.getIntegration = exports.deleteImageTag = exports.unshareImage = exports.shareImage = exports.listImageShares = exports.getImage = exports.deleteImage = exports.createImage = exports.listImages = exports.cleanupImages = exports.listFunctionRevisions = exports.updateFunction = exports.getFunction = exports.deleteFunction = exports.createFunction = exports.listFunctions = exports.testFeatureFlag = exports.getWorkspaceFeatures = exports.listAllEgressIps = exports.listAllEgressGateways = exports.getDriveJwks = exports.createDriveAccessToken = exports.updateDrive = exports.getDrive = exports.deleteDrive = exports.createDrive = exports.listDrives = exports.verifyCustomDomain = exports.updateCustomDomain = exports.getCustomDomain = exports.deleteCustomDomain = exports.createCustomDomain = exports.listCustomDomains = exports.getConfiguration = exports.listAgentRevisions = exports.updateAgent = exports.getAgent = exports.deleteAgent = exports.createAgent = exports.listAgents = void 0;
5
- exports.inviteWorkspaceUser = exports.listWorkspaceUsers = exports.getTemplate = exports.listTemplates = exports.deleteApiKeyForServiceAccount = exports.createApiKeyForServiceAccount = exports.listApiKeysForServiceAccount = exports.updateWorkspaceServiceAccount = exports.deleteWorkspaceServiceAccount = exports.createWorkspaceServiceAccount = exports.getWorkspaceServiceAccounts = exports.deleteSandboxPreviewToken = exports.createSandboxPreviewToken = exports.listSandboxPreviewTokens = exports.updateSandboxPreview = exports.getSandboxPreview = exports.deleteSandboxPreview = exports.createSandboxPreview = exports.listSandboxPreviews = exports.updateSandbox = exports.getSandbox = exports.deleteSandbox = exports.createSandbox = exports.listSandboxes = exports.listSandboxHubDefinitions = exports.listPublicIps = exports.updatePolicy = exports.getPolicy = exports.deletePolicy = exports.createPolicy = exports.listPolicies = exports.declineImageShare = exports.acceptImageShare = exports.listPendingImageShares = exports.listModelRevisions = exports.updateModel = exports.getModel = exports.deleteModel = exports.createModel = exports.listModels = exports.listMcpHubDefinitions = exports.listLocations = exports.listJobRevisions = exports.getJobExecution = exports.deleteJobExecution = exports.createJobExecution = exports.listJobExecutions = exports.updateJob = exports.getJob = exports.deleteJob = void 0;
6
- exports.checkWorkspaceAvailability = exports.leaveWorkspace = exports.acceptWorkspaceInvitation = exports.declineWorkspaceInvitation = exports.updateWorkspace = exports.getWorkspace = exports.deleteWorkspace = exports.createWorkspace = exports.listWorkspaces = exports.getEgressIp = exports.deleteEgressIp = exports.createEgressIp = exports.listEgressIps = exports.getEgressGateway = exports.deleteEgressGateway = exports.createEgressGateway = exports.listEgressGateways = exports.getVpc = exports.deleteVpc = exports.createVpc = exports.listVpcs = exports.updateVolume = exports.getVolume = exports.deleteVolume = exports.createVolume = exports.listVolumes = exports.deleteVolumeTemplateVersion = exports.updateVolumeTemplate = exports.getVolumeTemplate = exports.deleteVolumeTemplate = exports.createVolumeTemplate = exports.listVolumeTemplates = exports.updateWorkspaceUserRole = exports.removeWorkspaceUser = void 0;
4
+ exports.listJobs = exports.getIntegrationConnectionModel = exports.listIntegrationConnectionModels = exports.getIntegrationConnectionModelEndpointConfigurations = exports.updateIntegrationConnection = exports.getIntegrationConnection = exports.deleteIntegrationConnection = exports.createIntegrationConnection = exports.listIntegrationConnections = exports.getIntegration = exports.deleteImageTag = exports.unshareImage = exports.shareImage = exports.listImageShares = exports.getImage = exports.deleteImage = exports.createImage = exports.listImages = exports.cleanupImages = exports.listFunctionRevisions = exports.updateFunction = exports.getFunction = exports.deleteFunction = exports.createFunction = exports.listFunctions = exports.testFeatureFlag = exports.getWorkspaceFeatures = exports.listAllEgressIps = exports.getEgressGatewayUsage = exports.listAllEgressGateways = exports.getDriveJwks = exports.createDriveAccessToken = exports.updateDrive = exports.getDrive = exports.deleteDrive = exports.createDrive = exports.listDrives = exports.verifyCustomDomain = exports.updateCustomDomain = exports.getCustomDomain = exports.deleteCustomDomain = exports.createCustomDomain = exports.listCustomDomains = exports.getConfiguration = exports.listAgentRevisions = exports.updateAgent = exports.getAgent = exports.deleteAgent = exports.createAgent = exports.listAgents = void 0;
5
+ exports.listTemplates = exports.deleteApiKeyForServiceAccount = exports.createApiKeyForServiceAccount = exports.listApiKeysForServiceAccount = exports.updateWorkspaceServiceAccount = exports.deleteWorkspaceServiceAccount = exports.createWorkspaceServiceAccount = exports.getWorkspaceServiceAccounts = exports.deleteSandboxPreviewToken = exports.createSandboxPreviewToken = exports.listSandboxPreviewTokens = exports.updateSandboxPreview = exports.getSandboxPreview = exports.deleteSandboxPreview = exports.createSandboxPreview = exports.listSandboxPreviews = exports.updateSandbox = exports.getSandbox = exports.deleteSandbox = exports.createSandbox = exports.listSandboxes = exports.listSandboxHubDefinitions = exports.listPublicIps = exports.getPolicyUsages = exports.updatePolicy = exports.getPolicy = exports.deletePolicy = exports.createPolicy = exports.listPolicies = exports.declineImageShare = exports.acceptImageShare = exports.listPendingImageShares = exports.listModelRevisions = exports.updateModel = exports.getModel = exports.deleteModel = exports.createModel = exports.listModels = exports.listMcpHubDefinitions = exports.listLocations = exports.listJobRevisions = exports.listJobExecutionTasks = exports.getJobExecution = exports.deleteJobExecution = exports.createJobExecution = exports.listJobExecutions = exports.updateJob = exports.getJob = exports.deleteJob = exports.createJob = void 0;
6
+ exports.checkWorkspaceAvailability = exports.leaveWorkspace = exports.acceptWorkspaceInvitation = exports.declineWorkspaceInvitation = exports.updateWorkspace = exports.getWorkspace = exports.deleteWorkspace = exports.createWorkspace = exports.listWorkspaces = exports.getEgressIp = exports.deleteEgressIp = exports.createEgressIp = exports.listEgressIps = exports.getEgressGateway = exports.deleteEgressGateway = exports.createEgressGateway = exports.listEgressGateways = exports.getVpc = exports.deleteVpc = exports.createVpc = exports.listVpcs = exports.updateVolume = exports.getVolume = exports.deleteVolume = exports.createVolume = exports.listVolumes = exports.deleteVolumeTemplateVersion = exports.updateVolumeTemplate = exports.getVolumeTemplate = exports.deleteVolumeTemplate = exports.createVolumeTemplate = exports.listVolumeTemplates = exports.updateWorkspaceUserRole = exports.removeWorkspaceUser = exports.inviteWorkspaceUser = exports.listWorkspaceUsers = exports.getTemplate = void 0;
7
7
  const client_gen_1 = require("./client.gen");
8
8
  /**
9
9
  * List all agents
10
- * Returns all AI agents deployed in the workspace. Each agent includes its deployment status, runtime configuration, and global inference endpoint URL.
10
+ * Returns AI agents deployed in the workspace. Each agent includes its deployment status, runtime configuration, and global inference endpoint URL. Starting with API version 2026-04-28 the response is wrapped in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep returning a bare array with all agents.
11
11
  */
12
12
  const listAgents = (options) => {
13
13
  return (options?.client ?? client_gen_1.client).get({
@@ -239,7 +239,7 @@ const verifyCustomDomain = (options) => {
239
239
  exports.verifyCustomDomain = verifyCustomDomain;
240
240
  /**
241
241
  * List drives
242
- * Returns all drives in the workspace. Drives provide persistent storage that can be attached to agents, functions, and sandboxes.
242
+ * Returns all drives in the workspace. Drives provide persistent storage that can be attached to agents, functions, and sandboxes. Starting with API version 2026-04-28, the response wraps items in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep returning a bare array with all drives.
243
243
  */
244
244
  const listDrives = (options) => {
245
245
  return (options?.client ?? client_gen_1.client).get({
@@ -374,6 +374,23 @@ const listAllEgressGateways = (options) => {
374
374
  });
375
375
  };
376
376
  exports.listAllEgressGateways = listAllEgressGateways;
377
+ /**
378
+ * Egress gateway sandbox attachments
379
+ * Returns the inverse map (gateway → sandbox names) for the workspace. Used by the egress-IPs UI to render attachment counts without fetching the sandboxes listing full client-side.
380
+ */
381
+ const getEgressGatewayUsage = (options) => {
382
+ return (options?.client ?? client_gen_1.client).get({
383
+ security: [
384
+ {
385
+ scheme: 'bearer',
386
+ type: 'http'
387
+ }
388
+ ],
389
+ url: '/egressgateways/usage',
390
+ ...options
391
+ });
392
+ };
393
+ exports.getEgressGatewayUsage = getEgressGatewayUsage;
377
394
  /**
378
395
  * List all egress IPs across all VPCs and gateways in the workspace
379
396
  */
@@ -426,7 +443,7 @@ const testFeatureFlag = (options) => {
426
443
  exports.testFeatureFlag = testFeatureFlag;
427
444
  /**
428
445
  * List all MCP servers
429
- * Returns all MCP server functions deployed in the workspace. Each function includes its deployment status, transport protocol (websocket or http-stream), and endpoint URL.
446
+ * Returns MCP server functions deployed in the workspace. Each function includes its deployment status, transport protocol (websocket or http-stream), and endpoint URL. Starting with API version 2026-04-28 the response is wrapped in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep returning a bare array with all functions.
430
447
  */
431
448
  const listFunctions = (options) => {
432
449
  return (options?.client ?? client_gen_1.client).get({
@@ -858,7 +875,7 @@ const getIntegrationConnectionModel = (options) => {
858
875
  exports.getIntegrationConnectionModel = getIntegrationConnectionModel;
859
876
  /**
860
877
  * List batch jobs
861
- * Returns all batch job definitions in the workspace. Each job can be triggered to run multiple parallel tasks with configurable concurrency and retry settings.
878
+ * Returns batch job definitions in the workspace. Each job can be triggered to run multiple parallel tasks with configurable concurrency and retry settings. Starting with API version 2026-04-28 the response is wrapped in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep returning a bare array with all jobs.
862
879
  */
863
880
  const listJobs = (options) => {
864
881
  return (options?.client ?? client_gen_1.client).get({
@@ -951,7 +968,7 @@ const updateJob = (options) => {
951
968
  exports.updateJob = updateJob;
952
969
  /**
953
970
  * List job executions
954
- * Returns paginated list of executions for a batch job, sorted by creation time. Each execution contains status, task counts, and timing information.
971
+ * Returns executions for a batch job. Starting with API version 2026-04-28 the response is wrapped in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep the legacy offset/limit contract and return a bare array.
955
972
  */
956
973
  const listJobExecutions = (options) => {
957
974
  return (options.client ?? client_gen_1.client).get({
@@ -1021,6 +1038,23 @@ const getJobExecution = (options) => {
1021
1038
  });
1022
1039
  };
1023
1040
  exports.getJobExecution = getJobExecution;
1041
+ /**
1042
+ * List execution tasks
1043
+ * Returns one cursor-paginated page of an execution's tasks. Tasks are derived from event history each request; only the in-memory slicing is paginated, the events scan still fetches the whole event log behind the scenes. Available starting with API version 2026-04-28.
1044
+ */
1045
+ const listJobExecutionTasks = (options) => {
1046
+ return (options.client ?? client_gen_1.client).get({
1047
+ security: [
1048
+ {
1049
+ scheme: 'bearer',
1050
+ type: 'http'
1051
+ }
1052
+ ],
1053
+ url: '/jobs/{jobId}/executions/{executionId}/tasks',
1054
+ ...options
1055
+ });
1056
+ };
1057
+ exports.listJobExecutionTasks = listJobExecutionTasks;
1024
1058
  /**
1025
1059
  * List job revisions
1026
1060
  * Returns revisions for a job by name.
@@ -1074,7 +1108,7 @@ const listMcpHubDefinitions = (options) => {
1074
1108
  exports.listMcpHubDefinitions = listMcpHubDefinitions;
1075
1109
  /**
1076
1110
  * List model endpoints
1077
- * Returns all model gateway endpoints configured in the workspace. Each model represents a proxy to an external LLM provider (OpenAI, Anthropic, etc.) with unified access control.
1111
+ * Returns model gateway endpoints configured in the workspace. Each model represents a proxy to an external LLM provider (OpenAI, Anthropic, etc.) with unified access control. Starting with API version 2026-04-28 the response is wrapped in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep returning a bare array with all models.
1078
1112
  */
1079
1113
  const listModels = (options) => {
1080
1114
  return (options?.client ?? client_gen_1.client).get({
@@ -1235,7 +1269,7 @@ const declineImageShare = (options) => {
1235
1269
  exports.declineImageShare = declineImageShare;
1236
1270
  /**
1237
1271
  * List governance policies
1238
- * Returns all governance policies in the workspace. Policies control deployment locations, hardware flavors, and token limits for agents, functions, and models.
1272
+ * Returns governance policies in the workspace. Policies control deployment locations, hardware flavors, and token limits for agents, functions, and models. Starting with API version 2026-04-28 the response is wrapped in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep returning a bare array with all policies.
1239
1273
  */
1240
1274
  const listPolicies = (options) => {
1241
1275
  return (options?.client ?? client_gen_1.client).get({
@@ -1326,6 +1360,23 @@ const updatePolicy = (options) => {
1326
1360
  });
1327
1361
  };
1328
1362
  exports.updatePolicy = updatePolicy;
1363
+ /**
1364
+ * List resources using a policy
1365
+ * Returns the names of every resource (agent, function, model, sandbox, job) currently referencing the given policy. Replaces the client-side fan-out the policies UI used to do over the listings.
1366
+ */
1367
+ const getPolicyUsages = (options) => {
1368
+ return (options.client ?? client_gen_1.client).get({
1369
+ security: [
1370
+ {
1371
+ scheme: 'bearer',
1372
+ type: 'http'
1373
+ }
1374
+ ],
1375
+ url: '/policies/{policyName}/usages',
1376
+ ...options
1377
+ });
1378
+ };
1379
+ exports.getPolicyUsages = getPolicyUsages;
1329
1380
  /**
1330
1381
  * List public ips
1331
1382
  * Returns a list of all public ips used in Blaxel..
@@ -1362,7 +1413,7 @@ const listSandboxHubDefinitions = (options) => {
1362
1413
  exports.listSandboxHubDefinitions = listSandboxHubDefinitions;
1363
1414
  /**
1364
1415
  * List sandboxes
1365
- * Returns all sandboxes in the workspace. Each sandbox includes its configuration, status, and endpoint URL.
1416
+ * Returns sandboxes in the workspace. Each sandbox includes its configuration, status, and endpoint URL. Terminated sandboxes are hidden by default; pass `showTerminated=true` to include them. Starting with API version 2026-04-28 the response is wrapped in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep returning a bare array of all sandboxes.
1366
1417
  */
1367
1418
  const listSandboxes = (options) => {
1368
1419
  return (options?.client ?? client_gen_1.client).get({
@@ -1954,7 +2005,7 @@ const deleteVolumeTemplateVersion = (options) => {
1954
2005
  exports.deleteVolumeTemplateVersion = deleteVolumeTemplateVersion;
1955
2006
  /**
1956
2007
  * List persistent volumes
1957
- * Returns all persistent storage volumes in the workspace. Volumes can be attached to sandboxes for durable file storage that persists across sessions and sandbox deletions.
2008
+ * Returns persistent storage volumes in the workspace. Volumes can be attached to sandboxes for durable file storage that persists across sessions and sandbox deletions. Starting with API version 2026-04-28 the response is wrapped in `{data, meta}` and supports cursor pagination via the `cursor` and `limit` query parameters; older versions keep returning a bare array of volumes.
1958
2009
  */
1959
2010
  const listVolumes = (options) => {
1960
2011
  return (options?.client ?? client_gen_1.client).get({
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const apikey_js_1 = require("../authentication/apikey.js");
5
+ const credentials_js_1 = require("../authentication/credentials.js");
6
+ const index_js_1 = require("../authentication/index.js");
7
+ const errors_js_1 = require("./errors.js");
8
+ const settings_js_1 = require("./settings.js");
9
+ /**
10
+ * ENG-2698: missing / partial BL_WORKSPACE / BL_API_KEY must fail fast with a
11
+ * clear, actionable error instead of silently sending empty headers and
12
+ * surfacing the server's misleading "workspace is required".
13
+ *
14
+ * `env` reads through to `process.env`, so env state is controlled there.
15
+ */
16
+ (0, vitest_1.describe)('credential validation', () => {
17
+ const AUTH_ENV = ['BL_API_KEY', 'BL_WORKSPACE', 'BL_CLIENT_CREDENTIALS'];
18
+ let savedEnv;
19
+ let savedCredentials;
20
+ let savedConfig;
21
+ (0, vitest_1.beforeEach)(() => {
22
+ savedEnv = {};
23
+ for (const key of AUTH_ENV) {
24
+ savedEnv[key] = process.env[key];
25
+ delete process.env[key];
26
+ }
27
+ savedCredentials = settings_js_1.settings.credentials;
28
+ savedConfig = settings_js_1.settings.config;
29
+ settings_js_1.settings.config = { proxy: '', apikey: '', workspace: '' };
30
+ });
31
+ (0, vitest_1.afterEach)(() => {
32
+ for (const key of AUTH_ENV) {
33
+ if (savedEnv[key] === undefined)
34
+ delete process.env[key];
35
+ else
36
+ process.env[key] = savedEnv[key];
37
+ }
38
+ settings_js_1.settings.credentials = savedCredentials;
39
+ settings_js_1.settings.config = savedConfig;
40
+ });
41
+ (0, vitest_1.it)('API key without workspace throws a clear BL_WORKSPACE error from headers', () => {
42
+ settings_js_1.settings.credentials = new apikey_js_1.ApiKey({ apiKey: 'test-key' });
43
+ (0, vitest_1.expect)(() => settings_js_1.settings.headers).toThrow(errors_js_1.CredentialsError);
44
+ (0, vitest_1.expect)(() => settings_js_1.settings.headers).toThrow(/BL_WORKSPACE/);
45
+ });
46
+ (0, vitest_1.it)('API key without workspace rejects from authenticate()', async () => {
47
+ settings_js_1.settings.credentials = new apikey_js_1.ApiKey({ apiKey: 'test-key' });
48
+ await (0, vitest_1.expect)(settings_js_1.settings.authenticate()).rejects.toThrow(/BL_WORKSPACE/);
49
+ });
50
+ (0, vitest_1.it)('workspace set but no API key names the missing API key', () => {
51
+ process.env.BL_WORKSPACE = 'my-workspace';
52
+ settings_js_1.settings.credentials = new credentials_js_1.MissingCredentials();
53
+ (0, vitest_1.expect)(() => settings_js_1.settings.headers).toThrow(/API key is missing/);
54
+ });
55
+ (0, vitest_1.it)('no credentials at all names both env vars', () => {
56
+ settings_js_1.settings.credentials = new credentials_js_1.MissingCredentials();
57
+ (0, vitest_1.expect)(() => settings_js_1.settings.headers).toThrow(errors_js_1.CredentialsError);
58
+ (0, vitest_1.expect)(() => settings_js_1.settings.headers).toThrow(/BL_API_KEY and BL_WORKSPACE/);
59
+ });
60
+ (0, vitest_1.it)('api key + workspace builds clean headers with no empty values', () => {
61
+ settings_js_1.settings.credentials = new apikey_js_1.ApiKey({ apiKey: 'test-key', workspace: 'my-workspace' });
62
+ const headers = settings_js_1.settings.headers;
63
+ (0, vitest_1.expect)(headers['x-blaxel-workspace']).toBe('my-workspace');
64
+ (0, vitest_1.expect)(headers['x-blaxel-authorization']).toBe('Bearer test-key');
65
+ (0, vitest_1.expect)(Object.values(headers)).not.toContain('');
66
+ });
67
+ (0, vitest_1.it)('authentication() returns a real ApiKey when BL_API_KEY is set', () => {
68
+ process.env.BL_API_KEY = 'test-key';
69
+ (0, vitest_1.expect)((0, index_js_1.authentication)()).toBeInstanceOf(apikey_js_1.ApiKey);
70
+ });
71
+ });
@@ -1,6 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CredentialsError = void 0;
3
4
  exports.handleDynamicImportError = handleDynamicImportError;
5
+ /**
6
+ * Thrown when Blaxel credentials are missing or incomplete.
7
+ *
8
+ * Surfaced eagerly with an actionable message (which env var / login step is
9
+ * missing) instead of silently sending empty workspace/authorization headers
10
+ * and letting the user hit a misleading server-side "workspace is required".
11
+ */
12
+ class CredentialsError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = "CredentialsError";
16
+ }
17
+ }
18
+ exports.CredentialsError = CredentialsError;
4
19
  function handleDynamicImportError(err) {
5
20
  if (err instanceof Error) {
6
21
  // We check if it's module import error and retrieve package name from the error message with a regex
@@ -17,14 +17,21 @@ const sessionsWithListenerBudget = new WeakSet();
17
17
  * When `settings.maxConcurrentH2Requests` is `0`/unset the gate is a no-op
18
18
  * (current default behavior: unlimited concurrency).
19
19
  */
20
- // Safety timeout for a held slot. A request that never resolves (no response,
21
- // no error, no abort) would otherwise hold its slot forever and starve every
22
- // queued request for the same domain. After this window we release the slot
23
- // and let the underlying request continue or reject on its own; we never
24
- // cancel the in-flight request here, we only stop it from blocking the queue.
25
- // Kept deliberately conservative (well above any realistic part-upload time)
26
- // so it does not interfere with legitimately slow but healthy requests.
27
- const H2_SLOT_TIMEOUT_MS = 120_000;
20
+ // Last-resort leak guard for a held slot. The slot is now released on the real
21
+ // stream terminal (end / error / abort / cancel / pre-response reject), which
22
+ // always fires, so this timer is a pure backstop for the one residual case: a
23
+ // request that never opens a stream AND never settles (no response, no error,
24
+ // no abort) it must not pin a slot forever and starve the per-domain queue.
25
+ //
26
+ // When it fires it ONLY frees the queue slot. It NEVER aborts or cancels the
27
+ // underlying request or its response stream: `release` does not touch `req` or
28
+ // the body stream, so a long-lived streaming response keeps flowing. Raised
29
+ // well beyond any legitimate stream lifetime so it cannot interfere with a
30
+ // healthy long-open stream (process.streamLogs / execWithStreaming / port
31
+ // proxy). RESIDUAL: a stream that outlives this backstop would have its slot
32
+ // freed early (the queue could then admit one extra stream); acceptable as a
33
+ // pure backstop, since the slot is otherwise tied to the true stream terminal.
34
+ const H2_SLOT_TIMEOUT_MS = 1_800_000; // 30 minutes
28
35
  const h2GatesByDomain = new Map();
29
36
  function getH2Gate(domain) {
30
37
  let gate = h2GatesByDomain.get(domain);
@@ -35,10 +42,14 @@ function getH2Gate(domain) {
35
42
  return gate;
36
43
  }
37
44
  /**
38
- * Acquire an in-flight slot for `domain`. Resolves with a release function
39
- * that is idempotent and FIFO-fair: releasing wakes the longest-waiting
40
- * queued caller for the same domain. A safety timer also releases the slot
41
- * if the caller never does, preventing per-domain starvation.
45
+ * Acquire an OPEN-STREAM slot for `domain`. Resolves with a release function
46
+ * that is idempotent and FIFO-fair: releasing wakes the longest-waiting queued
47
+ * caller for the same domain. The slot is held for the lifetime of an OPEN H2
48
+ * stream the send path releases it on the stream terminal — so the gate
49
+ * bounds true concurrent streams on the one shared session, not merely requests
50
+ * awaiting headers (ENG-2678). A backstop timer releases the slot if a request
51
+ * neither opens a stream nor ever settles, preventing per-domain starvation;
52
+ * it never aborts the underlying request (see `H2_SLOT_TIMEOUT_MS`).
42
53
  */
43
54
  async function acquireH2Slot(domain) {
44
55
  const max = settings_js_1.settings.maxConcurrentH2Requests; // 0/undefined = unlimited
@@ -92,66 +103,89 @@ function createH2Fetch(session) {
92
103
  };
93
104
  }
94
105
  /**
95
- * Creates a fetch()-compatible function backed by the H2 session pool.
106
+ * The single HTTP/2 request gateway (ENG-2679).
96
107
  *
97
- * The pool validates idle sessions before reuse. If no usable H2 session is
98
- * available, the request falls back to regular fetch before any H2 frames
99
- * are sent.
108
+ * Every pool-backed request funnels through here, no matter which entry point
109
+ * it came from: the generated client's fetch (`createPoolBackedH2Fetch`),
110
+ * `SandboxAction.h2Fetch`, and the interpreter's direct path (both via
111
+ * `h2RequestDirectFromPool`). It owns the shared request lifecycle in one place:
112
+ * 1. take a per-domain open-stream slot,
113
+ * 2. get a live session from the pool,
114
+ * 3. send the request on it,
115
+ * 4. evict the session if the send fails after a stream was opened,
116
+ * 5. fall back to globalThis.fetch when the pool has no usable session.
117
+ *
118
+ * This is the chokepoint where reliability behavior that must protect EVERY
119
+ * consumer belongs: the open-stream concurrency limit today, and retry,
120
+ * timeouts, typed errors, and observability in later phases. Adding it once here
121
+ * (instead of re-implementing it per entry point) is what stops the recurring
122
+ * "fixed on one path, still broken on another" regressions.
123
+ *
124
+ * `send` performs the actual wire send on a live session; the caller supplies it
125
+ * so the gateway stays agnostic to the `Request` vs `(url, init)` call shapes,
126
+ * and it receives the slot-release and request-created hooks. `fallback` runs
127
+ * only when the pool has no usable session (a fresh connection, no shared
128
+ * stream is opened).
100
129
  */
101
- function createPoolBackedH2Fetch(pool, domain) {
102
- return async (input) => {
103
- const rel = await acquireH2Slot(domain);
104
- try {
105
- const session = await pool.get(domain);
106
- if (session) {
107
- let h2RequestCreated = false;
108
- try {
109
- return await _h2Request(session, input, {
110
- onH2RequestCreated: () => {
111
- h2RequestCreated = true;
112
- },
113
- });
114
- }
115
- catch (err) {
116
- if (h2RequestCreated) {
117
- pool.evictSession(domain, session);
118
- }
119
- throw err;
120
- }
121
- }
122
- return await globalThis.fetch(input);
123
- }
124
- finally {
125
- rel();
126
- }
127
- };
128
- }
129
- async function h2RequestDirectFromPool(pool, domain, url, init) {
130
+ async function h2GatewayRequest(pool, domain, send, fallback) {
131
+ // Take the slot here, but hand its release to the send path: it is held for
132
+ // the OPEN-STREAM lifetime and freed on the stream terminal (ENG-2678). A
133
+ // request that never opens a stream on the shared session (the fallback goes
134
+ // over a different connection) releases it immediately so it does not count
135
+ // against the open-stream budget. `rel` is idempotent, so releasing here when
136
+ // the send path may also release is safe.
130
137
  const rel = await acquireH2Slot(domain);
131
138
  try {
132
139
  const session = await pool.get(domain);
133
140
  if (session) {
134
141
  let h2RequestCreated = false;
135
142
  try {
136
- return await h2RequestDirectInternal(session, url, init, {
143
+ return await send(session, {
137
144
  onH2RequestCreated: () => {
138
145
  h2RequestCreated = true;
139
146
  },
147
+ releaseSlot: rel,
140
148
  });
141
149
  }
142
150
  catch (err) {
151
+ // A failure AFTER a stream opened means the session is suspect: drop it
152
+ // so the next caller gets a fresh one.
143
153
  if (h2RequestCreated) {
144
154
  pool.evictSession(domain, session);
145
155
  }
146
156
  throw err;
147
157
  }
148
158
  }
149
- return await globalThis.fetch(url, init);
159
+ // No usable session: free the slot before falling back over a different
160
+ // connection (no stream opens on the shared session).
161
+ rel();
162
+ return await fallback();
150
163
  }
151
- finally {
164
+ catch (err) {
165
+ // Pre-send throw (pool.get(), Request body read, or the fallback itself):
166
+ // release the slot so a failed request never pins it. Idempotent.
152
167
  rel();
168
+ throw err;
153
169
  }
154
170
  }
171
+ /**
172
+ * Creates a fetch()-compatible function backed by the H2 session pool, routed
173
+ * through the single gateway. Used as the generated client's `fetch`.
174
+ *
175
+ * If no usable H2 session is available, the request falls back to regular fetch
176
+ * before any H2 frames are sent.
177
+ */
178
+ function createPoolBackedH2Fetch(pool, domain) {
179
+ return (input) => h2GatewayRequest(pool, domain, (session, options) => _h2Request(session, input, options), () => globalThis.fetch(input));
180
+ }
181
+ /**
182
+ * Pool-backed H2 request taking raw url + init (skips Request allocation),
183
+ * routed through the same single gateway. Used by `SandboxAction.h2Fetch` and
184
+ * the code interpreter.
185
+ */
186
+ function h2RequestDirectFromPool(pool, domain, url, init) {
187
+ return h2GatewayRequest(pool, domain, (session, options) => h2RequestDirectInternal(session, url, init, options), () => globalThis.fetch(url, init));
188
+ }
155
189
  /**
156
190
  * Low-level H2 request that takes raw URL + init, skipping Request construction.
157
191
  * Used by SandboxAction.h2Fetch() for direct calls from subsystems.
@@ -161,6 +195,9 @@ function h2RequestDirect(session, url, init) {
161
195
  }
162
196
  function h2RequestDirectInternal(session, url, init, options) {
163
197
  if (session.closed || session.destroyed) {
198
+ // Pre-flight fallback (session unusable): no stream opens on the shared
199
+ // session, so free any held slot before going over globalThis.fetch.
200
+ options?.releaseSlot?.();
164
201
  return globalThis.fetch(url, init);
165
202
  }
166
203
  const parsed = new URL(url);
@@ -200,7 +237,9 @@ function h2RequestDirectInternal(session, url, init, options) {
200
237
  else {
201
238
  // FormData, ReadableStream, Blob, etc. can't be serialized to Buffer
202
239
  // for manual H2 framing — fall back to regular fetch (pre-flight,
203
- // nothing has been sent on the wire yet).
240
+ // nothing has been sent on the wire yet). No stream opens on the shared
241
+ // session, so free any held slot before falling back.
242
+ options?.releaseSlot?.();
204
243
  return globalThis.fetch(url, init);
205
244
  }
206
245
  if (!h2Headers["content-length"]) {
@@ -244,13 +283,19 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
244
283
  let streamClosed = false;
245
284
  let req = null;
246
285
  let releaseSessionRef = () => { };
286
+ // The per-domain open-stream slot (idempotent; no-op for the non-pool
287
+ // transports). Held for the OPEN-STREAM lifetime and released alongside the
288
+ // session ref from cleanupActiveRequest() on every terminal path.
289
+ const releaseSlot = options?.releaseSlot ?? (() => { });
247
290
  let abort = null;
248
291
  try {
249
292
  req = session.request(h2Headers);
250
293
  }
251
294
  catch {
252
295
  // Pre-flight fallback: session.request() threw synchronously, so no
253
- // H2 frames were sent. Safe to retry over globalThis.fetch.
296
+ // H2 frames were sent. No stream opened on the shared session, so free
297
+ // the slot before retrying over globalThis.fetch.
298
+ releaseSlot();
254
299
  globalThis.fetch(fallbackUrl, fallbackInit).then(resolve, reject);
255
300
  return;
256
301
  }
@@ -265,7 +310,13 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
265
310
  const cleanupActiveRequest = () => {
266
311
  if (abort)
267
312
  signal?.removeEventListener("abort", abort);
313
+ // Slot and session-ref share the OPEN-STREAM lifetime but stay
314
+ // independent and each idempotent (PM-2160). Every terminal path funnels
315
+ // through here exactly once: pre-response reject (close/goaway/error),
316
+ // abort-before-response, abort-during-stream, stream end, stream error,
317
+ // and ReadableStream cancel — so the slot is freed once on each.
268
318
  releaseSessionRef();
319
+ releaseSlot();
269
320
  };
270
321
  const rejectBeforeResponse = (err) => {
271
322
  if (settled)
@@ -153,6 +153,15 @@ class H2Pool {
153
153
  return session;
154
154
  }
155
155
  if (await this.ping(session)) {
156
+ // ENG-2676 generation/identity pin: `await this.ping` yields, and during
157
+ // that await an eviction listener (goaway/error/close ->
158
+ // attachEvictionListeners, see above) may have deleted or replaced this
159
+ // entry. `entry` is the exact object held in the map, so if it is no
160
+ // longer the cached generation, refuse the now-stale session instead of
161
+ // handing back a zombie — the ENG-2422 failure re-entering through the
162
+ // validate race. The caller falls through to establish a fresh session.
163
+ if (this.sessions.get(domain) !== entry)
164
+ return null;
156
165
  this.markUsed(domain, session);
157
166
  return session;
158
167
  }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unwrapListData = unwrapListData;
4
+ exports.createPaginatedList = createPaginatedList;
5
+ function unwrapListData(response) {
6
+ if (!response) {
7
+ return [];
8
+ }
9
+ if (Array.isArray(response)) {
10
+ return response;
11
+ }
12
+ return response.data ?? [];
13
+ }
14
+ function unwrapListMeta(response) {
15
+ if (!response || Array.isArray(response)) {
16
+ return { hasMore: false };
17
+ }
18
+ return response.meta ?? { hasMore: false };
19
+ }
20
+ async function createPaginatedList({ response, fetchPage, mapItem, query, seenCursors, }) {
21
+ const meta = unwrapListMeta(response);
22
+ const data = await Promise.all(unwrapListData(response).map(mapItem));
23
+ const cursors = new Set(seenCursors);
24
+ if (query?.cursor) {
25
+ cursors.add(query.cursor);
26
+ }
27
+ const list = {
28
+ data,
29
+ meta,
30
+ get hasMore() {
31
+ return Boolean(meta.hasMore);
32
+ },
33
+ get nextCursor() {
34
+ return meta.nextCursor || undefined;
35
+ },
36
+ async nextPage() {
37
+ const cursor = list.nextCursor;
38
+ if (!cursor) {
39
+ return null;
40
+ }
41
+ if (cursors.has(cursor)) {
42
+ throw new Error("Pagination returned a repeated cursor");
43
+ }
44
+ const nextQuery = { ...(query ?? {}), cursor };
45
+ const nextSeenCursors = new Set(cursors);
46
+ nextSeenCursors.add(cursor);
47
+ return createPaginatedList({
48
+ response: await fetchPage(nextQuery),
49
+ fetchPage,
50
+ mapItem,
51
+ query: nextQuery,
52
+ seenCursors: nextSeenCursors,
53
+ });
54
+ },
55
+ async autoPagingEach(onItem) {
56
+ for await (const item of list) {
57
+ const shouldContinue = await onItem(item);
58
+ if (shouldContinue === false) {
59
+ return;
60
+ }
61
+ }
62
+ },
63
+ async autoPagingToArray(options) {
64
+ if (!options || !Number.isFinite(options.limit) || options.limit <= 0) {
65
+ throw new Error("autoPagingToArray requires a positive limit");
66
+ }
67
+ const items = [];
68
+ for await (const item of list) {
69
+ items.push(item);
70
+ if (items.length >= options.limit) {
71
+ return items;
72
+ }
73
+ }
74
+ return items;
75
+ },
76
+ async *[Symbol.asyncIterator]() {
77
+ let page = list;
78
+ while (page) {
79
+ for (const item of page.data) {
80
+ yield item;
81
+ }
82
+ page = await page.nextPage();
83
+ }
84
+ },
85
+ };
86
+ return list;
87
+ }