alchemy 0.1.17 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) 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 -78
  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 +4 -3
  38. package/lib/cloudflare/bindings.js +3 -2
  39. package/lib/cloudflare/bound.d.ts +7 -0
  40. package/lib/cloudflare/bound.js +1 -0
  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 +13 -13
  66. package/lib/cloudflare/worker.js +43 -43
  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 +6 -7
  86. package/lib/github/secret.js +30 -36
  87. package/lib/index.d.ts +7 -10
  88. package/lib/index.js +6 -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 +7 -0
  94. package/lib/secret.js +17 -0
  95. package/lib/state.d.ts +14 -10
  96. package/lib/state.js +15 -13
  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/util/encrypt.d.ts +16 -0
  110. package/lib/util/encrypt.js +44 -0
  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/util/serde.js +46 -0
  117. package/lib/util/slugify.d.ts +1 -0
  118. package/lib/util/slugify.js +3 -0
  119. package/package.json +5 -7
  120. package/src/alchemy.ts +120 -0
  121. package/src/apply.ts +109 -111
  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 +12 -2
  134. package/src/cloudflare/bound.ts +18 -0
  135. package/src/cloudflare/bucket.ts +40 -48
  136. package/src/cloudflare/durable-object-namespace.ts +0 -10
  137. package/src/cloudflare/generate-asset-manifest.ts +1 -1
  138. package/src/cloudflare/kv-namespace.ts +35 -33
  139. package/src/cloudflare/static-site-router.ts +0 -3
  140. package/src/cloudflare/static-site.ts +43 -59
  141. package/src/cloudflare/worker.ts +76 -64
  142. package/src/context.ts +122 -0
  143. package/src/destroy.ts +124 -73
  144. package/src/{esbuild.ts → esbuild/bundle.ts} +16 -28
  145. package/src/esbuild/index.ts +1 -0
  146. package/src/fs/file.ts +39 -0
  147. package/src/fs/folder.ts +32 -0
  148. package/src/fs/index.ts +2 -0
  149. package/src/github/secret.ts +53 -49
  150. package/src/index.ts +8 -15
  151. package/src/resource.ts +101 -462
  152. package/src/scope.ts +101 -36
  153. package/src/secret.ts +18 -0
  154. package/src/state.ts +30 -20
  155. package/src/stripe/price.ts +17 -22
  156. package/src/stripe/product.ts +17 -22
  157. package/src/stripe/webhook.ts +21 -27
  158. package/src/test/bun.ts +105 -0
  159. package/src/util/encrypt.ts +79 -0
  160. package/src/util/serde.ts +53 -0
  161. package/src/util/slugify.ts +3 -0
  162. package/lib/$.d.ts +0 -12
  163. package/lib/$.d.ts.map +0 -1
  164. package/lib/$.js +0 -42
  165. package/lib/$.js.map +0 -1
  166. package/lib/alchemize.d.ts +0 -43
  167. package/lib/alchemize.d.ts.map +0 -1
  168. package/lib/alchemize.js +0 -112
  169. package/lib/alchemize.js.map +0 -1
  170. package/lib/apply.d.ts.map +0 -1
  171. package/lib/apply.js.map +0 -1
  172. package/lib/aws/account-id.d.ts.map +0 -1
  173. package/lib/aws/account-id.js.map +0 -1
  174. package/lib/aws/bucket.d.ts.map +0 -1
  175. package/lib/aws/bucket.js.map +0 -1
  176. package/lib/aws/function.d.ts.map +0 -1
  177. package/lib/aws/function.js.map +0 -1
  178. package/lib/aws/index.d.ts.map +0 -1
  179. package/lib/aws/index.js.map +0 -1
  180. package/lib/aws/oidc/github-oidc-provider.d.ts.map +0 -1
  181. package/lib/aws/oidc/github-oidc-provider.js.map +0 -1
  182. package/lib/aws/oidc/index.d.ts.map +0 -1
  183. package/lib/aws/oidc/index.js.map +0 -1
  184. package/lib/aws/oidc/oidc-provider.d.ts.map +0 -1
  185. package/lib/aws/oidc/oidc-provider.js.map +0 -1
  186. package/lib/aws/policy.d.ts.map +0 -1
  187. package/lib/aws/policy.js.map +0 -1
  188. package/lib/aws/queue.d.ts.map +0 -1
  189. package/lib/aws/queue.js.map +0 -1
  190. package/lib/aws/role.d.ts.map +0 -1
  191. package/lib/aws/role.js.map +0 -1
  192. package/lib/aws/ses.d.ts.map +0 -1
  193. package/lib/aws/ses.js.map +0 -1
  194. package/lib/aws/table.d.ts.map +0 -1
  195. package/lib/aws/table.js.map +0 -1
  196. package/lib/cloudflare/api.d.ts.map +0 -1
  197. package/lib/cloudflare/api.js.map +0 -1
  198. package/lib/cloudflare/asset-manifest.d.ts.map +0 -1
  199. package/lib/cloudflare/asset-manifest.js.map +0 -1
  200. package/lib/cloudflare/auth.d.ts.map +0 -1
  201. package/lib/cloudflare/auth.js.map +0 -1
  202. package/lib/cloudflare/bindings.d.ts.map +0 -1
  203. package/lib/cloudflare/bindings.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/error.d.ts.map +0 -1
  233. package/lib/error.js.map +0 -1
  234. package/lib/esbuild.d.ts.map +0 -1
  235. package/lib/esbuild.js.map +0 -1
  236. package/lib/fs.d.ts +0 -12
  237. package/lib/fs.d.ts.map +0 -1
  238. package/lib/fs.js +0 -41
  239. package/lib/fs.js.map +0 -1
  240. package/lib/github/client.d.ts.map +0 -1
  241. package/lib/github/client.js.map +0 -1
  242. package/lib/github/index.d.ts.map +0 -1
  243. package/lib/github/index.js.map +0 -1
  244. package/lib/github/secret.d.ts.map +0 -1
  245. package/lib/github/secret.js.map +0 -1
  246. package/lib/global.d.ts +0 -16
  247. package/lib/global.d.ts.map +0 -1
  248. package/lib/global.js +0 -42
  249. package/lib/global.js.map +0 -1
  250. package/lib/index.d.ts.map +0 -1
  251. package/lib/index.js.map +0 -1
  252. package/lib/input.d.ts +0 -6
  253. package/lib/input.d.ts.map +0 -1
  254. package/lib/input.js +0 -2
  255. package/lib/input.js.map +0 -1
  256. package/lib/main.d.ts +0 -3
  257. package/lib/main.d.ts.map +0 -1
  258. package/lib/main.js +0 -32
  259. package/lib/main.js.map +0 -1
  260. package/lib/output.d.ts +0 -24
  261. package/lib/output.d.ts.map +0 -1
  262. package/lib/output.js +0 -23
  263. package/lib/output.js.map +0 -1
  264. package/lib/print.d.ts +0 -7
  265. package/lib/print.d.ts.map +0 -1
  266. package/lib/print.js +0 -10
  267. package/lib/print.js.map +0 -1
  268. package/lib/resource.d.ts.map +0 -1
  269. package/lib/resource.js.map +0 -1
  270. package/lib/scope.d.ts.map +0 -1
  271. package/lib/scope.js.map +0 -1
  272. package/lib/slug.d.ts +0 -2
  273. package/lib/slug.d.ts.map +0 -1
  274. package/lib/slug.js +0 -4
  275. package/lib/slug.js.map +0 -1
  276. package/lib/state.d.ts.map +0 -1
  277. package/lib/state.js.map +0 -1
  278. package/lib/stripe/index.d.ts.map +0 -1
  279. package/lib/stripe/index.js.map +0 -1
  280. package/lib/stripe/price.d.ts.map +0 -1
  281. package/lib/stripe/price.js.map +0 -1
  282. package/lib/stripe/product.d.ts.map +0 -1
  283. package/lib/stripe/product.js.map +0 -1
  284. package/lib/stripe/webhook.d.ts.map +0 -1
  285. package/lib/stripe/webhook.js.map +0 -1
  286. package/lib/utils/content-type.d.ts.map +0 -1
  287. package/lib/utils/content-type.js.map +0 -1
  288. package/lib/utils/retry.d.ts.map +0 -1
  289. package/lib/utils/retry.js.map +0 -1
  290. package/src/$.ts +0 -69
  291. package/src/alchemize.ts +0 -186
  292. package/src/fs.ts +0 -47
  293. package/src/global.ts +0 -63
  294. package/src/input.ts +0 -16
  295. package/src/main.ts +0 -34
  296. package/src/output.ts +0 -71
  297. package/src/print.ts +0 -18
  298. package/src/slug.ts +0 -3
  299. /package/src/{utils → util}/content-type.ts +0 -0
  300. /package/src/{error.ts → util/ignore.ts} +0 -0
  301. /package/src/{utils → util}/retry.ts +0 -0
