alchemy 0.1.18 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/README.md +506 -0
  2. package/lib/alchemy.d.ts +67 -0
  3. package/lib/alchemy.js +48 -0
  4. package/lib/apply.d.ts +3 -20
  5. package/lib/apply.js +95 -82
  6. package/lib/aws/account-id.d.ts +0 -1
  7. package/lib/aws/account-id.js +0 -1
  8. package/lib/aws/bucket.d.ts +4 -7
  9. package/lib/aws/bucket.js +8 -12
  10. package/lib/aws/function.d.ts +4 -7
  11. package/lib/aws/function.js +9 -30
  12. package/lib/aws/index.d.ts +1 -1
  13. package/lib/aws/index.js +1 -1
  14. package/lib/aws/oidc/github-oidc-provider.d.ts +2 -6
  15. package/lib/aws/oidc/github-oidc-provider.js +10 -15
  16. package/lib/aws/oidc/index.d.ts +0 -1
  17. package/lib/aws/oidc/index.js +0 -1
  18. package/lib/aws/oidc/oidc-provider.d.ts +4 -6
  19. package/lib/aws/oidc/oidc-provider.js +9 -11
  20. package/lib/aws/policy-attachment.d.ts +9 -0
  21. package/lib/aws/policy-attachment.js +20 -0
  22. package/lib/aws/policy.d.ts +4 -16
  23. package/lib/aws/policy.js +9 -40
  24. package/lib/aws/queue.d.ts +4 -34
  25. package/lib/aws/queue.js +10 -20
  26. package/lib/aws/role.d.ts +4 -7
  27. package/lib/aws/role.js +17 -26
  28. package/lib/aws/ses.d.ts +4 -10
  29. package/lib/aws/ses.js +118 -131
  30. package/lib/aws/table.d.ts +4 -7
  31. package/lib/aws/table.js +8 -11
  32. package/lib/cloudflare/api.d.ts +0 -1
  33. package/lib/cloudflare/api.js +0 -1
  34. package/lib/cloudflare/asset-manifest.d.ts +0 -1
  35. package/lib/cloudflare/asset-manifest.js +0 -1
  36. package/lib/cloudflare/auth.d.ts +0 -1
  37. package/lib/cloudflare/auth.js +0 -1
  38. package/lib/cloudflare/bindings.d.ts +1 -1
  39. package/lib/cloudflare/bindings.js +3 -2
  40. package/lib/cloudflare/bound.d.ts +0 -1
  41. package/lib/cloudflare/bound.js +0 -1
  42. package/lib/cloudflare/bucket.d.ts +7 -15
  43. package/lib/cloudflare/bucket.js +12 -19
  44. package/lib/cloudflare/durable-object-namespace.d.ts +0 -3
  45. package/lib/cloudflare/durable-object-namespace.js +0 -4
  46. package/lib/cloudflare/generate-asset-manifest.d.ts +0 -1
  47. package/lib/cloudflare/generate-asset-manifest.js +1 -2
  48. package/lib/cloudflare/index.d.ts +2 -1
  49. package/lib/cloudflare/index.js +2 -1
  50. package/lib/cloudflare/kv-namespace.d.ts +6 -9
  51. package/lib/cloudflare/kv-namespace.js +16 -20
  52. package/lib/cloudflare/state.d.ts +0 -1
  53. package/lib/cloudflare/state.js +0 -1
  54. package/lib/cloudflare/static-site-router.d.ts +0 -1
  55. package/lib/cloudflare/static-site-router.js +0 -4
  56. package/lib/cloudflare/static-site.d.ts +5 -11
  57. package/lib/cloudflare/static-site.js +25 -37
  58. package/lib/cloudflare/types.d.ts +0 -1
  59. package/lib/cloudflare/types.js +0 -1
  60. package/lib/cloudflare/upload-asset-manifest.d.ts +0 -1
  61. package/lib/cloudflare/upload-asset-manifest.js +0 -1
  62. package/lib/cloudflare/worker-metadata.d.ts +0 -1
  63. package/lib/cloudflare/worker-metadata.js +0 -1
  64. package/lib/cloudflare/worker-migration.d.ts +0 -1
  65. package/lib/cloudflare/worker-migration.js +0 -1
  66. package/lib/cloudflare/worker.d.ts +8 -14
  67. package/lib/cloudflare/worker.js +38 -50
  68. package/lib/cloudflare/wrangler.json.d.ts +243 -0
  69. package/lib/cloudflare/wrangler.json.js +35 -0
  70. package/lib/cloudflare/zone-settings.d.ts +301 -0
  71. package/lib/cloudflare/zone-settings.js +1 -0
  72. package/lib/cloudflare/zone.d.ts +196 -0
  73. package/lib/cloudflare/zone.js +175 -0
  74. package/lib/context.d.ts +58 -0
  75. package/lib/context.js +36 -0
  76. package/lib/destroy.d.ts +10 -13
  77. package/lib/destroy.js +104 -43
  78. package/lib/{esbuild.d.ts → esbuild/bundle.d.ts} +4 -18
  79. package/lib/{esbuild.js → esbuild/bundle.js} +10 -24
  80. package/lib/esbuild/index.d.ts +1 -0
  81. package/lib/esbuild/index.js +1 -0
  82. package/lib/fs/file.d.ts +13 -0
  83. package/lib/fs/file.js +20 -0
  84. package/lib/fs/folder.d.ts +10 -0
  85. package/lib/fs/folder.js +16 -0
  86. package/lib/fs/index.d.ts +2 -0
  87. package/lib/fs/index.js +2 -0
  88. package/lib/github/client.d.ts +0 -1
  89. package/lib/github/client.js +0 -1
  90. package/lib/github/index.d.ts +0 -1
  91. package/lib/github/index.js +0 -1
  92. package/lib/github/secret.d.ts +4 -6
  93. package/lib/github/secret.js +10 -12
  94. package/lib/index.d.ts +6 -10
  95. package/lib/index.js +5 -9
  96. package/lib/project/index.d.ts +1 -0
  97. package/lib/project/index.js +1 -0
  98. package/lib/project/vite.d.ts +39 -0
  99. package/lib/project/vite.js +68 -0
  100. package/lib/resource.d.ts +34 -62
  101. package/lib/resource.js +29 -270
  102. package/lib/scope.d.ts +37 -14
  103. package/lib/scope.js +97 -23
  104. package/lib/secret.d.ts +2 -7
  105. package/lib/secret.js +7 -20
  106. package/lib/state.d.ts +14 -10
  107. package/lib/state.js +20 -14
  108. package/lib/stripe/index.d.ts +0 -1
  109. package/lib/stripe/index.js +0 -1
  110. package/lib/stripe/price.d.ts +4 -5
  111. package/lib/stripe/price.js +10 -20
  112. package/lib/stripe/product.d.ts +4 -5
  113. package/lib/stripe/product.js +10 -20
  114. package/lib/stripe/webhook.d.ts +4 -6
  115. package/lib/stripe/webhook.js +12 -25
  116. package/lib/test/bun.d.ts +19 -0
  117. package/lib/test/bun.js +55 -0
  118. package/lib/{utils → util}/content-type.d.ts +0 -1
  119. package/lib/{utils → util}/content-type.js +0 -1
  120. package/lib/{encrypt.d.ts → util/encrypt.d.ts} +0 -1
  121. package/lib/{encrypt.js → util/encrypt.js} +0 -1
  122. package/lib/{error.d.ts → util/ignore.d.ts} +0 -1
  123. package/lib/{error.js → util/ignore.js} +0 -1
  124. package/lib/{utils → util}/retry.d.ts +0 -1
  125. package/lib/{utils → util}/retry.js +0 -1
  126. package/lib/util/rm.d.ts +1 -0
  127. package/lib/util/rm.js +11 -0
  128. package/lib/util/serde.d.ts +3 -0
  129. package/lib/{serde.js → util/serde.js} +19 -10
  130. package/lib/util/slugify.d.ts +1 -0
  131. package/lib/util/slugify.js +3 -0
  132. package/package.json +7 -5
  133. package/src/alchemy.ts +127 -0
  134. package/src/apply.ts +116 -115
  135. package/src/aws/bucket.ts +11 -14
  136. package/src/aws/function.ts +13 -33
  137. package/src/aws/index.ts +1 -0
  138. package/src/aws/oidc/github-oidc-provider.ts +14 -19
  139. package/src/aws/oidc/oidc-provider.ts +19 -12
  140. package/src/aws/policy-attachment.ts +51 -0
  141. package/src/aws/policy.ts +15 -60
  142. package/src/aws/queue.ts +17 -21
  143. package/src/aws/role.ts +25 -28
  144. package/src/aws/ses.ts +150 -164
  145. package/src/aws/table.ts +15 -15
  146. package/src/cloudflare/bindings.ts +8 -0
  147. package/src/cloudflare/bucket.ts +39 -47
  148. package/src/cloudflare/durable-object-namespace.ts +0 -10
  149. package/src/cloudflare/generate-asset-manifest.ts +1 -1
  150. package/src/cloudflare/index.ts +2 -0
  151. package/src/cloudflare/kv-namespace.ts +35 -33
  152. package/src/cloudflare/static-site-router.ts +0 -3
  153. package/src/cloudflare/static-site.ts +55 -71
  154. package/src/cloudflare/worker.ts +106 -112
  155. package/src/cloudflare/wrangler.json.ts +309 -0
  156. package/src/cloudflare/zone-settings.ts +368 -0
  157. package/src/cloudflare/zone.ts +491 -0
  158. package/src/context.ts +122 -0
  159. package/src/destroy.ts +124 -73
  160. package/src/{esbuild.ts → esbuild/bundle.ts} +16 -28
  161. package/src/esbuild/index.ts +1 -0
  162. package/src/fs/file.ts +39 -0
  163. package/src/fs/folder.ts +32 -0
  164. package/src/fs/index.ts +2 -0
  165. package/src/github/secret.ts +19 -16
  166. package/src/index.ts +7 -15
  167. package/src/project/index.ts +1 -0
  168. package/src/project/vite.ts +152 -0
  169. package/src/resource.ts +101 -462
  170. package/src/scope.ts +125 -36
  171. package/src/secret.ts +9 -32
  172. package/src/state.ts +38 -21
  173. package/src/stripe/price.ts +17 -22
  174. package/src/stripe/product.ts +17 -22
  175. package/src/stripe/webhook.ts +21 -27
  176. package/src/test/bun.ts +105 -0
  177. package/src/util/rm.ts +11 -0
  178. package/src/util/serde.ts +53 -0
  179. package/src/util/slugify.ts +3 -0
  180. package/lib/$.d.ts +0 -12
  181. package/lib/$.d.ts.map +0 -1
  182. package/lib/$.js +0 -42
  183. package/lib/$.js.map +0 -1
  184. package/lib/alchemize.d.ts +0 -47
  185. package/lib/alchemize.d.ts.map +0 -1
  186. package/lib/alchemize.js +0 -116
  187. package/lib/alchemize.js.map +0 -1
  188. package/lib/apply.d.ts.map +0 -1
  189. package/lib/apply.js.map +0 -1
  190. package/lib/aws/account-id.d.ts.map +0 -1
  191. package/lib/aws/account-id.js.map +0 -1
  192. package/lib/aws/bucket.d.ts.map +0 -1
  193. package/lib/aws/bucket.js.map +0 -1
  194. package/lib/aws/function.d.ts.map +0 -1
  195. package/lib/aws/function.js.map +0 -1
  196. package/lib/aws/index.d.ts.map +0 -1
  197. package/lib/aws/index.js.map +0 -1
  198. package/lib/aws/oidc/github-oidc-provider.d.ts.map +0 -1
  199. package/lib/aws/oidc/github-oidc-provider.js.map +0 -1
  200. package/lib/aws/oidc/index.d.ts.map +0 -1
  201. package/lib/aws/oidc/index.js.map +0 -1
  202. package/lib/aws/oidc/oidc-provider.d.ts.map +0 -1
  203. package/lib/aws/oidc/oidc-provider.js.map +0 -1
  204. package/lib/aws/policy.d.ts.map +0 -1
  205. package/lib/aws/policy.js.map +0 -1
  206. package/lib/aws/queue.d.ts.map +0 -1
  207. package/lib/aws/queue.js.map +0 -1
  208. package/lib/aws/role.d.ts.map +0 -1
  209. package/lib/aws/role.js.map +0 -1
  210. package/lib/aws/ses.d.ts.map +0 -1
  211. package/lib/aws/ses.js.map +0 -1
  212. package/lib/aws/table.d.ts.map +0 -1
  213. package/lib/aws/table.js.map +0 -1
  214. package/lib/cloudflare/api.d.ts.map +0 -1
  215. package/lib/cloudflare/api.js.map +0 -1
  216. package/lib/cloudflare/asset-manifest.d.ts.map +0 -1
  217. package/lib/cloudflare/asset-manifest.js.map +0 -1
  218. package/lib/cloudflare/auth.d.ts.map +0 -1
  219. package/lib/cloudflare/auth.js.map +0 -1
  220. package/lib/cloudflare/bindings.d.ts.map +0 -1
  221. package/lib/cloudflare/bindings.js.map +0 -1
  222. package/lib/cloudflare/bound.d.ts.map +0 -1
  223. package/lib/cloudflare/bound.js.map +0 -1
  224. package/lib/cloudflare/bucket.d.ts.map +0 -1
  225. package/lib/cloudflare/bucket.js.map +0 -1
  226. package/lib/cloudflare/durable-object-namespace.d.ts.map +0 -1
  227. package/lib/cloudflare/durable-object-namespace.js.map +0 -1
  228. package/lib/cloudflare/generate-asset-manifest.d.ts.map +0 -1
  229. package/lib/cloudflare/generate-asset-manifest.js.map +0 -1
  230. package/lib/cloudflare/index.d.ts.map +0 -1
  231. package/lib/cloudflare/index.js.map +0 -1
  232. package/lib/cloudflare/kv-namespace.d.ts.map +0 -1
  233. package/lib/cloudflare/kv-namespace.js.map +0 -1
  234. package/lib/cloudflare/state.d.ts.map +0 -1
  235. package/lib/cloudflare/state.js.map +0 -1
  236. package/lib/cloudflare/static-site-router.d.ts.map +0 -1
  237. package/lib/cloudflare/static-site-router.js.map +0 -1
  238. package/lib/cloudflare/static-site.d.ts.map +0 -1
  239. package/lib/cloudflare/static-site.js.map +0 -1
  240. package/lib/cloudflare/types.d.ts.map +0 -1
  241. package/lib/cloudflare/types.js.map +0 -1
  242. package/lib/cloudflare/upload-asset-manifest.d.ts.map +0 -1
  243. package/lib/cloudflare/upload-asset-manifest.js.map +0 -1
  244. package/lib/cloudflare/worker-metadata.d.ts.map +0 -1
  245. package/lib/cloudflare/worker-metadata.js.map +0 -1
  246. package/lib/cloudflare/worker-migration.d.ts.map +0 -1
  247. package/lib/cloudflare/worker-migration.js.map +0 -1
  248. package/lib/cloudflare/worker.d.ts.map +0 -1
  249. package/lib/cloudflare/worker.js.map +0 -1
  250. package/lib/destroy.d.ts.map +0 -1
  251. package/lib/destroy.js.map +0 -1
  252. package/lib/encrypt.d.ts.map +0 -1
  253. package/lib/encrypt.js.map +0 -1
  254. package/lib/error.d.ts.map +0 -1
  255. package/lib/error.js.map +0 -1
  256. package/lib/esbuild.d.ts.map +0 -1
  257. package/lib/esbuild.js.map +0 -1
  258. package/lib/fs.d.ts +0 -12
  259. package/lib/fs.d.ts.map +0 -1
  260. package/lib/fs.js +0 -41
  261. package/lib/fs.js.map +0 -1
  262. package/lib/github/client.d.ts.map +0 -1
  263. package/lib/github/client.js.map +0 -1
  264. package/lib/github/index.d.ts.map +0 -1
  265. package/lib/github/index.js.map +0 -1
  266. package/lib/github/secret.d.ts.map +0 -1
  267. package/lib/github/secret.js.map +0 -1
  268. package/lib/global.d.ts +0 -16
  269. package/lib/global.d.ts.map +0 -1
  270. package/lib/global.js +0 -42
  271. package/lib/global.js.map +0 -1
  272. package/lib/index.d.ts.map +0 -1
  273. package/lib/index.js.map +0 -1
  274. package/lib/input.d.ts +0 -7
  275. package/lib/input.d.ts.map +0 -1
  276. package/lib/input.js +0 -2
  277. package/lib/input.js.map +0 -1
  278. package/lib/main.d.ts +0 -3
  279. package/lib/main.d.ts.map +0 -1
  280. package/lib/main.js +0 -32
  281. package/lib/main.js.map +0 -1
  282. package/lib/output.d.ts +0 -25
  283. package/lib/output.d.ts.map +0 -1
  284. package/lib/output.js +0 -23
  285. package/lib/output.js.map +0 -1
  286. package/lib/print.d.ts +0 -7
  287. package/lib/print.d.ts.map +0 -1
  288. package/lib/print.js +0 -10
  289. package/lib/print.js.map +0 -1
  290. package/lib/resource.d.ts.map +0 -1
  291. package/lib/resource.js.map +0 -1
  292. package/lib/scope.d.ts.map +0 -1
  293. package/lib/scope.js.map +0 -1
  294. package/lib/secret.d.ts.map +0 -1
  295. package/lib/secret.js.map +0 -1
  296. package/lib/serde.d.ts +0 -3
  297. package/lib/serde.d.ts.map +0 -1
  298. package/lib/serde.js.map +0 -1
  299. package/lib/slug.d.ts +0 -2
  300. package/lib/slug.d.ts.map +0 -1
  301. package/lib/slug.js +0 -4
  302. package/lib/slug.js.map +0 -1
  303. package/lib/state.d.ts.map +0 -1
  304. package/lib/state.js.map +0 -1
  305. package/lib/stripe/index.d.ts.map +0 -1
  306. package/lib/stripe/index.js.map +0 -1
  307. package/lib/stripe/price.d.ts.map +0 -1
  308. package/lib/stripe/price.js.map +0 -1
  309. package/lib/stripe/product.d.ts.map +0 -1
  310. package/lib/stripe/product.js.map +0 -1
  311. package/lib/stripe/webhook.d.ts.map +0 -1
  312. package/lib/stripe/webhook.js.map +0 -1
  313. package/lib/utils/content-type.d.ts.map +0 -1
  314. package/lib/utils/content-type.js.map +0 -1
  315. package/lib/utils/retry.d.ts.map +0 -1
  316. package/lib/utils/retry.js.map +0 -1
  317. package/src/$.ts +0 -69
  318. package/src/alchemize.ts +0 -195
  319. package/src/fs.ts +0 -47
  320. package/src/global.ts +0 -63
  321. package/src/input.ts +0 -19
  322. package/src/main.ts +0 -34
  323. package/src/output.ts +0 -75
  324. package/src/print.ts +0 -18
  325. package/src/serde.ts +0 -46
  326. package/src/slug.ts +0 -3
  327. /package/src/{utils → util}/content-type.ts +0 -0
  328. /package/src/{encrypt.ts → util/encrypt.ts} +0 -0
  329. /package/src/{error.ts → util/ignore.ts} +0 -0
  330. /package/src/{utils → util}/retry.ts +0 -0
