alchemy 0.1.18 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/lib/alchemy.d.ts +67 -0
  2. package/lib/alchemy.js +40 -0
  3. package/lib/apply.d.ts +3 -20
  4. package/lib/apply.js +86 -82
  5. package/lib/aws/account-id.d.ts +0 -1
  6. package/lib/aws/account-id.js +0 -1
  7. package/lib/aws/bucket.d.ts +4 -7
  8. package/lib/aws/bucket.js +8 -12
  9. package/lib/aws/function.d.ts +4 -7
  10. package/lib/aws/function.js +9 -30
  11. package/lib/aws/index.d.ts +1 -1
  12. package/lib/aws/index.js +1 -1
  13. package/lib/aws/oidc/github-oidc-provider.d.ts +2 -6
  14. package/lib/aws/oidc/github-oidc-provider.js +10 -15
  15. package/lib/aws/oidc/index.d.ts +0 -1
  16. package/lib/aws/oidc/index.js +0 -1
  17. package/lib/aws/oidc/oidc-provider.d.ts +4 -6
  18. package/lib/aws/oidc/oidc-provider.js +9 -11
  19. package/lib/aws/policy-attachment.d.ts +9 -0
  20. package/lib/aws/policy-attachment.js +20 -0
  21. package/lib/aws/policy.d.ts +4 -16
  22. package/lib/aws/policy.js +9 -40
  23. package/lib/aws/queue.d.ts +4 -34
  24. package/lib/aws/queue.js +10 -20
  25. package/lib/aws/role.d.ts +4 -7
  26. package/lib/aws/role.js +17 -26
  27. package/lib/aws/ses.d.ts +4 -10
  28. package/lib/aws/ses.js +118 -131
  29. package/lib/aws/table.d.ts +4 -7
  30. package/lib/aws/table.js +8 -11
  31. package/lib/cloudflare/api.d.ts +0 -1
  32. package/lib/cloudflare/api.js +0 -1
  33. package/lib/cloudflare/asset-manifest.d.ts +0 -1
  34. package/lib/cloudflare/asset-manifest.js +0 -1
  35. package/lib/cloudflare/auth.d.ts +0 -1
  36. package/lib/cloudflare/auth.js +0 -1
  37. package/lib/cloudflare/bindings.d.ts +1 -1
  38. package/lib/cloudflare/bindings.js +3 -2
  39. package/lib/cloudflare/bound.d.ts +0 -1
  40. package/lib/cloudflare/bound.js +0 -1
  41. package/lib/cloudflare/bucket.d.ts +7 -15
  42. package/lib/cloudflare/bucket.js +12 -19
  43. package/lib/cloudflare/durable-object-namespace.d.ts +0 -3
  44. package/lib/cloudflare/durable-object-namespace.js +0 -4
  45. package/lib/cloudflare/generate-asset-manifest.d.ts +0 -1
  46. package/lib/cloudflare/generate-asset-manifest.js +1 -2
  47. package/lib/cloudflare/index.d.ts +0 -1
  48. package/lib/cloudflare/index.js +0 -1
  49. package/lib/cloudflare/kv-namespace.d.ts +6 -9
  50. package/lib/cloudflare/kv-namespace.js +16 -20
  51. package/lib/cloudflare/state.d.ts +0 -1
  52. package/lib/cloudflare/state.js +0 -1
  53. package/lib/cloudflare/static-site-router.d.ts +0 -1
  54. package/lib/cloudflare/static-site-router.js +0 -4
  55. package/lib/cloudflare/static-site.d.ts +5 -11
  56. package/lib/cloudflare/static-site.js +16 -28
  57. package/lib/cloudflare/types.d.ts +0 -1
  58. package/lib/cloudflare/types.js +0 -1
  59. package/lib/cloudflare/upload-asset-manifest.d.ts +0 -1
  60. package/lib/cloudflare/upload-asset-manifest.js +0 -1
  61. package/lib/cloudflare/worker-metadata.d.ts +0 -1
  62. package/lib/cloudflare/worker-metadata.js +0 -1
  63. package/lib/cloudflare/worker-migration.d.ts +0 -1
  64. package/lib/cloudflare/worker-migration.js +0 -1
  65. package/lib/cloudflare/worker.d.ts +8 -14
  66. package/lib/cloudflare/worker.js +37 -49
  67. package/lib/context.d.ts +58 -0
  68. package/lib/context.js +36 -0
  69. package/lib/destroy.d.ts +10 -13
  70. package/lib/destroy.js +104 -43
  71. package/lib/{esbuild.d.ts → esbuild/bundle.d.ts} +4 -18
  72. package/lib/{esbuild.js → esbuild/bundle.js} +10 -24
  73. package/lib/esbuild/index.d.ts +1 -0
  74. package/lib/esbuild/index.js +1 -0
  75. package/lib/fs/file.d.ts +13 -0
  76. package/lib/fs/file.js +20 -0
  77. package/lib/fs/folder.d.ts +10 -0
  78. package/lib/fs/folder.js +16 -0
  79. package/lib/fs/index.d.ts +2 -0
  80. package/lib/fs/index.js +2 -0
  81. package/lib/github/client.d.ts +0 -1
  82. package/lib/github/client.js +0 -1
  83. package/lib/github/index.d.ts +0 -1
  84. package/lib/github/index.js +0 -1
  85. package/lib/github/secret.d.ts +4 -6
  86. package/lib/github/secret.js +10 -12
  87. package/lib/index.d.ts +6 -10
  88. package/lib/index.js +5 -9
  89. package/lib/resource.d.ts +34 -62
  90. package/lib/resource.js +29 -270
  91. package/lib/scope.d.ts +35 -14
  92. package/lib/scope.js +78 -23
  93. package/lib/secret.d.ts +2 -7
  94. package/lib/secret.js +7 -20
  95. package/lib/state.d.ts +14 -10
  96. package/lib/state.js +15 -14
  97. package/lib/stripe/index.d.ts +0 -1
  98. package/lib/stripe/index.js +0 -1
  99. package/lib/stripe/price.d.ts +4 -5
  100. package/lib/stripe/price.js +10 -20
  101. package/lib/stripe/product.d.ts +4 -5
  102. package/lib/stripe/product.js +10 -20
  103. package/lib/stripe/webhook.d.ts +4 -6
  104. package/lib/stripe/webhook.js +12 -25
  105. package/lib/test/bun.d.ts +19 -0
  106. package/lib/test/bun.js +55 -0
  107. package/lib/{utils → util}/content-type.d.ts +0 -1
  108. package/lib/{utils → util}/content-type.js +0 -1
  109. package/lib/{encrypt.d.ts → util/encrypt.d.ts} +0 -1
  110. package/lib/{encrypt.js → util/encrypt.js} +0 -1
  111. package/lib/{error.d.ts → util/ignore.d.ts} +0 -1
  112. package/lib/{error.js → util/ignore.js} +0 -1
  113. package/lib/{utils → util}/retry.d.ts +0 -1
  114. package/lib/{utils → util}/retry.js +0 -1
  115. package/lib/util/serde.d.ts +3 -0
  116. package/lib/{serde.js → util/serde.js} +19 -10
  117. package/lib/util/slugify.d.ts +1 -0
  118. package/lib/util/slugify.js +3 -0
  119. package/package.json +5 -4
  120. package/src/alchemy.ts +120 -0
  121. package/src/apply.ts +109 -114
  122. package/src/aws/bucket.ts +11 -14
  123. package/src/aws/function.ts +13 -33
  124. package/src/aws/index.ts +1 -0
  125. package/src/aws/oidc/github-oidc-provider.ts +14 -19
  126. package/src/aws/oidc/oidc-provider.ts +19 -12
  127. package/src/aws/policy-attachment.ts +51 -0
  128. package/src/aws/policy.ts +15 -60
  129. package/src/aws/queue.ts +17 -21
  130. package/src/aws/role.ts +25 -28
  131. package/src/aws/ses.ts +150 -164
  132. package/src/aws/table.ts +15 -15
  133. package/src/cloudflare/bindings.ts +8 -0
  134. package/src/cloudflare/bucket.ts +39 -47
  135. package/src/cloudflare/durable-object-namespace.ts +0 -10
  136. package/src/cloudflare/generate-asset-manifest.ts +1 -1
  137. package/src/cloudflare/kv-namespace.ts +35 -33
  138. package/src/cloudflare/static-site-router.ts +0 -3
  139. package/src/cloudflare/static-site.ts +44 -60
  140. package/src/cloudflare/worker.ts +105 -111
  141. package/src/context.ts +122 -0
  142. package/src/destroy.ts +124 -73
  143. package/src/{esbuild.ts → esbuild/bundle.ts} +16 -28
  144. package/src/esbuild/index.ts +1 -0
  145. package/src/fs/file.ts +39 -0
  146. package/src/fs/folder.ts +32 -0
  147. package/src/fs/index.ts +2 -0
  148. package/src/github/secret.ts +19 -16
  149. package/src/index.ts +7 -15
  150. package/src/resource.ts +101 -462
  151. package/src/scope.ts +101 -36
  152. package/src/secret.ts +9 -32
  153. package/src/state.ts +30 -21
  154. package/src/stripe/price.ts +17 -22
  155. package/src/stripe/product.ts +17 -22
  156. package/src/stripe/webhook.ts +21 -27
  157. package/src/test/bun.ts +105 -0
  158. package/src/util/serde.ts +53 -0
  159. package/src/util/slugify.ts +3 -0
  160. package/lib/$.d.ts +0 -12
  161. package/lib/$.d.ts.map +0 -1
  162. package/lib/$.js +0 -42
  163. package/lib/$.js.map +0 -1
  164. package/lib/alchemize.d.ts +0 -47
  165. package/lib/alchemize.d.ts.map +0 -1
  166. package/lib/alchemize.js +0 -116
  167. package/lib/alchemize.js.map +0 -1
  168. package/lib/apply.d.ts.map +0 -1
  169. package/lib/apply.js.map +0 -1
  170. package/lib/aws/account-id.d.ts.map +0 -1
  171. package/lib/aws/account-id.js.map +0 -1
  172. package/lib/aws/bucket.d.ts.map +0 -1
  173. package/lib/aws/bucket.js.map +0 -1
  174. package/lib/aws/function.d.ts.map +0 -1
  175. package/lib/aws/function.js.map +0 -1
  176. package/lib/aws/index.d.ts.map +0 -1
  177. package/lib/aws/index.js.map +0 -1
  178. package/lib/aws/oidc/github-oidc-provider.d.ts.map +0 -1
  179. package/lib/aws/oidc/github-oidc-provider.js.map +0 -1
  180. package/lib/aws/oidc/index.d.ts.map +0 -1
  181. package/lib/aws/oidc/index.js.map +0 -1
  182. package/lib/aws/oidc/oidc-provider.d.ts.map +0 -1
  183. package/lib/aws/oidc/oidc-provider.js.map +0 -1
  184. package/lib/aws/policy.d.ts.map +0 -1
  185. package/lib/aws/policy.js.map +0 -1
  186. package/lib/aws/queue.d.ts.map +0 -1
  187. package/lib/aws/queue.js.map +0 -1
  188. package/lib/aws/role.d.ts.map +0 -1
  189. package/lib/aws/role.js.map +0 -1
  190. package/lib/aws/ses.d.ts.map +0 -1
  191. package/lib/aws/ses.js.map +0 -1
  192. package/lib/aws/table.d.ts.map +0 -1
  193. package/lib/aws/table.js.map +0 -1
  194. package/lib/cloudflare/api.d.ts.map +0 -1
  195. package/lib/cloudflare/api.js.map +0 -1
  196. package/lib/cloudflare/asset-manifest.d.ts.map +0 -1
  197. package/lib/cloudflare/asset-manifest.js.map +0 -1
  198. package/lib/cloudflare/auth.d.ts.map +0 -1
  199. package/lib/cloudflare/auth.js.map +0 -1
  200. package/lib/cloudflare/bindings.d.ts.map +0 -1
  201. package/lib/cloudflare/bindings.js.map +0 -1
  202. package/lib/cloudflare/bound.d.ts.map +0 -1
  203. package/lib/cloudflare/bound.js.map +0 -1
  204. package/lib/cloudflare/bucket.d.ts.map +0 -1
  205. package/lib/cloudflare/bucket.js.map +0 -1
  206. package/lib/cloudflare/durable-object-namespace.d.ts.map +0 -1
  207. package/lib/cloudflare/durable-object-namespace.js.map +0 -1
  208. package/lib/cloudflare/generate-asset-manifest.d.ts.map +0 -1
  209. package/lib/cloudflare/generate-asset-manifest.js.map +0 -1
  210. package/lib/cloudflare/index.d.ts.map +0 -1
  211. package/lib/cloudflare/index.js.map +0 -1
  212. package/lib/cloudflare/kv-namespace.d.ts.map +0 -1
  213. package/lib/cloudflare/kv-namespace.js.map +0 -1
  214. package/lib/cloudflare/state.d.ts.map +0 -1
  215. package/lib/cloudflare/state.js.map +0 -1
  216. package/lib/cloudflare/static-site-router.d.ts.map +0 -1
  217. package/lib/cloudflare/static-site-router.js.map +0 -1
  218. package/lib/cloudflare/static-site.d.ts.map +0 -1
  219. package/lib/cloudflare/static-site.js.map +0 -1
  220. package/lib/cloudflare/types.d.ts.map +0 -1
  221. package/lib/cloudflare/types.js.map +0 -1
  222. package/lib/cloudflare/upload-asset-manifest.d.ts.map +0 -1
  223. package/lib/cloudflare/upload-asset-manifest.js.map +0 -1
  224. package/lib/cloudflare/worker-metadata.d.ts.map +0 -1
  225. package/lib/cloudflare/worker-metadata.js.map +0 -1
  226. package/lib/cloudflare/worker-migration.d.ts.map +0 -1
  227. package/lib/cloudflare/worker-migration.js.map +0 -1
  228. package/lib/cloudflare/worker.d.ts.map +0 -1
  229. package/lib/cloudflare/worker.js.map +0 -1
  230. package/lib/destroy.d.ts.map +0 -1
  231. package/lib/destroy.js.map +0 -1
  232. package/lib/encrypt.d.ts.map +0 -1
  233. package/lib/encrypt.js.map +0 -1
  234. package/lib/error.d.ts.map +0 -1
  235. package/lib/error.js.map +0 -1
  236. package/lib/esbuild.d.ts.map +0 -1
  237. package/lib/esbuild.js.map +0 -1
  238. package/lib/fs.d.ts +0 -12
  239. package/lib/fs.d.ts.map +0 -1
  240. package/lib/fs.js +0 -41
  241. package/lib/fs.js.map +0 -1
  242. package/lib/github/client.d.ts.map +0 -1
  243. package/lib/github/client.js.map +0 -1
  244. package/lib/github/index.d.ts.map +0 -1
  245. package/lib/github/index.js.map +0 -1
  246. package/lib/github/secret.d.ts.map +0 -1
  247. package/lib/github/secret.js.map +0 -1
  248. package/lib/global.d.ts +0 -16
  249. package/lib/global.d.ts.map +0 -1
  250. package/lib/global.js +0 -42
  251. package/lib/global.js.map +0 -1
  252. package/lib/index.d.ts.map +0 -1
  253. package/lib/index.js.map +0 -1
  254. package/lib/input.d.ts +0 -7
  255. package/lib/input.d.ts.map +0 -1
  256. package/lib/input.js +0 -2
  257. package/lib/input.js.map +0 -1
  258. package/lib/main.d.ts +0 -3
  259. package/lib/main.d.ts.map +0 -1
  260. package/lib/main.js +0 -32
  261. package/lib/main.js.map +0 -1
  262. package/lib/output.d.ts +0 -25
  263. package/lib/output.d.ts.map +0 -1
  264. package/lib/output.js +0 -23
  265. package/lib/output.js.map +0 -1
  266. package/lib/print.d.ts +0 -7
  267. package/lib/print.d.ts.map +0 -1
  268. package/lib/print.js +0 -10
  269. package/lib/print.js.map +0 -1
  270. package/lib/resource.d.ts.map +0 -1
  271. package/lib/resource.js.map +0 -1
  272. package/lib/scope.d.ts.map +0 -1
  273. package/lib/scope.js.map +0 -1
  274. package/lib/secret.d.ts.map +0 -1
  275. package/lib/secret.js.map +0 -1
  276. package/lib/serde.d.ts +0 -3
  277. package/lib/serde.d.ts.map +0 -1
  278. package/lib/serde.js.map +0 -1
  279. package/lib/slug.d.ts +0 -2
  280. package/lib/slug.d.ts.map +0 -1
  281. package/lib/slug.js +0 -4
  282. package/lib/slug.js.map +0 -1
  283. package/lib/state.d.ts.map +0 -1
  284. package/lib/state.js.map +0 -1
  285. package/lib/stripe/index.d.ts.map +0 -1
  286. package/lib/stripe/index.js.map +0 -1
  287. package/lib/stripe/price.d.ts.map +0 -1
  288. package/lib/stripe/price.js.map +0 -1
  289. package/lib/stripe/product.d.ts.map +0 -1
  290. package/lib/stripe/product.js.map +0 -1
  291. package/lib/stripe/webhook.d.ts.map +0 -1
  292. package/lib/stripe/webhook.js.map +0 -1
  293. package/lib/utils/content-type.d.ts.map +0 -1
  294. package/lib/utils/content-type.js.map +0 -1
  295. package/lib/utils/retry.d.ts.map +0 -1
  296. package/lib/utils/retry.js.map +0 -1
  297. package/src/$.ts +0 -69
  298. package/src/alchemize.ts +0 -195
  299. package/src/fs.ts +0 -47
  300. package/src/global.ts +0 -63
  301. package/src/input.ts +0 -19
  302. package/src/main.ts +0 -34
  303. package/src/output.ts +0 -75
  304. package/src/print.ts +0 -18
  305. package/src/serde.ts +0 -46
  306. package/src/slug.ts +0 -3
  307. /package/src/{utils → util}/content-type.ts +0 -0
  308. /package/src/{encrypt.ts → util/encrypt.ts} +0 -0
  309. /package/src/{error.ts → util/ignore.ts} +0 -0
  310. /package/src/{utils → util}/retry.ts +0 -0
