alchemy 2.0.0-beta.35 → 2.0.0-beta.37

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 (222) hide show
  1. package/bin/exec.js +176 -26
  2. package/bin/exec.js.map +1 -1
  3. package/lib/AWS/Lambda/Function.d.ts.map +1 -1
  4. package/lib/AWS/Lambda/Function.js +22 -2
  5. package/lib/AWS/Lambda/Function.js.map +1 -1
  6. package/lib/Apply.d.ts.map +1 -1
  7. package/lib/Apply.js +6 -1
  8. package/lib/Apply.js.map +1 -1
  9. package/lib/Cli/main.d.ts.map +1 -1
  10. package/lib/Cli/main.js +2 -0
  11. package/lib/Cli/main.js.map +1 -1
  12. package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.d.ts +54 -0
  13. package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.d.ts.map +1 -0
  14. package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.js +17 -0
  15. package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.js.map +1 -0
  16. package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.d.ts +37 -0
  17. package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.d.ts.map +1 -0
  18. package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.js +45 -0
  19. package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.js.map +1 -0
  20. package/lib/Cloudflare/AnalyticsEngine/index.d.ts +3 -0
  21. package/lib/Cloudflare/AnalyticsEngine/index.d.ts.map +1 -0
  22. package/lib/Cloudflare/AnalyticsEngine/index.js +3 -0
  23. package/lib/Cloudflare/AnalyticsEngine/index.js.map +1 -0
  24. package/lib/Cloudflare/D1/D1Connection.d.ts +47 -3
  25. package/lib/Cloudflare/D1/D1Connection.d.ts.map +1 -1
  26. package/lib/Cloudflare/D1/D1Connection.js +62 -5
  27. package/lib/Cloudflare/D1/D1Connection.js.map +1 -1
  28. package/lib/Cloudflare/Images/Images.d.ts +103 -0
  29. package/lib/Cloudflare/Images/Images.d.ts.map +1 -0
  30. package/lib/Cloudflare/Images/Images.js +82 -0
  31. package/lib/Cloudflare/Images/Images.js.map +1 -0
  32. package/lib/Cloudflare/Images/ImagesBinding.d.ts +73 -0
  33. package/lib/Cloudflare/Images/ImagesBinding.d.ts.map +1 -0
  34. package/lib/Cloudflare/Images/ImagesBinding.js +83 -0
  35. package/lib/Cloudflare/Images/ImagesBinding.js.map +1 -0
  36. package/lib/Cloudflare/Images/index.d.ts +3 -0
  37. package/lib/Cloudflare/Images/index.d.ts.map +1 -0
  38. package/lib/Cloudflare/Images/index.js +3 -0
  39. package/lib/Cloudflare/Images/index.js.map +1 -0
  40. package/lib/Cloudflare/Local/SidecarHandlers.js +9 -1
  41. package/lib/Cloudflare/Local/SidecarHandlers.js.map +1 -1
  42. package/lib/Cloudflare/Providers.d.ts.map +1 -1
  43. package/lib/Cloudflare/Providers.js +6 -1
  44. package/lib/Cloudflare/Providers.js.map +1 -1
  45. package/lib/Cloudflare/R2/R2Bucket.d.ts +135 -0
  46. package/lib/Cloudflare/R2/R2Bucket.d.ts.map +1 -1
  47. package/lib/Cloudflare/R2/R2Bucket.js +146 -7
  48. package/lib/Cloudflare/R2/R2Bucket.js.map +1 -1
  49. package/lib/Cloudflare/StateStore/Api.d.ts +6 -1
  50. package/lib/Cloudflare/StateStore/Api.d.ts.map +1 -1
  51. package/lib/Cloudflare/StateStore/Api.js +23 -1
  52. package/lib/Cloudflare/StateStore/Api.js.map +1 -1
  53. package/lib/Cloudflare/StateStore/Store.d.ts +16 -1
  54. package/lib/Cloudflare/StateStore/Store.d.ts.map +1 -1
  55. package/lib/Cloudflare/StateStore/Store.js +22 -5
  56. package/lib/Cloudflare/StateStore/Store.js.map +1 -1
  57. package/lib/Cloudflare/Workers/CronEventSource.d.ts +35 -0
  58. package/lib/Cloudflare/Workers/CronEventSource.d.ts.map +1 -0
  59. package/lib/Cloudflare/Workers/CronEventSource.js +55 -0
  60. package/lib/Cloudflare/Workers/CronEventSource.js.map +1 -0
  61. package/lib/Cloudflare/Workers/InferEnv.d.ts +37 -2
  62. package/lib/Cloudflare/Workers/InferEnv.d.ts.map +1 -1
  63. package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
  64. package/lib/Cloudflare/Workers/LocalWorkerProvider.js +2 -1
  65. package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
  66. package/lib/Cloudflare/Workers/Rpc.d.ts +76 -3
  67. package/lib/Cloudflare/Workers/Rpc.d.ts.map +1 -1
  68. package/lib/Cloudflare/Workers/Rpc.js +197 -13
  69. package/lib/Cloudflare/Workers/Rpc.js.map +1 -1
  70. package/lib/Cloudflare/Workers/Worker.d.ts +26 -6
  71. package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
  72. package/lib/Cloudflare/Workers/Worker.js +183 -41
  73. package/lib/Cloudflare/Workers/Worker.js.map +1 -1
  74. package/lib/Cloudflare/Workers/WorkerBundle.d.ts.map +1 -1
  75. package/lib/Cloudflare/Workers/WorkerBundle.js +15 -5
  76. package/lib/Cloudflare/Workers/WorkerBundle.js.map +1 -1
  77. package/lib/Cloudflare/Workers/Workflow.d.ts +50 -47
  78. package/lib/Cloudflare/Workers/Workflow.d.ts.map +1 -1
  79. package/lib/Cloudflare/Workers/Workflow.js +41 -35
  80. package/lib/Cloudflare/Workers/Workflow.js.map +1 -1
  81. package/lib/Cloudflare/Workers/index.d.ts +1 -0
  82. package/lib/Cloudflare/Workers/index.d.ts.map +1 -1
  83. package/lib/Cloudflare/Workers/index.js +1 -0
  84. package/lib/Cloudflare/Workers/index.js.map +1 -1
  85. package/lib/Cloudflare/index.d.ts +2 -0
  86. package/lib/Cloudflare/index.d.ts.map +1 -1
  87. package/lib/Cloudflare/index.js +2 -0
  88. package/lib/Cloudflare/index.js.map +1 -1
  89. package/lib/Deploy.d.ts +4 -1
  90. package/lib/Deploy.d.ts.map +1 -1
  91. package/lib/Deploy.js +2 -2
  92. package/lib/Deploy.js.map +1 -1
  93. package/lib/Destroy.d.ts +4 -1
  94. package/lib/Destroy.d.ts.map +1 -1
  95. package/lib/Destroy.js +2 -2
  96. package/lib/Destroy.js.map +1 -1
  97. package/lib/Output.d.ts +45 -5
  98. package/lib/Output.d.ts.map +1 -1
  99. package/lib/Output.js +100 -4
  100. package/lib/Output.js.map +1 -1
  101. package/lib/Plan.d.ts.map +1 -1
  102. package/lib/Plan.js +93 -12
  103. package/lib/Plan.js.map +1 -1
  104. package/lib/Platform.d.ts.map +1 -1
  105. package/lib/Platform.js +16 -3
  106. package/lib/Platform.js.map +1 -1
  107. package/lib/Ref.d.ts +4 -1
  108. package/lib/Ref.d.ts.map +1 -1
  109. package/lib/Ref.js +1 -1
  110. package/lib/Ref.js.map +1 -1
  111. package/lib/Resource.d.ts +8 -0
  112. package/lib/Resource.d.ts.map +1 -1
  113. package/lib/Resource.js +10 -0
  114. package/lib/Resource.js.map +1 -1
  115. package/lib/RuntimeContext.d.ts +3 -1
  116. package/lib/RuntimeContext.d.ts.map +1 -1
  117. package/lib/RuntimeContext.js.map +1 -1
  118. package/lib/Secret.d.ts +50 -0
  119. package/lib/Secret.d.ts.map +1 -0
  120. package/lib/Secret.js +23 -0
  121. package/lib/Secret.js.map +1 -0
  122. package/lib/Serverless/Function.d.ts +9 -1
  123. package/lib/Serverless/Function.d.ts.map +1 -1
  124. package/lib/Stack.d.ts +14 -5
  125. package/lib/Stack.d.ts.map +1 -1
  126. package/lib/Stack.js +31 -19
  127. package/lib/Stack.js.map +1 -1
  128. package/lib/State/HttpStateApi.d.ts +15 -1
  129. package/lib/State/HttpStateApi.d.ts.map +1 -1
  130. package/lib/State/HttpStateApi.js +11 -0
  131. package/lib/State/HttpStateApi.js.map +1 -1
  132. package/lib/State/HttpStateStore.d.ts.map +1 -1
  133. package/lib/State/HttpStateStore.js +11 -0
  134. package/lib/State/HttpStateStore.js.map +1 -1
  135. package/lib/State/InMemoryState.d.ts +2 -2
  136. package/lib/State/InMemoryState.d.ts.map +1 -1
  137. package/lib/State/InMemoryState.js +12 -6
  138. package/lib/State/InMemoryState.js.map +1 -1
  139. package/lib/State/LocalState.d.ts.map +1 -1
  140. package/lib/State/LocalState.js +11 -2
  141. package/lib/State/LocalState.js.map +1 -1
  142. package/lib/State/State.d.ts +21 -0
  143. package/lib/State/State.d.ts.map +1 -1
  144. package/lib/Test/Bun.d.ts.map +1 -1
  145. package/lib/Test/Bun.js +30 -7
  146. package/lib/Test/Bun.js.map +1 -1
  147. package/lib/Test/Core.d.ts +17 -2
  148. package/lib/Test/Core.d.ts.map +1 -1
  149. package/lib/Test/Core.js +29 -11
  150. package/lib/Test/Core.js.map +1 -1
  151. package/lib/Test/Vitest.d.ts.map +1 -1
  152. package/lib/Test/Vitest.js +26 -5
  153. package/lib/Test/Vitest.js.map +1 -1
  154. package/lib/Util/LocalhostDns.d.ts +23 -0
  155. package/lib/Util/LocalhostDns.d.ts.map +1 -0
  156. package/lib/Util/LocalhostDns.js +46 -0
  157. package/lib/Util/LocalhostDns.js.map +1 -0
  158. package/lib/Util/PlatformServices.d.ts.map +1 -1
  159. package/lib/Util/PlatformServices.js +2 -0
  160. package/lib/Util/PlatformServices.js.map +1 -1
  161. package/lib/Util/effect.d.ts +7 -0
  162. package/lib/Util/effect.d.ts.map +1 -1
  163. package/lib/Util/effect.js +6 -0
  164. package/lib/Util/effect.js.map +1 -1
  165. package/lib/Variable.d.ts +29 -0
  166. package/lib/Variable.d.ts.map +1 -0
  167. package/lib/Variable.js +9 -0
  168. package/lib/Variable.js.map +1 -0
  169. package/lib/index.d.ts +3 -0
  170. package/lib/index.d.ts.map +1 -1
  171. package/lib/index.js +3 -0
  172. package/lib/index.js.map +1 -1
  173. package/lib/tsconfig.test.tsbuildinfo +1 -1
  174. package/package.json +7 -7
  175. package/src/AWS/Lambda/Function.ts +30 -2
  176. package/src/Apply.ts +8 -1
  177. package/src/Cli/main.ts +3 -0
  178. package/src/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.ts +82 -0
  179. package/src/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.ts +106 -0
  180. package/src/Cloudflare/AnalyticsEngine/index.ts +2 -0
  181. package/src/Cloudflare/D1/D1Connection.ts +95 -12
  182. package/src/Cloudflare/Images/Images.ts +121 -0
  183. package/src/Cloudflare/Images/ImagesBinding.ts +192 -0
  184. package/src/Cloudflare/Images/index.ts +2 -0
  185. package/src/Cloudflare/Local/SidecarHandlers.ts +9 -1
  186. package/src/Cloudflare/Providers.ts +8 -0
  187. package/src/Cloudflare/R2/R2Bucket.ts +271 -7
  188. package/src/Cloudflare/StateStore/Api.ts +34 -1
  189. package/src/Cloudflare/StateStore/Store.ts +40 -10
  190. package/src/Cloudflare/Workers/CronEventSource.ts +89 -0
  191. package/src/Cloudflare/Workers/InferEnv.ts +94 -16
  192. package/src/Cloudflare/Workers/LocalWorkerProvider.ts +9 -1
  193. package/src/Cloudflare/Workers/Rpc.ts +227 -18
  194. package/src/Cloudflare/Workers/Worker.ts +295 -62
  195. package/src/Cloudflare/Workers/WorkerBundle.ts +15 -5
  196. package/src/Cloudflare/Workers/Workflow.ts +74 -70
  197. package/src/Cloudflare/Workers/index.ts +1 -0
  198. package/src/Cloudflare/index.ts +2 -0
  199. package/src/Deploy.ts +5 -1
  200. package/src/Destroy.ts +5 -1
  201. package/src/Output.ts +121 -12
  202. package/src/Plan.ts +101 -12
  203. package/src/Platform.ts +19 -4
  204. package/src/Ref.ts +10 -5
  205. package/src/Resource.ts +22 -0
  206. package/src/RuntimeContext.ts +1 -0
  207. package/src/Secret.ts +87 -0
  208. package/src/Serverless/Function.ts +10 -1
  209. package/src/Stack.ts +52 -29
  210. package/src/State/HttpStateApi.ts +21 -0
  211. package/src/State/HttpStateStore.ts +21 -0
  212. package/src/State/InMemoryState.ts +29 -8
  213. package/src/State/LocalState.ts +28 -4
  214. package/src/State/State.ts +21 -0
  215. package/src/Test/Bun.ts +43 -7
  216. package/src/Test/Core.ts +29 -8
  217. package/src/Test/Vitest.ts +36 -4
  218. package/src/Util/LocalhostDns.ts +52 -0
  219. package/src/Util/PlatformServices.ts +2 -0
  220. package/src/Util/effect.ts +25 -0
  221. package/src/Variable.ts +44 -0
  222. package/src/index.ts +3 -0
