alchemy 0.1.17 → 0.2.0
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/lib/alchemy.d.ts +67 -0
- package/lib/alchemy.js +40 -0
- package/lib/apply.d.ts +3 -20
- package/lib/apply.js +86 -78
- 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 +4 -3
- package/lib/cloudflare/bindings.js +3 -2
- package/lib/cloudflare/bound.d.ts +7 -0
- package/lib/cloudflare/bound.js +1 -0
- 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 +0 -1
- package/lib/cloudflare/index.js +0 -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 +16 -28
- 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 +13 -13
- package/lib/cloudflare/worker.js +43 -43
- 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 +6 -7
- package/lib/github/secret.js +30 -36
- package/lib/index.d.ts +7 -10
- package/lib/index.js +6 -9
- package/lib/resource.d.ts +34 -62
- package/lib/resource.js +29 -270
- package/lib/scope.d.ts +35 -14
- package/lib/scope.js +78 -23
- package/lib/secret.d.ts +7 -0
- package/lib/secret.js +17 -0
- package/lib/state.d.ts +14 -10
- package/lib/state.js +15 -13
- 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/util/encrypt.d.ts +16 -0
- package/lib/util/encrypt.js +44 -0
- 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/serde.d.ts +3 -0
- package/lib/util/serde.js +46 -0
- package/lib/util/slugify.d.ts +1 -0
- package/lib/util/slugify.js +3 -0
- package/package.json +5 -7
- package/src/alchemy.ts +120 -0
- package/src/apply.ts +109 -111
- 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 +12 -2
- package/src/cloudflare/bound.ts +18 -0
- package/src/cloudflare/bucket.ts +40 -48
- package/src/cloudflare/durable-object-namespace.ts +0 -10
- package/src/cloudflare/generate-asset-manifest.ts +1 -1
- package/src/cloudflare/kv-namespace.ts +35 -33
- package/src/cloudflare/static-site-router.ts +0 -3
- package/src/cloudflare/static-site.ts +43 -59
- package/src/cloudflare/worker.ts +76 -64
- 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 +53 -49
- package/src/index.ts +8 -15
- package/src/resource.ts +101 -462
- package/src/scope.ts +101 -36
- package/src/secret.ts +18 -0
- package/src/state.ts +30 -20
- 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/encrypt.ts +79 -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 -43
- package/lib/alchemize.d.ts.map +0 -1
- package/lib/alchemize.js +0 -112
- 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/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/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 -6
- 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 -24
- 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/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 -186
- package/src/fs.ts +0 -47
- package/src/global.ts +0 -63
- package/src/input.ts +0 -16
- package/src/main.ts +0 -34
- package/src/output.ts +0 -71
- package/src/print.ts +0 -18
- package/src/slug.ts +0 -3
- /package/src/{utils → util}/content-type.ts +0 -0
- /package/src/{error.ts → util/ignore.ts} +0 -0
- /package/src/{utils → util}/retry.ts +0 -0
package/src/alchemy.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { destroy } from "./destroy";
|
|
2
|
+
import { Scope } from "./scope";
|
|
3
|
+
import { secret } from "./secret";
|
|
4
|
+
import type { StateStoreType } from "./state";
|
|
5
|
+
|
|
6
|
+
// TODO: support browser
|
|
7
|
+
const DEFAULT_STAGE = process.env.ALCHEMY_STAGE ?? process.env.USER ?? "dev";
|
|
8
|
+
|
|
9
|
+
function _alchemy(appName: string, options: Omit<AlchemyOptions, "appName">) {
|
|
10
|
+
return scope(undefined, {
|
|
11
|
+
...options,
|
|
12
|
+
appName,
|
|
13
|
+
stage: options.stage,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
_alchemy.destroy = destroy;
|
|
17
|
+
_alchemy.run = run;
|
|
18
|
+
_alchemy.scope = scope;
|
|
19
|
+
_alchemy.secret = secret;
|
|
20
|
+
|
|
21
|
+
// alchemy type is to semantically highlight `alchemy` as a type (keyword)
|
|
22
|
+
export type alchemy = Alchemy;
|
|
23
|
+
|
|
24
|
+
export const alchemy: Alchemy = _alchemy as any;
|
|
25
|
+
|
|
26
|
+
// Alchemy is for module augmentation
|
|
27
|
+
export interface Alchemy {
|
|
28
|
+
scope: typeof scope;
|
|
29
|
+
run: typeof run;
|
|
30
|
+
destroy: typeof destroy;
|
|
31
|
+
secret: typeof secret;
|
|
32
|
+
(...parameters: Parameters<typeof scope>): ReturnType<typeof scope>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface AlchemyOptions {
|
|
36
|
+
/**
|
|
37
|
+
* The name of the application.
|
|
38
|
+
*/
|
|
39
|
+
appName?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Determines whether the resources will be created/updated or deleted.
|
|
42
|
+
*
|
|
43
|
+
* @default "up"
|
|
44
|
+
*/
|
|
45
|
+
phase?: "up" | "destroy";
|
|
46
|
+
/**
|
|
47
|
+
* Name to scope the resource state under (e.g. `.alchemy/{stage}/..`).
|
|
48
|
+
*
|
|
49
|
+
* @default - your POSIX username
|
|
50
|
+
*/
|
|
51
|
+
stage?: string;
|
|
52
|
+
/**
|
|
53
|
+
* If true, will not prune resources that were dropped from the root stack.
|
|
54
|
+
*
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
destroyOrphans?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* A custom state store to use instead of the default file system store.
|
|
60
|
+
*/
|
|
61
|
+
stateStore?: StateStoreType;
|
|
62
|
+
/**
|
|
63
|
+
* A custom scope to use as a parent.
|
|
64
|
+
*/
|
|
65
|
+
parent?: Scope;
|
|
66
|
+
/**
|
|
67
|
+
* If true, will not print any Create/Update/Delete messages.
|
|
68
|
+
*
|
|
69
|
+
* @default false
|
|
70
|
+
*/
|
|
71
|
+
quiet?: boolean;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A passphrase to use to encrypt/decrypt secrets.
|
|
75
|
+
*/
|
|
76
|
+
password?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Enter a new scope synchronously.
|
|
81
|
+
* @param options
|
|
82
|
+
* @returns
|
|
83
|
+
*/
|
|
84
|
+
function scope(
|
|
85
|
+
id: string | undefined,
|
|
86
|
+
options?: AlchemyOptions,
|
|
87
|
+
// TODO: maybe we want to allow using _ = await alchemy.scope(import.meta)
|
|
88
|
+
// | [meta: ImportMeta]
|
|
89
|
+
): Scope {
|
|
90
|
+
const scope = new Scope({
|
|
91
|
+
...options,
|
|
92
|
+
appName: options?.appName,
|
|
93
|
+
stage: options?.stage ?? DEFAULT_STAGE,
|
|
94
|
+
scopeName: id,
|
|
95
|
+
parent: options?.parent ?? Scope.get(),
|
|
96
|
+
});
|
|
97
|
+
scope.enter();
|
|
98
|
+
return scope;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function run<T>(
|
|
102
|
+
...args:
|
|
103
|
+
| [id: string, fn: (this: Scope, scope: Scope) => Promise<T>]
|
|
104
|
+
| [
|
|
105
|
+
id: string,
|
|
106
|
+
options: AlchemyOptions,
|
|
107
|
+
fn: (this: Scope, scope: Scope) => Promise<T>,
|
|
108
|
+
]
|
|
109
|
+
): Promise<T> {
|
|
110
|
+
const [id, options, fn] =
|
|
111
|
+
typeof args[1] === "function"
|
|
112
|
+
? [args[0], undefined, args[1]]
|
|
113
|
+
: (args as [
|
|
114
|
+
string,
|
|
115
|
+
AlchemyOptions | undefined,
|
|
116
|
+
(this: Scope, scope: Scope) => Promise<T>,
|
|
117
|
+
]);
|
|
118
|
+
await using scope = alchemy.scope(id, options);
|
|
119
|
+
return await fn.bind(scope)(scope);
|
|
120
|
+
}
|
package/src/apply.ts
CHANGED
|
@@ -1,132 +1,130 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { alchemy } from "./alchemy";
|
|
2
|
+
import { context } from "./context";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
PROVIDERS,
|
|
5
|
+
type PendingResource,
|
|
6
|
+
type Provider,
|
|
6
7
|
type Resource,
|
|
7
|
-
|
|
8
|
-
isResource,
|
|
8
|
+
type ResourceProps,
|
|
9
9
|
} from "./resource";
|
|
10
|
-
import
|
|
11
|
-
import
|
|
10
|
+
import type { State } from "./state";
|
|
11
|
+
import { serialize } from "./util/serde";
|
|
12
12
|
|
|
13
13
|
export interface ApplyOptions {
|
|
14
|
-
stage: string;
|
|
15
|
-
scope: IScope;
|
|
16
|
-
stateStore: StateStore;
|
|
17
14
|
quiet?: boolean;
|
|
15
|
+
alwaysUpdate?: boolean;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
18
|
+
export async function apply<Out extends Resource>(
|
|
19
|
+
resource: PendingResource<Out>,
|
|
20
|
+
props: ResourceProps,
|
|
21
|
+
options?: ApplyOptions,
|
|
22
|
+
): Promise<Awaited<Out>> {
|
|
23
|
+
const scope = resource.Scope;
|
|
24
|
+
const quiet = props.quiet ?? scope.quiet;
|
|
25
|
+
await scope.init();
|
|
26
|
+
let state: State | undefined = (await scope.state.get(resource.ID))!;
|
|
27
|
+
const provider: Provider = PROVIDERS.get(resource.Kind);
|
|
28
|
+
if (provider === undefined) {
|
|
29
|
+
throw new Error(`Provider "${resource.Kind}" not found`);
|
|
30
|
+
}
|
|
31
|
+
if (state === undefined) {
|
|
32
|
+
state = {
|
|
33
|
+
kind: resource.Kind,
|
|
34
|
+
id: resource.ID,
|
|
35
|
+
fqn: resource.FQN,
|
|
36
|
+
seq: resource.Seq,
|
|
37
|
+
status: "creating",
|
|
38
|
+
data: {},
|
|
39
|
+
output: {
|
|
40
|
+
ID: resource.ID,
|
|
41
|
+
FQN: resource.FQN,
|
|
42
|
+
Kind: resource.Kind,
|
|
43
|
+
Scope: scope,
|
|
44
|
+
Seq: resource.Seq,
|
|
45
|
+
},
|
|
46
|
+
// deps: [...deps],
|
|
47
|
+
props,
|
|
48
|
+
};
|
|
49
|
+
await scope.state.set(resource.ID, state);
|
|
50
|
+
}
|
|
33
51
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
).value as Resolved<T>;
|
|
37
|
-
}
|
|
52
|
+
const alwaysUpdate =
|
|
53
|
+
options?.alwaysUpdate ?? provider.options?.alwaysUpdate ?? false;
|
|
38
54
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
55
|
+
// Skip update if inputs haven't changed and resource is in a stable state
|
|
56
|
+
if (state.status === "created" || state.status === "updated") {
|
|
57
|
+
if (
|
|
58
|
+
JSON.stringify(state.props) === JSON.stringify(serialize(scope, props)) &&
|
|
59
|
+
alwaysUpdate !== true
|
|
60
|
+
) {
|
|
61
|
+
if (!quiet) {
|
|
62
|
+
console.log(`Skip: "${resource.FQN}" (no changes)`);
|
|
63
|
+
}
|
|
64
|
+
// if (resourceState.output !== undefined) {
|
|
65
|
+
// resource[Provide](resourceState.output);
|
|
66
|
+
// }
|
|
67
|
+
return state.output as Awaited<Out>;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
45
70
|
|
|
46
|
-
const
|
|
71
|
+
const phase = state.status === "creating" ? "create" : "update";
|
|
72
|
+
state.status = phase === "create" ? "creating" : "updating";
|
|
73
|
+
state.oldProps = state.props;
|
|
74
|
+
state.props = props;
|
|
47
75
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
): Promise<Evaluated<T>> {
|
|
52
|
-
const stage = options.stage;
|
|
53
|
-
const stateStore = options.stateStore;
|
|
54
|
-
if (isResource(output)) {
|
|
55
|
-
const resource = output;
|
|
56
|
-
const resourceID = resource[ResourceID];
|
|
57
|
-
const evaluated = await Promise.all(
|
|
58
|
-
resource[Input].map((r) => evaluate<any>(r, options)),
|
|
76
|
+
if (!quiet) {
|
|
77
|
+
console.log(
|
|
78
|
+
`${phase === "create" ? "Create" : "Update"}: "${resource.FQN}"`,
|
|
59
79
|
);
|
|
80
|
+
}
|
|
60
81
|
|
|
61
|
-
|
|
62
|
-
return await cache.get(resource)!;
|
|
63
|
-
}
|
|
64
|
-
let resolve: (value: Evaluated<any>) => void;
|
|
65
|
-
let reject: (reason?: any) => void;
|
|
66
|
-
const promise = new Promise<Evaluated<any>>((res, rej) => {
|
|
67
|
-
resolve = res;
|
|
68
|
-
reject = rej;
|
|
69
|
-
});
|
|
70
|
-
// set this eagerly to avoid double-apply (caused by recursive applies to inputs)
|
|
71
|
-
cache.set(resource, promise);
|
|
82
|
+
await scope.state.set(resource.ID, state);
|
|
72
83
|
|
|
73
|
-
|
|
74
|
-
const inputs = evaluated.map((input) => input.value);
|
|
75
|
-
try {
|
|
76
|
-
const result: T = await resource[Provider].update(
|
|
77
|
-
stage,
|
|
78
|
-
resource,
|
|
79
|
-
deps,
|
|
80
|
-
inputs as [],
|
|
81
|
-
stateStore,
|
|
82
|
-
options,
|
|
83
|
-
);
|
|
84
|
-
resolve!(new Evaluated(result, [resourceID, ...deps]));
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.error(error);
|
|
87
|
-
reject!(error);
|
|
88
|
-
}
|
|
89
|
-
return promise;
|
|
90
|
-
} else if (output instanceof OutputChain) {
|
|
91
|
-
const inside = output as unknown as {
|
|
92
|
-
parent: Output<any>;
|
|
93
|
-
fn: (value: any) => T;
|
|
94
|
-
};
|
|
95
|
-
const parent = await evaluate(inside.parent, options);
|
|
96
|
-
const ret = inside.fn(parent.value);
|
|
97
|
-
// the ret may be an Output (e.g. in the flatMap case), so we need to evaluate it and include its deps
|
|
98
|
-
const evaluated = await evaluate(ret, options);
|
|
99
|
-
return new Evaluated<T>(evaluated.value, [
|
|
100
|
-
...parent.deps,
|
|
101
|
-
...evaluated.deps,
|
|
102
|
-
]);
|
|
103
|
-
} else if (Array.isArray(output)) {
|
|
104
|
-
const evaluatedItems = await Promise.all(
|
|
105
|
-
output.map((item) => evaluate(item, options)),
|
|
106
|
-
);
|
|
107
|
-
return new Evaluated(
|
|
108
|
-
evaluatedItems.map((e) => e.value) as unknown as T,
|
|
109
|
-
evaluatedItems.flatMap((e) => e.deps),
|
|
110
|
-
);
|
|
111
|
-
} else if (output instanceof Date) {
|
|
112
|
-
return new Evaluated(output as T);
|
|
113
|
-
} else if (output && typeof output === "object") {
|
|
114
|
-
const entries = Object.entries(output);
|
|
115
|
-
const evaluatedEntries = await Promise.all(
|
|
116
|
-
entries.map(
|
|
117
|
-
async ([key, value]) => [key, await evaluate(value, options)] as const,
|
|
118
|
-
),
|
|
119
|
-
);
|
|
84
|
+
let isReplaced = false;
|
|
120
85
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
86
|
+
const ctx = context({
|
|
87
|
+
scope,
|
|
88
|
+
phase,
|
|
89
|
+
kind: resource.Kind,
|
|
90
|
+
id: resource.ID,
|
|
91
|
+
fqn: resource.FQN,
|
|
92
|
+
seq: resource.Seq,
|
|
93
|
+
state,
|
|
94
|
+
replace: () => {
|
|
95
|
+
if (isReplaced) {
|
|
96
|
+
console.warn(
|
|
97
|
+
`Resource ${resource.Kind} ${resource.FQN} is already marked as REPLACE`,
|
|
98
|
+
);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
isReplaced = true;
|
|
102
|
+
},
|
|
103
|
+
});
|
|
124
104
|
|
|
125
|
-
|
|
105
|
+
const output = await alchemy.run(resource.ID, async () =>
|
|
106
|
+
provider.handler.bind(ctx)(resource.ID, props),
|
|
107
|
+
);
|
|
126
108
|
|
|
127
|
-
|
|
109
|
+
if (!quiet) {
|
|
110
|
+
console.log(
|
|
111
|
+
`${phase === "create" ? "Created" : "Updated"}: "${resource.FQN}"`,
|
|
112
|
+
);
|
|
128
113
|
}
|
|
129
114
|
|
|
130
|
-
|
|
131
|
-
|
|
115
|
+
await scope.state.set(resource.ID, {
|
|
116
|
+
kind: resource.Kind,
|
|
117
|
+
id: resource.ID,
|
|
118
|
+
fqn: resource.FQN,
|
|
119
|
+
seq: resource.Seq,
|
|
120
|
+
data: state.data,
|
|
121
|
+
status: phase === "create" ? "created" : "updated",
|
|
122
|
+
output,
|
|
123
|
+
props,
|
|
124
|
+
// deps: [...deps],
|
|
125
|
+
});
|
|
126
|
+
// if (output !== undefined) {
|
|
127
|
+
// resource[Provide](output as Out);
|
|
128
|
+
// }
|
|
129
|
+
return output as any;
|
|
132
130
|
}
|
package/src/aws/bucket.ts
CHANGED
|
@@ -10,16 +10,16 @@ import {
|
|
|
10
10
|
PutBucketTaggingCommand,
|
|
11
11
|
S3Client,
|
|
12
12
|
} from "@aws-sdk/client-s3";
|
|
13
|
-
import {
|
|
13
|
+
import type { Context } from "../context";
|
|
14
14
|
import { Resource } from "../resource";
|
|
15
|
+
import { ignore } from "../util/ignore";
|
|
15
16
|
|
|
16
17
|
export interface BucketProps {
|
|
17
18
|
bucketName: string;
|
|
18
19
|
tags?: Record<string, string>;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
export interface
|
|
22
|
-
id: string; // Same as bucketName for AWS
|
|
22
|
+
export interface Bucket extends Resource<"s3::Bucket">, BucketProps {
|
|
23
23
|
arn: string;
|
|
24
24
|
bucketDomainName: string; // Format: bucket-name.s3.amazonaws.com
|
|
25
25
|
bucketRegionalDomainName?: string; // Format: bucket-name.s3.region.amazonaws.com
|
|
@@ -31,12 +31,12 @@ export interface BucketOutput extends BucketProps {
|
|
|
31
31
|
acl?: string;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export
|
|
34
|
+
export const Bucket = Resource(
|
|
35
35
|
"s3::Bucket",
|
|
36
|
-
async (
|
|
36
|
+
async function (this: Context<Bucket>, id: string, props: BucketProps) {
|
|
37
37
|
const client = new S3Client({});
|
|
38
38
|
|
|
39
|
-
if (
|
|
39
|
+
if (this.phase === "delete") {
|
|
40
40
|
await ignore(NoSuchBucket.name, () =>
|
|
41
41
|
client.send(
|
|
42
42
|
new DeleteBucketCommand({
|
|
@@ -44,7 +44,7 @@ export class Bucket extends Resource(
|
|
|
44
44
|
}),
|
|
45
45
|
),
|
|
46
46
|
);
|
|
47
|
-
return
|
|
47
|
+
return this.destroy();
|
|
48
48
|
} else {
|
|
49
49
|
try {
|
|
50
50
|
// Check if bucket exists
|
|
@@ -55,7 +55,7 @@ export class Bucket extends Resource(
|
|
|
55
55
|
);
|
|
56
56
|
|
|
57
57
|
// Update tags if they changed and bucket exists
|
|
58
|
-
if (
|
|
58
|
+
if (this.phase === "update" && props.tags) {
|
|
59
59
|
await client.send(
|
|
60
60
|
new PutBucketTaggingCommand({
|
|
61
61
|
Bucket: props.bucketName,
|
|
@@ -121,9 +121,8 @@ export class Bucket extends Resource(
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
return this({
|
|
125
125
|
bucketName: props.bucketName,
|
|
126
|
-
id: props.bucketName,
|
|
127
126
|
arn: `arn:aws:s3:::${props.bucketName}`,
|
|
128
127
|
bucketDomainName: `${props.bucketName}.s3.amazonaws.com`,
|
|
129
128
|
bucketRegionalDomainName: `${props.bucketName}.s3.${region}.amazonaws.com`,
|
|
@@ -132,12 +131,10 @@ export class Bucket extends Resource(
|
|
|
132
131
|
versioningEnabled: versioningResponse.Status === "Enabled",
|
|
133
132
|
acl: aclResponse.Grants?.[0]?.Permission?.toLowerCase(),
|
|
134
133
|
...(tags && { tags }),
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
return output;
|
|
134
|
+
});
|
|
138
135
|
}
|
|
139
136
|
},
|
|
140
|
-
)
|
|
137
|
+
);
|
|
141
138
|
|
|
142
139
|
// Helper function to get S3 hosted zone IDs by region
|
|
143
140
|
function getHostedZoneId(region: string): string {
|
package/src/aws/function.ts
CHANGED
|
@@ -12,8 +12,9 @@ import {
|
|
|
12
12
|
} from "@aws-sdk/client-lambda";
|
|
13
13
|
import fs from "node:fs";
|
|
14
14
|
import path from "node:path";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import type { Context } from "../context";
|
|
16
|
+
import { Resource } from "../resource";
|
|
17
|
+
import { ignore } from "../util/ignore";
|
|
17
18
|
|
|
18
19
|
async function resolveRegion(client: LambdaClient): Promise<string> {
|
|
19
20
|
const region = client.config.region;
|
|
@@ -47,8 +48,7 @@ export interface FunctionProps {
|
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
export interface
|
|
51
|
-
id: string; // Same as functionName
|
|
51
|
+
export interface Function extends Resource<"lambda::Function">, FunctionProps {
|
|
52
52
|
arn: string;
|
|
53
53
|
lastModified: string;
|
|
54
54
|
version: string;
|
|
@@ -71,15 +71,15 @@ export interface FunctionOutput extends FunctionProps {
|
|
|
71
71
|
signingJobArn?: string;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
export
|
|
74
|
+
export const Function = Resource(
|
|
75
75
|
"lambda::Function",
|
|
76
|
-
async (
|
|
76
|
+
async function (this: Context<Function>, id: string, props: FunctionProps) {
|
|
77
77
|
const client = new LambdaClient({});
|
|
78
78
|
const region = await resolveRegion(client);
|
|
79
79
|
|
|
80
80
|
const code = await zipCode(props.zipPath);
|
|
81
81
|
|
|
82
|
-
if (
|
|
82
|
+
if (this.phase === "delete") {
|
|
83
83
|
await ignore(ResourceNotFoundException.name, () =>
|
|
84
84
|
client.send(
|
|
85
85
|
new DeleteFunctionCommand({
|
|
@@ -88,34 +88,17 @@ export class Function extends Resource(
|
|
|
88
88
|
),
|
|
89
89
|
);
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
...props,
|
|
94
|
-
id: props.functionName,
|
|
95
|
-
arn: `arn:aws:lambda:${region}:${process.env.AWS_ACCOUNT_ID}:function:${props.functionName}`,
|
|
96
|
-
lastModified: new Date().toISOString(),
|
|
97
|
-
version: "$LATEST",
|
|
98
|
-
qualifiedArn: `arn:aws:lambda:${region}:${process.env.AWS_ACCOUNT_ID}:function:${props.functionName}:$LATEST`,
|
|
99
|
-
invokeArn: `arn:aws:apigateway:${region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${region}:${process.env.AWS_ACCOUNT_ID}:function:${props.functionName}/invocations`,
|
|
100
|
-
sourceCodeHash: "",
|
|
101
|
-
sourceCodeSize: 0,
|
|
102
|
-
architectures: props.architecture
|
|
103
|
-
? [props.architecture]
|
|
104
|
-
: [Architecture.x86_64],
|
|
105
|
-
revisionId: "",
|
|
106
|
-
state: "Inactive",
|
|
107
|
-
packageType: "Zip",
|
|
108
|
-
};
|
|
91
|
+
return this.destroy();
|
|
109
92
|
} else {
|
|
110
93
|
try {
|
|
111
94
|
// Check if function exists
|
|
112
|
-
|
|
95
|
+
await client.send(
|
|
113
96
|
new GetFunctionCommand({
|
|
114
97
|
FunctionName: props.functionName,
|
|
115
98
|
}),
|
|
116
99
|
);
|
|
117
100
|
|
|
118
|
-
if (
|
|
101
|
+
if (this.phase === "update") {
|
|
119
102
|
// Wait for function to stabilize
|
|
120
103
|
await waitForFunctionStabilization(client, props.functionName);
|
|
121
104
|
|
|
@@ -228,9 +211,8 @@ export class Function extends Resource(
|
|
|
228
211
|
),
|
|
229
212
|
]);
|
|
230
213
|
|
|
231
|
-
|
|
214
|
+
return this({
|
|
232
215
|
...props,
|
|
233
|
-
id: props.functionName,
|
|
234
216
|
arn: config.FunctionArn!,
|
|
235
217
|
lastModified: config.LastModified!,
|
|
236
218
|
version: config.Version!,
|
|
@@ -251,12 +233,10 @@ export class Function extends Resource(
|
|
|
251
233
|
packageType: config.PackageType!,
|
|
252
234
|
signingProfileVersionArn: config.SigningProfileVersionArn,
|
|
253
235
|
signingJobArn: config.SigningJobArn,
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
return output;
|
|
236
|
+
});
|
|
257
237
|
}
|
|
258
238
|
},
|
|
259
|
-
)
|
|
239
|
+
);
|
|
260
240
|
|
|
261
241
|
// Helper to wait for function to stabilize
|
|
262
242
|
async function waitForFunctionStabilization(
|
package/src/aws/index.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { Input } from "../../input";
|
|
2
|
-
import { isOutput } from "../../output";
|
|
3
1
|
import { OIDCProvider, type OIDCProviderProps } from "./oidc-provider";
|
|
4
2
|
|
|
5
3
|
/**
|
|
@@ -13,22 +11,19 @@ export interface GitHubOIDCProviderProps
|
|
|
13
11
|
extends Omit<OIDCProviderProps, "thumbprint"> {
|
|
14
12
|
owner: string;
|
|
15
13
|
repository: string;
|
|
16
|
-
thumbprint?: string;
|
|
17
14
|
}
|
|
15
|
+
export type GitHubOIDCProvider = ReturnType<typeof GitHubOIDCProvider>;
|
|
18
16
|
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
17
|
+
export const GitHubOIDCProvider = async (
|
|
18
|
+
id: string,
|
|
19
|
+
props: GitHubOIDCProviderProps,
|
|
20
|
+
) => {
|
|
21
|
+
return OIDCProvider(id, {
|
|
22
|
+
owner: props.owner,
|
|
23
|
+
repository: props.repository,
|
|
24
|
+
roleArn: props.roleArn,
|
|
25
|
+
branches: props.branches,
|
|
26
|
+
environments: props.environments,
|
|
27
|
+
thumbprint: DEFAULT_GITHUB_THUMBPRINT,
|
|
28
|
+
});
|
|
29
|
+
};
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
type Tag,
|
|
8
8
|
UpdateAssumeRolePolicyCommand,
|
|
9
9
|
} from "@aws-sdk/client-iam";
|
|
10
|
-
import {
|
|
10
|
+
import type { Context } from "../../context";
|
|
11
|
+
import { Resource } from "../../resource";
|
|
11
12
|
import { getAccountId } from "../account-id";
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -60,7 +61,9 @@ export interface OIDCProviderProps {
|
|
|
60
61
|
/**
|
|
61
62
|
* Output returned after OIDC provider configuration
|
|
62
63
|
*/
|
|
63
|
-
export interface
|
|
64
|
+
export interface OIDCProvider
|
|
65
|
+
extends Resource<"aws::OIDCProvider">,
|
|
66
|
+
OIDCProviderProps {
|
|
64
67
|
/**
|
|
65
68
|
* The ARN of the OIDC provider
|
|
66
69
|
*/
|
|
@@ -81,16 +84,20 @@ const TRUST_POLICY_SID = "GitHubOIDCTrust";
|
|
|
81
84
|
/**
|
|
82
85
|
* Resource for configuring AWS OIDC provider for GitHub Actions
|
|
83
86
|
*/
|
|
84
|
-
export
|
|
87
|
+
export const OIDCProvider = Resource(
|
|
85
88
|
"aws::OIDCProvider",
|
|
86
|
-
async (
|
|
89
|
+
async function (
|
|
90
|
+
this: Context<OIDCProvider>,
|
|
91
|
+
id: string,
|
|
92
|
+
props: OIDCProviderProps,
|
|
93
|
+
) {
|
|
87
94
|
// Initialize AWS SDK client
|
|
88
95
|
const client = new IAMClient({
|
|
89
96
|
region: props.region,
|
|
90
97
|
});
|
|
91
98
|
|
|
92
|
-
if (
|
|
93
|
-
if (
|
|
99
|
+
if (this.phase === "delete") {
|
|
100
|
+
if (this.output?.providerArn) {
|
|
94
101
|
try {
|
|
95
102
|
// First, remove our trust policy statement from the role
|
|
96
103
|
const getRole = await client.send(
|
|
@@ -120,7 +127,7 @@ export class OIDCProvider extends Resource(
|
|
|
120
127
|
// Then delete the OIDC provider if we're the last user
|
|
121
128
|
const provider = await client.send(
|
|
122
129
|
new GetOpenIDConnectProviderCommand({
|
|
123
|
-
OpenIDConnectProviderArn:
|
|
130
|
+
OpenIDConnectProviderArn: this.output.providerArn,
|
|
124
131
|
}),
|
|
125
132
|
);
|
|
126
133
|
|
|
@@ -128,7 +135,7 @@ export class OIDCProvider extends Resource(
|
|
|
128
135
|
if (provider && (!provider.Tags || provider.Tags.length === 0)) {
|
|
129
136
|
await client.send(
|
|
130
137
|
new DeleteOpenIDConnectProviderCommand({
|
|
131
|
-
OpenIDConnectProviderArn:
|
|
138
|
+
OpenIDConnectProviderArn: this.output.providerArn,
|
|
132
139
|
}),
|
|
133
140
|
);
|
|
134
141
|
}
|
|
@@ -137,7 +144,7 @@ export class OIDCProvider extends Resource(
|
|
|
137
144
|
console.error("Error during cleanup:", error);
|
|
138
145
|
}
|
|
139
146
|
}
|
|
140
|
-
return;
|
|
147
|
+
return this.destroy();
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
try {
|
|
@@ -240,14 +247,14 @@ export class OIDCProvider extends Resource(
|
|
|
240
247
|
}),
|
|
241
248
|
);
|
|
242
249
|
|
|
243
|
-
return {
|
|
250
|
+
return this({
|
|
244
251
|
...props,
|
|
245
252
|
providerArn,
|
|
246
253
|
createdAt: Date.now(),
|
|
247
|
-
};
|
|
254
|
+
});
|
|
248
255
|
} catch (error) {
|
|
249
256
|
console.error("Error configuring OIDC provider:", error);
|
|
250
257
|
throw error;
|
|
251
258
|
}
|
|
252
259
|
},
|
|
253
|
-
)
|
|
260
|
+
);
|