@buddy-works/sandbox-sdk 0.1.0-rc.1 → 0.1.1-rc.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.
package/README.md CHANGED
@@ -19,6 +19,7 @@ let sandbox: Sandbox;
19
19
 
20
20
  try {
21
21
  sandbox = await Sandbox.getByIdentifier(identifier);
22
+ await sandbox.start();
22
23
  } catch {
23
24
  sandbox = await Sandbox.create({
24
25
  identifier,
@@ -30,6 +31,8 @@ try {
30
31
  await sandbox.runCommand({
31
32
  command: "ping -c 5 buddy.works",
32
33
  });
34
+
35
+ await sandbox.stop();
33
36
  ```
34
37
 
35
38
  Set required environment variables:
package/dist/index.d.mts CHANGED
@@ -3,6 +3,26 @@ import { inspect } from "node:util";
3
3
  import { Writable } from "node:stream";
4
4
 
5
5
  //#region src/api/openapi/types.gen.d.ts
6
+ type GroupPermissionView = {
7
+ /**
8
+ * The ID of the group
9
+ */
10
+ id?: number;
11
+ /**
12
+ * The access level for the group
13
+ */
14
+ access_level?: "DENIED" | "READ_ONLY" | "BLIND" | "RUN_ONLY" | "READ_WRITE" | "MANAGE" | "DEFAULT" | "ALLOWED" | "STAGE" | "COMMIT" | "USE_ONLY";
15
+ };
16
+ type UserPermissionView = {
17
+ /**
18
+ * The ID of the user
19
+ */
20
+ id?: number;
21
+ /**
22
+ * The access level for the user
23
+ */
24
+ access_level?: "DENIED" | "READ_ONLY" | "BLIND" | "RUN_ONLY" | "READ_WRITE" | "MANAGE" | "DEFAULT" | "ALLOWED" | "STAGE" | "COMMIT" | "USE_ONLY";
25
+ };
6
26
  /**
7
27
  * Sandbox reference
8
28
  */
@@ -214,6 +234,23 @@ type ProjectView = {
214
234
  */
215
235
  without_repository?: boolean;
216
236
  };
237
+ /**
238
+ * Access permissions configuration
239
+ */
240
+ type PermissionsView = {
241
+ /**
242
+ * Access level for other workspace members
243
+ */
244
+ others?: "DENIED" | "READ_ONLY" | "BLIND" | "RUN_ONLY" | "READ_WRITE" | "MANAGE" | "DEFAULT" | "ALLOWED" | "STAGE" | "COMMIT" | "USE_ONLY";
245
+ /**
246
+ * List of specific users with their access levels
247
+ */
248
+ users?: Array<UserPermissionView>;
249
+ /**
250
+ * List of user groups with their access levels
251
+ */
252
+ groups?: Array<GroupPermissionView>;
253
+ };
217
254
  /**
218
255
  * The TLS/SSL encryption settings of the tunnel
219
256
  */
@@ -616,6 +653,7 @@ type SandboxResponse = {
616
653
  */
617
654
  endpoints?: Array<TunnelView>;
618
655
  project?: ProjectView;
656
+ permissions?: PermissionsView;
619
657
  /**
620
658
  * The environment variables of the sandbox
621
659
  */
@@ -1590,16 +1628,21 @@ declare class Sandbox {
1590
1628
  waitUntilStopped(pollIntervalMs?: number, maxWaitMs?: number): Promise<void>;
1591
1629
  /**
1592
1630
  * Start a stopped sandbox
1593
- * Waits until the sandbox reaches RUNNING state
1631
+ *
1632
+ * If the sandbox is already running, this method returns immediately.
1633
+ * Waits until the sandbox reaches RUNNING state.
1594
1634
  */
1595
1635
  start(): Promise<void>;
1596
1636
  /**
1597
1637
  * Stop a running sandbox
1598
- * Waits until the sandbox reaches STOPPED state
1638
+ *
1639
+ * If the sandbox is already stopped, this method returns immediately.
1640
+ * Waits until the sandbox reaches STOPPED state.
1599
1641
  */
1600
1642
  stop(): Promise<void>;
1601
1643
  /**
1602
1644
  * Restart the sandbox
1645
+ *
1603
1646
  * Waits until the sandbox reaches RUNNING state and setup is complete
1604
1647
  */
1605
1648
  restart(): Promise<void>;
package/dist/index.mjs CHANGED
@@ -55,89 +55,37 @@ const stopSandboxResponseTransformer = async (data) => {
55
55
 
56
56
  //#endregion
57
57
  //#region src/api/openapi/zod.gen.ts
58
- const zUriBuilder = z.record(z.string(), z.unknown());
59
- const zStatusType = z.object({
60
- family: z.optional(z.enum([
61
- "INFORMATIONAL",
62
- "SUCCESSFUL",
63
- "REDIRECTION",
64
- "CLIENT_ERROR",
65
- "SERVER_ERROR",
66
- "OTHER"
67
- ])),
68
- status_code: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
69
- reason_phrase: z.optional(z.string())
70
- });
71
- const zEntityTag = z.object({
72
- value: z.optional(z.string()),
73
- weak: z.optional(z.boolean())
74
- });
75
- const zMediaType = z.object({
76
- type: z.optional(z.string()),
77
- subtype: z.optional(z.string()),
78
- parameters: z.optional(z.record(z.string(), z.string())),
79
- wildcard_type: z.optional(z.boolean()),
80
- wildcard_subtype: z.optional(z.boolean())
81
- });
82
- const zLink = z.object({
83
- uri: z.optional(z.url()),
84
- uri_builder: z.optional(zUriBuilder),
85
- rel: z.optional(z.string()),
86
- rels: z.optional(z.array(z.string())),
87
- type: z.optional(z.string()),
88
- params: z.optional(z.record(z.string(), z.string())),
89
- title: z.optional(z.string())
90
- });
91
- const zNewCookie = z.object({
92
- name: z.optional(z.string()),
93
- value: z.optional(z.string()),
94
- version: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
95
- path: z.optional(z.string()),
96
- domain: z.optional(z.string()),
97
- comment: z.optional(z.string()),
98
- max_age: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
99
- expiry: z.optional(z.iso.datetime()),
100
- secure: z.optional(z.boolean()),
101
- http_only: z.optional(z.boolean()),
102
- same_site: z.optional(z.enum([
103
- "NONE",
104
- "LAX",
105
- "STRICT"
106
- ]))
58
+ const zGroupPermissionView = z.object({
59
+ id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The ID of the group" })),
60
+ access_level: z.optional(z.enum([
61
+ "DENIED",
62
+ "READ_ONLY",
63
+ "BLIND",
64
+ "RUN_ONLY",
65
+ "READ_WRITE",
66
+ "MANAGE",
67
+ "DEFAULT",
68
+ "ALLOWED",
69
+ "STAGE",
70
+ "COMMIT",
71
+ "USE_ONLY"
72
+ ]).register(z.globalRegistry, { description: "The access level for the group" }))
107
73
  });
108
- const zResponse = z.object({
109
- status_info: z.optional(zStatusType),
110
- cookies: z.optional(z.record(z.string(), zNewCookie)),
111
- allowed_methods: z.optional(z.array(z.string())),
112
- links: z.optional(z.array(zLink)),
113
- media_type: z.optional(zMediaType),
114
- entity_tag: z.optional(zEntityTag),
115
- string_headers: z.optional(z.object({ empty: z.optional(z.boolean()) })),
116
- closed: z.optional(z.boolean()),
117
- length: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
118
- location: z.optional(z.url()),
119
- language: z.optional(z.object({
120
- language: z.optional(z.string()),
121
- display_name: z.optional(z.string()),
122
- country: z.optional(z.string()),
123
- variant: z.optional(z.string()),
124
- script: z.optional(z.string()),
125
- unicode_locale_attributes: z.optional(z.array(z.string())),
126
- unicode_locale_keys: z.optional(z.array(z.string())),
127
- display_language: z.optional(z.string()),
128
- display_script: z.optional(z.string()),
129
- display_country: z.optional(z.string()),
130
- display_variant: z.optional(z.string()),
131
- extension_keys: z.optional(z.array(z.string())),
132
- iso3_language: z.optional(z.string()),
133
- iso3_country: z.optional(z.string())
134
- })),
135
- date: z.optional(z.iso.datetime()),
136
- last_modified: z.optional(z.iso.datetime()),
137
- status: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
138
- metadata: z.optional(z.object({ empty: z.optional(z.boolean()) })),
139
- entity: z.optional(z.record(z.string(), z.unknown())),
140
- headers: z.optional(z.object({ empty: z.optional(z.boolean()) }))
74
+ const zUserPermissionView = z.object({
75
+ id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The ID of the user" })),
76
+ access_level: z.optional(z.enum([
77
+ "DENIED",
78
+ "READ_ONLY",
79
+ "BLIND",
80
+ "RUN_ONLY",
81
+ "READ_WRITE",
82
+ "MANAGE",
83
+ "DEFAULT",
84
+ "ALLOWED",
85
+ "STAGE",
86
+ "COMMIT",
87
+ "USE_ONLY"
88
+ ]).register(z.globalRegistry, { description: "The access level for the user" }))
141
89
  });
142
90
  /**
143
91
  * Sandbox reference
@@ -276,6 +224,26 @@ const zProjectView = z.object({
276
224
  without_repository: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to true, the project is created without any repository attached." }))
277
225
  });
278
226
  /**
227
+ * Access permissions configuration
228
+ */
229
+ const zPermissionsView = z.object({
230
+ others: z.optional(z.enum([
231
+ "DENIED",
232
+ "READ_ONLY",
233
+ "BLIND",
234
+ "RUN_ONLY",
235
+ "READ_WRITE",
236
+ "MANAGE",
237
+ "DEFAULT",
238
+ "ALLOWED",
239
+ "STAGE",
240
+ "COMMIT",
241
+ "USE_ONLY"
242
+ ]).register(z.globalRegistry, { description: "Access level for other workspace members" })),
243
+ users: z.optional(z.array(zUserPermissionView).register(z.globalRegistry, { description: "List of specific users with their access levels" })),
244
+ groups: z.optional(z.array(zGroupPermissionView).register(z.globalRegistry, { description: "List of user groups with their access levels" }))
245
+ }).register(z.globalRegistry, { description: "Access permissions configuration" });
246
+ /**
279
247
  * The environment variables of the sandbox
280
248
  */
281
249
  const zAddVariableInObjectRequest = z.object({
@@ -386,7 +354,8 @@ const zUpdateSandboxRequest = z.object({
386
354
  app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
387
355
  tags: z.optional(z.array(z.string().register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
388
356
  endpoints: z.optional(z.array(zTunnelView).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
389
- variables: z.optional(z.array(zAddVariableInObjectRequest).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
357
+ variables: z.optional(z.array(zAddVariableInObjectRequest).register(z.globalRegistry, { description: "The environment variables of the sandbox" })),
358
+ permissions: z.optional(zPermissionsView)
390
359
  });
391
360
  const zSandboxesView = z.object({
392
361
  url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
@@ -637,6 +606,7 @@ const zSandboxResponse = z.object({
637
606
  ]).register(z.globalRegistry, { description: "The current setup status of the sandbox" })),
638
607
  endpoints: z.optional(z.array(zTunnelView).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
639
608
  project: z.optional(zProjectView),
609
+ permissions: z.optional(zPermissionsView),
640
610
  variables: z.optional(z.array(zEnvironmentVariableView).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
641
611
  });
642
612
  /**
@@ -875,7 +845,8 @@ const zUpdateSandboxRequestWritable = z.object({
875
845
  app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
876
846
  tags: z.optional(z.array(z.string().register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
877
847
  endpoints: z.optional(z.array(zTunnelViewWritable).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
878
- variables: z.optional(z.array(zAddVariableInObjectRequestWritable).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
848
+ variables: z.optional(z.array(zAddVariableInObjectRequestWritable).register(z.globalRegistry, { description: "The environment variables of the sandbox" })),
849
+ permissions: z.optional(zPermissionsView)
879
850
  });
880
851
  const zSandboxesViewWritable = z.object({ sandboxes: z.optional(z.array(zSandboxIdViewWritable)) });
881
852
  /**
@@ -1042,6 +1013,7 @@ const zSandboxResponseWritable = z.object({
1042
1013
  ]).register(z.globalRegistry, { description: "The current setup status of the sandbox" })),
1043
1014
  endpoints: z.optional(z.array(zTunnelViewWritable).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
1044
1015
  project: z.optional(zProjectViewWritable),
1016
+ permissions: z.optional(zPermissionsView),
1045
1017
  variables: z.optional(z.array(zEnvironmentVariableView).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
1046
1018
  });
1047
1019
  const zGetSandboxesData = z.object({
@@ -1204,6 +1176,10 @@ const zDownloadSandboxContentData = z.object({
1204
1176
  }),
1205
1177
  query: z.optional(z.never())
1206
1178
  });
1179
+ /**
1180
+ * File download
1181
+ */
1182
+ const zDownloadSandboxContentResponse = z.string().register(z.globalRegistry, { description: "File download" });
1207
1183
  const zRestartSandboxData = z.object({
1208
1184
  body: z.optional(z.never()),
1209
1185
  path: z.object({
@@ -1311,7 +1287,7 @@ const zAddSandboxByYamlData = z.object({
1311
1287
  //#endregion
1312
1288
  //#region package.json
1313
1289
  var name = "@buddy-works/sandbox-sdk";
1314
- var version = "0.1.0-rc.1";
1290
+ var version = "0.1.1-rc.0";
1315
1291
 
1316
1292
  //#endregion
1317
1293
  //#region src/utils/environment.ts
@@ -2551,11 +2527,18 @@ var Sandbox = class Sandbox {
2551
2527
  }
2552
2528
  /**
2553
2529
  * Start a stopped sandbox
2554
- * Waits until the sandbox reaches RUNNING state
2530
+ *
2531
+ * If the sandbox is already running, this method returns immediately.
2532
+ * Waits until the sandbox reaches RUNNING state.
2555
2533
  */
2556
2534
  async start() {
2557
2535
  const sandboxId = this.initializedId;
2558
2536
  return withErrorHandler("Failed to start sandbox", async () => {
2537
+ await this.refresh();
2538
+ if (this.data.status === "RUNNING") {
2539
+ logger_default.debug(`Sandbox ${sandboxId} is already running.`);
2540
+ return;
2541
+ }
2559
2542
  logger_default.debug(`Starting sandbox ${sandboxId}...`);
2560
2543
  this.#sandboxData = await this.#client.startSandbox({ path: { sandbox_id: sandboxId } });
2561
2544
  await this.waitUntilRunning();
@@ -2564,11 +2547,18 @@ var Sandbox = class Sandbox {
2564
2547
  }
2565
2548
  /**
2566
2549
  * Stop a running sandbox
2567
- * Waits until the sandbox reaches STOPPED state
2550
+ *
2551
+ * If the sandbox is already stopped, this method returns immediately.
2552
+ * Waits until the sandbox reaches STOPPED state.
2568
2553
  */
2569
2554
  async stop() {
2570
2555
  const sandboxId = this.initializedId;
2571
2556
  return withErrorHandler("Failed to stop sandbox", async () => {
2557
+ await this.refresh();
2558
+ if (this.data.status === "STOPPED") {
2559
+ logger_default.debug(`Sandbox ${sandboxId} is already stopped.`);
2560
+ return;
2561
+ }
2572
2562
  logger_default.debug(`Stopping sandbox ${sandboxId}...`);
2573
2563
  this.#sandboxData = await this.#client.stopSandbox({ path: { sandbox_id: sandboxId } });
2574
2564
  await this.waitUntilStopped();
@@ -2577,6 +2567,7 @@ var Sandbox = class Sandbox {
2577
2567
  }
2578
2568
  /**
2579
2569
  * Restart the sandbox
2570
+ *
2580
2571
  * Waits until the sandbox reaches RUNNING state and setup is complete
2581
2572
  */
2582
2573
  async restart() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buddy-works/sandbox-sdk",
3
- "version": "0.1.0-rc.1",
3
+ "version": "0.1.1-rc.0",
4
4
  "type": "module",
5
5
  "description": "TypeScript SDK for managing sandboxes through the Buddy API",
6
6
  "main": "./dist/index.mjs",
@@ -46,6 +46,7 @@
46
46
  "knip": "5.81.0",
47
47
  "msw": "2.12.7",
48
48
  "tsdown": "0.20.0-beta.3",
49
+ "tsx": "4.21.0",
49
50
  "typescript": "5.9.3",
50
51
  "vitest": "4.0.17"
51
52
  },
@@ -54,7 +55,7 @@
54
55
  "zod": "4.3.5"
55
56
  },
56
57
  "scripts": {
57
- "fetch:schemas": "openapi-ts",
58
+ "fetch:schemas": "dotenvx run -q -- openapi-ts",
58
59
  "build": "tsdown",
59
60
  "test": "NODE_OPTIONS='--enable-source-maps' dotenvx run -q -- vitest run",
60
61
  "test:watch": "NODE_OPTIONS='--enable-source-maps' dotenvx run -q -- vitest",