alchemy-effect 0.3.0 → 0.5.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 (167) hide show
  1. package/bin/alchemy-effect.js +618 -260
  2. package/bin/alchemy-effect.js.map +1 -1
  3. package/lib/apply.d.ts +4 -4
  4. package/lib/apply.d.ts.map +1 -1
  5. package/lib/apply.js +444 -159
  6. package/lib/apply.js.map +1 -1
  7. package/lib/aws/dynamodb/table.provider.d.ts.map +1 -1
  8. package/lib/aws/dynamodb/table.provider.js +11 -2
  9. package/lib/aws/dynamodb/table.provider.js.map +1 -1
  10. package/lib/aws/ec2/index.d.ts +8 -0
  11. package/lib/aws/ec2/index.d.ts.map +1 -1
  12. package/lib/aws/ec2/index.js +8 -0
  13. package/lib/aws/ec2/index.js.map +1 -1
  14. package/lib/aws/ec2/internet-gateway.d.ts +65 -0
  15. package/lib/aws/ec2/internet-gateway.d.ts.map +1 -0
  16. package/lib/aws/ec2/internet-gateway.js +4 -0
  17. package/lib/aws/ec2/internet-gateway.js.map +1 -0
  18. package/lib/aws/ec2/internet-gateway.provider.d.ts +6 -0
  19. package/lib/aws/ec2/internet-gateway.provider.d.ts.map +1 -0
  20. package/lib/aws/ec2/internet-gateway.provider.js +193 -0
  21. package/lib/aws/ec2/internet-gateway.provider.js.map +1 -0
  22. package/lib/aws/ec2/route-table-association.d.ts +63 -0
  23. package/lib/aws/ec2/route-table-association.d.ts.map +1 -0
  24. package/lib/aws/ec2/route-table-association.js +4 -0
  25. package/lib/aws/ec2/route-table-association.js.map +1 -0
  26. package/lib/aws/ec2/route-table-association.provider.d.ts +4 -0
  27. package/lib/aws/ec2/route-table-association.provider.d.ts.map +1 -0
  28. package/lib/aws/ec2/route-table-association.provider.js +121 -0
  29. package/lib/aws/ec2/route-table-association.provider.js.map +1 -0
  30. package/lib/aws/ec2/route-table.d.ts +159 -0
  31. package/lib/aws/ec2/route-table.d.ts.map +1 -0
  32. package/lib/aws/ec2/route-table.js +4 -0
  33. package/lib/aws/ec2/route-table.js.map +1 -0
  34. package/lib/aws/ec2/route-table.provider.d.ts +6 -0
  35. package/lib/aws/ec2/route-table.provider.d.ts.map +1 -0
  36. package/lib/aws/ec2/route-table.provider.js +213 -0
  37. package/lib/aws/ec2/route-table.provider.js.map +1 -0
  38. package/lib/aws/ec2/route.d.ts +155 -0
  39. package/lib/aws/ec2/route.d.ts.map +1 -0
  40. package/lib/aws/ec2/route.js +3 -0
  41. package/lib/aws/ec2/route.js.map +1 -0
  42. package/lib/aws/ec2/route.provider.d.ts +4 -0
  43. package/lib/aws/ec2/route.provider.d.ts.map +1 -0
  44. package/lib/aws/ec2/route.provider.js +166 -0
  45. package/lib/aws/ec2/route.provider.js.map +1 -0
  46. package/lib/aws/ec2/subnet.provider.d.ts.map +1 -1
  47. package/lib/aws/ec2/subnet.provider.js +1 -1
  48. package/lib/aws/ec2/subnet.provider.js.map +1 -1
  49. package/lib/aws/ec2/vpc.d.ts +1 -0
  50. package/lib/aws/ec2/vpc.d.ts.map +1 -1
  51. package/lib/aws/ec2/vpc.provider.d.ts.map +1 -1
  52. package/lib/aws/ec2/vpc.provider.js +32 -10
  53. package/lib/aws/ec2/vpc.provider.js.map +1 -1
  54. package/lib/aws/index.d.ts +2 -3
  55. package/lib/aws/index.d.ts.map +1 -1
  56. package/lib/aws/index.js +2 -1
  57. package/lib/aws/index.js.map +1 -1
  58. package/lib/aws/lambda/function.provider.d.ts +2 -2
  59. package/lib/aws/lambda/function.provider.d.ts.map +1 -1
  60. package/lib/aws/lambda/function.provider.js +39 -42
  61. package/lib/aws/lambda/function.provider.js.map +1 -1
  62. package/lib/aws/sqs/queue.provider.d.ts +3 -4
  63. package/lib/aws/sqs/queue.provider.d.ts.map +1 -1
  64. package/lib/aws/sqs/queue.provider.js +17 -9
  65. package/lib/aws/sqs/queue.provider.js.map +1 -1
  66. package/lib/cli/index.d.ts +183 -100
  67. package/lib/cli/index.d.ts.map +1 -1
  68. package/lib/cloudflare/kv/namespace.client.d.ts +1 -1
  69. package/lib/cloudflare/kv/namespace.provider.d.ts.map +1 -1
  70. package/lib/cloudflare/kv/namespace.provider.js +12 -6
  71. package/lib/cloudflare/kv/namespace.provider.js.map +1 -1
  72. package/lib/cloudflare/r2/bucket.binding.js +1 -1
  73. package/lib/cloudflare/r2/bucket.binding.js.map +1 -1
  74. package/lib/cloudflare/r2/bucket.d.ts +1 -1
  75. package/lib/cloudflare/r2/bucket.d.ts.map +1 -1
  76. package/lib/cloudflare/r2/bucket.provider.d.ts +1 -2
  77. package/lib/cloudflare/r2/bucket.provider.d.ts.map +1 -1
  78. package/lib/cloudflare/r2/bucket.provider.js +23 -12
  79. package/lib/cloudflare/r2/bucket.provider.js.map +1 -1
  80. package/lib/cloudflare/worker/worker.d.ts +2 -2
  81. package/lib/cloudflare/worker/worker.d.ts.map +1 -1
  82. package/lib/cloudflare/worker/worker.provider.d.ts +2 -3
  83. package/lib/cloudflare/worker/worker.provider.d.ts.map +1 -1
  84. package/lib/cloudflare/worker/worker.provider.js +44 -13
  85. package/lib/cloudflare/worker/worker.provider.js.map +1 -1
  86. package/lib/diff.d.ts +8 -6
  87. package/lib/diff.d.ts.map +1 -1
  88. package/lib/diff.js +13 -0
  89. package/lib/diff.js.map +1 -1
  90. package/lib/event.d.ts +1 -1
  91. package/lib/event.d.ts.map +1 -1
  92. package/lib/instance-id.d.ts +12 -0
  93. package/lib/instance-id.d.ts.map +1 -0
  94. package/lib/instance-id.js +16 -0
  95. package/lib/instance-id.js.map +1 -0
  96. package/lib/output.d.ts +4 -2
  97. package/lib/output.d.ts.map +1 -1
  98. package/lib/output.js +18 -4
  99. package/lib/output.js.map +1 -1
  100. package/lib/physical-name.d.ts +25 -1
  101. package/lib/physical-name.d.ts.map +1 -1
  102. package/lib/physical-name.js +50 -2
  103. package/lib/physical-name.js.map +1 -1
  104. package/lib/plan.d.ts +49 -42
  105. package/lib/plan.d.ts.map +1 -1
  106. package/lib/plan.js +417 -137
  107. package/lib/plan.js.map +1 -1
  108. package/lib/provider.d.ts +26 -10
  109. package/lib/provider.d.ts.map +1 -1
  110. package/lib/provider.js +9 -0
  111. package/lib/provider.js.map +1 -1
  112. package/lib/resource.d.ts +3 -2
  113. package/lib/resource.d.ts.map +1 -1
  114. package/lib/resource.js.map +1 -1
  115. package/lib/state.d.ts +86 -9
  116. package/lib/state.d.ts.map +1 -1
  117. package/lib/state.js +21 -18
  118. package/lib/state.js.map +1 -1
  119. package/lib/tags.d.ts +15 -0
  120. package/lib/tags.d.ts.map +1 -1
  121. package/lib/tags.js +27 -0
  122. package/lib/tags.js.map +1 -1
  123. package/lib/test.d.ts +2 -2
  124. package/lib/test.d.ts.map +1 -1
  125. package/lib/test.js +4 -4
  126. package/lib/test.js.map +1 -1
  127. package/lib/todo.d.ts +3 -0
  128. package/lib/todo.d.ts.map +1 -0
  129. package/lib/todo.js +3 -0
  130. package/lib/todo.js.map +1 -0
  131. package/lib/tsconfig.test.tsbuildinfo +1 -1
  132. package/package.json +2 -2
  133. package/src/apply.ts +742 -348
  134. package/src/aws/dynamodb/table.provider.ts +16 -4
  135. package/src/aws/ec2/index.ts +8 -0
  136. package/src/aws/ec2/internet-gateway.provider.ts +316 -0
  137. package/src/aws/ec2/internet-gateway.ts +79 -0
  138. package/src/aws/ec2/route-table-association.provider.ts +214 -0
  139. package/src/aws/ec2/route-table-association.ts +82 -0
  140. package/src/aws/ec2/route-table.provider.ts +306 -0
  141. package/src/aws/ec2/route-table.ts +175 -0
  142. package/src/aws/ec2/route.provider.ts +213 -0
  143. package/src/aws/ec2/route.ts +192 -0
  144. package/src/aws/ec2/subnet.provider.ts +2 -2
  145. package/src/aws/ec2/vpc.provider.ts +36 -11
  146. package/src/aws/ec2/vpc.ts +2 -0
  147. package/src/aws/index.ts +4 -1
  148. package/src/aws/lambda/function.provider.ts +66 -53
  149. package/src/aws/sqs/queue.provider.ts +18 -11
  150. package/src/cloudflare/kv/namespace.provider.ts +19 -14
  151. package/src/cloudflare/r2/bucket.binding.ts +1 -1
  152. package/src/cloudflare/r2/bucket.provider.ts +34 -24
  153. package/src/cloudflare/r2/bucket.ts +1 -1
  154. package/src/cloudflare/worker/worker.provider.ts +43 -13
  155. package/src/cloudflare/worker/worker.ts +2 -2
  156. package/src/diff.ts +35 -17
  157. package/src/event.ts +6 -0
  158. package/src/instance-id.ts +20 -0
  159. package/src/output.ts +29 -5
  160. package/src/physical-name.ts +79 -2
  161. package/src/plan.ts +566 -214
  162. package/src/provider.ts +46 -10
  163. package/src/resource.ts +65 -8
  164. package/src/state.ts +150 -35
  165. package/src/tags.ts +31 -0
  166. package/src/test.ts +5 -5
  167. package/src/todo.ts +4 -0