package/bin/exec.js CHANGED
@@ -11,6 +11,8 @@ import * as Redacted from "effect/Redacted";
11
11
  import path from "pathe";
12
12
  import * as Config from "effect/Config";
13
13
  import os from "node:os";
14
+ import * as dns from "node:dns";
15
+ import * as undici from "undici";
14
16
  import * as Console from "effect/Console";
15
17
  import * as Logger from "effect/Logger";
16
18
  import * as Option from "effect/Option";
@@ -22,6 +24,7 @@ import * as Deferred from "effect/Deferred";
22
24
  import { pipe } from "effect/Function";
23
25
  import { SingleShotGen } from "effect/Utils";
24
26
  import { pipeArguments } from "effect/Pipeable";
27
+ import "effect/Scope";
25
28
  import * as Duration from "effect/Duration";
26
29
  import * as Exit from "effect/Exit";
27
30
  import * as Metric from "effect/Metric";
@@ -144,6 +147,25 @@ const CredentialsStoreLive = Layer.effect(CredentialsStore, Effect.gen(function*
144
147
  };
145
148
  }));
146
149
 
150
+ //#endregion
151
+ //#region lib/Util/LocalhostDns.js
152
+ let installed = false;
153
+ const isLocalhost = (hostname) => hostname === "localhost" || hostname === "[::1]" || hostname.endsWith(".localhost");
154
+ const installLocalhostDns = () => {
155
+ if (installed) return;
156
+ installed = true;
157
+ undici.setGlobalDispatcher(new undici.Agent({ connect: { lookup: (hostname, options, cb) => {
158
+ if (isLocalhost(hostname)) {
159
+ if (options && options.all) return cb(null, [{
160
+ address: "127.0.0.1",
161
+ family: 4
162
+ }]);
163
+ return cb(null, "127.0.0.1", 4);
164
+ }
165
+ return dns.lookup(hostname, options, cb);
166
+ } } }));
167
+ };
168
+
147
169
  //#endregion
