@alchemy.run/boat 0.0.0-stage → 2.0.0-beta.86

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 (149) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +70 -2
  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 +186 -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 +249 -0
  114. package/lib/internal/SandboxHandle.js.map +1 -0
  115. package/lib/internal/WebhookDelivery.d.ts +16 -0
  116. package/lib/internal/WebhookDelivery.d.ts.map +1 -0
  117. package/lib/internal/WebhookDelivery.js +109 -0
  118. package/lib/internal/WebhookDelivery.js.map +1 -0
  119. package/package.json +81 -3
  120. package/src/AiProxy.ts +171 -0
  121. package/src/ApiKey.ts +250 -0
  122. package/src/AuthProvider.ts +472 -0
  123. package/src/BoatBindings.ts +136 -0
  124. package/src/Bootstrap.ts +55 -0
  125. package/src/ConnectSandbox.ts +60 -0
  126. package/src/ConnectSandboxHttp.ts +59 -0
  127. package/src/Contributions.ts +9 -0
  128. package/src/CreateSandbox.ts +143 -0
  129. package/src/CreateSandboxHttp.ts +115 -0
  130. package/src/CredentialProfile.ts +350 -0
  131. package/src/Credentials.ts +33 -0
  132. package/src/Environment.ts +416 -0
  133. package/src/Errors.ts +34 -0
  134. package/src/Providers.ts +71 -0
  135. package/src/Sandbox.ts +647 -0
  136. package/src/SandboxClient.ts +199 -0
  137. package/src/SandboxEvents.ts +125 -0
  138. package/src/SandboxEventsLive.ts +88 -0
  139. package/src/Snapshot.ts +284 -0
  140. package/src/Webhook.ts +163 -0
  141. package/src/globals.d.ts +2 -0
  142. package/src/index.ts +18 -0
  143. package/src/internal/Declared.ts +87 -0
  144. package/src/internal/Org.ts +31 -0
  145. package/src/internal/Ownership.ts +75 -0
  146. package/src/internal/Program.ts +250 -0
  147. package/src/internal/Ref.ts +15 -0
  148. package/src/internal/SandboxHandle.ts +425 -0
  149. package/src/internal/WebhookDelivery.ts +179 -0