@@ -0,0 +1,20 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Context from "effect/Context";
3
+
4
+ /** A 16-byte (128-bit) random hex-encoded string representing an physical instance of a logical resource */
5
+ export class InstanceId extends Context.Tag("instance-id")<
6
+ InstanceId,
7
+ string
8
+ >() {}
9
+
10
+ /**
11
+ * @returns Hex-encoded instance ID (16 random bytes)
12
+ */
13
+ export const generateInstanceId = () =>
14
+ Effect.sync(() => {
15
+ const bytes = new Uint8Array(16);
16
+ crypto.getRandomValues(bytes);
17
+ return Array.from(bytes)
18
+ .map((b) => b.toString(16).padStart(2, "0"))
19
+ .join("");
20
+ });
package/src/output.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { pipe } from "effect";
2
- import * as App from "./app.ts";
3
2
  import * as Data from "effect/Data";
4
3
  import * as Effect from "effect/Effect";
4
+ import * as App from "./app.ts";
5
5
  import { isPrimitive } from "./data.ts";
6
6
  import type { From } from "./policy.ts";
7
+ import { getRefMetadata, isRef, ref as stageRef, type Ref } from "./ref.ts";
7
8
  import type { AnyResource, Resource } from "./resource.ts";
8
- import type { IsAny, UnionToIntersection } from "./util.ts";
9
9
  import * as State from "./state.ts";
