alchemy 0.65.1 → 0.66.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 (119) hide show
  1. package/bin/alchemy.js +132 -78
  2. package/bin/commands/init.ts +6 -3
  3. package/bin/services/cdp-manager/server.ts +3 -2
  4. package/bin/services/execute-alchemy.ts +33 -3
  5. package/bin/services/find-workspace-root.ts +48 -0
  6. package/lib/alchemy.d.ts +14 -3
  7. package/lib/alchemy.d.ts.map +1 -1
  8. package/lib/alchemy.js +17 -5
  9. package/lib/alchemy.js.map +1 -1
  10. package/lib/apply.d.ts.map +1 -1
  11. package/lib/apply.js +51 -1
  12. package/lib/apply.js.map +1 -1
  13. package/lib/cloudflare/bucket.js +1 -1
  14. package/lib/cloudflare/bucket.js.map +1 -1
  15. package/lib/cloudflare/cloudflare-env-proxy.js +3 -3
  16. package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -1
  17. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  18. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  19. package/lib/cloudflare/d1-database.d.ts.map +1 -1
  20. package/lib/cloudflare/d1-database.js +2 -1
  21. package/lib/cloudflare/d1-database.js.map +1 -1
  22. package/lib/cloudflare/d1-local-migrations.d.ts +1 -0
  23. package/lib/cloudflare/d1-local-migrations.d.ts.map +1 -1
  24. package/lib/cloudflare/d1-local-migrations.js +3 -2
  25. package/lib/cloudflare/d1-local-migrations.js.map +1 -1
  26. package/lib/cloudflare/kv-namespace.js +1 -1
  27. package/lib/cloudflare/kv-namespace.js.map +1 -1
  28. package/lib/cloudflare/miniflare/delete.d.ts +3 -2
  29. package/lib/cloudflare/miniflare/delete.d.ts.map +1 -1
  30. package/lib/cloudflare/miniflare/delete.js +13 -12
  31. package/lib/cloudflare/miniflare/delete.js.map +1 -1
  32. package/lib/cloudflare/miniflare/miniflare-controller.d.ts.map +1 -1
  33. package/lib/cloudflare/miniflare/miniflare-controller.js +5 -4
  34. package/lib/cloudflare/miniflare/miniflare-controller.js.map +1 -1
  35. package/lib/cloudflare/miniflare/paths.d.ts +4 -4
  36. package/lib/cloudflare/miniflare/paths.d.ts.map +1 -1
  37. package/lib/cloudflare/miniflare/paths.js +10 -4
  38. package/lib/cloudflare/miniflare/paths.js.map +1 -1
  39. package/lib/cloudflare/miniflare/symlink-miniflare-state.d.ts +2 -0
  40. package/lib/cloudflare/miniflare/symlink-miniflare-state.d.ts.map +1 -0
  41. package/lib/cloudflare/miniflare/symlink-miniflare-state.js +19 -0
  42. package/lib/cloudflare/miniflare/symlink-miniflare-state.js.map +1 -0
  43. package/lib/cloudflare/nuxt/plugin.d.ts.map +1 -1
  44. package/lib/cloudflare/nuxt/plugin.js +3 -3
  45. package/lib/cloudflare/nuxt/plugin.js.map +1 -1
  46. package/lib/cloudflare/redwood/plugin.js +2 -2
  47. package/lib/cloudflare/redwood/plugin.js.map +1 -1
  48. package/lib/cloudflare/vite/plugin.d.ts.map +1 -1
  49. package/lib/cloudflare/vite/plugin.js +6 -3
  50. package/lib/cloudflare/vite/plugin.js.map +1 -1
  51. package/lib/cloudflare/website.d.ts.map +1 -1
  52. package/lib/cloudflare/website.js +5 -16
  53. package/lib/cloudflare/website.js.map +1 -1
  54. package/lib/cloudflare/worker.d.ts.map +1 -1
  55. package/lib/cloudflare/worker.js +4 -2
  56. package/lib/cloudflare/worker.js.map +1 -1
  57. package/lib/cloudflare/wrangler.json.js +1 -0
  58. package/lib/cloudflare/wrangler.json.js.map +1 -1
  59. package/lib/scope.d.ts +16 -0
  60. package/lib/scope.d.ts.map +1 -1
  61. package/lib/scope.js +10 -5
  62. package/lib/scope.js.map +1 -1
  63. package/lib/state/file-system-state-store.d.ts.map +1 -1
  64. package/lib/state/file-system-state-store.js +1 -2
  65. package/lib/state/file-system-state-store.js.map +1 -1
  66. package/lib/state/sqlite-state-store.d.ts +11 -0
  67. package/lib/state/sqlite-state-store.d.ts.map +1 -1
  68. package/lib/state/sqlite-state-store.js +22 -14
  69. package/lib/state/sqlite-state-store.js.map +1 -1
  70. package/lib/stripe/customer.d.ts +0 -8
  71. package/lib/stripe/customer.d.ts.map +1 -1
  72. package/lib/stripe/customer.js +0 -6
  73. package/lib/stripe/customer.js.map +1 -1
  74. package/lib/stripe/price.d.ts +23 -23
  75. package/lib/stripe/price.d.ts.map +1 -1
  76. package/lib/stripe/price.js +6 -22
  77. package/lib/stripe/price.js.map +1 -1
  78. package/lib/test/vitest.d.ts.map +1 -1
  79. package/lib/test/vitest.js +1 -1
  80. package/lib/test/vitest.js.map +1 -1
  81. package/lib/util/assert-never.js +1 -1
  82. package/lib/util/assert-never.js.map +1 -1
  83. package/lib/util/cli.d.ts.map +1 -1
  84. package/lib/util/cli.js +12 -13
  85. package/lib/util/cli.js.map +1 -1
  86. package/lib/util/root-dir.d.ts +2 -0
  87. package/lib/util/root-dir.d.ts.map +1 -0
  88. package/lib/util/root-dir.js +2 -0
  89. package/lib/util/root-dir.js.map +1 -0
  90. package/package.json +4 -4
  91. package/src/alchemy.ts +36 -8
  92. package/src/apply.ts +58 -3
  93. package/src/cloudflare/bucket.ts +1 -1
  94. package/src/cloudflare/cloudflare-env-proxy.ts +5 -5
  95. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  96. package/src/cloudflare/d1-database.ts +2 -1
  97. package/src/cloudflare/d1-local-migrations.ts +10 -6
  98. package/src/cloudflare/kv-namespace.ts +1 -1
  99. package/src/cloudflare/miniflare/delete.ts +19 -11
  100. package/src/cloudflare/miniflare/miniflare-controller.ts +10 -6
  101. package/src/cloudflare/miniflare/paths.ts +11 -7
  102. package/src/cloudflare/miniflare/symlink-miniflare-state.ts +19 -0
  103. package/src/cloudflare/nuxt/plugin.ts +12 -3
  104. package/src/cloudflare/redwood/plugin.ts +2 -2
  105. package/src/cloudflare/vite/plugin.ts +8 -3
  106. package/src/cloudflare/website.ts +5 -19
  107. package/src/cloudflare/worker.ts +4 -2
  108. package/src/cloudflare/wrangler.json.ts +1 -0
  109. package/src/scope.ts +26 -5
  110. package/src/state/file-system-state-store.ts +1 -2
  111. package/src/state/sqlite-state-store.ts +41 -14
  112. package/src/stripe/customer.ts +0 -14
  113. package/src/stripe/price.ts +59 -56
  114. package/src/test/vitest.ts +4 -1
  115. package/src/util/assert-never.ts +1 -1
  116. package/src/util/cli.ts +15 -13
  117. package/src/util/root-dir.ts +1 -0
  118. package/templates/nextjs/alchemy.run.ts +2 -2
  119. package/workers/cloudflare-state-store.js +1 -1
