wrangler 2.9.0 → 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 (82) hide show
  1. package/README.md +3 -3
  2. package/miniflare-dist/index.mjs +2 -15
  3. package/package.json +9 -9
  4. package/src/__tests__/configuration.test.ts +70 -0
  5. package/src/__tests__/d1/d1.test.ts +3 -6
  6. package/src/__tests__/d1/execute.test.ts +64 -0
  7. package/src/__tests__/d1/migrate.test.ts +107 -0
  8. package/src/__tests__/deployments.test.ts +40 -16
  9. package/src/__tests__/dev.test.tsx +3 -3
  10. package/src/__tests__/generate.test.ts +1 -1
  11. package/src/__tests__/helpers/end-event-loop.ts +6 -0
  12. package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
  13. package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
  14. package/src/__tests__/helpers/msw/handlers/deployments.ts +40 -16
  15. package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
  16. package/src/__tests__/index.test.ts +3 -4
  17. package/src/__tests__/init.test.ts +1 -1
  18. package/src/__tests__/kv.test.ts +8 -8
  19. package/src/__tests__/middleware.test.ts +65 -0
  20. package/src/__tests__/mtls-certificates.test.ts +585 -0
  21. package/src/__tests__/pages/deployment-list.test.ts +78 -0
  22. package/src/__tests__/pages/functions-build.test.ts +402 -0
  23. package/src/__tests__/pages/pages.test.ts +81 -0
  24. package/src/__tests__/pages/project-create.test.ts +63 -0
  25. package/src/__tests__/pages/project-list.test.ts +108 -0
  26. package/src/__tests__/pages/project-upload.test.ts +481 -0
  27. package/src/__tests__/pages/publish.test.ts +2745 -0
  28. package/src/__tests__/publish.test.ts +58 -27
  29. package/src/__tests__/queues.test.ts +2 -2
  30. package/src/__tests__/secret.test.ts +4 -4
  31. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  32. package/src/__tests__/user.test.ts +1 -1
  33. package/src/__tests__/whoami.test.tsx +1 -1
  34. package/src/__tests__/worker-namespace.test.ts +1 -1
  35. package/src/api/index.ts +8 -0
  36. package/src/api/mtls-certificate.ts +148 -0
  37. package/src/api/pages/create-worker-bundle-contents.ts +75 -0
  38. package/src/api/pages/publish.tsx +52 -8
  39. package/src/bundle.ts +6 -5
  40. package/src/config/config.ts +7 -7
  41. package/src/config/environment.ts +9 -2
  42. package/src/config/index.ts +13 -0
  43. package/src/config/validation.ts +50 -3
  44. package/src/create-worker-upload-form.ts +9 -0
  45. package/src/d1/execute.tsx +124 -91
  46. package/src/d1/migrations/apply.tsx +36 -29
  47. package/src/d1/migrations/create.tsx +10 -8
  48. package/src/d1/migrations/helpers.ts +63 -38
  49. package/src/d1/migrations/list.tsx +31 -20
  50. package/src/d1/migrations/options.ts +6 -1
  51. package/src/d1/types.ts +1 -0
  52. package/src/d1/utils.ts +2 -1
  53. package/src/deployments.ts +62 -39
  54. package/src/dev/dev.tsx +1 -15
  55. package/src/dev/remote.tsx +2 -2
  56. package/src/dev.tsx +9 -6
  57. package/src/generate/index.ts +1 -1
  58. package/src/index.ts +15 -5
  59. package/src/miniflare-cli/assets.ts +1 -1
  60. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  61. package/src/mtls-certificate/cli.ts +155 -0
  62. package/src/pages/build.ts +103 -23
  63. package/src/pages/buildFunctions.ts +32 -31
  64. package/src/pages/dev.ts +4 -2
  65. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  66. package/src/pages/publish.tsx +12 -1
  67. package/src/pages/utils.ts +1 -1
  68. package/src/publish/publish.ts +3 -2
  69. package/src/secret/index.ts +1 -0
  70. package/src/sites.ts +1 -1
  71. package/src/tail/filters.ts +1 -1
  72. package/src/user/user.ts +4 -3
  73. package/src/worker.ts +6 -0
  74. package/templates/format-dev-errors.ts +1 -0
  75. package/templates/new-worker.ts +3 -0
  76. package/templates/serve-static-assets.ts +1 -0
  77. package/templates/service-bindings-module-facade.js +1 -0
  78. package/templates/tsconfig.init.json +1 -1
  79. package/templates/tsconfig.tsbuildinfo +1 -1
  80. package/wrangler-dist/cli.d.ts +82 -2
  81. package/wrangler-dist/cli.js +1726 -1616
  82. package/src/__tests__/pages.test.ts +0 -2905
