wrangler 2.9.1 → 2.10.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 (70) hide show
  1. package/README.md +3 -3
  2. package/miniflare-dist/index.mjs +1 -1
  3. package/package.json +8 -8
  4. package/src/__tests__/configuration.test.ts +70 -0
  5. package/src/__tests__/d1/d1.test.ts +2 -2
  6. package/src/__tests__/d1/execute.test.ts +64 -0
  7. package/src/__tests__/d1/migrate.test.ts +14 -0
  8. package/src/__tests__/deployments.test.ts +40 -16
  9. package/src/__tests__/dev.test.tsx +3 -3
  10. package/src/__tests__/helpers/msw/handlers/deployments.ts +40 -16
  11. package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
  12. package/src/__tests__/index.test.ts +2 -0
  13. package/src/__tests__/kv.test.ts +8 -8
  14. package/src/__tests__/middleware.test.ts +65 -0
  15. package/src/__tests__/mtls-certificates.test.ts +585 -0
  16. package/src/__tests__/pages/functions-build.test.ts +402 -0
  17. package/src/__tests__/pages/pages.test.ts +7 -7
  18. package/src/__tests__/pages/publish.test.ts +525 -1
  19. package/src/__tests__/publish.test.ts +58 -27
  20. package/src/__tests__/queues.test.ts +2 -2
  21. package/src/__tests__/secret.test.ts +4 -4
  22. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  23. package/src/__tests__/user.test.ts +1 -1
  24. package/src/__tests__/whoami.test.tsx +1 -1
  25. package/src/api/index.ts +8 -0
  26. package/src/api/mtls-certificate.ts +148 -0
  27. package/src/api/pages/create-worker-bundle-contents.ts +75 -0
  28. package/src/api/pages/publish.tsx +52 -8
  29. package/src/bundle.ts +6 -5
  30. package/src/config/config.ts +7 -7
  31. package/src/config/environment.ts +9 -2
  32. package/src/config/index.ts +13 -0
  33. package/src/config/validation.ts +50 -3
  34. package/src/create-worker-upload-form.ts +9 -0
  35. package/src/d1/execute.tsx +123 -90
  36. package/src/d1/migrations/apply.tsx +29 -24
  37. package/src/d1/migrations/create.tsx +7 -7
  38. package/src/d1/migrations/helpers.ts +63 -38
  39. package/src/d1/migrations/list.tsx +19 -16
  40. package/src/d1/migrations/options.ts +6 -1
  41. package/src/d1/types.ts +1 -0
  42. package/src/d1/utils.ts +2 -1
  43. package/src/deployments.ts +62 -39
  44. package/src/dev/dev.tsx +1 -15
  45. package/src/dev/remote.tsx +2 -2
  46. package/src/dev.tsx +9 -6
  47. package/src/generate/index.ts +1 -1
  48. package/src/index.ts +15 -5
  49. package/src/miniflare-cli/assets.ts +1 -1
  50. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  51. package/src/mtls-certificate/cli.ts +155 -0
  52. package/src/pages/build.ts +103 -23
  53. package/src/pages/buildFunctions.ts +32 -31
  54. package/src/pages/dev.ts +4 -2
  55. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  56. package/src/pages/publish.tsx +12 -1
  57. package/src/pages/utils.ts +1 -1
  58. package/src/publish/publish.ts +3 -2
  59. package/src/secret/index.ts +1 -0
  60. package/src/sites.ts +1 -1
  61. package/src/tail/filters.ts +1 -1
  62. package/src/user/user.ts +4 -3
  63. package/src/worker.ts +6 -0
  64. package/templates/format-dev-errors.ts +1 -0
  65. package/templates/new-worker.ts +3 -0
  66. package/templates/serve-static-assets.ts +1 -0
  67. package/templates/service-bindings-module-facade.js +1 -0
  68. package/templates/tsconfig.tsbuildinfo +1 -1
  69. package/wrangler-dist/cli.d.ts +82 -2
  70. package/wrangler-dist/cli.js +1501 -1031
@@ -27,17 +27,6 @@ import type {
27
27
  StrictYargsOptionsToInterface,
28
28
  } from "../yargs-types";
29
29
  import type { Database } from "./types";