@@ -1,7 +1,8 @@
1
1
  import type { Config as LibSQLConfig } from "@libsql/client";
2
- import fs from "node:fs";
2
+ import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import type { Scope } from "../scope.ts";
5
+ import { exists } from "../util/exists.ts";
5
6
  import { memoize } from "../util/memoize.ts";
6
7
  import { importPeer } from "../util/peer.ts";
7
8
  import { MIGRATIONS_DIRECTORY } from "./migrations.ts";
@@ -27,6 +28,7 @@ interface BunSQLiteStateStoreOptions {
27
28
  readwrite?: boolean;
28
29
  safeIntegers?: boolean;
29
30
  strict?: boolean;
31
+ dotAlchemy?: string;
30
32
  }
31
33
 
32
34
  interface LibSQLStateStoreOptions extends Omit<LibSQLConfig, "url"> {
@@ -50,6 +52,11 @@ interface LibSQLStateStoreOptions extends Omit<LibSQLConfig, "url"> {
50
52
  * https://github.com/libsql/libsql-client-ts#supported-urls
51
53
  */
52
54
  url?: string;
55
+ /**
56
+ * The path to the .alchemy directory.
57
+ * @default "./.alchemy"
58
+ */
59
+ dotAlchemy?: string;
53
60
  }
54
61
 
55
62
  interface AutoSQLiteStateStoreOptions {
@@ -64,6 +71,12 @@ interface AutoSQLiteStateStoreOptions {
64
71
  * @default ".alchemy/state.sqlite"
65
72
  */
66
73
  filename?: string;
74
+
75
+ /**
76
+ * The path to the .alchemy directory.
77
+ * @default "./.alchemy"
78
+ */
79
+ dotAlchemy?: string;
67
80
  }
68
81
 
69
82
  type SQLiteStateStoreOptions =
@@ -80,7 +93,10 @@ export class SQLiteStateStore extends StateStoreProxy {
80
93
  }
81
94
 
82
95
  async provision(): Promise<StateStoreProxy.Dispatch> {
83
- const db = await createDatabase(this.options);
96
+ const db = await createDatabase({
97
+ ...(this.options ?? {}),
98
+ dotAlchemy: this.scope.dotAlchemy,
99
+ });
84
100
  const { SQLiteStateStoreOperations } = await import("./operations.js");
85
101
  const operations = new SQLiteStateStoreOperations(db, {
86
102
  chain: this.scope.chain,
@@ -97,17 +113,23 @@ const createDatabase = memoize(
97
113
  case "libsql":
98
114
  return await createLibSQLDatabase(options);
99
115
  default: {
100
- return await createDefaultDatabase(options?.filename);
116
+ return await createDefaultDatabase(
117
+ options?.filename,
118
+ options?.dotAlchemy,
119
+ );
101
120
  }
102
121
  }
103
122
  },
104
123
  );
105
124
 
106
- async function createDefaultDatabase(filename: string | undefined) {
125
+ async function createDefaultDatabase(
126
+ filename: string | undefined,
127
+ dotAlchemy: string | undefined,
128
+ ) {
107
129
  if ("Bun" in globalThis) {
108
- return createBunSQLiteDatabase({ engine: "bun", filename });
130
+ return createBunSQLiteDatabase({ engine: "bun", filename, dotAlchemy });
109
131
  }
110
- return createLibSQLDatabase({ engine: "libsql", filename });
132
+ return createLibSQLDatabase({ engine: "libsql", filename, dotAlchemy });
111
133
  }
112
134
 
113
135
  async function createBunSQLiteDatabase(
@@ -122,8 +144,8 @@ async function createBunSQLiteDatabase(
122
144
  const filename =
123
145
  options?.filename ??
124
146
  process.env.ALCHEMY_STATE_FILE ??
125
- ".alchemy/state.sqlite";
126
- ensureDirectory(filename);
147
+ path.join(options?.dotAlchemy ?? ".alchemy", "state.sqlite");
148
+ await ensureDirectory(filename);
127
149
  const { Database } = await import("bun:sqlite");
128
150
  const { drizzle } = await importPeer(
129
151
  import("drizzle-orm/bun-sqlite"),
@@ -135,7 +157,11 @@ async function createBunSQLiteDatabase(
135
157
  // options are passed in, so here's some ugly destructuring!
136
158
  const { engine: _engine, filename: _filename, ...rest } = options ?? {};
137
159
  const bunOptions = Object.keys(rest).length > 0 ? rest : undefined;
138
- const client = new Database(filename, bunOptions);
160
+ const client = new Database(filename, {
161
+ readwrite: true,
162
+ create: true,
163
+ ...bunOptions,
164
+ });
139
165
  client.exec("PRAGMA journal_mode = WAL;");
140
166
  const db = drizzle(client, {
141
167
  schema,
@@ -149,10 +175,11 @@ async function createLibSQLDatabase(
149
175
  ) {
150
176
  const url =
151
177
  options?.url ??
152
- `file:${options?.filename ?? process.env.ALCHEMY_STATE_FILE ?? ".alchemy/state.sqlite"}`;
178
+ `file:${options?.filename ?? process.env.ALCHEMY_STATE_FILE ?? path.join(options?.dotAlchemy ?? ".alchemy", "state.sqlite")}`;
179
+
153
180
  const filename = url.startsWith("file:") ? url.slice(5) : undefined;
154
181
  if (filename) {
155
- ensureDirectory(filename);
182
+ await ensureDirectory(filename);
156
183
  }
157
184
  const { drizzle } = await importPeer(
158
185
  import("drizzle-orm/libsql"),
@@ -173,9 +200,9 @@ async function createLibSQLDatabase(
173
200
  return db;
174
201
  }
175
202
 
176
- const ensureDirectory = (filename: string) => {
203
+ const ensureDirectory = async (filename: string) => {
177
204
  const dir = path.dirname(filename);
178
- if (!fs.existsSync(dir)) {
179
- fs.mkdirSync(dir, { recursive: true });
205
+ if (!(await exists(dir))) {
206
+ await fs.mkdir(dir, { recursive: true });
180
207
  }
181
208
  };
@@ -92,10 +92,6 @@ export interface CustomerProps {
92
92
  * An integer amount in cents that represents the customer's current balance
93
93
  */
94
94
  balance?: number;
95
- /**
96
- * If you provide a coupon code, the customer will have a discount applied on all recurring charges
97
- */
98
- coupon?: string;
99
95
  /**
100
96
  * An arbitrary string attached to the object
101
97
  */
@@ -136,10 +132,6 @@ export interface CustomerProps {
136
132
  * Customer's preferred languages, ordered by preference
137
133
  */
138
134
  preferredLocales?: string[];
139
- /**
140
- * The ID of a promotion code to apply to the customer
141
- */
142
- promotionCode?: string;
143
135
  /**
144
136
  * The customer's shipping information
145
137
  */
@@ -311,7 +303,6 @@ export const Customer = Resource(
311
303
  }
312
304
  : undefined,
313
305
  balance: props.balance,
314
- coupon: props.coupon,
315
306
  description: props.description,
316
307
  email: props.email,
317
308
  invoice_prefix: props.invoicePrefix,
@@ -320,7 +311,6 @@ export const Customer = Resource(
320
311
  next_invoice_sequence: props.nextInvoiceSequence,
321
312
  phone: props.phone,
322
313
  preferred_locales: props.preferredLocales,
323
- promotion_code: props.promotionCode,
324
314
  shipping: props.shipping as any,
325
315
  source: props.source,
326
316
  tax_exempt: props.taxExempt,
@@ -354,7 +344,6 @@ export const Customer = Resource(
354
344
  }
355
345
  : undefined,
356
346
  balance: props.balance,
357
- coupon: props.coupon,
358
347
  description: props.description,
359
348
  email: props.email,
360
349
  invoice_prefix: props.invoicePrefix,
@@ -364,7 +353,6 @@ export const Customer = Resource(
364
353
  payment_method: props.paymentMethod,
365
354
  phone: props.phone,
366
355
  preferred_locales: props.preferredLocales,
367
- promotion_code: props.promotionCode,
368
356
  shipping: props.shipping as any,
369
357
  source: props.source,
370
358
  tax_exempt: props.taxExempt,
@@ -404,7 +392,6 @@ export const Customer = Resource(
404
392
  }
405
393
  : undefined,
406
394
  balance: props.balance,
407
- coupon: props.coupon,
408
395
  description: props.description,
409
396
  email: props.email,
410
397
  invoice_prefix: props.invoicePrefix,
@@ -413,7 +400,6 @@ export const Customer = Resource(
413
400
  next_invoice_sequence: props.nextInvoiceSequence,
414
401
  phone: props.phone,
415
402
  preferred_locales: props.preferredLocales,
416
- promotion_code: props.promotionCode,
417
403
  shipping: props.shipping as any,
418
404
  source: props.source,
419
405
  tax_exempt: props.taxExempt,
@@ -4,41 +4,60 @@ import { Resource } from "../resource.ts";
4
4
  import type { Secret } from "../secret.ts";
5
5
  import { logger } from "../util/logger.ts";
6
6
  import { createStripeClient, handleStripeDeleteError } from "./client.ts";
7
+ import type { Meter } from "./meter.ts";
7
8
 
8
9
  /**
9
10
  * Properties for price recurring configuration
10
11
  */
11
- export interface PriceRecurring {
12
- /**
13
- * Specifies billing frequency. Either 'day', 'week', 'month' or 'year'.
14
- */
15
- interval: Stripe.PriceCreateParams.Recurring.Interval;
16
-
17
- /**
18
- * The number of intervals between subscription billings. For example, interval=month and interval_count=3 bills every 3 months.
19
- */
20
- intervalCount?: number;
21
-
22
- /**
23
- * Configures how the quantity per period should be determined, can be either 'metered' or 'licensed'.
24
- * 'licensed' will automatically bill the quantity set for a plan when adding it to a subscription,
25
- * 'metered' will aggregate the total usage based on usage records.
26
- */
27
- usageType?: Stripe.PriceCreateParams.Recurring.UsageType;
28
-
29
- /**
30
- * Specifies a usage aggregation strategy for prices of `usage_type=metered`. Allowed values are `sum` for summing up all usage during a period,
31
- * `last_during_period` for picking the last usage record reported within a period,
32
- * `last_ever` for picking the last usage record ever (across period bounds) or `max` which picks the usage record with the maximum reported usage during a period.
33
- */
34
- aggregateUsage?: Stripe.PriceCreateParams.Recurring.AggregateUsage;
35
-
36
- /**
37
- * The ID of the billing meter this price is associated with.
38
- * Only applicable when usageType = 'metered'.
39
- */
40
- meter?: string;
41
- }
12
+ export type PriceRecurring =
13
+ // If usageType is 'metered', meter is required
14
+ | {
15
+ /**
16
+ * Specifies billing frequency. Either 'day', 'week', 'month' or 'year'.
17
+ */
18
+ interval: Stripe.PriceCreateParams.Recurring.Interval;
19
+
20
+ /**
21
+ * The number of intervals between subscription billings. For example, interval=month and interval_count=3 bills every 3 months.
22
+ */
23
+ intervalCount?: number;
24
+
25
+ /**
26
+ * Configures how the quantity per period should be determined, can be either 'metered' or 'licensed'.
27
+ * 'metered' will aggregate the total usage based on usage records.
28
+ */
29
+ usageType: "metered";
30
+
31
+ /**
32
+ * The ID of the billing meter this price is associated with.
33
+ * Required when usageType = 'metered'.
34
+ */
35
+ meter: string | Meter;
36
+ }
37
+ // If usageType is 'licensed' or not provided, meter is not allowed
38
+ | {
39
+ /**
40
+ * Specifies billing frequency. Either 'day', 'week', 'month' or 'year'.
41
+ */
42
+ interval: Stripe.PriceCreateParams.Recurring.Interval;
43
+
44
+ /**
45
+ * The number of intervals between subscription billings. For example, interval=month and interval_count=3 bills every 3 months.
46
+ */
47
+ intervalCount?: number;
48
+
49
+ /**
50
+ * Configures how the quantity per period should be determined, can be either 'metered' or 'licensed'.
51
+ * 'licensed' will automatically bill the quantity set for a plan when adding it to a subscription.
52
+ */
53
+ usageType?: "licensed" | undefined;
54
+
55
+ /**
56
+ * The ID of the billing meter this price is associated with.
57
+ * Not applicable when usageType is not 'metered'.
58
+ */
59
+ meter?: never;
60
+ };
42
61
 
43
62
  type TaxBehavior = Stripe.PriceCreateParams.TaxBehavior;
44
63
  type BillingScheme = Stripe.PriceCreateParams.BillingScheme;
@@ -262,19 +281,6 @@ export interface Price extends Resource<"stripe::Price">, PriceProps {
262
281
  * });
263
282
  *
264
283
  * @example
265
- * // Create a metered price for usage-based billing
266
- * const meteredPrice = await Price("storage", {
267
- * currency: "usd",
268
- * unitAmount: 25, // $0.25 per GB
269
- * product: "prod_xyz",
270
- * recurring: {
271
- * interval: "month",
272
- * usageType: "metered",
273
- * aggregateUsage: "sum"
274
- * }
275
- * });
276
- *
277
- * @example
278
284
  * // Create a graduated tiered price with usage-based billing
279
285
  * const tieredPrice = await Price("api-usage", {
280
286
  * currency: "usd",
@@ -428,22 +434,21 @@ export const Price = Resource(
428
434
  interval: props.recurring.interval,
429
435
  interval_count: props.recurring.intervalCount,
430
436
  usage_type: props.recurring.usageType,
431
- aggregate_usage: props.recurring.aggregateUsage,
432
437
  };
433
438
 
434
439
  // Add meter to recurring if present (only for metered usage type)
435
- if (props.recurring.meter) {
436
- if (props.recurring.usageType !== "metered") {
437
- throw new Error(
438
- "Meter can only be set for prices with recurring.usageType = 'metered'",
439
- );
440
- }
441
- // Extend the recurring params with meter
440
+ if (
441
+ props.recurring.usageType === "metered" &&
442
+ props.recurring.meter
443
+ ) {
442
444
  (
443
445
  createParams.recurring as Stripe.PriceCreateParams.Recurring & {
444
446
  meter: string;
445
447
  }
446
- ).meter = props.recurring.meter;
448
+ ).meter =
449
+ typeof props.recurring.meter === "string"
450
+ ? props.recurring.meter
451
+ : props.recurring.meter.id;
447
452
  }
448
453
  }
449
454
 
@@ -514,8 +519,6 @@ export const Price = Resource(
514
519
  intervalCount: price.recurring.interval_count,
515
520
  usageType: price.recurring
516
521
  .usage_type as Stripe.PriceCreateParams.Recurring.UsageType,
517
- aggregateUsage: price.recurring
518
- .aggregate_usage as Stripe.PriceCreateParams.Recurring.AggregateUsage,
519
522
  meter: (
520
523
  price.recurring as Stripe.Price.Recurring & { meter?: string }
521
524
  ).meter,
@@ -552,7 +555,7 @@ export const Price = Resource(
552
555
  active: price.active,
553
556
  billingScheme: price.billing_scheme as BillingScheme,
554
557
  nickname: price.nickname || undefined,
555
- recurring: recurring,
558
+ recurring: recurring as PriceRecurring,
556
559
  metadata: price.metadata || undefined,
557
560
  taxBehavior: price.tax_behavior as TaxBehavior,
558
561
  createdAt: price.created,
@@ -112,7 +112,10 @@ export function test(
112
112
  return new D1StateStore(scope);
113
113
  default:
114
114
  return new SQLiteStateStore(scope, {
115
- filename: `.alchemy/${path.relative(process.cwd(), meta.filename)}.sqlite`,
115
+ filename: path.join(
116
+ scope.dotAlchemy,
117
+ `${path.relative(process.cwd(), meta.filename)}.sqlite`,
118
+ ),
116
119
  });
117
120
  }
118
121
  };
@@ -1,3 +1,3 @@
1
1
  export function assertNever(value: never, message?: string): never {
2
- throw new Error(message ?? `Unexpected value: ${value}`);
2
+ throw new Error(message ?? `Unexpected value: ${JSON.stringify(value)}`);
3
3
  }
package/src/util/cli.ts CHANGED
@@ -55,16 +55,16 @@ interface AlchemyInfo {
55
55
  appName: string;
56
56
  }
57
57
 
58
- let loggerApi: LoggerApi | null = null;
58
+ let loggers: {
59
+ [appName: string]: LoggerApi;
60
+ } = {};
61
+
59
62
  export const createLoggerInstance = (
60
63
  alchemyInfo: AlchemyInfo,
61
64
  customLogger?: LoggerApi,
62
65
  ) => {
63
- if (loggerApi) return loggerApi;
64
-
65
- // Use custom logger if provided, otherwise use the basic fallback logger
66
- loggerApi = customLogger ?? createFallbackLogger(alchemyInfo);
67
- return loggerApi;
66
+ return (loggers[alchemyInfo.appName] ??=
67
+ customLogger ?? createFallbackLogger(alchemyInfo));
68
68
  };
69
69
 
70
70
  export const createDummyLogger = (): LoggerApi => {
@@ -79,13 +79,15 @@ export const createDummyLogger = (): LoggerApi => {
79
79
  };
80
80
 
81
81
  export const createFallbackLogger = (alchemyInfo: AlchemyInfo): LoggerApi => {
82
- console.log(dedent`
83
- ${colorize("Alchemy", "cyanBright")} (v${packageJson.version})
84
- App: ${alchemyInfo.appName}
85
- Phase: ${alchemyInfo.phase}
86
- Stage: ${alchemyInfo.stage}
87
-
88
- `);
82
+ if (alchemyInfo.phase !== "read") {
83
+ console.log(dedent`
84
+ ${colorize("Alchemy", "cyanBright")} (v${packageJson.version})
85
+ App: ${alchemyInfo.appName}
86
+ Phase: ${alchemyInfo.phase}
87
+ Stage: ${alchemyInfo.stage}
88
+
89
+ `);
90
+ }
89
91
 
90
92
  return {
91
93
  log: console.log,
@@ -0,0 +1 @@
1
+ export const ALCHEMY_ROOT = process.env.ALCHEMY_ROOT ?? process.cwd();
@@ -5,12 +5,12 @@ import { Nextjs } from "alchemy/cloudflare";
5
5
 
6
6
  const app = await alchemy("{projectName}");
7
7
 
8
- export const website = await Nextjs("website", {
8
+ export const worker = await Nextjs("website", {
9
9
  name: `${app.name}-${app.stage}-website`,
10
10
  });
11
11
 
12
12
  console.log({
13
- url: website.url,
13
+ url: worker.url,
14
14
  });
15
15
 
16
16
  await app.finalize();
@@ -5397,7 +5397,7 @@ var migrations_default = {
5397
5397
 
5398
5398
  // src/util/assert-never.ts
5399
5399
  function assertNever(value, message) {
5400
- throw new Error(message ?? `Unexpected value: ${value}`);
5400
+ throw new Error(message ?? `Unexpected value: ${JSON.stringify(value)}`);
5401
5401
  }
5402
5402
 
5403
5403
  // src/state/schema.ts