package/lib/context.js ADDED
@@ -0,0 +1,36 @@
1
+ import { DestroyedSignal } from "./destroy";
2
+ export function context({ scope, phase, kind, id, fqn, seq, state, replace, }) {
3
+ function create(props) {
4
+ return {
5
+ ...props,
6
+ Kind: kind,
7
+ ID: id,
8
+ FQN: fqn,
9
+ Scope: scope,
10
+ Seq: seq,
11
+ };
12
+ }
13
+ return Object.assign(create, {
14
+ stage: scope.stage,
15
+ scope,
16
+ id: id,
17
+ fqn: fqn,
18
+ phase,
19
+ output: state.output,
20
+ replace,
21
+ get: (key) => state.data[key],
22
+ set: async (key, value) => {
23
+ state.data[key] = value;
24
+ },
25
+ delete: async (key) => {
26
+ const value = state.data[key];
27
+ delete state.data[key];
28
+ return value;
29
+ },
30
+ quiet: scope.quiet,
31
+ destroy: () => {
32
+ throw new DestroyedSignal();
33
+ },
34
+ create,
35
+ });
36
+ }
package/lib/destroy.d.ts CHANGED
@@ -1,19 +1,16 @@
1
- import type { Output } from "./output";
2
- import { Provider, ResourceID } from "./resource";
3
- import { type Scope } from "./scope";
4
- import type { State, StateStore } from "./state";
1
+ import { type Resource } from "./resource";
2
+ import { Scope } from "./scope";
3
+ export declare class DestroyedSignal extends Error {
4
+ }
5
5
  export interface DestroyOptions {
6
- stage?: string;
7
- stateStore?: StateStore;
8
- scope?: Scope;
9
6
  quiet?: boolean;
7
+ strategy?: "sequential" | "parallel";
10
8
  }