@@ -0,0 +1,67 @@
1
+ import { destroy } from "./destroy";
2
+ import { Scope } from "./scope";
3
+ import { secret } from "./secret";
4
+ import type { StateStoreType } from "./state";
5
+ export type alchemy = Alchemy;
6
+ export declare const alchemy: Alchemy;
7
+ export interface Alchemy {
8
+ scope: typeof scope;
9
+ run: typeof run;
10
+ destroy: typeof destroy;
11
+ secret: typeof secret;
12
+ (...parameters: Parameters<typeof scope>): ReturnType<typeof scope>;
13
+ }
14
+ export interface AlchemyOptions {
15
+ /**
16
+ * The name of the application.
17
+ */
18
+ appName?: string;
19
+ /**
20
+ * Determines whether the resources will be created/updated or deleted.
21
+ *
22
+ * @default "up"
23
+ */
24
+ phase?: "up" | "destroy";
25
+ /**
26
+ * Name to scope the resource state under (e.g. `.alchemy/{stage}/..`).
27
+ *
28
+ * @default - your POSIX username
29
+ */
30
+ stage?: string;
31
+ /**
32
+ * If true, will not prune resources that were dropped from the root stack.
33
+ *
34
+ * @default true
35
+ */
36
+ destroyOrphans?: boolean;
37
+ /**
38
+ * A custom state store to use instead of the default file system store.
39
+ */
40
+ stateStore?: StateStoreType;
41
+ /**
42
+ * A custom scope to use as a parent.
43
+ */
44
+ parent?: Scope;
45
+ /**
46
+ * If true, will not print any Create/Update/Delete messages.
47
+ *
48
+ * @default false
49
+ */
50
+ quiet?: boolean;
51
+ /**
52
+ * A passphrase to use to encrypt/decrypt secrets.
53
+ */
54
+ password?: string;
55
+ }
56
+ /**
57
+ * Enter a new scope synchronously.
58
+ * @param options
59
+ * @returns
60
+ */
61
+ declare function scope(id: string | undefined, options?: AlchemyOptions): Scope;
62
+ declare function run<T>(...args: [id: string, fn: (this: Scope, scope: Scope) => Promise<T>] | [
63
+ id: string,
64
+ options: AlchemyOptions,
65
+ fn: (this: Scope, scope: Scope) => Promise<T>
66
+ ]): Promise<T>;
67
+ export {};
package/lib/alchemy.js ADDED
@@ -0,0 +1,40 @@
1
+ import { destroy } from "./destroy";
2
+ import { Scope } from "./scope";
3
+ import { secret } from "./secret";
4
+ // TODO: support browser
5
+ const DEFAULT_STAGE = process.env.ALCHEMY_STAGE ?? process.env.USER ?? "dev";
6
+ function _alchemy(appName, options) {
7
+ return scope(undefined, {
8
+ ...options,
9
+ appName,
10
+ stage: options.stage,
11
+ });
12
+ }
13
+ _alchemy.destroy = destroy;
14
+ _alchemy.run = run;
15
+ _alchemy.scope = scope;
16
+ _alchemy.secret = secret;
17
+ export const alchemy = _alchemy;
18
+ /**
19
+ * Enter a new scope synchronously.
20
+ * @param options
21
+ * @returns
22
+ */
23
+ function scope(id, options) {
24
+ const scope = new Scope({
25
+ ...options,
26
+ appName: options?.appName,
27
+ stage: options?.stage ?? DEFAULT_STAGE,
28
+ scopeName: id,
29
+ parent: options?.parent ?? Scope.get(),
30
+ });
31
+ scope.enter();
32
+ return scope;
33
+ }
34
+ async function run(...args) {
35
+ const [id, options, fn] = typeof args[1] === "function"
36
+ ? [args[0], undefined, args[1]]
37
+ : args;
38
+ await using scope = alchemy.scope(id, options);
39
+ return await fn.bind(scope)(scope);
40
+ }
package/lib/apply.d.ts CHANGED
@@ -1,23 +1,6 @@
1
- import { type Output, type Resolved } from "./output";
2
- import { type Scope as IScope } from "./scope";
3
- import type { StateStore } from "./state";
1
+ import { type PendingResource, type Resource, type ResourceProps } from "./resource";
4
2
  export interface ApplyOptions {
5
- stage: string;
6
- scope: IScope;
7
- stateStore: StateStore;
8
3
  quiet?: boolean;
4
+ alwaysUpdate?: boolean;
9
5
  }