package/lib/apply.js CHANGED
@@ -1,88 +1,101 @@
1
- import { defaultStage, defaultStateStore } from "./global";
2
- import { OutputChain } from "./output";
3
- import { Input, Provider, ResourceID, isResource, } from "./resource";
4
- import { getScope } from "./scope";
5
- import { Secret } from "./secret";
6
- /**
7
- * Apply a sub-graph to produce a resource.
8
- * @param output A sub-graph that produces a resource.
9
- * @returns The resource properties.
10
- */
11
- export async function apply(output, options) {
12
- const stage = options?.stage ?? defaultStage;
13
- const scope = options?.scope ?? getScope();
14
- const statePath = scope.getScopePath(stage);
15
- const stateStore = options?.stateStore ?? new defaultStateStore(statePath);
16
- return (await evaluate(output, { stage, scope, stateStore, quiet: options?.quiet })).value;
17
- }
18
- class Evaluated {
19
- value;
20
- deps;
21
- constructor(value, deps = []) {
22
- this.value = value;
23
- this.deps = deps;
24
- }
25
- }
26
- const cache = new WeakMap();
27
- export async function evaluate(output, options) {
28
- const stage = options.stage;
29
- const stateStore = options.stateStore;
30
- if (isResource(output)) {
31
- const resource = output;
32
- const resourceID = resource[ResourceID];
33
- const evaluated = await Promise.all(resource[Input].map((r) => evaluate(r, options)));
34
- if (cache.has(resource)) {
35
- return await cache.get(resource);
1
+ import { alchemy } from "./alchemy";
2
+ import { context } from "./context";
3
+ import { PROVIDERS, } from "./resource";
4
+ import { serialize } from "./util/serde";
5
+ export async function apply(resource, props, options) {
6
+ const scope = resource.Scope;
7
+ try {
8
+ const quiet = props.quiet ?? scope.quiet;
9
+ await scope.init();
10
+ let state = (await scope.state.get(resource.ID));
11
+ const provider = PROVIDERS.get(resource.Kind);
12
+ if (provider === undefined) {
13
+ throw new Error(`Provider "${resource.Kind}" not found`);
36
14
  }
37
- let resolve;
38
- let reject;
39
- const promise = new Promise((res, rej) => {
40
- resolve = res;
41
- reject = rej;
42
- });
43
- // set this eagerly to avoid double-apply (caused by recursive applies to inputs)
44
- cache.set(resource, promise);
45
- const deps = new Set(evaluated.flatMap((input) => input.deps));
46
- const inputs = evaluated.map((input) => input.value);
47
- try {
48
- const result = await resource[Provider].update(stage, resource, deps, inputs, stateStore, options);
49
- resolve(new Evaluated(result, [resourceID, ...deps]));
15
+ if (state === undefined) {
16
+ state = {
17
+ kind: resource.Kind,
18
+ id: resource.ID,
19
+ fqn: resource.FQN,
20
+ seq: resource.Seq,
21
+ status: "creating",
22
+ data: {},
23
+ output: {
24
+ ID: resource.ID,
25
+ FQN: resource.FQN,
26
+ Kind: resource.Kind,
27
+ Scope: scope,
28
+ Seq: resource.Seq,
29
+ },
30
+ // deps: [...deps],
31
+ props,
32
+ };
33
+ await scope.state.set(resource.ID, state);
50
34
  }
51
- catch (error) {
52
- console.error(error);
53
- reject(error);
35
+ const alwaysUpdate = options?.alwaysUpdate ?? provider.options?.alwaysUpdate ?? false;
36
+ // Skip update if inputs haven't changed and resource is in a stable state
37
+ if (state.status === "created" || state.status === "updated") {
38
+ if (JSON.stringify(state.props) ===
39
+ JSON.stringify(await serialize(scope, props)) &&
40
+ alwaysUpdate !== true) {
41
+ if (!quiet) {
42
+ console.log(`Skip: "${resource.FQN}" (no changes)`);
43
+ }
44
+ // if (resourceState.output !== undefined) {
45
+ // resource[Provide](resourceState.output);
46
+ // }
47
+ return state.output;
48
+ }
54
49
  }
55
- return promise;
56
- }
57
- else if (output instanceof OutputChain) {
58
- const inside = output;
59
- const parent = await evaluate(inside.parent, options);
60
- const ret = inside.fn(parent.value);
61
- // the ret may be an Output (e.g. in the flatMap case), so we need to evaluate it and include its deps
62
- const evaluated = await evaluate(ret, options);
63
- return new Evaluated(evaluated.value, [
64
- ...parent.deps,
65
- ...evaluated.deps,
66
- ]);
67
- }
68
- else if (Array.isArray(output)) {
69
- const evaluatedItems = await Promise.all(output.map((item) => evaluate(item, options)));
70
- return new Evaluated(evaluatedItems.map((e) => e.value), evaluatedItems.flatMap((e) => e.deps));
71
- }
72
- else if (output instanceof Date) {
73
- return new Evaluated(output);
74
- }
75
- else if (output instanceof Secret) {
76
- return new Evaluated(output);
50
+ const phase = state.status === "creating" ? "create" : "update";
51
+ state.status = phase === "create" ? "creating" : "updating";
52
+ state.oldProps = state.props;
53
+ state.props = props;
54
+ if (!quiet) {
55
+ console.log(`${phase === "create" ? "Create" : "Update"}: "${resource.FQN}"`);
56
+ }
57
+ await scope.state.set(resource.ID, state);
58
+ let isReplaced = false;
59
+ const ctx = context({
60
+ scope,
61
+ phase,
62
+ kind: resource.Kind,
63
+ id: resource.ID,
64
+ fqn: resource.FQN,
65
+ seq: resource.Seq,
66
+ state,
67
+ replace: () => {
68
+ if (isReplaced) {
69
+ console.warn(`Resource ${resource.Kind} ${resource.FQN} is already marked as REPLACE`);
70
+ return;
71
+ }
72
+ isReplaced = true;
73
+ },
74
+ });
75
+ const output = await alchemy.run(resource.ID, async () => {
76
+ return provider.handler.bind(ctx)(resource.ID, props);
77
+ });
78
+ if (!quiet) {
79
+ console.log(`${phase === "create" ? "Created" : "Updated"}: "${resource.FQN}"`);
80
+ }
81
+ await scope.state.set(resource.ID, {
82
+ kind: resource.Kind,
83
+ id: resource.ID,
84
+ fqn: resource.FQN,
85
+ seq: resource.Seq,
86
+ data: state.data,
87
+ status: phase === "create" ? "created" : "updated",
88
+ output,
89
+ props,
90
+ // deps: [...deps],
91
+ });
92
+ // if (output !== undefined) {
93
+ // resource[Provide](output as Out);
94
+ // }
95
+ return output;
77
96
  }
78
- else if (output && typeof output === "object") {
79
- const entries = Object.entries(output);
80
- const evaluatedEntries = await Promise.all(entries.map(async ([key, value]) => [key, await evaluate(value, options)]));
81
- const result = Object.fromEntries(evaluatedEntries.map(([key, evaluated]) => [key, evaluated.value]));
82
- const deps = evaluatedEntries.flatMap(([_, evaluated]) => evaluated.deps);
83
- return new Evaluated(result, deps);
97
+ catch (error) {
98
+ scope.fail();
99
+ throw error;
84
100
  }
85
- // Base case: primitive value
86
- return new Evaluated(output);
87
101
  }
88
- //# sourceMappingURL=apply.js.map
@@ -2,4 +2,3 @@
2
2
  * Helper to get the current AWS account ID
3
3
  */
4
4
  export declare function getAccountId(): Promise<string>;
5
- //# sourceMappingURL=account-id.d.ts.map
@@ -7,4 +7,3 @@ export async function getAccountId() {
7
7
  const identity = await sts.send(new GetCallerIdentityCommand({}));
8
8
  return identity.Account;
9
9
  }
10
- //# sourceMappingURL=account-id.js.map
@@ -1,9 +1,10 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
1
3
  export interface BucketProps {
2
4
  bucketName: string;
3
5
  tags?: Record<string, string>;
4
6
  }
5
- export interface BucketOutput extends BucketProps {
6
- id: string;
7
+ export interface Bucket extends Resource<"s3::Bucket">, BucketProps {
7
8
  arn: string;
8
9
  bucketDomainName: string;
9
10
  bucketRegionalDomainName?: string;
@@ -14,8 +15,4 @@ export interface BucketOutput extends BucketProps {
14
15
  versioningEnabled?: boolean;
15
16
  acl?: string;
16
17
  }
17
- declare const Bucket_base: import("../resource").Provider<"s3::Bucket", [props: BucketProps], BucketProps>;
18
- export declare class Bucket extends Bucket_base {
19
- }
20
- export {};
21
- //# sourceMappingURL=bucket.d.ts.map
18
+ export declare const Bucket: ((this: Context<Bucket>, id: string, props: BucketProps) => Promise<Bucket>) | (((this: any, id: string, props: BucketProps) => never) & (new (_: never) => never));
package/lib/aws/bucket.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { CreateBucketCommand, DeleteBucketCommand, GetBucketAclCommand, GetBucketLocationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, HeadBucketCommand, NoSuchBucket, PutBucketTaggingCommand, S3Client, } from "@aws-sdk/client-s3";
2
- import { ignore } from "../error";
3
2
  import { Resource } from "../resource";
4
- export class Bucket extends Resource("s3::Bucket", async (ctx, props) => {
3
+ import { ignore } from "../util/ignore";
4
+ export const Bucket = Resource("s3::Bucket", async function (id, props) {
5
5
  const client = new S3Client({});
6
- if (ctx.event === "delete") {
6
+ if (this.phase === "delete") {
7
7
  await ignore(NoSuchBucket.name, () => client.send(new DeleteBucketCommand({
8
8
  Bucket: props.bucketName,
9
9
  })));
10
- return props;
10
+ return this.destroy();
11
11
  }
12
12
  else {
13
13
  try {
@@ -16,7 +16,7 @@ export class Bucket extends Resource("s3::Bucket", async (ctx, props) => {
16
16
  Bucket: props.bucketName,
17
17
  }));
18
18
  // Update tags if they changed and bucket exists
19
- if (ctx.event === "update" && props.tags) {
19
+ if (this.phase === "update" && props.tags) {
20
20
  await client.send(new PutBucketTaggingCommand({
21
21
  Bucket: props.bucketName,
22
22
  Tagging: {
@@ -68,9 +68,8 @@ export class Bucket extends Resource("s3::Bucket", async (ctx, props) => {
68
68
  }
69
69
  }
70
70
  }
71
- const output = {
71
+ return this({
72
72
  bucketName: props.bucketName,
73
- id: props.bucketName,
74
73
  arn: `arn:aws:s3:::${props.bucketName}`,
75
74
  bucketDomainName: `${props.bucketName}.s3.amazonaws.com`,
76
75
  bucketRegionalDomainName: `${props.bucketName}.s3.${region}.amazonaws.com`,
@@ -79,11 +78,9 @@ export class Bucket extends Resource("s3::Bucket", async (ctx, props) => {
79
78
  versioningEnabled: versioningResponse.Status === "Enabled",
80
79
  acl: aclResponse.Grants?.[0]?.Permission?.toLowerCase(),
81
80
  ...(tags && { tags }),
82
- };
83
- return output;
81
+ });
84
82
  }
85
- }) {
86
- }
83
+ });
87
84
  // Helper function to get S3 hosted zone IDs by region
88
85
  function getHostedZoneId(region) {
89
86
  const hostedZoneIds = {
@@ -111,4 +108,3 @@ function getHostedZoneId(region) {
111
108
  };
112
109
  return hostedZoneIds[region] || "Z3AQBSTGFYJSTF"; // Default to us-east-1 if region not found
113
110
  }
114
- //# sourceMappingURL=bucket.js.map
@@ -1,4 +1,6 @@
1
1
  import { Architecture, Runtime } from "@aws-sdk/client-lambda";
2
+ import type { Context } from "../context";
3
+ import { Resource } from "../resource";
2
4
  export interface FunctionProps {
3
5
  functionName: string;
4
6
  zipPath: string;
@@ -23,8 +25,7 @@ export interface FunctionProps {
23
25
  };
24
26
  };
25
27
  }
26
- export interface FunctionOutput extends FunctionProps {
27
- id: string;
28
+ export interface Function extends Resource<"lambda::Function">, FunctionProps {
28
29
  arn: string;
29
30
  lastModified: string;
30
31
  version: string;
@@ -46,8 +47,4 @@ export interface FunctionOutput extends FunctionProps {
46
47
  signingProfileVersionArn?: string;
47
48
  signingJobArn?: string;
48
49
  }
49
- declare const Function_base: import("../resource").Provider<"lambda::Function", [props: FunctionProps], FunctionOutput>;
50
- export declare class Function extends Function_base {
51
- }
52
- export {};
53
- //# sourceMappingURL=function.d.ts.map
50
+ export declare const Function: ((this: Context<Function>, id: string, props: FunctionProps) => Promise<Function>) | (((this: any, id: string, props: FunctionProps) => never) & (new (_: never) => never));
@@ -1,8 +1,8 @@
1
1
  import { Architecture, CreateFunctionCommand, DeleteFunctionCommand, GetFunctionCommand, GetFunctionConfigurationCommand, LambdaClient, ResourceNotFoundException, Runtime, UpdateFunctionCodeCommand, UpdateFunctionConfigurationCommand, } from "@aws-sdk/client-lambda";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
- import { ignore } from "../error";
5
4
  import { Resource } from "../resource";
5
+ import { ignore } from "../util/ignore";
6
6
  async function resolveRegion(client) {
7
7
  const region = client.config.region;
8
8
  if (typeof region === "string")
@@ -11,40 +11,23 @@ async function resolveRegion(client) {
11
11
  return region();
12
12
  throw new Error("Could not resolve AWS region");
13
13
  }
14
- export class Function extends Resource("lambda::Function", async (ctx, props) => {
14
+ export const Function = Resource("lambda::Function", async function (id, props) {
15
15
  const client = new LambdaClient({});
16
16
  const region = await resolveRegion(client);
17
17
  const code = await zipCode(props.zipPath);
18
- if (ctx.event === "delete") {
18
+ if (this.phase === "delete") {
19
19
  await ignore(ResourceNotFoundException.name, () => client.send(new DeleteFunctionCommand({
20
20
  FunctionName: props.functionName,
21
21
  })));
22
- // Return a minimal FunctionOutput for deleted state
23
- return {
24
- ...props,
25
- id: props.functionName,
26
- arn: `arn:aws:lambda:${region}:${process.env.AWS_ACCOUNT_ID}:function:${props.functionName}`,
27
- lastModified: new Date().toISOString(),
28
- version: "$LATEST",
29
- qualifiedArn: `arn:aws:lambda:${region}:${process.env.AWS_ACCOUNT_ID}:function:${props.functionName}:$LATEST`,
30
- invokeArn: `arn:aws:apigateway:${region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${region}:${process.env.AWS_ACCOUNT_ID}:function:${props.functionName}/invocations`,
31
- sourceCodeHash: "",
32
- sourceCodeSize: 0,
33
- architectures: props.architecture
34
- ? [props.architecture]
35
- : [Architecture.x86_64],
36
- revisionId: "",
37
- state: "Inactive",
38
- packageType: "Zip",
39
- };
22
+ return this.destroy();
40
23
  }
41
24
  else {
42
25
  try {
43
26
  // Check if function exists
44
- const func = await client.send(new GetFunctionCommand({
27
+ await client.send(new GetFunctionCommand({
45
28
  FunctionName: props.functionName,
46
29
  }));
47
- if (ctx.event === "update") {
30
+ if (this.phase === "update") {
48
31
  // Wait for function to stabilize
49
32
  await waitForFunctionStabilization(client, props.functionName);
50
33
  // Update function code
@@ -134,9 +117,8 @@ export class Function extends Resource("lambda::Function", async (ctx, props) =>
134
117
  FunctionName: props.functionName,
135
118
  })),
136
119
  ]);
137
- const output = {
120
+ return this({
138
121
  ...props,
139
- id: props.functionName,
140
122
  arn: config.FunctionArn,
141
123
  lastModified: config.LastModified,
142
124
  version: config.Version,
@@ -157,11 +139,9 @@ export class Function extends Resource("lambda::Function", async (ctx, props) =>
157
139
  packageType: config.PackageType,
158
140
  signingProfileVersionArn: config.SigningProfileVersionArn,
159
141
  signingJobArn: config.SigningJobArn,
160
- };
161
- return output;
142
+ });
162
143
  }
163
- }) {
164
- }
144
+ });
165
145
  // Helper to wait for function to stabilize
166
146
  async function waitForFunctionStabilization(client, functionName) {
167
147
  while (true) {
@@ -192,4 +172,3 @@ async function zipCode(filePath) {
192
172
  platform: "UNIX",
193
173
  });
194
174
  }
195
- //# sourceMappingURL=function.js.map
@@ -2,8 +2,8 @@ export * from "./account-id";
2
2
  export * from "./bucket";
3
3
  export * from "./function";
4
4
  export * from "./policy";
5
+ export * from "./policy-attachment";
5
6
  export * from "./queue";
6
7
  export * from "./role";
7
8
  export * from "./ses";
8
9
  export * from "./table";
9
- //# sourceMappingURL=index.d.ts.map
package/lib/aws/index.js CHANGED
@@ -2,8 +2,8 @@ export * from "./account-id";
2
2
  export * from "./bucket";
3
3
  export * from "./function";
4
4
  export * from "./policy";
5
+ export * from "./policy-attachment";
5
6
  export * from "./queue";
6
7
  export * from "./role";
7
8
  export * from "./ses";
8
9
  export * from "./table";
9
- //# sourceMappingURL=index.js.map
@@ -1,11 +1,7 @@
1
- import type { Input } from "../../input";
2
1
  import { OIDCProvider, type OIDCProviderProps } from "./oidc-provider";
3
2
  export interface GitHubOIDCProviderProps extends Omit<OIDCProviderProps, "thumbprint"> {
4
3
  owner: string;
5
4
  repository: string;
6
- thumbprint?: string;
7
5
  }
8
- export declare class GitHubOIDCProvider extends OIDCProvider {
9
- constructor(id: string, props: Input<GitHubOIDCProviderProps>);
10
- }
11
- //# sourceMappingURL=github-oidc-provider.d.ts.map
6
+ export type GitHubOIDCProvider = ReturnType<typeof GitHubOIDCProvider>;
7
+ export declare const GitHubOIDCProvider: (id: string, props: GitHubOIDCProviderProps) => Promise<OIDCProvider>;
@@ -1,4 +1,3 @@
1
- import { isOutput } from "../../output";
2
1
  import { OIDCProvider } from "./oidc-provider";
3
2
  /**
4
3
  * Default thumbprint for GitHub's OIDC provider
@@ -6,17 +5,13 @@ import { OIDCProvider } from "./oidc-provider";
6
5
  * @see https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#adding-the-identity-provider-to-aws
7
6
  */
8
7
  const DEFAULT_GITHUB_THUMBPRINT = "6938fd4d98bab03faadb97b34396831e3780aea1";
9
- export class GitHubOIDCProvider extends OIDCProvider {
10
- constructor(id, props) {
11
- super(id, isOutput(props)
12
- ? props.apply((props) => ({
13
- ...props,
14
- thumbprint: props.thumbprint ?? DEFAULT_GITHUB_THUMBPRINT,
15
- }))
16
- : {
17
- ...props,
18
- thumbprint: props.thumbprint ?? DEFAULT_GITHUB_THUMBPRINT,
19
- });
20
- }
21
- }
22
- //# sourceMappingURL=github-oidc-provider.js.map
8
+ export const GitHubOIDCProvider = async (id, props) => {
9
+ return OIDCProvider(id, {
10
+ owner: props.owner,
11
+ repository: props.repository,
12
+ roleArn: props.roleArn,
13
+ branches: props.branches,
14
+ environments: props.environments,
15
+ thumbprint: DEFAULT_GITHUB_THUMBPRINT,
16
+ });
17
+ };
@@ -1,3 +1,2 @@
1
1
  export * from "./github-oidc-provider";
2
2
  export * from "./oidc-provider";
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,2 @@
1
1
  export * from "./github-oidc-provider";
2
2
  export * from "./oidc-provider";
3
- //# sourceMappingURL=index.js.map
@@ -1,3 +1,5 @@
1
+ import type { Context } from "../../context";
2
+ import { Resource } from "../../resource";
1
3
  /**
2
4
  * Properties for configuring an AWS OIDC provider for GitHub Actions
3
5
  */
@@ -40,7 +42,7 @@ export interface OIDCProviderProps {
40
42
  /**
41
43
  * Output returned after OIDC provider configuration
42
44
  */
43
- export interface OIDCProviderOutput extends OIDCProviderProps {
45
+ export interface OIDCProvider extends Resource<"aws::OIDCProvider">, OIDCProviderProps {
44
46
  /**
45
47
  * The ARN of the OIDC provider
46
48
  */
@@ -50,11 +52,7 @@ export interface OIDCProviderOutput extends OIDCProviderProps {
50
52
  */
51
53
  createdAt: number;
52
54
  }
53
- declare const OIDCProvider_base: import("../../resource").Provider<"aws::OIDCProvider", [props: OIDCProviderProps], OIDCProviderOutput>;
54
55
  /**
55
56
  * Resource for configuring AWS OIDC provider for GitHub Actions
56
57
  */
57
- export declare class OIDCProvider extends OIDCProvider_base {
58
- }
59
- export {};
60
- //# sourceMappingURL=oidc-provider.d.ts.map
58
+ export declare const OIDCProvider: ((this: Context<OIDCProvider>, id: string, props: OIDCProviderProps) => Promise<OIDCProvider>) | (((this: any, id: string, props: OIDCProviderProps) => never) & (new (_: never) => never));
@@ -9,13 +9,13 @@ const TRUST_POLICY_SID = "GitHubOIDCTrust";
9
9
  /**
10
10
  * Resource for configuring AWS OIDC provider for GitHub Actions
11
11
  */
12
- export class OIDCProvider extends Resource("aws::OIDCProvider", async (ctx, props) => {
12
+ export const OIDCProvider = Resource("aws::OIDCProvider", async function (id, props) {
13
13
  // Initialize AWS SDK client
14
14
  const client = new IAMClient({
15
15
  region: props.region,
16
16
  });
17
- if (ctx.event === "delete") {
18
- if (ctx.output?.providerArn) {
17
+ if (this.phase === "delete") {
18
+ if (this.output?.providerArn) {
19
19
  try {
20
20
  // First, remove our trust policy statement from the role
21
21
  const getRole = await client.send(new GetRoleCommand({
@@ -32,12 +32,12 @@ export class OIDCProvider extends Resource("aws::OIDCProvider", async (ctx, prop
32
32
  }
33
33
  // Then delete the OIDC provider if we're the last user
34
34
  const provider = await client.send(new GetOpenIDConnectProviderCommand({
35
- OpenIDConnectProviderArn: ctx.output.providerArn,
35
+ OpenIDConnectProviderArn: this.output.providerArn,
36
36
  }));
37
37
  // Only delete the provider if it exists and has no other tags
38
38
  if (provider && (!provider.Tags || provider.Tags.length === 0)) {
39
39
  await client.send(new DeleteOpenIDConnectProviderCommand({
40
- OpenIDConnectProviderArn: ctx.output.providerArn,
40
+ OpenIDConnectProviderArn: this.output.providerArn,
41
41
  }));
42
42
  }
43
43
  }
@@ -46,7 +46,7 @@ export class OIDCProvider extends Resource("aws::OIDCProvider", async (ctx, prop
46
46
  console.error("Error during cleanup:", error);
47
47
  }
48
48
  }
49
- return;
49
+ return this.destroy();
50
50
  }
51
51
  try {
52
52
  const url = "https://token.actions.githubusercontent.com";
@@ -125,16 +125,14 @@ export class OIDCProvider extends Resource("aws::OIDCProvider", async (ctx, prop
125
125
  RoleName: props.roleArn.split("/").pop(),
126
126
  PolicyDocument: JSON.stringify(policy),
127
127
  }));
128
- return {
128
+ return this({
129
129
  ...props,
130
130
  providerArn,
131
131
  createdAt: Date.now(),
132
- };
132
+ });
133
133
  }
134
134
  catch (error) {
135
135
  console.error("Error configuring OIDC provider:", error);
136
136
  throw error;
137
137
  }
138
- }) {
139
- }
140
- //# sourceMappingURL=oidc-provider.js.map
138
+ });
@@ -0,0 +1,9 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ export interface PolicyAttachmentProps {
4
+ policyArn: string;
5
+ roleName: string;
6
+ }
7
+ export interface PolicyAttachment extends Resource<"iam::PolicyAttachment">, PolicyAttachmentProps {
8
+ }
9
+ export declare const PolicyAttachment: ((this: Context<PolicyAttachment>, id: string, props: PolicyAttachmentProps) => Promise<PolicyAttachment>) | (((this: any, id: string, props: PolicyAttachmentProps) => never) & (new (_: never) => never));
@@ -0,0 +1,20 @@
1
+ import { AttachRolePolicyCommand, DetachRolePolicyCommand, IAMClient, NoSuchEntityException, } from "@aws-sdk/client-iam";
2
+ import { Resource } from "../resource";
3
+ import { ignore } from "../util/ignore";
4
+ export const PolicyAttachment = Resource("iam::PolicyAttachment", async function (id, props) {
5
+ const client = new IAMClient({});
6
+ if (this.phase === "delete") {
7
+ await ignore(NoSuchEntityException.name, () => client.send(new DetachRolePolicyCommand({
8
+ PolicyArn: props.policyArn,
9
+ RoleName: props.roleName,
10
+ })));
11
+ return this.destroy();
12
+ }
13
+ else {
14
+ await client.send(new AttachRolePolicyCommand({
15
+ PolicyArn: props.policyArn,
16
+ RoleName: props.roleName,
17
+ }));
18
+ }
19
+ return this(props);
20
+ });
@@ -1,3 +1,5 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
1
3
  export type Effect = "Allow" | "Deny";
2
4
  export interface PolicyStatement {
3
5
  Sid?: string;
@@ -21,8 +23,7 @@ export interface PolicyProps {
21
23
  path?: string;
22
24
  tags?: Record<string, string>;
23
25
  }
24
- export interface PolicyOutput extends PolicyProps {
25
- id: string;
26
+ export interface Policy extends Resource<"iam::Policy">, PolicyProps {
26
27
  arn: string;
27
28
  defaultVersionId: string;
28
29
  attachmentCount: number;
@@ -30,17 +31,4 @@ export interface PolicyOutput extends PolicyProps {
30
31
  updateDate: Date;
31
32
  isAttachable: boolean;
32
33
  }
33
- declare const Policy_base: import("../resource").Provider<"iam::Policy", [props: PolicyProps], PolicyOutput>;
34
- export declare class Policy extends Policy_base {
35
- }
36
- export interface PolicyAttachmentProps {
37
- policyArn: string;
38
- roleName: string;
39
- }
40
- export interface PolicyAttachmentOutput extends PolicyAttachmentProps {
41
- }
42
- declare const PolicyAttachment_base: import("../resource").Provider<"iam::PolicyAttachment", [props: PolicyAttachmentProps], PolicyAttachmentProps>;
43
- export declare class PolicyAttachment extends PolicyAttachment_base {
44
- }
45
- export {};
46
- //# sourceMappingURL=policy.d.ts.map
34
+ export declare const Policy: ((this: Context<Policy>, id: string, props: PolicyProps) => Promise<Policy>) | (((this: any, id: string, props: PolicyProps) => never) & (new (_: never) => never));