netlify-cli 17.18.1 → 17.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/blobs/blobs-list.d.ts.map +1 -1
- package/dist/commands/blobs/blobs-list.js +4 -2
- package/dist/commands/recipes/recipes.d.ts +9 -5
- package/dist/commands/recipes/recipes.d.ts.map +1 -1
- package/dist/commands/recipes/recipes.js +4 -4
- package/dist/lib/blobs/blobs.js +1 -1
- package/dist/lib/edge-functions/editor-helper.js +1 -1
- package/dist/recipes/blobs-migrate/index.d.ts +9 -0
- package/dist/recipes/blobs-migrate/index.d.ts.map +1 -0
- package/dist/recipes/blobs-migrate/index.js +76 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/npm-shrinkwrap.json +997 -135
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blobs-list.d.ts","sourceRoot":"","sources":["../../../src/commands/blobs/blobs-list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAGxC,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAE5C,UAAU,OAAQ,SAAQ,YAAY;IACpC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,SAAS,cAAqB,MAAM,WAAW,OAAO,WAAW,WAAW,
|
|
1
|
+
{"version":3,"file":"blobs-list.d.ts","sourceRoot":"","sources":["../../../src/commands/blobs/blobs-list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAGxC,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAE5C,UAAU,OAAQ,SAAQ,YAAY;IACpC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,SAAS,cAAqB,MAAM,WAAW,OAAO,WAAW,WAAW,kBAuCxF,CAAA"}
|
|
@@ -15,8 +15,10 @@ export const blobsList = async (storeName, options, command) => {
|
|
|
15
15
|
prefix: options.prefix,
|
|
16
16
|
});
|
|
17
17
|
if (options.json) {
|
|
18
|
-
logJson({ blobs, directories });
|
|
19
|
-
|
|
18
|
+
return logJson({ blobs, directories });
|
|
19
|
+
}
|
|
20
|
+
if (blobs.length === 0 && directories.length === 0) {
|
|
21
|
+
return log(`Netlify Blobs store ${chalk.yellow(storeName)} is empty`);
|
|
20
22
|
}
|
|
21
23
|
const table = new AsciiTable(`Netlify Blobs (${storeName})`);
|
|
22
24
|
table.setHeading('Key', 'ETag');
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { OptionValues } from 'commander';
|
|
2
2
|
import BaseCommand from '../base-command.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
interface RunRecipeOptions {
|
|
4
|
+
args: string[];
|
|
5
|
+
command?: BaseCommand;
|
|
6
|
+
config: unknown;
|
|
7
|
+
recipeName: string;
|
|
8
|
+
repositoryRoot: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const runRecipe: ({ args, command, config, recipeName, repositoryRoot }: RunRecipeOptions) => Promise<any>;
|
|
8
11
|
export declare const recipesCommand: (recipeName: string, options: OptionValues, command: BaseCommand) => Promise<any>;
|
|
12
|
+
export {};
|
|
9
13
|
//# sourceMappingURL=recipes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recipes.d.ts","sourceRoot":"","sources":["../../../src/commands/recipes/recipes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAKxC,OAAO,WAAW,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"recipes.d.ts","sourceRoot":"","sources":["../../../src/commands/recipes/recipes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAKxC,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAM5C,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,MAAM,EAAE,OAAO,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,eAAO,MAAM,SAAS,0DAAiE,gBAAgB,iBAItG,CAAA;AAED,eAAO,MAAM,cAAc,eAAsB,MAAM,WAAW,YAAY,WAAW,WAAW,KAAG,QAAQ,GAAG,CAgDjH,CAAA"}
|
|
@@ -4,10 +4,9 @@ import inquirer from 'inquirer';
|
|
|
4
4
|
import { NETLIFYDEVERR, chalk, log } from '../../utils/command-helpers.js';
|
|
5
5
|
import { getRecipe, listRecipes } from './common.js';
|
|
6
6
|
const SUGGESTION_TIMEOUT = 1e4;
|
|
7
|
-
|
|
8
|
-
export const runRecipe = async ({ config, recipeName, repositoryRoot }) => {
|
|
7
|
+
export const runRecipe = async ({ args, command, config, recipeName, repositoryRoot }) => {
|
|
9
8
|
const recipe = await getRecipe(recipeName);
|
|
10
|
-
return recipe.run({ config, repositoryRoot });
|
|
9
|
+
return recipe.run({ args, command, config, repositoryRoot });
|
|
11
10
|
};
|
|
12
11
|
export const recipesCommand = async (recipeName, options, command) => {
|
|
13
12
|
const { config, repositoryRoot } = command.netlify;
|
|
@@ -15,8 +14,9 @@ export const recipesCommand = async (recipeName, options, command) => {
|
|
|
15
14
|
if (sanitizedRecipeName.length === 0) {
|
|
16
15
|
return command.help();
|
|
17
16
|
}
|
|
17
|
+
const args = command.args.slice(1);
|
|
18
18
|
try {
|
|
19
|
-
return await runRecipe({ config, recipeName: sanitizedRecipeName, repositoryRoot });
|
|
19
|
+
return await runRecipe({ args, command, config, recipeName: sanitizedRecipeName, repositoryRoot });
|
|
20
20
|
}
|
|
21
21
|
catch (error) {
|
|
22
22
|
if (
|
package/dist/lib/blobs/blobs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { BlobsServer } from '@netlify/blobs';
|
|
3
|
+
import { BlobsServer } from '@netlify/blobs/server';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
import { log, NETLIFYDEVLOG } from '../../utils/command-helpers.js';
|
|
6
6
|
import { getPathInProject } from '../settings.js';
|
|
@@ -26,5 +26,5 @@ export const promptEditorHelper = async ({ NETLIFYDEVLOG, chalk, config, log, re
|
|
|
26
26
|
log(`${NETLIFYDEVLOG} You can start this configuration manually by running ${chalk.magenta.bold('netlify recipes vscode')}.`);
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
|
-
await runRecipe({ config, recipeName: 'vscode', repositoryRoot });
|
|
29
|
+
await runRecipe({ args: [], config, recipeName: 'vscode', repositoryRoot });
|
|
30
30
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import BaseCommand from '../../commands/base-command.js';
|
|
2
|
+
export declare const description = "Migrate legacy Netlify Blobs stores";
|
|
3
|
+
interface Options {
|
|
4
|
+
args: string[];
|
|
5
|
+
command: BaseCommand;
|
|
6
|
+
}
|
|
7
|
+
export declare const run: ({ args, command }: Options) => Promise<void>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/recipes/blobs-migrate/index.ts"],"names":[],"mappings":"AAIA,OAAO,WAAW,MAAM,gCAAgC,CAAA;AAGxD,eAAO,MAAM,WAAW,wCAAwC,CAAA;AAIhE,UAAU,OAAO;IACf,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,OAAO,EAAE,WAAW,CAAA;CACrB;AAED,eAAO,MAAM,GAAG,sBAA6B,OAAO,kBA0FnD,CAAA"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getStore, listStores } from '@netlify/blobs';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import pMap from 'p-map';
|
|
4
|
+
import { error, log } from '../../utils/command-helpers.js';
|
|
5
|
+
export const description = 'Migrate legacy Netlify Blobs stores';
|
|
6
|
+
const BLOB_OPS_CONCURRENCY = 5;
|
|
7
|
+
export const run = async ({ args, command }) => {
|
|
8
|
+
if (args.length !== 1) {
|
|
9
|
+
return error(`Usage: netlify recipes blobs-migrate <name of store>`);
|
|
10
|
+
}
|
|
11
|
+
const [storeName] = args;
|
|
12
|
+
const { api, siteInfo } = command.netlify;
|
|
13
|
+
const clientOptions = {
|
|
14
|
+
apiURL: `${api.scheme}://${api.host}`,
|
|
15
|
+
siteID: siteInfo?.id ?? '',
|
|
16
|
+
token: api.accessToken ?? '',
|
|
17
|
+
};
|
|
18
|
+
// The store we'll copy from.
|
|
19
|
+
const oldStore = getStore({
|
|
20
|
+
...clientOptions,
|
|
21
|
+
name: `netlify-internal/legacy-namespace/${storeName}`,
|
|
22
|
+
});
|
|
23
|
+
// The store we'll write to.
|
|
24
|
+
const newStore = getStore({
|
|
25
|
+
...clientOptions,
|
|
26
|
+
name: storeName,
|
|
27
|
+
});
|
|
28
|
+
const { blobs } = await oldStore.list();
|
|
29
|
+
if (blobs.length === 0) {
|
|
30
|
+
return log(`Store '${storeName}' does not exist or is empty, so there's nothing to migrate.`);
|
|
31
|
+
}
|
|
32
|
+
const { stores } = await listStores(clientOptions);
|
|
33
|
+
if (stores.includes(storeName)) {
|
|
34
|
+
const { confirmExistingStore } = await inquirer.prompt({
|
|
35
|
+
type: 'confirm',
|
|
36
|
+
name: 'confirmExistingStore',
|
|
37
|
+
message: `The store '${storeName}' already exists in the new format, which means it has already been migrated or it has been used with a newer version of the Netlify Blobs client. If you continue with the migration, any blobs from the legacy store will overwrite newer entries that have the same key. Do you want to proceed?`,
|
|
38
|
+
default: false,
|
|
39
|
+
});
|
|
40
|
+
if (!confirmExistingStore) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const { confirmMigration } = await inquirer.prompt({
|
|
45
|
+
type: 'confirm',
|
|
46
|
+
name: 'confirmMigration',
|
|
47
|
+
message: `You're about to migrate the store '${storeName}' with ${blobs.length} blobs. Do you want to proceed?`,
|
|
48
|
+
default: true,
|
|
49
|
+
});
|
|
50
|
+
if (!confirmMigration) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
await pMap(blobs, async (blob) => {
|
|
54
|
+
log(`Migrating blob with key '${blob.key}'...`);
|
|
55
|
+
const result = await oldStore.getWithMetadata(blob.key);
|
|
56
|
+
if (result === null) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
await newStore.set(blob.key, result.data, { metadata: result.metadata });
|
|
60
|
+
}, { concurrency: BLOB_OPS_CONCURRENCY });
|
|
61
|
+
log('Verifying data in the new store...');
|
|
62
|
+
const { blobs: newBlobs } = await newStore.list();
|
|
63
|
+
const blobsMap = new Map(newBlobs.map((blob) => [blob.key, blob.etag]));
|
|
64
|
+
// Before deleting anything, let's first verify that all entries that exist
|
|
65
|
+
// in the old store are now also on the new store, with the same etag.
|
|
66
|
+
if (!blobs.every((blob) => blobsMap.get(blob.key) === blob.etag)) {
|
|
67
|
+
return error(`Failed to migrate some blobs. Try running the command again.`);
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
await pMap(blobs, (blob) => oldStore.delete(blob.key), { concurrency: BLOB_OPS_CONCURRENCY });
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return error('Failed to remove legacy store after migration. Try running the command again.');
|
|
74
|
+
}
|
|
75
|
+
log(`Store '${storeName}' has been migrated successfully.`);
|
|
76
|
+
};
|