148
170
  //#region lib/Util/PlatformServices.js
149
171
  const isBun = typeof Bun !== "undefined";
@@ -157,6 +179,7 @@ const PlatformServices = Effect.promise(async () => {
157
179
  }
158
180
  }).pipe(Layer.unwrap);
159
181
  const runMain = (effect, options) => {
182
+ installLocalhostDns();
160
183
  if (isBun) import("@effect/platform-bun/BunRuntime").then((BunRuntime) => BunRuntime.runMain(effect, options));
161
184
  else import("@effect/platform-node/NodeRuntime").then((NodeRuntime) => NodeRuntime.runMain(effect, options));
162
185
  };
@@ -331,18 +354,7 @@ var Cli = class extends EffectContext.Service()("CLI") {};
331
354
  //#region lib/Ref.js
332
355
  const RefMetadata = Symbol.for("alchemy/RefMetadata");
333
356
  const isRef = (s) => s && s[RefMetadata] !== void 0;
334
- const getRefMetadata = (ref$1) => ref$1[RefMetadata];
335
- const ref = ({ stack, id, stage: stage$1 }) => {
336
- const ref$1 = new Proxy({}, { get: (_, prop) => {
337
- if (prop === RefMetadata) return {
338
- stack,
339
- stage: stage$1,
340
- id
341
- };
342
- return of(ref$1)[prop];
343
- } });
344
- return ref$1;
345
- };
357
+ const getRefMetadata = (ref) => ref[RefMetadata];
346
358
 