10
- import { isRef, type Ref, getRefMetadata, ref as stageRef } from "./ref.ts";
10
+ import type { IsAny, UnionToIntersection } from "./util.ts";
11
11
 
12
12
  // a special symbol only used at runtime to probe the Output proxy
13
13
  const ExprSymbol = Symbol.for("alchemy/Expr");
@@ -125,7 +125,7 @@ const proxy = (self: any): any => {
125
125
  return new EffectExpr(self.expr, args[0]);
126
126
  }
127
127
  }
128
- throw new Error("Not callable");
128
+ return undefined;
129
129
  },
130
130
  },
131
131
  );
@@ -367,7 +367,7 @@ export const evaluate: <A, Upstream extends AnyResource, Req>(
367
367
  }),
368
368
  );
369
369
  }
370
- return resource.output;
370
+ return resource.attr;
371
371
  } else if (Array.isArray(expr)) {
372
372
  return yield* Effect.all(expr.map((item) => evaluate(item, upstream)));
373
373
  } else if (typeof expr === "object" && expr !== null) {
@@ -389,6 +389,30 @@ export type Upstream<O extends Output<any, any, any>> =
389
389
  }
390
390
  : never;
391
391
 
392
+ export const hasOutputs = (value: any): value is Output<any, any, any> =>
393
+ Object.keys(upstreamAny(value)).length > 0;
394
+
395
+ export const upstreamAny = (
396
+ value: any,
397
+ ): {
398
+ [ID in string]: Resource;
399
+ } => {
400
+ if (isExpr(value)) {
401
+ return upstream(value);
402
+ } else if (Array.isArray(value)) {
403
+ return Object.assign({}, ...value.map(resolveUpstream));
404
+ } else if (
405
+ value &&
406
+ (typeof value === "object" || typeof value === "function")
407
+ ) {
408
+ return Object.assign(
409
+ {},
410
+ ...Object.values(value).map((value) => resolveUpstream(value)),
411
+ );
412
+ }
413
+ return {};
414
+ };
415
+
392
416
  export const upstream = <E extends Output<any, AnyResource, any>>(
393
417
  expr: E,
394
418
  ): {
@@ -1,7 +1,84 @@
1
1
  import * as Effect from "effect/Effect";
2
2
  import { App } from "./app.ts";
3
+ import { InstanceId } from "./instance-id.ts";
3
4
 
4
- export const physicalName = Effect.fn(function* (id: string) {
5
+ export const createPhysicalName = Effect.fn(function* ({
6
+ id,
7
+ // 16 base32 characters = 80 bits of entropy = 4 × 10⁻⁷
8
+ instanceId,
9
+ suffixLength = 16,
10
+ maxLength = 64,
11
+ }: {
12
+ id: string;
13
+ /**
14
+ * Hex-encoded instance ID (16 random bytes)
15
+ *
16
+ * @default - the InstanceID set by the engine in Context
17
+ */
18
+ instanceId?: string;
19
+ suffixLength?: number;
20
+ /**
21
+ * Maximum length of the physical name.
22
+ *
23
+ * If the name exceeds this length, the human-friendly portion of the name will be truncated to maxLength-suffixLength
24
+ */
25
+ maxLength?: number;
26
+ }) {
5
27
  const app = yield* App;
6
- return `${app.name}-${id}-${app.stage}`;
28
+ const sanitizedId = id.replace(/[^a-zA-Z0-9-_]/g, "-");
29
+ const prefix = `${app.name}-${sanitizedId}-${app.stage}-`;
30
+ const randomId = base32(
31
+ Buffer.from(instanceId ?? (yield* InstanceId), "hex"),
32
+ );
33
+ const suffix = randomId.slice(0, suffixLength);
34
+ const name = `${prefix}${suffix}`;
35
+ if (maxLength && name.length > maxLength) {
36
+ return `${prefix.slice(0, maxLength - suffix.length)}${suffix}`;
37
+ }
38
+ return name;
7
39
  });
40
+
41
+ // Base32 is ideal for physical names because it's denser than hex (5 bits per char vs 4)
42
+ // and compatible with DNS/S3 (as opposed to base64 which contains uppercase letters and symbols).
43
+
44
+ // base32.ts
45
+ // Concise, fast RFC 4648 Base32 encoder (no padding), lowercase output.
46
+ // Charset: a-z2-7 (DNS/S3 friendly)
47
+ const ALPH = "abcdefghijklmnopqrstuvwxyz234567";
48
+
49
+ /**
50
+ * Encode bytes into RFC4648 Base32 (no padding), lowercase.
51
+ *
52
+ * Performance notes:
53
+ * - O(n) single pass, no big-int
54
+ * - Avoids per-byte string concatenation by using a char array
55
+ */
56
+ export function base32(bytes: Uint8Array): string {
57
+ const n = bytes.length;
58
+ if (n === 0) return "";
59
+
60
+ // Base32 length without padding: ceil(n*8/5)
61
+ const outLen = ((n * 8 + 4) / 5) | 0;
62
+ const out = Array.from<string>({ length: outLen });
63
+
64
+ let buffer = 0;
65
+ let bits = 0;
66
+ let o = 0;
67
+
68
+ for (let i = 0; i < n; i++) {
69
+ buffer = (buffer << 8) | bytes[i];
70
+ bits += 8;
71
+
72
+ while (bits >= 5) {
73
+ out[o++] = ALPH[(buffer >>> (bits - 5)) & 31];
74
+ bits -= 5;
75
+ }
76
+ }
77
+
78
+ if (bits > 0) {
79
+ out[o++] = ALPH[(buffer << (5 - bits)) & 31];
80
+ }
81
+
82
+ // outLen computed as exact ceiling; o should match, but slice defensively.
83
+ return o === outLen ? out.join("") : out.slice(0, o).join("");
84
+ }