10
- /**
11
- * Apply a sub-graph to produce a resource.
12
- * @param output A sub-graph that produces a resource.
13
- * @returns The resource properties.
14
- */
15
- export declare function apply<T>(output: T, options?: Partial<ApplyOptions>): Promise<Resolved<T>>;
16
- declare class Evaluated<T> {
17
- readonly value: T;
18
- readonly deps: string[];
19
- constructor(value: T, deps?: string[]);
20
- }
21
- export declare function evaluate<T>(output: T | Output<T>, options: ApplyOptions): Promise<Evaluated<T>>;
22
- export {};
23
- //# sourceMappingURL=apply.d.ts.map
6
+ export declare function apply<Out extends Resource>(resource: PendingResource<Out>, props: ResourceProps, options?: ApplyOptions): Promise<Awaited<Out>>;
package/lib/apply.js CHANGED
@@ -1,88 +1,92 @@
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);
36
- }
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]));
50
- }
51
- catch (error) {
52
- console.error(error);
53
- reject(error);
54
- }
55
- return promise;
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
+ const quiet = props.quiet ?? scope.quiet;
8
+ await scope.init();
9
+ let state = (await scope.state.get(resource.ID));
10
+ const provider = PROVIDERS.get(resource.Kind);
11
+ if (provider === undefined) {
12
+ throw new Error(`Provider "${resource.Kind}" not found`);
56
13
  }
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
- ]);
14
+ if (state === undefined) {
15
+ state = {
16
+ kind: resource.Kind,
17
+ id: resource.ID,
18
+ fqn: resource.FQN,
19
+ seq: resource.Seq,
20
+ status: "creating",
21
+ data: {},
22
+ output: {
23
+ ID: resource.ID,
24
+ FQN: resource.FQN,
25
+ Kind: resource.Kind,
26
+ Scope: scope,
27
+ Seq: resource.Seq,
28
+ },
29
+ // deps: [...deps],
30
+ props,
31
+ };
32
+ await scope.state.set(resource.ID, state);
67
33
  }
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);
34
+ const alwaysUpdate = options?.alwaysUpdate ?? provider.options?.alwaysUpdate ?? false;
35
+ // Skip update if inputs haven't changed and resource is in a stable state
36
+ if (state.status === "created" || state.status === "updated") {
37
+ if (JSON.stringify(state.props) === JSON.stringify(serialize(scope, props)) &&
38
+ alwaysUpdate !== true) {
39
+ if (!quiet) {
40
+ console.log(`Skip: "${resource.FQN}" (no changes)`);
41
+ }
42
+ // if (resourceState.output !== undefined) {
43
+ // resource[Provide](resourceState.output);
44
+ // }
45
+ return state.output;
46
+ }
74
47
  }
