@sanity/runtime-cli 17.12.0 → 17.13.0-next.g2501ffa
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/README.md +19 -19
- package/dist/actions/blueprints/assets.d.ts +23 -20
- package/dist/actions/blueprints/assets.js +18 -87
- package/dist/actions/blueprints/logs-polling.d.ts +3 -5
- package/dist/actions/blueprints/logs-polling.js +4 -9
- package/dist/actions/blueprints/logs.d.ts +1 -2
- package/dist/actions/blueprints/logs.js +1 -3
- package/dist/actions/blueprints/operations-state.d.ts +10 -0
- package/dist/actions/blueprints/operations-state.js +42 -0
- package/dist/actions/blueprints/operations.d.ts +2 -9
- package/dist/actions/blueprints/operations.js +1 -15
- package/dist/actions/blueprints/pre-deploy.d.ts +19 -11
- package/dist/actions/blueprints/pre-deploy.js +95 -27
- package/dist/actions/blueprints/process-assets.d.ts +13 -11
- package/dist/actions/blueprints/process-assets.js +9 -7
- package/dist/actions/blueprints/stacks.d.ts +4 -4
- package/dist/actions/blueprints/stacks.js +2 -4
- package/dist/actions/blueprints/wait-for-operation.d.ts +1 -10
- package/dist/actions/blueprints/wait-for-operation.js +56 -101
- package/dist/baseCommands.js +6 -1
- package/dist/commands/blueprints/deploy.js +2 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +6 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/cores/blueprints/config.js +1 -1
- package/dist/cores/blueprints/deploy.d.ts +2 -0
- package/dist/cores/blueprints/deploy.js +38 -7
- package/dist/cores/blueprints/destroy.js +4 -2
- package/dist/cores/blueprints/doctor.js +2 -2
- package/dist/cores/blueprints/init.js +3 -1
- package/dist/cores/blueprints/logs.js +11 -5
- package/dist/cores/blueprints/mint-deploy-token.js +2 -1
- package/dist/cores/functions/build.js +4 -5
- package/dist/cores/functions/test.js +3 -1
- package/dist/cores/index.js +3 -1
- package/dist/server/handlers/invoke.js +1 -1
- package/dist/server/static/vendor/vendor.bundle.js +21791 -25197
- package/dist/utils/blueprints/deploy-metadata.d.ts +10 -0
- package/dist/utils/blueprints/deploy-metadata.js +17 -0
- package/dist/utils/blueprints/resolve-deployed-resources.d.ts +2 -3
- package/dist/utils/blueprints/resolve-deployed-resources.js +2 -2
- package/dist/utils/blueprints/wait-for.d.ts +60 -0
- package/dist/utils/blueprints/wait-for.js +115 -0
- package/dist/utils/display/blueprints-formatting.d.ts +1 -0
- package/dist/utils/display/blueprints-formatting.js +17 -3
- package/dist/utils/display/dates.d.ts +0 -2
- package/dist/utils/display/dates.js +0 -25
- package/dist/utils/display/functions-formatting.js +1 -1
- package/dist/utils/display/prompt.js +5 -2
- package/dist/utils/display/resources-formatting.d.ts +6 -0
- package/dist/utils/display/resources-formatting.js +17 -0
- package/dist/utils/functions/child-runtime/durable.js +2 -2
- package/dist/utils/functions/dependency-info.d.ts +30 -0
- package/dist/utils/functions/dependency-info.js +57 -0
- package/dist/utils/functions/invoke/assert-console.d.ts +5 -0
- package/dist/utils/functions/invoke/assert-console.js +60 -0
- package/dist/utils/functions/invoke/local.js +9 -0
- package/dist/utils/functions/is-folder-larger-than.d.ts +5 -0
- package/dist/utils/functions/is-folder-larger-than.js +38 -0
- package/dist/utils/functions/prepare-asset.d.ts +2 -0
- package/dist/utils/functions/prepare-asset.js +59 -23
- package/dist/utils/studios/prepare-asset.js +36 -9
- package/dist/utils/types.d.ts +35 -4
- package/dist/utils/types.js +0 -3
- package/oclif.manifest.json +1002 -1002
- package/package.json +17 -19
- package/dist/utils/functions/get-folder-size.d.ts +0 -5
- package/dist/utils/functions/get-folder-size.js +0 -24
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Recursively validates the total size of a folder, including all nested files and subdirectories.
|
|
5
|
+
*/
|
|
6
|
+
export function isFolderLargerThan(folder, maxBytes) {
|
|
7
|
+
if (!statSync(folder).isDirectory()) {
|
|
8
|
+
throw new Error('Provided path is not a directory');
|
|
9
|
+
}
|
|
10
|
+
function recurse(f, bytesSoFar) {
|
|
11
|
+
let totalBytes = bytesSoFar;
|
|
12
|
+
const fileEntries = readdirSync(f);
|
|
13
|
+
for (const file of fileEntries) {
|
|
14
|
+
const filePath = path.join(f.toString(), file);
|
|
15
|
+
const stats = statSync(filePath);
|
|
16
|
+
if (stats.isFile()) {
|
|
17
|
+
totalBytes += stats.size;
|
|
18
|
+
}
|
|
19
|
+
else if (stats.isDirectory()) {
|
|
20
|
+
const result = recurse(filePath, totalBytes);
|
|
21
|
+
totalBytes = result.totalBytes;
|
|
22
|
+
}
|
|
23
|
+
// return early if we have already exceeded the maximum
|
|
24
|
+
if (totalBytes > maxBytes) {
|
|
25
|
+
return {
|
|
26
|
+
totalBytes,
|
|
27
|
+
exceededMax: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
totalBytes,
|
|
33
|
+
exceededMax: false,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const result = recurse(folder, 0);
|
|
37
|
+
return result.exceededMax;
|
|
38
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import AdmZip from 'adm-zip';
|
|
1
2
|
import type { AssetPrepResult, FunctionResource, InstallerType } from '../types.js';
|
|
2
3
|
export declare function prepareAsset({ blueprintFileDir, resource, installer, }: {
|
|
3
4
|
blueprintFileDir: string;
|
|
4
5
|
resource: FunctionResource;
|
|
5
6
|
installer?: InstallerType;
|
|
6
7
|
}): Promise<AssetPrepResult>;
|
|
8
|
+
export declare function pathToZip(path: string): Promise<AdmZip>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import {
|
|
1
|
+
import fs, { existsSync } from 'node:fs';
|
|
2
|
+
import { stat } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import
|
|
4
|
+
import AdmZip from 'adm-zip';
|
|
5
|
+
import { CONVERT_BYTES_TO_MB, MAX_ASSET_SIZE } from '../../constants.js';
|
|
6
|
+
import { getDependencyInfo, takeAutoInstallManifest, } from './dependency-info.js';
|
|
5
7
|
import { detectNativeModules, errorMessage } from './detect-native-modules.js';
|
|
6
|
-
import {
|
|
8
|
+
import { isFolderLargerThan } from './is-folder-larger-than.js';
|
|
7
9
|
import { resolveResourceDependencies } from './resolve-dependencies.js';
|
|
8
10
|
import { shouldAutoResolveDependencies } from './should-auto-resolve-deps.js';
|
|
9
11
|
import { shouldTranspileFunction } from './should-transpile.js';
|
|
@@ -15,6 +17,8 @@ export async function prepareAsset({ blueprintFileDir, resource, installer, }) {
|
|
|
15
17
|
let functionPath = resolvedFunctionPath;
|
|
16
18
|
let cleanup = async () => { };
|
|
17
19
|
let wasBundled = false;
|
|
20
|
+
let dependenciesInstalled = false;
|
|
21
|
+
let autoInstall;
|
|
18
22
|
const shouldTranspile = await shouldTranspileFunction(resource, functionPath);
|
|
19
23
|
if (shouldTranspile.transpile) {
|
|
20
24
|
try {
|
|
@@ -41,7 +45,8 @@ export async function prepareAsset({ blueprintFileDir, resource, installer, }) {
|
|
|
41
45
|
transpiled: shouldTranspile.transpile,
|
|
42
46
|
installer,
|
|
43
47
|
});
|
|
44
|
-
await
|
|
48
|
+
autoInstall = await takeAutoInstallManifest(functionPath);
|
|
49
|
+
dependenciesInstalled = true;
|
|
45
50
|
}
|
|
46
51
|
if (existsSync(path.join(functionPath, 'node_modules'))) {
|
|
47
52
|
const modulesPath = path.join(functionPath, 'node_modules');
|
|
@@ -51,29 +56,60 @@ export async function prepareAsset({ blueprintFileDir, resource, installer, }) {
|
|
|
51
56
|
}
|
|
52
57
|
}
|
|
53
58
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
// First check the size before trying to create the zip file
|
|
60
|
+
const result = isFolderLargerThan(functionPath, MAX_ASSET_SIZE);
|
|
61
|
+
if (result) {
|
|
56
62
|
throw new Error('Resource is larger than max asset size of 200 MB.');
|
|
57
63
|
}
|
|
58
|
-
|
|
64
|
+
const zip = await pathToZip(functionPath);
|
|
65
|
+
// Add up the uncompressed sizes of all entries to get a more accurate size of the asset being uploaded
|
|
66
|
+
const zipEntrySize = zip
|
|
67
|
+
.getEntries()
|
|
68
|
+
.map((entry) => entry.header.size)
|
|
69
|
+
.reduce((a, b) => a + b, 0);
|
|
70
|
+
if (zipEntrySize > MAX_ASSET_SIZE) {
|
|
71
|
+
throw new Error(`Asset size of ${(zipEntrySize / CONVERT_BYTES_TO_MB).toFixed(2)} MB exceeds the maximum allowed size of 200 MB.`);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
outputBuffer: await zip.toBufferPromise(),
|
|
76
|
+
fileExtension: 'zip',
|
|
77
|
+
assetParameter: 'src',
|
|
78
|
+
cleanup,
|
|
79
|
+
metadata: {
|
|
80
|
+
transpiled: shouldTranspile.transpile,
|
|
81
|
+
bundled: wasBundled,
|
|
82
|
+
dependenciesInstalled,
|
|
83
|
+
...(await getDependencyInfo({
|
|
84
|
+
sourceDir: resolvedFunctionPath,
|
|
85
|
+
autoInstall,
|
|
86
|
+
bundled: wasBundled,
|
|
87
|
+
})),
|
|
88
|
+
assetBytes: zipEntrySize,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
59
91
|
}
|
|
60
92
|
catch (err) {
|
|
61
93
|
return { success: false, cleanup, error: err instanceof Error ? err.message : `${err}` };
|
|
62
94
|
}
|
|
63
95
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
96
|
+
export async function pathToZip(path) {
|
|
97
|
+
const stats = await stat(path);
|
|
98
|
+
const zip = new AdmZip(undefined, {
|
|
99
|
+
fs: {
|
|
100
|
+
...fs,
|
|
101
|
+
// @ts-expect-error monkey patching to return matching mtime for builds
|
|
102
|
+
statSync(path, options) {
|
|
103
|
+
const s = fs.statSync(path, options);
|
|
104
|
+
if (s)
|
|
105
|
+
s.mtime = new Date(0);
|
|
106
|
+
return s;
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
if (stats.isDirectory())
|
|
111
|
+
zip.addLocalFolder(path);
|
|
112
|
+
else
|
|
113
|
+
zip.addLocalFile(path, '', 'index.js');
|
|
114
|
+
return zip;
|
|
79
115
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { createWriteStream } from 'node:fs';
|
|
2
|
-
import { mkdtemp, rm, stat } from 'node:fs/promises';
|
|
2
|
+
import { mkdtemp, readFile, rm, stat } from 'node:fs/promises';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import path, { basename, dirname, join } from 'node:path';
|
|
5
5
|
import { pipeline } from 'node:stream/promises';
|
|
6
6
|
import { createGzip } from 'node:zlib';
|
|
7
7
|
import { buildStudio, compareDependencyVersions } from '@sanity/cli-build/_internal/build';
|
|
8
|
+
import { getLocalPackageVersion } from '@sanity/cli-core';
|
|
8
9
|
import { pack } from 'tar-fs';
|
|
9
10
|
export async function prepareStudioAsset({ blueprintFileDir, resource, }) {
|
|
10
|
-
// validate resource has an
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
!resource.externalId) {
|
|
11
|
+
// validate resource has an appId
|
|
12
|
+
const appId = getAppId(resource);
|
|
13
|
+
if (!appId) {
|
|
14
14
|
return {
|
|
15
15
|
success: false,
|
|
16
16
|
async cleanup() {
|
|
@@ -23,6 +23,8 @@ export async function prepareStudioAsset({ blueprintFileDir, resource, }) {
|
|
|
23
23
|
// no op
|
|
24
24
|
};
|
|
25
25
|
const studioPath = path.resolve(blueprintFileDir, resource.src);
|
|
26
|
+
// set only when auto-updates is on, because the build compares versions only then
|
|
27
|
+
let mismatchedPackages;
|
|
26
28
|
try {
|
|
27
29
|
const studioPathStat = await stat(studioPath);
|
|
28
30
|
if (!studioPathStat.isDirectory()) {
|
|
@@ -48,14 +50,15 @@ export async function prepareStudioAsset({ blueprintFileDir, resource, }) {
|
|
|
48
50
|
await rm(outDir, { force: true, recursive: true });
|
|
49
51
|
await rm(outFile, { force: true });
|
|
50
52
|
};
|
|
51
|
-
const appId = resource.externalId;
|
|
52
53
|
try {
|
|
53
54
|
await buildStudio({
|
|
54
55
|
appId,
|
|
55
56
|
autoUpdatesEnabled: resource.autoUpdates.enabled,
|
|
56
57
|
checkAppId() { },
|
|
57
58
|
async compareDependencyVersions(packages) {
|
|
58
|
-
|
|
59
|
+
const result = await compareDependencyVersions(packages, studioPath, { appId });
|
|
60
|
+
mismatchedPackages = result.mismatched.map((m) => m.pkg);
|
|
61
|
+
return result;
|
|
59
62
|
},
|
|
60
63
|
determineBasePath() {
|
|
61
64
|
return resource.basePath ?? '/';
|
|
@@ -105,11 +108,18 @@ export async function prepareStudioAsset({ blueprintFileDir, resource, }) {
|
|
|
105
108
|
}
|
|
106
109
|
// tar/gzip/write the built output
|
|
107
110
|
await pipeline(pack(dirname(outDir), { entries: [basename(outDir)] }), createGzip(), createWriteStream(outFile));
|
|
111
|
+
const buffer = await readFile(outFile);
|
|
108
112
|
return {
|
|
109
113
|
success: true,
|
|
110
114
|
cleanup,
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
outputBuffer: buffer,
|
|
116
|
+
fileExtension: 'tar.gz',
|
|
117
|
+
assetParameter: 'src',
|
|
118
|
+
metadata: {
|
|
119
|
+
sanityVersion: await getInstalledSanityVersion(studioPath),
|
|
120
|
+
mismatchedPackages,
|
|
121
|
+
assetBytes: buffer.length,
|
|
122
|
+
},
|
|
113
123
|
};
|
|
114
124
|
}
|
|
115
125
|
catch (error) {
|
|
@@ -137,3 +147,20 @@ function createSilentOutput() {
|
|
|
137
147
|
},
|
|
138
148
|
};
|
|
139
149
|
}
|
|
150
|
+
async function getInstalledSanityVersion(studioPath) {
|
|
151
|
+
try {
|
|
152
|
+
return (await getLocalPackageVersion('sanity', studioPath)) ?? undefined;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function getAppId(resource) {
|
|
159
|
+
if ('externalId' in resource && typeof resource.externalId === 'string' && resource.externalId) {
|
|
160
|
+
return resource.externalId;
|
|
161
|
+
}
|
|
162
|
+
else if (resource.lifecycle?.ownershipAction?.type === 'attach') {
|
|
163
|
+
return resource.lifecycle.ownershipAction.id;
|
|
164
|
+
}
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -20,8 +20,6 @@ export type FunctionResource = FunctionGroqResource | BlueprintPubSubFunctionRes
|
|
|
20
20
|
export type EventFunctionResource = Exclude<FunctionResource, BlueprintPubSubFunctionResource>;
|
|
21
21
|
/** The `event` of any function resource that declares one */
|
|
22
22
|
export type FunctionResourceEvent = EventFunctionResource['event'];
|
|
23
|
-
/** Resource types that carry a deployable asset (have src: string) */
|
|
24
|
-
export type AssetResource = FunctionResource | BlueprintStudioResource;
|
|
25
23
|
/** @internal */
|
|
26
24
|
export interface AuthParams {
|
|
27
25
|
token: string;
|
|
@@ -52,7 +50,6 @@ export declare function isRoleResource(r: unknown): r is BlueprintRoleResource;
|
|
|
52
50
|
export declare function isDatasetResource(r: unknown): r is BlueprintDatasetResource;
|
|
53
51
|
export declare function isStudioResource(r: BlueprintResource): r is BlueprintStudioResource;
|
|
54
52
|
export declare function isDurableFunctionResource(r: unknown): r is BlueprintDurableFunctionResource;
|
|
55
|
-
export declare function isAssetResource(r: BlueprintResource): r is AssetResource;
|
|
56
53
|
export declare function isWebhookResource(r: unknown): r is BlueprintDocumentWebhookResource;
|
|
57
54
|
interface StackBase {
|
|
58
55
|
id: string;
|
|
@@ -90,7 +87,22 @@ export interface StackMutation {
|
|
|
90
87
|
};
|
|
91
88
|
userMessage?: string;
|
|
92
89
|
preDeploy?: boolean;
|
|
90
|
+
metadata?: DeployMetadata;
|
|
93
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Facts about one deploy, stored with the Blueprint on the server.
|
|
94
|
+
* The API accepts it on stack update and never returns it.
|
|
95
|
+
*/
|
|
96
|
+
export interface DeployMetadata {
|
|
97
|
+
/** The environment that ran the deploy */
|
|
98
|
+
client?: Record<string, unknown>;
|
|
99
|
+
/** One entry per resource that had an asset prepared, plus what was learned while preparing it */
|
|
100
|
+
resources?: ResourceMetadata[];
|
|
101
|
+
}
|
|
102
|
+
export type ResourceMetadata = {
|
|
103
|
+
name: string;
|
|
104
|
+
type: string;
|
|
105
|
+
} & Record<string, unknown>;
|
|
94
106
|
/** @internal */
|
|
95
107
|
export interface BuildPayloadOptions {
|
|
96
108
|
data?: string;
|
|
@@ -301,13 +313,32 @@ export declare const INSTALLER_OPTIONS: readonly ['npm', 'pnpm', 'yarn'];
|
|
|
301
313
|
export type InstallerType = 'npm' | 'pnpm' | 'yarn';
|
|
302
314
|
export type AssetPrepResult = {
|
|
303
315
|
success: true;
|
|
304
|
-
|
|
316
|
+
outputBuffer: Buffer;
|
|
317
|
+
fileExtension: string;
|
|
318
|
+
assetParameter: string;
|
|
305
319
|
cleanup: () => Promise<void>;
|
|
320
|
+
/** Facts learned about the resource while preparing its asset. Sent as deploy metadata. */
|
|
321
|
+
metadata?: Record<string, unknown>;
|
|
306
322
|
} | {
|
|
307
323
|
success: false;
|
|
308
324
|
cleanup: () => Promise<void>;
|
|
309
325
|
error: string;
|
|
310
326
|
};
|
|
327
|
+
export type PrepAssetFn<R extends BlueprintResource> = (options: {
|
|
328
|
+
resource: R;
|
|
329
|
+
blueprintFileDir: string;
|
|
330
|
+
installer?: InstallerType;
|
|
331
|
+
}) => Promise<AssetPrepResult>;
|
|
332
|
+
export type PreDeployConfig = {
|
|
333
|
+
/** The resource type this config applies to or a function that returns true if this config applies to the given type. */
|
|
334
|
+
resourceType: string | ((type: string) => boolean);
|
|
335
|
+
/** Function that takes a resource and returns a buffer to be sent to blueprints. */
|
|
336
|
+
prepareAsset?: PrepAssetFn<BlueprintResource>;
|
|
337
|
+
};
|
|
338
|
+
export type AssetResource<R extends BlueprintResource> = {
|
|
339
|
+
resource: R;
|
|
340
|
+
prepareAsset: PrepAssetFn<R>;
|
|
341
|
+
};
|
|
311
342
|
export type Warning = {
|
|
312
343
|
code: string;
|
|
313
344
|
suggestions: string[];
|
package/dist/utils/types.js
CHANGED
|
@@ -31,9 +31,6 @@ export function isStudioResource(r) {
|
|
|
31
31
|
export function isDurableFunctionResource(r) {
|
|
32
32
|
return validateDurableFunction(r).length === 0;
|
|
33
33
|
}
|
|
34
|
-
export function isAssetResource(r) {
|
|
35
|
-
return isLocalFunctionResource(r) || isStudioResource(r);
|
|
36
|
-
}
|
|
37
34
|
export function isWebhookResource(r) {
|
|
38
35
|
return validateDocumentWebhook(r).length === 0;
|
|
39
36
|
}
|