alchemy 0.2.2 → 0.2.4
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/ai/ark.d.ts +11 -0
- package/lib/ai/ark.js +86 -0
- package/lib/ai/client.d.ts +51 -0
- package/lib/ai/client.js +29 -0
- package/lib/ai/document.d.ts +97 -0
- package/lib/ai/document.js +82 -0
- package/lib/ai/index.d.ts +2 -0
- package/lib/ai/index.js +2 -0
- package/lib/ai/object.d.ts +101 -0
- package/lib/ai/object.js +70 -0
- package/lib/alchemy.d.ts +84 -2
- package/lib/alchemy.js +114 -10
- package/lib/apply.d.ts +1 -1
- package/lib/apply.js +13 -10
- package/lib/aws/bucket.d.ts +87 -1
- package/lib/aws/bucket.js +48 -1
- package/lib/aws/function.d.ts +186 -1
- package/lib/aws/function.js +62 -8
- package/lib/aws/oidc/github-oidc-provider.d.ts +81 -0
- package/lib/aws/oidc/github-oidc-provider.js +68 -0
- package/lib/aws/oidc/oidc-provider.d.ts +14 -6
- package/lib/aws/oidc/oidc-provider.js +26 -5
- package/lib/aws/policy-attachment.d.ts +44 -1
- package/lib/aws/policy-attachment.js +31 -0
- package/lib/aws/policy.d.ts +160 -1
- package/lib/aws/policy.js +78 -0
- package/lib/aws/queue.d.ts +83 -1
- package/lib/aws/queue.js +39 -0
- package/lib/aws/role.d.ts +162 -1
- package/lib/aws/role.js +114 -0
- package/lib/aws/ses.d.ts +57 -2
- package/lib/aws/ses.js +42 -1
- package/lib/aws/table.d.ts +96 -1
- package/lib/aws/table.js +36 -0
- package/lib/cloudflare/asset-manifest.js +0 -1
- package/lib/cloudflare/bound.js +0 -1
- package/lib/cloudflare/bucket.d.ts +37 -1
- package/lib/cloudflare/bucket.js +36 -0
- package/lib/cloudflare/durable-object-namespace.d.ts +25 -0
- package/lib/cloudflare/durable-object-namespace.js +22 -0
- package/lib/cloudflare/kv-namespace.d.ts +37 -1
- package/lib/cloudflare/kv-namespace.js +36 -0
- package/lib/cloudflare/static-site.d.ts +53 -1
- package/lib/cloudflare/static-site.js +53 -1
- package/lib/cloudflare/worker-metadata.js +0 -1
- package/lib/cloudflare/worker.d.ts +64 -1
- package/lib/cloudflare/worker.js +63 -0
- package/lib/cloudflare/wrangler.json.d.ts +1 -1
- package/lib/cloudflare/zone-settings.js +0 -1
- package/lib/cloudflare/zone.d.ts +56 -1
- package/lib/cloudflare/zone.js +55 -0
- package/lib/context.d.ts +9 -4
- package/lib/context.js +4 -2
- package/lib/destroy.js +9 -8
- package/lib/esbuild/bundle.d.ts +43 -4
- package/lib/esbuild/bundle.js +16 -0
- package/lib/fs/file-collection.d.ts +16 -0
- package/lib/fs/file-collection.js +6 -0
- package/lib/fs/file-ref.d.ts +14 -0
- package/lib/fs/file-ref.js +6 -0
- package/lib/fs/file.d.ts +78 -5
- package/lib/fs/file.js +39 -3
- package/lib/fs/folder.d.ts +37 -5
- package/lib/fs/folder.js +28 -3
- package/lib/fs/index.d.ts +6 -0
- package/lib/fs/index.js +6 -0
- package/lib/fs/json-file.d.ts +16 -0
- package/lib/fs/json-file.js +7 -0
- package/lib/fs/text-file.d.ts +12 -0
- package/lib/fs/text-file.js +7 -0
- package/lib/fs/typescript-file.d.ts +19 -0
- package/lib/fs/typescript-file.js +14 -0
- package/lib/fs/yaml-file.d.ts +19 -0
- package/lib/fs/yaml-file.js +8 -0
- package/lib/github/secret.d.ts +63 -2
- package/lib/github/secret.js +61 -1
- package/lib/internal/docs.d.ts +5 -0
- package/lib/internal/docs.js +324 -0
- package/lib/resource.d.ts +2 -2
- package/lib/resource.js +4 -0
- package/lib/scope.d.ts +1 -1
- package/lib/scope.js +6 -6
- package/lib/secret.d.ts +67 -0
- package/lib/secret.js +67 -0
- package/lib/shadcn/component.d.ts +1 -1
- package/lib/state.d.ts +1 -1
- package/lib/state.js +8 -1
- package/lib/stripe/price.d.ts +51 -1
- package/lib/stripe/price.js +50 -0
- package/lib/stripe/product.d.ts +39 -1
- package/lib/stripe/product.js +38 -0
- package/lib/stripe/webhook.d.ts +46 -1
- package/lib/stripe/webhook.js +45 -0
- package/lib/test/bun.d.ts +64 -0
- package/lib/test/bun.js +35 -3
- package/lib/util/serde.d.ts +3 -1
- package/lib/util/serde.js +20 -4
- package/lib/vite/vite.d.ts +1 -1
- package/lib/vitepress/dependencies.d.ts +12 -0
- package/lib/vitepress/dependencies.js +35 -0
- package/lib/vitepress/home-page.d.ts +133 -0
- package/lib/vitepress/home-page.js +11 -0
- package/lib/vitepress/index.d.ts +2 -0
- package/lib/vitepress/index.js +2 -0
- package/lib/vitepress/vitepress.d.ts +71 -0
- package/lib/vitepress/vitepress.js +266 -0
- package/package.json +22 -10
- package/src/ai/ark.ts +118 -0
- package/src/ai/client.ts +78 -0
- package/src/ai/document.ts +160 -0
- package/src/ai/index.ts +2 -0
- package/src/ai/object.ts +149 -0
- package/src/alchemy.ts +192 -17
- package/src/apply.ts +25 -13
- package/src/aws/bucket.ts +111 -7
- package/src/aws/function.ts +231 -10
- package/src/aws/oidc/github-oidc-provider.ts +83 -0
- package/src/aws/oidc/oidc-provider.ts +39 -7
- package/src/aws/policy-attachment.ts +44 -1
- package/src/aws/policy.ts +177 -2
- package/src/aws/queue.ts +89 -0
- package/src/aws/role.ts +174 -2
- package/src/aws/ses.ts +56 -1
- package/src/aws/table.ts +103 -0
- package/src/cloudflare/bucket.ts +36 -0
- package/src/cloudflare/durable-object-namespace.ts +25 -0
- package/src/cloudflare/kv-namespace.ts +36 -0
- package/src/cloudflare/static-site.ts +53 -1
- package/src/cloudflare/worker.ts +63 -0
- package/src/cloudflare/zone.ts +55 -0
- package/src/context.ts +30 -10
- package/src/destroy.ts +11 -8
- package/src/esbuild/bundle.ts +53 -3
- package/src/fs/file-collection.ts +24 -0
- package/src/fs/file-ref.ts +22 -0
- package/src/fs/file.ts +107 -6
- package/src/fs/folder.ts +45 -5
- package/src/fs/index.ts +6 -0
- package/src/fs/json-file.ts +23 -0
- package/src/fs/text-file.ts +19 -0
- package/src/fs/typescript-file.ts +36 -0
- package/src/fs/yaml-file.ts +26 -0
- package/src/github/secret.ts +65 -2
- package/src/internal/docs.ts +369 -0
- package/src/resource.ts +7 -2
- package/src/scope.ts +9 -9
- package/src/secret.ts +67 -0
- package/src/state.ts +9 -2
- package/src/stripe/price.ts +50 -0
- package/src/stripe/product.ts +38 -0
- package/src/stripe/webhook.ts +45 -0
- package/src/test/bun.ts +83 -3
- package/src/util/serde.ts +30 -4
- package/src/vitepress/dependencies.ts +68 -0
- package/src/vitepress/home-page.ts +166 -0
- package/src/vitepress/index.md +75 -0
- package/src/vitepress/index.ts +2 -0
- package/src/vitepress/vitepress.ts +382 -0
- package/lib/project/vite.d.ts +0 -90
- package/lib/project/vite.js +0 -228
- package/src/project/vite.ts +0 -406
package/lib/alchemy.js
CHANGED
|
@@ -1,24 +1,108 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import { DestroyedSignal, destroy } from "./destroy";
|
|
2
4
|
import { Scope } from "./scope";
|
|
3
5
|
import { secret } from "./secret";
|
|
4
6
|
// TODO: support browser
|
|
5
7
|
const DEFAULT_STAGE = process.env.ALCHEMY_STAGE ?? process.env.USER ?? "dev";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
export const alchemy = _alchemy;
|
|
9
|
+
/**
|
|
10
|
+
* Implementation of the alchemy function that handles both application scoping
|
|
11
|
+
* and template string interpolation.
|
|
12
|
+
*/
|
|
13
|
+
function _alchemy(...args) {
|
|
14
|
+
if (typeof args[0] === "string") {
|
|
15
|
+
const [appName, options] = args;
|
|
16
|
+
return scope(undefined, {
|
|
17
|
+
...options,
|
|
18
|
+
appName,
|
|
19
|
+
stage: options?.stage,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const [template, ...values] = args;
|
|
24
|
+
const [, secondLine] = template[0].split("\n");
|
|
25
|
+
const leadingSpaces = secondLine
|
|
26
|
+
? secondLine.match(/^(\s*)/)?.[1]?.length || 0
|
|
27
|
+
: 0;
|
|
28
|
+
const indent = " ".repeat(leadingSpaces);
|
|
29
|
+
return (async () => {
|
|
30
|
+
const { isFileCollection, isFileRef } = await import("./fs");
|
|
31
|
+
const appendices = {};
|
|
32
|
+
const stringValues = await Promise.all(values.map(async function resolve(value) {
|
|
33
|
+
if (typeof value === "string") {
|
|
34
|
+
return indent + value;
|
|
35
|
+
}
|
|
36
|
+
else if (value instanceof Promise) {
|
|
37
|
+
return resolve(await value);
|
|
38
|
+
}
|
|
39
|
+
else if (isFileRef(value)) {
|
|
40
|
+
if (!(value.path in appendices)) {
|
|
41
|
+
appendices[value.path] = await fs.readFile(value.path, "utf-8");
|
|
42
|
+
}
|
|
43
|
+
return `[${path.basename(value.path)}](${value.path})`;
|
|
44
|
+
}
|
|
45
|
+
else if (isFileCollection(value)) {
|
|
46
|
+
return Object.entries(value.files)
|
|
47
|
+
.map(([filePath, content]) => {
|
|
48
|
+
appendices[filePath] = content;
|
|
49
|
+
return `[${path.basename(filePath)}](${filePath})`;
|
|
50
|
+
})
|
|
51
|
+
.join("\n\n");
|
|
52
|
+
}
|
|
53
|
+
else if (Array.isArray(value)) {
|
|
54
|
+
return (await Promise.all(value.map(async (value, i) => `${i}. ${await resolve(value)}`))).join("\n");
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// TODO: support other types
|
|
58
|
+
throw new Error(`Unsupported value type: ${JSON.stringify(value)}`);
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
61
|
+
// Construct the string template by joining template parts with interpolated values
|
|
62
|
+
const lines = template
|
|
63
|
+
.map((part) => part
|
|
64
|
+
.split("\n")
|
|
65
|
+
.map((line) => line.startsWith(indent) ? line.slice(indent.length) : line)
|
|
66
|
+
.join("\n"))
|
|
67
|
+
.flatMap((part, i) => i < stringValues.length ? [part, stringValues[i] ?? ""] : [part])
|
|
68
|
+
.join("")
|
|
69
|
+
.split("\n");
|
|
70
|
+
// Collect and sort appendices by file path
|
|
71
|
+
return [
|
|
72
|
+
// format the user prompt and trim the first line if it's empty
|
|
73
|
+
lines.length > 1 && lines[0].replaceAll(" ", "").length === 0
|
|
74
|
+
? lines.slice(1).join("\n")
|
|
75
|
+
: lines.join("\n"),
|
|
76
|
+
// sort appendices by path and include at the end of the prompt
|
|
77
|
+
Object.entries(appendices)
|
|
78
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
79
|
+
.map(([filePath, content]) => {
|
|
80
|
+
const extension = path.extname(filePath).slice(1);
|
|
81
|
+
const codeTag = extension ? extension : "";
|
|
82
|
+
return `// ${filePath}\n\`\`\`${codeTag}\n${content}\n\`\`\``;
|
|
83
|
+
})
|
|
84
|
+
.join("\n\n"),
|
|
85
|
+
].join("\n");
|
|
86
|
+
})();
|
|
87
|
+
}
|
|
12
88
|
}
|
|
13
89
|
_alchemy.destroy = destroy;
|
|
14
90
|
_alchemy.run = run;
|
|
15
91
|
_alchemy.scope = scope;
|
|
16
92
|
_alchemy.secret = secret;
|
|
17
|
-
export const alchemy = _alchemy;
|
|
18
93
|
/**
|
|
19
94
|
* Enter a new scope synchronously.
|
|
20
|
-
*
|
|
21
|
-
* @
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* // Create a scope with a password for secret handling
|
|
98
|
+
* await using scope = alchemy.scope("my-scope", {
|
|
99
|
+
* password: process.env.SECRET_PASSPHRASE
|
|
100
|
+
* });
|
|
101
|
+
*
|
|
102
|
+
* // Use secrets within the scope
|
|
103
|
+
* const resource = await Resource("my-resource", {
|
|
104
|
+
* apiKey: alchemy.secret(process.env.API_KEY)
|
|
105
|
+
* });
|
|
22
106
|
*/
|
|
23
107
|
function scope(id, options) {
|
|
24
108
|
const scope = new Scope({
|
|
@@ -31,11 +115,26 @@ function scope(id, options) {
|
|
|
31
115
|
scope.enter();
|
|
32
116
|
return scope;
|
|
33
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Run a function in a new scope asynchronously.
|
|
120
|
+
* Useful for isolating secret handling with a specific password.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* // Run operations in a scope with its own password
|
|
124
|
+
* await alchemy.run("secure-scope", {
|
|
125
|
+
* password: process.env.SCOPE_PASSWORD
|
|
126
|
+
* }, async () => {
|
|
127
|
+
* // Secrets in this scope will use this password
|
|
128
|
+
* const resource = await Resource("my-resource", {
|
|
129
|
+
* apiKey: alchemy.secret(process.env.API_KEY)
|
|
130
|
+
* });
|
|
131
|
+
* });
|
|
132
|
+
*/
|
|
34
133
|
async function run(...args) {
|
|
35
134
|
const [id, options, fn] = typeof args[1] === "function"
|
|
36
135
|
? [args[0], undefined, args[1]]
|
|
37
136
|
: args;
|
|
38
|
-
|
|
137
|
+
const scope = alchemy.scope(id, options);
|
|
39
138
|
try {
|
|
40
139
|
return await fn.bind(scope)(scope);
|
|
41
140
|
}
|
|
@@ -43,6 +142,11 @@ async function run(...args) {
|
|
|
43
142
|
if (!(error instanceof DestroyedSignal)) {
|
|
44
143
|
scope.fail();
|
|
45
144
|
}
|
|
145
|
+
else {
|
|
146
|
+
}
|
|
46
147
|
throw error;
|
|
47
148
|
}
|
|
149
|
+
finally {
|
|
150
|
+
await scope.finalize();
|
|
151
|
+
}
|
|
48
152
|
}
|
package/lib/apply.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export interface ApplyOptions {
|
|
|
3
3
|
quiet?: boolean;
|
|
4
4
|
alwaysUpdate?: boolean;
|
|
5
5
|
}
|
|
6
|
-
export declare function apply<Out extends Resource>(resource: PendingResource<Out>, props: ResourceProps, options?: ApplyOptions): Promise<Awaited<Out>>;
|
|
6
|
+
export declare function apply<Out extends Resource>(resource: PendingResource<Out>, props: ResourceProps | undefined, options?: ApplyOptions): Promise<Awaited<Out>>;
|
package/lib/apply.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { alchemy } from "./alchemy";
|
|
2
2
|
import { context } from "./context";
|
|
3
3
|
import { PROVIDERS, } from "./resource";
|
|
4
|
+
import { Secret } from "./secret";
|
|
4
5
|
import { serialize } from "./util/serde";
|
|
5
6
|
export async function apply(resource, props, options) {
|
|
6
7
|
const scope = resource.Scope;
|
|
7
8
|
try {
|
|
8
|
-
const quiet = props
|
|
9
|
+
const quiet = props?.quiet ?? scope.quiet;
|
|
9
10
|
await scope.init();
|
|
10
11
|
let state = (await scope.state.get(resource.ID));
|
|
11
12
|
const provider = PROVIDERS.get(resource.Kind);
|
|
@@ -35,15 +36,18 @@ export async function apply(resource, props, options) {
|
|
|
35
36
|
const alwaysUpdate = options?.alwaysUpdate ?? provider.options?.alwaysUpdate ?? false;
|
|
36
37
|
// Skip update if inputs haven't changed and resource is in a stable state
|
|
37
38
|
if (state.status === "created" || state.status === "updated") {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
const oldProps = JSON.stringify(state.props, (_, value) => value instanceof Secret
|
|
40
|
+
? {
|
|
41
|
+
"@secret": value.unencrypted,
|
|
42
|
+
}
|
|
43
|
+
: value, 2);
|
|
44
|
+
const newProps = JSON.stringify(await serialize(scope, props, {
|
|
45
|
+
encrypt: false,
|
|
46
|
+
}), null, 2);
|
|
47
|
+
if (oldProps === newProps && alwaysUpdate !== true) {
|
|
41
48
|
if (!quiet) {
|
|
42
49
|
console.log(`Skip: "${resource.FQN}" (no changes)`);
|
|
43
50
|
}
|
|
44
|
-
// if (resourceState.output !== undefined) {
|
|
45
|
-
// resource[Provide](resourceState.output);
|
|
46
|
-
// }
|
|
47
51
|
return state.output;
|
|
48
52
|
}
|
|
49
53
|
}
|
|
@@ -63,6 +67,7 @@ export async function apply(resource, props, options) {
|
|
|
63
67
|
id: resource.ID,
|
|
64
68
|
fqn: resource.FQN,
|
|
65
69
|
seq: resource.Seq,
|
|
70
|
+
props: state.oldProps,
|
|
66
71
|
state,
|
|
67
72
|
replace: () => {
|
|
68
73
|
if (isReplaced) {
|
|
@@ -72,9 +77,7 @@ export async function apply(resource, props, options) {
|
|
|
72
77
|
isReplaced = true;
|
|
73
78
|
},
|
|
74
79
|
});
|
|
75
|
-
const output = await alchemy.run(resource.ID, async () =>
|
|
76
|
-
return provider.handler.bind(ctx)(resource.ID, props);
|
|
77
|
-
});
|
|
80
|
+
const output = await alchemy.run(resource.ID, async () => provider.handler.bind(ctx)(resource.ID, props));
|
|
78
81
|
if (!quiet) {
|
|
79
82
|
console.log(`${phase === "create" ? "Created" : "Updated"}: "${resource.FQN}"`);
|
|
80
83
|
}
|
package/lib/aws/bucket.d.ts
CHANGED
|
@@ -1,18 +1,104 @@
|
|
|
1
1
|
import type { Context } from "../context";
|
|
2
2
|
import { Resource } from "../resource";
|
|
3
|
+
/**
|
|
4
|
+
* Properties for creating or updating an S3 bucket
|
|
5
|
+
*/
|
|
3
6
|
export interface BucketProps {
|
|
7
|
+
/**
|
|
8
|
+
* The name of the bucket. Must be globally unique across all AWS accounts.
|
|
9
|
+
* Should be lowercase alphanumeric characters or hyphens.
|
|
10
|
+
*/
|
|
4
11
|
bucketName: string;
|
|
12
|
+
/**
|
|
13
|
+
* Optional tags to apply to the bucket for organization and cost tracking.
|
|
14
|
+
* Each tag is a key-value pair.
|
|
15
|
+
*/
|
|
5
16
|
tags?: Record<string, string>;
|
|
6
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Output returned after S3 bucket creation/update
|
|
20
|
+
*/
|
|
7
21
|
export interface Bucket extends Resource<"s3::Bucket">, BucketProps {
|
|
22
|
+
/**
|
|
23
|
+
* The ARN (Amazon Resource Name) of the bucket
|
|
24
|
+
* Format: arn:aws:s3:::bucket-name
|
|
25
|
+
*/
|
|
8
26
|
arn: string;
|
|
27
|
+
/**
|
|
28
|
+
* The global domain name for the bucket
|
|
29
|
+
* Format: bucket-name.s3.amazonaws.com
|
|
30
|
+
*/
|
|
9
31
|
bucketDomainName: string;
|
|
32
|
+
/**
|
|
33
|
+
* The regional domain name for the bucket
|
|
34
|
+
* Format: bucket-name.s3.region.amazonaws.com
|
|
35
|
+
*/
|
|
10
36
|
bucketRegionalDomainName?: string;
|
|
37
|
+
/**
|
|
38
|
+
* The S3 hosted zone ID for the region where the bucket resides
|
|
39
|
+
* Used for DNS configuration with Route 53
|
|
40
|
+
*/
|
|
11
41
|
hostedZoneId?: string;
|
|
42
|
+
/**
|
|
43
|
+
* The AWS region where the bucket is located
|
|
44
|
+
*/
|
|
12
45
|
region?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The website endpoint URL if static website hosting is enabled
|
|
48
|
+
* Format: http://bucket-name.s3-website-region.amazonaws.com
|
|
49
|
+
*/
|
|
13
50
|
websiteEndpoint?: string;
|
|
51
|
+
/**
|
|
52
|
+
* The website domain if static website hosting is enabled
|
|
53
|
+
* Format: bucket-name.s3-website-region.amazonaws.com
|
|
54
|
+
*/
|
|
14
55
|
websiteDomain?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Whether versioning is enabled for the bucket
|
|
58
|
+
*/
|
|
15
59
|
versioningEnabled?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* The canned ACL applied to the bucket
|
|
62
|
+
* Common values: private, public-read, public-read-write, authenticated-read
|
|
63
|
+
*/
|
|
16
64
|
acl?: string;
|
|
17
65
|
}
|
|
18
|
-
|
|
66
|
+
/**
|
|
67
|
+
* AWS S3 Bucket Resource
|
|
68
|
+
*
|
|
69
|
+
* Creates and manages Amazon S3 buckets with support for versioning, tags, and regional configuration.
|
|
70
|
+
* S3 buckets provide scalable object storage for any type of data, with features like versioning,
|
|
71
|
+
* lifecycle policies, and fine-grained access control.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* // Create a basic S3 bucket with default settings
|
|
75
|
+
* const basicBucket = await Bucket("my-app-storage", {
|
|
76
|
+
* bucketName: "my-app-storage",
|
|
77
|
+
* tags: {
|
|
78
|
+
* Environment: "production",
|
|
79
|
+
* Project: "my-app"
|
|
80
|
+
* }
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* // Create a bucket with versioning enabled and specific tags
|
|
85
|
+
* const versionedBucket = await Bucket("document-archive", {
|
|
86
|
+
* bucketName: "document-archive",
|
|
87
|
+
* tags: {
|
|
88
|
+
* Environment: "production",
|
|
89
|
+
* Purpose: "document-storage",
|
|
90
|
+
* Versioning: "enabled"
|
|
91
|
+
* }
|
|
92
|
+
* });
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* // Create a development bucket with minimal configuration
|
|
96
|
+
* const devBucket = await Bucket("dev-testing", {
|
|
97
|
+
* bucketName: "dev-testing",
|
|
98
|
+
* tags: {
|
|
99
|
+
* Environment: "development",
|
|
100
|
+
* Temporary: "true"
|
|
101
|
+
* }
|
|
102
|
+
* });
|
|
103
|
+
*/
|
|
104
|
+
export declare const Bucket: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<Bucket>, id: string, props: BucketProps) => Promise<Bucket>);
|
package/lib/aws/bucket.js
CHANGED
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
import { CreateBucketCommand, DeleteBucketCommand, GetBucketAclCommand, GetBucketLocationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, HeadBucketCommand, NoSuchBucket, PutBucketTaggingCommand, S3Client, } from "@aws-sdk/client-s3";
|
|
2
2
|
import { Resource } from "../resource";
|
|
3
3
|
import { ignore } from "../util/ignore";
|
|
4
|
+
/**
|
|
5
|
+
* AWS S3 Bucket Resource
|
|
6
|
+
*
|
|
7
|
+
* Creates and manages Amazon S3 buckets with support for versioning, tags, and regional configuration.
|
|
8
|
+
* S3 buckets provide scalable object storage for any type of data, with features like versioning,
|
|
9
|
+
* lifecycle policies, and fine-grained access control.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Create a basic S3 bucket with default settings
|
|
13
|
+
* const basicBucket = await Bucket("my-app-storage", {
|
|
14
|
+
* bucketName: "my-app-storage",
|
|
15
|
+
* tags: {
|
|
16
|
+
* Environment: "production",
|
|
17
|
+
* Project: "my-app"
|
|
18
|
+
* }
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Create a bucket with versioning enabled and specific tags
|
|
23
|
+
* const versionedBucket = await Bucket("document-archive", {
|
|
24
|
+
* bucketName: "document-archive",
|
|
25
|
+
* tags: {
|
|
26
|
+
* Environment: "production",
|
|
27
|
+
* Purpose: "document-storage",
|
|
28
|
+
* Versioning: "enabled"
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Create a development bucket with minimal configuration
|
|
34
|
+
* const devBucket = await Bucket("dev-testing", {
|
|
35
|
+
* bucketName: "dev-testing",
|
|
36
|
+
* tags: {
|
|
37
|
+
* Environment: "development",
|
|
38
|
+
* Temporary: "true"
|
|
39
|
+
* }
|
|
40
|
+
* });
|
|
41
|
+
*/
|
|
4
42
|
export const Bucket = Resource("s3::Bucket", async function (id, props) {
|
|
5
43
|
const client = new S3Client({});
|
|
6
44
|
if (this.phase === "delete") {
|
|
@@ -81,7 +119,16 @@ export const Bucket = Resource("s3::Bucket", async function (id, props) {
|
|
|
81
119
|
});
|
|
82
120
|
}
|
|
83
121
|
});
|
|
84
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Helper function to get S3 hosted zone IDs by region
|
|
124
|
+
*
|
|
125
|
+
* Returns the S3 hosted zone ID for a given AWS region. These IDs are used when
|
|
126
|
+
* configuring Route 53 DNS records that point to S3 buckets. If the region is not
|
|
127
|
+
* found in the mapping, defaults to the us-east-1 hosted zone ID.
|
|
128
|
+
*
|
|
129
|
+
* @param region - The AWS region code (e.g., us-east-1, eu-west-1)
|
|
130
|
+
* @returns The S3 hosted zone ID for the region
|
|
131
|
+
*/
|
|
85
132
|
function getHostedZoneId(region) {
|
|
86
133
|
const hostedZoneIds = {
|
|
87
134
|
"us-east-1": "Z3AQBSTGFYJSTF",
|
package/lib/aws/function.d.ts
CHANGED
|
@@ -1,50 +1,235 @@
|
|
|
1
1
|
import { Architecture, Runtime } from "@aws-sdk/client-lambda";
|
|
2
2
|
import type { Context } from "../context";
|
|
3
3
|
import { Resource } from "../resource";
|
|
4
|
+
/**
|
|
5
|
+
* Properties for creating or updating a Lambda function
|
|
6
|
+
*/
|
|
4
7
|
export interface FunctionProps {
|
|
8
|
+
/**
|
|
9
|
+
* Name of the Lambda function
|
|
10
|
+
*/
|
|
5
11
|
functionName: string;
|
|
12
|
+
/**
|
|
13
|
+
* Path to the zip file containing the function code
|
|
14
|
+
*/
|
|
6
15
|
zipPath: string;
|
|
16
|
+
/**
|
|
17
|
+
* ARN of the IAM role that Lambda assumes when executing the function
|
|
18
|
+
*/
|
|
7
19
|
roleArn: string;
|
|
20
|
+
/**
|
|
21
|
+
* Function handler in the format 'file.function'
|
|
22
|
+
* For Node.js this is typically 'index.handler' or similar
|
|
23
|
+
*/
|
|
8
24
|
handler?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Lambda runtime environment for the function
|
|
27
|
+
* @default nodejs20.x if not specified
|
|
28
|
+
*/
|
|
9
29
|
runtime?: Runtime;
|
|
30
|
+
/**
|
|
31
|
+
* CPU architecture for the function
|
|
32
|
+
* @default x86_64 if not specified
|
|
33
|
+
*/
|
|
10
34
|
architecture?: Architecture;
|
|
35
|
+
/**
|
|
36
|
+
* Description of the function's purpose
|
|
37
|
+
*/
|
|
11
38
|
description?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Maximum execution time in seconds
|
|
41
|
+
* @default 3 seconds if not specified
|
|
42
|
+
*/
|
|
12
43
|
timeout?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Amount of memory available to the function in MB
|
|
46
|
+
* @default 128 MB if not specified
|
|
47
|
+
*/
|
|
13
48
|
memorySize?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Environment variables available to the function code
|
|
51
|
+
*/
|
|
14
52
|
environment?: Record<string, string>;
|
|
53
|
+
/**
|
|
54
|
+
* Resource tags for the function
|
|
55
|
+
*/
|
|
15
56
|
tags?: Record<string, string>;
|
|
57
|
+
/**
|
|
58
|
+
* Function URL configuration for direct HTTP(S) invocation
|
|
59
|
+
*/
|
|
16
60
|
url?: {
|
|
61
|
+
/**
|
|
62
|
+
* Authentication type for the function URL
|
|
63
|
+
*/
|
|
17
64
|
authType?: "AWS_IAM" | "NONE";
|
|
65
|
+
/**
|
|
66
|
+
* CORS configuration for the function URL
|
|
67
|
+
*/
|
|
18
68
|
cors?: {
|
|
69
|
+
/**
|
|
70
|
+
* Whether to allow credentials in CORS requests
|
|
71
|
+
*/
|
|
19
72
|
allowCredentials?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Allowed headers in CORS requests
|
|
75
|
+
*/
|
|
20
76
|
allowHeaders?: string[];
|
|
77
|
+
/**
|
|
78
|
+
* Allowed HTTP methods in CORS requests
|
|
79
|
+
*/
|
|
21
80
|
allowMethods?: string[];
|
|
81
|
+
/**
|
|
82
|
+
* Allowed origins in CORS requests
|
|
83
|
+
*/
|
|
22
84
|
allowOrigins?: string[];
|
|
85
|
+
/**
|
|
86
|
+
* Headers exposed to the browser
|
|
87
|
+
*/
|
|
23
88
|
exposeHeaders?: string[];
|
|
89
|
+
/**
|
|
90
|
+
* CORS preflight cache time in seconds
|
|
91
|
+
*/
|
|
24
92
|
maxAge?: number;
|
|
25
93
|
};
|
|
26
94
|
};
|
|
27
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Output returned after Lambda function creation/update
|
|
98
|
+
*/
|
|
28
99
|
export interface Function extends Resource<"lambda::Function">, FunctionProps {
|
|
100
|
+
/**
|
|
101
|
+
* ARN of the Lambda function
|
|
102
|
+
*/
|
|
29
103
|
arn: string;
|
|
104
|
+
/**
|
|
105
|
+
* Timestamp of the last function modification
|
|
106
|
+
*/
|
|
30
107
|
lastModified: string;
|
|
108
|
+
/**
|
|
109
|
+
* Function version
|
|
110
|
+
*/
|
|
31
111
|
version: string;
|
|
112
|
+
/**
|
|
113
|
+
* ARN with version suffix
|
|
114
|
+
*/
|
|
32
115
|
qualifiedArn: string;
|
|
116
|
+
/**
|
|
117
|
+
* ARN for invoking the function through API Gateway
|
|
118
|
+
*/
|
|
33
119
|
invokeArn: string;
|
|
120
|
+
/**
|
|
121
|
+
* SHA256 hash of the function code
|
|
122
|
+
*/
|
|
34
123
|
sourceCodeHash: string;
|
|
124
|
+
/**
|
|
125
|
+
* Size of the function code in bytes
|
|
126
|
+
*/
|
|
35
127
|
sourceCodeSize: number;
|
|
128
|
+
/**
|
|
129
|
+
* Size of ephemeral storage (/tmp) in MB
|
|
130
|
+
*/
|
|
36
131
|
ephemeralStorageSize?: number;
|
|
132
|
+
/**
|
|
133
|
+
* List of supported CPU architectures
|
|
134
|
+
*/
|
|
37
135
|
architectures: string[];
|
|
136
|
+
/**
|
|
137
|
+
* ARN of the master function (Lambda@Edge only)
|
|
138
|
+
*/
|
|
38
139
|
masterArn?: string;
|
|
140
|
+
/**
|
|
141
|
+
* Unique identifier for the current function code/config
|
|
142
|
+
*/
|
|
39
143
|
revisionId: string;
|
|
144
|
+
/**
|
|
145
|
+
* Current state of the function
|
|
146
|
+
*/
|
|
40
147
|
state?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Reason for the current state
|
|
150
|
+
*/
|
|
41
151
|
stateReason?: string;
|
|
152
|
+
/**
|
|
153
|
+
* Code for the current state reason
|
|
154
|
+
*/
|
|
42
155
|
stateReasonCode?: string;
|
|
156
|
+
/**
|
|
157
|
+
* Status of the last update operation
|
|
158
|
+
*/
|
|
43
159
|
lastUpdateStatus?: string;
|
|
160
|
+
/**
|
|
161
|
+
* Reason for the last update status
|
|
162
|
+
*/
|
|
44
163
|
lastUpdateStatusReason?: string;
|
|
164
|
+
/**
|
|
165
|
+
* Code for the last update status reason
|
|
166
|
+
*/
|
|
45
167
|
lastUpdateStatusReasonCode?: string;
|
|
168
|
+
/**
|
|
169
|
+
* Function package type (Zip or Image)
|
|
170
|
+
*/
|
|
46
171
|
packageType: string;
|
|
172
|
+
/**
|
|
173
|
+
* ARN of the signing profile version
|
|
174
|
+
*/
|
|
47
175
|
signingProfileVersionArn?: string;
|
|
176
|
+
/**
|
|
177
|
+
* ARN of the signing job
|
|
178
|
+
*/
|
|
48
179
|
signingJobArn?: string;
|
|
49
180
|
}
|
|
50
|
-
|
|
181
|
+
/**
|
|
182
|
+
* AWS Lambda Function Resource
|
|
183
|
+
*
|
|
184
|
+
* Creates and manages AWS Lambda functions with support for Node.js runtimes, custom handlers,
|
|
185
|
+
* environment variables, and function URLs. Handles deployment packaging, IAM role
|
|
186
|
+
* stabilization, and function updates.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* // Create a basic Lambda function with minimal configuration
|
|
190
|
+
* const basicFunction = await Function("api-handler", {
|
|
191
|
+
* functionName: "api-handler",
|
|
192
|
+
* zipPath: "./dist/api.zip",
|
|
193
|
+
* roleArn: role.arn,
|
|
194
|
+
* runtime: Runtime.nodejs20x,
|
|
195
|
+
* handler: "index.handler",
|
|
196
|
+
* tags: {
|
|
197
|
+
* Environment: "production"
|
|
198
|
+
* }
|
|
199
|
+
* });
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* // Create a function with environment variables and custom memory/timeout
|
|
203
|
+
* const configuredFunction = await Function("worker", {
|
|
204
|
+
* functionName: "worker",
|
|
205
|
+
* zipPath: "./dist/worker.zip",
|
|
206
|
+
* roleArn: role.arn,
|
|
207
|
+
* runtime: Runtime.nodejs20x,
|
|
208
|
+
* handler: "worker.process",
|
|
209
|
+
* memorySize: 512,
|
|
210
|
+
* timeout: 30,
|
|
211
|
+
* environment: {
|
|
212
|
+
* QUEUE_URL: queue.url,
|
|
213
|
+
* LOG_LEVEL: "info"
|
|
214
|
+
* }
|
|
215
|
+
* });
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* // Create a function with a public URL endpoint and CORS
|
|
219
|
+
* const apiFunction = await Function("public-api", {
|
|
220
|
+
* functionName: "public-api",
|
|
221
|
+
* zipPath: "./dist/api.zip",
|
|
222
|
+
* roleArn: role.arn,
|
|
223
|
+
* handler: "api.handler",
|
|
224
|
+
* url: {
|
|
225
|
+
* authType: "NONE",
|
|
226
|
+
* cors: {
|
|
227
|
+
* allowOrigins: ["*"],
|
|
228
|
+
* allowMethods: ["GET", "POST"],
|
|
229
|
+
* allowHeaders: ["content-type"],
|
|
230
|
+
* maxAge: 86400
|
|
231
|
+
* }
|
|
232
|
+
* }
|
|
233
|
+
* });
|
|
234
|
+
*/
|
|
235
|
+
export declare const Function: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<Function>, id: string, props: FunctionProps) => Promise<Function>);
|