30
- import type { Statement as StatementType } from "@miniflare/d1";
31
- import type { createSQLiteDB as createSQLiteDBType } from "@miniflare/shared";
32
-
33
- type MiniflareNpxImportTypes = [
34
- {
35
- Statement: typeof StatementType;
36
- },
37
- {
38
- createSQLiteDB: typeof createSQLiteDBType;
39
- }
40
- ];
41
30
 
42
31
  export type QueryResult = {
43
32
  results: Record<string, string | number | boolean>[];
@@ -80,55 +69,19 @@ export function Options(yargs: CommonYargsArgv) {
80
69
  describe: "Return output as clean JSON",
81
70
  type: "boolean",
82
71
  default: false,
72
+ })
73
+ .option("preview", {
74
+ describe: "Execute commands/files against a preview D1 DB",
75
+ type: "boolean",
76
+ default: false,
83
77
  });
84
78
  }
85
79
 
86
- function shorten(query: string | undefined, length: number) {
87
- return query && query.length > length
88
- ? query.slice(0, length) + "..."
89
- : query;
90
- }
91
-
92
- export async function executeSql(
93
- local: undefined | boolean,
94
- config: ConfigFields<DevConfig> & Environment,
95
- name: string,
96
- shouldPrompt: boolean | undefined,
97
- persistTo: undefined | string,
98
- file?: string,
99
- command?: string,
100
- json?: boolean
101
- ) {
102
- const sql = file ? readFileSync(file) : command;
103
- if (!sql) throw new Error(`Error: must provide --command or --file.`);
104
- if (persistTo && !local)
105
- throw new Error(`Error: can't use --persist-to without --local`);
106
- logger.log(`šŸŒ€ Mapping SQL input into an array of statements`);
107
- const queries = splitSqlQuery(sql);
108
-
109
- if (file && sql) {
110
- if (queries[0].startsWith("SQLite format 3")) {
111
- //TODO: update this error to recommend using `wrangler d1 restore` when it exists
112
- throw new Error(
113
- "Provided file is a binary SQLite database file instead of an SQL text file.\nThe execute command can only process SQL text files.\nPlease export an SQL file from your SQLite database and try again."
114
- );
115
- }
116
- }
117
-
118
- return local
119
- ? await executeLocally(config, name, shouldPrompt, queries, persistTo, json)
120
- : await executeRemotely(
121
- config,
122
- name,
123
- shouldPrompt,
124
- batchSplit(queries),
125
- json
126
- );
127
- }
128
80
  type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
129
81
 