347
359
  //#endregion
348
360
  //#region lib/FQN.js
@@ -452,6 +464,17 @@ const loadConfigProvider = (envFile$1) => {
452
464
 
453
465
  //#endregion
454
466
  //#region lib/Util/effect.js
467
+ const effectClass = ((impl) => impl === void 0 ? (innerImpl) => effectClass(innerImpl) : Object.assign(class {
468
+ static asEffect() {
469
+ return impl;
470
+ }
471
+ static [Symbol.iterator]() {
472
+ return new SingleShotGen(this);
473
+ }
474
+ static pipe(...fns) {
475
+ return pipeArguments(this.asEffect(), fns);
476
+ }
477
+ }, impl));
455
478
  const taggedFunction = (tag$1, fn) => {
456
479
  const overrides = {
457
480
  asEffect: () => tag$1.asEffect(),
@@ -478,14 +501,17 @@ const fileLogger = Effect.fnUntraced(function* (...segments) {
478
501
 
479
502
  //#endregion
480
503
  //#region lib/Stack.js
481
- const Stack = Object.assign(taggedFunction(EffectContext.Service()("Stack"), (stackName, options, eff) => eff.pipe(make$1({
482
- name: stackName,
483
- ...options
484
- }), (eff$1) => Object.assign(eff$1, { stage: new Proxy({}, { get: (_, stage$1) => ref({
485
- stack: stackName,
486
- stage: stage$1,
487
- id: stackName
488
- }) }) }))));
504
+ const Stack = Object.assign(taggedFunction(EffectContext.Service()("Stack"), (stackName, options, eff) => {
505
+ if (!stackName) return (stackName$1) => Object.assign(stackRef(stackName$1).pipe(effectClass), {
506
+ stage: createStageProxy(stackName$1),
507
+ make: (options$1, eff$1) => Stack(stackName$1, options$1, eff$1)
508
+ });
509
+ return eff.pipe(make$1({
510
+ name: stackName,
511
+ ...options
512
+ }), (eff$1) => Object.assign(eff$1, { stage: createStageProxy(stackName) }));
513
+ }));
514
+ const createStageProxy = (stackName) => new Proxy({}, { get: (_, stage$1) => stackRef(stackName, { stage: stage$1 }) });
489
515
  const StackName = Stack.use((stack) => Effect.succeed(stack.name));
490
516
  const make$1 = (options) => (effect) => Effect.scope.pipe(Effect.flatMap((scope) => {
491
517
  if (options.state == null) return Effect.die(/* @__PURE__ */ new Error(`Stack "${options.name}" is missing a state store. Add a \`state\` layer to the stack options, e.g.:\n Alchemy.Stack("${options.name}", {\n providers: Cloudflare.providers(),\n state: Cloudflare.state(), // <-- required\n }, ...)\nSee https://v2.alchemy.run/concepts/state-store for available state stores.`));
@@ -640,6 +666,28 @@ var EffectExpr = class extends BaseExpr {
640
666
  return `${this.expr[inspect]()}.mapEffect(${this.f.toString()})`;
641
667
  }
642
668
  };
669
+ const isNamedExpr = (node) => node?.kind === "NamedExpr";
670
+ /**
671
+ * Wraps another `Expr` and overrides its `toString()` / inspect output.
672
+ *
673
+ * `BaseExpr.asEffect()` derives the binding id from `this.toString()`, so
674
+ * wrapping an expression in `NamedExpr` makes that derived id stable and
675
+ * caller-controlled (e.g. an env var name like `"API_KEY"`).
676
+ */
677
+ var NamedExpr = class extends BaseExpr {
678
+ expr;
679
+ bindingName;
680
+ kind = "NamedExpr";
681
+ constructor(expr, bindingName) {
682
+ super();
683
+ this.expr = expr;
684
+ this.bindingName = bindingName;
685
+ return proxy(this);
686
+ }
687
+ [inspect]() {
688
+ return this.bindingName;
689
+ }
690
+ };
643
691
  const isAllExpr = (node) => node?.kind === "AllExpr";
644
692
  var AllExpr = class extends BaseExpr {
645
693
  outs;
@@ -670,6 +718,39 @@ var RefExpr = class extends BaseExpr {
670
718
  return `ref(${this.resourceId}, { stack: ${this.stack}, stage: ${this.stage} })`;
671
719
  }
672
720
  };
721
+ const isStackRefExpr = (node) => node?.kind === "StackRefExpr";
722
+ /**
723
+ * A reference to the persisted output of a Stack at `(stack, stage)`.
724
+ *
725
+ * Resolved at evaluation time by reading `state.getOutput({ stack,
726
+ * stage })`. Distinct from {@link RefExpr}, which references a
727
+ * single resource's attributes within a stack/stage. `stage` may be
728
+ * `undefined`, in which case it falls back to the current stage.
729
+ */
730
+ var StackRefExpr = class extends BaseExpr {
731
+ stack;
732
+ stage;
733
+ kind = "StackRefExpr";
734
+ constructor(stack, stage$1) {
735
+ super();
736
+ this.stack = stack;
737
+ this.stage = stage$1;
738
+ return proxy(this);
739
+ }
740
+ [inspect]() {
741
+ return `stackRef(${this.stack}${this.stage ? `, { stage: ${this.stage} }` : ""})`;
742
+ }
743
+ };
744
+ /**
745
+ * Build an `Output<A>` referencing the persisted output of another
746
+ * Stack. The returned Effect resolves to a lazy `Output<A>` whose
747
+ * value is read from the state store at plan/apply time.
748
+ *
749
+ * Returns `Effect<Output<A>>` (not `Output<A>` directly) so that
750
+ * `yield* Output.stackRef(...)` reads ergonomically inside an Effect
751
+ * generator and lines up with `Resource.ref` and `Stack.stage.<name>`.
752
+ */
753
+ const stackRef = (stack, options = {}) => Effect.succeed(new StackRefExpr(stack, options.stage));
673
754
  function proxy(self) {
674
755
  const target = Object.assign(() => {}, self);
675
756
  if (inspect in self) Object.defineProperty(target, inspect, {
@@ -678,7 +759,9 @@ function proxy(self) {
678
759
  });
679
760
  const proxy$1 = new Proxy(target, {
680
761
  has: (_, prop) => prop === ExprSymbol || prop === inspect ? true : prop in self,
681
- get: (target$1, prop) => prop === Symbol.toPrimitive ? (hint) => hint === "number" ? NaN : self.toString() : prop === ExprSymbol ? self : prop === inspect ? target$1[inspect] : isResourceExpr(self) && self.stables && prop in self.stables ? self.stables[prop] : prop === "apply" ? self[prop] : prop in self ? typeof self[prop] === "function" && !("kind" in self) ? new PropExpr(proxy$1, prop) : self[prop] : new PropExpr(proxy$1, prop),
762
+ get: (target$1, prop) => prop === Symbol.toPrimitive ? (hint) => {
763
+ throw new Error(`Cannot coerce Output<${self[inspect]()}> to a ${hint === "number" ? "number" : "string"} via JS coercion. Use Output.interpolate\`...\` or Output.map(output, fn) to compose Outputs — the value isn't known until deploy time.`);
764
+ } : prop === ExprSymbol ? self : prop === inspect ? target$1[inspect] : isResourceExpr(self) && self.stables && prop in self.stables ? self.stables[prop] : prop === "apply" ? self[prop] : prop in self ? typeof self[prop] === "function" && !("kind" in self) ? new PropExpr(proxy$1, prop) : self[prop] : new PropExpr(proxy$1, prop),
682
765
  apply: (_, thisArg, args) => {
683
766
  if (isPropExpr(self)) {
684
767
  if (self.identifier === "apply") return new ApplyExpr(self.expr, args[0]);
@@ -713,6 +796,7 @@ const evaluate = (expr, upstream$1) => Effect.gen(function* () {
713
796
  else if (isEffectExpr(expr)) return yield* expr.f(yield* evaluate(expr.expr, upstream$1));
714
797
  else if (isAllExpr(expr)) return yield* Effect.all(expr.outs.map((out) => evaluate(out, upstream$1)));
715
798
  else if (isPropExpr(expr)) return (yield* evaluate(expr.expr, upstream$1))?.[expr.identifier];
799
+ else if (isNamedExpr(expr)) return yield* evaluate(expr.expr, upstream$1);
716
800
  else if (isRefExpr(expr)) {
717
801
  const state = yield* State;
718
802
  const stack = expr.stack ?? (yield* Stack).name;
@@ -729,6 +813,21 @@ const evaluate = (expr, upstream$1) => Effect.gen(function* () {
729
813
  resourceId: expr.resourceId
730
814
  }));
731
815
  return resource.attr;
816
+ } else if (isStackRefExpr(expr)) {
817
+ const state = yield* State;
818
+ const stack = expr.stack;
819
+ const stage$1 = expr.stage ?? (yield* Stage);
820
+ const output = yield* state.getOutput({
821
+ stack,
822
+ stage: stage$1
823
+ });
824
+ if (output == null) return yield* Effect.fail(new InvalidReferenceError({
825
+ message: `Reference to stack '${stack}' at stage '${stage$1}' not found. Have you deployed stage '${stage$1}' of '${stack}'?`,
826
+ stack,
827
+ stage: stage$1,
828
+ resourceId: stack
829
+ }));
830
+ return output;
732
831
  }
733
832
  }
734
833
  if (Array.isArray(expr)) return yield* Effect.all(expr.map((item) => evaluate(item, upstream$1)));
@@ -749,7 +848,7 @@ const upstream = (expr) => {
749
848
  else if (isResourceExpr(expr)) return { [expr.src.FQN]: expr.src };
750
849
  else if (isPropExpr(expr)) return upstream(expr.expr);
751
850
  else if (isAllExpr(expr)) return Object.assign({}, ...expr.outs.map((out) => upstream(out)));
752
- else if (isEffectExpr(expr) || isApplyExpr(expr)) return upstream(expr.expr);
851
+ else if (isEffectExpr(expr) || isApplyExpr(expr) || isNamedExpr(expr)) return upstream(expr.expr);
753
852
  else if (Array.isArray(expr)) return expr.map(upstream).reduce(toObject, {});
754
853
  else if (typeof expr === "object" && expr !== null) return Object.values(expr).map((v) => upstream(v)).reduce(toObject, {});
755
854
  return {};
@@ -1047,7 +1146,37 @@ const make = (stack, options = {}) => Effect.gen(function* () {
1047
1146
  return hasOutputs(upstream$1) ? expr : yield* expr.f(upstream$1);
1048
1147
  } else if (isAllExpr(expr)) return yield* Effect.all(expr.outs.map(resolveOutput), { concurrency: "unbounded" });
1049
1148
  else if (isLiteralExpr(expr)) return expr.value;
1050
- return yield* Effect.die(/* @__PURE__ */ new Error("Not implemented yet"));
1149
+ else if (isRefExpr(expr)) {
1150
+ const refStack = expr.stack ?? stackName;
1151
+ const refStage = expr.stage ?? stage$1;
1152
+ const refState = yield* state.get({
1153
+ stack: refStack,
1154
+ stage: refStage,
1155
+ fqn: expr.resourceId
1156
+ }).pipe(Effect.orDie);
1157
+ if (!refState) return yield* Effect.die(new InvalidReferenceError({
1158
+ message: `Reference to '${expr.resourceId}' in stack '${refStack}' and stage '${refStage}' not found. Have you deployed '${refStage}' of '${refStack}'?`,
1159
+ stack: refStack,
1160
+ stage: refStage,
1161
+ resourceId: expr.resourceId
1162
+ }));
1163
+ return refState.attr;
1164
+ } else if (isStackRefExpr(expr)) {
1165
+ const refStack = expr.stack;
1166
+ const refStage = expr.stage ?? stage$1;
1167
+ const output = yield* state.getOutput({
1168
+ stack: refStack,
1169
+ stage: refStage
1170
+ }).pipe(Effect.orDie);
1171
+ if (output == null) return yield* Effect.die(new InvalidReferenceError({
1172
+ message: `Reference to stack '${refStack}' at stage '${refStage}' not found. Have you deployed stage '${refStage}' of '${refStack}'?`,
1173
+ stack: refStack,
1174
+ stage: refStage,
1175
+ resourceId: refStack
1176
+ }));
1177
+ return output;
1178
+ } else if (isNamedExpr(expr)) return yield* resolveOutput(expr.expr);
1179
+ return yield* Effect.die(/* @__PURE__ */ new Error("Not implemented yet" + expr.kind));
1051
1180
  });
1052
1181
  const oldDownstreamDependencies = Object.fromEntries(oldResources.filter((resource) => !!resource).map((resource) => [resource.fqn, resource.downstream]));
1053
1182
  const newResourceFqns = new Set(resources.map((r) => r.FQN));
@@ -1063,7 +1192,22 @@ const make = (stack, options = {}) => Effect.gen(function* () {
1063
1192
  const fqn = resource.FQN;
1064
1193
  return [fqn, (rawUpstreamDependencies[fqn] ?? []).filter((dep) => newResourceFqns.has(dep))];
1065
1194
  }));
1066
- const newDownstreamDependencies = Object.fromEntries(resources.map((resource) => [resource.FQN, Object.entries(newUpstreamDependencies).filter(([_, upstream$1]) => upstream$1.includes(resource.FQN)).map(([depFqn]) => depFqn)]));
1195
+ const combinedCycleMembers = findCycleMembers(allUpstreamDependencies);
1196
+ const newDownstreamDependencies = Object.fromEntries(resources.map((resource) => {
1197
+ const upFqn = resource.FQN;
1198
+ const downstream = [];
1199
+ for (const [downFqn, upstreams] of Object.entries(rawUpstreamDependencies)) {
1200
+ if (downFqn === upFqn) continue;
1201
+ if (!upstreams.includes(upFqn)) continue;
1202
+ if ((newUpstreamDependencies[downFqn] ?? []).includes(upFqn)) {
1203
+ downstream.push(downFqn);
1204
+ continue;
1205
+ }
1206
+ if (combinedCycleMembers.has(upFqn) && combinedCycleMembers.has(downFqn)) continue;
1207
+ downstream.push(downFqn);
1208
+ }
1209
+ return [upFqn, downstream];
1210
+ }));
1067
1211
  const resourceGraph = Object.fromEntries((yield* Effect.all(resources.map(Effect.fn("plan.diff.resource")(function* (resource) {
1068
1212
  const provider = yield* findProviderByType(resource.Type);
1069
1213
  const id = resource.LogicalId;
@@ -1246,7 +1390,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
1246
1390
  state: oldState
1247
1391
  });
1248
1392
  })), { concurrency: "unbounded" })).map((update) => [update.resource.FQN, update]));
1249
- const cycleMembers = findCycleMembers(allUpstreamDependencies);
1393
+ const cycleMembers = combinedCycleMembers;
1250
1394
  {
1251
1395
  const createReplaceNodes = new Set(Object.entries(resourceGraph).filter(([_, node]) => node.action === "create" || node.action === "replace").map(([fqn]) => fqn));
1252
1396
  if (createReplaceNodes.size > 0) {
@@ -1390,7 +1534,13 @@ const apply = (plan) => Effect.gen(function* () {
1390
1534
  yield* session.done();
1391
1535
  if (!plan.output) return;
1392
1536
  const outputs = Object.fromEntries(Object.entries(tracker).map(([fqn, t]) => [fqn, t.output]));
1393
- return yield* evaluate(plan.output, outputs);
1537
+ const resolved = yield* evaluate(plan.output, outputs);
1538
+ yield* state.setOutput({
1539
+ stack: stackName,
1540
+ stage: stage$1,
1541
+ value: resolved
1542
+ });
1543
+ return resolved;
1394
1544
  }).pipe(ensureArtifactStore, Effect.withSpan("apply", { attributes: {
1395
1545
  "alchemy.resources.count": Object.keys(plan.resources).length,
1396
1546
  "alchemy.deletions.count": Object.keys(plan.deletions).length