75
- else if (output instanceof Secret) {
76
- return new Evaluated(output);
48
+ const phase = state.status === "creating" ? "create" : "update";
49
+ state.status = phase === "create" ? "creating" : "updating";
50
+ state.oldProps = state.props;
51
+ state.props = props;
52
+ if (!quiet) {
53
+ console.log(`${phase === "create" ? "Create" : "Update"}: "${resource.FQN}"`);
77
54
  }
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);
55
+ await scope.state.set(resource.ID, state);
56
+ let isReplaced = false;
57
+ const ctx = context({
58
+ scope,
59
+ phase,
60
+ kind: resource.Kind,
61
+ id: resource.ID,
62
+ fqn: resource.FQN,
63
+ seq: resource.Seq,
64
+ state,
65
+ replace: () => {
66
+ if (isReplaced) {
67
+ console.warn(`Resource ${resource.Kind} ${resource.FQN} is already marked as REPLACE`);
68
+ return;
69
+ }
70
+ isReplaced = true;
71
+ },
72
+ });
73
+ const output = await alchemy.run(resource.ID, async () => provider.handler.bind(ctx)(resource.ID, props));
74
+ if (!quiet) {
75
+ console.log(`${phase === "create" ? "Created" : "Updated"}: "${resource.FQN}"`);
84
76
  }
85
- // Base case: primitive value
86
- return new Evaluated(output);
77
+ await scope.state.set(resource.ID, {
78
+ kind: resource.Kind,
79
+ id: resource.ID,
80
+ fqn: resource.FQN,
81
+ seq: resource.Seq,
82
+ data: state.data,
83
+ status: phase === "create" ? "created" : "updated",
84
+ output,
85
+ props,
86
+ // deps: [...deps],
87
+ });
88
+ // if (output !== undefined) {
89
+ // resource[Provide](output as Out);
90
+ // }
91
+ return output;
87
92
  }
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));