alchemy 0.48.2 → 0.49.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.
- package/bin/alchemy.mjs +13 -13
- package/bin/commands/create.ts +0 -15
- package/bin/commands/deploy.ts +2 -0
- package/bin/commands/dev.ts +10 -1
- package/bin/services/execute-alchemy.ts +9 -0
- package/lib/alchemy.d.ts +6 -0
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +1 -0
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.js +13 -12
- package/lib/apply.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +21 -2
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bindings.js.map +1 -1
- package/lib/cloudflare/bound.d.ts +8 -1
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
- package/lib/cloudflare/compatibility-date.gen.js +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/cloudflare/miniflare/miniflare-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-options.js +4 -0
- package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +1 -1
- package/lib/cloudflare/rate-limit.d.ts +63 -0
- package/lib/cloudflare/rate-limit.d.ts.map +1 -0
- package/lib/cloudflare/rate-limit.js +41 -0
- package/lib/cloudflare/rate-limit.js.map +1 -0
- package/lib/cloudflare/tanstack-start.d.ts.map +1 -1
- package/lib/cloudflare/tanstack-start.js +10 -1
- package/lib/cloudflare/tanstack-start.js.map +1 -1
- package/lib/cloudflare/website.d.ts +4 -0
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +14 -1
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker-metadata.d.ts +3 -0
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +9 -0
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +9 -0
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +5 -1
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +23 -0
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +17 -1
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/context.d.ts +2 -2
- package/lib/context.d.ts.map +1 -1
- package/lib/planetscale/password.js +1 -1
- package/lib/planetscale/password.js.map +1 -1
- package/lib/scope.d.ts +7 -0
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +3 -1
- package/lib/scope.js.map +1 -1
- package/lib/test/bun.d.ts +1 -24
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js.map +1 -1
- package/lib/test/options.d.ts +30 -0
- package/lib/test/options.d.ts.map +1 -0
- package/lib/test/options.js +1 -0
- package/lib/test/options.js.map +1 -0
- package/lib/test/vitest.d.ts +1 -24
- package/lib/test/vitest.d.ts.map +1 -1
- package/lib/test/vitest.js.map +1 -1
- package/lib/util/ignore-matcher.d.ts.map +1 -1
- package/lib/util/ignore-matcher.js +1 -3
- package/lib/util/ignore-matcher.js.map +1 -1
- package/package.json +1 -1
- package/src/alchemy.ts +7 -0
- package/src/apply.ts +14 -13
- package/src/cloudflare/bindings.ts +22 -0
- package/src/cloudflare/bound.ts +29 -22
- package/src/cloudflare/compatibility-date.gen.ts +1 -1
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/miniflare/miniflare-worker-options.ts +4 -0
- package/src/cloudflare/rate-limit.ts +70 -0
- package/src/cloudflare/tanstack-start.ts +10 -1
- package/src/cloudflare/website.ts +20 -1
- package/src/cloudflare/worker-metadata.ts +11 -0
- package/src/cloudflare/worker.ts +15 -1
- package/src/cloudflare/wrangler.json.ts +46 -1
- package/src/context.ts +2 -2
- package/src/planetscale/password.ts +1 -1
- package/src/scope.ts +9 -1
- package/src/test/bun.ts +1 -28
- package/src/test/options.ts +34 -0
- package/src/test/vitest.ts +1 -28
- package/src/util/ignore-matcher.ts +0 -1
- package/templates/tanstack-start/alchemy.run.ts +1 -3
- package/templates/tanstack-start/package.json +3 -3
- package/templates/tanstack-start/vite.config.ts +26 -25
|
@@ -4,13 +4,21 @@ import type { Context } from "../context.ts";
|
|
|
4
4
|
import { formatJson } from "../fs/static-json-file.ts";
|
|
5
5
|
import { Resource } from "../resource.ts";
|
|
6
6
|
import { assertNever } from "../util/assert-never.ts";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Self,
|
|
9
|
+
type Bindings,
|
|
10
|
+
type WorkerBindingRateLimit,
|
|
11
|
+
} from "./bindings.ts";
|
|
8
12
|
import type { DurableObjectNamespace } from "./durable-object-namespace.ts";
|
|
9
13
|
import type { EventSource } from "./event-source.ts";
|
|
10
14
|
import { isQueueEventSource } from "./event-source.ts";
|
|
11
15
|
import { isQueue } from "./queue.ts";
|
|
12
16
|
import type { Worker, WorkerProps } from "./worker.ts";
|
|
13
17
|
|
|
18
|
+
type WranglerJsonRateLimit = Omit<WorkerBindingRateLimit, "type"> & {
|
|
19
|
+
type: "rate_limit";
|
|
20
|
+
};
|
|
21
|
+
|
|
14
22
|
/**
|
|
15
23
|
* Properties for wrangler.json configuration file
|
|
16
24
|
*/
|
|
@@ -149,6 +157,8 @@ export const WranglerJson = Resource(
|
|
|
149
157
|
binding: props.assets.binding,
|
|
150
158
|
}
|
|
151
159
|
: undefined,
|
|
160
|
+
placement: worker.placement,
|
|
161
|
+
limits: worker.limits,
|
|
152
162
|
};
|
|
153
163
|
|
|
154
164
|
// Process bindings if they exist
|
|
@@ -218,6 +228,20 @@ export interface WranglerJsonSpec {
|
|
|
218
228
|
*/
|
|
219
229
|
compatibility_flags?: string[];
|
|
220
230
|
|
|
231
|
+
/**
|
|
232
|
+
* The placement mode for the worker
|
|
233
|
+
*/
|
|
234
|
+
placement?: {
|
|
235
|
+
mode: "smart";
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* The CPU time limit for the worker
|
|
240
|
+
*/
|
|
241
|
+
limits?: {
|
|
242
|
+
cpu_ms?: number;
|
|
243
|
+
};
|
|
244
|
+
|
|
221
245
|
/**
|
|
222
246
|
* Whether to enable a workers.dev URL for this worker
|
|
223
247
|
*/
|
|
@@ -431,6 +455,13 @@ export interface WranglerJsonSpec {
|
|
|
431
455
|
namespace: string;
|
|
432
456
|
experimental_remote?: boolean;
|
|
433
457
|
}[];
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Unsafe bindings section for experimental features
|
|
461
|
+
*/
|
|
462
|
+
unsafe?: {
|
|
463
|
+
bindings: WranglerJsonRateLimit[];
|
|
464
|
+
};
|
|
434
465
|
}
|
|
435
466
|
|
|
436
467
|
/**
|
|
@@ -518,6 +549,7 @@ function processBindings(
|
|
|
518
549
|
namespace: string;
|
|
519
550
|
experimental_remote?: boolean;
|
|
520
551
|
}[] = [];
|
|
552
|
+
const unsafeBindings: WranglerJsonRateLimit[] = [];
|
|
521
553
|
const containers: {
|
|
522
554
|
class_name: string;
|
|
523
555
|
}[] = [];
|
|
@@ -705,6 +737,13 @@ function processBindings(
|
|
|
705
737
|
namespace: binding.namespaceName,
|
|
706
738
|
experimental_remote: true,
|
|
707
739
|
});
|
|
740
|
+
} else if (binding.type === "ratelimit") {
|
|
741
|
+
unsafeBindings.push({
|
|
742
|
+
name: bindingName,
|
|
743
|
+
type: "rate_limit",
|
|
744
|
+
namespace_id: binding.namespace_id.toString(),
|
|
745
|
+
simple: binding.simple,
|
|
746
|
+
});
|
|
708
747
|
} else if (binding.type === "secret_key") {
|
|
709
748
|
// no-op
|
|
710
749
|
} else if (binding.type === "container") {
|
|
@@ -786,4 +825,10 @@ function processBindings(
|
|
|
786
825
|
if (dispatchNamespaces.length > 0) {
|
|
787
826
|
spec.dispatch_namespaces = dispatchNamespaces;
|
|
788
827
|
}
|
|
828
|
+
|
|
829
|
+
if (unsafeBindings.length > 0) {
|
|
830
|
+
spec.unsafe = {
|
|
831
|
+
bindings: unsafeBindings,
|
|
832
|
+
};
|
|
833
|
+
}
|
|
789
834
|
}
|
package/src/context.ts
CHANGED
|
@@ -57,7 +57,7 @@ export interface BaseContext<Out extends Resource> {
|
|
|
57
57
|
* Indicate that this resource is being replaced.
|
|
58
58
|
* This will cause the resource to be deleted at the end of the stack's CREATE phase.
|
|
59
59
|
*/
|
|
60
|
-
replace(force?: boolean):
|
|
60
|
+
replace(force?: boolean): never;
|
|
61
61
|
/**
|
|
62
62
|
* Terminate the resource lifecycle handler and destroy the resource.
|
|
63
63
|
*
|
|
@@ -102,7 +102,7 @@ export function context<
|
|
|
102
102
|
seq: number;
|
|
103
103
|
props: Props;
|
|
104
104
|
state: State<Kind, Props, Out>;
|
|
105
|
-
replace: (force?: boolean) =>
|
|
105
|
+
replace: (force?: boolean) => never;
|
|
106
106
|
isReplacement?: boolean;
|
|
107
107
|
}): Context<Out> {
|
|
108
108
|
type InternalSymbols =
|
|
@@ -306,7 +306,7 @@ export const Password = Resource(
|
|
|
306
306
|
this.output.cidrs.length === props.cidrs.length &&
|
|
307
307
|
this.output.cidrs.every((cidr, i) => cidr === props.cidrs![i])))
|
|
308
308
|
) {
|
|
309
|
-
return
|
|
309
|
+
return this.replace();
|
|
310
310
|
}
|
|
311
311
|
const updateResponse = await api.patch(
|
|
312
312
|
`/organizations/${props.organizationId}/databases/${databaseName}/branches/${branchName}/passwords/${this.output.id}`,
|
package/src/scope.ts
CHANGED
|
@@ -50,6 +50,12 @@ export interface ScopeOptions {
|
|
|
50
50
|
* @default - `true` if ran with `alchemy dev`, `alchemy watch`, `bun --watch ./alchemy.run.ts`
|
|
51
51
|
*/
|
|
52
52
|
watch?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Apply updates to resources even if there are no changes.
|
|
55
|
+
*
|
|
56
|
+
* @default false
|
|
57
|
+
*/
|
|
58
|
+
force?: boolean;
|
|
53
59
|
telemetryClient?: ITelemetryClient;
|
|
54
60
|
logger?: LoggerApi;
|
|
55
61
|
}
|
|
@@ -120,6 +126,7 @@ export class Scope {
|
|
|
120
126
|
public readonly phase: Phase;
|
|
121
127
|
public readonly local: boolean;
|
|
122
128
|
public readonly watch: boolean;
|
|
129
|
+
public readonly force: boolean;
|
|
123
130
|
public readonly logger: LoggerApi;
|
|
124
131
|
public readonly telemetryClient: ITelemetryClient;
|
|
125
132
|
public readonly dataMutex: AsyncMutex;
|
|
@@ -177,6 +184,7 @@ export class Scope {
|
|
|
177
184
|
|
|
178
185
|
this.local = options.local ?? this.parent?.local ?? false;
|
|
179
186
|
this.watch = options.watch ?? this.parent?.watch ?? false;
|
|
187
|
+
this.force = options.force ?? this.parent?.force ?? false;
|
|
180
188
|
|
|
181
189
|
if (this.local) {
|
|
182
190
|
this.logger.warnOnce(
|
|
@@ -432,7 +440,7 @@ export class Scope {
|
|
|
432
440
|
event: "app.success",
|
|
433
441
|
elapsed: performance.now() - this.startedAt,
|
|
434
442
|
});
|
|
435
|
-
} else {
|
|
443
|
+
} else if (this.isErrored) {
|
|
436
444
|
this.logger.warn("Scope is in error, skipping finalize");
|
|
437
445
|
this.rootTelemetryClient?.record({
|
|
438
446
|
event: "app.error",
|
package/src/test/bun.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { afterAll, beforeAll, it } from "bun:test";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { alchemy } from "../alchemy.ts";
|
|
6
6
|
import { Scope } from "../scope.ts";
|
|
7
|
-
import type { StateStoreType } from "../state.ts";
|
|
8
7
|
import { NoopTelemetryClient } from "../util/telemetry/index.ts";
|
|
8
|
+
import type { TestOptions } from "./options.ts";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Extend the Alchemy interface to include test functionality
|
|
@@ -21,33 +21,6 @@ declare module "../alchemy.ts" {
|
|
|
21
21
|
*/
|
|
22
22
|
alchemy.test = test;
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* Options for configuring test behavior
|
|
26
|
-
*/
|
|
27
|
-
export interface TestOptions {
|
|
28
|
-
/**
|
|
29
|
-
* Whether to suppress logging output.
|
|
30
|
-
* @default false.
|
|
31
|
-
*/
|
|
32
|
-
quiet?: boolean;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Password to use for test resources.
|
|
36
|
-
* @default "test-password".
|
|
37
|
-
*/
|
|
38
|
-
password?: string;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Override the default state store for the test.
|
|
42
|
-
*/
|
|
43
|
-
stateStore?: StateStoreType;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Prefix to use for the scope to isolate tests and environments.
|
|
47
|
-
*/
|
|
48
|
-
prefix?: string;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
24
|
/**
|
|
52
25
|
* Test function type definition with overloads
|
|
53
26
|
*/
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { StateStoreType } from "../state.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Options for configuring test behavior
|
|
5
|
+
*/
|
|
6
|
+
export interface TestOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Whether to suppress logging output.
|
|
9
|
+
* @default false.
|
|
10
|
+
*/
|
|
11
|
+
quiet?: boolean;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Apply updates to resources even if there are no changes.
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
force?: boolean;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Password to use for test resources.
|
|
21
|
+
* @default "test-password".
|
|
22
|
+
*/
|
|
23
|
+
password?: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Override the default state store for the test.
|
|
27
|
+
*/
|
|
28
|
+
stateStore?: StateStoreType;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Prefix to use for the scope to isolate tests and environments.
|
|
32
|
+
*/
|
|
33
|
+
prefix?: string;
|
|
34
|
+
}
|
package/src/test/vitest.ts
CHANGED
|
@@ -2,7 +2,6 @@ import path from "node:path";
|
|
|
2
2
|
import { afterAll, beforeAll, it } from "vitest";
|
|
3
3
|
import { alchemy } from "../alchemy.ts";
|
|
4
4
|
import { Scope } from "../scope.ts";
|
|
5
|
-
import type { StateStoreType } from "../state.ts";
|
|
6
5
|
import {
|
|
7
6
|
CloudflareStateStore,
|
|
8
7
|
D1StateStore,
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
SQLiteStateStore,
|
|
11
10
|
} from "../state/index.ts";
|
|
12
11
|
import { NoopTelemetryClient } from "../util/telemetry/client.ts";
|
|
12
|
+
import type { TestOptions } from "./options.ts";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Extend the Alchemy interface to include test functionality
|
|
@@ -25,33 +25,6 @@ declare module "../alchemy.ts" {
|
|
|
25
25
|
*/
|
|
26
26
|
alchemy.test = test;
|
|
27
27
|
|
|
28
|
-
/**
|
|
29
|
-
* Options for configuring test behavior
|
|
30
|
-
*/
|
|
31
|
-
export interface TestOptions {
|
|
32
|
-
/**
|
|
33
|
-
* Whether to suppress logging output.
|
|
34
|
-
* @default false.
|
|
35
|
-
*/
|
|
36
|
-
quiet?: boolean;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Password to use for test resources.
|
|
40
|
-
* @default "test-password".
|
|
41
|
-
*/
|
|
42
|
-
password?: string;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Override the default state store for the test.
|
|
46
|
-
*/
|
|
47
|
-
stateStore?: StateStoreType;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Prefix to use for the scope to isolate tests and environments.
|
|
51
|
-
*/
|
|
52
|
-
prefix?: string;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
28
|
/**
|
|
56
29
|
* Test function type definition with overloads
|
|
57
30
|
*/
|
|
@@ -835,7 +835,6 @@ const isPathValid = (path: string): boolean =>
|
|
|
835
835
|
const setupWindows = (): void => {
|
|
836
836
|
/* eslint no-control-regex: "off" */
|
|
837
837
|
const makePosix = (str: string): string =>
|
|
838
|
-
// biome-ignore lint/suspicious/noControlCharactersInRegex: adapted from node-ignore
|
|
839
838
|
/^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str)
|
|
840
839
|
? str
|
|
841
840
|
: str.replace(/\\/g, "/");
|
|
@@ -5,9 +5,7 @@ import { TanStackStart } from "alchemy/cloudflare";
|
|
|
5
5
|
|
|
6
6
|
const app = await alchemy("my-alchemy-app");
|
|
7
7
|
|
|
8
|
-
export const worker = await TanStackStart("website"
|
|
9
|
-
command: "bun run build",
|
|
10
|
-
});
|
|
8
|
+
export const worker = await TanStackStart("website");
|
|
11
9
|
|
|
12
10
|
console.log({
|
|
13
11
|
url: worker.url,
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"start": "node .output/server/index.mjs"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@tanstack/react-router": "^1.
|
|
15
|
-
"@tanstack/react-router-devtools": "^1.
|
|
16
|
-
"@tanstack/react-start": "^1.
|
|
14
|
+
"@tanstack/react-router": "^1.128.3",
|
|
15
|
+
"@tanstack/react-router-devtools": "^1.128.3",
|
|
16
|
+
"@tanstack/react-start": "^1.128.3",
|
|
17
17
|
"react": "^19.0.0",
|
|
18
18
|
"react-dom": "^19.0.0",
|
|
19
19
|
"tailwind-merge": "3",
|
|
@@ -5,29 +5,30 @@ import { defineConfig, PluginOption } from "vite";
|
|
|
5
5
|
import tsConfigPaths from "vite-tsconfig-paths";
|
|
6
6
|
|
|
7
7
|
export default defineConfig({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
8
|
+
server: {
|
|
9
|
+
port: 3000,
|
|
10
|
+
},
|
|
11
|
+
build: {
|
|
12
|
+
target: "esnext",
|
|
13
|
+
rollupOptions: {
|
|
14
|
+
external: ["node:async_hooks", "cloudflare:workers"],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
plugins: [
|
|
18
|
+
tailwindcss() as PluginOption,
|
|
19
|
+
cloudflareWorkersDevEnvironmentShim(),
|
|
20
|
+
tsConfigPaths({
|
|
21
|
+
projects: ["./tsconfig.json"],
|
|
22
|
+
}),
|
|
23
|
+
tanstackStart({
|
|
24
|
+
target: "cloudflare-module",
|
|
25
|
+
customViteReactPlugin: true,
|
|
26
|
+
tsr: {
|
|
27
|
+
routeTreeFileHeader: [
|
|
28
|
+
"/** biome-ignore-all lint/suspicious/noExplicitAny: code generated by @tanstack/react-start */",
|
|
29
|
+
],
|
|
30
|
+
quoteStyle: "double",
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
33
34
|
});
|