alchemy 0.1.18 → 0.2.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/README.md +506 -0
- package/lib/alchemy.d.ts +67 -0
- package/lib/alchemy.js +48 -0
- package/lib/apply.d.ts +3 -20
- package/lib/apply.js +95 -82
- package/lib/aws/account-id.d.ts +0 -1
- package/lib/aws/account-id.js +0 -1
- package/lib/aws/bucket.d.ts +4 -7
- package/lib/aws/bucket.js +8 -12
- package/lib/aws/function.d.ts +4 -7
- package/lib/aws/function.js +9 -30
- package/lib/aws/index.d.ts +1 -1
- package/lib/aws/index.js +1 -1
- package/lib/aws/oidc/github-oidc-provider.d.ts +2 -6
- package/lib/aws/oidc/github-oidc-provider.js +10 -15
- package/lib/aws/oidc/index.d.ts +0 -1
- package/lib/aws/oidc/index.js +0 -1
- package/lib/aws/oidc/oidc-provider.d.ts +4 -6
- package/lib/aws/oidc/oidc-provider.js +9 -11
- package/lib/aws/policy-attachment.d.ts +9 -0
- package/lib/aws/policy-attachment.js +20 -0
- package/lib/aws/policy.d.ts +4 -16
- package/lib/aws/policy.js +9 -40
- package/lib/aws/queue.d.ts +4 -34
- package/lib/aws/queue.js +10 -20
- package/lib/aws/role.d.ts +4 -7
- package/lib/aws/role.js +17 -26
- package/lib/aws/ses.d.ts +4 -10
- package/lib/aws/ses.js +118 -131
- package/lib/aws/table.d.ts +4 -7
- package/lib/aws/table.js +8 -11
- package/lib/cloudflare/api.d.ts +0 -1
- package/lib/cloudflare/api.js +0 -1
- package/lib/cloudflare/asset-manifest.d.ts +0 -1
- package/lib/cloudflare/asset-manifest.js +0 -1
- package/lib/cloudflare/auth.d.ts +0 -1
- package/lib/cloudflare/auth.js +0 -1
- package/lib/cloudflare/bindings.d.ts +1 -1
- package/lib/cloudflare/bindings.js +3 -2
- package/lib/cloudflare/bound.d.ts +0 -1
- package/lib/cloudflare/bound.js +0 -1
- package/lib/cloudflare/bucket.d.ts +7 -15
- package/lib/cloudflare/bucket.js +12 -19
- package/lib/cloudflare/durable-object-namespace.d.ts +0 -3
- package/lib/cloudflare/durable-object-namespace.js +0 -4
- package/lib/cloudflare/generate-asset-manifest.d.ts +0 -1
- package/lib/cloudflare/generate-asset-manifest.js +1 -2
- package/lib/cloudflare/index.d.ts +2 -1
- package/lib/cloudflare/index.js +2 -1
- package/lib/cloudflare/kv-namespace.d.ts +6 -9
- package/lib/cloudflare/kv-namespace.js +16 -20
- package/lib/cloudflare/state.d.ts +0 -1
- package/lib/cloudflare/state.js +0 -1
- package/lib/cloudflare/static-site-router.d.ts +0 -1
- package/lib/cloudflare/static-site-router.js +0 -4
- package/lib/cloudflare/static-site.d.ts +5 -11
- package/lib/cloudflare/static-site.js +25 -37
- package/lib/cloudflare/types.d.ts +0 -1
- package/lib/cloudflare/types.js +0 -1
- package/lib/cloudflare/upload-asset-manifest.d.ts +0 -1
- package/lib/cloudflare/upload-asset-manifest.js +0 -1
- package/lib/cloudflare/worker-metadata.d.ts +0 -1
- package/lib/cloudflare/worker-metadata.js +0 -1
- package/lib/cloudflare/worker-migration.d.ts +0 -1
- package/lib/cloudflare/worker-migration.js +0 -1
- package/lib/cloudflare/worker.d.ts +8 -14
- package/lib/cloudflare/worker.js +38 -50
- package/lib/cloudflare/wrangler.json.d.ts +243 -0
- package/lib/cloudflare/wrangler.json.js +35 -0
- package/lib/cloudflare/zone-settings.d.ts +301 -0
- package/lib/cloudflare/zone-settings.js +1 -0
- package/lib/cloudflare/zone.d.ts +196 -0
- package/lib/cloudflare/zone.js +175 -0
- package/lib/context.d.ts +58 -0
- package/lib/context.js +36 -0
- package/lib/destroy.d.ts +10 -13
- package/lib/destroy.js +104 -43
- package/lib/{esbuild.d.ts → esbuild/bundle.d.ts} +4 -18
- package/lib/{esbuild.js → esbuild/bundle.js} +10 -24
- package/lib/esbuild/index.d.ts +1 -0
- package/lib/esbuild/index.js +1 -0
- package/lib/fs/file.d.ts +13 -0
- package/lib/fs/file.js +20 -0
- package/lib/fs/folder.d.ts +10 -0
- package/lib/fs/folder.js +16 -0
- package/lib/fs/index.d.ts +2 -0
- package/lib/fs/index.js +2 -0
- package/lib/github/client.d.ts +0 -1
- package/lib/github/client.js +0 -1
- package/lib/github/index.d.ts +0 -1
- package/lib/github/index.js +0 -1
- package/lib/github/secret.d.ts +4 -6
- package/lib/github/secret.js +10 -12
- package/lib/index.d.ts +6 -10
- package/lib/index.js +5 -9
- package/lib/project/index.d.ts +1 -0
- package/lib/project/index.js +1 -0
- package/lib/project/vite.d.ts +39 -0
- package/lib/project/vite.js +68 -0
- package/lib/resource.d.ts +34 -62
- package/lib/resource.js +29 -270
- package/lib/scope.d.ts +37 -14
- package/lib/scope.js +97 -23
- package/lib/secret.d.ts +2 -7
- package/lib/secret.js +7 -20
- package/lib/state.d.ts +14 -10
- package/lib/state.js +20 -14
- package/lib/stripe/index.d.ts +0 -1
- package/lib/stripe/index.js +0 -1
- package/lib/stripe/price.d.ts +4 -5
- package/lib/stripe/price.js +10 -20
- package/lib/stripe/product.d.ts +4 -5
- package/lib/stripe/product.js +10 -20
- package/lib/stripe/webhook.d.ts +4 -6
- package/lib/stripe/webhook.js +12 -25
- package/lib/test/bun.d.ts +19 -0
- package/lib/test/bun.js +55 -0
- package/lib/{utils → util}/content-type.d.ts +0 -1
- package/lib/{utils → util}/content-type.js +0 -1
- package/lib/{encrypt.d.ts → util/encrypt.d.ts} +0 -1
- package/lib/{encrypt.js → util/encrypt.js} +0 -1
- package/lib/{error.d.ts → util/ignore.d.ts} +0 -1
- package/lib/{error.js → util/ignore.js} +0 -1
- package/lib/{utils → util}/retry.d.ts +0 -1
- package/lib/{utils → util}/retry.js +0 -1
- package/lib/util/rm.d.ts +1 -0
- package/lib/util/rm.js +11 -0
- package/lib/util/serde.d.ts +3 -0
- package/lib/{serde.js → util/serde.js} +19 -10
- package/lib/util/slugify.d.ts +1 -0
- package/lib/util/slugify.js +3 -0
- package/package.json +7 -5
- package/src/alchemy.ts +127 -0
- package/src/apply.ts +116 -115
- package/src/aws/bucket.ts +11 -14
- package/src/aws/function.ts +13 -33
- package/src/aws/index.ts +1 -0
- package/src/aws/oidc/github-oidc-provider.ts +14 -19
- package/src/aws/oidc/oidc-provider.ts +19 -12
- package/src/aws/policy-attachment.ts +51 -0
- package/src/aws/policy.ts +15 -60
- package/src/aws/queue.ts +17 -21
- package/src/aws/role.ts +25 -28
- package/src/aws/ses.ts +150 -164
- package/src/aws/table.ts +15 -15
- package/src/cloudflare/bindings.ts +8 -0
- package/src/cloudflare/bucket.ts +39 -47
- package/src/cloudflare/durable-object-namespace.ts +0 -10
- package/src/cloudflare/generate-asset-manifest.ts +1 -1
- package/src/cloudflare/index.ts +2 -0
- package/src/cloudflare/kv-namespace.ts +35 -33
- package/src/cloudflare/static-site-router.ts +0 -3
- package/src/cloudflare/static-site.ts +55 -71
- package/src/cloudflare/worker.ts +106 -112
- package/src/cloudflare/wrangler.json.ts +309 -0
- package/src/cloudflare/zone-settings.ts +368 -0
- package/src/cloudflare/zone.ts +491 -0
- package/src/context.ts +122 -0
- package/src/destroy.ts +124 -73
- package/src/{esbuild.ts → esbuild/bundle.ts} +16 -28
- package/src/esbuild/index.ts +1 -0
- package/src/fs/file.ts +39 -0
- package/src/fs/folder.ts +32 -0
- package/src/fs/index.ts +2 -0
- package/src/github/secret.ts +19 -16
- package/src/index.ts +7 -15
- package/src/project/index.ts +1 -0
- package/src/project/vite.ts +152 -0
- package/src/resource.ts +101 -462
- package/src/scope.ts +125 -36
- package/src/secret.ts +9 -32
- package/src/state.ts +38 -21
- package/src/stripe/price.ts +17 -22
- package/src/stripe/product.ts +17 -22
- package/src/stripe/webhook.ts +21 -27
- package/src/test/bun.ts +105 -0
- package/src/util/rm.ts +11 -0
- package/src/util/serde.ts +53 -0
- package/src/util/slugify.ts +3 -0
- package/lib/$.d.ts +0 -12
- package/lib/$.d.ts.map +0 -1
- package/lib/$.js +0 -42
- package/lib/$.js.map +0 -1
- package/lib/alchemize.d.ts +0 -47
- package/lib/alchemize.d.ts.map +0 -1
- package/lib/alchemize.js +0 -116
- package/lib/alchemize.js.map +0 -1
- package/lib/apply.d.ts.map +0 -1
- package/lib/apply.js.map +0 -1
- package/lib/aws/account-id.d.ts.map +0 -1
- package/lib/aws/account-id.js.map +0 -1
- package/lib/aws/bucket.d.ts.map +0 -1
- package/lib/aws/bucket.js.map +0 -1
- package/lib/aws/function.d.ts.map +0 -1
- package/lib/aws/function.js.map +0 -1
- package/lib/aws/index.d.ts.map +0 -1
- package/lib/aws/index.js.map +0 -1
- package/lib/aws/oidc/github-oidc-provider.d.ts.map +0 -1
- package/lib/aws/oidc/github-oidc-provider.js.map +0 -1
- package/lib/aws/oidc/index.d.ts.map +0 -1
- package/lib/aws/oidc/index.js.map +0 -1
- package/lib/aws/oidc/oidc-provider.d.ts.map +0 -1
- package/lib/aws/oidc/oidc-provider.js.map +0 -1
- package/lib/aws/policy.d.ts.map +0 -1
- package/lib/aws/policy.js.map +0 -1
- package/lib/aws/queue.d.ts.map +0 -1
- package/lib/aws/queue.js.map +0 -1
- package/lib/aws/role.d.ts.map +0 -1
- package/lib/aws/role.js.map +0 -1
- package/lib/aws/ses.d.ts.map +0 -1
- package/lib/aws/ses.js.map +0 -1
- package/lib/aws/table.d.ts.map +0 -1
- package/lib/aws/table.js.map +0 -1
- package/lib/cloudflare/api.d.ts.map +0 -1
- package/lib/cloudflare/api.js.map +0 -1
- package/lib/cloudflare/asset-manifest.d.ts.map +0 -1
- package/lib/cloudflare/asset-manifest.js.map +0 -1
- package/lib/cloudflare/auth.d.ts.map +0 -1
- package/lib/cloudflare/auth.js.map +0 -1
- package/lib/cloudflare/bindings.d.ts.map +0 -1
- package/lib/cloudflare/bindings.js.map +0 -1
- package/lib/cloudflare/bound.d.ts.map +0 -1
- package/lib/cloudflare/bound.js.map +0 -1
- package/lib/cloudflare/bucket.d.ts.map +0 -1
- package/lib/cloudflare/bucket.js.map +0 -1
- package/lib/cloudflare/durable-object-namespace.d.ts.map +0 -1
- package/lib/cloudflare/durable-object-namespace.js.map +0 -1
- package/lib/cloudflare/generate-asset-manifest.d.ts.map +0 -1
- package/lib/cloudflare/generate-asset-manifest.js.map +0 -1
- package/lib/cloudflare/index.d.ts.map +0 -1
- package/lib/cloudflare/index.js.map +0 -1
- package/lib/cloudflare/kv-namespace.d.ts.map +0 -1
- package/lib/cloudflare/kv-namespace.js.map +0 -1
- package/lib/cloudflare/state.d.ts.map +0 -1
- package/lib/cloudflare/state.js.map +0 -1
- package/lib/cloudflare/static-site-router.d.ts.map +0 -1
- package/lib/cloudflare/static-site-router.js.map +0 -1
- package/lib/cloudflare/static-site.d.ts.map +0 -1
- package/lib/cloudflare/static-site.js.map +0 -1
- package/lib/cloudflare/types.d.ts.map +0 -1
- package/lib/cloudflare/types.js.map +0 -1
- package/lib/cloudflare/upload-asset-manifest.d.ts.map +0 -1
- package/lib/cloudflare/upload-asset-manifest.js.map +0 -1
- package/lib/cloudflare/worker-metadata.d.ts.map +0 -1
- package/lib/cloudflare/worker-metadata.js.map +0 -1
- package/lib/cloudflare/worker-migration.d.ts.map +0 -1
- package/lib/cloudflare/worker-migration.js.map +0 -1
- package/lib/cloudflare/worker.d.ts.map +0 -1
- package/lib/cloudflare/worker.js.map +0 -1
- package/lib/destroy.d.ts.map +0 -1
- package/lib/destroy.js.map +0 -1
- package/lib/encrypt.d.ts.map +0 -1
- package/lib/encrypt.js.map +0 -1
- package/lib/error.d.ts.map +0 -1
- package/lib/error.js.map +0 -1
- package/lib/esbuild.d.ts.map +0 -1
- package/lib/esbuild.js.map +0 -1
- package/lib/fs.d.ts +0 -12
- package/lib/fs.d.ts.map +0 -1
- package/lib/fs.js +0 -41
- package/lib/fs.js.map +0 -1
- package/lib/github/client.d.ts.map +0 -1
- package/lib/github/client.js.map +0 -1
- package/lib/github/index.d.ts.map +0 -1
- package/lib/github/index.js.map +0 -1
- package/lib/github/secret.d.ts.map +0 -1
- package/lib/github/secret.js.map +0 -1
- package/lib/global.d.ts +0 -16
- package/lib/global.d.ts.map +0 -1
- package/lib/global.js +0 -42
- package/lib/global.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/input.d.ts +0 -7
- package/lib/input.d.ts.map +0 -1
- package/lib/input.js +0 -2
- package/lib/input.js.map +0 -1
- package/lib/main.d.ts +0 -3
- package/lib/main.d.ts.map +0 -1
- package/lib/main.js +0 -32
- package/lib/main.js.map +0 -1
- package/lib/output.d.ts +0 -25
- package/lib/output.d.ts.map +0 -1
- package/lib/output.js +0 -23
- package/lib/output.js.map +0 -1
- package/lib/print.d.ts +0 -7
- package/lib/print.d.ts.map +0 -1
- package/lib/print.js +0 -10
- package/lib/print.js.map +0 -1
- package/lib/resource.d.ts.map +0 -1
- package/lib/resource.js.map +0 -1
- package/lib/scope.d.ts.map +0 -1
- package/lib/scope.js.map +0 -1
- package/lib/secret.d.ts.map +0 -1
- package/lib/secret.js.map +0 -1
- package/lib/serde.d.ts +0 -3
- package/lib/serde.d.ts.map +0 -1
- package/lib/serde.js.map +0 -1
- package/lib/slug.d.ts +0 -2
- package/lib/slug.d.ts.map +0 -1
- package/lib/slug.js +0 -4
- package/lib/slug.js.map +0 -1
- package/lib/state.d.ts.map +0 -1
- package/lib/state.js.map +0 -1
- package/lib/stripe/index.d.ts.map +0 -1
- package/lib/stripe/index.js.map +0 -1
- package/lib/stripe/price.d.ts.map +0 -1
- package/lib/stripe/price.js.map +0 -1
- package/lib/stripe/product.d.ts.map +0 -1
- package/lib/stripe/product.js.map +0 -1
- package/lib/stripe/webhook.d.ts.map +0 -1
- package/lib/stripe/webhook.js.map +0 -1
- package/lib/utils/content-type.d.ts.map +0 -1
- package/lib/utils/content-type.js.map +0 -1
- package/lib/utils/retry.d.ts.map +0 -1
- package/lib/utils/retry.js.map +0 -1
- package/src/$.ts +0 -69
- package/src/alchemize.ts +0 -195
- package/src/fs.ts +0 -47
- package/src/global.ts +0 -63
- package/src/input.ts +0 -19
- package/src/main.ts +0 -34
- package/src/output.ts +0 -75
- package/src/print.ts +0 -18
- package/src/serde.ts +0 -46
- package/src/slug.ts +0 -3
- /package/src/{utils → util}/content-type.ts +0 -0
- /package/src/{encrypt.ts → util/encrypt.ts} +0 -0
- /package/src/{error.ts → util/ignore.ts} +0 -0
- /package/src/{utils → util}/retry.ts +0 -0
package/src/destroy.ts
CHANGED
|
@@ -1,92 +1,143 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { alchemy } from "./alchemy";
|
|
2
|
+
import { context } from "./context";
|
|
3
|
+
import { PROVIDERS, type Provider, type Resource } from "./resource";
|
|
4
|
+
import { Scope } from "./scope";
|
|
5
|
+
|
|
6
|
+
export class DestroyedSignal extends Error {}
|
|
6
7
|
|
|
7
8
|
export interface DestroyOptions {
|
|
8
|
-
stage?: string;
|
|
9
|
-
stateStore?: StateStore;
|
|
10
|
-
scope?: Scope;
|
|
11
9
|
quiet?: boolean;
|
|
10
|
+
strategy?: "sequential" | "parallel";
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export async function destroy<T>(
|
|
18
|
-
output: Output<T>,
|
|
19
|
-
options?: DestroyOptions,
|
|
20
|
-
): Promise<void>;
|
|
13
|
+
function isScopeArgs(a: any): a is [scope: Scope, options?: DestroyOptions] {
|
|
14
|
+
return a[0] instanceof Scope;
|
|
15
|
+
}
|
|
21
16
|
|
|
22
17
|
/**
|
|
23
|
-
*
|
|
18
|
+
* Prune all resources from an Output and "down", i.e. that branches from it.
|
|
24
19
|
*/
|
|
25
|
-
export async function destroy<
|
|
26
|
-
stage: string,
|
|
27
|
-
scope: Scope,
|
|
28
|
-
resourceID: ResourceID,
|
|
29
|
-
resourceState: State,
|
|
30
|
-
resourceProvider: Provider,
|
|
31
|
-
stateStore: StateStore,
|
|
32
|
-
options: DestroyOptions,
|
|
33
|
-
): Promise<void>;
|
|
34
|
-
|
|
35
|
-
export async function destroy<T>(
|
|
20
|
+
export async function destroy<Type extends string>(
|
|
36
21
|
...args:
|
|
37
|
-
| [
|
|
38
|
-
| [
|
|
22
|
+
| [scope: Scope, options?: DestroyOptions]
|
|
23
|
+
| [resource: Resource<Type> | undefined | null, options?: DestroyOptions]
|
|
39
24
|
): Promise<void> {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
} else {
|
|
73
|
-
console.log(args[0]);
|
|
74
|
-
throw new Error("Not implemented: must handle destroy a Output chain");
|
|
25
|
+
if (isScopeArgs(args)) {
|
|
26
|
+
const [scope, options] = args;
|
|
27
|
+
const strategy = options?.strategy ?? "sequential";
|
|
28
|
+
// destroy all active resources
|
|
29
|
+
await destroy.all(Array.from(scope.resources.values()), {
|
|
30
|
+
strategy,
|
|
31
|
+
});
|
|
32
|
+
// then detect orphans and destroy them
|
|
33
|
+
const orphans = await scope.state.all();
|
|
34
|
+
await destroy.all(
|
|
35
|
+
Object.values(orphans).map((orphan) => ({
|
|
36
|
+
...orphan.output,
|
|
37
|
+
Scope: scope,
|
|
38
|
+
})),
|
|
39
|
+
options,
|
|
40
|
+
);
|
|
41
|
+
// finally, destroy the scope container
|
|
42
|
+
await scope.deinit();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const [instance, options] = args;
|
|
47
|
+
|
|
48
|
+
if (!instance) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const Provider: Provider<Type> | undefined = PROVIDERS.get(instance.Kind);
|
|
53
|
+
if (!Provider) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Cannot destroy resource type ${instance.Kind} - no provider found. You may need to import the provider in your alchemy.config.ts.`,
|
|
56
|
+
);
|
|
75
57
|
}
|
|
58
|
+
|
|
59
|
+
const scope = instance.Scope;
|
|
60
|
+
if (!scope) {
|
|
61
|
+
console.warn(`Resource "${instance.FQN}" has no scope`);
|
|
62
|
+
}
|
|
63
|
+
const quiet = options?.quiet ?? scope.quiet;
|
|
64
|
+
|
|
76
65
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
66
|
+
if (!quiet) {
|
|
67
|
+
console.log(`Delete: "${instance.FQN}"`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const state = (await scope.state.get(instance.ID))!;
|
|
71
|
+
|
|
72
|
+
if (state === undefined) {
|
|
73
|
+
console.warn(`Resource "${instance.FQN}" not found`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const ctx = context({
|
|
79
78
|
scope,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
phase: "delete",
|
|
80
|
+
kind: instance.Kind,
|
|
81
|
+
id: instance.ID,
|
|
82
|
+
fqn: instance.FQN,
|
|
83
|
+
seq: instance.Seq,
|
|
84
|
+
state,
|
|
85
|
+
replace: () => {
|
|
86
|
+
throw new Error("Cannot replace a resource that is being deleted");
|
|
85
87
|
},
|
|
86
|
-
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
let nestedScope: Scope | undefined;
|
|
91
|
+
try {
|
|
92
|
+
// BUG: this does not restore persisted scope
|
|
93
|
+
await alchemy.run(instance.ID, async (scope) => {
|
|
94
|
+
nestedScope = scope;
|
|
95
|
+
return await Provider.handler.bind(ctx)(instance.ID, state.props);
|
|
96
|
+
});
|
|
97
|
+
} catch (err) {
|
|
98
|
+
if (err instanceof DestroyedSignal) {
|
|
99
|
+
// TODO: should we fail if the DestroyedSignal is not thrown?
|
|
100
|
+
} else {
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (nestedScope) {
|
|
106
|
+
await destroy(nestedScope, options);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
await scope.delete(instance.ID);
|
|
110
|
+
|
|
111
|
+
if (!quiet) {
|
|
112
|
+
console.log(`Deleted: "${instance.FQN}"`);
|
|
113
|
+
}
|
|
87
114
|
} catch (error) {
|
|
88
115
|
console.error(error);
|
|
89
116
|
throw error;
|
|
90
117
|
}
|
|
91
|
-
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export namespace destroy {
|
|
121
|
+
export async function all(resources: Resource[], options?: DestroyOptions) {
|
|
122
|
+
if (options?.strategy !== "parallel") {
|
|
123
|
+
const sorted = resources.sort((a, b) => b.Seq - a.Seq);
|
|
124
|
+
for (const resource of sorted) {
|
|
125
|
+
await destroy(resource);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
await Promise.all(
|
|
129
|
+
resources.map((resource) => destroy(resource, options)),
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function sequentially(
|
|
135
|
+
...resources: (Resource<string> | undefined | null)[]
|
|
136
|
+
) {
|
|
137
|
+
for (const resource of resources) {
|
|
138
|
+
if (resource) {
|
|
139
|
+
await destroy(resource);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
92
143
|
}
|
|
@@ -2,8 +2,8 @@ import * as esbuild from "esbuild";
|
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import type { Context } from "../context";
|
|
6
|
+
import { Resource } from "../resource";
|
|
7
7
|
export interface BundleProps {
|
|
8
8
|
/**
|
|
9
9
|
* Entry point for the bundle
|
|
@@ -47,7 +47,7 @@ export interface BundleProps {
|
|
|
47
47
|
options?: Partial<esbuild.BuildOptions>;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export interface
|
|
50
|
+
export interface Bundle extends Resource<"esbuild::Bundle"> {
|
|
51
51
|
/**
|
|
52
52
|
* Path to the bundled file
|
|
53
53
|
*/
|
|
@@ -58,23 +58,27 @@ export interface BundleOutput {
|
|
|
58
58
|
hash: string;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export
|
|
61
|
+
export const Bundle = Resource(
|
|
62
62
|
"esbuild::Bundle",
|
|
63
63
|
{
|
|
64
64
|
alwaysUpdate: true,
|
|
65
65
|
},
|
|
66
|
-
async (
|
|
66
|
+
async function (
|
|
67
|
+
this: Context<Bundle>,
|
|
68
|
+
id: string,
|
|
69
|
+
props: BundleProps,
|
|
70
|
+
): Promise<Bundle> {
|
|
67
71
|
// Determine output path
|
|
68
72
|
const outputPath = getOutputPath(props);
|
|
69
73
|
|
|
70
74
|
// Ensure output directory exists
|
|
71
75
|
await fs.promises.mkdir(path.dirname(outputPath), { recursive: true });
|
|
72
76
|
|
|
73
|
-
if (
|
|
77
|
+
if (this.phase === "delete") {
|
|
74
78
|
await fs.promises.unlink(outputPath).catch(() => {});
|
|
75
79
|
// Also clean up sourcemap if it exists
|
|
76
80
|
await fs.promises.unlink(outputPath + ".map").catch(() => {});
|
|
77
|
-
return
|
|
81
|
+
return this.destroy();
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
const result = await bundle(props);
|
|
@@ -83,32 +87,16 @@ export class Bundle extends Resource(
|
|
|
83
87
|
const hash = crypto.createHash("sha256").update(contents).digest("hex");
|
|
84
88
|
|
|
85
89
|
// Store metadata in context
|
|
86
|
-
await
|
|
87
|
-
await
|
|
90
|
+
await this.set("metafile", result.metafile);
|
|
91
|
+
await this.set("hash", hash);
|
|
88
92
|
|
|
89
93
|
// Return output info
|
|
90
|
-
return {
|
|
94
|
+
return this({
|
|
91
95
|
path: outputPath,
|
|
92
96
|
hash,
|
|
93
|
-
};
|
|
97
|
+
});
|
|
94
98
|
},
|
|
95
|
-
)
|
|
96
|
-
/**
|
|
97
|
-
* Get the metafile from the last build
|
|
98
|
-
*/
|
|
99
|
-
public async getMetafile(ctx: {
|
|
100
|
-
get<T>(key: string): Promise<T | undefined>;
|
|
101
|
-
}) {
|
|
102
|
-
return ctx.get<esbuild.Metafile>("metafile");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Get the hash from the last build
|
|
107
|
-
*/
|
|
108
|
-
public async getHash(ctx: { get<T>(key: string): Promise<T | undefined> }) {
|
|
109
|
-
return ctx.get<string>("hash");
|
|
110
|
-
}
|
|
111
|
-
}
|
|
99
|
+
);
|
|
112
100
|
|
|
113
101
|
export async function bundle(props: BundleProps) {
|
|
114
102
|
const outputPath = getOutputPath(props);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./bundle";
|
package/src/fs/file.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import type { Context } from "../context";
|
|
4
|
+
import { Resource } from "../resource";
|
|
5
|
+
import { ignore } from "../util/ignore";
|
|
6
|
+
|
|
7
|
+
export interface File extends Resource<"fs::File"> {
|
|
8
|
+
path: string;
|
|
9
|
+
content: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const File = Resource(
|
|
13
|
+
"fs::File",
|
|
14
|
+
async function (
|
|
15
|
+
this: Context<File>,
|
|
16
|
+
id: string,
|
|
17
|
+
{
|
|
18
|
+
path: filePath,
|
|
19
|
+
content,
|
|
20
|
+
}: {
|
|
21
|
+
path: string;
|
|
22
|
+
content: string;
|
|
23
|
+
},
|
|
24
|
+
): Promise<File> {
|
|
25
|
+
if (this.phase === "delete") {
|
|
26
|
+
await ignore("ENOENT", async () => fs.promises.unlink(filePath));
|
|
27
|
+
return this.destroy();
|
|
28
|
+
} else {
|
|
29
|
+
await fs.promises.mkdir(path.dirname(filePath), {
|
|
30
|
+
recursive: true,
|
|
31
|
+
});
|
|
32
|
+
await fs.promises.writeFile(filePath, content);
|
|
33
|
+
}
|
|
34
|
+
return this({
|
|
35
|
+
path: filePath,
|
|
36
|
+
content,
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
);
|
package/src/fs/folder.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import type { Context } from "../context";
|
|
3
|
+
import { Resource } from "../resource";
|
|
4
|
+
import { ignore } from "../util/ignore";
|
|
5
|
+
|
|
6
|
+
export interface Folder extends Resource<"fs::Folder"> {
|
|
7
|
+
path: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Folder = Resource(
|
|
11
|
+
"fs::Folder",
|
|
12
|
+
async function (
|
|
13
|
+
this: Context<Folder>,
|
|
14
|
+
id: string,
|
|
15
|
+
{ path: dirPath }: { path: string },
|
|
16
|
+
): Promise<Folder> {
|
|
17
|
+
if (this.phase === "delete") {
|
|
18
|
+
// we just do a best effort attempt
|
|
19
|
+
await ignore(["ENOENT", "ENOTEMPTY"], async () =>
|
|
20
|
+
fs.promises.rmdir(dirPath),
|
|
21
|
+
);
|
|
22
|
+
return this.destroy();
|
|
23
|
+
} else {
|
|
24
|
+
await ignore("EEXIST", async () =>
|
|
25
|
+
fs.promises.mkdir(dirPath, { recursive: true }),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return this({
|
|
29
|
+
path: dirPath,
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
);
|
package/src/fs/index.ts
ADDED
package/src/github/secret.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import sodium from "libsodium-wrappers";
|
|
2
|
-
import {
|
|
2
|
+
import type { Context } from "../context";
|
|
3
|
+
import { Resource } from "../resource";
|
|
3
4
|
import type { Secret } from "../secret";
|
|
4
5
|
import { createGitHubClient, verifyGitHubAuth } from "./client";
|
|
5
6
|
/**
|
|
@@ -35,7 +36,9 @@ export interface GitHubSecretProps {
|
|
|
35
36
|
/**
|
|
36
37
|
* Output returned after Secret creation/update
|
|
37
38
|
*/
|
|
38
|
-
export interface GitHubSecretOutput
|
|
39
|
+
export interface GitHubSecretOutput
|
|
40
|
+
extends Resource<"github::Secret">,
|
|
41
|
+
Omit<GitHubSecretProps, "value"> {
|
|
39
42
|
/**
|
|
40
43
|
* The ID of the resource
|
|
41
44
|
*/
|
|
@@ -50,22 +53,24 @@ export interface GitHubSecretOutput extends Omit<GitHubSecretProps, "value"> {
|
|
|
50
53
|
/**
|
|
51
54
|
* Resource for managing GitHub repository secrets
|
|
52
55
|
*/
|
|
53
|
-
export
|
|
56
|
+
export const GitHubSecret = Resource(
|
|
54
57
|
"github::Secret",
|
|
55
|
-
async (
|
|
56
|
-
|
|
58
|
+
async function (
|
|
59
|
+
this: Context<GitHubSecretOutput>,
|
|
60
|
+
id: string,
|
|
57
61
|
props: GitHubSecretProps,
|
|
58
|
-
): Promise<GitHubSecretOutput
|
|
62
|
+
): Promise<GitHubSecretOutput> {
|
|
59
63
|
// Create authenticated Octokit client - will automatically handle token resolution
|
|
64
|
+
/// TODO: use fetch
|
|
60
65
|
const octokit = await createGitHubClient({ token: props.token });
|
|
61
66
|
|
|
62
67
|
// Verify authentication and permissions
|
|
63
|
-
if (!
|
|
68
|
+
if (!this.quiet) {
|
|
64
69
|
await verifyGitHubAuth(octokit, props.owner, props.repository);
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
if (
|
|
68
|
-
if (
|
|
72
|
+
if (this.phase === "delete") {
|
|
73
|
+
if (this.output?.id) {
|
|
69
74
|
try {
|
|
70
75
|
// Delete the secret
|
|
71
76
|
await octokit.rest.actions.deleteRepoSecret({
|
|
@@ -84,7 +89,7 @@ export class GitHubSecret extends Resource(
|
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
// Return void (a deleted resource has no content)
|
|
87
|
-
return
|
|
92
|
+
return this.destroy();
|
|
88
93
|
} else {
|
|
89
94
|
try {
|
|
90
95
|
// Get the repository's public key for encrypting secrets
|
|
@@ -102,7 +107,7 @@ export class GitHubSecret extends Resource(
|
|
|
102
107
|
);
|
|
103
108
|
|
|
104
109
|
// Create or update the secret with the encrypted value and key_id
|
|
105
|
-
|
|
110
|
+
await octokit.rest.actions.createOrUpdateRepoSecret({
|
|
106
111
|
owner: props.owner,
|
|
107
112
|
repo: props.repository,
|
|
108
113
|
secret_name: props.name,
|
|
@@ -111,16 +116,14 @@ export class GitHubSecret extends Resource(
|
|
|
111
116
|
});
|
|
112
117
|
|
|
113
118
|
// GitHub doesn't return the secret details on create/update, so we need to construct it
|
|
114
|
-
|
|
119
|
+
return this({
|
|
115
120
|
id: `${props.owner}/${props.repository}/${props.name}`,
|
|
116
121
|
owner: props.owner,
|
|
117
122
|
repository: props.repository,
|
|
118
123
|
name: props.name,
|
|
119
124
|
token: props.token,
|
|
120
125
|
updatedAt: new Date().toISOString(),
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
return output;
|
|
126
|
+
});
|
|
124
127
|
} catch (error: any) {
|
|
125
128
|
if (
|
|
126
129
|
error.status === 403 &&
|
|
@@ -142,7 +145,7 @@ export class GitHubSecret extends Resource(
|
|
|
142
145
|
}
|
|
143
146
|
}
|
|
144
147
|
},
|
|
145
|
-
)
|
|
148
|
+
);
|
|
146
149
|
|
|
147
150
|
/**
|
|
148
151
|
* Encrypt a value for GitHub using libsodium
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
export * from "
|
|
2
|
-
export * from "./
|
|
3
|
-
export * from "./error";
|
|
4
|
-
export * from "./global";
|
|
5
|
-
export * from "./input";
|
|
6
|
-
export * from "./output";
|
|
7
|
-
export * from "./print";
|
|
8
|
-
export {
|
|
9
|
-
Resource,
|
|
10
|
-
type Context,
|
|
11
|
-
type CreateContext,
|
|
12
|
-
type DeleteContext,
|
|
13
|
-
type UpdateContext,
|
|
14
|
-
} from "./resource";
|
|
1
|
+
export type * from "./context";
|
|
2
|
+
export * from "./resource";
|
|
15
3
|
export * from "./secret";
|
|
16
|
-
export
|
|
4
|
+
export * from "./state";
|
|
5
|
+
export * from "./util/ignore";
|
|
6
|
+
|
|
7
|
+
import { alchemy } from "./alchemy";
|
|
8
|
+
export default alchemy;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./vite";
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { exec } from "child_process";
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { promisify } from "util";
|
|
5
|
+
import type { Context } from "../context";
|
|
6
|
+
import { Resource } from "../resource";
|
|
7
|
+
import { rm } from "../util/rm";
|
|
8
|
+
const execAsync = promisify(exec);
|
|
9
|
+
|
|
10
|
+
type ViteTemplate =
|
|
11
|
+
| "vanilla"
|
|
12
|
+
| "vanilla-ts"
|
|
13
|
+
| "vue"
|
|
14
|
+
| "vue-ts"
|
|
15
|
+
| "react"
|
|
16
|
+
| "react-ts"
|
|
17
|
+
| "react-swc"
|
|
18
|
+
| "react-swc-ts"
|
|
19
|
+
| "preact"
|
|
20
|
+
| "preact-ts"
|
|
21
|
+
| "lit"
|
|
22
|
+
| "lit-ts"
|
|
23
|
+
| "svelte"
|
|
24
|
+
| "svelte-ts"
|
|
25
|
+
| "solid"
|
|
26
|
+
| "solid-ts"
|
|
27
|
+
| "qwik"
|
|
28
|
+
| "qwik-ts";
|
|
29
|
+
|
|
30
|
+
export interface ViteProjectProps {
|
|
31
|
+
/**
|
|
32
|
+
* The name/path of the project
|
|
33
|
+
*/
|
|
34
|
+
name: string;
|
|
35
|
+
/**
|
|
36
|
+
* The Vite template to use
|
|
37
|
+
*/
|
|
38
|
+
template: ViteTemplate;
|
|
39
|
+
/**
|
|
40
|
+
* The extends to add to the tsconfig.json file
|
|
41
|
+
*/
|
|
42
|
+
extends?: string;
|
|
43
|
+
/**
|
|
44
|
+
* The references to add to the tsconfig.json file
|
|
45
|
+
*/
|
|
46
|
+
references?: string[];
|
|
47
|
+
/**
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
tailwind?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Force overwrite the project config tfiles during the update phase
|
|
53
|
+
*
|
|
54
|
+
* @default false
|
|
55
|
+
*/
|
|
56
|
+
overwrite?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ViteProject extends ViteProjectProps, Resource {
|
|
60
|
+
/**
|
|
61
|
+
* The name/path of the project
|
|
62
|
+
*/
|
|
63
|
+
name: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const ViteProject = Resource(
|
|
67
|
+
"project::ViteProject",
|
|
68
|
+
async function (
|
|
69
|
+
this: Context<ViteProject>,
|
|
70
|
+
id: string,
|
|
71
|
+
props: ViteProjectProps,
|
|
72
|
+
): Promise<ViteProject> {
|
|
73
|
+
if (this.phase === "delete") {
|
|
74
|
+
try {
|
|
75
|
+
if (await fs.exists(props.name)) {
|
|
76
|
+
// TODO: OS agnostic - fs.rm is slow to delete node_modules/
|
|
77
|
+
await execAsync("rm -rf " + props.name);
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error(`Error deleting project ${id}:`, error);
|
|
81
|
+
}
|
|
82
|
+
return this.destroy();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (this.phase === "update") {
|
|
86
|
+
if (props.overwrite) {
|
|
87
|
+
await modifyConfig(props);
|
|
88
|
+
} else {
|
|
89
|
+
console.warn(
|
|
90
|
+
"ViteProject does not support updates - the project must be recreated to change the template",
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
// Create phase
|
|
95
|
+
await execAsync(`bun create vite ${id} --template ${props.template}`);
|
|
96
|
+
|
|
97
|
+
await modifyConfig(props);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return this(props);
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
async function modifyConfig(props: ViteProjectProps) {
|
|
105
|
+
if (props.tailwind) {
|
|
106
|
+
await execAsync(`bun add tailwindcss @tailwindcss/vite`);
|
|
107
|
+
|
|
108
|
+
await fs.writeFile(
|
|
109
|
+
path.join(props.name, "vite.config.ts"),
|
|
110
|
+
`import tailwindcss from "@tailwindcss/vite";
|
|
111
|
+
import react from "@vitejs/plugin-react";
|
|
112
|
+
import { defineConfig } from "vite";
|
|
113
|
+
|
|
114
|
+
// https://vite.dev/config/
|
|
115
|
+
export default defineConfig({
|
|
116
|
+
plugins: [react(), tailwindcss()],
|
|
117
|
+
});`,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// Add Tailwind CSS import to index.css
|
|
121
|
+
const indexCssPath = path.join(props.name, "src", "index.css");
|
|
122
|
+
const currentCss = await fs.readFile(indexCssPath, "utf-8");
|
|
123
|
+
if (!currentCss.includes('@import "tailwindcss";')) {
|
|
124
|
+
await fs.writeFile(
|
|
125
|
+
indexCssPath,
|
|
126
|
+
'@import "tailwindcss";\n\n' + currentCss,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await Promise.all([
|
|
132
|
+
rm(path.join(props.name, "tsconfig.app.json")),
|
|
133
|
+
rm(path.join(props.name, "tsconfig.node.json")),
|
|
134
|
+
fs.writeFile(
|
|
135
|
+
path.join(props.name, "tsconfig.json"),
|
|
136
|
+
JSON.stringify(
|
|
137
|
+
{
|
|
138
|
+
extends: props.extends,
|
|
139
|
+
compilerOptions: {
|
|
140
|
+
types: ["@cloudflare/workers-types"],
|
|
141
|
+
allowImportingTsExtensions: true,
|
|
142
|
+
jsx: "react-jsx",
|
|
143
|
+
},
|
|
144
|
+
include: ["vite/*.ts", "src/**/*.ts", "src/**/*.tsx", "src/env.d.ts"],
|
|
145
|
+
references: props.references?.map((path) => ({ path })),
|
|
146
|
+
},
|
|
147
|
+
null,
|
|
148
|
+
2,
|
|
149
|
+
),
|
|
150
|
+
),
|
|
151
|
+
]);
|
|
152
|
+
}
|