@sanity/runtime-cli 17.12.1 → 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 +2 -0
- package/dist/actions/blueprints/assets.js +4 -3
- package/dist/actions/blueprints/pre-deploy.d.ts +6 -3
- package/dist/actions/blueprints/pre-deploy.js +12 -1
- package/dist/actions/blueprints/process-assets.d.ts +1 -0
- package/dist/actions/blueprints/process-assets.js +1 -0
- 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 +10 -1
- package/dist/cores/blueprints/doctor.js +1 -1
- package/dist/cores/blueprints/mint-deploy-token.js +2 -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/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/dependency-info.d.ts +30 -0
- package/dist/utils/functions/dependency-info.js +57 -0
- package/dist/utils/functions/prepare-asset.js +17 -18
- package/dist/utils/studios/prepare-asset.js +31 -6
- package/dist/utils/types.d.ts +17 -0
- package/oclif.manifest.json +1002 -1002
- package/package.json +16 -18
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facts about the environment that runs a deploy.
|
|
3
|
+
* Sent as the `client` part of deploy metadata. Keys with an `undefined` value drop out of the JSON body.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getClientMetadata({ cliVersion, dir, }: {
|
|
6
|
+
/** Version of the CLI that hosts this plugin, when known */
|
|
7
|
+
cliVersion?: string;
|
|
8
|
+
/** Directory of the Blueprint file, used to detect the package manager */
|
|
9
|
+
dir: string;
|
|
10
|
+
}): Record<string, unknown>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { platform, versions } from 'node:process';
|
|
2
|
+
import config, { RUNTIME_CLI_VERSION } from '../../config.js';
|
|
3
|
+
import { detectPackageManager } from '../package-manager.js';
|
|
4
|
+
/**
|
|
5
|
+
* Facts about the environment that runs a deploy.
|
|
6
|
+
* Sent as the `client` part of deploy metadata. Keys with an `undefined` value drop out of the JSON body.
|
|
7
|
+
*/
|
|
8
|
+
export function getClientMetadata({ cliVersion, dir, }) {
|
|
9
|
+
return {
|
|
10
|
+
cliVersion,
|
|
11
|
+
runtimeCliVersion: RUNTIME_CLI_VERSION,
|
|
12
|
+
nodeVersion: versions.node,
|
|
13
|
+
nodePackageManager: detectPackageManager(dir),
|
|
14
|
+
platform,
|
|
15
|
+
ci: config.isCi,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -4,6 +4,7 @@ import type { DeploymentPlan } from '../../actions/blueprints/stacks.js';
|
|
|
4
4
|
import { type BlueprintResourceRecord, type Stack, type StackSummary } from '../types.js';
|
|
5
5
|
export declare function formatTitle(title: string, name: string): string;
|
|
6
6
|
export declare function formatDeployedResourceTree(resources: BlueprintResourceRecord[] | undefined, verbose?: boolean): string;
|
|
7
|
+
export declare function formatStudioUrls(resources: BlueprintResourceRecord[] | undefined): string[];
|
|
7
8
|
export declare function formatResourceTree(resources: BlueprintResource[] | undefined, verbose?: boolean): string;
|
|
8
9
|
export declare function formatStackInfo(stack: Stack | StackSummary | Blueprint, isCurrentStack?: boolean): string;
|
|
9
10
|
export declare function formatStacksListing(stacks: StackSummary[], currentStackId?: string): string;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { formatDateTime, formatElapsed } from '@sanity/cli-core/dates';
|
|
1
2
|
import { treeify } from 'array-treeify';
|
|
2
3
|
import { SANITY_ACCESS_ROBOT, SANITY_ACCESS_ROLE, SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_DURABLE, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_PUBSUB, SANITY_FUNCTION_SCHEDULED, SANITY_FUNCTION_SYNC_TAG_INVALIDATE, SANITY_PROJECT, SANITY_PROJECT_CORS, SANITY_PROJECT_DATASET, SANITY_PROJECT_WEBHOOK, SANITY_STUDIO, } from '../../constants.js';
|
|
3
4
|
import { styleText } from '../style-text.js';
|
|
4
5
|
import { isCorsOriginResource, isDatasetResource, isRobotResource, isRoleResource, isStudioResource, isWebhookResource, } from '../types.js';
|
|
5
|
-
import { formatDateTime, formatDuration } from './dates.js';
|
|
6
6
|
import { capitalize, niceId, renderSection } from './presenters.js';
|
|
7
|
-
import { arrayifyCors, arrayifyDataset, arrayifyFunction, arrayifyRobot, arrayifyRole, arrayifyStudio, arrayifyWebhook, } from './resources-formatting.js';
|
|
7
|
+
import { arrayifyCors, arrayifyDataset, arrayifyFunction, arrayifyRobot, arrayifyRole, arrayifyStudio, arrayifyWebhook, studioHost, studioUrl, } from './resources-formatting.js';
|
|
8
8
|
const functionCategory = {
|
|
9
9
|
label: 'Functions',
|
|
10
10
|
displayNameAttribute: 'displayName',
|
|
@@ -165,6 +165,19 @@ export function formatDeployedResourceTree(resources, verbose = false) {
|
|
|
165
165
|
(res) => ({ name: res.name, type: res.type, ...(res.resolvedParameters ?? res.parameters) }), verbose);
|
|
166
166
|
return `${treeify(output)}\n`;
|
|
167
167
|
}
|
|
168
|
+
export function formatStudioUrls(resources) {
|
|
169
|
+
if (!resources)
|
|
170
|
+
return [];
|
|
171
|
+
const lines = [];
|
|
172
|
+
for (const res of resources) {
|
|
173
|
+
if (res.type !== SANITY_STUDIO)
|
|
174
|
+
continue;
|
|
175
|
+
const host = studioHost(res.resolvedParameters ?? res.parameters);
|
|
176
|
+
if (host)
|
|
177
|
+
lines.push(`Studio ${styleText(['bold', 'green'], res.name)} ${studioUrl(host)}`);
|
|
178
|
+
}
|
|
179
|
+
return lines;
|
|
180
|
+
}
|
|
168
181
|
export function formatResourceTree(resources, verbose = false) {
|
|
169
182
|
if (!resources || resources.length === 0)
|
|
170
183
|
return ' Zero resources';
|
|
@@ -207,7 +220,8 @@ export function formatStackInfo(stack, isCurrentStack = false) {
|
|
|
207
220
|
if (time)
|
|
208
221
|
parts.push(styleText('dim', formatDateTime(time)));
|
|
209
222
|
if (op.completedAt && op.createdAt) {
|
|
210
|
-
|
|
223
|
+
const duration = new Date(op.completedAt).getTime() - new Date(op.createdAt).getTime();
|
|
224
|
+
parts.push(styleText('yellow', `(${formatElapsed(duration)})`));
|
|
211
225
|
}
|
|
212
226
|
rows.push(['Operation', parts.join(' ')]);
|
|
213
227
|
if (op.userMessage)
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
type DateInput = string | number | Date;
|
|
2
2
|
export declare function formatDate(input: DateInput): string;
|
|
3
3
|
export declare function formatTime(input: DateInput): string;
|
|
4
|
-
export declare function formatDateTime(input: DateInput): string;
|
|
5
|
-
export declare function formatDuration(startDate: string, endDate: string): string;
|
|
6
4
|
export {};
|
|
@@ -19,28 +19,3 @@ export function formatTime(input) {
|
|
|
19
19
|
const s = String(d.getSeconds()).padStart(2, '0');
|
|
20
20
|
return `${h}:${m}:${s}`;
|
|
21
21
|
}
|
|
22
|
-
export function formatDateTime(input) {
|
|
23
|
-
const d = toDate(input);
|
|
24
|
-
if (Number.isNaN(d.getTime()))
|
|
25
|
-
return '';
|
|
26
|
-
return `${formatDate(d)} ${formatTime(d)}`;
|
|
27
|
-
}
|
|
28
|
-
export function formatDuration(startDate, endDate) {
|
|
29
|
-
const start = new Date(startDate).getTime();
|
|
30
|
-
const end = new Date(endDate).getTime();
|
|
31
|
-
if (start > end)
|
|
32
|
-
return 'Invalid duration';
|
|
33
|
-
const durationMs = end - start;
|
|
34
|
-
if (durationMs < 1000)
|
|
35
|
-
return `${durationMs}ms`;
|
|
36
|
-
if (durationMs < 60000)
|
|
37
|
-
return `${Math.round(durationMs / 1000)}s`;
|
|
38
|
-
if (durationMs < 3600000) {
|
|
39
|
-
const minutes = Math.floor(durationMs / 60000);
|
|
40
|
-
const seconds = Math.floor((durationMs % 60000) / 1000);
|
|
41
|
-
return `${minutes}m ${seconds}s`;
|
|
42
|
-
}
|
|
43
|
-
const hours = Math.floor(durationMs / 3600000);
|
|
44
|
-
const minutes = Math.floor((durationMs % 3600000) / 60000);
|
|
45
|
-
return `${hours}h ${minutes}m`;
|
|
46
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { formatDateTime } from '@sanity/cli-core/dates';
|
|
1
2
|
import { SANITY_FUNCTION_PREFIX } from '../../constants.js';
|
|
2
3
|
import { styleText } from '../style-text.js';
|
|
3
|
-
import { formatDateTime } from './dates.js';
|
|
4
4
|
import { niceId, renderSection } from './presenters.js';
|
|
5
5
|
export function formatFunctionsList(functions, options = {}) {
|
|
6
6
|
if (!options.verbose)
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { confirm, input, Separator, select } from '@inquirer/prompts';
|
|
2
2
|
import { createEmptyStack, listStacks } from '../../actions/blueprints/stacks.js';
|
|
3
3
|
import { groupProjectsByOrganization } from '../../actions/sanity/projects.js';
|
|
4
|
+
import { STACKS_DOCS_URL } from '../../constants.js';
|
|
4
5
|
import { styleText } from '../style-text.js';
|
|
5
6
|
import { niceId } from './presenters.js';
|
|
6
7
|
// --- Wizard infrastructure ---
|
|
7
8
|
export const BACK = Symbol('back');
|
|
9
|
+
/** Shown under the highlighted Stack choice; a printed line would break the wizard's two-line erase on Back */
|
|
10
|
+
const STACK_DEFINITION = `A Stack is the deployed copy of a Blueprint: the live resources on Sanity's side. ${STACKS_DOCS_URL}`;
|
|
8
11
|
/** Thrown when the user picks "Cancel" in a prompt. Cores translate it to a clean result. */
|
|
9
12
|
export class CancelledError extends Error {
|
|
10
13
|
constructor(message = 'Cancelled by user.') {
|
|
@@ -270,7 +273,7 @@ export async function promptForStack({ scopeType, scopeId, token, logger, allowB
|
|
|
270
273
|
if (stacks.length > 0) {
|
|
271
274
|
const stackChoices = [
|
|
272
275
|
new Separator(styleText('underline', 'Create a new Stack:')),
|
|
273
|
-
{ name: styleText('bold', 'New Stack'), value: NEW_STACK_ID },
|
|
276
|
+
{ name: styleText('bold', 'New Stack'), value: NEW_STACK_ID, description: STACK_DEFINITION },
|
|
274
277
|
new Separator(styleText('underline', 'Use an existing Stack:')),
|
|
275
278
|
...stacks.map((s) => ({
|
|
276
279
|
name: `"${s.name}" ${niceId(s.id)} ${styleText('dim', `(${s.resourceCount} ${s.resourceCount === 1 ? 'resource' : 'resources'})`)}`,
|
|
@@ -301,7 +304,7 @@ export async function promptForStack({ scopeType, scopeId, token, logger, allowB
|
|
|
301
304
|
{
|
|
302
305
|
name: 'Create the first Stack',
|
|
303
306
|
value: NEW_STACK_ID,
|
|
304
|
-
description:
|
|
307
|
+
description: STACK_DEFINITION,
|
|
305
308
|
},
|
|
306
309
|
{ name: 'Cancel', value: CANCEL, description: 'Stop here and change nothing' },
|
|
307
310
|
], allowBack),
|
|
@@ -5,5 +5,11 @@ export declare function arrayifyDataset(resource: BlueprintDatasetResource): Tre
|
|
|
5
5
|
export declare function arrayifyFunction(fn: BlueprintResource): TreeInput;
|
|
6
6
|
export declare function arrayifyRobot(resource: BlueprintRobotResource): TreeInput;
|
|
7
7
|
export declare function arrayifyRole(resource: BlueprintRoleResource): TreeInput;
|
|
8
|
+
/**
|
|
9
|
+
* Hostname label of a Studio: the resolved `appHost` when present, else the authored `slug`.
|
|
10
|
+
* undefined when a `$.resources` reference
|
|
11
|
+
*/
|
|
12
|
+
export declare function studioHost(params: Record<string, unknown>): string | undefined;
|
|
13
|
+
export declare function studioUrl(host: string): string;
|
|
8
14
|
export declare function arrayifyStudio(resource: BlueprintStudioResource): TreeInput;
|
|
9
15
|
export declare function arrayifyWebhook(resource: BlueprintDocumentWebhookResource): TreeInput;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import config from '../../config.js';
|
|
1
2
|
import { hasEventSource, isLocalFunctionResource, isScheduleEvent, } from '../../utils/types.js';
|
|
2
3
|
import { styleText } from '../style-text.js';
|
|
3
4
|
import { niceId } from './presenters.js';
|
|
@@ -120,8 +121,24 @@ export function arrayifyRole(resource) {
|
|
|
120
121
|
}
|
|
121
122
|
return details;
|
|
122
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Hostname label of a Studio: the resolved `appHost` when present, else the authored `slug`.
|
|
126
|
+
* undefined when a `$.resources` reference
|
|
127
|
+
*/
|
|
128
|
+
export function studioHost(params) {
|
|
129
|
+
const host = params.appHost ?? params.slug;
|
|
130
|
+
if (typeof host !== 'string' || host.length === 0 || host.startsWith('$.'))
|
|
131
|
+
return undefined;
|
|
132
|
+
return host;
|
|
133
|
+
}
|
|
134
|
+
export function studioUrl(host) {
|
|
135
|
+
return `https://${host}.${config.studioDomain}`;
|
|
136
|
+
}
|
|
123
137
|
export function arrayifyStudio(resource) {
|
|
124
138
|
const details = [formatLabeledValue('appHost', resource.slug)];
|
|
139
|
+
const host = studioHost(resource);
|
|
140
|
+
if (host)
|
|
141
|
+
details.push(formatLabeledValue('url', studioUrl(host)));
|
|
125
142
|
if (resource.project)
|
|
126
143
|
details.push(formatLabeledValue('project', niceId(resource.project)));
|
|
127
144
|
return details;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Where a function's dependency list came from. */
|
|
2
|
+
export type DependencySource = 'manifest' | 'autoinstall' | 'bundled' | 'none';
|
|
3
|
+
export type DependencyInfo = {
|
|
4
|
+
dependencySource: DependencySource;
|
|
5
|
+
dependencyCount: number;
|
|
6
|
+
/** Declared versions */
|
|
7
|
+
dependencies?: Record<string, string>;
|
|
8
|
+
/** Source files the Arc treeshaker parsed - autoinstall only */
|
|
9
|
+
parsedFileCount?: number;
|
|
10
|
+
};
|
|
11
|
+
/** The package.json Architect generates during autoinstall. */
|
|
12
|
+
export type AutoInstallManifest = {
|
|
13
|
+
dependencies?: Record<string, string>;
|
|
14
|
+
_parsed?: string[];
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Read and delete the manifest Architect generated during autoinstall.
|
|
18
|
+
* Arc moves it to `node_modules/_arc-autoinstall/` after the install.
|
|
19
|
+
* Has a timestamp, so it must be deleted to avoid hash changes on every deploy.
|
|
20
|
+
*/
|
|
21
|
+
export declare function takeAutoInstallManifest(installDir: string): Promise<AutoInstallManifest | undefined>;
|
|
22
|
+
/**
|
|
23
|
+
* Describe a function's dependencies from the manifest that declared them.
|
|
24
|
+
* The user's own package.json wins. Otherwise the Architect autoinstall manifest is used.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getDependencyInfo({ sourceDir, autoInstall, bundled, }: {
|
|
27
|
+
sourceDir: string;
|
|
28
|
+
autoInstall?: AutoInstallManifest;
|
|
29
|
+
bundled: boolean;
|
|
30
|
+
}): Promise<DependencyInfo>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readFile, rm } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Read and delete the manifest Architect generated during autoinstall.
|
|
5
|
+
* Arc moves it to `node_modules/_arc-autoinstall/` after the install.
|
|
6
|
+
* Has a timestamp, so it must be deleted to avoid hash changes on every deploy.
|
|
7
|
+
*/
|
|
8
|
+
export async function takeAutoInstallManifest(installDir) {
|
|
9
|
+
const file = path.join(installDir, 'node_modules', '_arc-autoinstall', 'package.json');
|
|
10
|
+
let manifest;
|
|
11
|
+
try {
|
|
12
|
+
manifest = JSON.parse(await readFile(file, 'utf8'));
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// no autoinstall happened, or the file is unreadable
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
await rm(file, { force: true });
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// best effort
|
|
22
|
+
}
|
|
23
|
+
return manifest;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Describe a function's dependencies from the manifest that declared them.
|
|
27
|
+
* The user's own package.json wins. Otherwise the Architect autoinstall manifest is used.
|
|
28
|
+
*/
|
|
29
|
+
export async function getDependencyInfo({ sourceDir, autoInstall, bundled, }) {
|
|
30
|
+
const declared = await readDeclaredDependencies(sourceDir);
|
|
31
|
+
if (declared && Object.keys(declared).length > 0) {
|
|
32
|
+
return {
|
|
33
|
+
dependencySource: 'manifest',
|
|
34
|
+
dependencyCount: Object.keys(declared).length,
|
|
35
|
+
dependencies: declared,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (autoInstall) {
|
|
39
|
+
const dependencies = autoInstall.dependencies ?? {};
|
|
40
|
+
return {
|
|
41
|
+
dependencySource: 'autoinstall',
|
|
42
|
+
dependencyCount: Object.keys(dependencies).length,
|
|
43
|
+
dependencies,
|
|
44
|
+
parsedFileCount: autoInstall._parsed?.length,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return { dependencySource: bundled ? 'bundled' : 'none', dependencyCount: 0 };
|
|
48
|
+
}
|
|
49
|
+
async function readDeclaredDependencies(dir) {
|
|
50
|
+
try {
|
|
51
|
+
const pkg = JSON.parse(await readFile(path.join(dir, 'package.json'), 'utf8'));
|
|
52
|
+
return pkg.dependencies;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import fs, { existsSync } from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { stat } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import AdmZip from 'adm-zip';
|
|
5
5
|
import { CONVERT_BYTES_TO_MB, MAX_ASSET_SIZE } from '../../constants.js';
|
|
6
|
+
import { getDependencyInfo, takeAutoInstallManifest, } from './dependency-info.js';
|
|
6
7
|
import { detectNativeModules, errorMessage } from './detect-native-modules.js';
|
|
7
8
|
import { isFolderLargerThan } from './is-folder-larger-than.js';
|
|
8
9
|
import { resolveResourceDependencies } from './resolve-dependencies.js';
|
|
@@ -16,6 +17,8 @@ export async function prepareAsset({ blueprintFileDir, resource, installer, }) {
|
|
|
16
17
|
let functionPath = resolvedFunctionPath;
|
|
17
18
|
let cleanup = async () => { };
|
|
18
19
|
let wasBundled = false;
|
|
20
|
+
let dependenciesInstalled = false;
|
|
21
|
+
let autoInstall;
|
|
19
22
|
const shouldTranspile = await shouldTranspileFunction(resource, functionPath);
|
|
20
23
|
if (shouldTranspile.transpile) {
|
|
21
24
|
try {
|
|
@@ -42,7 +45,8 @@ export async function prepareAsset({ blueprintFileDir, resource, installer, }) {
|
|
|
42
45
|
transpiled: shouldTranspile.transpile,
|
|
43
46
|
installer,
|
|
44
47
|
});
|
|
45
|
-
await
|
|
48
|
+
autoInstall = await takeAutoInstallManifest(functionPath);
|
|
49
|
+
dependenciesInstalled = true;
|
|
46
50
|
}
|
|
47
51
|
if (existsSync(path.join(functionPath, 'node_modules'))) {
|
|
48
52
|
const modulesPath = path.join(functionPath, 'node_modules');
|
|
@@ -72,6 +76,17 @@ export async function prepareAsset({ blueprintFileDir, resource, installer, }) {
|
|
|
72
76
|
fileExtension: 'zip',
|
|
73
77
|
assetParameter: 'src',
|
|
74
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
|
+
},
|
|
75
90
|
};
|
|
76
91
|
}
|
|
77
92
|
catch (err) {
|
|
@@ -98,19 +113,3 @@ export async function pathToZip(path) {
|
|
|
98
113
|
zip.addLocalFile(path, '', 'index.js');
|
|
99
114
|
return zip;
|
|
100
115
|
}
|
|
101
|
-
/**
|
|
102
|
-
* Remove file that contains the current date to prevent the hash from changing in the final asset.
|
|
103
|
-
* @param functionPath The path to the built function
|
|
104
|
-
*/
|
|
105
|
-
async function removeArcAutoInstallPackageJson(functionPath) {
|
|
106
|
-
const arcAutoInstallPackageJson = path.join(functionPath, 'node_modules', '_arc-autoinstall', 'package.json');
|
|
107
|
-
try {
|
|
108
|
-
const fileStat = await stat(arcAutoInstallPackageJson);
|
|
109
|
-
if (fileStat.isFile()) {
|
|
110
|
-
await rm(arcAutoInstallPackageJson);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
catch {
|
|
114
|
-
// ignore errors
|
|
115
|
-
}
|
|
116
|
-
}
|
|
@@ -5,12 +5,12 @@ 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 ?? '/';
|
|
@@ -112,6 +115,11 @@ export async function prepareStudioAsset({ blueprintFileDir, resource, }) {
|
|
|
112
115
|
outputBuffer: buffer,
|
|
113
116
|
fileExtension: 'tar.gz',
|
|
114
117
|
assetParameter: 'src',
|
|
118
|
+
metadata: {
|
|
119
|
+
sanityVersion: await getInstalledSanityVersion(studioPath),
|
|
120
|
+
mismatchedPackages,
|
|
121
|
+
assetBytes: buffer.length,
|
|
122
|
+
},
|
|
115
123
|
};
|
|
116
124
|
}
|
|
117
125
|
catch (error) {
|
|
@@ -139,3 +147,20 @@ function createSilentOutput() {
|
|
|
139
147
|
},
|
|
140
148
|
};
|
|
141
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
|
@@ -87,7 +87,22 @@ export interface StackMutation {
|
|
|
87
87
|
};
|
|
88
88
|
userMessage?: string;
|
|
89
89
|
preDeploy?: boolean;
|
|
90
|
+
metadata?: DeployMetadata;
|
|
90
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>;
|
|
91
106
|
/** @internal */
|
|
92
107
|
export interface BuildPayloadOptions {
|
|
93
108
|
data?: string;
|
|
@@ -302,6 +317,8 @@ export type AssetPrepResult = {
|
|
|
302
317
|
fileExtension: string;
|
|
303
318
|
assetParameter: string;
|
|
304
319
|
cleanup: () => Promise<void>;
|
|
320
|
+
/** Facts learned about the resource while preparing its asset. Sent as deploy metadata. */
|
|
321
|
+
metadata?: Record<string, unknown>;
|
|
305
322
|
} | {
|
|
306
323
|
success: false;
|
|
307
324
|
cleanup: () => Promise<void>;
|