alchemy 2.0.0-beta.36 → 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.
- package/bin/exec.js +166 -43
- package/bin/exec.js.map +1 -1
- package/lib/AWS/Lambda/Function.d.ts.map +1 -1
- package/lib/AWS/Lambda/Function.js +22 -2
- package/lib/AWS/Lambda/Function.js.map +1 -1
- package/lib/Apply.d.ts.map +1 -1
- package/lib/Apply.js +6 -1
- package/lib/Apply.js.map +1 -1
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.d.ts +54 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.d.ts.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.js +17 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.js.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.d.ts +37 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.d.ts.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.js +45 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.js.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/index.d.ts +3 -0
- package/lib/Cloudflare/AnalyticsEngine/index.d.ts.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/index.js +3 -0
- package/lib/Cloudflare/AnalyticsEngine/index.js.map +1 -0
- package/lib/Cloudflare/D1/D1Connection.d.ts +47 -3
- package/lib/Cloudflare/D1/D1Connection.d.ts.map +1 -1
- package/lib/Cloudflare/D1/D1Connection.js +62 -5
- package/lib/Cloudflare/D1/D1Connection.js.map +1 -1
- package/lib/Cloudflare/Local/SidecarHandlers.js +9 -1
- package/lib/Cloudflare/Local/SidecarHandlers.js.map +1 -1
- package/lib/Cloudflare/Providers.d.ts.map +1 -1
- package/lib/Cloudflare/Providers.js +4 -1
- package/lib/Cloudflare/Providers.js.map +1 -1
- package/lib/Cloudflare/R2/R2Bucket.d.ts.map +1 -1
- package/lib/Cloudflare/R2/R2Bucket.js +16 -0
- package/lib/Cloudflare/R2/R2Bucket.js.map +1 -1
- package/lib/Cloudflare/StateStore/Api.d.ts +6 -1
- package/lib/Cloudflare/StateStore/Api.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/Api.js +23 -1
- package/lib/Cloudflare/StateStore/Api.js.map +1 -1
- package/lib/Cloudflare/StateStore/Store.d.ts +16 -1
- package/lib/Cloudflare/StateStore/Store.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/Store.js +22 -5
- package/lib/Cloudflare/StateStore/Store.js.map +1 -1
- package/lib/Cloudflare/Workers/CronEventSource.d.ts +35 -0
- package/lib/Cloudflare/Workers/CronEventSource.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/CronEventSource.js +55 -0
- package/lib/Cloudflare/Workers/CronEventSource.js.map +1 -0
- package/lib/Cloudflare/Workers/InferEnv.d.ts +37 -2
- package/lib/Cloudflare/Workers/InferEnv.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js +2 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/Rpc.d.ts +76 -3
- package/lib/Cloudflare/Workers/Rpc.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Rpc.js +197 -13
- package/lib/Cloudflare/Workers/Rpc.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +22 -2
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +174 -43
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.js +15 -5
- package/lib/Cloudflare/Workers/WorkerBundle.js.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.d.ts +50 -47
- package/lib/Cloudflare/Workers/Workflow.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.js +41 -35
- package/lib/Cloudflare/Workers/Workflow.js.map +1 -1
- package/lib/Cloudflare/Workers/index.d.ts +1 -0
- package/lib/Cloudflare/Workers/index.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/index.js +1 -0
- package/lib/Cloudflare/Workers/index.js.map +1 -1
- package/lib/Cloudflare/index.d.ts +1 -0
- package/lib/Cloudflare/index.d.ts.map +1 -1
- package/lib/Cloudflare/index.js +1 -0
- package/lib/Cloudflare/index.js.map +1 -1
- package/lib/Deploy.d.ts +4 -1
- package/lib/Deploy.d.ts.map +1 -1
- package/lib/Deploy.js +2 -2
- package/lib/Deploy.js.map +1 -1
- package/lib/Destroy.d.ts +4 -1
- package/lib/Destroy.d.ts.map +1 -1
- package/lib/Destroy.js +2 -2
- package/lib/Destroy.js.map +1 -1
- package/lib/Output.d.ts +45 -5
- package/lib/Output.d.ts.map +1 -1
- package/lib/Output.js +100 -4
- package/lib/Output.js.map +1 -1
- package/lib/Plan.d.ts.map +1 -1
- package/lib/Plan.js +93 -12
- package/lib/Plan.js.map +1 -1
- package/lib/Platform.d.ts.map +1 -1
- package/lib/Platform.js +16 -3
- package/lib/Platform.js.map +1 -1
- package/lib/Ref.d.ts +4 -1
- package/lib/Ref.d.ts.map +1 -1
- package/lib/Ref.js +1 -1
- package/lib/Ref.js.map +1 -1
- package/lib/Resource.d.ts +8 -0
- package/lib/Resource.d.ts.map +1 -1
- package/lib/Resource.js +10 -0
- package/lib/Resource.js.map +1 -1
- package/lib/RuntimeContext.d.ts +3 -1
- package/lib/RuntimeContext.d.ts.map +1 -1
- package/lib/RuntimeContext.js.map +1 -1
- package/lib/Secret.d.ts +50 -0
- package/lib/Secret.d.ts.map +1 -0
- package/lib/Secret.js +23 -0
- package/lib/Secret.js.map +1 -0
- package/lib/Serverless/Function.d.ts +9 -1
- package/lib/Serverless/Function.d.ts.map +1 -1
- package/lib/Stack.d.ts +14 -5
- package/lib/Stack.d.ts.map +1 -1
- package/lib/Stack.js +31 -19
- package/lib/Stack.js.map +1 -1
- package/lib/State/HttpStateApi.d.ts +15 -1
- package/lib/State/HttpStateApi.d.ts.map +1 -1
- package/lib/State/HttpStateApi.js +11 -0
- package/lib/State/HttpStateApi.js.map +1 -1
- package/lib/State/HttpStateStore.d.ts.map +1 -1
- package/lib/State/HttpStateStore.js +11 -0
- package/lib/State/HttpStateStore.js.map +1 -1
- package/lib/State/InMemoryState.d.ts +2 -2
- package/lib/State/InMemoryState.d.ts.map +1 -1
- package/lib/State/InMemoryState.js +12 -6
- package/lib/State/InMemoryState.js.map +1 -1
- package/lib/State/LocalState.d.ts.map +1 -1
- package/lib/State/LocalState.js +11 -2
- package/lib/State/LocalState.js.map +1 -1
- package/lib/State/State.d.ts +21 -0
- package/lib/State/State.d.ts.map +1 -1
- package/lib/Test/Bun.d.ts.map +1 -1
- package/lib/Test/Bun.js +30 -7
- package/lib/Test/Bun.js.map +1 -1
- package/lib/Test/Core.d.ts +17 -2
- package/lib/Test/Core.d.ts.map +1 -1
- package/lib/Test/Core.js +29 -11
- package/lib/Test/Core.js.map +1 -1
- package/lib/Test/Vitest.d.ts.map +1 -1
- package/lib/Test/Vitest.js +24 -5
- package/lib/Test/Vitest.js.map +1 -1
- package/lib/Util/LocalhostDns.d.ts +14 -10
- package/lib/Util/LocalhostDns.d.ts.map +1 -1
- package/lib/Util/LocalhostDns.js +27 -36
- package/lib/Util/LocalhostDns.js.map +1 -1
- package/lib/Util/effect.d.ts +7 -0
- package/lib/Util/effect.d.ts.map +1 -1
- package/lib/Util/effect.js +6 -0
- package/lib/Util/effect.js.map +1 -1
- package/lib/Variable.d.ts +29 -0
- package/lib/Variable.d.ts.map +1 -0
- package/lib/Variable.js +9 -0
- package/lib/Variable.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +6 -7
- package/src/AWS/Lambda/Function.ts +30 -2
- package/src/Apply.ts +8 -1
- package/src/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.ts +82 -0
- package/src/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.ts +106 -0
- package/src/Cloudflare/AnalyticsEngine/index.ts +2 -0
- package/src/Cloudflare/D1/D1Connection.ts +95 -12
- package/src/Cloudflare/Local/SidecarHandlers.ts +9 -1
- package/src/Cloudflare/Providers.ts +5 -0
- package/src/Cloudflare/R2/R2Bucket.ts +31 -0
- package/src/Cloudflare/StateStore/Api.ts +34 -1
- package/src/Cloudflare/StateStore/Store.ts +40 -10
- package/src/Cloudflare/Workers/CronEventSource.ts +89 -0
- package/src/Cloudflare/Workers/InferEnv.ts +94 -20
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +9 -1
- package/src/Cloudflare/Workers/Rpc.ts +227 -18
- package/src/Cloudflare/Workers/Worker.ts +277 -63
- package/src/Cloudflare/Workers/WorkerBundle.ts +15 -5
- package/src/Cloudflare/Workers/Workflow.ts +74 -70
- package/src/Cloudflare/Workers/index.ts +1 -0
- package/src/Cloudflare/index.ts +1 -0
- package/src/Deploy.ts +5 -1
- package/src/Destroy.ts +5 -1
- package/src/Output.ts +121 -12
- package/src/Plan.ts +101 -12
- package/src/Platform.ts +19 -4
- package/src/Ref.ts +10 -5
- package/src/Resource.ts +22 -0
- package/src/RuntimeContext.ts +1 -0
- package/src/Secret.ts +87 -0
- package/src/Serverless/Function.ts +10 -1
- package/src/Stack.ts +52 -29
- package/src/State/HttpStateApi.ts +21 -0
- package/src/State/HttpStateStore.ts +21 -0
- package/src/State/InMemoryState.ts +29 -8
- package/src/State/LocalState.ts +28 -4
- package/src/State/State.ts +21 -0
- package/src/Test/Bun.ts +43 -7
- package/src/Test/Core.ts +29 -8
- package/src/Test/Vitest.ts +33 -4
- package/src/Util/LocalhostDns.ts +30 -36
- package/src/Util/effect.ts +25 -0
- package/src/Variable.ts +44 -0
- package/src/index.ts +3 -0
package/src/Test/Core.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { ConfigProvider } from "effect/ConfigProvider";
|
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Layer from "effect/Layer";
|
|
4
4
|
import * as Option from "effect/Option";
|
|
5
|
+
import * as Scope from "effect/Scope";
|
|
5
6
|
import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
|
|
6
7
|
|
|
7
8
|
import { AdoptPolicy } from "../AdoptPolicy.ts";
|
|
@@ -90,14 +91,22 @@ const alchemyLayer = Layer.mergeAll(LoggingCli, AlchemyContextLive);
|
|
|
90
91
|
* registry that the user's `providers` layer populates, the platform layers,
|
|
91
92
|
* and the configured state store. Adapters wrap this into runner-specific
|
|
92
93
|
* thunks (`bun.test` -> `runPromise`, `it.live` -> as-is).
|
|
94
|
+
*
|
|
95
|
+
* When `scope` is provided, scoped resources (like the Cloudflare dev
|
|
96
|
+
* sidecar) survive past this effect and are tied to the lifetime of the
|
|
97
|
+
* provided scope instead. The runner is responsible for closing it.
|
|
98
|
+
*
|
|
99
|
+
* When `scope` is omitted, the effect runs with `Effect.scoped` and any
|
|
100
|
+
* scoped resources are torn down as soon as it resolves.
|
|
93
101
|
*/
|
|
94
102
|
export const toEffect = <A>(
|
|
95
103
|
effect: TestEffect<A>,
|
|
96
104
|
options: MakeOptions,
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
105
|
+
scope?: Scope.Scope,
|
|
106
|
+
): Effect.Effect<A, any, never> => {
|
|
107
|
+
const base = Effect.gen(function* () {
|
|
108
|
+
const cfg = yield* loadConfigProvider(Option.none());
|
|
109
|
+
const configProvider = withProfileOverride(cfg, options.profile);
|
|
101
110
|
return yield* effect.pipe(
|
|
102
111
|
provideFreshArtifactStore,
|
|
103
112
|
Effect.provide(Layer.succeed(ConfigProvider, configProvider)),
|
|
@@ -112,14 +121,19 @@ export const toEffect = <A>(
|
|
|
112
121
|
Effect.provide(options.state ?? State.localState()),
|
|
113
122
|
Effect.provideService(AuthProviders, {}),
|
|
114
123
|
Effect.provide(Layer.provideMerge(alchemyLayer, platformLayer)),
|
|
115
|
-
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
scope === undefined ? Effect.scoped(base) : Scope.provide(base, scope)
|
|
116
128
|
) as Effect.Effect<A, any, never>;
|
|
129
|
+
};
|
|
117
130
|
|
|
118
131
|
/** Promise wrapper around {@link toEffect} for `bun.test`-style runners. */
|
|
119
132
|
export const run = <A>(
|
|
120
133
|
effect: TestEffect<A>,
|
|
121
134
|
options: MakeOptions,
|
|
122
|
-
|
|
135
|
+
scope?: Scope.Scope,
|
|
136
|
+
): Promise<A> => Effect.runPromise(toEffect(effect, options, scope));
|
|
123
137
|
|
|
124
138
|
/**
|
|
125
139
|
* Wrap an effect so it runs with `options.providers` + a placeholder Stack +
|
|
@@ -148,27 +162,34 @@ export const withProviders = <A, E, R, ROut>(
|
|
|
148
162
|
* Curried `deploy` for the test factory: bakes in the configured stage and
|
|
149
163
|
* adds the telemetry layer the CLI uses, so `beforeAll(deploy(Stack))` works
|
|
150
164
|
* the same way as `alchemy deploy`.
|
|
165
|
+
*
|
|
166
|
+
* `scope`, when supplied, is forwarded down so the dev sidecar (and other
|
|
167
|
+
* scoped resources) lives until the caller closes it instead of dying as
|
|
168
|
+
* soon as `deploy` resolves. The test harness uses this to keep workerd
|
|
169
|
+
* alive across `beforeAll` → tests → `afterAll`.
|
|
151
170
|
*/
|
|
152
171
|
export const deploy = <A>(
|
|
153
172
|
options: MakeOptions,
|
|
154
173
|
stack: TestEffect<CompiledStack<A>, Stage | AlchemyContext>,
|
|
155
|
-
callOptions?: { stage?: string },
|
|
174
|
+
callOptions?: { stage?: string; scope?: Scope.Scope },
|
|
156
175
|
) =>
|
|
157
176
|
_deploy({
|
|
158
177
|
stack: stack as Effect.Effect<CompiledStack<A>, never, any>,
|
|
159
178
|
stage: callOptions?.stage ?? options.stage ?? "test",
|
|
160
179
|
dev: resolveDev(options),
|
|
180
|
+
scope: callOptions?.scope,
|
|
161
181
|
}).pipe(Effect.provide(TelemetryLive));
|
|
162
182
|
|
|
163
183
|
export const destroy = (
|
|
164
184
|
options: MakeOptions,
|
|
165
185
|
stack: TestEffect<CompiledStack, Stage | AlchemyContext>,
|
|
166
|
-
callOptions?: { stage?: string },
|
|
186
|
+
callOptions?: { stage?: string; scope?: Scope.Scope },
|
|
167
187
|
) =>
|
|
168
188
|
_destroy({
|
|
169
189
|
stack: stack as Effect.Effect<CompiledStack, never, any>,
|
|
170
190
|
stage: callOptions?.stage ?? options.stage ?? "test",
|
|
171
191
|
dev: resolveDev(options),
|
|
192
|
+
scope: callOptions?.scope,
|
|
172
193
|
}).pipe(Effect.provide(TelemetryLive));
|
|
173
194
|
|
|
174
195
|
/**
|
package/src/Test/Vitest.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { it } from "@effect/vitest";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Exit from "effect/Exit";
|
|
4
|
+
import * as Scope from "effect/Scope";
|
|
3
5
|
import {
|
|
4
6
|
afterAll as vitestAfterAll,
|
|
5
7
|
afterEach as vitestAfterEach,
|
|
@@ -98,8 +100,13 @@ const DEFAULT_TIMEOUT = 120_000;
|
|
|
98
100
|
* Effect-aware tests stay first-class.
|
|
99
101
|
*/
|
|
100
102
|
export const make = <ROut = any>(options: MakeOptions<ROut>): TestApi => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
// See `Test/Bun.ts` for the rationale: the dev sidecar must outlive a
|
|
104
|
+
// single `runPromise` boundary, so all hooks share one scope that's only
|
|
105
|
+
// closed after `destroy(...)` runs.
|
|
106
|
+
const sharedScope = Scope.makeUnsafe("sequential");
|
|
107
|
+
const wrap = <A>(eff: TestEffect<A>) =>
|
|
108
|
+
Core.toEffect(eff, options, sharedScope);
|
|
109
|
+
const runEff = <A>(eff: TestEffect<A>) => Core.run(eff, options, sharedScope);
|
|
103
110
|
|
|
104
111
|
const test = ((name, eff, opts) => {
|
|
105
112
|
it.live(name, () => wrap(eff), timeoutOf(opts));
|
|
@@ -130,6 +137,7 @@ export const make = <ROut = any>(options: MakeOptions<ROut>): TestApi => {
|
|
|
130
137
|
return Core.toEffect(
|
|
131
138
|
Core.withProviders(fn(scratch), options, scratch.name),
|
|
132
139
|
{ ...options, state: scratch.state },
|
|
140
|
+
sharedScope,
|
|
133
141
|
);
|
|
134
142
|
};
|
|
135
143
|
|
|
@@ -182,13 +190,34 @@ export const make = <ROut = any>(options: MakeOptions<ROut>): TestApi => {
|
|
|
182
190
|
vitestAfterEach(() => runEff(eff), timeoutOf(hookOptions));
|
|
183
191
|
};
|
|
184
192
|
|
|
193
|
+
// `destroy(Stack)` needs the dev sidecar alive so it can call `sidecar.stop`.
|
|
194
|
+
// `Scope.close` on an already-closed scope is a no-op, so the destroy
|
|
195
|
+
// wrapper AND the fallback cleanup hook below can both call it safely.
|
|
196
|
+
const closeScope = Effect.suspend(() =>
|
|
197
|
+
Scope.close(sharedScope, Exit.void),
|
|
198
|
+
).pipe(Effect.ignore);
|
|
199
|
+
|
|
200
|
+
// Fallback cleanup: if the user never calls `destroy(Stack)` (e.g.
|
|
201
|
+
// `NO_DESTROY=1`), nothing else closes the shared scope and the sidecar
|
|
202
|
+
// child process leaks past the test process. Register an `afterAll` that
|
|
203
|
+
// closes it. We defer registration to a microtask so it runs AFTER any
|
|
204
|
+
// user-registered `afterAll` (including `destroy(Stack)`); vitest runs
|
|
205
|
+
// afterAll hooks in registration order.
|
|
206
|
+
queueMicrotask(() => {
|
|
207
|
+
vitestAfterAll(() => Effect.runPromise(closeScope), DEFAULT_TIMEOUT);
|
|
208
|
+
});
|
|
209
|
+
|
|
185
210
|
return {
|
|
186
211
|
test,
|
|
187
212
|
beforeAll,
|
|
188
213
|
beforeEach,
|
|
189
214
|
afterAll,
|
|
190
215
|
afterEach,
|
|
191
|
-
deploy: (stack, callOpts) =>
|
|
192
|
-
|
|
216
|
+
deploy: (stack, callOpts) =>
|
|
217
|
+
Core.deploy(options, stack, { ...callOpts, scope: sharedScope }),
|
|
218
|
+
destroy: (stack, callOpts) =>
|
|
219
|
+
Core.destroy(options, stack, { ...callOpts, scope: sharedScope }).pipe(
|
|
220
|
+
Effect.ensuring(closeScope),
|
|
221
|
+
),
|
|
193
222
|
};
|
|
194
223
|
};
|
package/src/Util/LocalhostDns.ts
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Process-level DNS shim that makes `*.localhost` resolve to 127.0.0.1
|
|
2
|
+
* Process-level DNS shim that makes `*.localhost` resolve to 127.0.0.1
|
|
3
|
+
* for any HTTP client that goes through undici (Node's global `fetch`,
|
|
4
|
+
* undici-based clients, etc.).
|
|
3
5
|
*
|
|
4
6
|
* Background: macOS's `getaddrinfo` does not honor RFC 6761 for arbitrary
|
|
5
|
-
* `*.localhost` names
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* `*.localhost` names — only the bare `localhost` is mapped to loopback.
|
|
8
|
+
* The Cloudflare local proxy returns URLs like
|
|
9
|
+
* `http://my-worker.localhost:1337` and dispatches by the URL hostname,
|
|
10
|
+
* so we cannot rewrite the URL client-side to `127.0.0.1` (and `Host` is
|
|
11
|
+
* a forbidden fetch header). The fix is to make the host resolvable at
|
|
12
|
+
* the network layer.
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
14
|
+
* On Bun, `globalThis.fetch` is the native (Zig) implementation and does
|
|
15
|
+
* not consult undici's global dispatcher; Bun resolves `*.localhost`
|
|
16
|
+
* itself on Darwin/Linux, so this shim is effectively a no-op there for
|
|
17
|
+
* the global `fetch` and only matters if user code reaches for `undici`
|
|
18
|
+
* directly.
|
|
15
19
|
*
|
|
16
20
|
* Calling `installLocalhostDns()` is idempotent.
|
|
17
21
|
*/
|
|
18
22
|
|
|
19
|
-
import
|
|
23
|
+
import * as dns from "node:dns";
|
|
24
|
+
import * as undici from "undici";
|
|
20
25
|
|
|
21
26
|
let installed = false;
|
|
22
27
|
|
|
@@ -28,31 +33,20 @@ const isLocalhost = (hostname: string): boolean =>
|
|
|
28
33
|
export const installLocalhostDns = (): void => {
|
|
29
34
|
if (installed) return;
|
|
30
35
|
installed = true;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const dns: typeof import("node:dns") = require("node:dns");
|
|
40
|
-
undici.setGlobalDispatcher(
|
|
41
|
-
new undici.Agent({
|
|
42
|
-
connect: {
|
|
43
|
-
lookup: (hostname, options, cb: any) => {
|
|
44
|
-
if (isLocalhost(hostname)) {
|
|
45
|
-
if (options && (options as { all?: boolean }).all) {
|
|
46
|
-
return cb(null, [{ address: "127.0.0.1", family: 4 }]);
|
|
47
|
-
}
|
|
48
|
-
return cb(null, "127.0.0.1", 4);
|
|
36
|
+
|
|
37
|
+
undici.setGlobalDispatcher(
|
|
38
|
+
new undici.Agent({
|
|
39
|
+
connect: {
|
|
40
|
+
lookup: (hostname, options, cb) => {
|
|
41
|
+
if (isLocalhost(hostname)) {
|
|
42
|
+
if (options && (options as { all?: boolean }).all) {
|
|
43
|
+
return cb(null, [{ address: "127.0.0.1", family: 4 }]);
|
|
49
44
|
}
|
|
50
|
-
return
|
|
51
|
-
}
|
|
45
|
+
return cb(null, "127.0.0.1", 4);
|
|
46
|
+
}
|
|
47
|
+
return dns.lookup(hostname, options, cb);
|
|
52
48
|
},
|
|
53
|
-
}
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
// undici not available; nothing to do.
|
|
57
|
-
}
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
);
|
|
58
52
|
};
|
package/src/Util/effect.ts
CHANGED
|
@@ -64,6 +64,31 @@ export const taggedFunction = <
|
|
|
64
64
|
}) as Tag & Fn;
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
+
export const isYieldableEffect = (
|
|
68
|
+
value: unknown,
|
|
69
|
+
): value is Effect.Effect<unknown, unknown, unknown> =>
|
|
70
|
+
Effect.isEffect(value) &&
|
|
71
|
+
typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] ===
|
|
72
|
+
"function";
|
|
73
|
+
|
|
74
|
+
export type YieldableEffectLike<A = unknown, E = unknown, R = unknown> =
|
|
75
|
+
| Effect.Effect<A, E, R>
|
|
76
|
+
| {
|
|
77
|
+
asEffect: () => Effect.Effect<A, E, R>;
|
|
78
|
+
[Symbol.iterator]: () => Iterator<unknown>;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const isEffectClassLike = (
|
|
82
|
+
value: unknown,
|
|
83
|
+
): value is YieldableEffectLike =>
|
|
84
|
+
typeof value === "function" &&
|
|
85
|
+
typeof (value as { asEffect?: unknown }).asEffect === "function";
|
|
86
|
+
|
|
87
|
+
export const isYieldableEffectLike = (
|
|
88
|
+
value: unknown,
|
|
89
|
+
): value is YieldableEffectLike =>
|
|
90
|
+
isYieldableEffect(value) || isEffectClassLike(value);
|
|
91
|
+
|
|
67
92
|
export type UnwrapEffect<T> =
|
|
68
93
|
T extends Effect.Effect<infer A, any, any> ? A : T;
|
|
69
94
|
|
package/src/Variable.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as Config from "effect/Config";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Output from "./Output.ts";
|
|
4
|
+
import { toOutput } from "./Secret.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The shapes a {@link variable} can be derived from.
|
|
8
|
+
*/
|
|
9
|
+
export type VariableInput<T, R = never> =
|
|
10
|
+
| T
|
|
11
|
+
| Effect.Effect<T, any, R>
|
|
12
|
+
| Config.Config<T>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Bind a non-secret value into the active {@link RuntimeContext} (e.g. a
|
|
16
|
+
* Cloudflare Worker's `env`) under the given `name`. Counterpart to
|
|
17
|
+
* {@link Secret} for plain (non-redacted) values — the resource provider
|
|
18
|
+
* deploys it as `plain_text` / `json` rather than `secret_text`.
|
|
19
|
+
*
|
|
20
|
+
* The result is an `Output<T>` — `yield*`-ing it returns an `Accessor<T>`
|
|
21
|
+
* that resolves the value at runtime.
|
|
22
|
+
*
|
|
23
|
+
* @example One-arg shortcut — reads `Config.string("DATABASE_URL")`
|
|
24
|
+
* ```ts
|
|
25
|
+
* const url = yield* Alchemy.Variable("DATABASE_URL");
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example From a literal
|
|
29
|
+
* ```ts
|
|
30
|
+
* const port = yield* Alchemy.Variable("PORT", 3000);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function Variable(name: string): Output.Output<string, never>;
|
|
34
|
+
export function Variable<T, R = never>(
|
|
35
|
+
name: string,
|
|
36
|
+
value: VariableInput<T, R>,
|
|
37
|
+
): Output.Output<T, R>;
|
|
38
|
+
export function Variable<T = string, R = never>(
|
|
39
|
+
name: string,
|
|
40
|
+
value?: VariableInput<T, R>,
|
|
41
|
+
): Output.Output<T, R> {
|
|
42
|
+
const source: any = value ?? Config.string(name);
|
|
43
|
+
return Output.named(toOutput<T, R>(source), name);
|
|
44
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from "./Diff.ts";
|
|
|
14
14
|
export * from "./Input.ts";
|
|
15
15
|
export * from "./InstanceId.ts";
|
|
16
16
|
export * from "./Namespace.ts";
|
|
17
|
+
export { stackRef } from "./Output.ts";
|
|
17
18
|
export type { Output } from "./Output.ts";
|
|
18
19
|
export * from "./PhysicalName.ts";
|
|
19
20
|
export * as Plan from "./Plan.ts";
|
|
@@ -23,12 +24,14 @@ export * from "./Ref.ts";
|
|
|
23
24
|
export * as RemovalPolicy from "./RemovalPolicy.ts";
|
|
24
25
|
export * from "./Resource.ts";
|
|
25
26
|
export * as Schema from "./Schema.ts";
|
|
27
|
+
export { Secret } from "./Secret.ts";
|
|
26
28
|
export * as Server from "./Server/index.ts";
|
|
27
29
|
export * as Serverless from "./Serverless/index.ts";
|
|
28
30
|
export { Stack } from "./Stack.ts";
|
|
29
31
|
export * from "./Stage.ts";
|
|
30
32
|
export { inMemoryState, localState } from "./State/index.ts";
|
|
31
33
|
export * from "./Trait.ts";
|
|
34
|
+
export { Variable } from "./Variable.ts";
|
|
32
35
|
|
|
33
36
|
export * as Construct from "./Construct.ts";
|
|
34
37
|
|