@alchemy.run/boat 0.0.0 → 2.0.0-beta.87

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 (154) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +66 -4
  3. package/lib/AiProxy.d.ts +89 -0
  4. package/lib/AiProxy.d.ts.map +1 -0
  5. package/lib/AiProxy.js +125 -0
  6. package/lib/AiProxy.js.map +1 -0
  7. package/lib/ApiKey.d.ts +105 -0
  8. package/lib/ApiKey.d.ts.map +1 -0
  9. package/lib/ApiKey.js +134 -0
  10. package/lib/ApiKey.js.map +1 -0
  11. package/lib/AuthProvider.d.ts +71 -0
  12. package/lib/AuthProvider.d.ts.map +1 -0
  13. package/lib/AuthProvider.js +322 -0
  14. package/lib/AuthProvider.js.map +1 -0
  15. package/lib/BoatBindings.d.ts +52 -0
  16. package/lib/BoatBindings.d.ts.map +1 -0
  17. package/lib/BoatBindings.js +104 -0
  18. package/lib/BoatBindings.js.map +1 -0
  19. package/lib/Bootstrap.d.ts +8 -0
  20. package/lib/Bootstrap.d.ts.map +1 -0
  21. package/lib/Bootstrap.js +28 -0
  22. package/lib/Bootstrap.js.map +1 -0
  23. package/lib/ConnectSandbox.d.ts +56 -0
  24. package/lib/ConnectSandbox.d.ts.map +1 -0
  25. package/lib/ConnectSandbox.js +3 -0
  26. package/lib/ConnectSandbox.js.map +1 -0
  27. package/lib/ConnectSandboxHttp.d.ts +21 -0
  28. package/lib/ConnectSandboxHttp.d.ts.map +1 -0
  29. package/lib/ConnectSandboxHttp.js +46 -0
  30. package/lib/ConnectSandboxHttp.js.map +1 -0
  31. package/lib/Contributions.d.ts +7 -0
  32. package/lib/Contributions.d.ts.map +1 -0
  33. package/lib/Contributions.js +6 -0
  34. package/lib/Contributions.js.map +1 -0
  35. package/lib/CreateSandbox.d.ts +134 -0
  36. package/lib/CreateSandbox.d.ts.map +1 -0
  37. package/lib/CreateSandbox.js +3 -0
  38. package/lib/CreateSandbox.js.map +1 -0
  39. package/lib/CreateSandboxHttp.d.ts +21 -0
  40. package/lib/CreateSandboxHttp.d.ts.map +1 -0
  41. package/lib/CreateSandboxHttp.js +93 -0
  42. package/lib/CreateSandboxHttp.js.map +1 -0
  43. package/lib/CredentialProfile.d.ts +157 -0
  44. package/lib/CredentialProfile.d.ts.map +1 -0
  45. package/lib/CredentialProfile.js +245 -0
  46. package/lib/CredentialProfile.js.map +1 -0
  47. package/lib/Credentials.d.ts +15 -0
  48. package/lib/Credentials.d.ts.map +1 -0
  49. package/lib/Credentials.js +23 -0
  50. package/lib/Credentials.js.map +1 -0
  51. package/lib/Environment.d.ts +219 -0
  52. package/lib/Environment.d.ts.map +1 -0
  53. package/lib/Environment.js +273 -0
  54. package/lib/Environment.js.map +1 -0
  55. package/lib/Errors.d.ts +50 -0
  56. package/lib/Errors.d.ts.map +1 -0
  57. package/lib/Errors.js +17 -0
  58. package/lib/Errors.js.map +1 -0
  59. package/lib/Providers.d.ts +33 -0
  60. package/lib/Providers.d.ts.map +1 -0
  61. package/lib/Providers.js +47 -0
  62. package/lib/Providers.js.map +1 -0
  63. package/lib/Sandbox.d.ts +205 -0
  64. package/lib/Sandbox.d.ts.map +1 -0
  65. package/lib/Sandbox.js +368 -0
  66. package/lib/Sandbox.js.map +1 -0
  67. package/lib/SandboxClient.d.ts +159 -0
  68. package/lib/SandboxClient.d.ts.map +1 -0
  69. package/lib/SandboxClient.js +1 -0
  70. package/lib/SandboxClient.js.map +1 -0
  71. package/lib/SandboxEvents.d.ts +111 -0
  72. package/lib/SandboxEvents.d.ts.map +1 -0
  73. package/lib/SandboxEvents.js +60 -0
  74. package/lib/SandboxEvents.js.map +1 -0
  75. package/lib/SandboxEventsLive.d.ts +13 -0
  76. package/lib/SandboxEventsLive.d.ts.map +1 -0
  77. package/lib/SandboxEventsLive.js +63 -0
  78. package/lib/SandboxEventsLive.js.map +1 -0
  79. package/lib/Snapshot.d.ts +123 -0
  80. package/lib/Snapshot.d.ts.map +1 -0
  81. package/lib/Snapshot.js +173 -0
  82. package/lib/Snapshot.js.map +1 -0
  83. package/lib/Webhook.d.ts +56 -0
  84. package/lib/Webhook.d.ts.map +1 -0
  85. package/lib/Webhook.js +98 -0
  86. package/lib/Webhook.js.map +1 -0
  87. package/lib/index.d.ts +19 -0
  88. package/lib/index.d.ts.map +1 -0
  89. package/lib/index.js +19 -0
  90. package/lib/index.js.map +1 -0
  91. package/lib/internal/Declared.d.ts +34 -0
  92. package/lib/internal/Declared.d.ts.map +1 -0
  93. package/lib/internal/Declared.js +38 -0
  94. package/lib/internal/Declared.js.map +1 -0
  95. package/lib/internal/Org.d.ts +22 -0
  96. package/lib/internal/Org.d.ts.map +1 -0
  97. package/lib/internal/Org.js +23 -0
  98. package/lib/internal/Org.js.map +1 -0
  99. package/lib/internal/Ownership.d.ts +29 -0
  100. package/lib/internal/Ownership.d.ts.map +1 -0
  101. package/lib/internal/Ownership.js +50 -0
  102. package/lib/internal/Ownership.js.map +1 -0
  103. package/lib/internal/Program.d.ts +69 -0
  104. package/lib/internal/Program.d.ts.map +1 -0
  105. package/lib/internal/Program.js +178 -0
  106. package/lib/internal/Program.js.map +1 -0
  107. package/lib/internal/Ref.d.ts +14 -0
  108. package/lib/internal/Ref.d.ts.map +1 -0
  109. package/lib/internal/Ref.js +7 -0
  110. package/lib/internal/Ref.js.map +1 -0
  111. package/lib/internal/SandboxHandle.d.ts +17 -0
  112. package/lib/internal/SandboxHandle.d.ts.map +1 -0
  113. package/lib/internal/SandboxHandle.js +238 -0
  114. package/lib/internal/SandboxHandle.js.map +1 -0
  115. package/lib/internal/SavedSnapshot.d.ts +10 -0
  116. package/lib/internal/SavedSnapshot.d.ts.map +1 -0
  117. package/lib/internal/SavedSnapshot.js +22 -0
  118. package/lib/internal/SavedSnapshot.js.map +1 -0
  119. package/lib/internal/WebhookDelivery.d.ts +16 -0
  120. package/lib/internal/WebhookDelivery.d.ts.map +1 -0
  121. package/lib/internal/WebhookDelivery.js +109 -0
  122. package/lib/internal/WebhookDelivery.js.map +1 -0
  123. package/package.json +67 -3
  124. package/src/AiProxy.ts +171 -0
  125. package/src/ApiKey.ts +250 -0
  126. package/src/AuthProvider.ts +472 -0
  127. package/src/BoatBindings.ts +136 -0
  128. package/src/Bootstrap.ts +55 -0
  129. package/src/ConnectSandbox.ts +60 -0
  130. package/src/ConnectSandboxHttp.ts +59 -0
  131. package/src/Contributions.ts +9 -0
  132. package/src/CreateSandbox.ts +143 -0
  133. package/src/CreateSandboxHttp.ts +115 -0
  134. package/src/CredentialProfile.ts +350 -0
  135. package/src/Credentials.ts +33 -0
  136. package/src/Environment.ts +416 -0
  137. package/src/Errors.ts +34 -0
  138. package/src/Providers.ts +71 -0
  139. package/src/Sandbox.ts +647 -0
  140. package/src/SandboxClient.ts +200 -0
  141. package/src/SandboxEvents.ts +125 -0
  142. package/src/SandboxEventsLive.ts +88 -0
  143. package/src/Snapshot.ts +264 -0
  144. package/src/Webhook.ts +163 -0
  145. package/src/globals.d.ts +2 -0
  146. package/src/index.ts +18 -0
  147. package/src/internal/Declared.ts +87 -0
  148. package/src/internal/Org.ts +31 -0
  149. package/src/internal/Ownership.ts +75 -0
  150. package/src/internal/Program.ts +250 -0
  151. package/src/internal/Ref.ts +15 -0
  152. package/src/internal/SandboxHandle.ts +407 -0
  153. package/src/internal/SavedSnapshot.ts +34 -0
  154. package/src/internal/WebhookDelivery.ts +179 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * How Boat bindings reach Boat from any host.