package/lib/ApiKey.js ADDED
@@ -0,0 +1,134 @@
1
+ import * as boat from "@distilled.cloud/boat-dev/boat";
2
+ import { Unowned } from "alchemy/AdoptPolicy";
3
+ import { isResolved } from "alchemy/Diff";
4
+ import * as Provider from "alchemy/Provider";
5
+ import { Resource } from "alchemy/Resource";
6
+ import * as Effect from "effect/Effect";
7
+ import * as Redacted from "effect/Redacted";
8
+ import { boatName, isGeneratedName } from "./internal/Ownership.js";
9
+ /**
10
+ * A scoped Boat API key: the actions it may take, and the sandboxes or
11
+ * environments it reaches. Give each app or CI system its own key with
12
+ * only what it needs.
13
+ *
14
+ * Boat shows a key once, when it is created, so Alchemy keeps it in state
15
+ * as a `Redacted` value. Changing any prop creates a new key and revokes
16
+ * the old one; destroying the resource revokes it.
17
+ *
18
+ * Creating a key needs a key with `account.admin`, such as the one
19
+ * `alchemy profile edit --add Boat` signs in with. A new key cannot have
20
+ * more actions, more sandboxes or a later expiry than the key creating it.
21
+ * The key a browser sign-in gets lasts a year, so keys it creates expire
22
+ * with it. An expired key is minted again on the next deploy.
23
+ *
24
+ * ### Creating an API key
25
+ * **Example:** A key for CI that manages the sandboxes it creates
26
+ * ```typescript
27
+ * export const Ci = Boat.ApiKey("Ci", { preset: "ci", ttl: "90d" });
28
+ * ```
29
+ *
30
+ * **Example:** A key that only runs commands in one sandbox
31
+ * ```typescript
32
+ * const box = yield* Boat.Sandbox("Box", {});
33
+ * const key = yield* Boat.ApiKey("BoxExec", {
34
+ * actions: ["sandbox.read", "exec", "file.read", "file.write"],
35
+ * sandboxIds: [box.sandboxId],
36
+ * });
37
+ * ```
38
+ *
39
+ * @resource
40
+ * @product API key
41
+ */
42
+ export const ApiKey = Resource("Boat.ApiKey");
43
+ const redact = (value) => Redacted.isRedacted(value) ? value : Redacted.make(value);
44
+ const findById = (apiKeyId) => boat
45
+ .listApiKeys({})
46
+ .pipe(Effect.map((listed) => listed.apiKeys.find((key) => key.id === apiKeyId)));
47
+ /** The props that decide what a key is; Boat can't change any of them on a key. */
48
+ const scopeOf = (props) => JSON.stringify({
49
+ name: props.name,
50
+ preset: props.preset,
51
+ actions: props.actions === undefined ? undefined : [...props.actions].sort(),
52
+ sandboxIds: props.sandboxIds === undefined ? undefined : [...props.sandboxIds].sort(),
53
+ environmentIds: props.environmentIds === undefined ? undefined : [...props.environmentIds].sort(),
54
+ ttl: props.ttl ?? "never",
55
+ });
56
+ const attributesOf = (key, secret) => ({
57
+ apiKeyId: key.id,
58
+ name: key.name,
59
+ key: secret,
60
+ keyPrefix: key.keyPrefix,
61
+ keyLastFour: key.keyLastFour,
62
+ expiresAt: key.expiresAt ?? undefined,
63
+ });
64
+ /**
65
+ * Seconds until the signing key expires, from Boat's refusal ("…signed
66
+ * with an API key that expires 2027-11-07T16:21:12.757Z…"), less a minute;
67
+ * Boat's 90-day default when the message names no date.
68
+ */
69
+ const ttlUntilSignerExpires = (message) => {
70
+ const expires = /expires (\S+?Z)/.exec(message ?? "")?.[1];
71
+ const seconds = expires === undefined ? Number.NaN : (Date.parse(expires) - Date.now()) / 1000 - 60;
72
+ return Number.isFinite(seconds) && seconds > 60 ? String(Math.floor(seconds)) : "90d";
73
+ };
74
+ /** Revoke a key; revoking one that is gone succeeds. */
75
+ export const revokeApiKey = (apiKeyId) => boat.revokeApiKey({ apiKeyId }).pipe(Effect.asVoid, Effect.catchTag("NotFound", () => Effect.void));
76
+ export const ApiKeyProvider = () => Provider.effect(ApiKey, Effect.gen(function* () {
77
+ return {
78
+ stables: ["apiKeyId", "key", "keyPrefix", "keyLastFour"],
79
+ diff: Effect.fn(function* ({ news, olds }) {
80
+ if (!isResolved(news) || olds === undefined)
81
+ return undefined;
82
+ if (scopeOf(news) !== scopeOf(olds))
83
+ return { action: "replace" };
84
+ return undefined;
85
+ }),
86
+ read: Effect.fn(function* ({ olds, output }) {
87
+ // Boat never returns a key's value after creation, so a key is
88
+ // only usable through state.
89
+ if (output === undefined)
90
+ return undefined;
91
+ const key = yield* findById(output.apiKeyId);
92
+ if (key === undefined || key.expired === true)
93
+ return undefined;
94
+ const attrs = attributesOf(key, output.key);
95
+ return olds !== undefined || isGeneratedName(key.name) ? attrs : Unowned(attrs);
96
+ }),
97
+ reconcile: Effect.fn(function* ({ id, news, output, session }) {
98
+ const name = yield* boatName(id, news.name ?? output?.name);
99
+ // Observe — a key is usable only while its value is in state.
100
+ const observed = output === undefined ? undefined : yield* findById(output.apiKeyId);
101
+ if (output !== undefined && observed !== undefined && observed.expired !== true) {
102
+ return attributesOf(observed, output.key);
103
+ }
104
+ // Ensure
105
+ yield* session.note(`Creating API key ${name}...`);
106
+ const create = (ttl) => boat.createScopedApiKey({
107
+ name,
108
+ ttl,
109
+ ...(news.preset === undefined ? {} : { preset: news.preset }),
110
+ ...(news.actions === undefined ? {} : { actions: news.actions }),
111
+ ...(news.sandboxIds === undefined ? {} : { sandboxIds: news.sandboxIds }),
112
+ ...(news.environmentIds === undefined ? {} : { environmentIds: news.environmentIds }),
113
+ });
114
+ const created = yield* create(news.ttl ?? "never").pipe(
115
+ // Without a `ttl`, the longest Boat allows: as long as the key
116
+ // signing the request, whose expiry Boat names in the refusal.
117
+ Effect.catchTag("ApiKeyOutlivesSigner", (error) => news.ttl === undefined
118
+ ? Effect.suspend(() => create(ttlUntilSignerExpires(error.message)))
119
+ : Effect.fail(error)));
120
+ return attributesOf(created.apiKey, redact(created.secret));
121
+ }),
122
+ delete: Effect.fn(function* ({ output }) {
123
+ yield* revokeApiKey(output.apiKeyId);
124
+ }),
125
+ // For nuke. Listed keys carry no value; delete needs only the id.
126
+ list: Effect.fn(function* () {
127
+ const listed = yield* boat.listApiKeys({});
128
+ return listed.apiKeys
129
+ .filter((key) => isGeneratedName(key.name))
130
+ .map((key) => attributesOf(key, Redacted.make("")));
131
+ }),
132
+ };
133
+ }));
134
+ //# sourceMappingURL=ApiKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiKey.js","sources":["../src/ApiKey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import * as Layer from "effect/Layer";
2
+ import type { ChildProcessSpawner } from "effect/process/ChildProcessSpawner";
3
+ import * as Redacted from "effect/Redacted";
4
+ import * as Schema from "effect/Schema";
5
+ /**
6
+ * Canonical name registered in the AuthProviders registry. Use this key to
7
+ * look up the Boat AuthProvider from inside provider Layers.
8
+ */
9
+ export declare const BOAT_AUTH_PROVIDER_NAME = "Boat";
10
+ /**
11
+ * A Boat profile entry. Both methods store a Boat API key (`boat_…`):
12
+ *
13
+ * - `browser`: Boat's agent sign-in (https://boat.dev/auth.md). You sign in
14
+ * to boat.dev with GitHub, Google or an email code, type the code Alchemy
15
+ * shows, and Boat issues a key. The identity assertion that comes with it
16
+ * mints the next key when this one expires.
17
+ * - `stored`: you paste a key created with `boat api-keys create` or on the
18
+ * dashboard.
19
+ *
20
+ * Either may pin `org`, the organization Alchemy works in, the way the
21
+ * dashboard's organization select or `boat --org` do: every call bills it
22
+ * (`X-Boat-Org`), and `Boat.Environment` manages its shared environments.
23
+ * Sign-in picks the account's organization (asking only when it belongs
24
+ * to several) and stores its id (`team_…`), which survives renames, with
25
+ * `orgName` for display.
26
+ * Without it, sandboxes bill the account's active wallet (`boat org
27
+ * switch`) and environments are personal.
28
+ *
29
+ * A revoked key fails with Boat's `unauthorized` error; run
30
+ * `alchemy profile edit --reconfigure Boat` to sign in again.
31
+ */
32
+ export declare const BoatAuthConfigSchema: Schema.Union<readonly [Schema.Struct<{
33
+ readonly method: Schema.Literal<"browser">;
34
+ readonly email: Schema.String;
35
+ readonly apiKey: Schema.String;
36
+ readonly identityAssertion: Schema.optional<Schema.String>;
37
+ /** Epoch millis the key expires at, when Boat says. */
38
+ readonly expires: Schema.optional<Schema.Number>;
39
+ readonly account: Schema.optional<Schema.String>;
40
+ readonly org: Schema.optional<Schema.String>;
41
+ readonly orgName: Schema.optional<Schema.String>;
42
+ }>, Schema.Struct<{
43
+ readonly method: Schema.Literal<"stored">;
44
+ readonly apiKey: Schema.String;
45
+ readonly org: Schema.optional<Schema.String>;
46
+ readonly orgName: Schema.optional<Schema.String>;
47
+ }>]>;
48
+ export type BoatAuthConfig = typeof BoatAuthConfigSchema.Type;
49
+ /** Resolved Boat credentials: an API key sent as a bearer token. */
50
+ export interface BoatResolvedCredentials {
51
+ type: "apiKey";
52
+ apiKey: Redacted.Redacted<string>;
53
+ apiBaseUrl: string;
54
+ /** The organization (wallet) calls bill, sent as `X-Boat-Org`. */
55
+ org?: string;
56
+ source: {
57
+ type: BoatAuthConfig["method"] | "env";
58
+ details?: string;
59
+ };
60
+ }
61
+ /**
62
+ * Layer that registers the Boat {@link AuthProvider} into the
63
+ * `AuthProviders` registry when built. Included in `Boat.providers()` so
64
+ * `alchemy profile edit` can configure it.
65
+ *
66
+ * Supported methods:
67
+ * - `browser`: Boat's browser sign-in with GitHub or Google (interactive only).
68
+ * - `stored`: a pasted API key (`--method stored --set apiKey=-`).
69
+ */
70
+ export declare const BoatAuth: Layer.Layer<never, never, import("alchemy/Auth/Registry").AuthProviders | ChildProcessSpawner | import("effect/FileSystem").FileSystem | import("effect/Path").Path | import("effect/crypto/SecureRandom").SecureRandom>;
71
+ //# sourceMappingURL=AuthProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthProvider.d.ts","sources":["../src/AuthProvider.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,oBAAoB;;;;;IAM7B,uDAAuD;;;;;;;;;;IAYzD,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,oBAAoB,CAAC,IAAI,CAAC;AAG9D,oEAAoE;AACpE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACtE;AAkPD;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,0NAkIpB,CAAC"}
@@ -0,0 +1,322 @@
1
+ import * as boat from "@distilled.cloud/boat-dev";
2
+ import { DEFAULT_API_BASE_URL, fromApiKey } from "@distilled.cloud/boat-dev/Credentials";
3
+ import * as Login from "@distilled.cloud/boat-dev/Login";
4
+ import { AuthError, AuthProviderLayer, NeedsReauth, refreshHint, } from "alchemy/Auth/AuthProvider";
5
+ import { displayRedacted } from "alchemy/Auth/Credentials";
6
+ import { getEnv, getEnvRedacted, mapPromptCancellation } from "alchemy/Auth/Env";
7
+ import { collectFieldValues, storedSecret, storedValueText, validateFieldValues, } from "alchemy/Auth/StoredAuthProvider";
8
+ import * as Interaction from "alchemy/Interaction";
9
+ import * as Clock from "effect/Clock";
10
+ import * as Duration from "effect/Duration";
11
+ import * as Effect from "effect/Effect";
12
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
13
+ import * as Layer from "effect/Layer";
14
+ import * as Match from "effect/Match";
15
+ import * as Redacted from "effect/Redacted";
16
+ import * as Schema from "effect/Schema";
17
+ /**
18
+ * Canonical name registered in the AuthProviders registry. Use this key to
19
+ * look up the Boat AuthProvider from inside provider Layers.
20
+ */
21
+ export const BOAT_AUTH_PROVIDER_NAME = "Boat";
22
+ /**
23
+ * A Boat profile entry. Both methods store a Boat API key (`boat_…`):
24
+ *
25
+ * - `browser`: Boat's agent sign-in (https://boat.dev/auth.md). You sign in
26
+ * to boat.dev with GitHub, Google or an email code, type the code Alchemy
27
+ * shows, and Boat issues a key. The identity assertion that comes with it
28
+ * mints the next key when this one expires.
29
+ * - `stored`: you paste a key created with `boat api-keys create` or on the
30
+ * dashboard.
31
+ *
32
+ * Either may pin `org`, the organization Alchemy works in, the way the
33
+ * dashboard's organization select or `boat --org` do: every call bills it
34
+ * (`X-Boat-Org`), and `Boat.Environment` manages its shared environments.
35
+ * Sign-in picks the account's organization (asking only when it belongs
36
+ * to several) and stores its id (`team_…`), which survives renames, with
37
+ * `orgName` for display.
38
+ * Without it, sandboxes bill the account's active wallet (`boat org
39
+ * switch`) and environments are personal.
40
+ *
41
+ * A revoked key fails with Boat's `unauthorized` error; run
42
+ * `alchemy profile edit --reconfigure Boat` to sign in again.
43
+ */
44
+ export const BoatAuthConfigSchema = Schema.Union([
45
+ Schema.Struct({
46
+ method: Schema.Literal("browser"),
47
+ email: Schema.String,
48
+ apiKey: Schema.String,
49
+ identityAssertion: Schema.optional(Schema.String),
50
+ /** Epoch millis the key expires at, when Boat says. */
51
+ expires: Schema.optional(Schema.Number),
52
+ account: Schema.optional(Schema.String),
53
+ org: Schema.optional(Schema.String),
54
+ orgName: Schema.optional(Schema.String),
55
+ }),
56
+ Schema.Struct({
57
+ method: Schema.Literal("stored"),
58
+ apiKey: Schema.String,
59
+ org: Schema.optional(Schema.String),
60
+ orgName: Schema.optional(Schema.String),
61
+ }),
62
+ ]);
63
+ const apiKeyField = {
64
+ name: "apiKey",
65
+ label: "Boat API key",
66
+ description: "Create one with `boat api-keys create` or at https://boat.dev/dashboard.",
67
+ secret: true,
68
+ validate: (value) => (value.trim().startsWith("boat_") ? undefined : "Expected a boat_… key"),
69
+ };
70
+ const orgField = {
71
+ name: "org",
72
+ label: "Boat organization",
73
+ description: "The organization to work in: its id (team_…), its name, or `personal`. Leave it out to follow your active wallet.",
74
+ optional: true,
75
+ };
76
+ /** `--set` fields; interactively the org is picked from a list instead. */
77
+ const keyFields = [apiKeyField, orgField];
78
+ /** A set org, trimmed; blank means the active wallet. */
79
+ const orgOf = (value) => {
80
+ const org = value?.trim();
81
+ return org ? { org } : {};
82
+ };
83
+ const storedConfig = (values) => ({
84
+ method: "stored",
85
+ apiKey: Redacted.value(storedSecret(values.apiKey) ?? Redacted.make("")).trim(),
86
+ ...orgOf(storedValueText(values.org)),
87
+ });
88
+ /** Sentinel choice: pin nothing and follow the account's active wallet. */
89
+ const ACTIVE_WALLET = "";
90
+ /**
91
+ * The organization to work in. An account in no organization works
92
+ * personally and one in exactly one works in it, without a question;
93
+ * only an account in several is asked to pick.
94
+ */
95
+ const chooseOrg = Effect.fn(function* (apiKey, current) {
96
+ const { orgs } = yield* boat.listOrganizations({}).pipe(Effect.provide(Layer.mergeAll(fromApiKey({ apiKey }), FetchHttpClient.layer)), Effect.mapError((cause) => AuthError.make({ message: "Boat: could not list your organizations.", cause })));
97
+ const teams = orgs.filter((org) => org.type === "org");
98
+ if (teams.length === 0)
99
+ return {};
100
+ if (teams.length === 1) {
101
+ const [team] = teams;
102
+ yield* Interaction.info(`Boat: working in ${team.name}.`);
103
+ return { org: team.id, orgName: team.name };
104
+ }
105
+ const active = orgs.find((org) => org.active);
106
+ const org = yield* Interaction.select({
107
+ message: "Boat organization to work in",
108
+ options: [
109
+ ...teams.map((team) => ({
110
+ value: team.id,
111
+ label: team.name,
112
+ description: `${team.role ?? "member"}: sandboxes bill it, environments are its shared ones`,
113
+ })),
114
+ {
115
+ value: "personal",
116
+ label: "Personal",
117
+ description: "your own wallet and your personal environments",
118
+ },
119
+ {
120
+ value: ACTIVE_WALLET,
121
+ label: "Follow the active wallet",
122
+ description: `whatever \`boat org switch\` picks (now ${active?.name ?? "Personal"}); environments stay personal`,
123
+ },
124
+ ],
125
+ initialValue: current ?? (active?.type === "org" ? active.id : teams[0].id),
126
+ }).pipe(mapPromptCancellation);
127
+ if (org === ACTIVE_WALLET)
128
+ return {};
129
+ const orgName = org === "personal" ? "Personal" : teams.find((team) => team.id === org)?.name;
130
+ return { org, ...(orgName ? { orgName } : {}) };
131
+ });
132
+ const loginFailed = (cause) => AuthError.make({ message: `Boat: browser sign-in failed: ${cause.message}`, cause });
133
+ /** The account a key acts for, as `boat whoami` shows it. */
134
+ const accountOf = (apiKey) => boat.getCurrentUser({}).pipe(Effect.provide(Layer.mergeAll(fromApiKey({ apiKey }), FetchHttpClient.layer)), Effect.map(({ user }) => user.email ?? user.login ?? user.displayName ?? user.id), Effect.mapError((cause) => AuthError.make({ message: "Boat: the new API key was refused.", cause })));
135
+ /** Fresh codes the sign-in hands out before it gives up. */
136
+ const CODE_ROUNDS = 6;
137
+ /** Polls give up after this many attempts: about fifteen minutes at 5s. */
138
+ const POLL_ATTEMPTS = 180;
139
+ const expiryOf = (now, expiresIn) => expiresIn === undefined ? {} : { expires: now + expiresIn * 1000 };
140
+ /**
141
+ * Boat's agent sign-in: register for the account with the user's email,
142
+ * open the claim page, where the user signs in with any method and types the
143
+ * code, then poll until Boat issues a key.
144
+ */
145
+ const browserLogin = (initialEmail, initialOrg) => Effect.gen(function* () {
146
+ const email = (yield* Interaction.text({
147
+ message: "Email of your Boat account",
148
+ description: "You sign in on boat.dev next, with GitHub, Google or an email code.",
149
+ ...(initialEmail ? { initialValue: initialEmail } : {}),
150
+ validate: (value) => (value.includes("@") ? undefined : "Expected an email address"),
151
+ }).pipe(mapPromptCancellation)).trim();
152
+ const http = FetchHttpClient.layer;
153
+ const registered = yield* Login.registerAgent({ email }).pipe(Effect.provide(http), Effect.mapError(loginFailed));
154
+ const poll = (claim, interval, attempt) => Effect.sleep(Duration.seconds(interval)).pipe(Effect.andThen(Login.pollClaim({ claimToken: claim.claimToken, interval }).pipe(Effect.provide(http))), Effect.flatMap((result) => result._tag === "Issued"
155
+ ? Effect.succeed(result.key)
156
+ : attempt >= POLL_ATTEMPTS
157
+ ? Effect.fail(AuthError.make({ message: "Boat: the sign-in wasn't completed in time." }))
158
+ : poll(claim, result.interval, attempt + 1)));
159
+ // A code lapses after about ten minutes (`expired_token`); the claim
160
+ // then hands out a fresh one, shown in a new sign-in prompt.
161
+ const signIn = (claim, round) => Interaction.browserLogin({
162
+ provider: "Boat",
163
+ url: claim.verificationUri,
164
+ code: claim.userCode,
165
+ waitFor: poll(claim, claim.interval, 1),
166
+ }).pipe(Effect.catchIf((e) => e._tag === "BoatLoginError" && e.code === "expired_token" && round < CODE_ROUNDS, () => Login.refreshClaim({ claimToken: claim.claimToken, email }).pipe(Effect.provide(http), Effect.mapError(loginFailed), Effect.tap(() => Interaction.info("Boat: the code expired; here is a new one.")), Effect.flatMap((next) => signIn(next, round + 1)))), Effect.mapError((e) => (e._tag === "AuthError" ? e : loginFailed(e))));
167
+ const key = yield* signIn(registered, 1);
168
+ const account = yield* accountOf(key.apiKey);
169
+ yield* Interaction.success(`Boat: signed in as ${account ?? email}.`);
170
+ const org = yield* chooseOrg(key.apiKey, initialOrg);
171
+ const now = yield* Clock.currentTimeMillis;
172
+ return {
173
+ method: "browser",
174
+ email,
175
+ apiKey: Redacted.value(key.apiKey),
176
+ ...(key.identityAssertion
177
+ ? { identityAssertion: Redacted.value(key.identityAssertion) }
178
+ : {}),
179
+ ...expiryOf(now, key.expiresIn),
180
+ ...(account ? { account } : {}),
181
+ ...org,
182
+ };
183
+ });
184
+ /** Mints a new key from the assertion when the stored one is within a minute of expiring. */
185
+ const freshKey = Effect.fn(function* (profileName, config) {
186
+ const now = yield* Clock.currentTimeMillis;
187
+ if (config.expires === undefined || config.expires > now + 60_000)
188
+ return config;
189
+ if (config.identityAssertion === undefined) {
190
+ return yield* NeedsReauth.make({
191
+ provider: BOAT_AUTH_PROVIDER_NAME,
192
+ profile: profileName,
193
+ message: `Boat API key expired. ${refreshHint(BOAT_AUTH_PROVIDER_NAME, profileName)}`,
194
+ });
195
+ }
196
+ const key = yield* Login.exchangeAssertion({
197
+ identityAssertion: Redacted.make(config.identityAssertion),
198
+ }).pipe(Effect.provide(FetchHttpClient.layer), Effect.mapError((cause) => NeedsReauth.make({
199
+ provider: BOAT_AUTH_PROVIDER_NAME,
200
+ profile: profileName,
201
+ message: `Boat sign-in expired. ${refreshHint(BOAT_AUTH_PROVIDER_NAME, profileName)}`,
202
+ cause,
203
+ })));
204
+ return {
205
+ ...config,
206
+ apiKey: Redacted.value(key.apiKey),
207
+ ...(key.identityAssertion ? { identityAssertion: Redacted.value(key.identityAssertion) } : {}),
208
+ expires: key.expiresIn === undefined ? undefined : now + key.expiresIn * 1000,
209
+ };
210
+ });
211
+ const readEnvironment = Effect.gen(function* () {
212
+ const apiKey = yield* getEnvRedacted("BOAT_API_KEY");
213
+ if (apiKey === undefined || Redacted.value(apiKey).trim().length === 0) {
214
+ return yield* AuthError.make({
215
+ message: "Boat CI credentials not found. Set BOAT_API_KEY.",
216
+ });
217
+ }
218
+ return {
219
+ type: "apiKey",
220
+ apiKey: Redacted.make(Redacted.value(apiKey).trim()),
221
+ apiBaseUrl: (yield* getEnv("BOAT_API_BASE_URL")) ?? DEFAULT_API_BASE_URL,
222
+ ...orgOf(yield* getEnv("BOAT_ORG")),
223
+ source: { type: "env", details: "BOAT_API_KEY" },
224
+ };
225
+ });
226
+ const resolve = (config) => ({
227
+ type: "apiKey",
228
+ apiKey: Redacted.make(config.apiKey),
229
+ apiBaseUrl: DEFAULT_API_BASE_URL,
230
+ ...orgOf(config.org),
231
+ source: {
232
+ type: config.method,
233
+ details: config.method === "browser" ? (config.account ?? config.email) : undefined,
234
+ },
235
+ });
236
+ /**
237
+ * Layer that registers the Boat {@link AuthProvider} into the
238
+ * `AuthProviders` registry when built. Included in `Boat.providers()` so
239
+ * `alchemy profile edit` can configure it.
240
+ *
241
+ * Supported methods:
242
+ * - `browser`: Boat's browser sign-in with GitHub or Google (interactive only).
243
+ * - `stored`: a pasted API key (`--method stored --set apiKey=-`).
244
+ */
245
+ export const BoatAuth = AuthProviderLayer()(BOAT_AUTH_PROVIDER_NAME, Effect.gen(function* () {
246
+ const pasteKey = collectFieldValues([apiKeyField]).pipe(Effect.map(storedConfig), Effect.flatMap((config) => chooseOrg(Redacted.make(config.apiKey)).pipe(Effect.map((org) => ({ ...config, ...org })))), Effect.tap(() => Interaction.success("Boat: credentials saved.")));
247
+ const configure = (_profileName) => Interaction.select({
248
+ message: "Boat authentication method",
249
+ options: [
250
+ {
251
+ value: "browser",
252
+ label: "Browser sign-in",
253
+ description: "recommended — sign in on boat.dev with GitHub, Google or email",
254
+ },
255
+ {
256
+ value: "stored",
257
+ label: "API key",
258
+ description: "paste a boat_… key",
259
+ },
260
+ ],
261
+ }).pipe(mapPromptCancellation, Effect.flatMap((method) => Match.value(method).pipe(Match.when("browser", () => browserLogin()), Match.when("stored", () => pasteKey), Match.exhaustive)), Effect.mapError((e) => e._tag === "AuthError"
262
+ ? e
263
+ : AuthError.make({ message: "Boat: failed to configure credentials", cause: e })));
264
+ /** The browser sign-in needs a person, so only `stored` takes flags. */
265
+ const configureMethods = [
266
+ { method: "stored", fields: keyFields },
267
+ ];
268
+ const configureWith = (_profileName, input) => input.method === "stored"
269
+ ? validateFieldValues(BOAT_AUTH_PROVIDER_NAME, keyFields, input.values).pipe(Effect.map(storedConfig), Effect.tap(() => Interaction.success("Boat: credentials saved.")))
270
+ : Effect.fail(AuthError.make({
271
+ message: `Boat: unknown method '${input.method}'. Valid methods: stored. (Browser sign-in is interactive-only.)`,
272
+ }));
273
+ // A key doesn't refresh, so logging in again repeats the browser
274
+ // sign-in; a pasted key stays as it is.
275
+ const login = (_profileName, config) => config.method === "browser"
276
+ ? browserLogin(config.email, config.org).pipe(Effect.mapError((e) => e._tag === "AuthError"
277
+ ? e
278
+ : AuthError.make({ message: "Boat: login failed", cause: e })))
279
+ : Effect.succeed(config);
280
+ const details = (_profileName, config) => Effect.succeed({
281
+ lines: [
282
+ ...(config.method === "browser"
283
+ ? [{ key: "account", value: config.account ?? config.email }]
284
+ : []),
285
+ { key: "apiKey", value: displayRedacted(Redacted.make(config.apiKey)) },
286
+ ...(config.org ? [{ key: "org", value: config.orgName ?? config.org }] : []),
287
+ { key: "source", value: config.method },
288
+ ],
289
+ });
290
+ return {
291
+ configSchema: BoatAuthConfigSchema,
292
+ configure,
293
+ configureWith,
294
+ configureMethods,
295
+ login,
296
+ logout: () => Effect.void,
297
+ details,
298
+ read: (profileName, config, updateConfig) => config.method === "stored"
299
+ ? Effect.succeed(resolve(config))
300
+ : freshKey(profileName, config).pipe(Effect.tap((fresh) => fresh === config ? Effect.void : (updateConfig?.(fresh) ?? Effect.void)), Effect.map(resolve)),
301
+ readEnvironment,
302
+ environment: [
303
+ {
304
+ name: "BOAT_API_KEY",
305
+ required: true,
306
+ secret: true,
307
+ description: "Boat API key (`boat_…`).",
308
+ },
309
+ {
310
+ name: "BOAT_API_BASE_URL",
311
+ required: false,
312
+ description: `Boat API URL override. Defaults to ${DEFAULT_API_BASE_URL}.`,
313
+ },
314
+ {
315
+ name: "BOAT_ORG",
316
+ required: false,
317
+ description: "Boat organization (wallet) to bill: an org id (`team_…`), an org name, or `personal`. Defaults to the account's active wallet.",
318
+ },
319
+ ],
320
+ };
321
+ }));
322
+ //# sourceMappingURL=AuthProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthProvider.js","sources":["../src/AuthProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
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 } from "@distilled.cloud/boat-dev/Credentials";
21
+ import type { RuntimeContext } from "alchemy/RuntimeContext";
22
+ import * as Effect from "effect/Effect";
23
+ import type * as HttpClient from "effect/http/HttpClient";
24
+ /** The `alchemy.*` labels on sandboxes a host creates at run time. */
25
+ export type OwnerLabels = Readonly<Record<string, string>>;
26
+ export interface BoatAuth {
27
+ /** Runs a distilled call with the binding's key and an HTTP client. */
28
+ readonly authorize: <A, E>(effect: Effect.Effect<A, E, Credentials | HttpClient.HttpClient>) => Effect.Effect<A, E, RuntimeContext>;
29
+ }
30
+ /**
31
+ * Mints the binding's key (`<keyId>` in the host's namespace, with
32
+ * `scope`) and binds it onto the host as `<envName>`, and returns a runtime
33
+ * accessor for it. Without a host (a script) nothing is minted, and calls
34
+ * use the ambient credentials.
35
+ */
36
+ export declare const bindBoat: (keyId: string, envName: string, scope: {
37
+ name?: import("alchemy/Input").Input<string | undefined>;
38
+ preset?: import("alchemy/Input").Input<import("./ApiKey.ts").ApiKeyPreset | undefined>;
39
+ actions?: import("alchemy/Input").Input<import("./ApiKey.ts").ApiKeyAction[] | undefined>;
40
+ sandboxIds?: import("alchemy/Input").Input<string[] | undefined>;
41
+ environmentIds?: import("alchemy/Input").Input<string[] | undefined>;
42
+ ttl?: import("alchemy/Input").Input<string | undefined>;
43
+ }) => Effect.Effect<{
44
+ authorize: <A, E>(effect: Effect.Effect<A, E, Credentials | HttpClient.HttpClient>) => Effect.Effect<A, E, never>;
45
+ }, never, never>;
46
+ /**
47
+ * Binds the host's `alchemy.stack` / `alchemy.stage` / `alchemy.id` into
48
+ * it, and returns them at run time for `create` to label what it makes.
49
+ * Without a host (a script) there are none.
50
+ */
51
+ export declare const bindOwnerLabels: Effect.Effect<Effect.Effect<Readonly<Record<string, string>>, never, never>, never, never>;
52
+ //# sourceMappingURL=BoatBindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoatBindings.d.ts","sources":["../src/BoatBindings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,WAAW,EAAwB,MAAM,uCAAuC,CAAC;AAM1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG7D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,KAAK,UAAU,MAAM,wBAAwB,CAAC;AAU1D,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE3D,MAAM,WAAW,QAAQ;IACvB,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,KAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC;CAC1C;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ;;;;;;;;gBAXE,CAAC,EAAE,CAAC;gBAyDzB,CAAC;AAUH;;;;GAIG;AACH,eAAO,MAAM,eAAe,4FAkB1B,CAAC"}