wrangler 0.0.0-e7cf0caa → 0.0.0-e87ad068
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/miniflare-dist/index.mjs +167 -93
- package/package.json +6 -6
- package/src/__tests__/configuration.test.ts +218 -0
- package/src/__tests__/constellation.test.ts +371 -0
- package/src/__tests__/d1/migrate.test.ts +100 -0
- package/src/__tests__/index.test.ts +4 -2
- package/src/__tests__/init.test.ts +109 -3
- package/src/__tests__/mtls-certificates.test.ts +2 -1
- package/src/__tests__/pages/functions-build.test.ts +77 -0
- package/src/__tests__/pages-deployment-tail.test.ts +2 -0
- package/src/__tests__/publish.test.ts +646 -187
- package/src/__tests__/tail.test.ts +49 -7
- package/src/__tests__/tsconfig.tsbuildinfo +1 -1
- package/src/__tests__/unstableDev.test.ts +61 -0
- package/src/__tests__/user.test.ts +1 -1
- package/src/api/dev.ts +12 -0
- package/src/api/pages/create-worker-bundle-contents.ts +4 -0
- package/src/api/pages/publish.tsx +28 -12
- package/src/bundle.ts +58 -14
- package/src/cfetch/internal.ts +19 -14
- package/src/config/environment.ts +41 -0
- package/src/config/index.ts +21 -0
- package/src/config/validation.ts +182 -0
- package/src/constellation/createProject.tsx +51 -0
- package/src/constellation/deleteProject.ts +51 -0
- package/src/constellation/deleteProjectModel.ts +76 -0
- package/src/constellation/index.ts +75 -0
- package/src/constellation/listCatalog.tsx +35 -0
- package/src/constellation/listModel.tsx +49 -0
- package/src/constellation/listProject.tsx +28 -0
- package/src/constellation/listRuntime.tsx +28 -0
- package/src/constellation/options.ts +17 -0
- package/src/constellation/types.ts +17 -0
- package/src/constellation/uploadModel.tsx +84 -0
- package/src/constellation/utils.ts +90 -0
- package/src/create-worker-upload-form.ts +25 -0
- package/src/d1/backups.tsx +4 -4
- package/src/d1/constants.ts +3 -0
- package/src/d1/create.tsx +77 -43
- package/src/d1/delete.ts +1 -1
- package/src/d1/execute.tsx +27 -13
- package/src/d1/list.tsx +13 -11
- package/src/d1/migrations/apply.tsx +29 -6
- package/src/d1/migrations/helpers.ts +8 -9
- package/src/d1/types.ts +7 -0
- package/src/dev/dev.tsx +9 -2
- package/src/dev/local.tsx +52 -20
- package/src/dev/remote.tsx +4 -0
- package/src/dev/start-server.ts +64 -40
- package/src/dev/use-esbuild.ts +70 -43
- package/src/dev-registry.ts +11 -0
- package/src/dev.tsx +23 -6
- package/src/docs/helpers.ts +50 -0
- package/src/docs/index.ts +25 -68
- package/src/entry.ts +8 -1
- package/src/environment-variables/factory.ts +2 -1
- package/src/generate/index.ts +5 -0
- package/src/index.ts +12 -1
- package/src/init.ts +52 -10
- package/src/inspect.ts +107 -6
- package/src/kv/helpers.ts +7 -4
- package/src/logger.ts +5 -1
- package/src/miniflare-cli/index.ts +2 -2
- package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
- package/src/module-collection.ts +1 -1
- package/src/pages/build.ts +30 -17
- package/src/pages/dev.ts +51 -8
- package/src/pages/functions/buildPlugin.ts +1 -0
- package/src/pages/functions/buildWorker.ts +92 -2
- package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
- package/src/publish/publish.ts +9 -1
- package/src/secret/index.ts +4 -0
- package/src/sites.ts +164 -52
- package/src/tail/createTail.ts +9 -0
- package/src/tail/printing.ts +12 -0
- package/src/traverse-module-graph.ts +2 -1
- package/src/type-generation.ts +6 -0
- package/src/user/user.ts +1 -0
- package/src/utils/render.ts +1 -1
- package/src/worker.ts +26 -0
- package/templates/__tests__/tsconfig.tsbuildinfo +1 -1
- package/templates/pages-dev-util.ts +4 -1
- package/templates/tsconfig.tsbuildinfo +1 -1
- package/wrangler-dist/cli.d.ts +78 -2
- package/wrangler-dist/cli.js +65057 -63883
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { FormData, File } from "undici";
|
|
3
|
+
import { fetchResult } from "../cfetch";
|
|
4
|
+
import { withConfig } from "../config";
|
|
5
|
+
import { logger } from "../logger";
|
|
6
|
+
import { requireAuth } from "../user";
|
|
7
|
+
import { constellationBetaWarning, getProjectByName } from "./utils";
|
|
8
|
+
import type {
|
|
9
|
+
CommonYargsArgv,
|
|
10
|
+
StrictYargsOptionsToInterface,
|
|
11
|
+
} from "../yargs-types";
|
|
12
|
+
import type { Model } from "./types";
|
|
13
|
+
|
|
14
|
+
export function options(yargs: CommonYargsArgv) {
|
|
15
|
+
return yargs
|
|
16
|
+
.positional("projectName", {
|
|
17
|
+
describe: "The name of the project",
|
|
18
|
+
type: "string",
|
|
19
|
+
demandOption: true,
|
|
20
|
+
})
|
|
21
|
+
.positional("modelName", {
|
|
22
|
+
describe: "The name of the uploaded model",
|
|
23
|
+
type: "string",
|
|
24
|
+
demandOption: true,
|
|
25
|
+
})
|
|
26
|
+
.positional("modelFile", {
|
|
27
|
+
describe: "The name of the local file with the model contents",
|
|
28
|
+
type: "string",
|
|
29
|
+
demandOption: true,
|
|
30
|
+
})
|
|
31
|
+
.option("description", {
|
|
32
|
+
describe: "include a description of the model",
|
|
33
|
+
type: "string",
|
|
34
|
+
demandOption: false,
|
|
35
|
+
alias: "d",
|
|
36
|
+
})
|
|
37
|
+
.epilogue(constellationBetaWarning);
|
|
38
|
+
}
|
|
39
|
+
type HandlerOptions = StrictYargsOptionsToInterface<typeof options>;
|
|
40
|
+
export const handler = withConfig<HandlerOptions>(
|
|
41
|
+
async ({
|
|
42
|
+
projectName,
|
|
43
|
+
modelName,
|
|
44
|
+
modelFile,
|
|
45
|
+
description,
|
|
46
|
+
config,
|
|
47
|
+
}): Promise<void> => {
|
|
48
|
+
const accountId = await requireAuth(config);
|
|
49
|
+
logger.log(constellationBetaWarning);
|
|
50
|
+
|
|
51
|
+
const proj = await getProjectByName(config, accountId, projectName);
|
|
52
|
+
|
|
53
|
+
const formData = new FormData();
|
|
54
|
+
formData.set(
|
|
55
|
+
"file",
|
|
56
|
+
new File([readFileSync(modelFile)], modelFile, {
|
|
57
|
+
type: "application/octet-stream",
|
|
58
|
+
})
|
|
59
|
+
);
|
|
60
|
+
formData.set("name", modelName);
|
|
61
|
+
|
|
62
|
+
if (description !== undefined) {
|
|
63
|
+
formData.set("description", description);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let model: Model;
|
|
67
|
+
try {
|
|
68
|
+
model = await fetchResult(
|
|
69
|
+
`/accounts/${accountId}/constellation/project/${proj.id}/model`,
|
|
70
|
+
{
|
|
71
|
+
method: "POST",
|
|
72
|
+
body: formData,
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
if ((e as { code: number }).code === 7408) {
|
|
77
|
+
throw new Error("A model with that name already exists");
|
|
78
|
+
}
|
|
79
|
+
throw e;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
logger.log(`✅ Successfully uploaded Model "${model.name}"!`);
|
|
83
|
+
}
|
|
84
|
+
);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { fetchResult } from "../cfetch";
|
|
2
|
+
import { getEnvironmentVariableFactory } from "../environment-variables/factory";
|
|
3
|
+
import type { Config } from "../config";
|
|
4
|
+
import type { Project, Model, CatalogEntry } from "./types";
|
|
5
|
+
|
|
6
|
+
export const getConstellationWarningFromEnv = getEnvironmentVariableFactory({
|
|
7
|
+
variableName: "NO_CONSTELLATION_WARNING",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const constellationBetaWarning =
|
|
11
|
+
getConstellationWarningFromEnv() !== undefined
|
|
12
|
+
? ""
|
|
13
|
+
: "--------------------\n🚧 Constellation 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 give feedback, visit https://discord.gg/cloudflaredev\n--------------------\n";
|
|
14
|
+
|
|
15
|
+
export const getProjectByName = async (
|
|
16
|
+
config: Config,
|
|
17
|
+
accountId: string,
|
|
18
|
+
name: string
|
|
19
|
+
): Promise<Project> => {
|
|
20
|
+
const allProjects = await listProjects(accountId);
|
|
21
|
+
const matchingProj = allProjects.find((proj) => proj.name === name);
|
|
22
|
+
if (!matchingProj) {
|
|
23
|
+
throw new Error(`Couldn't find Project with name '${name}'`);
|
|
24
|
+
}
|
|
25
|
+
return matchingProj;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const getProjectModelByName = async (
|
|
29
|
+
config: Config,
|
|
30
|
+
accountId: string,
|
|
31
|
+
proj: Project,
|
|
32
|
+
modelName: string
|
|
33
|
+
): Promise<Model> => {
|
|
34
|
+
const allModels = await listModels(accountId, proj);
|
|
35
|
+
const matchingModel = allModels.find((model) => model.name === modelName);
|
|
36
|
+
if (!matchingModel) {
|
|
37
|
+
throw new Error(`Couldn't find Model with name '${modelName}'`);
|
|
38
|
+
}
|
|
39
|
+
return matchingModel;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export async function constellationList<ResponseType>(
|
|
43
|
+
accountId: string,
|
|
44
|
+
partialUrl: string
|
|
45
|
+
): Promise<Array<ResponseType>> {
|
|
46
|
+
const pageSize = 50;
|
|
47
|
+
let page = 1;
|
|
48
|
+
const results = [];
|
|
49
|
+
while (results.length % pageSize === 0) {
|
|
50
|
+
const json: Array<ResponseType> = await fetchResult(
|
|
51
|
+
`/accounts/${accountId}/constellation/${partialUrl}`,
|
|
52
|
+
{},
|
|
53
|
+
new URLSearchParams({
|
|
54
|
+
per_page: pageSize.toString(),
|
|
55
|
+
page: page.toString(),
|
|
56
|
+
})
|
|
57
|
+
);
|
|
58
|
+
page++;
|
|
59
|
+
results.push(...json);
|
|
60
|
+
if (json.length < pageSize) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const listCatalogEntries = async (
|
|
68
|
+
accountId: string
|
|
69
|
+
): Promise<Array<CatalogEntry>> => {
|
|
70
|
+
return await constellationList(accountId, "catalog");
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const listModels = async (
|
|
74
|
+
accountId: string,
|
|
75
|
+
proj: Project
|
|
76
|
+
): Promise<Array<Model>> => {
|
|
77
|
+
return constellationList(accountId, `project/${proj.id}/model`);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const listProjects = async (
|
|
81
|
+
accountId: string
|
|
82
|
+
): Promise<Array<Project>> => {
|
|
83
|
+
return await constellationList(accountId, "project");
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const listRuntimes = async (
|
|
87
|
+
accountId: string
|
|
88
|
+
): Promise<Array<string>> => {
|
|
89
|
+
return await constellationList(accountId, "runtime");
|
|
90
|
+
};
|
|
@@ -4,6 +4,8 @@ import type {
|
|
|
4
4
|
CfWorkerInit,
|
|
5
5
|
CfModuleType,
|
|
6
6
|
CfDurableObjectMigrations,
|
|
7
|
+
CfPlacement,
|
|
8
|
+
CfTailConsumer,
|
|
7
9
|
} from "./worker.js";
|
|
8
10
|
|
|
9
11
|
export function toMimeType(type: CfModuleType): string {
|
|
@@ -30,6 +32,7 @@ export type WorkerMetadataBinding =
|
|
|
30
32
|
| { type: "json"; name: string; json: unknown }
|
|
31
33
|
| { type: "wasm_module"; name: string; part: string }
|
|
32
34
|
| { type: "text_blob"; name: string; part: string }
|
|
35
|
+
| { type: "browser"; name: string }
|
|
33
36
|
| { type: "data_blob"; name: string; part: string }
|
|
34
37
|
| { type: "kv_namespace"; name: string; namespace_id: string }
|
|
35
38
|
| {
|
|
@@ -48,6 +51,7 @@ export type WorkerMetadataBinding =
|
|
|
48
51
|
| { type: "queue"; name: string; queue_name: string }
|
|
49
52
|
| { type: "r2_bucket"; name: string; bucket_name: string }
|
|
50
53
|
| { type: "d1"; name: string; id: string; internalEnv?: string }
|
|
54
|
+
| { type: "constellation"; name: string; project: string }
|
|
51
55
|
| { type: "service"; name: string; service: string; environment?: string }
|
|
52
56
|
| { type: "analytics_engine"; name: string; dataset?: string }
|
|
53
57
|
| { type: "dispatch_namespace"; name: string; namespace: string }
|
|
@@ -71,6 +75,8 @@ export interface WorkerMetadata {
|
|
|
71
75
|
bindings: WorkerMetadataBinding[];
|
|
72
76
|
keep_bindings?: WorkerMetadataBinding["type"][];
|
|
73
77
|
logpush?: boolean;
|
|
78
|
+
placement?: CfPlacement;
|
|
79
|
+
tail_consumers?: CfTailConsumer[];
|
|
74
80
|
// Allow unsafe.metadata to add arbitary properties at runtime
|
|
75
81
|
[key: string]: unknown;
|
|
76
82
|
}
|
|
@@ -89,6 +95,8 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
89
95
|
compatibility_flags,
|
|
90
96
|
keepVars,
|
|
91
97
|
logpush,
|
|
98
|
+
placement,
|
|
99
|
+
tail_consumers,
|
|
92
100
|
} = worker;
|
|
93
101
|
|
|
94
102
|
let { modules } = worker;
|
|
@@ -161,6 +169,14 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
161
169
|
}
|
|
162
170
|
);
|
|
163
171
|
|
|
172
|
+
bindings.constellation?.forEach(({ binding, project_id }) => {
|
|
173
|
+
metadataBindings.push({
|
|
174
|
+
name: binding,
|
|
175
|
+
type: "constellation",
|
|
176
|
+
project: project_id,
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
164
180
|
bindings.services?.forEach(({ binding, service, environment }) => {
|
|
165
181
|
metadataBindings.push({
|
|
166
182
|
name: binding,
|
|
@@ -217,6 +233,13 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
217
233
|
);
|
|
218
234
|
}
|
|
219
235
|
|
|
236
|
+
if (bindings.browser !== undefined) {
|
|
237
|
+
metadataBindings.push({
|
|
238
|
+
name: bindings.browser.binding,
|
|
239
|
+
type: "browser",
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
220
243
|
for (const [name, filePath] of Object.entries(bindings.text_blobs || {})) {
|
|
221
244
|
metadataBindings.push({
|
|
222
245
|
name,
|
|
@@ -320,6 +343,8 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
320
343
|
capnp_schema: bindings.logfwdr?.schema,
|
|
321
344
|
...(keepVars && { keep_bindings: ["plain_text", "json"] }),
|
|
322
345
|
...(logpush !== undefined && { logpush }),
|
|
346
|
+
...(placement && { placement }),
|
|
347
|
+
...(tail_consumers && { tail_consumers }),
|
|
323
348
|
};
|
|
324
349
|
|
|
325
350
|
if (bindings.unsafe?.metadata !== undefined) {
|
package/src/d1/backups.tsx
CHANGED
|
@@ -24,7 +24,7 @@ export function ListOptions(yargs: CommonYargsArgv) {
|
|
|
24
24
|
type ListHandlerOptions = StrictYargsOptionsToInterface<typeof ListOptions>;
|
|
25
25
|
export const ListHandler = withConfig<ListHandlerOptions>(
|
|
26
26
|
async ({ config, name }): Promise<void> => {
|
|
27
|
-
const accountId = await requireAuth(
|
|
27
|
+
const accountId = await requireAuth(config);
|
|
28
28
|
logger.log(d1BetaWarning);
|
|
29
29
|
const db: Database = await getDatabaseByNameOrBinding(
|
|
30
30
|
config,
|
|
@@ -87,7 +87,7 @@ type CreateHandlerOptions = StrictYargsOptionsToInterface<typeof CreateOptions>;
|
|
|
87
87
|
|
|
88
88
|
export const CreateHandler = withConfig<CreateHandlerOptions>(
|
|
89
89
|
async ({ config, name }): Promise<void> => {
|
|
90
|
-
const accountId = await requireAuth(
|
|
90
|
+
const accountId = await requireAuth(config);
|
|
91
91
|
logger.log(d1BetaWarning);
|
|
92
92
|
const db: Database = await getDatabaseByNameOrBinding(
|
|
93
93
|
config,
|
|
@@ -135,7 +135,7 @@ type RestoreHandlerOptions = StrictYargsOptionsToInterface<
|
|
|
135
135
|
>;
|
|
136
136
|
export const RestoreHandler = withConfig<RestoreHandlerOptions>(
|
|
137
137
|
async ({ config, name, backupId }): Promise<void> => {
|
|
138
|
-
const accountId = await requireAuth(
|
|
138
|
+
const accountId = await requireAuth(config);
|
|
139
139
|
logger.log(d1BetaWarning);
|
|
140
140
|
const db: Database = await getDatabaseByNameOrBinding(
|
|
141
141
|
config,
|
|
@@ -183,7 +183,7 @@ type DownloadHandlerOptions = StrictYargsOptionsToInterface<
|
|
|
183
183
|
>;
|
|
184
184
|
export const DownloadHandler = withConfig<DownloadHandlerOptions>(
|
|
185
185
|
async ({ name, backupId, output, config }): Promise<void> => {
|
|
186
|
-
const accountId = await requireAuth(
|
|
186
|
+
const accountId = await requireAuth(config);
|
|
187
187
|
logger.log(d1BetaWarning);
|
|
188
188
|
const db: Database = await getDatabaseByNameOrBinding(
|
|
189
189
|
config,
|
package/src/d1/constants.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export const DEFAULT_MIGRATION_PATH = "./migrations";
|
|
2
2
|
export const DEFAULT_MIGRATION_TABLE = "d1_migrations";
|
|
3
|
+
export const LOCATION_CHOICES = ["weur", "eeur", "apac", "wnam", "enam"];
|
|
4
|
+
// Max number of statements to send in a single /execute call
|
|
5
|
+
export const DEFAULT_BATCH_SIZE = 10_000;
|
package/src/d1/create.tsx
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Box, Text } from "ink";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { fetchResult } from "../cfetch";
|
|
4
|
+
import { withConfig } from "../config";
|
|
4
5
|
import { logger } from "../logger";
|
|
5
6
|
import { requireAuth } from "../user";
|
|
6
7
|
import { renderToString } from "../utils/render";
|
|
8
|
+
import { LOCATION_CHOICES } from "./constants";
|
|
7
9
|
import { d1BetaWarning } from "./utils";
|
|
8
10
|
import type {
|
|
9
11
|
CommonYargsArgv,
|
|
10
12
|
StrictYargsOptionsToInterface,
|
|
11
13
|
} from "../yargs-types";
|
|
12
|
-
import type {
|
|
14
|
+
import type { DatabaseCreationResult } from "./types";
|
|
13
15
|
|
|
14
16
|
export function Options(yargs: CommonYargsArgv) {
|
|
15
17
|
return yargs
|
|
@@ -18,51 +20,83 @@ export function Options(yargs: CommonYargsArgv) {
|
|
|
18
20
|
type: "string",
|
|
19
21
|
demandOption: true,
|
|
20
22
|
})
|
|
23
|
+
.option("location", {
|
|
24
|
+
describe:
|
|
25
|
+
"A hint for the primary location of the new DB. Options:\nweur: Western Europe\neeur: Eastern Europe\napac: Asia Pacific\nwnam: Western North America\nenam: Eastern North America \n",
|
|
26
|
+
type: "string",
|
|
27
|
+
})
|
|
28
|
+
.option("experimental-backend", {
|
|
29
|
+
default: false,
|
|
30
|
+
describe: "Use new experimental DB backend",
|
|
31
|
+
type: "boolean",
|
|
32
|
+
})
|
|
21
33
|
.epilogue(d1BetaWarning);
|
|
22
34
|
}
|
|
23
35
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
|
|
37
|
+
export const Handler = withConfig<HandlerOptions>(
|
|
38
|
+
async ({ name, config, location, experimentalBackend }): Promise<void> => {
|
|
39
|
+
const accountId = await requireAuth(config);
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+
logger.log(d1BetaWarning);
|
|
30
42
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
name,
|
|
40
|
-
}),
|
|
41
|
-
});
|
|
42
|
-
} catch (e) {
|
|
43
|
-
if ((e as { code: number }).code === 7502) {
|
|
44
|
-
throw new Error("A database with that name already exists");
|
|
43
|
+
if (!experimentalBackend && location) {
|
|
44
|
+
if (LOCATION_CHOICES.indexOf(location.toLowerCase()) === -1) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Location '${location}' invalid. Valid values are ${LOCATION_CHOICES.join(
|
|
47
|
+
","
|
|
48
|
+
)}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
45
51
|
}
|
|
46
|
-
throw e;
|
|
47
|
-
}
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
53
|
+
let db: DatabaseCreationResult;
|
|
54
|
+
try {
|
|
55
|
+
db = await fetchResult(`/accounts/${accountId}/d1/database`, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: {
|
|
58
|
+
"Content-Type": "application/json",
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
name,
|
|
62
|
+
...(location && { primary_location_hint: location }),
|
|
63
|
+
...(experimentalBackend && { experimental: true }),
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
} catch (e) {
|
|
67
|
+
if ((e as { code: number }).code === 7502) {
|
|
68
|
+
throw new Error("A database with that name already exists");
|
|
69
|
+
}
|
|
70
|
+
throw e;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
logger.log(
|
|
74
|
+
renderToString(
|
|
75
|
+
<Box flexDirection="column">
|
|
76
|
+
<Text>
|
|
77
|
+
✅ Successfully created DB '{db.name}'
|
|
78
|
+
{db.created_in_region
|
|
79
|
+
? ` in region ${db.created_in_region}`
|
|
80
|
+
: location
|
|
81
|
+
? ` using primary location hint ${location}`
|
|
82
|
+
: ``}
|
|
83
|
+
</Text>
|
|
84
|
+
{experimentalBackend && (
|
|
85
|
+
<Text>
|
|
86
|
+
Created your database using D1's new storage backend. The new
|
|
87
|
+
storage backend is not yet recommended for production workloads
|
|
88
|
+
and does not yet support backups.
|
|
89
|
+
</Text>
|
|
90
|
+
)}
|
|
91
|
+
<Text> </Text>
|
|
92
|
+
<Text>[[d1_databases]]</Text>
|
|
93
|
+
<Text>
|
|
94
|
+
binding = "DB" # i.e. available in your Worker on env.DB
|
|
95
|
+
</Text>
|
|
96
|
+
<Text>database_name = "{db.name}"</Text>
|
|
97
|
+
<Text>database_id = "{db.uuid}"</Text>
|
|
98
|
+
</Box>
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
);
|
package/src/d1/delete.ts
CHANGED
|
@@ -24,7 +24,7 @@ export function Options(d1ListYargs: CommonYargsArgv) {
|
|
|
24
24
|
type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
|
|
25
25
|
export const Handler = withConfig<HandlerOptions>(
|
|
26
26
|
async ({ name, skipConfirmation, config }): Promise<void> => {
|
|
27
|
-
const accountId = await requireAuth(
|
|
27
|
+
const accountId = await requireAuth(config);
|
|
28
28
|
logger.log(d1BetaWarning);
|
|
29
29
|
|
|
30
30
|
const db: Database = await getDatabaseByNameOrBinding(
|
package/src/d1/execute.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import { readFileSync } from "../parse";
|
|
|
15
15
|
import { readableRelative } from "../paths";
|
|
16
16
|
import { requireAuth } from "../user";
|
|
17
17
|
import { renderToString } from "../utils/render";
|
|
18
|
+
import { DEFAULT_BATCH_SIZE } from "./constants";
|
|
18
19
|
import * as options from "./options";
|
|
19
20
|
import splitSqlQuery from "./splitter";
|
|
20
21
|
import {
|
|
@@ -37,8 +38,6 @@ export type QueryResult = {
|
|
|
37
38
|
};
|
|
38
39
|
query?: string;
|
|
39
40
|
};
|
|
40
|
-
// Max number of statements to send in a single /execute call
|
|
41
|
-
const QUERY_LIMIT = 10_000;
|
|
42
41
|
|
|
43
42
|
export function Options(yargs: CommonYargsArgv) {
|
|
44
43
|
return options
|
|
@@ -75,14 +74,28 @@ export function Options(yargs: CommonYargsArgv) {
|
|
|
75
74
|
describe: "Execute commands/files against a preview D1 DB",
|
|
76
75
|
type: "boolean",
|
|
77
76
|
default: false,
|
|
77
|
+
})
|
|
78
|
+
.option("batch-size", {
|
|
79
|
+
describe: "Number of queries to send in a single batch",
|
|
80
|
+
type: "number",
|
|
81
|
+
default: DEFAULT_BATCH_SIZE,
|
|
78
82
|
});
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
|
|
82
86
|
|
|
83
87
|
export const Handler = async (args: HandlerOptions): Promise<void> => {
|
|
84
|
-
const {
|
|
85
|
-
|
|
88
|
+
const {
|
|
89
|
+
local,
|
|
90
|
+
database,
|
|
91
|
+
yes,
|
|
92
|
+
persistTo,
|
|
93
|
+
file,
|
|
94
|
+
command,
|
|
95
|
+
json,
|
|
96
|
+
preview,
|
|
97
|
+
batchSize,
|
|
98
|
+
} = args;
|
|
86
99
|
const existingLogLevel = logger.loggerLevel;
|
|
87
100
|
if (json) {
|
|
88
101
|
// set loggerLevel to error to avoid readConfig warnings appearing in JSON output
|
|
@@ -104,6 +117,7 @@ export const Handler = async (args: HandlerOptions): Promise<void> => {
|
|
|
104
117
|
command,
|
|
105
118
|
json,
|
|
106
119
|
preview,
|
|
120
|
+
batchSize,
|
|
107
121
|
});
|
|
108
122
|
|
|
109
123
|
// Early exit if prompt rejected
|
|
@@ -150,6 +164,7 @@ export async function executeSql({
|
|
|
150
164
|
command,
|
|
151
165
|
json,
|
|
152
166
|
preview,
|
|
167
|
+
batchSize,
|
|
153
168
|
}: {
|
|
154
169
|
local: boolean | undefined;
|
|
155
170
|
config: ConfigFields<DevConfig> & Environment;
|
|
@@ -160,6 +175,7 @@ export async function executeSql({
|
|
|
160
175
|
command: string | undefined;
|
|
161
176
|
json: boolean | undefined;
|
|
162
177
|
preview: boolean | undefined;
|
|
178
|
+
batchSize: number;
|
|
163
179
|
}) {
|
|
164
180
|
const sql = file ? readFileSync(file) : command;
|
|
165
181
|
if (!sql) throw new Error(`Error: must provide --command or --file.`);
|
|
@@ -192,7 +208,7 @@ export async function executeSql({
|
|
|
192
208
|
config,
|
|
193
209
|
name,
|
|
194
210
|
shouldPrompt,
|
|
195
|
-
batches: batchSplit(queries),
|
|
211
|
+
batches: batchSplit(queries, batchSize),
|
|
196
212
|
json,
|
|
197
213
|
preview,
|
|
198
214
|
});
|
|
@@ -281,7 +297,7 @@ async function executeRemotely({
|
|
|
281
297
|
}
|
|
282
298
|
}
|
|
283
299
|
|
|
284
|
-
const accountId = await requireAuth(
|
|
300
|
+
const accountId = await requireAuth(config);
|
|
285
301
|
const db: Database = await getDatabaseByNameOrBinding(
|
|
286
302
|
config,
|
|
287
303
|
accountId,
|
|
@@ -313,7 +329,7 @@ async function executeRemotely({
|
|
|
313
329
|
body: JSON.stringify({ sql }),
|
|
314
330
|
}
|
|
315
331
|
);
|
|
316
|
-
result
|
|
332
|
+
logResult(result);
|
|
317
333
|
results.push(...result);
|
|
318
334
|
}
|
|
319
335
|
return results;
|
|
@@ -333,18 +349,16 @@ function logResult(r: QueryResult | QueryResult[]) {
|
|
|
333
349
|
);
|
|
334
350
|
}
|
|
335
351
|
|
|
336
|
-
function batchSplit(queries: string[]) {
|
|
352
|
+
function batchSplit(queries: string[], batchSize: number) {
|
|
337
353
|
logger.log(`🌀 Parsing ${queries.length} statements`);
|
|
338
|
-
const num_batches = Math.ceil(queries.length /
|
|
354
|
+
const num_batches = Math.ceil(queries.length / batchSize);
|
|
339
355
|
const batches: string[] = [];
|
|
340
356
|
for (let i = 0; i < num_batches; i++) {
|
|
341
|
-
batches.push(
|
|
342
|
-
queries.slice(i * QUERY_LIMIT, (i + 1) * QUERY_LIMIT).join("; ")
|
|
343
|
-
);
|
|
357
|
+
batches.push(queries.slice(i * batchSize, (i + 1) * batchSize).join("; "));
|
|
344
358
|
}
|
|
345
359
|
if (num_batches > 1) {
|
|
346
360
|
logger.log(
|
|
347
|
-
`🌀 We are sending ${num_batches} batch(es) to D1 (limited to ${
|
|
361
|
+
`🌀 We are sending ${num_batches} batch(es) to D1 (limited to ${batchSize} statements per batch. Use --batch-size to override.)`
|
|
348
362
|
);
|
|
349
363
|
}
|
|
350
364
|
return batches;
|
package/src/d1/list.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Table from "ink-table";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { fetchResult } from "../cfetch";
|
|
4
|
+
import { withConfig } from "../config";
|
|
4
5
|
import { logger } from "../logger";
|
|
5
6
|
import { requireAuth } from "../user";
|
|
6
7
|
import { renderToString } from "../utils/render";
|
|
@@ -21,19 +22,20 @@ export function Options(d1ListYargs: CommonYargsArgv) {
|
|
|
21
22
|
.epilogue(d1BetaWarning);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
|
|
26
|
+
export const Handler = withConfig<HandlerOptions>(
|
|
27
|
+
async ({ json, config }): Promise<void> => {
|
|
28
|
+
const accountId = await requireAuth(config);
|
|
29
|
+
const dbs: Array<Database> = await listDatabases(accountId);
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
if (json) {
|
|
32
|
+
logger.log(JSON.stringify(dbs, null, 2));
|
|
33
|
+
} else {
|
|
34
|
+
logger.log(d1BetaWarning);
|
|
35
|
+
logger.log(renderToString(<Table data={dbs}></Table>));
|
|
36
|
+
}
|
|
35
37
|
}
|
|
36
|
-
|
|
38
|
+
);
|
|
37
39
|
|
|
38
40
|
export const listDatabases = async (
|
|
39
41
|
accountId: string
|
|
@@ -12,7 +12,11 @@ import { logger } from "../../logger";
|
|
|
12
12
|
import { requireAuth } from "../../user";
|
|
13
13
|
import { renderToString } from "../../utils/render";
|
|
14
14
|
import { createBackup } from "../backups";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_MIGRATION_PATH,
|
|
17
|
+
DEFAULT_MIGRATION_TABLE,
|
|
18
|
+
DEFAULT_BATCH_SIZE,
|
|
19
|
+
} from "../constants";
|
|
16
20
|
import { executeSql } from "../execute";
|
|
17
21
|
import { d1BetaWarning, getDatabaseInfoFromConfig } from "../utils";
|
|
18
22
|
import {
|
|
@@ -28,13 +32,31 @@ import type {
|
|
|
28
32
|
} from "../../yargs-types";
|
|
29
33
|
|
|
30
34
|
export function ApplyOptions(yargs: CommonYargsArgv) {
|
|
31
|
-
return MigrationOptions(yargs)
|
|
35
|
+
return MigrationOptions(yargs)
|
|
36
|
+
.option("experimentalBackend", {
|
|
37
|
+
default: false,
|
|
38
|
+
describe: "Use new experimental DB backend",
|
|
39
|
+
type: "boolean",
|
|
40
|
+
})
|
|
41
|
+
.option("batch-size", {
|
|
42
|
+
describe: "Number of queries to send in a single batch",
|
|
43
|
+
type: "number",
|
|
44
|
+
default: DEFAULT_BATCH_SIZE,
|
|
45
|
+
});
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
type ApplyHandlerOptions = StrictYargsOptionsToInterface<typeof ApplyOptions>;
|
|
35
49
|
|
|
36
50
|
export const ApplyHandler = withConfig<ApplyHandlerOptions>(
|
|
37
|
-
async ({
|
|
51
|
+
async ({
|
|
52
|
+
config,
|
|
53
|
+
database,
|
|
54
|
+
local,
|
|
55
|
+
persistTo,
|
|
56
|
+
preview,
|
|
57
|
+
experimentalBackend,
|
|
58
|
+
batchSize,
|
|
59
|
+
}): Promise<void> => {
|
|
38
60
|
logger.log(d1BetaWarning);
|
|
39
61
|
|
|
40
62
|
const databaseInfo = getDatabaseInfoFromConfig(config, database);
|
|
@@ -115,14 +137,14 @@ Your database may not be available to serve requests during the migration, conti
|
|
|
115
137
|
);
|
|
116
138
|
if (!ok) return;
|
|
117
139
|
|
|
118
|
-
// don't backup prod db when applying migrations locally or
|
|
119
|
-
if (!local
|
|
140
|
+
// don't backup prod db when applying migrations locally, in preview, or when using the experimental backend
|
|
141
|
+
if (!(local || preview || experimentalBackend)) {
|
|
120
142
|
assert(
|
|
121
143
|
databaseInfo,
|
|
122
144
|
"In non-local mode `databaseInfo` should be defined."
|
|
123
145
|
);
|
|
124
146
|
logger.log(renderToString(<Text>🕒 Creating backup...</Text>));
|
|
125
|
-
const accountId = await requireAuth(
|
|
147
|
+
const accountId = await requireAuth(config);
|
|
126
148
|
await createBackup(accountId, databaseInfo.uuid);
|
|
127
149
|
}
|
|
128
150
|
|
|
@@ -149,6 +171,7 @@ Your database may not be available to serve requests during the migration, conti
|
|
|
149
171
|
file: undefined,
|
|
150
172
|
json: undefined,
|
|
151
173
|
preview,
|
|
174
|
+
batchSize,
|
|
152
175
|
});
|
|
153
176
|
|
|
154
177
|
if (response === null) {
|