alchemy 0.37.2 → 0.38.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.mjs +44306 -48055
- package/bin/alchemy.ts +80 -85
- package/bin/commands/create.ts +263 -0
- package/bin/constants.ts +13 -0
- package/bin/errors.ts +11 -0
- package/bin/services/dependencies.ts +47 -0
- package/bin/services/get-package-version.ts +11 -0
- package/bin/services/package-manager.ts +113 -0
- package/bin/services/template-manager.ts +137 -0
- package/bin/types.ts +83 -0
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +12 -3
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.d.ts +2 -0
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +47 -12
- package/lib/apply.js.map +1 -1
- package/lib/build-date.d.ts +6 -0
- package/lib/build-date.d.ts.map +1 -0
- package/lib/build-date.js +8 -0
- package/lib/build-date.js.map +1 -0
- package/lib/cloudflare/api.d.ts.map +1 -1
- package/lib/cloudflare/api.js +2 -1
- package/lib/cloudflare/api.js.map +1 -1
- package/lib/cloudflare/do-state-store/internal.js +5 -3
- package/lib/cloudflare/do-state-store/internal.js.map +1 -1
- package/lib/cloudflare/do-state-store/worker.d.ts.map +1 -1
- package/lib/cloudflare/do-state-store/worker.js +6 -1
- package/lib/cloudflare/do-state-store/worker.js.map +1 -1
- package/lib/cloudflare/pipeline.d.ts +1 -1
- package/lib/cloudflare/pipeline.d.ts.map +1 -1
- package/lib/cloudflare/pipeline.js +6 -1
- package/lib/cloudflare/pipeline.js.map +1 -1
- package/lib/cloudflare/worker-stub.d.ts +23 -2
- package/lib/cloudflare/worker-stub.d.ts.map +1 -1
- package/lib/cloudflare/worker-stub.js +16 -2
- package/lib/cloudflare/worker-stub.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +5 -4
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +4 -7
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/context.d.ts +2 -2
- package/lib/context.d.ts.map +1 -1
- package/lib/destroy.d.ts +8 -2
- package/lib/destroy.d.ts.map +1 -1
- package/lib/destroy.js +19 -5
- package/lib/destroy.js.map +1 -1
- package/lib/scope.d.ts +26 -4
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +104 -9
- package/lib/scope.js.map +1 -1
- package/lib/sentry/project.js +1 -1
- package/lib/sentry/project.js.map +1 -1
- package/lib/util/logger.js +1 -1
- package/lib/util/logger.js.map +1 -1
- package/lib/util/mutex.d.ts +9 -0
- package/lib/util/mutex.d.ts.map +1 -0
- package/lib/util/mutex.js +35 -0
- package/lib/util/mutex.js.map +1 -0
- package/package.json +16 -6
- package/src/alchemy.ts +17 -5
- package/src/apply.ts +67 -17
- package/src/build-date.ts +8 -0
- package/src/cloudflare/api.ts +2 -1
- package/src/cloudflare/do-state-store/internal.ts +5 -3
- package/src/cloudflare/do-state-store/worker.ts +13 -3
- package/src/cloudflare/pipeline.ts +6 -0
- package/src/cloudflare/worker-stub.ts +31 -2
- package/src/cloudflare/worker.ts +6 -15
- package/src/context.ts +2 -2
- package/src/destroy.ts +30 -7
- package/src/scope.ts +145 -10
- package/src/sentry/project.ts +1 -1
- package/src/util/logger.ts +1 -1
- package/src/util/mutex.ts +33 -0
- package/templates/astro/.vscode/extensions.json +4 -0
- package/templates/astro/.vscode/launch.json +11 -0
- package/templates/astro/README.md +48 -0
- package/templates/astro/_env.example +1 -0
- package/templates/astro/_gitignore +27 -0
- package/templates/astro/alchemy.run.ts +16 -0
- package/templates/astro/astro.config.mjs +8 -0
- package/templates/astro/package.json +23 -0
- package/templates/astro/public/favicon.svg +9 -0
- package/templates/astro/src/assets/astro.svg +1 -0
- package/templates/astro/src/assets/background.svg +1 -0
- package/templates/astro/src/components/Welcome.astro +210 -0
- package/templates/astro/src/layouts/Layout.astro +22 -0
- package/templates/astro/src/pages/api/hello.ts +19 -0
- package/templates/astro/src/pages/index.astro +11 -0
- package/templates/astro/tsconfig.json +18 -0
- package/templates/astro/types/env.d.ts +16 -0
- package/templates/astro/wrangler.jsonc +6 -0
- package/templates/nuxt/README.md +75 -0
- package/templates/nuxt/_env +1 -0
- package/templates/nuxt/_env.example +1 -0
- package/templates/nuxt/_gitignore +27 -0
- package/templates/nuxt/alchemy.run.ts +16 -0
- package/templates/nuxt/app.vue +6 -0
- package/templates/nuxt/nuxt.config.ts +13 -0
- package/templates/nuxt/package.json +26 -0
- package/templates/nuxt/public/favicon.ico +0 -0
- package/templates/nuxt/public/robots.txt +2 -0
- package/templates/nuxt/server/api/hello.ts +7 -0
- package/templates/nuxt/server/middleware/auth.ts +5 -0
- package/templates/nuxt/server/middleware/hello.ts +5 -0
- package/templates/nuxt/server/tsconfig.json +3 -0
- package/templates/nuxt/tsconfig.json +15 -0
- package/templates/nuxt/types/env.d.ts +16 -0
- package/templates/react-router/.vscode/settings.json +5 -0
- package/templates/react-router/README.md +79 -0
- package/templates/react-router/_env +1 -0
- package/templates/react-router/_env.example +1 -0
- package/templates/react-router/_gitignore +15 -0
- package/templates/react-router/alchemy.run.ts +17 -0
- package/templates/react-router/app/app.css +15 -0
- package/templates/react-router/app/entry.server.tsx +43 -0
- package/templates/react-router/app/root.tsx +75 -0
- package/templates/react-router/app/routes/home.tsx +17 -0
- package/templates/react-router/app/routes.ts +3 -0
- package/templates/react-router/app/welcome/logo-dark.svg +23 -0
- package/templates/react-router/app/welcome/logo-light.svg +23 -0
- package/templates/react-router/app/welcome/welcome.tsx +90 -0
- package/templates/react-router/package.json +34 -0
- package/templates/react-router/public/favicon.ico +0 -0
- package/templates/react-router/react-router.config.ts +8 -0
- package/templates/react-router/tsconfig.cloudflare.json +27 -0
- package/templates/react-router/tsconfig.json +17 -0
- package/templates/react-router/tsconfig.node.json +20 -0
- package/templates/react-router/types/env.d.ts +16 -0
- package/templates/react-router/vite.config.ts +14 -0
- package/templates/react-router/workers/app.ts +23 -0
- package/templates/react-router/wrangler.jsonc +6 -0
- package/templates/rwsdk/.cursor/rules/rwsdk_rwsdk-interruptors.mdc +247 -0
- package/templates/rwsdk/.cursor/rules/rwsdk_rwsdk-middleware.mdc +75 -0
- package/templates/rwsdk/.cursor/rules/rwsdk_rwsdk-react.mdc +110 -0
- package/templates/rwsdk/.cursor/rules/rwsdk_rwsdk-request-response.mdc +213 -0
- package/templates/rwsdk/.devcontainer/Dockerfile +8 -0
- package/templates/rwsdk/.devcontainer/devcontainer.json +21 -0
- package/templates/rwsdk/README.md +62 -0
- package/templates/rwsdk/_env +5 -0
- package/templates/rwsdk/_env.example +5 -0
- package/templates/rwsdk/_gitignore +71 -0
- package/templates/rwsdk/alchemy.run.ts +29 -0
- package/templates/rwsdk/package.json +61 -0
- package/templates/rwsdk/prisma/schema.prisma +43 -0
- package/templates/rwsdk/src/app/Document.tsx +16 -0
- package/templates/rwsdk/src/app/headers.ts +32 -0
- package/templates/rwsdk/src/app/pages/Home.tsx +13 -0
- package/templates/rwsdk/src/app/pages/user/Login.tsx +79 -0
- package/templates/rwsdk/src/app/pages/user/functions.ts +171 -0
- package/templates/rwsdk/src/app/pages/user/routes.ts +17 -0
- package/templates/rwsdk/src/app/shared/links.ts +3 -0
- package/templates/rwsdk/src/client.tsx +3 -0
- package/templates/rwsdk/src/db.ts +26 -0
- package/templates/rwsdk/src/scripts/seed.ts +21 -0
- package/templates/rwsdk/src/session/durableObject.ts +63 -0
- package/templates/rwsdk/src/session/store.ts +13 -0
- package/templates/rwsdk/src/worker.tsx +63 -0
- package/templates/rwsdk/tsconfig.json +47 -0
- package/templates/rwsdk/types/env.d.ts +16 -0
- package/templates/rwsdk/types/rw.d.ts +5 -0
- package/templates/rwsdk/types/vite.d.ts +4 -0
- package/templates/rwsdk/vite.config.mts +6 -0
- package/templates/rwsdk/wrangler.jsonc +28 -0
- package/templates/sveltekit/README.md +38 -0
- package/templates/sveltekit/_env +1 -0
- package/templates/sveltekit/_env.example +1 -0
- package/templates/sveltekit/_gitignore +26 -0
- package/templates/sveltekit/_npmrc +1 -0
- package/templates/sveltekit/_prettierrc +3 -0
- package/templates/sveltekit/alchemy.run.ts +16 -0
- package/templates/sveltekit/bun.lock +1099 -0
- package/templates/sveltekit/package.json +33 -0
- package/templates/sveltekit/src/app.css +1 -0
- package/templates/sveltekit/src/app.d.ts +13 -0
- package/templates/sveltekit/src/app.html +12 -0
- package/templates/sveltekit/src/routes/+layout.svelte +7 -0
- package/templates/sveltekit/src/routes/+page.svelte +2 -0
- package/templates/sveltekit/static/favicon.png +0 -0
- package/templates/sveltekit/svelte.config.js +12 -0
- package/templates/sveltekit/tsconfig.json +27 -0
- package/templates/sveltekit/types/env.d.ts +16 -0
- package/templates/sveltekit/vite.config.ts +6 -0
- package/templates/sveltekit/wrangler.jsonc +7 -0
- package/templates/tanstack-start/.vscode/settings.json +11 -0
- package/templates/tanstack-start/README.md +72 -0
- package/templates/tanstack-start/_env +1 -0
- package/templates/tanstack-start/_env.example +1 -0
- package/templates/tanstack-start/_gitignore +22 -0
- package/templates/tanstack-start/_prettierignore +4 -0
- package/templates/tanstack-start/alchemy.run.ts +16 -0
- package/templates/tanstack-start/package.json +37 -0
- package/templates/tanstack-start/public/android-chrome-192x192.png +0 -0
- package/templates/tanstack-start/public/android-chrome-512x512.png +0 -0
- package/templates/tanstack-start/public/apple-touch-icon.png +0 -0
- package/templates/tanstack-start/public/favicon-16x16.png +0 -0
- package/templates/tanstack-start/public/favicon-32x32.png +0 -0
- package/templates/tanstack-start/public/favicon.ico +0 -0
- package/templates/tanstack-start/public/favicon.png +0 -0
- package/templates/tanstack-start/public/site.webmanifest +19 -0
- package/templates/tanstack-start/src/components/DefaultCatchBoundary.tsx +53 -0
- package/templates/tanstack-start/src/components/NotFound.tsx +25 -0
- package/templates/tanstack-start/src/components/PostError.tsx +5 -0
- package/templates/tanstack-start/src/components/UserError.tsx +5 -0
- package/templates/tanstack-start/src/router.tsx +22 -0
- package/templates/tanstack-start/src/routes/__root.tsx +146 -0
- package/templates/tanstack-start/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +10 -0
- package/templates/tanstack-start/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +10 -0
- package/templates/tanstack-start/src/routes/_pathlessLayout/_nested-layout.tsx +34 -0
- package/templates/tanstack-start/src/routes/_pathlessLayout.tsx +16 -0
- package/templates/tanstack-start/src/routes/api/users.$userId.ts +28 -0
- package/templates/tanstack-start/src/routes/api/users.ts +59 -0
- package/templates/tanstack-start/src/routes/customScript[.]js.ts +10 -0
- package/templates/tanstack-start/src/routes/deferred.tsx +62 -0
- package/templates/tanstack-start/src/routes/index.tsx +12 -0
- package/templates/tanstack-start/src/routes/posts.$postId.tsx +34 -0
- package/templates/tanstack-start/src/routes/posts.index.tsx +8 -0
- package/templates/tanstack-start/src/routes/posts.tsx +38 -0
- package/templates/tanstack-start/src/routes/posts_.$postId.deep.tsx +29 -0
- package/templates/tanstack-start/src/routes/redirect.tsx +9 -0
- package/templates/tanstack-start/src/routes/users.$userId.tsx +44 -0
- package/templates/tanstack-start/src/routes/users.index.tsx +18 -0
- package/templates/tanstack-start/src/routes/users.tsx +49 -0
- package/templates/tanstack-start/src/styles/app.css +12 -0
- package/templates/tanstack-start/src/utils/loggingMiddleware.tsx +41 -0
- package/templates/tanstack-start/src/utils/posts.tsx +40 -0
- package/templates/tanstack-start/src/utils/seo.ts +33 -0
- package/templates/tanstack-start/src/utils/users.tsx +5 -0
- package/templates/tanstack-start/tsconfig.json +31 -0
- package/templates/tanstack-start/types/env.d.ts +16 -0
- package/templates/tanstack-start/vite.config.ts +33 -0
- package/templates/tanstack-start/wrangler.jsonc +7 -0
- package/templates/typescript/README.md +15 -0
- package/templates/typescript/_gitignore +37 -0
- package/templates/typescript/alchemy.run.ts +15 -0
- package/templates/typescript/index.ts +1 -0
- package/templates/typescript/package.json +18 -0
- package/templates/typescript/src/worker.js +5 -0
- package/templates/typescript/src/worker.ts +7 -0
- package/templates/typescript/tsconfig.json +21 -0
- package/templates/typescript/types/env.d.ts +16 -0
- package/templates/vite/README.md +54 -0
- package/templates/vite/_env.example +1 -0
- package/templates/vite/_gitignore +27 -0
- package/templates/vite/alchemy.run.ts +17 -0
- package/templates/vite/eslint.config.js +28 -0
- package/templates/vite/index.html +13 -0
- package/templates/vite/package.json +35 -0
- package/templates/vite/public/vite.svg +1 -0
- package/templates/vite/src/App.css +42 -0
- package/templates/vite/src/App.tsx +35 -0
- package/templates/vite/src/assets/react.svg +1 -0
- package/templates/vite/src/index.css +68 -0
- package/templates/vite/src/main.tsx +10 -0
- package/templates/vite/src/vite-env.d.ts +1 -0
- package/templates/vite/tsconfig.json +34 -0
- package/templates/vite/types/env.d.ts +16 -0
- package/templates/vite/vite.config.ts +9 -0
- package/templates/vite/worker/index.ts +12 -0
- package/templates/vite/wrangler.jsonc +6 -0
- package/bin/create-alchemy.ts +0 -1220
package/src/scope.ts
CHANGED
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import type { Phase } from "./alchemy.ts";
|
|
3
|
-
import { destroyAll } from "./destroy.ts";
|
|
3
|
+
import { destroy, destroyAll } from "./destroy.ts";
|
|
4
4
|
import { FileSystemStateStore } from "./fs/file-system-state-store.ts";
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
ResourceFQN,
|
|
7
|
+
ResourceID,
|
|
8
|
+
ResourceKind,
|
|
9
|
+
ResourceScope,
|
|
10
|
+
ResourceSeq,
|
|
11
|
+
type PendingResource,
|
|
12
|
+
type Resource,
|
|
13
|
+
type ResourceProps,
|
|
14
|
+
} from "./resource.ts";
|
|
15
|
+
import type { State, StateStore, StateStoreType } from "./state.ts";
|
|
7
16
|
import {
|
|
8
17
|
createDummyLogger,
|
|
9
18
|
createLoggerInstance,
|
|
10
19
|
type LoggerApi,
|
|
11
20
|
} from "./util/cli.ts";
|
|
21
|
+
import { AsyncMutex } from "./util/mutex.ts";
|
|
12
22
|
import type { ITelemetryClient } from "./util/telemetry/client.ts";
|
|
13
23
|
|
|
24
|
+
export class RootScopeStateAttemptError extends Error {
|
|
25
|
+
constructor() {
|
|
26
|
+
super("Root scope cannot contain state");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
14
30
|
export interface ScopeOptions {
|
|
15
31
|
appName?: string;
|
|
16
32
|
stage?: string;
|
|
@@ -24,6 +40,11 @@ export interface ScopeOptions {
|
|
|
24
40
|
logger?: LoggerApi;
|
|
25
41
|
}
|
|
26
42
|
|
|
43
|
+
export type PendingDeletions = Array<{
|
|
44
|
+
resource: Resource<string>;
|
|
45
|
+
oldProps?: ResourceProps;
|
|
46
|
+
}>;
|
|
47
|
+
|
|
27
48
|
// TODO: support browser
|
|
28
49
|
const DEFAULT_STAGE = process.env.ALCHEMY_STAGE ?? process.env.USER ?? "dev";
|
|
29
50
|
|
|
@@ -47,7 +68,7 @@ export class Scope {
|
|
|
47
68
|
new AsyncLocalStorage<Scope>());
|
|
48
69
|
public static globals: Scope[] = (globalThis.__ALCHEMY_GLOBALS__ ??= []);
|
|
49
70
|
|
|
50
|
-
public static
|
|
71
|
+
public static getScope(): Scope | undefined {
|
|
51
72
|
const scope = Scope.storage.getStore();
|
|
52
73
|
if (!scope) {
|
|
53
74
|
if (Scope.globals.length > 0) {
|
|
@@ -63,7 +84,7 @@ export class Scope {
|
|
|
63
84
|
}
|
|
64
85
|
|
|
65
86
|
public static get current(): Scope {
|
|
66
|
-
const scope = Scope.
|
|
87
|
+
const scope = Scope.getScope();
|
|
67
88
|
if (!scope) throw new Error("Not running within an Alchemy Scope");
|
|
68
89
|
return scope;
|
|
69
90
|
}
|
|
@@ -81,6 +102,7 @@ export class Scope {
|
|
|
81
102
|
public readonly phase: Phase;
|
|
82
103
|
public readonly logger: LoggerApi;
|
|
83
104
|
public readonly telemetryClient: ITelemetryClient;
|
|
105
|
+
public readonly dataMutex: AsyncMutex;
|
|
84
106
|
|
|
85
107
|
private isErrored = false;
|
|
86
108
|
private finalized = false;
|
|
@@ -96,7 +118,7 @@ export class Scope {
|
|
|
96
118
|
`Scope name ${this.scopeName} cannot contain double colons`,
|
|
97
119
|
);
|
|
98
120
|
}
|
|
99
|
-
this.parent = options.parent ?? Scope.
|
|
121
|
+
this.parent = options.parent ?? Scope.getScope();
|
|
100
122
|
this.stage = options?.stage ?? this.parent?.stage ?? DEFAULT_STAGE;
|
|
101
123
|
this.parent?.children.set(this.scopeName!, this);
|
|
102
124
|
this.quiet = options.quiet ?? this.parent?.quiet ?? false;
|
|
@@ -131,6 +153,7 @@ export class Scope {
|
|
|
131
153
|
}
|
|
132
154
|
this.telemetryClient =
|
|
133
155
|
options.telemetryClient ?? this.parent?.telemetryClient!;
|
|
156
|
+
this.dataMutex = new AsyncMutex();
|
|
134
157
|
}
|
|
135
158
|
|
|
136
159
|
public get root(): Scope {
|
|
@@ -141,7 +164,7 @@ export class Scope {
|
|
|
141
164
|
return root;
|
|
142
165
|
}
|
|
143
166
|
|
|
144
|
-
public async
|
|
167
|
+
public async deleteResource(resourceID: ResourceID) {
|
|
145
168
|
await this.state.delete(resourceID);
|
|
146
169
|
this.resources.delete(resourceID);
|
|
147
170
|
}
|
|
@@ -158,7 +181,7 @@ export class Scope {
|
|
|
158
181
|
if (this.parent) {
|
|
159
182
|
return [...this.parent.chain, ...thisScope];
|
|
160
183
|
}
|
|
161
|
-
return [...app,
|
|
184
|
+
return [...app, ...thisScope];
|
|
162
185
|
}
|
|
163
186
|
|
|
164
187
|
public fail() {
|
|
@@ -179,6 +202,78 @@ export class Scope {
|
|
|
179
202
|
return [...this.chain, resourceID].join("/");
|
|
180
203
|
}
|
|
181
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Centralizes the "lock → locate the right scope → hand the caller a live
|
|
207
|
+
* ScopeState instance and a persist() helper".
|
|
208
|
+
*
|
|
209
|
+
* @param fn Your operation on the scope state.
|
|
210
|
+
* • `state` is already resolved and, if we're at the root, created.
|
|
211
|
+
* • `persist` will write the (possibly-mutated) state back.
|
|
212
|
+
*/
|
|
213
|
+
private async withScopeState<R>(
|
|
214
|
+
fn: (
|
|
215
|
+
state: State<string, ResourceProps | undefined, Resource<string>>, // current state for this.scopeName
|
|
216
|
+
persist: (
|
|
217
|
+
next: State<string, ResourceProps | undefined, Resource<string>>,
|
|
218
|
+
) => Promise<void>, // helper to save changes
|
|
219
|
+
) => Promise<R>,
|
|
220
|
+
): Promise<R> {
|
|
221
|
+
return this.dataMutex.lock(async () => {
|
|
222
|
+
// 1. We must know where to look.
|
|
223
|
+
if (!this.parent || !this.scopeName) {
|
|
224
|
+
throw new RootScopeStateAttemptError();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 2. Pull (or lazily create) the state bucket we care about.
|
|
228
|
+
const isRoot = this.parent.scopeName === this.root.scopeName;
|
|
229
|
+
const state =
|
|
230
|
+
(await this.parent.state.get(this.scopeName)) ??
|
|
231
|
+
(isRoot
|
|
232
|
+
? {
|
|
233
|
+
//todo(michael): should this have a different type cause its root?
|
|
234
|
+
kind: "alchemy::Scope",
|
|
235
|
+
id: this.scopeName!,
|
|
236
|
+
fqn: this.root.fqn(this.scopeName!),
|
|
237
|
+
seq: this.seq(),
|
|
238
|
+
status: "created",
|
|
239
|
+
data: {},
|
|
240
|
+
output: {
|
|
241
|
+
[ResourceID]: this.scopeName!,
|
|
242
|
+
[ResourceFQN]: this.root.fqn(this.scopeName!),
|
|
243
|
+
[ResourceKind]: "alchemy::Scope",
|
|
244
|
+
[ResourceScope]: this,
|
|
245
|
+
[ResourceSeq]: this.seq(),
|
|
246
|
+
},
|
|
247
|
+
props: {},
|
|
248
|
+
}
|
|
249
|
+
: undefined);
|
|
250
|
+
|
|
251
|
+
if (!state) throw new RootScopeStateAttemptError();
|
|
252
|
+
|
|
253
|
+
return fn(state, (updated) =>
|
|
254
|
+
this.parent!.state.set(this.scopeName!, updated),
|
|
255
|
+
);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
public async set<T>(key: string, value: T): Promise<void> {
|
|
260
|
+
return this.withScopeState<void>(async (state, persist) => {
|
|
261
|
+
state.data[key] = value;
|
|
262
|
+
await persist(state); // only one line to save!
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public async get<T>(key: string): Promise<T> {
|
|
267
|
+
return this.withScopeState<T>(async (state) => state.data[key]);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public async delete(key: string): Promise<void> {
|
|
271
|
+
return this.withScopeState<void>(async (state, persist) => {
|
|
272
|
+
delete state.data[key];
|
|
273
|
+
await persist(state);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
182
277
|
public async run<T>(fn: (scope: Scope) => Promise<T>): Promise<T> {
|
|
183
278
|
return Scope.storage.run(this, () => fn(this));
|
|
184
279
|
}
|
|
@@ -198,7 +293,11 @@ export class Scope {
|
|
|
198
293
|
return null;
|
|
199
294
|
}
|
|
200
295
|
|
|
201
|
-
public async finalize() {
|
|
296
|
+
public async finalize(force?: boolean) {
|
|
297
|
+
const shouldForce =
|
|
298
|
+
force ||
|
|
299
|
+
this.parent === undefined ||
|
|
300
|
+
this?.parent?.scopeName === this.root.scopeName;
|
|
202
301
|
if (this.phase === "read") {
|
|
203
302
|
this.rootTelemetryClient?.record({
|
|
204
303
|
event: "app.success",
|
|
@@ -206,7 +305,7 @@ export class Scope {
|
|
|
206
305
|
});
|
|
207
306
|
return;
|
|
208
307
|
}
|
|
209
|
-
if (this.finalized) {
|
|
308
|
+
if (this.finalized && !shouldForce) {
|
|
210
309
|
return;
|
|
211
310
|
}
|
|
212
311
|
if (this.parent === undefined && Scope.globals.length > 0) {
|
|
@@ -227,12 +326,23 @@ export class Scope {
|
|
|
227
326
|
const orphanIds = Array.from(
|
|
228
327
|
resourceIds.filter((id) => !aliveIds.has(id)),
|
|
229
328
|
);
|
|
329
|
+
|
|
330
|
+
if (shouldForce) {
|
|
331
|
+
await this.destroyPendingDeletions();
|
|
332
|
+
await Promise.all(
|
|
333
|
+
Array.from(this.children.values()).map((child) =>
|
|
334
|
+
child.finalize(shouldForce),
|
|
335
|
+
),
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
230
339
|
const orphans = await Promise.all(
|
|
231
340
|
orphanIds.map(async (id) => (await this.state.get(id))!.output),
|
|
232
341
|
);
|
|
233
342
|
await destroyAll(orphans, {
|
|
234
343
|
quiet: this.quiet,
|
|
235
344
|
strategy: "sequential",
|
|
345
|
+
force: shouldForce,
|
|
236
346
|
});
|
|
237
347
|
this.rootTelemetryClient?.record({
|
|
238
348
|
event: "app.success",
|
|
@@ -250,6 +360,31 @@ export class Scope {
|
|
|
250
360
|
await this.rootTelemetryClient?.finalize();
|
|
251
361
|
}
|
|
252
362
|
|
|
363
|
+
public async destroyPendingDeletions() {
|
|
364
|
+
const pendingDeletions =
|
|
365
|
+
(await this.get<PendingDeletions>("pendingDeletions").catch((e) => {
|
|
366
|
+
if (e instanceof RootScopeStateAttemptError) {
|
|
367
|
+
return [];
|
|
368
|
+
}
|
|
369
|
+
throw e;
|
|
370
|
+
})) ?? [];
|
|
371
|
+
if (pendingDeletions) {
|
|
372
|
+
for (const { resource, oldProps } of pendingDeletions) {
|
|
373
|
+
//todo(michael): ugly hack due to the way scope is serialized
|
|
374
|
+
const realResource = this.resources.get(resource[ResourceID])!;
|
|
375
|
+
resource[ResourceScope] = realResource?.[ResourceScope] ?? this;
|
|
376
|
+
await destroy(resource, {
|
|
377
|
+
quiet: this.quiet,
|
|
378
|
+
strategy: "sequential",
|
|
379
|
+
replace: {
|
|
380
|
+
props: oldProps,
|
|
381
|
+
output: resource,
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
253
388
|
/**
|
|
254
389
|
* Defers execution of a function until the Alchemy application finalizes.
|
|
255
390
|
*/
|
package/src/sentry/project.ts
CHANGED
package/src/util/logger.ts
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple async mutex that ensures only one async operation executes at a time
|
|
3
|
+
*/
|
|
4
|
+
export class AsyncMutex {
|
|
5
|
+
private locked = false;
|
|
6
|
+
private queue: Array<() => void> = [];
|
|
7
|
+
|
|
8
|
+
async lock<T>(operation: () => Promise<T>): Promise<T> {
|
|
9
|
+
return new Promise<T>((resolve, reject) => {
|
|
10
|
+
const execute = async () => {
|
|
11
|
+
this.locked = true;
|
|
12
|
+
try {
|
|
13
|
+
const result = await operation();
|
|
14
|
+
resolve(result);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
reject(error);
|
|
17
|
+
} finally {
|
|
18
|
+
this.locked = false;
|
|
19
|
+
const next = this.queue.shift();
|
|
20
|
+
if (next) {
|
|
21
|
+
next();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (this.locked) {
|
|
27
|
+
this.queue.push(execute);
|
|
28
|
+
} else {
|
|
29
|
+
execute();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Astro Starter Kit: Basics
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
bun create astro@latest -- --template basics
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
|
|
8
|
+
[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
|
|
9
|
+
[](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
|
|
10
|
+
|
|
11
|
+
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
## 🚀 Project Structure
|
|
16
|
+
|
|
17
|
+
Inside of your Astro project, you'll see the following folders and files:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
/
|
|
21
|
+
├── public/
|
|
22
|
+
│ └── favicon.svg
|
|
23
|
+
├── src/
|
|
24
|
+
│ ├── layouts/
|
|
25
|
+
│ │ └── Layout.astro
|
|
26
|
+
│ └── pages/
|
|
27
|
+
│ └── index.astro
|
|
28
|
+
└── package.json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/).
|
|
32
|
+
|
|
33
|
+
## 🧞 Commands
|
|
34
|
+
|
|
35
|
+
All commands are run from the root of the project, from a terminal:
|
|
36
|
+
|
|
37
|
+
| Command | Action |
|
|
38
|
+
| :------------------------ | :----------------------------------------------- |
|
|
39
|
+
| `bun install` | Installs dependencies |
|
|
40
|
+
| `bun dev` | Starts local dev server at `localhost:4321` |
|
|
41
|
+
| `bun build` | Build your production site to `./dist/` |
|
|
42
|
+
| `bun preview` | Preview your build locally, before deploying |
|
|
43
|
+
| `bun astro ...` | Run CLI commands like `astro add`, `astro check` |
|
|
44
|
+
| `bun astro -- --help` | Get help using the Astro CLI |
|
|
45
|
+
|
|
46
|
+
## 👀 Want to learn more?
|
|
47
|
+
|
|
48
|
+
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALCHEMY_PASSWORD=change-me
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# build output
|
|
2
|
+
dist/
|
|
3
|
+
|
|
4
|
+
# generated types
|
|
5
|
+
.astro/
|
|
6
|
+
|
|
7
|
+
# dependencies
|
|
8
|
+
node_modules/
|
|
9
|
+
|
|
10
|
+
# logs
|
|
11
|
+
npm-debug.log*
|
|
12
|
+
yarn-debug.log*
|
|
13
|
+
yarn-error.log*
|
|
14
|
+
pnpm-debug.log*
|
|
15
|
+
|
|
16
|
+
# environment variables
|
|
17
|
+
.env
|
|
18
|
+
.env.production
|
|
19
|
+
|
|
20
|
+
# macOS-specific files
|
|
21
|
+
.DS_Store
|
|
22
|
+
|
|
23
|
+
# jetbrains setting folder
|
|
24
|
+
.idea/
|
|
25
|
+
|
|
26
|
+
.alchemy/
|
|
27
|
+
.env
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="@types/node" />
|
|
2
|
+
|
|
3
|
+
import alchemy from "alchemy";
|
|
4
|
+
import { Astro } from "alchemy/cloudflare";
|
|
5
|
+
|
|
6
|
+
const app = await alchemy("my-alchemy-app");
|
|
7
|
+
|
|
8
|
+
export const worker = await Astro("website", {
|
|
9
|
+
command: "bun run build",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
console.log({
|
|
13
|
+
url: worker.url,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
await app.finalize();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "astro",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"astro": "astro",
|
|
7
|
+
"build": "astro check && astro build",
|
|
8
|
+
"deploy": "bun --env-file=./.env ./alchemy.run.ts",
|
|
9
|
+
"destroy": "bun --env-file=./.env ./alchemy.run.ts --destroy",
|
|
10
|
+
"dev": "astro dev",
|
|
11
|
+
"preview": "astro preview"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"astro": "^5.10.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"alchemy": "workspace:*",
|
|
18
|
+
"@astrojs/cloudflare": "^12.6.0",
|
|
19
|
+
"miniflare": "^4.20250617.3",
|
|
20
|
+
"@cloudflare/workers-types": "^4.20250620.0",
|
|
21
|
+
"typescript": "^5.8.3"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
|
2
|
+
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
|
3
|
+
<style>
|
|
4
|
+
path { fill: #000; }
|
|
5
|
+
@media (prefers-color-scheme: dark) {
|
|
6
|
+
path { fill: #FFF; }
|
|
7
|
+
}
|
|
8
|
+
</style>
|
|
9
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" width="115" height="48"><path fill="#17191E" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="url(#a)" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="#17191E" d="M.02 30.31s4.02-1.95 8.05-1.95l3.04-9.4c.11-.45.44-.76.82-.76.37 0 .7.31.82.76l3.04 9.4c4.77 0 8.05 1.95 8.05 1.95L17 11.71c-.2-.56-.53-.91-.98-.91H7.83c-.44 0-.76.35-.97.9L.02 30.31Zm42.37-5.97c0 1.64-2.05 2.62-4.88 2.62-1.85 0-2.5-.45-2.5-1.41 0-1 .8-1.49 2.65-1.49 1.67 0 3.09.03 4.73.23v.05Zm.03-2.04a21.37 21.37 0 0 0-4.37-.36c-5.32 0-7.82 1.25-7.82 4.18 0 3.04 1.71 4.2 5.68 4.2 3.35 0 5.63-.84 6.46-2.92h.14c-.03.5-.05 1-.05 1.4 0 1.07.18 1.16 1.06 1.16h4.15a16.9 16.9 0 0 1-.36-4c0-1.67.06-2.93.06-4.62 0-3.45-2.07-5.64-8.56-5.64-2.8 0-5.9.48-8.26 1.19.22.93.54 2.83.7 4.06 2.04-.96 4.95-1.37 7.2-1.37 3.11 0 3.97.71 3.97 2.15v.57Zm11.37 3c-.56.07-1.33.07-2.12.07-.83 0-1.6-.03-2.12-.1l-.02.58c0 2.85 1.87 4.52 8.45 4.52 6.2 0 8.2-1.64 8.2-4.55 0-2.74-1.33-4.09-7.2-4.39-4.58-.2-4.99-.7-4.99-1.28 0-.66.59-1 3.65-1 3.18 0 4.03.43 4.03 1.35v.2a46.13 46.13 0 0 1 4.24.03l.02-.55c0-3.36-2.8-4.46-8.2-4.46-6.08 0-8.13 1.49-8.13 4.39 0 2.6 1.64 4.23 7.48 4.48 4.3.14 4.77.62 4.77 1.28 0 .7-.7 1.03-3.71 1.03-3.47 0-4.35-.48-4.35-1.47v-.13Zm19.82-12.05a17.5 17.5 0 0 1-6.24 3.48c.03.84.03 2.4.03 3.24l1.5.02c-.02 1.63-.04 3.6-.04 4.9 0 3.04 1.6 5.32 6.58 5.32 2.1 0 3.5-.23 5.23-.6a43.77 43.77 0 0 1-.46-4.13c-1.03.34-2.34.53-3.78.53-2 0-2.82-.55-2.82-2.13 0-1.37 0-2.65.03-3.84 2.57.02 5.13.07 6.64.11-.02-1.18.03-2.9.1-4.04-2.2.04-4.65.07-6.68.07l.07-2.93h-.16Zm13.46 6.04a767.33 767.33 0 0 1 .07-3.18H82.6c.07 1.96.07 3.98.07 6.92 0 2.95-.03 4.99-.07 6.93h5.18c-.09-1.37-.11-3.68-.11-5.65 0-3.1 1.26-4 4.12-4 1.33 0 2.28.16 3.1.46.03-1.16.26-3.43.4-4.43-.86-.25-1.81-.41-2.96-.41-2.46-.03-4.26.98-5.1 3.38l-.17-.02Zm22.55 3.65c0 2.5-1.8 3.66-4.64 3.66-2.81 0-4.61-1.1-4.61-3.66s1.82-3.52 4.61-3.52c2.82 0 4.64 1.03 4.64 3.52Zm4.71-.11c0-4.96-3.87-7.18-9.35-7.18-5.5 0-9.23 2.22-9.23 7.18 0 4.94 3.49 7.59 9.21 7.59 5.77 0 9.37-2.65 9.37-7.6Z"/><defs><linearGradient id="a" x1="6.33" x2="19.43" y1="40.8" y2="34.6" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient></defs></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="1024" fill="none"><path fill="url(#a)" fill-rule="evenodd" d="M-217.58 475.75c91.82-72.02 225.52-29.38 341.2-44.74C240 415.56 372.33 315.14 466.77 384.9c102.9 76.02 44.74 246.76 90.31 366.31 29.83 78.24 90.48 136.14 129.48 210.23 57.92 109.99 169.67 208.23 155.9 331.77-13.52 121.26-103.42 264.33-224.23 281.37-141.96 20.03-232.72-220.96-374.06-196.99-151.7 25.73-172.68 330.24-325.85 315.72-128.6-12.2-110.9-230.73-128.15-358.76-12.16-90.14 65.87-176.25 44.1-264.57-26.42-107.2-167.12-163.46-176.72-273.45-10.15-116.29 33.01-248.75 124.87-320.79Z" clip-rule="evenodd" style="opacity:.154"/><path fill="url(#b)" fill-rule="evenodd" d="M1103.43 115.43c146.42-19.45 275.33-155.84 413.5-103.59 188.09 71.13 409 212.64 407.06 413.88-1.94 201.25-259.28 278.6-414.96 405.96-130 106.35-240.24 294.39-405.6 265.3-163.7-28.8-161.93-274.12-284.34-386.66-134.95-124.06-436-101.46-445.82-284.6-9.68-180.38 247.41-246.3 413.54-316.9 101.01-42.93 207.83 21.06 316.62 6.61Z" clip-rule="evenodd" style="opacity:.154"/><defs><linearGradient id="b" x1="373" x2="1995.44" y1="1100" y2="118.03" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient><linearGradient id="a" x1="107.37" x2="1130.66" y1="1993.35" y2="1026.31" gradientUnits="userSpaceOnUse"><stop stop-color="#3245FF"/><stop offset="1" stop-color="#BC52EE"/></linearGradient></defs></svg>
|