alchemy 0.12.21 → 0.13.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/ai/client.d.ts.map +1 -1
- package/lib/ai/client.js +3 -5
- package/lib/ai/client.js.map +1 -1
- package/lib/alchemy.d.ts +2 -1
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +87 -92
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +6 -0
- package/lib/apply.js.map +1 -1
- package/lib/aws/bucket.d.ts.map +1 -1
- package/lib/aws/bucket.js +55 -57
- package/lib/aws/bucket.js.map +1 -1
- package/lib/aws/function.d.ts.map +1 -1
- package/lib/aws/function.js +250 -252
- package/lib/aws/function.js.map +1 -1
- package/lib/aws/policy-attachment.d.ts.map +1 -1
- package/lib/aws/policy-attachment.js +4 -6
- package/lib/aws/policy-attachment.js.map +1 -1
- package/lib/aws/policy.d.ts.map +1 -1
- package/lib/aws/policy.js +63 -65
- package/lib/aws/policy.js.map +1 -1
- package/lib/aws/queue.js +88 -90
- package/lib/aws/queue.js.map +1 -1
- package/lib/aws/table.d.ts.map +1 -1
- package/lib/aws/table.js +95 -99
- package/lib/aws/table.js.map +1 -1
- package/lib/cloudflare/account-api-token.d.ts +1 -1
- package/lib/cloudflare/account-api-token.d.ts.map +1 -1
- package/lib/cloudflare/account-api-token.js +0 -1
- package/lib/cloudflare/account-api-token.js.map +1 -1
- package/lib/cloudflare/ai-gateway.js.map +1 -1
- package/lib/cloudflare/ai.d.ts +1 -1
- package/lib/cloudflare/ai.d.ts.map +1 -1
- package/lib/cloudflare/ai.js.map +1 -1
- package/lib/cloudflare/api.js +1 -5
- package/lib/cloudflare/api.js.map +1 -1
- package/lib/cloudflare/bucket.d.ts +2 -2
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +22 -24
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/bundle/hybrid-nodejs-compat.d.ts +0 -3
- package/lib/cloudflare/bundle/hybrid-nodejs-compat.d.ts.map +1 -1
- package/lib/cloudflare/bundle/hybrid-nodejs-compat.js +3 -4
- package/lib/cloudflare/bundle/hybrid-nodejs-compat.js.map +1 -1
- package/lib/cloudflare/custom-domain.d.ts.map +1 -1
- package/lib/cloudflare/custom-domain.js +3 -5
- package/lib/cloudflare/custom-domain.js.map +1 -1
- package/lib/cloudflare/d1-database.d.ts +1 -1
- package/lib/cloudflare/d1-database.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.js +70 -72
- package/lib/cloudflare/d1-database.js.map +1 -1
- package/lib/cloudflare/d1-migrations.d.ts +1 -1
- package/lib/cloudflare/d1-migrations.d.ts.map +1 -1
- package/lib/cloudflare/d1-migrations.js +2 -3
- package/lib/cloudflare/d1-migrations.js.map +1 -1
- package/lib/cloudflare/dns-records.d.ts.map +1 -1
- package/lib/cloudflare/dns-records.js +2 -4
- package/lib/cloudflare/dns-records.js.map +1 -1
- package/lib/cloudflare/kv-namespace.d.ts +1 -1
- package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
- package/lib/cloudflare/kv-namespace.js +24 -27
- package/lib/cloudflare/kv-namespace.js.map +1 -1
- package/lib/cloudflare/pipeline.d.ts +1 -1
- package/lib/cloudflare/pipeline.d.ts.map +1 -1
- package/lib/cloudflare/pipeline.js +32 -34
- package/lib/cloudflare/pipeline.js.map +1 -1
- package/lib/cloudflare/queue-consumer.d.ts +1 -1
- package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
- package/lib/cloudflare/queue-consumer.js +31 -33
- package/lib/cloudflare/queue-consumer.js.map +1 -1
- package/lib/cloudflare/queue.d.ts +1 -1
- package/lib/cloudflare/queue.d.ts.map +1 -1
- package/lib/cloudflare/queue.js +36 -38
- package/lib/cloudflare/queue.js.map +1 -1
- package/lib/cloudflare/r2-rest-state-store.js +4 -8
- package/lib/cloudflare/r2-rest-state-store.js.map +1 -1
- package/lib/cloudflare/types.d.ts.map +1 -1
- package/lib/cloudflare/types.js +1 -3
- package/lib/cloudflare/types.js.map +1 -1
- package/lib/cloudflare/vectorize-index.d.ts.map +1 -1
- package/lib/cloudflare/vectorize-index.js +37 -39
- package/lib/cloudflare/vectorize-index.js.map +1 -1
- package/lib/cloudflare/vectorize-metadata-index.d.ts +1 -1
- package/lib/cloudflare/vectorize-metadata-index.d.ts.map +1 -1
- package/lib/cloudflare/vectorize-metadata-index.js +10 -13
- package/lib/cloudflare/vectorize-metadata-index.js.map +1 -1
- package/lib/cloudflare/worker.js +6 -12
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/workflow.d.ts +1 -1
- package/lib/cloudflare/workflow.d.ts.map +1 -1
- package/lib/cloudflare/workflow.js.map +1 -1
- package/lib/cloudflare/zone.d.ts.map +1 -1
- package/lib/cloudflare/zone.js +48 -50
- package/lib/cloudflare/zone.js.map +1 -1
- package/lib/dns/godaddy.js +1 -1
- package/lib/dns/import-dns.js +1 -1
- package/lib/dns/import-dns.js.map +1 -1
- package/lib/env.js +7 -9
- package/lib/env.js.map +1 -1
- package/lib/esbuild/bundle.js +8 -10
- package/lib/esbuild/bundle.js.map +1 -1
- package/lib/fs/copy-file.d.ts.map +1 -1
- package/lib/fs/copy-file.js +27 -29
- package/lib/fs/copy-file.js.map +1 -1
- package/lib/fs/file.d.ts +1 -1
- package/lib/fs/file.d.ts.map +1 -1
- package/lib/fs/file.js +1 -1
- package/lib/fs/file.js.map +1 -1
- package/lib/fs/folder.d.ts.map +1 -1
- package/lib/fs/folder.js +1 -3
- package/lib/fs/folder.js.map +1 -1
- package/lib/github/client.d.ts.map +1 -1
- package/lib/github/client.js +3 -5
- package/lib/github/client.js.map +1 -1
- package/lib/github/repository-environment.d.ts.map +1 -1
- package/lib/github/repository-environment.js +173 -176
- package/lib/github/repository-environment.js.map +1 -1
- package/lib/github/secret.d.ts.map +1 -1
- package/lib/github/secret.js +97 -99
- package/lib/github/secret.js.map +1 -1
- package/lib/internal/docs/providers.d.ts.map +1 -1
- package/lib/internal/docs/providers.js +5 -7
- package/lib/internal/docs/providers.js.map +1 -1
- package/lib/neon/api.js +1 -2
- package/lib/neon/api.js.map +1 -1
- package/lib/neon/project.js +2 -2
- package/lib/neon/project.js.map +1 -1
- package/lib/os/exec.d.ts +5 -0
- package/lib/os/exec.d.ts.map +1 -1
- package/lib/os/exec.js +88 -56
- package/lib/os/exec.js.map +1 -1
- package/lib/scope.d.ts +3 -0
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +10 -3
- package/lib/scope.js.map +1 -1
- package/lib/secret.d.ts.map +1 -1
- package/lib/secret.js +1 -3
- package/lib/secret.js.map +1 -1
- package/lib/serde.d.ts.map +1 -1
- package/lib/serde.js +13 -15
- package/lib/serde.js.map +1 -1
- package/lib/stripe/price.d.ts.map +1 -1
- package/lib/stripe/price.js +69 -73
- package/lib/stripe/price.js.map +1 -1
- package/lib/stripe/product.d.ts.map +1 -1
- package/lib/stripe/product.js +50 -52
- package/lib/stripe/product.js.map +1 -1
- package/lib/stripe/webhook.d.ts.map +1 -1
- package/lib/stripe/webhook.js +51 -53
- package/lib/stripe/webhook.js.map +1 -1
- package/lib/test/bun.d.ts +1 -1
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js +1 -0
- package/lib/test/bun.js.map +1 -1
- package/lib/test/prune.d.ts.map +1 -1
- package/lib/test/prune.js.map +1 -1
- package/lib/util/dedent.js +4 -4
- package/lib/util/dedent.js.map +1 -1
- package/lib/web/astro.js +1 -1
- package/lib/web/shadcn.js +4 -4
- package/lib/web/shadcn.js.map +1 -1
- package/lib/web/tailwind.d.ts.map +1 -1
- package/lib/web/tailwind.js +0 -1
- package/lib/web/tailwind.js.map +1 -1
- package/lib/web/vite.js +3 -3
- package/lib/web/vitepress/home-page.d.ts.map +1 -1
- package/lib/web/vitepress/home-page.js +6 -8
- package/lib/web/vitepress/home-page.js.map +1 -1
- package/lib/web/vitepress/process-front-matter-files.js +1 -1
- package/lib/web/vitepress/process-front-matter-files.js.map +1 -1
- package/lib/web/vitepress/vitepress.js +2 -2
- package/lib/web/vitepress/vitepress.js.map +1 -1
- package/package.json +1 -1
- package/src/ai/astro-file.ts +4 -4
- package/src/ai/client.ts +4 -5
- package/src/ai/css-file.ts +4 -4
- package/src/ai/document.ts +3 -3
- package/src/ai/html-file.ts +4 -4
- package/src/ai/json-file.ts +1 -1
- package/src/ai/typescript-file.ts +4 -4
- package/src/ai/vue-file.ts +4 -4
- package/src/ai/yaml-file.ts +1 -1
- package/src/alchemy.ts +111 -104
- package/src/apply.ts +13 -5
- package/src/aws/bucket.ts +72 -75
- package/src/aws/function.ts +296 -297
- package/src/aws/oidc/github-oidc-provider.ts +1 -1
- package/src/aws/oidc/oidc-provider.ts +15 -15
- package/src/aws/policy-attachment.ts +10 -11
- package/src/aws/policy.ts +91 -94
- package/src/aws/queue.ts +111 -111
- package/src/aws/role.ts +24 -24
- package/src/aws/ses.ts +17 -17
- package/src/aws/table.ts +114 -115
- package/src/cloudflare/account-api-token.ts +11 -11
- package/src/cloudflare/account-id.ts +1 -1
- package/src/cloudflare/ai-gateway.ts +4 -4
- package/src/cloudflare/ai.ts +1 -1
- package/src/cloudflare/api-error.ts +1 -1
- package/src/cloudflare/api.ts +7 -11
- package/src/cloudflare/assets.ts +4 -4
- package/src/cloudflare/auth.ts +13 -13
- package/src/cloudflare/bucket.ts +62 -63
- package/src/cloudflare/bundle/hybrid-nodejs-compat.ts +13 -14
- package/src/cloudflare/custom-domain.ts +27 -28
- package/src/cloudflare/d1-database.ts +101 -102
- package/src/cloudflare/d1-migrations.ts +10 -10
- package/src/cloudflare/dns-records.ts +23 -24
- package/src/cloudflare/durable-object-namespace.ts +1 -1
- package/src/cloudflare/event-source.ts +1 -1
- package/src/cloudflare/hyperdrive.ts +3 -3
- package/src/cloudflare/kv-namespace.ts +36 -37
- package/src/cloudflare/nuxt.ts +1 -1
- package/src/cloudflare/permission-groups.ts +7 -7
- package/src/cloudflare/pipeline.ts +55 -56
- package/src/cloudflare/queue-consumer.ts +53 -54
- package/src/cloudflare/queue.ts +56 -57
- package/src/cloudflare/r2-rest-state-store.ts +11 -11
- package/src/cloudflare/redwood.ts +1 -1
- package/src/cloudflare/tanstack-start.ts +1 -1
- package/src/cloudflare/types.ts +1 -2
- package/src/cloudflare/vectorize-index.ts +60 -61
- package/src/cloudflare/vectorize-metadata-index.ts +25 -25
- package/src/cloudflare/vite.ts +1 -1
- package/src/cloudflare/website.ts +3 -3
- package/src/cloudflare/worker.ts +61 -61
- package/src/cloudflare/workflow.ts +4 -4
- package/src/cloudflare/wrangler.json.ts +4 -4
- package/src/cloudflare/zone.ts +69 -70
- package/src/destroy.ts +4 -4
- package/src/dns/godaddy.ts +1 -1
- package/src/dns/import-dns.ts +5 -5
- package/src/encrypt.ts +6 -6
- package/src/env.ts +10 -10
- package/src/esbuild/bundle.ts +14 -14
- package/src/fs/copy-file.ts +35 -36
- package/src/fs/file-system-state-store.ts +4 -4
- package/src/fs/file.ts +9 -8
- package/src/fs/folder.ts +6 -7
- package/src/github/client.ts +15 -14
- package/src/github/repository-environment.ts +206 -210
- package/src/github/secret.ts +111 -116
- package/src/internal/docs/providers.ts +16 -17
- package/src/neon/api-error.ts +1 -1
- package/src/neon/api.ts +6 -6
- package/src/neon/project.ts +18 -17
- package/src/os/exec.ts +107 -66
- package/src/resource.ts +3 -3
- package/src/scope.ts +14 -4
- package/src/secret.ts +2 -3
- package/src/serde.ts +30 -22
- package/src/stripe/price.ts +74 -77
- package/src/stripe/product.ts +55 -56
- package/src/stripe/webhook.ts +56 -57
- package/src/test/bun.ts +7 -6
- package/src/test/prune.ts +4 -4
- package/src/util/dedent.ts +4 -4
- package/src/web/astro.ts +10 -10
- package/src/web/shadcn-component.ts +4 -4
- package/src/web/shadcn.ts +10 -10
- package/src/web/tailwind.ts +2 -3
- package/src/web/vite.ts +11 -11
- package/src/web/vitepress/config.ts +2 -2
- package/src/web/vitepress/custom-theme.ts +7 -7
- package/src/web/vitepress/dependencies.ts +4 -4
- package/src/web/vitepress/home-page.ts +8 -9
- package/src/web/vitepress/process-front-matter-files.ts +5 -5
- package/src/web/vitepress/vitepress.ts +7 -7
package/src/alchemy.ts
CHANGED
|
@@ -98,10 +98,12 @@ async function _alchemy(
|
|
|
98
98
|
): Promise<Scope | string | never> {
|
|
99
99
|
if (typeof args[0] === "string") {
|
|
100
100
|
const [appName, options] = args as [string, AlchemyOptions?];
|
|
101
|
+
const phase = options?.phase ?? "up";
|
|
101
102
|
const root = new Scope({
|
|
102
103
|
...options,
|
|
103
104
|
appName,
|
|
104
105
|
stage: options?.stage,
|
|
106
|
+
phase,
|
|
105
107
|
});
|
|
106
108
|
root.enter();
|
|
107
109
|
if (options?.phase === "destroy") {
|
|
@@ -109,118 +111,123 @@ async function _alchemy(
|
|
|
109
111
|
return process.exit(0);
|
|
110
112
|
}
|
|
111
113
|
return root;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
}
|
|
115
|
+
const [template, ...values] = args;
|
|
116
|
+
const [, secondLine] = template[0].split("\n");
|
|
117
|
+
const leadingSpaces = secondLine
|
|
118
|
+
? secondLine.match(/^(\s*)/)?.[1]?.length || 0
|
|
119
|
+
: 0;
|
|
120
|
+
const indent = " ".repeat(leadingSpaces);
|
|
119
121
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
const [{ isFileRef }, { isFileCollection }] = await Promise.all([
|
|
123
|
+
import("./fs/file-ref.js"),
|
|
124
|
+
import("./fs/file-collection.js"),
|
|
125
|
+
]);
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
const appendices: Record<string, string> = {};
|
|
126
128
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
129
|
+
const stringValues = await Promise.all(
|
|
130
|
+
values.map(async function resolve(value): Promise<string> {
|
|
131
|
+
if (typeof value === "string") {
|
|
132
|
+
return indent + value;
|
|
133
|
+
}
|
|
134
|
+
if (value === null) {
|
|
135
|
+
return "null";
|
|
136
|
+
}
|
|
137
|
+
if (value === undefined) {
|
|
138
|
+
return "undefined";
|
|
139
|
+
}
|
|
140
|
+
if (
|
|
141
|
+
typeof value === "number" ||
|
|
142
|
+
typeof value === "boolean" ||
|
|
143
|
+
typeof value === "bigint"
|
|
144
|
+
) {
|
|
145
|
+
return value.toString();
|
|
146
|
+
}
|
|
147
|
+
if (value instanceof Promise) {
|
|
148
|
+
return resolve(await value);
|
|
149
|
+
}
|
|
150
|
+
if (isFileRef(value)) {
|
|
151
|
+
if (!(value.path in appendices)) {
|
|
152
|
+
appendices[value.path] = await fs.readFile(value.path, "utf-8");
|
|
153
|
+
}
|
|
154
|
+
return `[${path.basename(value.path)}](${value.path})`;
|
|
155
|
+
}
|
|
156
|
+
if (isFileCollection(value)) {
|
|
157
|
+
return Object.entries(value.files)
|
|
158
|
+
.map(([filePath, content]) => {
|
|
159
|
+
appendices[filePath] = content;
|
|
160
|
+
return `[${path.basename(filePath)}](${filePath})`;
|
|
161
|
+
})
|
|
162
|
+
.join("\n\n");
|
|
163
|
+
}
|
|
164
|
+
if (Array.isArray(value)) {
|
|
165
|
+
return (
|
|
166
|
+
await Promise.all(
|
|
167
|
+
value.map(async (value, i) => `${i}. ${await resolve(value)}`),
|
|
168
|
+
)
|
|
169
|
+
).join("\n");
|
|
170
|
+
}
|
|
171
|
+
if (typeof value === "object" && typeof value.path === "string") {
|
|
172
|
+
if (typeof value.content === "string") {
|
|
173
|
+
appendices[value.path] = value.content;
|
|
147
174
|
return `[${path.basename(value.path)}](${value.path})`;
|
|
148
|
-
} else if (isFileCollection(value)) {
|
|
149
|
-
return Object.entries(value.files)
|
|
150
|
-
.map(([filePath, content]) => {
|
|
151
|
-
appendices[filePath] = content;
|
|
152
|
-
return `[${path.basename(filePath)}](${filePath})`;
|
|
153
|
-
})
|
|
154
|
-
.join("\n\n");
|
|
155
|
-
} else if (Array.isArray(value)) {
|
|
156
|
-
return (
|
|
157
|
-
await Promise.all(
|
|
158
|
-
value.map(async (value, i) => `${i}. ${await resolve(value)}`)
|
|
159
|
-
)
|
|
160
|
-
).join("\n");
|
|
161
|
-
} else if (
|
|
162
|
-
typeof value === "object" &&
|
|
163
|
-
typeof value.path === "string"
|
|
164
|
-
) {
|
|
165
|
-
if (typeof value.content === "string") {
|
|
166
|
-
appendices[value.path] = value.content;
|
|
167
|
-
return `[${path.basename(value.path)}](${value.path})`;
|
|
168
|
-
} else {
|
|
169
|
-
appendices[value.path] = await fs.readFile(value.path, "utf-8");
|
|
170
|
-
return `[${path.basename(value.path)}](${value.path})`;
|
|
171
|
-
}
|
|
172
|
-
} else if (typeof value === "object") {
|
|
173
|
-
return (
|
|
174
|
-
await Promise.all(
|
|
175
|
-
Object.entries(value).map(async ([key, value]) => {
|
|
176
|
-
return `* ${key}: ${await resolve(value)}`;
|
|
177
|
-
})
|
|
178
|
-
)
|
|
179
|
-
).join("\n");
|
|
180
|
-
} else {
|
|
181
|
-
// TODO: support other types
|
|
182
|
-
console.log(value);
|
|
183
|
-
throw new Error(`Unsupported value type: ${value}`);
|
|
184
175
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
line.startsWith(indent) ? line.slice(indent.length) : line
|
|
176
|
+
appendices[value.path] = await fs.readFile(value.path, "utf-8");
|
|
177
|
+
return `[${path.basename(value.path)}](${value.path})`;
|
|
178
|
+
}
|
|
179
|
+
if (typeof value === "object") {
|
|
180
|
+
return (
|
|
181
|
+
await Promise.all(
|
|
182
|
+
Object.entries(value).map(async ([key, value]) => {
|
|
183
|
+
return `* ${key}: ${await resolve(value)}`;
|
|
184
|
+
}),
|
|
195
185
|
)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
|
|
186
|
+
).join("\n");
|
|
187
|
+
}
|
|
188
|
+
// TODO: support other types
|
|
189
|
+
console.log(value);
|
|
190
|
+
throw new Error(`Unsupported value type: ${value}`);
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
203
193
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
194
|
+
// Construct the string template by joining template parts with interpolated values
|
|
195
|
+
const lines = template
|
|
196
|
+
.map((part) =>
|
|
197
|
+
part
|
|
198
|
+
.split("\n")
|
|
199
|
+
.map((line) =>
|
|
200
|
+
line.startsWith(indent) ? line.slice(indent.length) : line,
|
|
201
|
+
)
|
|
202
|
+
.join("\n"),
|
|
203
|
+
)
|
|
204
|
+
.flatMap((part, i) =>
|
|
205
|
+
i < stringValues.length ? [part, stringValues[i] ?? ""] : [part],
|
|
206
|
+
)
|
|
207
|
+
.join("")
|
|
208
|
+
.split("\n");
|
|
210
209
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
210
|
+
// Collect and sort appendices by file path
|
|
211
|
+
return [
|
|
212
|
+
// format the user prompt and trim the first line if it's empty
|
|
213
|
+
lines.length > 1 && lines[0].replaceAll(" ", "").length === 0
|
|
214
|
+
? lines.slice(1).join("\n")
|
|
215
|
+
: lines.join("\n"),
|
|
216
|
+
|
|
217
|
+
// sort appendices by path and include at the end of the prompt
|
|
218
|
+
Object.entries(appendices)
|
|
219
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
220
|
+
.map(([filePath, content]) => {
|
|
221
|
+
const extension = path.extname(filePath).slice(1);
|
|
222
|
+
const codeTag = extension ? extension : "";
|
|
223
|
+
return `// ${filePath}\n\`\`\`${codeTag}\n${content}\n\`\`\``;
|
|
224
|
+
})
|
|
225
|
+
.join("\n\n"),
|
|
226
|
+
].join("\n");
|
|
222
227
|
}
|
|
223
228
|
|
|
229
|
+
export type Phase = "up" | "destroy" | "read";
|
|
230
|
+
|
|
224
231
|
export interface AlchemyOptions {
|
|
225
232
|
/**
|
|
226
233
|
* The name of the application.
|
|
@@ -231,7 +238,7 @@ export interface AlchemyOptions {
|
|
|
231
238
|
*
|
|
232
239
|
* @default "up"
|
|
233
240
|
*/
|
|
234
|
-
phase?:
|
|
241
|
+
phase?: Phase;
|
|
235
242
|
/**
|
|
236
243
|
* Name to scope the resource state under (e.g. `.alchemy/{stage}/..`).
|
|
237
244
|
*
|
|
@@ -337,7 +344,7 @@ async function run<T>(
|
|
|
337
344
|
await _scope.parent!.state.set(id, resource);
|
|
338
345
|
_scope.parent!.resources.set(
|
|
339
346
|
id,
|
|
340
|
-
Object.assign(Promise.resolve(resource), output) as PendingResource
|
|
347
|
+
Object.assign(Promise.resolve(resource), output) as PendingResource,
|
|
341
348
|
);
|
|
342
349
|
}
|
|
343
350
|
return await _scope.run(async () => fn.bind(_scope)(_scope));
|
package/src/apply.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface ApplyOptions {
|
|
|
18
18
|
export async function apply<Out extends Resource>(
|
|
19
19
|
resource: PendingResource<Out>,
|
|
20
20
|
props: ResourceProps | undefined,
|
|
21
|
-
options?: ApplyOptions
|
|
21
|
+
options?: ApplyOptions,
|
|
22
22
|
): Promise<Awaited<Out>> {
|
|
23
23
|
const scope = resource.Scope;
|
|
24
24
|
try {
|
|
@@ -29,6 +29,14 @@ export async function apply<Out extends Resource>(
|
|
|
29
29
|
if (provider === undefined) {
|
|
30
30
|
throw new Error(`Provider "${resource.Kind}" not found`);
|
|
31
31
|
}
|
|
32
|
+
if (scope.phase === "read") {
|
|
33
|
+
if (state === undefined) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Resource "${resource.FQN}" not found and running in 'read' phase.`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return state.output as Awaited<Out>;
|
|
39
|
+
}
|
|
32
40
|
if (state === undefined) {
|
|
33
41
|
state = {
|
|
34
42
|
kind: resource.Kind,
|
|
@@ -79,7 +87,7 @@ export async function apply<Out extends Resource>(
|
|
|
79
87
|
|
|
80
88
|
if (!quiet) {
|
|
81
89
|
console.log(
|
|
82
|
-
`${phase === "create" ? "Create" : "Update"}: "${resource.FQN}"
|
|
90
|
+
`${phase === "create" ? "Create" : "Update"}: "${resource.FQN}"`,
|
|
83
91
|
);
|
|
84
92
|
}
|
|
85
93
|
|
|
@@ -99,7 +107,7 @@ export async function apply<Out extends Resource>(
|
|
|
99
107
|
replace: () => {
|
|
100
108
|
if (isReplaced) {
|
|
101
109
|
console.warn(
|
|
102
|
-
`Resource ${resource.Kind} ${resource.FQN} is already marked as REPLACE
|
|
110
|
+
`Resource ${resource.Kind} ${resource.FQN} is already marked as REPLACE`,
|
|
103
111
|
);
|
|
104
112
|
return;
|
|
105
113
|
}
|
|
@@ -112,11 +120,11 @@ export async function apply<Out extends Resource>(
|
|
|
112
120
|
{
|
|
113
121
|
isResource: true,
|
|
114
122
|
},
|
|
115
|
-
async () => provider.handler.bind(ctx)(resource.ID, props)
|
|
123
|
+
async () => provider.handler.bind(ctx)(resource.ID, props),
|
|
116
124
|
);
|
|
117
125
|
if (!quiet) {
|
|
118
126
|
console.log(
|
|
119
|
-
`${phase === "create" ? "Created" : "Updated"}: "${resource.FQN}"
|
|
127
|
+
`${phase === "create" ? "Created" : "Updated"}: "${resource.FQN}"`,
|
|
120
128
|
);
|
|
121
129
|
}
|
|
122
130
|
|
package/src/aws/bucket.ts
CHANGED
|
@@ -136,99 +136,96 @@ export const Bucket = Resource(
|
|
|
136
136
|
client.send(
|
|
137
137
|
new DeleteBucketCommand({
|
|
138
138
|
Bucket: props.bucketName,
|
|
139
|
-
})
|
|
140
|
-
)
|
|
139
|
+
}),
|
|
140
|
+
),
|
|
141
141
|
);
|
|
142
142
|
return this.destroy();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
// Check if bucket exists
|
|
146
|
+
await client.send(
|
|
147
|
+
new HeadBucketCommand({
|
|
148
|
+
Bucket: props.bucketName,
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Update tags if they changed and bucket exists
|
|
153
|
+
if (this.phase === "update" && props.tags) {
|
|
146
154
|
await client.send(
|
|
147
|
-
new
|
|
155
|
+
new PutBucketTaggingCommand({
|
|
148
156
|
Bucket: props.bucketName,
|
|
149
|
-
|
|
157
|
+
Tagging: {
|
|
158
|
+
TagSet: Object.entries(props.tags).map(([Key, Value]) => ({
|
|
159
|
+
Key,
|
|
160
|
+
Value,
|
|
161
|
+
})),
|
|
162
|
+
},
|
|
163
|
+
}),
|
|
150
164
|
);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
165
|
+
}
|
|
166
|
+
} catch (error: any) {
|
|
167
|
+
if (error.name === "NotFound") {
|
|
168
|
+
// Create bucket if it doesn't exist
|
|
169
|
+
await client.send(
|
|
170
|
+
new CreateBucketCommand({
|
|
171
|
+
Bucket: props.bucketName,
|
|
172
|
+
// Add tags during creation if specified
|
|
173
|
+
...(props.tags && {
|
|
157
174
|
Tagging: {
|
|
158
175
|
TagSet: Object.entries(props.tags).map(([Key, Value]) => ({
|
|
159
176
|
Key,
|
|
160
177
|
Value,
|
|
161
178
|
})),
|
|
162
179
|
},
|
|
163
|
-
})
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Create bucket if it doesn't exist
|
|
169
|
-
await client.send(
|
|
170
|
-
new CreateBucketCommand({
|
|
171
|
-
Bucket: props.bucketName,
|
|
172
|
-
// Add tags during creation if specified
|
|
173
|
-
...(props.tags && {
|
|
174
|
-
Tagging: {
|
|
175
|
-
TagSet: Object.entries(props.tags).map(([Key, Value]) => ({
|
|
176
|
-
Key,
|
|
177
|
-
Value,
|
|
178
|
-
})),
|
|
179
|
-
},
|
|
180
|
-
}),
|
|
181
|
-
})
|
|
182
|
-
);
|
|
183
|
-
} else {
|
|
184
|
-
throw error;
|
|
185
|
-
}
|
|
180
|
+
}),
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
throw error;
|
|
186
185
|
}
|
|
186
|
+
}
|
|
187
187
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
),
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
client.send(new GetBucketAclCommand({ Bucket: props.bucketName })),
|
|
198
|
-
]);
|
|
188
|
+
// Get bucket details
|
|
189
|
+
const [locationResponse, versioningResponse, aclResponse] =
|
|
190
|
+
await Promise.all([
|
|
191
|
+
client.send(new GetBucketLocationCommand({ Bucket: props.bucketName })),
|
|
192
|
+
client.send(
|
|
193
|
+
new GetBucketVersioningCommand({ Bucket: props.bucketName }),
|
|
194
|
+
),
|
|
195
|
+
client.send(new GetBucketAclCommand({ Bucket: props.bucketName })),
|
|
196
|
+
]);
|
|
199
197
|
|
|
200
|
-
|
|
198
|
+
const region = locationResponse.LocationConstraint || "us-east-1";
|
|
201
199
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
200
|
+
// Get tags if they exist
|
|
201
|
+
let tags = props.tags;
|
|
202
|
+
if (!tags) {
|
|
203
|
+
try {
|
|
204
|
+
const taggingResponse = await client.send(
|
|
205
|
+
new GetBucketTaggingCommand({ Bucket: props.bucketName }),
|
|
206
|
+
);
|
|
207
|
+
tags = Object.fromEntries(
|
|
208
|
+
taggingResponse.TagSet?.map(({ Key, Value }) => [Key, Value]) || [],
|
|
209
|
+
);
|
|
210
|
+
} catch (error: any) {
|
|
211
|
+
if (error.name !== "NoSuchTagSet") {
|
|
212
|
+
throw error;
|
|
216
213
|
}
|
|
217
214
|
}
|
|
218
|
-
|
|
219
|
-
return this({
|
|
220
|
-
bucketName: props.bucketName,
|
|
221
|
-
arn: `arn:aws:s3:::${props.bucketName}`,
|
|
222
|
-
bucketDomainName: `${props.bucketName}.s3.amazonaws.com`,
|
|
223
|
-
bucketRegionalDomainName: `${props.bucketName}.s3.${region}.amazonaws.com`,
|
|
224
|
-
region,
|
|
225
|
-
hostedZoneId: getHostedZoneId(region),
|
|
226
|
-
versioningEnabled: versioningResponse.Status === "Enabled",
|
|
227
|
-
acl: aclResponse.Grants?.[0]?.Permission?.toLowerCase(),
|
|
228
|
-
...(tags && { tags }),
|
|
229
|
-
});
|
|
230
215
|
}
|
|
231
|
-
|
|
216
|
+
|
|
217
|
+
return this({
|
|
218
|
+
bucketName: props.bucketName,
|
|
219
|
+
arn: `arn:aws:s3:::${props.bucketName}`,
|
|
220
|
+
bucketDomainName: `${props.bucketName}.s3.amazonaws.com`,
|
|
221
|
+
bucketRegionalDomainName: `${props.bucketName}.s3.${region}.amazonaws.com`,
|
|
222
|
+
region,
|
|
223
|
+
hostedZoneId: getHostedZoneId(region),
|
|
224
|
+
versioningEnabled: versioningResponse.Status === "Enabled",
|
|
225
|
+
acl: aclResponse.Grants?.[0]?.Permission?.toLowerCase(),
|
|
226
|
+
...(tags && { tags }),
|
|
227
|
+
});
|
|
228
|
+
},
|
|
232
229
|
);
|
|
233
230
|
|
|
234
231
|
/**
|