3
+ *
4
+ * Boat has scoped API keys and no identity federation, so every binding
5
+ * mints its own key at deploy, a `Boat.ApiKey` in the host's namespace,
6
+ * with only the actions it needs and, for a declared sandbox, only that
7
+ * sandbox. The key is deleted with the host. The deployer's credentials
8
+ * never reach a host. The binding captures the key as a named runtime
9
+ * Output; inside the deployed host it is read back from the host's env,
10
+ * still `Redacted`. Every runtime call provides `Credentials` from it, so
11
+ * nothing reads `process.env`. The deployer's org and API URL are bound
12
+ * alongside it (`BOAT_ORG`, `BOAT_API_BASE_URL`), so the host's calls bill
13
+ * the same wallet the deploy did.
14
+ *
15
+ * Bindings that create sandboxes at run time label them with the host's
16
+ * `alchemy.stack` / `alchemy.stage` / `alchemy.id`, computed at deploy and
17
+ * bound into the host (`bindOwnerLabels`). Destroying the stack does not
18
+ * delete them.
19
+ */
20
+ import { Credentials, DEFAULT_API_BASE_URL } from "@distilled.cloud/boat-dev/Credentials";
21
+ import { orDieCredentialsUnavailable } from "alchemy/Auth/Resolve";
22
+ import * as Binding from "alchemy/Binding";
23
+ import * as Namespace from "alchemy/Namespace";
24
+ import * as Output from "alchemy/Output";
25
+ import { Stack } from "alchemy/Stack";
26
+ import { Stage } from "alchemy/Stage";
27
+ import * as Effect from "effect/Effect";
28
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
29
+ import * as Layer from "effect/Layer";
30
+ import * as Option from "effect/Option";
31
+ import * as Redacted from "effect/Redacted";
32
+ import { ApiKey } from "./ApiKey.js";
33
+ import { ALCHEMY_LABEL_PREFIX } from "./internal/Ownership.js";
34
+ /** A plain value as an Output with no requirements (`asOutput` leaves them `any`). */
35
+ const output = (value) => Output.asOutput(value);
36
+ /**
37
+ * Mints the binding's key (`<keyId>` in the host's namespace, with
38
+ * `scope`) and binds it onto the host as `<envName>`, and returns a runtime
39
+ * accessor for it. Without a host (a script) nothing is minted, and calls
40
+ * use the ambient credentials.
41
+ */
42
+ export const bindBoat = Effect.fn("Boat.bind")(function* (keyId, envName, scope) {
43
+ // Yielding the resource class erases its `Providers` requirement; the
44
+ // stack satisfies it at plan time.
45
+ const makeKey = yield* ApiKey;
46
+ let apiKey = output(Redacted.make(""));
47
+ let deployer = { apiBaseUrl: DEFAULT_API_BASE_URL, org: "" };
48
+ if (!globalThis.__ALCHEMY_RUNTIME__) {
49
+ const host = yield* Binding.Host;
50
+ if (host !== undefined) {
51
+ const key = yield* Namespace.push(host.LogicalId, makeKey(keyId, scope));
52
+ apiKey = key.key;
53
+ const credentials = yield* Effect.serviceOption(Credentials);
54
+ if (Option.isSome(credentials)) {
55
+ const { apiBaseUrl, org } = yield* credentials.value.pipe(orDieCredentialsUnavailable("Boat"));
56
+ deployer = { apiBaseUrl, org: org ?? "" };
57
+ }
58
+ }
59
+ }
60
+ const key = yield* Output.named(apiKey, envName).asEffect();
61
+ const apiBaseUrl = yield* Output.named(output(deployer.apiBaseUrl), "BOAT_API_BASE_URL").asEffect();
62
+ const org = yield* Output.named(output(deployer.org), "BOAT_ORG").asEffect();
63
+ const services = Layer.mergeAll(Layer.succeed(Credentials, Effect.all([key, apiBaseUrl, org]).pipe(Effect.map(([apiKey, apiBaseUrl, org]) => ({
64
+ apiKey,
65
+ apiBaseUrl: apiBaseUrl || DEFAULT_API_BASE_URL,
66
+ ...(org ? { org } : {}),
67
+ })))), FetchHttpClient.layer);
68
+ return {
69
+ authorize: (effect) => effect.pipe(Effect.provide(services)),
70
+ };
71
+ });
72
+ const parseOwnerLabels = (json) => {
73
+ try {
74
+ return JSON.parse(json || "{}");
75
+ }
76
+ catch {
77
+ return {};
78
+ }
79
+ };
80
+ /**
81
+ * Binds the host's `alchemy.stack` / `alchemy.stage` / `alchemy.id` into
82
+ * it, and returns them at run time for `create` to label what it makes.
83
+ * Without a host (a script) there are none.
84
+ */
85
+ export const bindOwnerLabels = Effect.gen(function* () {
86
+ let labels = "{}";
87
+ if (!globalThis.__ALCHEMY_RUNTIME__) {
88
+ const host = yield* Binding.Host;
89
+ // The values `createInternalTags(host.LogicalId)` gives, read without
90
+ // adding `Stack` / `Stage` to the binding's requirements.
91
+ const stack = yield* Effect.serviceOption(Stack);
92
+ const stage = yield* Effect.serviceOption(Stage);
93
+ if (host !== undefined && Option.isSome(stack) && Option.isSome(stage)) {
94
+ labels = JSON.stringify({
95
+ [`${ALCHEMY_LABEL_PREFIX}stack`]: stack.value.name,
96
+ [`${ALCHEMY_LABEL_PREFIX}stage`]: stage.value,
97
+ [`${ALCHEMY_LABEL_PREFIX}id`]: host.LogicalId,
98
+ });
99
+ }
100
+ }
101
+ const bound = yield* Output.named(output(labels), "BOAT_OWNER_LABELS").asEffect();
102
+ return Effect.map(bound, parseOwnerLabels);
103
+ });
104
+ //# sourceMappingURL=BoatBindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoatBindings.js","sources":["../src/BoatBindings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Resolve the bundled program (the runners registered via `host.run` /
3
+ * serve) and run it with a Node HTTP server bound to `PORT` on every
4
+ * interface, so the sandbox's port URL reaches the `{ fetch }`
5
+ * handler and `host.run` loops stay alive.
6
+ */
7
+ export declare const bootstrap: (entrypoint: unknown) => Promise<void>;
8
+ //# sourceMappingURL=Bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bootstrap.d.ts","sources":["../src/Bootstrap.ts"],"names":[],"mappings":"AAsBA;;;;;GAKG;AACH,eAAO,MAAM,SAAS,eAAgB,OAAO,KAAG,OAAO,CAAC,IAAI,CA0B3D,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Process bootstrap for a `Boat.Sandbox` with `main` (a Node process in
3
+ * the sandbox serving the bundled program). The generated entry imports this module
4
+ * and the user's `main`, nothing else — see `alchemy/Runtime/Bootstrap`
5
+ * for why.
6
+ */
7
+ import { NodeServices } from "@effect/platform-node";
8
+ import { NodeHttpServer } from "alchemy/Http";
9
+ import { reifyBoundConfigProvider } from "alchemy/Runtime";
10
+ import { entrypointLayer, resolveProgram, runProcess, stackFromEnv, } from "alchemy/Runtime/Bootstrap";
11
+ import * as ConfigProvider from "effect/ConfigProvider";
12
+ import * as SecureRandom from "effect/crypto/SecureRandom";
13
+ import * as Effect from "effect/Effect";
14
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
15
+ import * as Layer from "effect/Layer";
16
+ import * as Logger from "effect/Logger";
17
+ /**
18
+ * Resolve the bundled program (the runners registered via `host.run` /
19
+ * serve) and run it with a Node HTTP server bound to `PORT` on every
20
+ * interface, so the sandbox's port URL reaches the `{ fetch }`
21
+ * handler and `host.run` loops stay alive.
22
+ */
23
+ export const bootstrap = (entrypoint) => {
24
+ const platform = Layer.mergeAll(NodeServices.layer, FetchHttpClient.layer, SecureRandom.layerWebCrypto, Logger.layer([Logger.consolePretty()]));
25
+ const program = resolveProgram("program").pipe(Effect.provide(entrypointLayer(entrypoint).pipe(Layer.provideMerge(stackFromEnv), Layer.provideMerge(NodeHttpServer({ hostname: "0.0.0.0" })), Layer.provideMerge(platform), Layer.provideMerge(Layer.succeed(ConfigProvider.ConfigProvider, reifyBoundConfigProvider(ConfigProvider.fromEnv(), process.env))))), Effect.scoped);
26
+ return runProcess("Boat program", program);
27
+ };
28
+ //# sourceMappingURL=Bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bootstrap.js","sources":["../src/Bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,cAAc,EACd,UAAU,EACV,YAAY,GACb,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,YAAY,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,UAAmB,EAAiB,EAAE;IAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAC7B,YAAY,CAAC,KAAK,EAClB,eAAe,CAAC,KAAK,EACrB,YAAY,CAAC,cAAc,EAC3B,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CACvC,CAAC;IAEF,MAAM,OAAO,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,IAAI,CAC5C,MAAM,CAAC,OAAO,CACZ,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAC9B,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,EAChC,KAAK,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,EAC3D,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,EAC5B,KAAK,CAAC,YAAY,CAChB,KAAK,CAAC,OAAO,CACX,cAAc,CAAC,cAAc,EAC7B,wBAAwB,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAChE,CACF,CACF,CACF,EACD,MAAM,CAAC,MAAM,CACd,CAAC;IAEF,OAAO,UAAU,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC,CAAC"}
@@ -0,0 +1,56 @@
1
+ import * as Binding from "alchemy/Binding";
2
+ import type * as Effect from "effect/Effect";
3
+ import type { Sandbox } from "./Sandbox.ts";
4
+ import type { ConnectedSandbox } from "./SandboxClient.ts";
5
+ /**
6
+ * Work with one {@link Sandbox} declared in the stack, from a Worker,
7
+ * Function or any other host: run commands, read and write files, call its
8
+ * ports, stop, resume or snapshot it. The handle has the same operations
9
+ * as the sandboxes `CreateSandbox` returns, except `fork` and `delete`; its
10
+ * `sandboxId` is an Effect, read at runtime.
11
+ *
12
+ * A declared sandbox stops after its `autoStop`. Calls into it then fail
13
+ * with `SandboxNotRunning` until you `resume()` it.
14
+ *
15
+ * The host gets its own Boat API key, minted at deploy and revoked when the
16
+ * host is destroyed. The key reaches only this sandbox.
17
+ *
18
+ * ### Running commands in a dev box
19
+ * **Example:** Pull and test on request
20
+ * ```typescript
21
+ * const devBox = yield* Boat.ConnectSandbox(DevBox);
22
+ * return {
23
+ * fetch: Effect.gen(function* () {
24
+ * yield* devBox.resume({ autoStop: "10 minutes" });
25
+ * const test = yield* devBox.exec("git pull && npm test", { cwd: "/home/user/repo" });
26
+ * return yield* HttpServerResponse.json(test);
27
+ * }),
28
+ * };
29
+ * ```
30
+ *
31
+ * ### Calling a program in the sandbox
32
+ * **Example:** Call port 3000
33
+ * ```typescript
34
+ * const port = yield* devBox.getTcpPort(3000);
35
+ * const response = yield* port.fetch(HttpClientRequest.get("/health"));
36
+ * ```
37
+ *
38
+ * **Example:** Proxy the Worker's request to port 3000
39
+ * ```typescript
40
+ * const port = yield* devBox.getTcpPort(3000);
41
+ * return yield* port.fetch(yield* HttpServerRequest);
42
+ * ```
43
+ *
44
+ * ### Stopping it early
45
+ * **Example:** Stop when the work is done
46
+ * ```typescript
47
+ * yield* devBox.stop();
48
+ * ```
49
+ *
50
+ * @binding
51
+ * @product Sandbox
52
+ */
53
+ export interface ConnectSandbox extends Binding.Service<ConnectSandbox, "Boat.ConnectSandbox", (sandbox: Sandbox) => Effect.Effect<ConnectedSandbox>> {
54
+ }
55
+ export declare const ConnectSandbox: ConnectSandbox;
56
+ //# sourceMappingURL=ConnectSandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectSandbox.d.ts","sources":["../src/ConnectSandbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,WAAW,cAAe,SAAQ,OAAO,CAAC,OAAO,CACrD,cAAc,EACd,qBAAqB,EACrB,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CACtD;CAAG;AAEJ,eAAO,MAAM,cAAc,gBAAyD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import * as Binding from "alchemy/Binding";
2
+ export const ConnectSandbox = Binding.Service("Boat.ConnectSandbox");
3
+ //# sourceMappingURL=ConnectSandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectSandbox.js","sources":["../src/ConnectSandbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AA2D3C,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAiB,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import * as Layer from "effect/Layer";
2
+ import { ConnectSandbox } from "./ConnectSandbox.ts";
3
+ /**
4
+ * HTTP implementation of {@link ConnectSandbox}: Boat's REST API with a key
5
+ * that reaches only the bound sandbox. Works on any host.
6
+ *
7
+ * ### Provide the layer
8
+ * **Example:** On a Cloudflare Worker
9
+ * ```typescript
10
+ * Effect.gen(function* () {
11
+ * const devBox = yield* Boat.ConnectSandbox(DevBox);
12
+ * // ...
13
+ * }).pipe(Effect.provide(Boat.ConnectSandboxHttp))
14
+ * ```
15
+ *
16
+ * @layer
17
+ * @product Sandbox
18
+ * @provides Boat.ConnectSandbox
19
+ */
20
+ export declare const ConnectSandboxHttp: Layer.Layer<ConnectSandbox, never, never>;
21
+ //# sourceMappingURL=ConnectSandboxHttp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectSandboxHttp.d.ts","sources":["../src/ConnectSandboxHttp.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAyBrD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,kBAAkB,2CAW9B,CAAC"}
@@ -0,0 +1,46 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
3
+ import { bindBoat } from "./BoatBindings.js";
4
+ import { ConnectSandbox } from "./ConnectSandbox.js";
5
+ import { makeConnectedSandbox } from "./internal/SandboxHandle.js";
6
+ /** What a `ConnectSandbox` host may do, on its one sandbox. */
7
+ const CONNECT_SANDBOX_ACTIONS = [
8
+ "sandbox.read",
9
+ "sandbox.update",
10
+ "sandbox.stop",
11
+ "sandbox.resume",
12
+ "exec",
13
+ "file.read",
14
+ "file.write",
15
+ "host",
16
+ "snapshot.read",
17
+ "snapshot.write",
18
+ ];
19
+ /** `DevBox` → `DEV_BOX`, for the env var that carries its key. */
20
+ const envSuffix = (logicalId) => logicalId
21
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
22
+ .replace(/[^A-Za-z0-9]+/g, "_")
23
+ .toUpperCase();
24
+ /**
25
+ * HTTP implementation of {@link ConnectSandbox}: Boat's REST API with a key
26
+ * that reaches only the bound sandbox. Works on any host.
27
+ *
28
+ * ### Provide the layer
29
+ * **Example:** On a Cloudflare Worker
30
+ * ```typescript
31
+ * Effect.gen(function* () {
32
+ * const devBox = yield* Boat.ConnectSandbox(DevBox);
33
+ * // ...
34
+ * }).pipe(Effect.provide(Boat.ConnectSandboxHttp))
35
+ * ```
36
+ *
37
+ * @layer
38
+ * @product Sandbox
39
+ * @provides Boat.ConnectSandbox
40
+ */
41
+ export const ConnectSandboxHttp = Layer.succeed(ConnectSandbox, Effect.fn("Boat.ConnectSandbox")(function* (sandbox) {
42
+ const auth = yield* bindBoat(`${sandbox.LogicalId}Key`, `BOAT_${envSuffix(sandbox.LogicalId)}_KEY`, { actions: CONNECT_SANDBOX_ACTIONS, sandboxIds: [sandbox.sandboxId] });
43
+ const sandboxId = yield* sandbox.sandboxId.asEffect();
44
+ return makeConnectedSandbox(auth, sandboxId);
45
+ }));
46
+ //# sourceMappingURL=ConnectSandboxHttp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectSandboxHttp.js","sources":["../src/ConnectSandboxHttp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,+DAA+D;AAC/D,MAAM,uBAAuB,GAAmB;IAC9C,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,MAAM;IACN,WAAW;IACX,YAAY;IACZ,MAAM;IACN,eAAe;IACf,gBAAgB;CACjB,CAAC;AAEF,kEAAkE;AAClE,MAAM,SAAS,GAAG,CAAC,SAAiB,EAAE,EAAE,CACtC,SAAS;KACN,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;KACtC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;KAC9B,WAAW,EAAE,CAAC;AAEnB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAC7C,cAAc,EACd,MAAM,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAgB;IAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,QAAQ,CAC1B,GAAG,OAAO,CAAC,SAAS,KAAK,EACzB,QAAQ,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,EAC1C,EAAE,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CACtE,CAAC;IACF,MAAM,SAAS,GAAG,KAAK,CAAC,CAAE,OAAO,CAAC,SAA0C,CAAC,QAAQ,EAAE,CAAC;IACxF,OAAO,oBAAoB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC,CAAC,CACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import * as Contributions from "alchemy/Contributions";
2
+ declare const _default: {
3
+ readonly name: "boat";
4
+ readonly auth: Contributions.Lazy<import("effect/Layer").Layer<never, never, import("alchemy/Auth/Registry").AuthProviders | import("effect/process/ChildProcessSpawner").ChildProcessSpawner | import("effect/FileSystem").FileSystem | import("effect/Path").Path | import("effect/crypto/SecureRandom").SecureRandom>>;
5
+ };
6
+ export default _default;
7
+ //# sourceMappingURL=Contributions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Contributions.d.ts","sources":["../src/Contributions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,aAAa,MAAM,uBAAuB,CAAC;;;;;AAEvD,wBAMG"}
@@ -0,0 +1,6 @@
1
+ import * as Contributions from "alchemy/Contributions";
2
+ export default Contributions.make({
3
+ name: "boat",
4
+ auth: Contributions.lazy(() => import("./AuthProvider.js"), (module) => module.BoatAuth),
5
+ });
6
+ //# sourceMappingURL=Contributions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Contributions.js","sources":["../src/Contributions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,aAAa,MAAM,uBAAuB,CAAC;AAEvD,eAAe,aAAa,CAAC,IAAI,CAAC;IAChC,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,aAAa,CAAC,IAAI,CACtB,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,EACjC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAC5B;CACF,CAAC,CAAC"}
@@ -0,0 +1,134 @@
1
+ import type * as boat from "@distilled.cloud/boat-dev/boat";
2
+ import * as Binding from "alchemy/Binding";
3
+ import type { RuntimeContext } from "alchemy/RuntimeContext";
4
+ import type * as Duration from "effect/Duration";
5
+ import type * as Effect from "effect/Effect";
6
+ import type { BoatError, BoatSandbox } from "./SandboxClient.ts";
7
+ import type { Snapshot } from "./Snapshot.ts";
8
+ /**
9
+ * Boat's `createSandbox` parameters, with `autoStop` in place of
10
+ * `ttlSeconds`. `from` defaults to the bound snapshot; `labels` are merged
11
+ * under the host's ownership labels.
12
+ */
13
+ export type CreateSandboxOptions = Omit<boat.CreateSandboxRequest, "count" | "ttlSeconds"> & {
14
+ /**
15
+ * How long the sandbox runs before Boat stops it, saving its disk;
16
+ * `false` never stops it.
17
+ * @default "1 hour"
18
+ */
19
+ readonly autoStop?: Duration.Input | false;
20
+ };
21
+ /** Boat's `listSandboxes` filters, with `labels` as a record. */
22
+ export interface ListSandboxesOptions {
23
+ /** Only sandboxes with all of these labels. */
24
+ readonly labels?: Readonly<Record<string, string>>;
25
+ /** Only sandboxes in these states, e.g. `["ready", "idle", "running"]`. */
26
+ readonly state?: ReadonlyArray<boat.SandboxState>;
27
+ }
28
+ /** Boat sandboxes: create, connect to, list and delete them. */
29
+ export interface SandboxesClient {
30
+ /** Creates a sandbox, from the bound snapshot unless `from` says otherwise. */
31
+ create(options?: CreateSandboxOptions): Effect.Effect<BoatSandbox, BoatError, RuntimeContext>;
32
+ /** A handle to an existing sandbox. */
33
+ connect(sandboxId: string): Effect.Effect<BoatSandbox, BoatError, RuntimeContext>;
34
+ /** A sandbox's details. */
35
+ get(sandboxId: string): Effect.Effect<boat.Sandbox, BoatError, RuntimeContext>;
36
+ /** Sandboxes, filtered by labels or state. */
37
+ list(options?: ListSandboxesOptions): Effect.Effect<ReadonlyArray<boat.Sandbox>, BoatError, RuntimeContext>;
38
+ /**
39
+ * Deletes a sandbox this host created, with its disk. Deleting one that
40
+ * is gone succeeds.
41
+ */
42
+ delete(sandboxId: string): Effect.Effect<void, BoatError, RuntimeContext>;
43
+ }
44
+ /**
45
+ * Create and manage Boat sandboxes from a Worker, Function or any other
46
+ * host.
47
+ *
48
+ * `Boat.CreateSandbox(snapshot)` creates sandboxes from a snapshot declared
49
+ * in the stack; `Boat.CreateSandbox()` creates them from scratch, or from
50
+ * the `from` each call passes. Both return the same client, whose calls take
51
+ * Boat's own parameters.
52
+ *
53
+ * Sandboxes created at run time are labelled with the stack, stage and
54
+ * host (`alchemy.stack`, `alchemy.stage`, `alchemy.id`) and are not deleted
55
+ * when the stack is destroyed. List them by those labels to clean them up:
56
+ * `sandboxes.list({ labels: { "alchemy.stack": "my-app", "alchemy.stage": "prod" } })`.
57
+ * Labels you pass to `create` merge underneath; they never replace the
58
+ * `alchemy.*` ones.
59
+ *
60
+ * The host gets its own Boat API key, minted at deploy and revoked when the
61
+ * host is destroyed. It may create sandboxes and work in them, and delete
62
+ * only the sandboxes it created; it can't touch the account's other
63
+ * sandboxes, environments, keys or billing.
64
+ *
65
+ * ### Creating sandboxes
66
+ * **Example:** One sandbox per request, deleted when the request ends
67
+ * ```typescript
68
+ * const sandboxes = yield* Boat.CreateSandbox();
69
+ * // in fetch:
70
+ * const sandbox = yield* Effect.acquireRelease(
71
+ * sandboxes.create({ type: "small", noEnv: true, autoStop: "10 minutes" }),
72
+ * (sandbox) => Effect.ignore(sandbox.delete()),
73
+ * );
74
+ * const result = yield* sandbox.exec("node --version");
75
+ * ```
76
+ *
77
+ * **Example:** From a snapshot declared in the stack
78
+ * ```typescript
79
+ * const sandboxes = yield* Boat.CreateSandbox(Golden);
80
+ * const sandbox = yield* sandboxes.create();
81
+ * ```
82
+ *
83
+ * **Example:** A long-lived sandbox per task, found by label
84
+ * ```typescript
85
+ * const [existing] = yield* sandboxes.list({ labels: { task } });
86
+ * const sandbox = existing
87
+ * ? yield* sandboxes.connect(existing.id)
88
+ * : yield* sandboxes.create({ labels: { task }, autoStop: "30 minutes" });
89
+ * ```
90
+ *
91
+ * ### Running commands
92
+ * `exec` runs to completion and returns `{ exitCode, stdout, stderr }`; a
93
+ * non-zero exit is returned, not failed. A string runs in a shell, an
94
+ * array runs its arguments quoted.
95
+ *
96
+ * **Example:** A shell line, an argument vector, stdin and a timeout
97
+ * ```typescript
98
+ * const test = yield* sandbox.exec("npm test", { cwd: "/home/user/app" });
99
+ * const version = yield* sandbox.exec(["node", "--version"]);
100
+ * const sorted = yield* sandbox.exec("sort", { stdin: "b\na\n" });
101
+ * const slow = yield* sandbox.exec("make", { timeout: "2 minutes" }); // Boat.ExecTimedOut
102
+ * ```
103
+ *
104
+ * **Example:** Start a server in the background and stream its output
105
+ * ```typescript
106
+ * const server = yield* sandbox.start("npm run dev", { cwd: "/home/user/app" });
107
+ * yield* server.output.pipe(
108
+ * Stream.take(5),
109
+ * Stream.runForEach((chunk) => Effect.log(new TextDecoder().decode(chunk.data))),
110
+ * );
111
+ * ```
112
+ *
113
+ * ### Calling a port
114
+ * **Example:** Proxy the Worker's request to port 3000
115
+ * ```typescript
116
+ * const port = yield* sandbox.getTcpPort(3000);
117
+ * return yield* port.fetch(yield* HttpServerRequest);
118
+ * ```
119
+ *
120
+ * ### Forking and snapshots
121
+ * **Example:** Save a sandbox and fork it
122
+ * ```typescript
123
+ * yield* sandbox.stop(); // stopping snapshots it
124
+ * const copy = yield* sandbox.fork({ autoStop: "10 minutes" });
125
+ * yield* sandbox.resume();
126
+ * ```
127
+ *
128
+ * @binding
129
+ * @product Sandbox
130
+ */
131
+ export interface CreateSandbox extends Binding.Service<CreateSandbox, "Boat.CreateSandbox", (base?: Snapshot) => Effect.Effect<SandboxesClient>> {
132
+ }
133
+ export declare const CreateSandbox: CreateSandbox;
134
+ //# sourceMappingURL=CreateSandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateSandbox.d.ts","sources":["../src/CreateSandbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,gCAAgC,CAAC;AAC5D,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,YAAY,CAAC,GAAG;IAC3F;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;CAC5C,CAAC;AAEF,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;CACnD;AAED,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,MAAM,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IAC9F,uCAAuC;IACvC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IAClF,2BAA2B;IAC3B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IAC/E,8CAA8C;IAC9C,IAAI,CACF,OAAO,CAAC,EAAE,oBAAoB,GAC7B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IACzE;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;CAC3E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AACH,MAAM,WAAW,aAAc,SAAQ,OAAO,CAAC,OAAO,CACpD,aAAa,EACb,oBAAoB,EACpB,CAAC,IAAI,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CACpD;CAAG;AAEJ,eAAO,MAAM,aAAa,eAAuD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import * as Binding from "alchemy/Binding";
2
+ export const CreateSandbox = Binding.Service("Boat.CreateSandbox");
3
+ //# sourceMappingURL=CreateSandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateSandbox.js","sources":["../src/CreateSandbox.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AA6I3C,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAgB,oBAAoB,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import * as Layer from "effect/Layer";
2
+ import { CreateSandbox } from "./CreateSandbox.ts";
3
+ /**
4
+ * HTTP implementation of {@link CreateSandbox}: Boat's REST API with the
5
+ * host's own key. Works on any host.
6
+ *
7
+ * ### Provide the layer
8
+ * **Example:** On a Cloudflare Worker
9
+ * ```typescript
10
+ * Effect.gen(function* () {
11
+ * const sandboxes = yield* Boat.CreateSandbox();
12
+ * // ...
13
+ * }).pipe(Effect.provide(Boat.CreateSandboxHttp))
14
+ * ```
15
+ *
16
+ * @layer
17
+ * @product Sandbox
18
+ * @provides Boat.CreateSandbox
19
+ */
20
+ export declare const CreateSandboxHttp: Layer.Layer<CreateSandbox, never, never>;
21
+ //# sourceMappingURL=CreateSandboxHttp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateSandboxHttp.d.ts","sources":["../src/CreateSandboxHttp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAItC,OAAO,EAAE,aAAa,EAAmD,MAAM,oBAAoB,CAAC;AAuBpG;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,0CAmE7B,CAAC"}
@@ -0,0 +1,93 @@
1
+ import * as boat from "@distilled.cloud/boat-dev/boat";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import * as Stream from "effect/Stream";
5
+ import { bindBoat, bindOwnerLabels } from "./BoatBindings.js";
6
+ import { CreateSandbox } from "./CreateSandbox.js";
7
+ import { BoatUnexpectedResponse } from "./Errors.js";
8
+ import { labelFilter } from "./internal/Ownership.js";
9
+ import { makeSandboxHandle, ttlOf } from "./internal/SandboxHandle.js";
10
+ /** What a `CreateSandbox` host may do: work in sandboxes, and delete only its own. */
11
+ const CREATE_SANDBOX_ACTIONS = [
12
+ "sandbox.create",
13
+ "sandbox.read",
14
+ "sandbox.update",
15
+ "sandbox.stop",
16
+ "sandbox.resume",
17
+ "sandbox.fork",
18
+ "sandbox.delete-own",
19
+ "exec",
20
+ "file.read",
21
+ "file.write",
22
+ "host",
23
+ "snapshot.read",
24
+ "snapshot.write",
25
+ ];
26
+ /**
27
+ * HTTP implementation of {@link CreateSandbox}: Boat's REST API with the
28
+ * host's own key. Works on any host.
29
+ *
30
+ * ### Provide the layer
31
+ * **Example:** On a Cloudflare Worker
32
+ * ```typescript
33
+ * Effect.gen(function* () {
34
+ * const sandboxes = yield* Boat.CreateSandbox();
35
+ * // ...
36
+ * }).pipe(Effect.provide(Boat.CreateSandboxHttp))
37
+ * ```
38
+ *
39
+ * @layer
40
+ * @product Sandbox
41
+ * @provides Boat.CreateSandbox
42
+ */
43
+ export const CreateSandboxHttp = Layer.succeed(CreateSandbox, Effect.fn("Boat.CreateSandbox")(function* (base) {
44
+ const auth = yield* bindBoat("BoatSandboxesKey", "BOAT_SANDBOXES_KEY", {
45
+ actions: CREATE_SANDBOX_ACTIONS,
46
+ });
47
+ const owner = yield* bindOwnerLabels;
48
+ const baseName = base === undefined
49
+ ? undefined
50
+ : yield* base.name.asEffect();
51
+ const handleOf = (sandbox) => makeSandboxHandle(auth, sandbox, owner);
52
+ const client = {
53
+ create: Effect.fn("Boat.CreateSandbox.create")(function* (createOptions = {}) {
54
+ const { autoStop, ...options } = createOptions;
55
+ const from = options.from ?? (baseName === undefined ? undefined : yield* baseName);
56
+ const created = yield* auth.authorize(boat.createSandbox({
57
+ ...options,
58
+ ...(autoStop === undefined ? {} : { ttlSeconds: ttlOf(autoStop) }),
59
+ ...(from === undefined ? {} : { from }),
60
+ labels: { ...options.labels, ...(yield* owner) },
61
+ }));
62
+ return handleOf(created.sandbox);
63
+ }),
64
+ connect: Effect.fn("Boat.CreateSandbox.connect")(function* (sandboxId) {
65
+ const got = yield* auth.authorize(boat.getSandbox({ sandboxId }));
66
+ if (got.sandbox === undefined) {
67
+ return yield* new BoatUnexpectedResponse({
68
+ message: `Boat returned no sandbox for ${sandboxId}`,
69
+ });
70
+ }
71
+ return handleOf(got.sandbox);
72
+ }),
73
+ get: Effect.fn("Boat.CreateSandbox.get")(function* (sandboxId) {
74
+ const got = yield* auth.authorize(boat.getSandbox({ sandboxId }));
75
+ if (got.sandbox === undefined) {
76
+ return yield* new BoatUnexpectedResponse({
77
+ message: `Boat returned no sandbox for ${sandboxId}`,
78
+ });
79
+ }
80
+ return got.sandbox;
81
+ }),
82
+ list: Effect.fn("Boat.CreateSandbox.list")(function* (options) {
83
+ const all = yield* auth.authorize(Stream.runCollect(boat.listSandboxes.items({
84
+ ...(options?.labels === undefined ? {} : { label: labelFilter(options.labels) }),
85
+ ...(options?.state === undefined ? {} : { state: options.state.join(",") }),
86
+ })));
87
+ return Array.from(all);
88
+ }),
89
+ delete: (sandboxId) => auth.authorize(boat.deleteSandbox({ sandboxId, xAsciiConfirmDelete: sandboxId })).pipe(Effect.asVoid, Effect.catchTag("NotFound", () => Effect.void)),
90
+ };
91
+ return client;
92
+ }));
93
+ //# sourceMappingURL=CreateSandboxHttp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateSandboxHttp.js","sources":["../src/CreateSandboxHttp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,gCAAgC,CAAC;AAEvD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAmD,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAGvE,sFAAsF;AACtF,MAAM,sBAAsB,GAAmB;IAC7C,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,oBAAoB;IACpB,MAAM;IACN,WAAW;IACX,YAAY;IACZ,MAAM;IACN,eAAe;IACf,gBAAgB;CACjB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,CAAC,OAAO,CAC5C,aAAa,EACb,MAAM,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAe;IACxD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,kBAAkB,EAAE,oBAAoB,EAAE;QACrE,OAAO,EAAE,sBAAsB;KAChC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,eAAe,CAAC;IACrC,MAAM,QAAQ,GACZ,IAAI,KAAK,SAAS;QAChB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,KAAK,CAAC,CAAE,IAAI,CAAC,IAAqC,CAAC,QAAQ,EAAE,CAAC;IAEpE,MAAM,QAAQ,GAAG,CAAC,OAAqB,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAEpF,MAAM,MAAM,GAAoB;QAC9B,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,2BAA2B,CAAC,CAAC,QAAQ,CAAC,EACtD,aAAa,GAAyB,EAAE;YAExC,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,GAAG,aAAa,CAAC;YAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC;YACpF,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CACnC,IAAI,CAAC,aAAa,CAAC;gBACjB,GAAG,OAAO;gBACV,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAClE,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;gBACvC,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;aACjD,CAAC,CACH,CAAC;YACF,OAAO,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC,CAAC;QACF,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,QAAQ,CAAC,EAAE,SAAS;YACnE,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAClE,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC9B,OAAO,KAAK,CAAC,CAAC,IAAI,sBAAsB,CAAC;oBACvC,OAAO,EAAE,gCAAgC,SAAS,EAAE;iBACrD,CAAC,CAAC;YACL,CAAC;YACD,OAAO,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC,CAAC;QACF,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC,QAAQ,CAAC,EAAE,SAAS;YAC3D,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAClE,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC9B,OAAO,KAAK,CAAC,CAAC,IAAI,sBAAsB,CAAC;oBACvC,OAAO,EAAE,gCAAgC,SAAS,EAAE;iBACrD,CAAC,CAAC;YACL,CAAC;YACD,OAAO,GAAG,CAAC,OAAO,CAAC;QACrB,CAAC,CAAC;QACF,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO;YAC3D,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAC/B,MAAM,CAAC,UAAU,CACf,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;gBACvB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAChF,GAAG,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;aAC5E,CAAC,CACH,CACF,CAAC;YACF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC;QACF,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,CACpB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,mBAAmB,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CACpF,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAC/C;KACJ,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC,CACH,CAAC"}