alchemy 2.0.0-cli-shim.1 → 2.0.0-cli-bundle-fix.1
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/bin/alchemy.js +968 -814
- package/bin/alchemy.js.map +1 -1
- package/bin/alchemy.ts +4 -0
- package/bin/commands/deploy.ts +0 -1
- package/bin/commands/state.ts +230 -0
- package/lib/AWS/Lambda/BucketEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/BucketEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/EventBridgeEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/EventBridgeEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/QueueEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/QueueEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/StreamEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/StreamEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/TableEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/TableEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/TopicEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/TopicEventSource.d.ts.map +1 -1
- package/lib/Agent/lsp/client.d.ts +2 -2
- package/lib/Cli/InkCLI.d.ts +0 -1
- package/lib/Cli/InkCLI.d.ts.map +1 -1
- package/lib/Cli/InkCLI.js +0 -5
- package/lib/Cli/InkCLI.js.map +1 -1
- package/lib/Cli/index.d.ts +0 -1
- package/lib/Cli/index.d.ts.map +1 -1
- package/lib/Cli/index.js +4 -1
- package/lib/Cli/index.js.map +1 -1
- package/lib/Cloudflare/StateStore/State.d.ts +1 -1
- package/lib/Cloudflare/StateStore/State.d.ts.map +1 -1
- package/lib/Deploy.d.ts +1 -1
- package/lib/Deploy.d.ts.map +1 -1
- package/lib/Destroy.d.ts +1 -1
- package/lib/Destroy.d.ts.map +1 -1
- package/lib/Stack.d.ts +5 -4
- package/lib/Stack.d.ts.map +1 -1
- package/lib/Stack.js +27 -8
- package/lib/Stack.js.map +1 -1
- package/lib/State/HttpStateStore.js +32 -6
- package/lib/State/HttpStateStore.js.map +1 -1
- package/lib/State/Sync.d.ts +1 -0
- package/lib/State/Sync.d.ts.map +1 -1
- package/lib/State/Sync.js +1 -1
- package/lib/State/Sync.js.map +1 -1
- package/lib/Test/Bun.d.ts +2 -2
- package/lib/Test/Bun.d.ts.map +1 -1
- package/lib/Test/Bun.js +2 -4
- package/lib/Test/Bun.js.map +1 -1
- package/lib/Test/Vitest.d.ts +1 -1
- package/lib/cli/index.d.ts +2 -6
- package/lib/cli/index.d.ts.map +1 -1
- package/lib/cli/index.js +2 -43050
- package/lib/cli/index.js.map +1 -1
- package/package.json +2 -2
- package/src/Cli/InkCLI.tsx +0 -10
- package/src/Cli/index.ts +4 -1
- package/src/Stack.ts +33 -7
- package/src/State/HttpStateStore.ts +30 -7
- package/src/State/Sync.ts +4 -1
- package/src/Test/Bun.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alchemy",
|
|
3
|
-
"version": "2.0.0-cli-
|
|
3
|
+
"version": "2.0.0-cli-bundle-fix.1",
|
|
4
4
|
"homepage": "https://alchemy.run",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Sam Goodwin <sam@alchemy.run>",
|
|
@@ -255,7 +255,6 @@
|
|
|
255
255
|
"jszip": "^3.10.1",
|
|
256
256
|
"libsodium-wrappers": "^0.8.3",
|
|
257
257
|
"rolldown": "1.0.0-rc.13",
|
|
258
|
-
"solid-js": "latest",
|
|
259
258
|
"sonda": "^0.11.1",
|
|
260
259
|
"web-tree-sitter": "0.25.10",
|
|
261
260
|
"workerd": "1.20260417.1",
|
|
@@ -277,6 +276,7 @@
|
|
|
277
276
|
"pathe": "^2.0.3",
|
|
278
277
|
"react": "^19.2.0",
|
|
279
278
|
"react-devtools-core": "^7.0.1",
|
|
279
|
+
"solid-js": "latest",
|
|
280
280
|
"tsconfig-paths": "^4.2.0",
|
|
281
281
|
"tsdown": "^0.15.4",
|
|
282
282
|
"tsx": "^4.20.6",
|
package/src/Cli/InkCLI.tsx
CHANGED
|
@@ -19,16 +19,6 @@ export const inkCLI = () =>
|
|
|
19
19
|
}),
|
|
20
20
|
);
|
|
21
21
|
|
|
22
|
-
export const inkCLIAutoApprove = () =>
|
|
23
|
-
Layer.succeed(
|
|
24
|
-
Cli,
|
|
25
|
-
Cli.of({
|
|
26
|
-
approvePlan: () => Effect.succeed(true),
|
|
27
|
-
displayPlan,
|
|
28
|
-
startApplySession,
|
|
29
|
-
}),
|
|
30
|
-
);
|
|
31
|
-
|
|
32
22
|
const approvePlan = Effect.fn(function* <P extends Plan>(plan: P) {
|
|
33
23
|
let approved = false;
|
|
34
24
|
const { waitUntilExit } = render(
|
package/src/Cli/index.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export * from "./Cli.ts";
|
|
2
|
-
|
|
2
|
+
// Note: do NOT re-export InkCLI here. The Ink-based renderer pulls in
|
|
3
|
+
// `react`/`ink`, which we do not want consumers of `alchemy/Cli` to
|
|
4
|
+
// transitively depend on. Import `alchemy/Cli/InkCLI` directly when needed
|
|
5
|
+
// (currently only from `bin/alchemy.ts`, which is bundled).
|
package/src/Stack.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSp
|
|
|
13
13
|
import { AlchemyContext, AlchemyContextLive } from "./AlchemyContext.ts";
|
|
14
14
|
import { provideFreshArtifactStore } from "./Artifacts.ts";
|
|
15
15
|
import { AuthProviders } from "./Auth/AuthProvider.ts";
|
|
16
|
-
import {
|
|
16
|
+
import { Cli } from "./Cli/Cli.ts";
|
|
17
17
|
import type { Input, InputProps } from "./Input.ts";
|
|
18
18
|
import * as Output from "./Output.ts";
|
|
19
19
|
import { ref } from "./Ref.ts";
|
|
@@ -34,7 +34,8 @@ export type StackServices =
|
|
|
34
34
|
| AlchemyContext
|
|
35
35
|
| HttpClient
|
|
36
36
|
| ChildProcessSpawner
|
|
37
|
-
| AuthProviders
|
|
37
|
+
| AuthProviders
|
|
38
|
+
| Cli;
|
|
38
39
|
|
|
39
40
|
export type StackEffect<A, Err = never, Req = never> = Effect.Effect<
|
|
40
41
|
A,
|
|
@@ -44,6 +45,7 @@ export type StackEffect<A, Err = never, Req = never> = Effect.Effect<
|
|
|
44
45
|
| Scope
|
|
45
46
|
| AuthProviders
|
|
46
47
|
| AlchemyContext
|
|
48
|
+
| Cli
|
|
47
49
|
| State
|
|
48
50
|
| Req
|
|
49
51
|
>;
|
|
@@ -172,8 +174,33 @@ export const make =
|
|
|
172
174
|
effect: Effect.Effect<A, Err, Req>,
|
|
173
175
|
) =>
|
|
174
176
|
Effect.scope.pipe(
|
|
175
|
-
Effect.flatMap((scope) =>
|
|
176
|
-
options.
|
|
177
|
+
Effect.flatMap((scope) => {
|
|
178
|
+
if (options.state == null) {
|
|
179
|
+
return Effect.die(
|
|
180
|
+
new Error(
|
|
181
|
+
`Stack "${options.name}" is missing a state store. ` +
|
|
182
|
+
`Add a \`state\` layer to the stack options, e.g.:\n` +
|
|
183
|
+
` Alchemy.Stack("${options.name}", {\n` +
|
|
184
|
+
` providers: Cloudflare.providers(),\n` +
|
|
185
|
+
` state: Cloudflare.state(), // <-- required\n` +
|
|
186
|
+
` }, ...)\n` +
|
|
187
|
+
`See https://alchemy.run/concepts/state-store for available state stores.`,
|
|
188
|
+
),
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (options.providers == null) {
|
|
192
|
+
return Effect.die(
|
|
193
|
+
new Error(
|
|
194
|
+
`Stack "${options.name}" is missing a providers layer. ` +
|
|
195
|
+
`Add a \`providers\` layer to the stack options, e.g.:\n` +
|
|
196
|
+
` Alchemy.Stack("${options.name}", {\n` +
|
|
197
|
+
` providers: Cloudflare.providers(), // <-- required\n` +
|
|
198
|
+
` state: Cloudflare.state(),\n` +
|
|
199
|
+
` }, ...)`,
|
|
200
|
+
),
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
return options.providers.pipe(
|
|
177
204
|
Layer.provideMerge(options.state),
|
|
178
205
|
Layer.provideMerge(
|
|
179
206
|
Layer.effect(
|
|
@@ -192,8 +219,8 @@ export const make =
|
|
|
192
219
|
),
|
|
193
220
|
),
|
|
194
221
|
Layer.buildWithScope(scope),
|
|
195
|
-
)
|
|
196
|
-
),
|
|
222
|
+
);
|
|
223
|
+
}),
|
|
197
224
|
Effect.flatMap((context) =>
|
|
198
225
|
Effect.all([
|
|
199
226
|
effect,
|
|
@@ -257,7 +284,6 @@ export const evalStack = <A, B, Err, Req>(
|
|
|
257
284
|
),
|
|
258
285
|
),
|
|
259
286
|
Effect.provide(Layer.succeed(Stage, options.stage)),
|
|
260
|
-
Effect.provide(inkCLIAutoApprove()),
|
|
261
287
|
Effect.provide(Layer.provideMerge(alchemy, platform)),
|
|
262
288
|
Effect.scoped,
|
|
263
289
|
);
|
|
@@ -104,16 +104,39 @@ export const makeHttpStateStore = ({ url, authToken }: HttpStateStoreProps) =>
|
|
|
104
104
|
return service;
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Predicate over an `HttpClientError`-shaped failure that returns `true`
|
|
109
|
+
* for failures we expect to clear up on their own.
|
|
110
|
+
*
|
|
111
|
+
* We retry:
|
|
112
|
+
* - all transport-level errors (no `response` — DNS, TCP reset, TLS,
|
|
113
|
+
* abort, etc.)
|
|
114
|
+
* - 408 (request timeout) and 429 (rate limit)
|
|
115
|
+
* - 404, which is normal in the seconds after a worker is first
|
|
116
|
+
* deployed and the route hasn't propagated yet
|
|
117
|
+
* - every 5xx
|
|
118
|
+
*
|
|
119
|
+
* Anything else (400/401/403/etc.) is a real client-side problem and
|
|
120
|
+
* shouldn't be hidden behind retries.
|
|
121
|
+
*/
|
|
122
|
+
const isTransient = (e: any): boolean => {
|
|
123
|
+
if (e?._tag !== "HttpClientError") return false;
|
|
124
|
+
const status: number | undefined = e.response?.status;
|
|
125
|
+
if (status == null) return true;
|
|
126
|
+
if (status === 404 || status === 408 || status === 429) return true;
|
|
127
|
+
return status >= 500 && status < 600;
|
|
128
|
+
};
|
|
129
|
+
|
|
107
130
|
const retryTransient = <A, Err, Req>(eff: Effect.Effect<A, Err, Req>) =>
|
|
108
131
|
Effect.retry(eff, {
|
|
109
|
-
while:
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
132
|
+
while: isTransient,
|
|
133
|
+
// Exponential backoff capped at 2s, no attempt limit. The state
|
|
134
|
+
// store is on the deploy critical path; we'd rather block than
|
|
135
|
+
// surface a transient blip as a hard failure (which historically
|
|
136
|
+
// stranded `syncState` mid-flight, leaving the remote store
|
|
137
|
+
// partially populated).
|
|
115
138
|
schedule: Schedule.exponential(100).pipe(
|
|
116
|
-
Schedule.
|
|
139
|
+
Schedule.either(Schedule.spaced("2 seconds")),
|
|
117
140
|
),
|
|
118
141
|
});
|
|
119
142
|
|
package/src/State/Sync.ts
CHANGED
|
@@ -17,6 +17,7 @@ export const syncState = Effect.fnUntraced(function* (
|
|
|
17
17
|
source: StateService,
|
|
18
18
|
destination: StateService,
|
|
19
19
|
options?: {
|
|
20
|
+
stacks?: string[];
|
|
20
21
|
/**
|
|
21
22
|
* Maximum number of resources to copy in parallel within a single stage.
|
|
22
23
|
* @default "unbounded".
|
|
@@ -29,7 +30,9 @@ export const syncState = Effect.fnUntraced(function* (
|
|
|
29
30
|
source.listStacks(),
|
|
30
31
|
destination.listStacks(),
|
|
31
32
|
]);
|
|
32
|
-
const sourceStackSet = new Set(
|
|
33
|
+
const sourceStackSet = new Set(
|
|
34
|
+
sourceStacks.filter((stack) => options?.stacks?.includes(stack) ?? true),
|
|
35
|
+
);
|
|
33
36
|
|
|
34
37
|
yield* Effect.forEach(
|
|
35
38
|
sourceStacks,
|
package/src/Test/Bun.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { HookOptions } from "node:test";
|
|
|
9
9
|
import { AlchemyContext, AlchemyContextLive } from "../AlchemyContext.ts";
|
|
10
10
|
import { provideFreshArtifactStore } from "../Artifacts.ts";
|
|
11
11
|
import { AuthProviders } from "../Auth/AuthProvider.ts";
|
|
12
|
+
import { inkCLI } from "../Cli/InkCLI.tsx";
|
|
12
13
|
import { deploy as _deploy } from "../Deploy.ts";
|
|
13
14
|
import { destroy as _destroy } from "../Destroy.ts";
|
|
14
15
|
import {
|
|
@@ -28,8 +29,7 @@ const platform = Layer.mergeAll(PlatformServices, FetchHttpClient.layer);
|
|
|
28
29
|
|
|
29
30
|
// override alchemy state store, CLI/reporting, state, and dotAlchemy
|
|
30
31
|
const alchemy = Layer.mergeAll(
|
|
31
|
-
|
|
32
|
-
// optional
|
|
32
|
+
inkCLI(),
|
|
33
33
|
Logger.layer([Logger.consolePretty()]),
|
|
34
34
|
AlchemyContextLive,
|
|
35
35
|
);
|