@@ -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>[];
@@ -64,7 +53,7 @@ export function Options(yargs: CommonYargsArgv) {
64
53
  type: "boolean",
65
54
  })
66
55
  .option("file", {
67
- describe: "A .sql file to injest",
56
+ describe: "A .sql file to ingest",
68
57
  type: "string",
69
58
  })
70
59
  .option("command", {
@@ -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,14 +27,16 @@ 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
  type ApplyHandlerOptions = StrictYargsOptionsToInterface<typeof ApplyOptions>;
34
+
33
35
  export const ApplyHandler = withConfig<ApplyHandlerOptions>(
34
- async ({ config, database, local, persistTo }): Promise<void> => {
36
+ async ({ config, database, local, persistTo, preview }): Promise<void> => {
35
37
  logger.log(d1BetaWarning);
36
38
 
37
- const databaseInfo = await getDatabaseInfoFromConfig(config, database);
39
+ const databaseInfo = getDatabaseInfoFromConfig(config, database);
38
40
  if (!databaseInfo && !local) {
39
41
  throw new Error(
40
42
  `Can't find a DB with name/binding '${database}' in local config. Check info in wrangler.toml...`
@@ -45,31 +47,34 @@ export const ApplyHandler = withConfig<ApplyHandlerOptions>(
45
47
  return;
46
48
  }
47
49
 
48
- const migrationsPath = await getMigrationsPath(
49
- path.dirname(config.configPath),
50
- databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
51
- false
52
- );
50
+ const migrationsPath = await getMigrationsPath({
51
+ projectPath: path.dirname(config.configPath),
52
+ migrationsFolderPath:
53
+ databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
54
+ createIfMissing: false,
55
+ });
53
56
 
54
- const migrationTableName =
57
+ const migrationsTableName =
55
58
  databaseInfo?.migrationsTableName ?? DEFAULT_MIGRATION_TABLE;
56
- await initMigrationsTable(
57
- migrationTableName,
59
+ await initMigrationsTable({
60
+ migrationsTableName,
58
61
  local,
59
62
  config,
60
- database,
61
- persistTo
62
- );
63
+ name: database,
64
+ persistTo,
65
+ preview,
66
+ });
63
67
 
64
68
  const unappliedMigrations = (
65
- await getUnappliedMigrations(
66
- migrationTableName,
69
+ await getUnappliedMigrations({
70
+ migrationsTableName,
67
71
  migrationsPath,
68
72
  local,
69
73
  config,
70
- database,
71
- persistTo
72
- )
74
+ name: database,
75
+ persistTo,
76
+ preview,
77
+ })
73
78
  )
74
79
  .map((migration) => {
75
80
  return {
@@ -107,8 +112,8 @@ Your database may not be available to serve requests during the migration, conti
107
112
  );
108
113
  if (!ok) return;
109
114
 
110
- // don't backup prod db when applying migrations locally
111
- if (!local) {
115
+ // don't backup prod db when applying migrations locally or in preview
116
+ if (!local && !preview) {
112
117
  assert(
113
118
  databaseInfo,
114
119
  "In non-local mode `databaseInfo` should be defined."
@@ -124,22 +129,24 @@ Your database may not be available to serve requests during the migration, conti
124
129
  "utf8"
125
130
  );
126
131
  query += `
127
- INSERT INTO ${migrationTableName} (name)
132
+ INSERT INTO ${migrationsTableName} (name)
128
133
  values ('${migration.Name}');
129
134
  `;
130
135
 
131
136
  let success = true;
132
137
  let errorNotes: Array<string> = [];
133
138
  try {
134
- const response = await executeSql(
139
+ const response = await executeSql({
135
140
  local,
136
141
  config,
137
- database,
138
- isInteractive() && !CI.isCI(),
142
+ name: database,
143
+ shouldPrompt: isInteractive() && !CI.isCI(),
139
144
  persistTo,
140
- undefined,
141
- query
142
- );
145
+ command: query,
146
+ file: undefined,
147
+ json: undefined,
148
+ preview,
149
+ });
143
150
 
144
151
  if (response === null) {
145
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";
@@ -20,13 +20,14 @@ export function CreateOptions(yargs: CommonYargsArgv) {
20
20
  demandOption: true,
21
21
  });
22
22
  }
23
+
23
24
  type CreateHandlerOptions = StrictYargsOptionsToInterface<typeof CreateOptions>;
25
+
24
26
  export const CreateHandler = withConfig<CreateHandlerOptions>(
25
27
  async ({ config, database, message }): Promise<void> => {
26
- await requireAuth({});
27
28
  logger.log(d1BetaWarning);
28
29
 
29
- const databaseInfo = await getDatabaseInfoFromConfig(config, database);
30
+ const databaseInfo = getDatabaseInfoFromConfig(config, database);
30
31
  if (!databaseInfo) {
31
32
  throw new Error(
32
33
  `Can't find a DB with name/binding '${database}' in local config. Check info in wrangler.toml...`
@@ -37,11 +38,12 @@ export const CreateHandler = withConfig<CreateHandlerOptions>(
37
38
  return;
38
39
  }
39
40
 
40
- const migrationsPath = await getMigrationsPath(
41
- path.dirname(config.configPath),
42
- databaseInfo.migrationsFolderPath,
43
- true
44
- );
41
+ const migrationsPath = await getMigrationsPath({
42
+ projectPath: path.dirname(config.configPath),
43
+ migrationsFolderPath:
44
+ databaseInfo.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
45
+ createIfMissing: true,
46
+ });
45
47
  const nextMigrationNumber = pad(getNextMigrationNumber(migrationsPath), 4);
46
48
  const migrationName = message.replaceAll(" ", "_");
47
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
  };
@@ -5,29 +5,34 @@ import React from "react";
5
5
  import { withConfig } from "../../config";
6
6
  import { logger } from "../../logger";
7
7
  import { requireAuth } from "../../user";
8
+ import { DEFAULT_MIGRATION_PATH, DEFAULT_MIGRATION_TABLE } from "../constants";
8
9
  import { d1BetaWarning, getDatabaseInfoFromConfig } from "../utils";
9
10
  import {
10
11
  getMigrationsPath,
11
12
  getUnappliedMigrations,
12
13
  initMigrationsTable,
13
14
  } from "./helpers";
14
- import { DatabaseWithLocal } from "./options";
15
+ import { MigrationOptions } from "./options";
15
16
  import type {
16
17
  CommonYargsArgv,
17
18
  StrictYargsOptionsToInterface,
18
19
  } from "../../yargs-types";
19
20
 
20
21
  export function ListOptions(yargs: CommonYargsArgv) {
21
- return DatabaseWithLocal(yargs);
22
+ return MigrationOptions(yargs);
22
23
  }
24
+
23
25
  type ListHandlerOptions = StrictYargsOptionsToInterface<typeof ListOptions>;
26
+
24
27
  export const ListHandler = withConfig<ListHandlerOptions>(
25
- async ({ config, database, local, persistTo }): Promise<void> => {
26
- await requireAuth({});
28
+ async ({ config, database, local, persistTo, preview }): Promise<void> => {
29
+ if (!local) {
30
+ await requireAuth({});
31
+ }
27
32
  logger.log(d1BetaWarning);
28
33
 
29
- const databaseInfo = await getDatabaseInfoFromConfig(config, database);
30
- if (!databaseInfo) {
34
+ const databaseInfo = getDatabaseInfoFromConfig(config, database);
35
+ if (!databaseInfo && !local) {
31
36
  throw new Error(
32
37
  `Can't find a DB with name/binding '${database}' in local config. Check info in wrangler.toml...`
33
38
  );
@@ -36,30 +41,36 @@ export const ListHandler = withConfig<ListHandlerOptions>(
36
41
  if (!config.configPath) {
37
42
  return;
38
43
  }
39
- const { migrationsTableName, migrationsFolderPath } = databaseInfo;
40
44
 
41
- const migrationsPath = await getMigrationsPath(
42
- path.dirname(config.configPath),
43
- migrationsFolderPath,
44
- false
45
- );
46
- await initMigrationsTable(
45
+ const migrationsPath = await getMigrationsPath({
46
+ projectPath: path.dirname(config.configPath),
47
+ migrationsFolderPath:
48
+ databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
49
+ createIfMissing: false,
50
+ });
51
+
52
+ const migrationsTableName =
53
+ databaseInfo?.migrationsTableName ?? DEFAULT_MIGRATION_TABLE;
54
+
55
+ await initMigrationsTable({
47
56
  migrationsTableName,
48
57
  local,
49
58
  config,
50
- database,
51
- persistTo
52
- );
59
+ name: database,
60
+ persistTo,
61
+ preview,
62
+ });
53
63
 
54
64
  const unappliedMigrations = (
55
- await getUnappliedMigrations(
65
+ await getUnappliedMigrations({
56
66
  migrationsTableName,
57
67
  migrationsPath,
58
68
  local,
59
69
  config,
60
- database,
61
- persistTo
62
- )
70
+ name: database,
71
+ persistTo,
72
+ preview,
73
+ })
63
74
  ).map((migration) => {
64
75
  return {
65
76
  Name: migration,