130
82
  export const Handler = async (args: HandlerOptions): Promise<void> => {
131
- const { local, database, yes, persistTo, file, command, json } = args;
83
+ const { local, database, yes, persistTo, file, command, json, preview } =
84
+ args;
132
85
  const existingLogLevel = logger.loggerLevel;
133
86
  if (json) {
134
87
  // set loggerLevel to error to avoid readConfig warnings appearing in JSON output
@@ -140,16 +93,17 @@ export const Handler = async (args: HandlerOptions): Promise<void> => {
140
93
  return logger.error(`Error: can't provide both --command and --file.`);
141
94
 
142
95
  const isInteractive = process.stdout.isTTY;
143
- const response: QueryResult[] | null = await executeSql(
96
+ const response: QueryResult[] | null = await executeSql({
144
97
  local,
145
98
  config,
146
- database,
147
- isInteractive && !yes,
99
+ name: database,
100
+ shouldPrompt: isInteractive && !yes,
148
101
  persistTo,
149
102
  file,
150
103
  command,
151
- json
152
- );
104
+ json,
105
+ preview,
106
+ });
153
107
 
154
108
  // Early exit if prompt rejected
155
109
  if (!response) return;
@@ -183,14 +137,79 @@ export const Handler = async (args: HandlerOptions): Promise<void> => {
183
137
  }
184
138
  };
185
139
 
186
- async function executeLocally(
187
- config: Config,
188
- name: string,
189
- shouldPrompt: boolean | undefined,
190
- queries: string[],
191
- persistTo: string | undefined,
192
- json?: boolean
193
- ) {
140
+ export async function executeSql({
141
+ local,
142
+ config,
143
+ name,
144
+ shouldPrompt,
145
+ persistTo,
146
+ file,
147
+ command,
148
+ json,
149
+ preview,
150
+ }: {
151
+ local: boolean | undefined;
152
+ config: ConfigFields<DevConfig> & Environment;
153
+ name: string;
154
+ shouldPrompt: boolean | undefined;
155
+ persistTo: string | undefined;
156
+ file: string | undefined;
157
+ command: string | undefined;
158
+ json: boolean | undefined;
159
+ preview: boolean | undefined;
160
+ }) {
161
+ const sql = file ? readFileSync(file) : command;
162
+ if (!sql) throw new Error(`Error: must provide --command or --file.`);
163
+ if (preview && local)
164
+ throw new Error(`Error: can't use --preview with --local`);
165
+ if (persistTo && !local)
166
+ throw new Error(`Error: can't use --persist-to without --local`);
167
+ logger.log(`šŸŒ€ Mapping SQL input into an array of statements`);
168
+ const queries = splitSqlQuery(sql);
169
+
170
+ if (file && sql) {
171
+ if (queries[0].startsWith("SQLite format 3")) {
172
+ //TODO: update this error to recommend using `wrangler d1 restore` when it exists
173
+ throw new Error(
174
+ "Provided file is a binary SQLite database file instead of an SQL text file.\nThe execute command can only process SQL text files.\nPlease export an SQL file from your SQLite database and try again."
175
+ );
176
+ }
177
+ }
178
+
179
+ return local
180
+ ? await executeLocally({
181
+ config,
182
+ name,
183
+ shouldPrompt,
184
+ queries,
185
+ persistTo,
186
+ json,
187
+ })
188
+ : await executeRemotely({
189
+ config,
190
+ name,
191
+ shouldPrompt,
192
+ batches: batchSplit(queries),
193
+ json,
194
+ preview,
195
+ });
196
+ }
197
+
198
+ async function executeLocally({
199
+ config,
200
+ name,
201
+ shouldPrompt,
202
+ queries,
203
+ persistTo,
204
+ json,
205
+ }: {
206
+ config: Config;
207
+ name: string;
208
+ shouldPrompt: boolean | undefined;
209
+ queries: string[];
210
+ persistTo: string | undefined;
211
+ json: boolean | undefined;
212
+ }) {
194
213
  const localDB = getDatabaseInfoFromConfig(config, name);
195
214
  if (!localDB) {
196
215
  throw new Error(
@@ -206,11 +225,10 @@ async function executeLocally(
206
225
 
207
226
  const dbDir = path.join(persistencePath, "d1");
208
227
  const dbPath = path.join(dbDir, `${localDB.binding}.sqlite3`);
209
- const [{ Statement }, { createSQLiteDB }] =
210
- await npxImport<MiniflareNpxImportTypes>(
211
- ["@miniflare/d1", "@miniflare/shared"],
212
- logger.log
213
- );
228
+ const [{ D1Database, D1DatabaseAPI }, { createSQLiteDB }] = await npxImport<
229
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
230
+ [typeof import("@miniflare/d1"), typeof import("@miniflare/shared")]
231
+ >(["@miniflare/d1", "@miniflare/shared"], logger.log);
214
232
 
215
233
  if (!existsSync(dbDir)) {
216
234
  const ok =
@@ -222,24 +240,28 @@ async function executeLocally(
222
240
  }
223
241
 
224
242
  logger.log(`šŸŒ€ Loading DB at ${readableRelative(dbPath)}`);
225
- const db = await createSQLiteDB(dbPath);
226
243
 
227
- const results: QueryResult[] = [];
228
- for (const sql of queries) {
229
- const statement = new Statement(db, sql);
230
- results.push((await statement.all()) as QueryResult);
231
- }
232
-
233
- return results;
244
+ const sqliteDb = await createSQLiteDB(dbPath);
245
+ const db = new D1Database(new D1DatabaseAPI(sqliteDb));
246
+ const stmts = queries.map((query) => db.prepare(query));
247
+ return (await db.batch(stmts)) as QueryResult[];
234
248
  }
235
249
 
236
- async function executeRemotely(
237
- config: Config,
238
- name: string,
239
- shouldPrompt: boolean | undefined,
240
- batches: string[],
241
- json?: boolean
242
- ) {
250
+ async function executeRemotely({
251
+ config,
252
+ name,
253
+ shouldPrompt,
254
+ batches,
255
+ json,
256
+ preview,
257
+ }: {
258
+ config: Config;
259
+ name: string;
260
+ shouldPrompt: boolean | undefined;
261
+ batches: string[];
262
+ json: boolean | undefined;
263
+ preview: boolean | undefined;
264
+ }) {
243
265
  const multiple_batches = batches.length > 1;
244
266
  // in JSON mode, we don't want a prompt here
245
267
  if (multiple_batches && !json) {
@@ -262,8 +284,13 @@ async function executeRemotely(
262
284
  accountId,
263
285
  name
264
286
  );
265
-
266
- logger.log(`šŸŒ€ Executing on ${name} (${db.uuid}):`);
287
+ if (preview && !db.previewDatabaseUuid) {
288
+ throw logger.error(
289
+ "Please define a `preview_database_id` in your wrangler.toml to execute your queries against a preview database"
290
+ );
291
+ }
292
+ const dbUuid = preview ? db.previewDatabaseUuid : db.uuid;
293
+ logger.log(`šŸŒ€ Executing on ${name} (${dbUuid}):`);
267
294
 
268
295
  const results: QueryResult[] = [];
269
296
  for (const sql of batches) {
@@ -273,7 +300,7 @@ async function executeRemotely(
273
300
  );
274
301
 
275
302
  const result = await fetchResult<QueryResult[]>(
276
- `/accounts/${accountId}/d1/database/${db.uuid}/query`,
303
+ `/accounts/${accountId}/d1/database/${dbUuid}/query`,
277
304
  {
278
305
  method: "POST",
279
306
  headers: {
@@ -319,3 +346,9 @@ function batchSplit(queries: string[]) {
319
346
  }
320
347
  return batches;
321
348
  }
349
+
350
+ function shorten(query: string | undefined, length: number) {
351
+ return query && query.length > length
352
+ ? query.slice(0, length) + "..."
353
+ : query;
354
+ }
@@ -19,7 +19,7 @@ import {
19
19
  getUnappliedMigrations,
20
20
  initMigrationsTable,
21
21
  } from "./helpers";
22
- import { DatabaseWithLocal } from "./options";
22
+ import { MigrationOptions } from "./options";
23
23
  import type { ParseError } from "../../parse";
24
24
  import type {
25
25
  CommonYargsArgv,
@@ -27,13 +27,13 @@ import type {
27
27
  } from "../../yargs-types";
28
28
 
29
29
  export function ApplyOptions(yargs: CommonYargsArgv) {
30
- return DatabaseWithLocal(yargs);
30
+ return MigrationOptions(yargs);
31
31
  }
32
32
 
33
33
  type ApplyHandlerOptions = StrictYargsOptionsToInterface<typeof ApplyOptions>;
34
34
 
35
35
  export const ApplyHandler = withConfig<ApplyHandlerOptions>(
36
- async ({ config, database, local, persistTo }): Promise<void> => {
36
+ async ({ config, database, local, persistTo, preview }): Promise<void> => {
37
37
  logger.log(d1BetaWarning);
38
38
 
39
39
  const databaseInfo = getDatabaseInfoFromConfig(config, database);
@@ -47,31 +47,34 @@ export const ApplyHandler = withConfig<ApplyHandlerOptions>(
47
47
  return;
48
48
  }
49
49
 
50
- const migrationsPath = await getMigrationsPath(
51
- path.dirname(config.configPath),
52
- databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
53
- false
54
- );
50
+ const migrationsPath = await getMigrationsPath({
51
+ projectPath: path.dirname(config.configPath),
52
+ migrationsFolderPath:
53
+ databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
54
+ createIfMissing: false,
55
+ });
55
56
 
56
57
  const migrationsTableName =
57
58
  databaseInfo?.migrationsTableName ?? DEFAULT_MIGRATION_TABLE;
58
- await initMigrationsTable(
59
+ await initMigrationsTable({
59
60
  migrationsTableName,
60
61
  local,
61
62
  config,
62
- database,
63
- persistTo
64
- );
63
+ name: database,
64
+ persistTo,
65
+ preview,
66
+ });
65
67
 
66
68
  const unappliedMigrations = (
67
- await getUnappliedMigrations(
69
+ await getUnappliedMigrations({
68
70
  migrationsTableName,
69
71
  migrationsPath,
70
72
  local,
71
73
  config,
72
- database,
73
- persistTo
74
- )
74
+ name: database,
75
+ persistTo,
76
+ preview,
77
+ })
75
78
  )
76
79
  .map((migration) => {
77
80
  return {
@@ -109,8 +112,8 @@ Your database may not be available to serve requests during the migration, conti
109
112
  );
110
113
  if (!ok) return;
111
114
 
112
- // don't backup prod db when applying migrations locally
113
- if (!local) {
115
+ // don't backup prod db when applying migrations locally or in preview
116
+ if (!local && !preview) {
114
117
  assert(
115
118
  databaseInfo,
116
119
  "In non-local mode `databaseInfo` should be defined."
@@ -133,15 +136,17 @@ Your database may not be available to serve requests during the migration, conti
133
136
  let success = true;
134
137
  let errorNotes: Array<string> = [];
135
138
  try {
136
- const response = await executeSql(
139
+ const response = await executeSql({
137
140
  local,
138
141
  config,
139
- database,
140
- isInteractive() && !CI.isCI(),
142
+ name: database,
143
+ shouldPrompt: isInteractive() && !CI.isCI(),
141
144
  persistTo,
142
- undefined,
143
- query
144
- );
145
+ command: query,
146
+ file: undefined,
147
+ json: undefined,
148
+ preview,
149
+ });
145
150
 
146
151
  if (response === null) {
147
152
  // TODO: return error
@@ -4,7 +4,7 @@ import { Box, render, Text } from "ink";
4
4
  import React from "react";
5
5
  import { withConfig } from "../../config";
6
6
  import { logger } from "../../logger";
7
- import { requireAuth } from "../../user";
7
+ import { DEFAULT_MIGRATION_PATH } from "../constants";
8
8
  import { Database } from "../options";
9
9
  import { d1BetaWarning, getDatabaseInfoFromConfig } from "../utils";
10
10
  import { getMigrationsPath, getNextMigrationNumber } from "./helpers";
@@ -25,7 +25,6 @@ type CreateHandlerOptions = StrictYargsOptionsToInterface<typeof CreateOptions>;
25
25
 
26
26
  export const CreateHandler = withConfig<CreateHandlerOptions>(
27
27
  async ({ config, database, message }): Promise<void> => {
28
- await requireAuth({});
29
28
  logger.log(d1BetaWarning);
30
29
 
31
30
  const databaseInfo = getDatabaseInfoFromConfig(config, database);
@@ -39,11 +38,12 @@ export const CreateHandler = withConfig<CreateHandlerOptions>(
39
38
  return;
40
39
  }
41
40
 
42
- const migrationsPath = await getMigrationsPath(
43
- path.dirname(config.configPath),
44
- databaseInfo.migrationsFolderPath,
45
- true
46
- );
41
+ const migrationsPath = await getMigrationsPath({
42
+ projectPath: path.dirname(config.configPath),
43
+ migrationsFolderPath:
44
+ databaseInfo.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
45
+ createIfMissing: true,
46
+ });
47
47
  const nextMigrationNumber = pad(getNextMigrationNumber(migrationsPath), 4);
48
48
  const migrationName = message.replaceAll(" ", "_");
49
49
 
@@ -10,11 +10,15 @@ import type { ConfigFields, DevConfig, Environment } from "../../config";
10
10
  import type { QueryResult } from "../execute";
11
11
  import type { Migration } from "../types";
12
12
 
13
- export async function getMigrationsPath(
14
- projectPath: string,
15
- migrationsFolderPath: string,
16
- createIfMissing: boolean
17
- ): Promise<string> {
13
+ export async function getMigrationsPath({
14
+ projectPath,
15
+ migrationsFolderPath,
16
+ createIfMissing,
17
+ }: {
18
+ projectPath: string;
19
+ migrationsFolderPath: string;
20
+ createIfMissing: boolean;
21
+ }): Promise<string> {
18
22
  const dir = path.resolve(projectPath, migrationsFolderPath);
19
23
  if (fs.existsSync(dir)) return dir;
20
24
 
@@ -34,21 +38,31 @@ export async function getMigrationsPath(
34
38
  throw new Error(`No migrations present at ${dir}.`);
35
39
  }
36
40
 
37
- export async function getUnappliedMigrations(
38
- migrationsTableName: string,
39
- migrationsPath: string,
40
- local: undefined | boolean,
41
- config: ConfigFields<DevConfig> & Environment,
42
- name: string,
43
- persistTo: undefined | string
44
- ): Promise<Array<string>> {
41
+ export async function getUnappliedMigrations({
42
+ migrationsTableName,
43
+ migrationsPath,
44
+ local,
45
+ config,
46
+ name,
47
+ persistTo,
48
+ preview,
49
+ }: {
50
+ migrationsTableName: string;
51
+ migrationsPath: string;
52
+ local: boolean | undefined;
53
+ config: ConfigFields<DevConfig> & Environment;
54
+ name: string;
55
+ persistTo: string | undefined;
56
+ preview: boolean | undefined;
57
+ }): Promise<Array<string>> {
45
58
  const appliedMigrations = (
46
59
  await listAppliedMigrations(
47
60
  migrationsTableName,
48
61
  local,
49
62
  config,
50
63
  name,
51
- persistTo
64
+ persistTo,
65
+ preview
52
66
  )
53
67
  ).map((migration) => {
54
68
  return migration.name;
@@ -68,24 +82,25 @@ export async function getUnappliedMigrations(
68
82
 
69
83
  const listAppliedMigrations = async (
70
84
  migrationsTableName: string,
71
- local: undefined | boolean,
85
+ local: boolean | undefined,
72
86
  config: ConfigFields<DevConfig> & Environment,
73
87
  name: string,
74
- persistTo: undefined | string
88
+ persistTo: string | undefined,
89
+ preview: boolean | undefined
75
90
  ): Promise<Migration[]> => {
76
- const Query = `SELECT *
77
- FROM ${migrationsTableName}
78
- ORDER BY id`;
79
-
80
- const response: QueryResult[] | null = await executeSql(
91
+ const response: QueryResult[] | null = await executeSql({
81
92
  local,
82
93
  config,
83
94
  name,
84
- isInteractive() && !CI.isCI(),
95
+ shouldPrompt: isInteractive() && !CI.isCI(),
85
96
  persistTo,
86
- undefined,
87
- Query
88
- );
97
+ command: `SELECT *
98
+ FROM ${migrationsTableName}
99
+ ORDER BY id`,
100
+ file: undefined,
101
+ json: undefined,
102
+ preview,
103
+ });
89
104
 
90
105
  if (!response || response[0].results.length === 0) return [];
91
106
 
@@ -121,27 +136,37 @@ export function getNextMigrationNumber(migrationsPath: string): number {
121
136
  return highestMigrationNumber + 1;
122
137
  }
123
138
 
124
- export const initMigrationsTable = async (
125
- migrationsTableName: string,
126
- local: undefined | boolean,
127
- config: ConfigFields<DevConfig> & Environment,
128
- name: string,
129
- persistTo: undefined | string
130
- ) => {
131
- return executeSql(
139
+ export const initMigrationsTable = async ({
140
+ migrationsTableName,
141
+ local,
142
+ config,
143
+ name,
144
+ persistTo,
145
+ preview,
146
+ }: {
147
+ migrationsTableName: string;
148
+ local: boolean | undefined;
149
+ config: ConfigFields<DevConfig> & Environment;
150
+ name: string;
151
+ persistTo: string | undefined;
152
+ preview: boolean | undefined;
153
+ }) => {
154
+ return executeSql({
132
155
  local,
133
156
  config,
134
157
  name,
135
- isInteractive() && !CI.isCI(),
158
+ shouldPrompt: isInteractive() && !CI.isCI(),
136
159
  persistTo,
137
- undefined,
138
- `
160
+ command: `
139
161
  CREATE TABLE IF NOT EXISTS ${migrationsTableName}
140
162
  (
141
163
  id INTEGER PRIMARY KEY AUTOINCREMENT,
142
164
  name TEXT UNIQUE,
143
165
  applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
144
166
  );
145
- `
146
- );
167
+ `,
168
+ file: undefined,
169
+ json: undefined,
170
+ preview,
171
+ });
147
172
  };
@@ -12,20 +12,20 @@ import {
12
12
  getUnappliedMigrations,
13
13
  initMigrationsTable,
14
14
  } from "./helpers";
15
- import { DatabaseWithLocal } from "./options";
15
+ import { MigrationOptions } from "./options";
16
16
  import type {
17
17
  CommonYargsArgv,
18
18
  StrictYargsOptionsToInterface,
19
19
  } from "../../yargs-types";
20
20
 
21
21
  export function ListOptions(yargs: CommonYargsArgv) {
22
- return DatabaseWithLocal(yargs);
22
+ return MigrationOptions(yargs);
23
23
  }
24
24
 
25
25
  type ListHandlerOptions = StrictYargsOptionsToInterface<typeof ListOptions>;
26
26
 
27
27
  export const ListHandler = withConfig<ListHandlerOptions>(
28
- async ({ config, database, local, persistTo }): Promise<void> => {
28
+ async ({ config, database, local, persistTo, preview }): Promise<void> => {
29
29
  if (!local) {
30
30
  await requireAuth({});
31
31
  }
@@ -42,32 +42,35 @@ export const ListHandler = withConfig<ListHandlerOptions>(
42
42
  return;
43
43
  }
44
44
 
45
- const migrationsPath = await getMigrationsPath(
46
- path.dirname(config.configPath),
47
- databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
48
- false
49
- );
45
+ const migrationsPath = await getMigrationsPath({
46
+ projectPath: path.dirname(config.configPath),
47
+ migrationsFolderPath:
48
+ databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
49
+ createIfMissing: false,
50
+ });
50
51
 
51
52
  const migrationsTableName =
52
53
  databaseInfo?.migrationsTableName ?? DEFAULT_MIGRATION_TABLE;
53
54
 
54
- await initMigrationsTable(
55
+ await initMigrationsTable({
55
56
  migrationsTableName,
56
57
  local,
57
58
  config,
58
- database,
59
- persistTo
60
- );
59
+ name: database,
60
+ persistTo,
61
+ preview,
62
+ });
61
63
 
62
64
  const unappliedMigrations = (
63
- await getUnappliedMigrations(
65
+ await getUnappliedMigrations({
64
66
  migrationsTableName,
65
67
  migrationsPath,
66
68
  local,
67
69
  config,
68
- database,
69
- persistTo
70
- )
70
+ name: database,
71
+ persistTo,
72
+ preview,
73
+ })
71
74
  ).map((migration) => {
72
75
  return {
73
76
  Name: migration,
@@ -1,13 +1,18 @@
1
1
  import { Database } from "../options";
2
2
  import type { CommonYargsArgv } from "../../yargs-types";
3
3
 
4
- export function DatabaseWithLocal(yargs: CommonYargsArgv) {
4
+ export function MigrationOptions(yargs: CommonYargsArgv) {
5
5
  return Database(yargs)
6
6
  .option("local", {
7
7
  describe:
8
8
  "Execute commands/files against a local DB for use with wrangler dev --local",
9
9
  type: "boolean",
10
10
  })
11
+ .option("preview", {
12
+ describe: "Execute commands/files against a preview D1 DB",
13
+ type: "boolean",
14
+ default: false,
15
+ })
11
16
  .option("persist-to", {
12
17
  describe:
13
18
  "Specify directory to use for local persistence (you must use --local with this flag)",
package/src/d1/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export type Database = {
2
2
  uuid: string;
3
+ previewDatabaseUuid?: string;
3
4
  name: string;
4
5
  binding: string;
5
6
  internal_env?: string;
package/src/d1/utils.ts CHANGED
@@ -14,6 +14,7 @@ export function getDatabaseInfoFromConfig(
14
14
  ) {
15
15
  return {
16
16
  uuid: d1Database.database_id,
17
+ previewDatabaseUuid: d1Database.preview_database_id,
17
18
  binding: d1Database.binding,
18
19
  name: d1Database.database_name,
19
20
  migrationsTableName:
@@ -45,4 +46,4 @@ export const getDatabaseByNameOrBinding = async (
45
46
 
46
47
  export const d1BetaWarning = process.env.NO_D1_WARNING
47
48
  ? ""
48
- : "--------------------\n🚧 D1 is currently in open alpha and is not recommended for production data and traffic\n🚧 Please report any bugs to https://github.com/cloudflare/wrangler2/issues/new/choose\n🚧 To request features, visit https://community.cloudflare.com/c/developers/d1\n🚧 To give feedback, visit https://discord.gg/cloudflaredev\n--------------------\n";
49
+ : "--------------------\n🚧 D1 is currently in open alpha and is not recommended for production data and traffic\n🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose\n🚧 To request features, visit https://community.cloudflare.com/c/developers/d1\n🚧 To give feedback, visit https://discord.gg/cloudflaredev\n--------------------\n";