@sanity/cli 8.25.0 → 8.27.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/README.md +3 -2
- package/dist/actions/build/shouldAutoUpdate.js +1 -26
- package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
- package/dist/actions/context/mcpEndpoint.js +165 -0
- package/dist/actions/context/mcpEndpoint.js.map +1 -0
- package/dist/actions/context/resolveOrganizationId.js +8 -1
- package/dist/actions/context/resolveOrganizationId.js.map +1 -1
- package/dist/actions/deploy/deployApp.js +10 -3
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +11 -4
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/init/initAction.js +3 -3
- package/dist/actions/init/initAction.js.map +1 -1
- package/dist/actions/init/plan/verifyCoupon.js +0 -1
- package/dist/actions/init/plan/verifyCoupon.js.map +1 -1
- package/dist/actions/init/scaffoldTemplate.js +1 -1
- package/dist/actions/init/scaffoldTemplate.js.map +1 -1
- package/dist/commands/api.js +10 -0
- package/dist/commands/api.js.map +1 -1
- package/dist/commands/backups/download.js +6 -0
- package/dist/commands/backups/download.js.map +1 -1
- package/dist/commands/context/create.js +8 -22
- package/dist/commands/context/create.js.map +1 -1
- package/dist/commands/context/delete.js +8 -1
- package/dist/commands/context/delete.js.map +1 -1
- package/dist/commands/context/issues/list.js +0 -5
- package/dist/commands/context/issues/list.js.map +1 -1
- package/dist/commands/context/list.js +6 -14
- package/dist/commands/context/list.js.map +1 -1
- package/dist/commands/context/mcp/create.js +152 -0
- package/dist/commands/context/mcp/create.js.map +1 -0
- package/dist/commands/context/mcp/delete.js +82 -0
- package/dist/commands/context/mcp/delete.js.map +1 -0
- package/dist/commands/context/mcp/get.js +42 -0
- package/dist/commands/context/mcp/get.js.map +1 -0
- package/dist/commands/context/mcp/list.js +87 -0
- package/dist/commands/context/mcp/list.js.map +1 -0
- package/dist/commands/context/mcp/status.js +98 -0
- package/dist/commands/context/mcp/status.js.map +1 -0
- package/dist/commands/context/mcp/update.js +225 -0
- package/dist/commands/context/mcp/update.js.map +1 -0
- package/dist/commands/context/query.js +6 -14
- package/dist/commands/context/query.js.map +1 -1
- package/dist/commands/context/update.js +12 -1
- package/dist/commands/context/update.js.map +1 -1
- package/dist/commands/datasets/create.js +6 -0
- package/dist/commands/datasets/create.js.map +1 -1
- package/dist/commands/datasets/embeddings/enable.js +6 -0
- package/dist/commands/datasets/embeddings/enable.js.map +1 -1
- package/dist/commands/datasets/import.js +6 -0
- package/dist/commands/datasets/import.js.map +1 -1
- package/dist/commands/deploy.js +7 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/documents/validate.js +6 -0
- package/dist/commands/documents/validate.js.map +1 -1
- package/dist/commands/exec.js +4 -2
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/init.js +13 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/manifest/extract.js +6 -0
- package/dist/commands/manifest/extract.js.map +1 -1
- package/dist/commands/media/create-aspect.js +7 -0
- package/dist/commands/media/create-aspect.js.map +1 -1
- package/dist/commands/migrations/run.js +6 -0
- package/dist/commands/migrations/run.js.map +1 -1
- package/dist/commands/organizations/create.js +6 -0
- package/dist/commands/organizations/create.js.map +1 -1
- package/dist/commands/organizations/update.js +6 -0
- package/dist/commands/organizations/update.js.map +1 -1
- package/dist/commands/schemas/delete.js +6 -0
- package/dist/commands/schemas/delete.js.map +1 -1
- package/dist/commands/schemas/deploy.js +6 -0
- package/dist/commands/schemas/deploy.js.map +1 -1
- package/dist/commands/schemas/extract.js +28 -3
- package/dist/commands/schemas/extract.js.map +1 -1
- package/dist/commands/schemas/list.js +6 -0
- package/dist/commands/schemas/list.js.map +1 -1
- package/dist/commands/schemas/validate.js +6 -0
- package/dist/commands/schemas/validate.js.map +1 -1
- package/dist/commands/tokens/rotate.js +6 -0
- package/dist/commands/tokens/rotate.js.map +1 -1
- package/dist/commands/typegen/generate.js +25 -1
- package/dist/commands/typegen/generate.js.map +1 -1
- package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +6 -0
- package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
- package/dist/generated/apiRoutes.js +22 -0
- package/dist/generated/apiRoutes.js.map +1 -1
- package/dist/hooks/prerun/setupTelemetry.js +2 -3
- package/dist/hooks/prerun/setupTelemetry.js.map +1 -1
- package/dist/prompts/promptForText.js +12 -0
- package/dist/prompts/promptForText.js.map +1 -0
- package/dist/services/context.js +174 -1
- package/dist/services/context.js.map +1 -1
- package/dist/services/telemetry.js +4 -2
- package/dist/services/telemetry.js.map +1 -1
- package/dist/telemetry/cli.telemetry.js +1 -1
- package/dist/telemetry/cli.telemetry.js.map +1 -1
- package/dist/telemetry/init.telemetry.js +1 -1
- package/dist/telemetry/init.telemetry.js.map +1 -1
- package/dist/telemetry/typegen.telemetry.js +12 -0
- package/dist/telemetry/typegen.telemetry.js.map +1 -0
- package/dist/util/parseArguments.js +12 -40
- package/dist/util/parseArguments.js.map +1 -1
- package/dist/util/sharedFlags.js.map +1 -1
- package/dist/util/telemetry/cliCommandIdentity.js +222 -0
- package/dist/util/telemetry/cliCommandIdentity.js.map +1 -0
- package/dist/util/telemetry/cliTelemetryFlags.js +186 -0
- package/dist/util/telemetry/cliTelemetryFlags.js.map +1 -0
- package/dist/util/telemetry/commandTelemetry.js +56 -11
- package/dist/util/telemetry/commandTelemetry.js.map +1 -1
- package/dist/util/telemetry/createTelemetryStore.js +13 -5
- package/dist/util/telemetry/createTelemetryStore.js.map +1 -1
- package/dist/util/telemetry/createTraceId.js +3 -3
- package/dist/util/telemetry/createTraceId.js.map +1 -1
- package/dist/util/telemetry/flushTelemetryFiles.js +14 -4
- package/dist/util/telemetry/flushTelemetryFiles.js.map +1 -1
- package/dist/util/telemetry/logger.js +1 -1
- package/dist/util/telemetry/logger.js.map +1 -1
- package/dist/util/telemetry/readNDJSON.js +1 -1
- package/dist/util/telemetry/readNDJSON.js.map +1 -1
- package/dist/util/telemetry/sanitizeTelemetryEvent.js +304 -0
- package/dist/util/telemetry/sanitizeTelemetryEvent.js.map +1 -0
- package/dist/util/telemetry/trace.js +4 -7
- package/dist/util/telemetry/trace.js.map +1 -1
- package/oclif.config.js +1 -1
- package/oclif.manifest.json +2380 -1526
- package/package.json +8 -11
package/README.md
CHANGED
|
@@ -4234,10 +4234,11 @@ Extract a JSON representation of a Sanity schema within a Studio context.
|
|
|
4234
4234
|
|
|
4235
4235
|
```
|
|
4236
4236
|
USAGE
|
|
4237
|
-
$ sanity schemas extract [--enforce-required-fields] [--force] [--format <format>] [--path
|
|
4238
|
-
[--watch-patterns <glob>...] [--workspace <name>]
|
|
4237
|
+
$ sanity schemas extract [--config-path <path>] [--enforce-required-fields] [--force] [--format <format>] [--path
|
|
4238
|
+
<value>] [--watch] [--watch-patterns <glob>...] [--workspace <name>]
|
|
4239
4239
|
|
|
4240
4240
|
FLAGS
|
|
4241
|
+
--config-path=<path> Path to the Sanity Studio config file
|
|
4241
4242
|
--enforce-required-fields Makes the schema generated treat fields marked as required as non-optional
|
|
4242
4243
|
--force Overwrite an existing schema file
|
|
4243
4244
|
--format=<format> [default: groq-type-nodes] Output format (currently only groq-type-nodes)
|
|
@@ -1,31 +1,11 @@
|
|
|
1
1
|
import { styleText } from 'node:util';
|
|
2
2
|
import { exitCodes } from '@sanity/cli-core';
|
|
3
|
-
import { isWorkbenchApp } from '@sanity/workbench-cli';
|
|
4
3
|
/**
|
|
5
4
|
* Owns the auto-update rules and returns plain facts, so each surface (build,
|
|
6
5
|
* dev, deploy warnings, dry-run checks) decides its own presentation.
|
|
7
6
|
*
|
|
8
7
|
* @internal
|
|
9
|
-
*/ export function resolveAutoUpdates(
|
|
10
|
-
const settings = resolveConfiguredAutoUpdates(sources);
|
|
11
|
-
// A workbench app takes `sanity` from the shell's shared runtime, so it has no
|
|
12
|
-
// version of its own to pin.
|
|
13
|
-
// TODO(SDK-1045): confirm the long-term story with the studio team.
|
|
14
|
-
if (settings.enabled && isWorkbenchApp(sources.cliConfig?.app)) {
|
|
15
|
-
// A config conflict still fails — it's a problem with the config itself.
|
|
16
|
-
return settings.issue?.type === 'conflicting-config' ? {
|
|
17
|
-
enabled: false,
|
|
18
|
-
issue: settings.issue
|
|
19
|
-
} : {
|
|
20
|
-
enabled: false,
|
|
21
|
-
issue: {
|
|
22
|
-
type: 'unsupported'
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
return settings;
|
|
27
|
-
}
|
|
28
|
-
function resolveConfiguredAutoUpdates({ cliConfig, flags }) {
|
|
8
|
+
*/ export function resolveAutoUpdates({ cliConfig, flags }) {
|
|
29
9
|
// Flags always take precedence over config
|
|
30
10
|
if ('auto-updates' in flags) {
|
|
31
11
|
const enabled = Boolean(flags['auto-updates']);
|
|
@@ -80,10 +60,6 @@ function resolveConfiguredAutoUpdates({ cliConfig, flags }) {
|
|
|
80
60
|
{
|
|
81
61
|
return `The ${issue.flag} flag is deprecated for deploy and build commands. Set the autoUpdates option in the deployment section of sanity.cli.ts or sanity.cli.js instead.`;
|
|
82
62
|
}
|
|
83
|
-
case 'unsupported':
|
|
84
|
-
{
|
|
85
|
-
return "Auto-updates aren't supported yet — using the installed package versions";
|
|
86
|
-
}
|
|
87
63
|
}
|
|
88
64
|
}
|
|
89
65
|
/**
|
|
@@ -123,7 +99,6 @@ function resolveConfiguredAutoUpdates({ cliConfig, flags }) {
|
|
|
123
99
|
break;
|
|
124
100
|
}
|
|
125
101
|
case 'deprecated-flag':
|
|
126
|
-
case 'unsupported':
|
|
127
102
|
{
|
|
128
103
|
output.warn(getAutoUpdateIssueMessage(issue));
|
|
129
104
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/shouldAutoUpdate.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, exitCodes, type Output} from '@sanity/cli-core'\
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/build/shouldAutoUpdate.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, exitCodes, type Output} from '@sanity/cli-core'\n\nimport {type DeployFlags} from '../deploy/types.js'\nimport {type DevFlags} from '../dev/types.js'\nimport {type BuildFlags} from './types.js'\n\ninterface AutoUpdateSources {\n cliConfig: CliConfig\n flags: BuildFlags | DeployFlags | DevFlags\n}\n\n/**\n * The single auto-update configuration problem to surface, if any.\n * Flag usage takes precedence over config problems: when the deprecated flag\n * is passed, config is not consulted, so config issues are not reported.\n */\ntype AutoUpdateIssue =\n | {flag: '--auto-updates' | '--no-auto-updates'; type: 'deprecated-flag'}\n | {type: 'conflicting-config'}\n | {type: 'deprecated-config'}\n\nexport interface AutoUpdateSettings {\n enabled: boolean\n issue: AutoUpdateIssue | null\n}\n\n/**\n * Owns the auto-update rules and returns plain facts, so each surface (build,\n * dev, deploy warnings, dry-run checks) decides its own presentation.\n *\n * @internal\n */\nexport function resolveAutoUpdates({cliConfig, flags}: AutoUpdateSources): AutoUpdateSettings {\n // Flags always take precedence over config\n if ('auto-updates' in flags) {\n const enabled = Boolean(flags['auto-updates'])\n return {\n enabled,\n issue: {flag: enabled ? '--auto-updates' : '--no-auto-updates', type: 'deprecated-flag'},\n }\n }\n\n const hasOldConfig = cliConfig && 'autoUpdates' in cliConfig\n\n const hasNewConfig =\n cliConfig &&\n 'deployment' in cliConfig &&\n cliConfig.deployment &&\n 'autoUpdates' in cliConfig.deployment\n\n if (hasNewConfig) {\n return {\n enabled: Boolean(cliConfig?.deployment?.autoUpdates),\n issue: hasOldConfig ? {type: 'conflicting-config'} : null,\n }\n }\n\n if (hasOldConfig) {\n return {enabled: Boolean(cliConfig?.autoUpdates), issue: {type: 'deprecated-config'}}\n }\n\n return {enabled: false, issue: null}\n}\n\n/**\n * The user-facing message for an auto-update configuration problem.\n * Shared by every surface that reports the issue (deploy warnings, dry-run\n * checks) so the wording has one home.\n *\n * @internal\n */\nexport function getAutoUpdateIssueMessage(issue: AutoUpdateIssue): string {\n switch (issue.type) {\n case 'conflicting-config': {\n return 'Found both `autoUpdates` (deprecated) and `deployment.autoUpdates` in sanity.cli.js/.ts. Please remove the deprecated top level `autoUpdates` config.'\n }\n case 'deprecated-config': {\n return 'The autoUpdates config has moved to deployment.autoUpdates.'\n }\n case 'deprecated-flag': {\n return `The ${issue.flag} flag is deprecated for deploy and build commands. Set the autoUpdates option in the deployment section of sanity.cli.ts or sanity.cli.js instead.`\n }\n }\n}\n\n/**\n * The styled before/after edit that migrates the deprecated top-level\n * `autoUpdates` to `deployment.autoUpdates`. Lives here so every surface that\n * reports the deprecated config (deploy warnings, dry-run checks) shows the\n * same migration hint.\n *\n * @internal\n */\nexport function getAutoUpdateMigrationHint(currentValue: unknown): string {\n return `Please update sanity.cli.ts or sanity.cli.js and make the following change:\n ${styleText('red', `- autoUpdates: ${currentValue},`)}\n ${styleText('green', `+ deployment: {autoUpdates: ${currentValue}}`)}\n`\n}\n\n/**\n * Resolves the auto-update setting and prints any configuration problem.\n * @remarks Throws an error if both the old and new auto update config are used; throws a warning if the old config is used, or if the auto updates flags are used.\n * @internal\n */\nexport function shouldAutoUpdate({\n cliConfig,\n flags,\n output,\n}: AutoUpdateSources & {output: Output}): boolean {\n const {enabled, issue} = resolveAutoUpdates({cliConfig, flags})\n\n switch (issue?.type) {\n case 'conflicting-config': {\n output.error(getAutoUpdateIssueMessage(issue), {exit: exitCodes.RUNTIME_ERROR})\n break\n }\n case 'deprecated-config': {\n output.warn(getAutoUpdateIssueMessage(issue))\n output.warn(getAutoUpdateMigrationHint(cliConfig.autoUpdates))\n break\n }\n case 'deprecated-flag': {\n output.warn(getAutoUpdateIssueMessage(issue))\n break\n }\n default: {\n break\n }\n }\n\n return enabled\n}\n"],"names":["styleText","exitCodes","resolveAutoUpdates","cliConfig","flags","enabled","Boolean","issue","flag","type","hasOldConfig","hasNewConfig","deployment","autoUpdates","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","currentValue","shouldAutoUpdate","output","error","exit","RUNTIME_ERROR","warn"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAwBC,SAAS,QAAoB,mBAAkB;AA0BvE;;;;;CAKC,GACD,OAAO,SAASC,mBAAmB,EAACC,SAAS,EAAEC,KAAK,EAAoB;IACtE,2CAA2C;IAC3C,IAAI,kBAAkBA,OAAO;QAC3B,MAAMC,UAAUC,QAAQF,KAAK,CAAC,eAAe;QAC7C,OAAO;YACLC;YACAE,OAAO;gBAACC,MAAMH,UAAU,mBAAmB;gBAAqBI,MAAM;YAAiB;QACzF;IACF;IAEA,MAAMC,eAAeP,aAAa,iBAAiBA;IAEnD,MAAMQ,eACJR,aACA,gBAAgBA,aAChBA,UAAUS,UAAU,IACpB,iBAAiBT,UAAUS,UAAU;IAEvC,IAAID,cAAc;QAChB,OAAO;YACLN,SAASC,QAAQH,WAAWS,YAAYC;YACxCN,OAAOG,eAAe;gBAACD,MAAM;YAAoB,IAAI;QACvD;IACF;IAEA,IAAIC,cAAc;QAChB,OAAO;YAACL,SAASC,QAAQH,WAAWU;YAAcN,OAAO;gBAACE,MAAM;YAAmB;QAAC;IACtF;IAEA,OAAO;QAACJ,SAAS;QAAOE,OAAO;IAAI;AACrC;AAEA;;;;;;CAMC,GACD,OAAO,SAASO,0BAA0BP,KAAsB;IAC9D,OAAQA,MAAME,IAAI;QAChB,KAAK;YAAsB;gBACzB,OAAO;YACT;QACA,KAAK;YAAqB;gBACxB,OAAO;YACT;QACA,KAAK;YAAmB;gBACtB,OAAO,CAAC,IAAI,EAAEF,MAAMC,IAAI,CAAC,kJAAkJ,CAAC;YAC9K;IACF;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,SAASO,2BAA2BC,YAAqB;IAC9D,OAAO,CAAC;EACR,EAAEhB,UAAU,OAAO,CAAC,gBAAgB,EAAEgB,aAAa,CAAC,CAAC,EAAE;EACvD,EAAEhB,UAAU,SAAS,CAAC,6BAA6B,EAAEgB,aAAa,CAAC,CAAC,EAAE;AACxE,CAAC;AACD;AAEA;;;;CAIC,GACD,OAAO,SAASC,iBAAiB,EAC/Bd,SAAS,EACTC,KAAK,EACLc,MAAM,EAC+B;IACrC,MAAM,EAACb,OAAO,EAAEE,KAAK,EAAC,GAAGL,mBAAmB;QAACC;QAAWC;IAAK;IAE7D,OAAQG,OAAOE;QACb,KAAK;YAAsB;gBACzBS,OAAOC,KAAK,CAACL,0BAA0BP,QAAQ;oBAACa,MAAMnB,UAAUoB,aAAa;gBAAA;gBAC7E;YACF;QACA,KAAK;YAAqB;gBACxBH,OAAOI,IAAI,CAACR,0BAA0BP;gBACtCW,OAAOI,IAAI,CAACP,2BAA2BZ,UAAUU,WAAW;gBAC5D;YACF;QACA,KAAK;YAAmB;gBACtBK,OAAOI,IAAI,CAACR,0BAA0BP;gBACtC;YACF;QACA;YAAS;gBACP;YACF;IACF;IAEA,OAAOF;AACT"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { CLIError } from '@oclif/core/errors';
|
|
3
|
+
import { exitCodes } from '@sanity/cli-core';
|
|
4
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
5
|
+
import { getMcpEndpoint } from '../../services/context.js';
|
|
6
|
+
import { getOrganizationFlag } from '../../util/sharedFlags.js';
|
|
7
|
+
import { formatKeyValue } from '../debug/output.js';
|
|
8
|
+
/**
|
|
9
|
+
* The `<name>` argument of commands that act on an existing endpoint
|
|
10
|
+
*/ export const mcpEndpointNameArg = Args.string({
|
|
11
|
+
description: 'MCP endpoint name, as in its URL',
|
|
12
|
+
parse: parseEndpointName,
|
|
13
|
+
required: true
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* An argument `parse` that trims an endpoint name and rejects an empty one
|
|
17
|
+
*/ export async function parseEndpointName(input) {
|
|
18
|
+
const trimmed = input.trim();
|
|
19
|
+
if (trimmed === '') throw new Error('The MCP endpoint name cannot be empty');
|
|
20
|
+
return trimmed;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get an endpoint by name or ID, failing the command when the lookup fails or finds nothing
|
|
24
|
+
*/ export async function findMcpEndpoint(organizationId, nameOrId) {
|
|
25
|
+
let endpoint;
|
|
26
|
+
try {
|
|
27
|
+
endpoint = await getMcpEndpoint(organizationId, nameOrId);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
throw new CLIError(`Failed to get MCP endpoint: ${getErrorMessage(error)}`, {
|
|
30
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (!endpoint) {
|
|
34
|
+
throw new CLIError(`MCP endpoint "${nameOrId}" not found`, {
|
|
35
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return endpoint;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The `--organization` flag of commands that act on an existing endpoint
|
|
42
|
+
*/ export const mcpEndpointOrganizationFlag = getOrganizationFlag({
|
|
43
|
+
description: 'Organization the MCP endpoint belongs to',
|
|
44
|
+
semantics: 'override'
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* A flag `parse` that trims the value and rejects an empty one
|
|
48
|
+
*/ export function parseNonEmpty(flag) {
|
|
49
|
+
return async (input)=>{
|
|
50
|
+
const trimmed = input.trim();
|
|
51
|
+
if (trimmed === '') {
|
|
52
|
+
throw new Error(`\`--${flag}\` cannot be empty if provided`);
|
|
53
|
+
}
|
|
54
|
+
return trimmed;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The API names a dataset source `<projectId>.<datasetName>`; the project comes from
|
|
59
|
+
* `--project` or the CLI configuration.
|
|
60
|
+
*/ export function datasetSourceId(dataset, projectId) {
|
|
61
|
+
if (dataset === undefined) return undefined;
|
|
62
|
+
if (!projectId) {
|
|
63
|
+
throw new CLIError('Pass `--project` with `--dataset`, or run the command in a Sanity project directory.', {
|
|
64
|
+
exit: exitCodes.USAGE_ERROR
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return `${projectId}.${dataset}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Apply source changes to an endpoint's current sources, or to none when creating one. The dataset
|
|
71
|
+
* keeps its settings until it is switched for another one; `dataset: null`
|
|
72
|
+
* removes it. Sources are rebuilt from their known fields, since the stored
|
|
73
|
+
* configuration may carry more. `notes` names the changes that were already in
|
|
74
|
+
* place, which leave the sources as they were.
|
|
75
|
+
*/ export function editSources(current, changes) {
|
|
76
|
+
const notes = [];
|
|
77
|
+
const knowledgeBaseIds = current.filter((source)=>source.type === 'knowledge-base').map((source)=>source.id);
|
|
78
|
+
for (const id of new Set(changes.addKnowledgeBases)){
|
|
79
|
+
if (knowledgeBaseIds.includes(id)) {
|
|
80
|
+
notes.push(`Knowledge base "${id}" is already a source`);
|
|
81
|
+
} else {
|
|
82
|
+
knowledgeBaseIds.push(id);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (const id of new Set(changes.removeKnowledgeBases)){
|
|
86
|
+
if (!knowledgeBaseIds.includes(id)) notes.push(`Knowledge base "${id}" is not a source`);
|
|
87
|
+
}
|
|
88
|
+
const sources = knowledgeBaseIds.filter((id)=>!changes.removeKnowledgeBases.includes(id)).map((id)=>({
|
|
89
|
+
id,
|
|
90
|
+
type: 'knowledge-base'
|
|
91
|
+
}));
|
|
92
|
+
const dataset = findDatasetSource(current);
|
|
93
|
+
if (changes.dataset === null && !dataset) notes.push('The endpoint has no dataset');
|
|
94
|
+
const datasetId = changes.dataset === undefined ? dataset?.id : changes.dataset;
|
|
95
|
+
if (datasetId) {
|
|
96
|
+
const kept = dataset?.id === datasetId ? {
|
|
97
|
+
perspective: dataset.perspective,
|
|
98
|
+
semanticSearch: dataset.semanticSearch,
|
|
99
|
+
workspace: dataset.workspace
|
|
100
|
+
} : {};
|
|
101
|
+
sources.push({
|
|
102
|
+
id: datasetId,
|
|
103
|
+
type: 'dataset',
|
|
104
|
+
...kept,
|
|
105
|
+
...changes.settings
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
notes,
|
|
110
|
+
sources
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function findDatasetSource(sources) {
|
|
114
|
+
return sources.find((source)=>source.type === 'dataset');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Key-value lines describing an endpoint, for `get`, `create` and `update` output
|
|
118
|
+
*/ export function formatMcpEndpoint(endpoint) {
|
|
119
|
+
const padTo = 15 // "Knowledge bases" and "Semantic search" are the longest keys
|
|
120
|
+
;
|
|
121
|
+
const knowledgeBaseIds = endpoint.sources.filter((source)=>source.type === 'knowledge-base').map((source)=>source.id);
|
|
122
|
+
const dataset = findDatasetSource(endpoint.sources);
|
|
123
|
+
const lines = [
|
|
124
|
+
formatKeyValue('ID', endpoint.id, {
|
|
125
|
+
padTo
|
|
126
|
+
}),
|
|
127
|
+
formatKeyValue('Name', endpoint.name, {
|
|
128
|
+
padTo
|
|
129
|
+
}),
|
|
130
|
+
formatKeyValue('Title', endpoint.title, {
|
|
131
|
+
padTo
|
|
132
|
+
}),
|
|
133
|
+
formatKeyValue('URL', endpoint.url, {
|
|
134
|
+
padTo
|
|
135
|
+
}),
|
|
136
|
+
formatKeyValue('Knowledge bases', knowledgeBaseIds.join(', ') || '-', {
|
|
137
|
+
padTo
|
|
138
|
+
}),
|
|
139
|
+
formatKeyValue('Dataset', dataset?.id ?? '-', {
|
|
140
|
+
padTo
|
|
141
|
+
})
|
|
142
|
+
];
|
|
143
|
+
if (dataset) {
|
|
144
|
+
lines.push(formatKeyValue('Workspace', dataset.workspace ?? '-', {
|
|
145
|
+
padTo
|
|
146
|
+
}), formatKeyValue('Perspective', dataset.perspective ?? '-', {
|
|
147
|
+
padTo
|
|
148
|
+
}), formatKeyValue('Semantic search', formatSemanticSearch(dataset.semanticSearch), {
|
|
149
|
+
padTo
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
lines.push(formatKeyValue('Instructions', endpoint.instructions ?? '-', {
|
|
153
|
+
padTo
|
|
154
|
+
}), formatKeyValue('GROQ filter', endpoint.groqFilter ?? '-', {
|
|
155
|
+
padTo
|
|
156
|
+
}));
|
|
157
|
+
return lines;
|
|
158
|
+
}
|
|
159
|
+
function formatSemanticSearch(semanticSearch) {
|
|
160
|
+
if (semanticSearch === true) return 'on';
|
|
161
|
+
if (semanticSearch === false) return 'off';
|
|
162
|
+
return '-';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=mcpEndpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/context/mcpEndpoint.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {type Context} from '@sanity/client'\n\nimport {getMcpEndpoint} from '../../services/context.js'\nimport {getOrganizationFlag} from '../../util/sharedFlags.js'\nimport {formatKeyValue} from '../debug/output.js'\n\ntype McpSource = Context.McpEndpoint['sources'][number]\ntype DatasetSource = Extract<McpSource, {type: 'dataset'}>\ntype McpSourceInput = Context.CreateMcpEndpointParams['sources'][number]\nexport type DatasetSettings = Partial<\n Pick<DatasetSource, 'perspective' | 'semanticSearch' | 'workspace'>\n>\n\n/**\n * The `<name>` argument of commands that act on an existing endpoint\n */\nexport const mcpEndpointNameArg = Args.string({\n description: 'MCP endpoint name, as in its URL',\n parse: parseEndpointName,\n required: true,\n})\n\n/**\n * An argument `parse` that trims an endpoint name and rejects an empty one\n */\nexport async function parseEndpointName(input: string): Promise<string> {\n const trimmed = input.trim()\n if (trimmed === '') throw new Error('The MCP endpoint name cannot be empty')\n return trimmed\n}\n\n/**\n * Get an endpoint by name or ID, failing the command when the lookup fails or finds nothing\n */\nexport async function findMcpEndpoint(\n organizationId: string,\n nameOrId: string,\n): Promise<Context.McpEndpoint> {\n let endpoint\n try {\n endpoint = await getMcpEndpoint(organizationId, nameOrId)\n } catch (error) {\n throw new CLIError(`Failed to get MCP endpoint: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n if (!endpoint) {\n throw new CLIError(`MCP endpoint \"${nameOrId}\" not found`, {exit: exitCodes.RUNTIME_ERROR})\n }\n return endpoint\n}\n\n/**\n * The `--organization` flag of commands that act on an existing endpoint\n */\nexport const mcpEndpointOrganizationFlag = getOrganizationFlag({\n description: 'Organization the MCP endpoint belongs to',\n semantics: 'override',\n})\n\n/**\n * A flag `parse` that trims the value and rejects an empty one\n */\nexport function parseNonEmpty(flag: string): (input: string) => Promise<string> {\n return async (input) => {\n const trimmed = input.trim()\n if (trimmed === '') {\n throw new Error(`\\`--${flag}\\` cannot be empty if provided`)\n }\n return trimmed\n }\n}\n\n/**\n * The API names a dataset source `<projectId>.<datasetName>`; the project comes from\n * `--project` or the CLI configuration.\n */\nexport function datasetSourceId(\n dataset: string | undefined,\n projectId: string | undefined,\n): string | undefined {\n if (dataset === undefined) return undefined\n if (!projectId) {\n throw new CLIError(\n 'Pass `--project` with `--dataset`, or run the command in a Sanity project directory.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n return `${projectId}.${dataset}`\n}\n\n/**\n * Apply source changes to an endpoint's current sources, or to none when creating one. The dataset\n * keeps its settings until it is switched for another one; `dataset: null`\n * removes it. Sources are rebuilt from their known fields, since the stored\n * configuration may carry more. `notes` names the changes that were already in\n * place, which leave the sources as they were.\n */\nexport function editSources(\n current: McpSource[],\n changes: {\n addKnowledgeBases: string[]\n dataset: string | null | undefined\n removeKnowledgeBases: string[]\n settings: DatasetSettings\n },\n): {notes: string[]; sources: McpSourceInput[]} {\n const notes: string[] = []\n const knowledgeBaseIds = current\n .filter((source) => source.type === 'knowledge-base')\n .map((source) => source.id)\n\n for (const id of new Set(changes.addKnowledgeBases)) {\n if (knowledgeBaseIds.includes(id)) {\n notes.push(`Knowledge base \"${id}\" is already a source`)\n } else {\n knowledgeBaseIds.push(id)\n }\n }\n for (const id of new Set(changes.removeKnowledgeBases)) {\n if (!knowledgeBaseIds.includes(id)) notes.push(`Knowledge base \"${id}\" is not a source`)\n }\n const sources: McpSourceInput[] = knowledgeBaseIds\n .filter((id) => !changes.removeKnowledgeBases.includes(id))\n .map((id) => ({id, type: 'knowledge-base'}))\n\n const dataset = findDatasetSource(current)\n if (changes.dataset === null && !dataset) notes.push('The endpoint has no dataset')\n const datasetId = changes.dataset === undefined ? dataset?.id : changes.dataset\n if (datasetId) {\n const kept =\n dataset?.id === datasetId\n ? {\n perspective: dataset.perspective,\n semanticSearch: dataset.semanticSearch,\n workspace: dataset.workspace,\n }\n : {}\n sources.push({id: datasetId, type: 'dataset', ...kept, ...changes.settings})\n }\n\n return {notes, sources}\n}\n\nfunction findDatasetSource(sources: McpSource[]): DatasetSource | undefined {\n return sources.find((source): source is DatasetSource => source.type === 'dataset')\n}\n\n/**\n * Key-value lines describing an endpoint, for `get`, `create` and `update` output\n */\nexport function formatMcpEndpoint(endpoint: Context.McpEndpoint): string[] {\n const padTo = 15 // \"Knowledge bases\" and \"Semantic search\" are the longest keys\n const knowledgeBaseIds = endpoint.sources\n .filter((source) => source.type === 'knowledge-base')\n .map((source) => source.id)\n const dataset = findDatasetSource(endpoint.sources)\n\n const lines = [\n formatKeyValue('ID', endpoint.id, {padTo}),\n formatKeyValue('Name', endpoint.name, {padTo}),\n formatKeyValue('Title', endpoint.title, {padTo}),\n formatKeyValue('URL', endpoint.url, {padTo}),\n formatKeyValue('Knowledge bases', knowledgeBaseIds.join(', ') || '-', {padTo}),\n formatKeyValue('Dataset', dataset?.id ?? '-', {padTo}),\n ]\n if (dataset) {\n lines.push(\n formatKeyValue('Workspace', dataset.workspace ?? '-', {padTo}),\n formatKeyValue('Perspective', dataset.perspective ?? '-', {padTo}),\n formatKeyValue('Semantic search', formatSemanticSearch(dataset.semanticSearch), {padTo}),\n )\n }\n lines.push(\n formatKeyValue('Instructions', endpoint.instructions ?? '-', {padTo}),\n formatKeyValue('GROQ filter', endpoint.groqFilter ?? '-', {padTo}),\n )\n return lines\n}\n\nfunction formatSemanticSearch(semanticSearch: boolean | null | undefined): string {\n if (semanticSearch === true) return 'on'\n if (semanticSearch === false) return 'off'\n return '-'\n}\n"],"names":["Args","CLIError","exitCodes","getErrorMessage","getMcpEndpoint","getOrganizationFlag","formatKeyValue","mcpEndpointNameArg","string","description","parse","parseEndpointName","required","input","trimmed","trim","Error","findMcpEndpoint","organizationId","nameOrId","endpoint","error","exit","RUNTIME_ERROR","mcpEndpointOrganizationFlag","semantics","parseNonEmpty","flag","datasetSourceId","dataset","projectId","undefined","USAGE_ERROR","editSources","current","changes","notes","knowledgeBaseIds","filter","source","type","map","id","Set","addKnowledgeBases","includes","push","removeKnowledgeBases","sources","findDatasetSource","datasetId","kept","perspective","semanticSearch","workspace","settings","find","formatMcpEndpoint","padTo","lines","name","title","url","join","formatSemanticSearch","instructions","groqFilter"],"mappings":"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"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { CLIError } from '@oclif/core/errors';
|
|
2
|
+
import { exitCodes } from '@sanity/cli-core';
|
|
1
3
|
import { promptForOrganization } from '../../prompts/promptForOrganization.js';
|
|
2
|
-
/** The organization could not be determined and prompting is not possible. */ export class MissingOrganizationError extends
|
|
4
|
+
/** The organization could not be determined and prompting is not possible. */ export class MissingOrganizationError extends CLIError {
|
|
5
|
+
constructor(message){
|
|
6
|
+
super(message, {
|
|
7
|
+
exit: exitCodes.USAGE_ERROR
|
|
8
|
+
});
|
|
9
|
+
}
|
|
3
10
|
}
|
|
4
11
|
/**
|
|
5
12
|
* Resolve the organization to operate on: the `--organization` flag wins,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/context/resolveOrganizationId.ts"],"sourcesContent":["import {promptForOrganization} from '../../prompts/promptForOrganization.js'\n\n/** The organization could not be determined and prompting is not possible. */\nexport class MissingOrganizationError extends
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/context/resolveOrganizationId.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\n\nimport {promptForOrganization} from '../../prompts/promptForOrganization.js'\n\n/** The organization could not be determined and prompting is not possible. */\nexport class MissingOrganizationError extends CLIError {\n constructor(message: string) {\n super(message, {exit: exitCodes.USAGE_ERROR})\n }\n}\n\n/**\n * Resolve the organization to operate on: the `--organization` flag wins,\n * then the CLI config's `app.organizationId`, then an interactive prompt.\n */\nexport async function resolveOrganizationId(options: {\n configuredOrganizationId: string | undefined\n flagOrganizationId: string | undefined\n unattended: boolean\n}): Promise<string> {\n const {configuredOrganizationId, flagOrganizationId, unattended} = options\n\n if (flagOrganizationId) return flagOrganizationId\n if (configuredOrganizationId) return configuredOrganizationId\n\n if (unattended) {\n throw new MissingOrganizationError(\n 'Organization ID is required. Provide it with the --organization flag.',\n )\n }\n\n return promptForOrganization()\n}\n"],"names":["CLIError","exitCodes","promptForOrganization","MissingOrganizationError","message","exit","USAGE_ERROR","resolveOrganizationId","options","configuredOrganizationId","flagOrganizationId","unattended"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,qBAAoB;AAC3C,SAAQC,SAAS,QAAO,mBAAkB;AAE1C,SAAQC,qBAAqB,QAAO,yCAAwC;AAE5E,4EAA4E,GAC5E,OAAO,MAAMC,iCAAiCH;IAC5C,YAAYI,OAAe,CAAE;QAC3B,KAAK,CAACA,SAAS;YAACC,MAAMJ,UAAUK,WAAW;QAAA;IAC7C;AACF;AAEA;;;CAGC,GACD,OAAO,eAAeC,sBAAsBC,OAI3C;IACC,MAAM,EAACC,wBAAwB,EAAEC,kBAAkB,EAAEC,UAAU,EAAC,GAAGH;IAEnE,IAAIE,oBAAoB,OAAOA;IAC/B,IAAID,0BAA0B,OAAOA;IAErC,IAAIE,YAAY;QACd,MAAM,IAAIR,yBACR;IAEJ;IAEA,OAAOD;AACT"}
|
|
@@ -7,7 +7,7 @@ import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
|
7
7
|
import { getCoreAppUrl } from '@sanity/cli-core/util';
|
|
8
8
|
import { confirm, spinner } from '@sanity/cli-core/ux';
|
|
9
9
|
import { resolveAppEntry } from '@sanity/workbench-cli/build';
|
|
10
|
-
import { createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, resolveInstallationId, resolveWorkbenchConfig, summarizeConfig, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
|
|
10
|
+
import { createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, resolveInstallationId, resolveWorkbenchConfig, selectWorkbenchAppId, summarizeConfig, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
|
|
11
11
|
import { c as createTar } from 'tar';
|
|
12
12
|
import { createDeployment, updateUserApplication } from '../../services/userApplications.js';
|
|
13
13
|
import { getAppId } from '../../util/appId.js';
|
|
@@ -105,6 +105,7 @@ export function deployApp(options) {
|
|
|
105
105
|
let application = null;
|
|
106
106
|
let appCreated = false;
|
|
107
107
|
let workbenchApp;
|
|
108
|
+
let targetAppId = appId;
|
|
108
109
|
if (flags.external) {
|
|
109
110
|
reporter.report({
|
|
110
111
|
message: EXTERNAL_APP_NOT_SUPPORTED,
|
|
@@ -112,8 +113,14 @@ export function deployApp(options) {
|
|
|
112
113
|
status: 'fail'
|
|
113
114
|
});
|
|
114
115
|
} else if (deployApplication && workbench) {
|
|
115
|
-
|
|
116
|
+
targetAppId = await selectWorkbenchAppId({
|
|
116
117
|
appId,
|
|
118
|
+
flags,
|
|
119
|
+
organizationId,
|
|
120
|
+
type: 'coreApp'
|
|
121
|
+
});
|
|
122
|
+
workbenchApp = (await checkAppTarget(reporter, {
|
|
123
|
+
appId: targetAppId,
|
|
117
124
|
hasAppView,
|
|
118
125
|
isWorkbenchApp: true,
|
|
119
126
|
organizationId,
|
|
@@ -141,7 +148,7 @@ export function deployApp(options) {
|
|
|
141
148
|
const appIcon = !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined;
|
|
142
149
|
// Create the app before the build so the bundle carries its real id. A
|
|
143
150
|
// redeploy already has it from `deployment.appId`; a dry run skips creation.
|
|
144
|
-
let applicationId =
|
|
151
|
+
let applicationId = targetAppId;
|
|
145
152
|
let applicationCreated = false;
|
|
146
153
|
let rollbackApp;
|
|
147
154
|
if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {\n type CoreAppManifest,\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '@sanity/cli-build/_internal/manifest'\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {resolveAppEntry} from '@sanity/workbench-cli/build'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n getWorkbenchUrl,\n resolveInstallationId,\n resolveWorkbenchConfig,\n summarizeConfig,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {c as createTar} from 'tar'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {runStep} from '../../util/checks.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {pluralize} from '../../util/pluralize.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {\n applyAspectSync,\n type AspectSyncPlan,\n planAspectSync,\n} from '../media/aspectSync/syncAspects.js'\nimport {checkBlueprintManaged} from './blueprintManaged.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n // A config (the Media Library) is not an app — it resolves through its own\n // brand and persists to the org's installation instead of hosting an application.\n const config = resolveWorkbenchConfig(cliConfig)\n const dryRun = !!flags['dry-run']\n\n const deployConfigOnly = !!config\n const deployApplication = !config && (!workbench || workbench.hasInterfaces)\n const hasAppView = resolveAppEntry(cliConfig.app) !== undefined\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n // A config with no fields would overwrite the org's live config with an empty\n // snapshot, so block it here — same \"nothing to deploy\" gate an app gets.\n if (config && config.fields.length === 0) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Nothing to deploy: the media library config declares no fields.',\n solution: 'Add at least one field to the media library config',\n status: 'fail',\n })\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deployConfigOnly) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n await checkBlueprintManaged(reporter, {kind: 'coreApp', projectRootDir: workDir})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n let workbenchApp: object | undefined\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId,\n hasAppView,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n const created = await createCoreApp({\n isSingleton: workbench.isSingleton,\n name: workbench.name,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n })\n workbenchApp = created.application\n applicationId = created.application.id\n rollbackApp = created.rollback\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n const built = await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n // A federated build has already read its manifest; anything else verifies the directory.\n const mfManifest =\n built?.mfManifest ??\n (await verifyOutputDir({\n isWorkbenchApp: workbench !== null || config !== null,\n reporter,\n sourceDir,\n }))\n\n // Workbench apps and configs ship a federation remote and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench && !config) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let configSummary: string | undefined\n const configAppType = config?.appType\n if (deployConfigOnly && organizationId && config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n configSummary = summarizeConfig(config)\n reporter.report(\n installationId\n ? {message: configSummary, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n // Plan the aspect-document sync in both modes, so the report — dry-run and\n // real — shows what the sync will write and, prominently, what it will\n // delete, before anything mutates. Gated on a resolved installation: when\n // that check failed, a real run already exited and a dry run has reported\n // the config as undeployable.\n let aspectSyncPlan: AspectSyncPlan | undefined\n // Gated on the `appType` discriminator, not the mere presence of a config:\n // `ConfigSchema` is a union built to grow, and a future config type must\n // not inherit the media-library aspect sync — and its deletions — by\n // default.\n if (configAppType === 'media-library' && organizationId && config && installationId) {\n // runStep so an unexpected throw (network, API) becomes a fail check:\n // a real run exits, a dry run records it and keeps reporting.\n const planned = await runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Planning the aspect-document sync failed: ${getErrorMessage(err)}`,\n name: 'aspect sync plan',\n work: () =>\n planAspectSync({\n fields: config.fields,\n mediaLibraryId: flags['media-library-id'],\n organizationId,\n workDir,\n }),\n })\n if (planned && 'failure' in planned) {\n reporter.report({\n exitCode: planned.failure.exitCode,\n message: planned.failure.message,\n solution: planned.failure.solution,\n status: 'fail',\n })\n } else if (planned) {\n aspectSyncPlan = planned.plan\n reportAspectSyncPlan(reporter, aspectSyncPlan)\n }\n }\n\n const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n type: 'coreApp',\n version,\n ...toWorkbenchPayload(workbench, {config: configSummary, interfaces, title: appTitle}),\n ...(configSummary ? {config: configSummary} : {}),\n ...(aspectSyncPlan\n ? {\n aspectSync: {\n deleteIds: aspectSyncPlan.staleIds,\n mediaLibraryId: aspectSyncPlan.mediaLibraryId,\n upsertIds: aspectSyncPlan.documents.map((document) => document._id),\n },\n }\n : {}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // Deleting stored definitions is the destructive part of a config deploy,\n // so an interactive run confirms it before anything mutates. Unattended\n // runs (--yes; forced in CI) proceed — the config is the source of truth\n // and the dry-run report lists the deletions.\n if (aspectSyncPlan && aspectSyncPlan.staleIds.length > 0 && !flags.yes) {\n const staleCount = aspectSyncPlan.staleIds.length\n const proceed = await confirm({\n default: false,\n message:\n `Delete ${staleCount} stored aspect ${pluralize('definition', staleCount)} with no ` +\n `matching config field (${aspectSyncPlan.staleIds.join(', ')})?`,\n })\n if (!proceed) {\n output.error('Deploy cancelled — the stored aspect definitions are unchanged.', {\n exit: exitCodes.USER_ABORT,\n })\n }\n }\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (aspectSyncPlan) {\n await runAspectSync(aspectSyncPlan, output)\n }\n if (installationId && version) {\n return {application: null, installationId, payload}\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n if (!mfManifest) throw new Error('The federated build produced no manifest.')\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n mfManifest,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n slug: workbench.slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = hasAppView\n ? getApplicationUrl({\n id: applicationId,\n organizationId,\n slug: workbench.slug,\n type: 'coreApp',\n })\n : getWorkbenchUrl(organizationId)\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n createRequested: flags.create,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n action: appCreated ? 'create' : 'update',\n application,\n payload,\n url: getCoreAppUrl(application.organizationId, application.id),\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Reports the planned aspect-document sync: the upserts as a pass, stripped\n * non-serializable values as information, and — prominently, as a warning —\n * the stored definitions the sync will delete because no config field matches\n * them. Deploy is a mirror: the config owns the library's aspect namespace.\n */\nexport function reportAspectSyncPlan(reporter: DeployCheckReporter, plan: AspectSyncPlan): void {\n const upserts = plan.documents.length\n reporter.report({\n message: `Will sync ${upserts} aspect ${pluralize('definition', upserts)} to media library ${plan.mediaLibraryId}`,\n status: 'pass',\n })\n\n const strippedFields = Object.entries(plan.strippedByField)\n if (strippedFields.length > 0) {\n // Expected for fields with custom inputs, validation callbacks, or\n // initial-value resolvers: the live config keeps those capabilities, only\n // the stored mirror (read by Studio plugin mode and the dashboard) omits\n // them. Reported so the capability gap is explicit, but not a warning.\n const details = strippedFields\n .map(([name, paths]) => `${name} (${paths.join(', ')})`)\n .join('; ')\n reporter.report({\n message: `Stored definitions omit non-serializable values: ${details}`,\n status: 'pass',\n })\n }\n\n if (plan.staleIds.length > 0) {\n reporter.report({\n message: `Will delete ${plan.staleIds.length} stored aspect ${pluralize('definition', plan.staleIds.length)} with no matching config field: ${plan.staleIds.join(', ')}`,\n solution:\n 'Definitions only — aspects.<name> values on assets stay put and resurface if a matching ' +\n 'field is added back. To keep a definition, declare a matching field in sanity.cli.ts ' +\n '(generate one with `sanity media pull-aspects`)',\n status: 'warn',\n })\n }\n}\n\n/**\n * Applies the planned sync after the config itself deployed. A failure here\n * leaves the config live but the stored mirror stale, so the error says so\n * and points at the retry (deploys are idempotent).\n */\nasync function runAspectSync(\n plan: AspectSyncPlan,\n output: DeployAppOptions['output'],\n): Promise<void> {\n try {\n await applyAspectSync(plan)\n } catch (err) {\n throw new Error(\n `The config deployed, but syncing its aspect documents to media library ${plan.mediaLibraryId} failed: ${getErrorMessage(err)}\\nRun \\`sanity deploy\\` again to retry the sync.`,\n {cause: err},\n )\n }\n const deleted =\n plan.staleIds.length > 0\n ? ` (deleted ${plan.staleIds.length} stale ${pluralize('definition', plan.staleIds.length)})`\n : ''\n output.log(\n `Synced ${plan.documents.length} aspect ${pluralize('definition', plan.documents.length)} to media library ${plan.mediaLibraryId}${deleted}`,\n )\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {\n appId: getAppId(cliConfig),\n create: flags.create,\n organizationId,\n title,\n })\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n create: flags.create,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.logDiagnostic(`Warning: Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n createRequested = false,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n createRequested?: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n createRequested\n ? '\\nSave `deployment.appId` and omit --create on later deploys to update this application.'\n : '\\nSave `deployment.appId` to update this application on later deploys.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","exitCodes","getErrorMessage","getCoreAppUrl","confirm","spinner","resolveAppEntry","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","getWorkbenchUrl","resolveInstallationId","resolveWorkbenchConfig","summarizeConfig","toWorkbenchPayload","c","createTar","createDeployment","updateUserApplication","getAppId","runStep","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","pluralize","buildApp","applyAspectSync","planAspectSync","checkBlueprintManaged","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","config","dryRun","deployConfigOnly","deployApplication","hasInterfaces","hasAppView","undefined","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","fields","length","isAutoUpdating","version","moduleName","kind","projectRootDir","application","appCreated","workbenchApp","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","applicationId","applicationCreated","rollbackApp","isSingleton","name","visibility","id","rollback","built","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","mfManifest","manifest","installationId","configSummary","configAppType","appType","aspectSyncPlan","planned","debug","formatError","work","mediaLibraryId","failure","plan","reportAspectSyncPlan","interfaces","deployApplicationConfig","payload","aspectSync","deleteIds","staleIds","upsertIds","documents","map","document","_id","yes","staleCount","proceed","default","join","error","exit","USER_ABORT","runAspectSync","Error","isApp","onDeployed","url","logAppDeployed","action","syncApplicationMetadata","shipAppDeployment","createRequested","create","upserts","strippedFields","Object","entries","strippedByField","details","paths","cause","deleted","log","unattended","titleUpdate","visibilityChanged","dashboardStatus","from","to","spin","start","updated","body","succeed","fail","logDiagnostic","tarball","cwd","pipe","clear","named"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {\n type CoreAppManifest,\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '@sanity/cli-build/_internal/manifest'\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {resolveAppEntry} from '@sanity/workbench-cli/build'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n getWorkbenchUrl,\n resolveInstallationId,\n resolveWorkbenchConfig,\n selectWorkbenchAppId,\n summarizeConfig,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {c as createTar} from 'tar'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {runStep} from '../../util/checks.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {pluralize} from '../../util/pluralize.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {\n applyAspectSync,\n type AspectSyncPlan,\n planAspectSync,\n} from '../media/aspectSync/syncAspects.js'\nimport {checkBlueprintManaged} from './blueprintManaged.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n // A config (the Media Library) is not an app — it resolves through its own\n // brand and persists to the org's installation instead of hosting an application.\n const config = resolveWorkbenchConfig(cliConfig)\n const dryRun = !!flags['dry-run']\n\n const deployConfigOnly = !!config\n const deployApplication = !config && (!workbench || workbench.hasInterfaces)\n const hasAppView = resolveAppEntry(cliConfig.app) !== undefined\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n // A config with no fields would overwrite the org's live config with an empty\n // snapshot, so block it here — same \"nothing to deploy\" gate an app gets.\n if (config && config.fields.length === 0) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Nothing to deploy: the media library config declares no fields.',\n solution: 'Add at least one field to the media library config',\n status: 'fail',\n })\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deployConfigOnly) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n await checkBlueprintManaged(reporter, {kind: 'coreApp', projectRootDir: workDir})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n let workbenchApp: object | undefined\n let targetAppId = appId\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n targetAppId = await selectWorkbenchAppId({appId, flags, organizationId, type: 'coreApp'})\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId: targetAppId,\n hasAppView,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = targetAppId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n const created = await createCoreApp({\n isSingleton: workbench.isSingleton,\n name: workbench.name,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n })\n workbenchApp = created.application\n applicationId = created.application.id\n rollbackApp = created.rollback\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n const built = await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n // A federated build has already read its manifest; anything else verifies the directory.\n const mfManifest =\n built?.mfManifest ??\n (await verifyOutputDir({\n isWorkbenchApp: workbench !== null || config !== null,\n reporter,\n sourceDir,\n }))\n\n // Workbench apps and configs ship a federation remote and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench && !config) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let configSummary: string | undefined\n const configAppType = config?.appType\n if (deployConfigOnly && organizationId && config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n configSummary = summarizeConfig(config)\n reporter.report(\n installationId\n ? {message: configSummary, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n // Plan the aspect-document sync in both modes, so the report — dry-run and\n // real — shows what the sync will write and, prominently, what it will\n // delete, before anything mutates. Gated on a resolved installation: when\n // that check failed, a real run already exited and a dry run has reported\n // the config as undeployable.\n let aspectSyncPlan: AspectSyncPlan | undefined\n // Gated on the `appType` discriminator, not the mere presence of a config:\n // `ConfigSchema` is a union built to grow, and a future config type must\n // not inherit the media-library aspect sync — and its deletions — by\n // default.\n if (configAppType === 'media-library' && organizationId && config && installationId) {\n // runStep so an unexpected throw (network, API) becomes a fail check:\n // a real run exits, a dry run records it and keeps reporting.\n const planned = await runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Planning the aspect-document sync failed: ${getErrorMessage(err)}`,\n name: 'aspect sync plan',\n work: () =>\n planAspectSync({\n fields: config.fields,\n mediaLibraryId: flags['media-library-id'],\n organizationId,\n workDir,\n }),\n })\n if (planned && 'failure' in planned) {\n reporter.report({\n exitCode: planned.failure.exitCode,\n message: planned.failure.message,\n solution: planned.failure.solution,\n status: 'fail',\n })\n } else if (planned) {\n aspectSyncPlan = planned.plan\n reportAspectSyncPlan(reporter, aspectSyncPlan)\n }\n }\n\n const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n type: 'coreApp',\n version,\n ...toWorkbenchPayload(workbench, {config: configSummary, interfaces, title: appTitle}),\n ...(configSummary ? {config: configSummary} : {}),\n ...(aspectSyncPlan\n ? {\n aspectSync: {\n deleteIds: aspectSyncPlan.staleIds,\n mediaLibraryId: aspectSyncPlan.mediaLibraryId,\n upsertIds: aspectSyncPlan.documents.map((document) => document._id),\n },\n }\n : {}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // Deleting stored definitions is the destructive part of a config deploy,\n // so an interactive run confirms it before anything mutates. Unattended\n // runs (--yes; forced in CI) proceed — the config is the source of truth\n // and the dry-run report lists the deletions.\n if (aspectSyncPlan && aspectSyncPlan.staleIds.length > 0 && !flags.yes) {\n const staleCount = aspectSyncPlan.staleIds.length\n const proceed = await confirm({\n default: false,\n message:\n `Delete ${staleCount} stored aspect ${pluralize('definition', staleCount)} with no ` +\n `matching config field (${aspectSyncPlan.staleIds.join(', ')})?`,\n })\n if (!proceed) {\n output.error('Deploy cancelled — the stored aspect definitions are unchanged.', {\n exit: exitCodes.USER_ABORT,\n })\n }\n }\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (aspectSyncPlan) {\n await runAspectSync(aspectSyncPlan, output)\n }\n if (installationId && version) {\n return {application: null, installationId, payload}\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n if (!mfManifest) throw new Error('The federated build produced no manifest.')\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n mfManifest,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n slug: workbench.slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = hasAppView\n ? getApplicationUrl({\n id: applicationId,\n organizationId,\n slug: workbench.slug,\n type: 'coreApp',\n })\n : getWorkbenchUrl(organizationId)\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n createRequested: flags.create,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n action: appCreated ? 'create' : 'update',\n application,\n payload,\n url: getCoreAppUrl(application.organizationId, application.id),\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Reports the planned aspect-document sync: the upserts as a pass, stripped\n * non-serializable values as information, and — prominently, as a warning —\n * the stored definitions the sync will delete because no config field matches\n * them. Deploy is a mirror: the config owns the library's aspect namespace.\n */\nexport function reportAspectSyncPlan(reporter: DeployCheckReporter, plan: AspectSyncPlan): void {\n const upserts = plan.documents.length\n reporter.report({\n message: `Will sync ${upserts} aspect ${pluralize('definition', upserts)} to media library ${plan.mediaLibraryId}`,\n status: 'pass',\n })\n\n const strippedFields = Object.entries(plan.strippedByField)\n if (strippedFields.length > 0) {\n // Expected for fields with custom inputs, validation callbacks, or\n // initial-value resolvers: the live config keeps those capabilities, only\n // the stored mirror (read by Studio plugin mode and the dashboard) omits\n // them. Reported so the capability gap is explicit, but not a warning.\n const details = strippedFields\n .map(([name, paths]) => `${name} (${paths.join(', ')})`)\n .join('; ')\n reporter.report({\n message: `Stored definitions omit non-serializable values: ${details}`,\n status: 'pass',\n })\n }\n\n if (plan.staleIds.length > 0) {\n reporter.report({\n message: `Will delete ${plan.staleIds.length} stored aspect ${pluralize('definition', plan.staleIds.length)} with no matching config field: ${plan.staleIds.join(', ')}`,\n solution:\n 'Definitions only — aspects.<name> values on assets stay put and resurface if a matching ' +\n 'field is added back. To keep a definition, declare a matching field in sanity.cli.ts ' +\n '(generate one with `sanity media pull-aspects`)',\n status: 'warn',\n })\n }\n}\n\n/**\n * Applies the planned sync after the config itself deployed. A failure here\n * leaves the config live but the stored mirror stale, so the error says so\n * and points at the retry (deploys are idempotent).\n */\nasync function runAspectSync(\n plan: AspectSyncPlan,\n output: DeployAppOptions['output'],\n): Promise<void> {\n try {\n await applyAspectSync(plan)\n } catch (err) {\n throw new Error(\n `The config deployed, but syncing its aspect documents to media library ${plan.mediaLibraryId} failed: ${getErrorMessage(err)}\\nRun \\`sanity deploy\\` again to retry the sync.`,\n {cause: err},\n )\n }\n const deleted =\n plan.staleIds.length > 0\n ? ` (deleted ${plan.staleIds.length} stale ${pluralize('definition', plan.staleIds.length)})`\n : ''\n output.log(\n `Synced ${plan.documents.length} aspect ${pluralize('definition', plan.documents.length)} to media library ${plan.mediaLibraryId}${deleted}`,\n )\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {\n appId: getAppId(cliConfig),\n create: flags.create,\n organizationId,\n title,\n })\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n create: flags.create,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.logDiagnostic(`Warning: Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n createRequested = false,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n createRequested?: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n createRequested\n ? '\\nSave `deployment.appId` and omit --create on later deploys to update this application.'\n : '\\nSave `deployment.appId` to update this application on later deploys.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","exitCodes","getErrorMessage","getCoreAppUrl","confirm","spinner","resolveAppEntry","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","getWorkbenchUrl","resolveInstallationId","resolveWorkbenchConfig","selectWorkbenchAppId","summarizeConfig","toWorkbenchPayload","c","createTar","createDeployment","updateUserApplication","getAppId","runStep","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","pluralize","buildApp","applyAspectSync","planAspectSync","checkBlueprintManaged","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","config","dryRun","deployConfigOnly","deployApplication","hasInterfaces","hasAppView","undefined","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","fields","length","isAutoUpdating","version","moduleName","kind","projectRootDir","application","appCreated","workbenchApp","targetAppId","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","applicationId","applicationCreated","rollbackApp","isSingleton","name","visibility","id","rollback","built","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","mfManifest","manifest","installationId","configSummary","configAppType","appType","aspectSyncPlan","planned","debug","formatError","work","mediaLibraryId","failure","plan","reportAspectSyncPlan","interfaces","deployApplicationConfig","payload","aspectSync","deleteIds","staleIds","upsertIds","documents","map","document","_id","yes","staleCount","proceed","default","join","error","exit","USER_ABORT","runAspectSync","Error","isApp","onDeployed","url","logAppDeployed","action","syncApplicationMetadata","shipAppDeployment","createRequested","create","upserts","strippedFields","Object","entries","strippedByField","details","paths","cause","deleted","log","unattended","titleUpdate","visibilityChanged","dashboardStatus","from","to","spin","start","updated","body","succeed","fail","logDiagnostic","tarball","cwd","pipe","clear","named"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { formatSchemaValidation, SchemaExtractionError } from '@sanity/cli-build
|
|
|
5
5
|
import { readIconFromPath } from '@sanity/cli-build/_internal/manifest';
|
|
6
6
|
import { exitCodes } from '@sanity/cli-core';
|
|
7
7
|
import { spinner } from '@sanity/cli-core/ux';
|
|
8
|
-
import { createStudio, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
|
|
8
|
+
import { createStudio, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, selectWorkbenchAppId, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
|
|
9
9
|
import { c as createTar } from 'tar';
|
|
10
10
|
import { createDeployment } from '../../services/userApplications.js';
|
|
11
11
|
import { getAppId } from '../../util/appId.js';
|
|
@@ -67,6 +67,7 @@ export function deployStudio(options) {
|
|
|
67
67
|
let studioCreated = false;
|
|
68
68
|
let workbenchApp;
|
|
69
69
|
let externalUrl;
|
|
70
|
+
let targetAppId = appId;
|
|
70
71
|
if (workbench) {
|
|
71
72
|
reporter.report(organizationId ? {
|
|
72
73
|
message: `Organization: ${organizationId}`,
|
|
@@ -76,15 +77,21 @@ export function deployStudio(options) {
|
|
|
76
77
|
solution: 'Add `app.organizationId` to sanity.cli.ts',
|
|
77
78
|
status: 'fail'
|
|
78
79
|
});
|
|
79
|
-
|
|
80
|
+
targetAppId = await selectWorkbenchAppId({
|
|
80
81
|
appId,
|
|
82
|
+
flags,
|
|
83
|
+
organizationId,
|
|
84
|
+
type: 'studio'
|
|
85
|
+
});
|
|
86
|
+
workbenchApp = (await checkStudioTarget(reporter, {
|
|
87
|
+
appId: targetAppId,
|
|
81
88
|
isWorkbenchApp: true,
|
|
82
89
|
organizationId,
|
|
83
90
|
slug: workbench.slug,
|
|
84
91
|
title: appTitle
|
|
85
92
|
}))?.application;
|
|
86
93
|
if (isExternal) externalUrl = checkExternalUrl(reporter, {
|
|
87
|
-
appId,
|
|
94
|
+
appId: targetAppId,
|
|
88
95
|
url: flags.url
|
|
89
96
|
});
|
|
90
97
|
} else {
|
|
@@ -110,7 +117,7 @@ export function deployStudio(options) {
|
|
|
110
117
|
const appIcon = !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined;
|
|
111
118
|
// Create the studio before the build so the bundle carries its real id. A
|
|
112
119
|
// redeploy already has it from `deployment.appId`; a dry run skips creation.
|
|
113
|
-
let applicationId =
|
|
120
|
+
let applicationId = targetAppId;
|
|
114
121
|
let applicationCreated = false;
|
|
115
122
|
let rollbackApp;
|
|
116
123
|
if (!dryRun && workbench && organizationId && !applicationId) {
|