11
9
  /**
12
10
  * Prune all resources from an Output and "down", i.e. that branches from it.
13
11
  */
14
- export declare function destroy<T>(output: Output<T>, options?: DestroyOptions): Promise<void>;
15
- /**
16
- * @internal
17
- */
18
- export declare function destroy<T>(stage: string, scope: Scope, resourceID: ResourceID, resourceState: State, resourceProvider: Provider, stateStore: StateStore, options: DestroyOptions): Promise<void>;
19
- //# sourceMappingURL=destroy.d.ts.map
12
+ export declare function destroy<Type extends string>(...args: [scope: Scope, options?: DestroyOptions] | [resource: Resource<Type> | undefined | null, options?: DestroyOptions]): Promise<void>;
13
+ export declare namespace destroy {
14
+ function all(resources: Resource[], options?: DestroyOptions): Promise<void>;
15
+ function sequentially(...resources: (Resource<string> | undefined | null)[]): Promise<void>;
16
+ }
package/lib/destroy.js CHANGED
@@ -1,54 +1,115 @@
1
- import { defaultStage, defaultStateStore } from "./global";
2
- import { Provider, ResourceID, isResource } from "./resource";
3
- import { rootScope } from "./scope";
1
+ import { alchemy } from "./alchemy";
2
+ import { context } from "./context";
3
+ import { PROVIDERS } from "./resource";
4
+ import { Scope } from "./scope";
5
+ export class DestroyedSignal extends Error {
6
+ }
7
+ function isScopeArgs(a) {
8
+ return a[0] instanceof Scope;
9
+ }
10
+ /**
11
+ * Prune all resources from an Output and "down", i.e. that branches from it.
12
+ */
4
13
  export async function destroy(...args) {
5
- let resourceID;
6
- let resourceState;
7
- let resourceProvider;
8
- let stage;
9
- let stateStore;
10
- let scope = undefined;
11
- let options = undefined;
12
- if (args.length === 7) {
13
- stage = args[0];
14
- scope = args[1];
15
- resourceID = args[2];
16
- resourceState = args[3];
17
- resourceProvider = args[4];
18
- stateStore = args[5];
19
- options = args[6];
20
- }
21
- else if (isResource(args[0])) {
22
- const resource = args[0];
23
- // stage = args[1]?.stage ?? defaultStage;
24
- resourceID = resource[ResourceID];
25
- stage = args[1]?.stage ?? defaultStage;
26
- scope = args[1]?.scope ?? rootScope;
27
- const statePath = scope.getScopePath(stage);
28
- stateStore = args[1]?.stateStore ?? new defaultStateStore(statePath);
29
- // First destroy all dependencies
30
- const _resourceState = await stateStore.get(resourceID);
31
- if (_resourceState === undefined) {
32
- // we have no record of this resource, we must assume it's already deleted
33
- return;
34
- }
35
- resourceState = _resourceState;
36
- resourceProvider = resource[Provider];
37
- options = args[1];
14
+ if (isScopeArgs(args)) {
15
+ const [scope, options] = args;
16
+ const strategy = options?.strategy ?? "sequential";
17
+ // destroy all active resources
18
+ await destroy.all(Array.from(scope.resources.values()), {
19
+ strategy,
20
+ });
21
+ // then detect orphans and destroy them
22
+ const orphans = await scope.state.all();
23
+ await destroy.all(Object.values(orphans).map((orphan) => ({
24
+ ...orphan.output,
25
+ Scope: scope,
26
+ })), options);
27
+ // finally, destroy the scope container
28
+ await scope.deinit();
29
+ return;
38
30
  }
39
- else {
40
- console.log(args[0]);
41
- throw new Error("Not implemented: must handle destroy a Output chain");
31
+ const [instance, options] = args;
32
+ if (!instance) {
33
+ return;
42
34
  }
35
+ const Provider = PROVIDERS.get(instance.Kind);
36
+ if (!Provider) {
37
+ throw new Error(`Cannot destroy resource type ${instance.Kind} - no provider found. You may need to import the provider in your alchemy.config.ts.`);
38
+ }
39
+ const scope = instance.Scope;
40
+ if (!scope) {
41
+ console.warn(`Resource "${instance.FQN}" has no scope`);
42
+ }
43
+ const quiet = options?.quiet ?? scope.quiet;
43
44
  try {
44
- await resourceProvider.delete(stage, scope, resourceID, resourceState, resourceState.inputs, options ?? {
45
- quiet: false,
45
+ if (!quiet) {
46
+ console.log(`Delete: "${instance.FQN}"`);
47
+ }
48
+ const state = (await scope.state.get(instance.ID));
49
+ if (state === undefined) {
50
+ console.warn(`Resource "${instance.FQN}" not found`);
51
+ return;
52
+ }
53
+ const ctx = context({
54
+ scope,
55
+ phase: "delete",
56
+ kind: instance.Kind,
57
+ id: instance.ID,
58
+ fqn: instance.FQN,
59
+ seq: instance.Seq,
60
+ state,
61
+ replace: () => {
62
+ throw new Error("Cannot replace a resource that is being deleted");
63
+ },
46
64
  });
65
+ let nestedScope;
66
+ try {
67
+ // BUG: this does not restore persisted scope
68
+ await alchemy.run(instance.ID, async (scope) => {
69
+ nestedScope = scope;
70
+ return Provider.handler.bind(ctx)(instance.ID, state.props);
71
+ });
72
+ }
73
+ catch (err) {
74
+ if (err instanceof DestroyedSignal) {
75
+ // TODO: should we fail if the DestroyedSignal is not thrown?
76
+ }
77
+ else {
78
+ throw err;
79
+ }
80
+ }
81
+ if (nestedScope) {
82
+ await destroy(nestedScope, options);
83
+ }
84
+ await scope.delete(instance.ID);
85
+ if (!quiet) {
86
+ console.log(`Deleted: "${instance.FQN}"`);
87
+ }
47
88
  }
48
89
  catch (error) {
49
90
  console.error(error);
50
91
  throw error;
51
92
  }
52
- await stateStore.delete(resourceID);
53
93
  }
54
- //# sourceMappingURL=destroy.js.map
94
+ (function (destroy) {
95
+ async function all(resources, options) {
96
+ if (options?.strategy !== "parallel") {
97
+ const sorted = resources.sort((a, b) => b.Seq - a.Seq);
98
+ for (const resource of sorted) {
99
+ await destroy(resource);
100
+ }
101
+ }
102
+ else {
103
+ await Promise.all(resources.map((resource) => destroy(resource, options)));
104
+ }
105
+ }
106
+ destroy.all = all;
107
+ async function sequentially(...resources) {
108
+ for (const resource of resources) {
109
+ if (resource) {
110
+ await destroy(resource);
111
+ }
112
+ }
113
+ }
114
+ destroy.sequentially = sequentially;
115
+ })(destroy || (destroy = {}));
@@ -1,4 +1,6 @@
1
1
  import * as esbuild from "esbuild";
2
+ import type { Context } from "../context";
3
+ import { Resource } from "../resource";
2
4
  export interface BundleProps {
3
5
  /**
4
6
  * Entry point for the bundle
@@ -41,7 +43,7 @@ export interface BundleProps {
41
43
  */
42
44
  options?: Partial<esbuild.BuildOptions>;
43
45
  }
44
- export interface BundleOutput {
46
+ export interface Bundle extends Resource<"esbuild::Bundle"> {
45
47
  /**
46
48
  * Path to the bundled file
47
49
  */
@@ -51,21 +53,7 @@ export interface BundleOutput {
51
53
  */
52
54
  hash: string;
53
55
  }
54
- declare const Bundle_base: import("./resource").Provider<string, [props: BundleProps], BundleOutput>;
55
- export declare class Bundle extends Bundle_base {
56
- /**
57
- * Get the metafile from the last build
58
- */
59
- getMetafile(ctx: {
60
- get<T>(key: string): Promise<T | undefined>;
61
- }): Promise<esbuild.Metafile | undefined>;
62
- /**
63
- * Get the hash from the last build
64
- */
65
- getHash(ctx: {
66
- get<T>(key: string): Promise<T | undefined>;
67
- }): Promise<string | undefined>;
68
- }
56
+ export declare const Bundle: ((this: Context<Bundle>, id: string, props: BundleProps) => Promise<Bundle>) | (((this: any, id: string, props: BundleProps) => never) & (new (_: never) => never));
69
57
  export declare function bundle(props: BundleProps): Promise<esbuild.BuildResult<{
70
58
  bundle: boolean;
71
59
  splitting?: boolean;
@@ -148,5 +136,3 @@ export declare function bundle(props: BundleProps): Promise<esbuild.BuildResult<
148
136
  logOverride?: Record<string, esbuild.LogLevel>;
149
137
  tsconfigRaw?: string | esbuild.TsconfigRaw;
150
138
  }>>;
151
- export {};
152
- //# sourceMappingURL=esbuild.d.ts.map
@@ -2,46 +2,33 @@ import * as esbuild from "esbuild";
2
2
  import crypto from "node:crypto";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
- import { Resource } from "./resource";
6
- export class Bundle extends Resource("esbuild::Bundle", {
5
+ import { Resource } from "../resource";
6
+ export const Bundle = Resource("esbuild::Bundle", {
7
7
  alwaysUpdate: true,
8
- }, async (ctx, props) => {
8
+ }, async function (id, props) {
9
9
  // Determine output path
10
10
  const outputPath = getOutputPath(props);
11
11
  // Ensure output directory exists
12
12
  await fs.promises.mkdir(path.dirname(outputPath), { recursive: true });
13
- if (ctx.event === "delete") {
13
+ if (this.phase === "delete") {
14
14
  await fs.promises.unlink(outputPath).catch(() => { });
15
15
  // Also clean up sourcemap if it exists
16
16
  await fs.promises.unlink(outputPath + ".map").catch(() => { });
17
- return { path: outputPath, hash: "" };
17
+ return this.destroy();
18
18
  }
19
19
  const result = await bundle(props);
20
20
  // Calculate hash of the output
21
21
  const contents = await fs.promises.readFile(outputPath);
22
22
  const hash = crypto.createHash("sha256").update(contents).digest("hex");
23
23
  // Store metadata in context
24
- await ctx.set("metafile", result.metafile);
25
- await ctx.set("hash", hash);
24
+ await this.set("metafile", result.metafile);
25
+ await this.set("hash", hash);
26
26
  // Return output info
27
- return {
27
+ return this({
28
28
  path: outputPath,
29
29
  hash,
30
- };
31
- }) {
32
- /**
33
- * Get the metafile from the last build
34
- */
35
- async getMetafile(ctx) {
36
- return ctx.get("metafile");
37
- }
38
- /**
39
- * Get the hash from the last build
40
- */
41
- async getHash(ctx) {
42
- return ctx.get("hash");
43
- }
44
- }
30
+ });
31
+ });
45
32
  export async function bundle(props) {
46
33
  const outputPath = getOutputPath(props);
47
34
  // Build the bundle
@@ -64,4 +51,3 @@ function getOutputPath(props) {
64
51
  return (props.outfile ||
65
52
  path.join(props.outdir || "dist", path.basename(props.entryPoint, path.extname(props.entryPoint)) + ".js"));
66
53
  }
67
- //# sourceMappingURL=esbuild.js.map
@@ -0,0 +1 @@
1
+ export * from "./bundle";
@@ -0,0 +1 @@
1
+ export * from "./bundle";
@@ -0,0 +1,13 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ export interface File extends Resource<"fs::File"> {
4
+ path: string;
5
+ content: string;
6
+ }
7
+ export declare const File: ((this: Context<File>, id: string, { path: filePath, content, }: {
8
+ path: string;
9
+ content: string;
10
+ }) => Promise<File>) | (((this: any, id: string, props: {
11
+ path: string;
12
+ content: string;
13
+ }) => never) & (new (_: never) => never));
package/lib/fs/file.js ADDED
@@ -0,0 +1,20 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { Resource } from "../resource";
4
+ import { ignore } from "../util/ignore";
5
+ export const File = Resource("fs::File", async function (id, { path: filePath, content, }) {
6
+ if (this.phase === "delete") {
7
+ await ignore("ENOENT", async () => fs.promises.unlink(filePath));
8
+ return this.destroy();
9
+ }
10
+ else {
11
+ await fs.promises.mkdir(path.dirname(filePath), {
12
+ recursive: true,
13
+ });
14
+ await fs.promises.writeFile(filePath, content);
15
+ }
16
+ return this({
17
+ path: filePath,
18
+ content,
19
+ });
20
+ });
@@ -0,0 +1,10 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ export interface Folder extends Resource<"fs::Folder"> {
4
+ path: string;
5
+ }
6
+ export declare const Folder: ((this: Context<Folder>, id: string, { path: dirPath }: {
7
+ path: string;
8
+ }) => Promise<Folder>) | (((this: any, id: string, props: {
9
+ path: string;
10
+ }) => never) & (new (_: never) => never));
@@ -0,0 +1,16 @@
1
+ import fs from "node:fs";
2
+ import { Resource } from "../resource";
3
+ import { ignore } from "../util/ignore";
4
+ export const Folder = Resource("fs::Folder", async function (id, { path: dirPath }) {
5
+ if (this.phase === "delete") {
6
+ // we just do a best effort attempt
7
+ await ignore(["ENOENT", "ENOTEMPTY"], async () => fs.promises.rmdir(dirPath));
8
+ return this.destroy();
9
+ }
10
+ else {
11
+ await ignore("EEXIST", async () => fs.promises.mkdir(dirPath, { recursive: true }));
12
+ }
13
+ return this({
14
+ path: dirPath,
15
+ });
16
+ });
@@ -0,0 +1,2 @@
1
+ export * from "./file";
2
+ export * from "./folder";
@@ -0,0 +1,2 @@
1
+ export * from "./file";
2
+ export * from "./folder";
@@ -31,4 +31,3 @@ export declare function createGitHubClient(options?: {
31
31
  * @param repo Repository name
32
32
  */
33
33
  export declare function verifyGitHubAuth(octokit: Octokit, owner: string, repo: string): Promise<void>;
34
- //# sourceMappingURL=client.d.ts.map
@@ -88,4 +88,3 @@ export async function verifyGitHubAuth(octokit, owner, repo) {
88
88
  }
89
89
  }
90
90
  }
91
- //# sourceMappingURL=client.js.map
@@ -1,2 +1 @@
1
1
  export * from "./secret";
2
- //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1 @@
1
1
  export * from "./secret";
2
- //# sourceMappingURL=index.js.map
@@ -1,3 +1,6 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ import type { Secret } from "../secret";
1
4
  /**
2
5
  * Properties for creating or updating a GitHub Secret
3
6
  */
@@ -17,7 +20,7 @@ export interface GitHubSecretProps {
17
20
  /**
18
21
  * Secret value (will be stored securely on GitHub)
19
22
  */
20
- value: string;
23
+ value: Secret;
21
24
  /**
22
25
  * Optional GitHub API token (overrides environment variable)
23
26
  */
@@ -26,7 +29,7 @@ export interface GitHubSecretProps {
26
29
  /**
27
30
  * Output returned after Secret creation/update
28
31
  */
29
- export interface GitHubSecretOutput extends Omit<GitHubSecretProps, "value"> {
32
+ export interface GitHubSecretOutput extends Resource<"github::Secret">, Omit<GitHubSecretProps, "value"> {
30
33
  /**
31
34
  * The ID of the resource
32
35
  */
@@ -36,11 +39,7 @@ export interface GitHubSecretOutput extends Omit<GitHubSecretProps, "value"> {
36
39
  */
37
40
  updatedAt: string;
38
41
  }
39
- declare const GitHubSecret_base: import("../resource").Provider<"github::Secret", [props: GitHubSecretProps], GitHubSecretOutput>;
40
42
  /**
41
43
  * Resource for managing GitHub repository secrets
42
44
  */
43
- export declare class GitHubSecret extends GitHubSecret_base {
44
- }
45
- export {};
46
- //# sourceMappingURL=secret.d.ts.map
45
+ export declare const GitHubSecret: ((this: Context<GitHubSecretOutput>, id: string, props: GitHubSecretProps) => Promise<GitHubSecretOutput>) | (((this: any, id: string, props: GitHubSecretProps) => never) & (new (_: never) => never));
@@ -1,38 +1,19 @@
1
1
  import sodium from "libsodium-wrappers";
2
2
  import { Resource } from "../resource";
3
3
  import { createGitHubClient, verifyGitHubAuth } from "./client";
4
- /**
5
- * Encrypt a value for GitHub using libsodium
6
- * Based on GitHub's documentation for encrypting secrets
7
- *
8
- * @param value - The secret value to encrypt
9
- * @param publicKey - The base64-encoded public key from GitHub
10
- * @returns The base64-encoded encrypted value
11
- */
12
- async function encryptValue(value, publicKey) {
13
- // Initialize libsodium
14
- await sodium.ready;
15
- // Convert the public key from base64 to binary
16
- const binKey = sodium.from_base64(publicKey, sodium.base64_variants.ORIGINAL);
17
- // Convert the message to a Uint8Array
18
- const binMessage = sodium.from_string(value);
19
- // Encrypt the message with the public key using libsodium's sealed box
20
- const encryptedBin = sodium.crypto_box_seal(binMessage, binKey);
21
- // Convert the encrypted message to base64
22
- return sodium.to_base64(encryptedBin, sodium.base64_variants.ORIGINAL);
23
- }
24
4
  /**
25
5
  * Resource for managing GitHub repository secrets
26
6
  */
27
- export class GitHubSecret extends Resource("github::Secret", async (ctx, props) => {
7
+ export const GitHubSecret = Resource("github::Secret", async function (id, props) {
28
8
  // Create authenticated Octokit client - will automatically handle token resolution
9
+ /// TODO: use fetch
29
10
  const octokit = await createGitHubClient({ token: props.token });
30
11
  // Verify authentication and permissions
31
- if (!ctx.quiet) {
12
+ if (!this.quiet) {
32
13
  await verifyGitHubAuth(octokit, props.owner, props.repository);
33
14
  }
34
- if (ctx.event === "delete") {
35
- if (ctx.output?.id) {
15
+ if (this.phase === "delete") {
16
+ if (this.output?.id) {
36
17
  try {
37
18
  // Delete the secret
38
19
  await octokit.rest.actions.deleteRepoSecret({
@@ -52,7 +33,7 @@ export class GitHubSecret extends Resource("github::Secret", async (ctx, props)
52
33
  }
53
34
  }
54
35
  // Return void (a deleted resource has no content)
55
- return undefined;
36
+ return this.destroy();
56
37
  }
57
38
  else {
58
39
  try {
@@ -62,29 +43,24 @@ export class GitHubSecret extends Resource("github::Secret", async (ctx, props)
62
43
  repo: props.repository,
63
44
  });
64
45
  // Encrypt the secret value using libsodium
65
- const encryptedValue = await encryptValue(props.value, publicKey.key);
46
+ const encryptedValue = await encryptString(props.value.unencrypted, publicKey.key);
66
47
  // Create or update the secret with the encrypted value and key_id
67
- const response = await octokit.rest.actions.createOrUpdateRepoSecret({
48
+ await octokit.rest.actions.createOrUpdateRepoSecret({
68
49
  owner: props.owner,
69
50
  repo: props.repository,
70
51
  secret_name: props.name,
71
52
  encrypted_value: encryptedValue,
72
53
  key_id: publicKey.key_id,
73
54
  });
74
- // Log success
75
- if (!ctx.quiet) {
76
- console.log(`Successfully created/updated secret: ${props.name}`);
77
- }
78
55
  // GitHub doesn't return the secret details on create/update, so we need to construct it
79
- const output = {
56
+ return this({
80
57
  id: `${props.owner}/${props.repository}/${props.name}`,
81
58
  owner: props.owner,
82
59
  repository: props.repository,
83
60
  name: props.name,
84
61
  token: props.token,
85
62
  updatedAt: new Date().toISOString(),
86
- };
87
- return output;
63
+ });
88
64
  }
89
65
  catch (error) {
90
66
  if (error.status === 403 &&
@@ -98,6 +74,24 @@ export class GitHubSecret extends Resource("github::Secret", async (ctx, props)
98
74
  throw error;
99
75
  }
100
76
  }
101
- }) {
77
+ });
78
+ /**
79
+ * Encrypt a value for GitHub using libsodium
80
+ * Based on GitHub's documentation for encrypting secrets
81
+ *
82
+ * @param value - The secret value to encrypt
83
+ * @param publicKey - The base64-encoded public key from GitHub
84
+ * @returns The base64-encoded encrypted value
85
+ */
86
+ async function encryptString(value, publicKey) {
87
+ // Initialize libsodium
88
+ await sodium.ready;
89
+ // Convert the public key from base64 to binary
90
+ const binKey = sodium.from_base64(publicKey, sodium.base64_variants.ORIGINAL);
91
+ // Convert the message to a Uint8Array
92
+ const binMessage = sodium.from_string(value);
93
+ // Encrypt the message with the public key using libsodium's sealed box
94
+ const encryptedBin = sodium.crypto_box_seal(binMessage, binKey);
95
+ // Convert the encrypted message to base64
96
+ return sodium.to_base64(encryptedBin, sodium.base64_variants.ORIGINAL);
102
97
  }
103
- //# sourceMappingURL=secret.js.map
package/lib/index.d.ts CHANGED
@@ -1,10 +1,7 @@
1
- export * from "./$";
2
- export * from "./alchemize";
3
- export * from "./error";
4
- export * from "./global";
5
- export * from "./input";
6
- export * from "./output";
7
- export * from "./print";
8
- export { Resource, type Context, type CreateContext, type DeleteContext, type UpdateContext, } from "./resource";
9
- export type { FileSystemStateStore as StateStore } from "./state";
10
- //# sourceMappingURL=index.d.ts.map
1
+ export type * from "./context";
2
+ export * from "./resource";
3
+ export * from "./secret";
4
+ export * from "./state";
5
+ export * from "./util/ignore";
6
+ import { alchemy } from "./alchemy";
7
+ export default alchemy;
package/lib/index.js CHANGED
@@ -1,9 +1,6 @@
1
- export * from "./$";
2
- export * from "./alchemize";
3
- export * from "./error";
4
- export * from "./global";
5
- export * from "./input";
6
- export * from "./output";
7
- export * from "./print";
8
- export { Resource, } from "./resource";
9
- //# sourceMappingURL=index.js.map
1
+ export * from "./resource";
2
+ export * from "./secret";
3
+ export * from "./state";
4
+ export * from "./util/ignore";
5
+ import { alchemy } from "./alchemy";
6
+ export default alchemy;