@sanity/cli 7.5.0 → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/build/buildApp.js +7 -183
- package/dist/actions/build/buildApp.js.map +1 -1
- package/dist/actions/build/buildStudio.js +6 -213
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/actions/build/shouldAutoUpdate.js +100 -22
- package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
- package/dist/actions/deploy/{createStudioUserApplication.js → createUserApplication.js} +56 -5
- package/dist/actions/deploy/createUserApplication.js.map +1 -0
- package/dist/actions/deploy/deployApp.js +232 -185
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployChecks.js +263 -0
- package/dist/actions/deploy/deployChecks.js.map +1 -0
- package/dist/actions/deploy/deployRunner.js +57 -0
- package/dist/actions/deploy/deployRunner.js.map +1 -0
- package/dist/actions/deploy/deployStudio.js +189 -198
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/deploy/deploymentPlan.js +89 -0
- package/dist/actions/deploy/deploymentPlan.js.map +1 -0
- package/dist/actions/deploy/findUserApplication.js +209 -0
- package/dist/actions/deploy/findUserApplication.js.map +1 -0
- package/dist/actions/deploy/resolveDeployTarget.js +185 -0
- package/dist/actions/deploy/resolveDeployTarget.js.map +1 -0
- package/dist/actions/dev/devAction.js +1 -1
- package/dist/actions/dev/devAction.js.map +1 -1
- package/dist/actions/dev/servers/getDevServerConfig.js +18 -6
- package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
- package/dist/actions/dev/servers/startAppDevServer.js +1 -1
- package/dist/actions/dev/servers/startAppDevServer.js.map +1 -1
- package/dist/actions/dev/servers/startStudioDevServer.js +2 -1
- package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
- package/dist/actions/manifest/extractCoreAppManifest.js +14 -0
- package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
- package/dist/commands/deploy.js +27 -11
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.js +2 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.js +2 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/exports/index.d.ts +9 -0
- package/dist/exports/index.js +1 -8
- package/dist/exports/index.js.map +1 -1
- package/dist/server/devServer.js +27 -3
- package/dist/server/devServer.js.map +1 -1
- package/dist/util/appId.js +13 -5
- package/dist/util/appId.js.map +1 -1
- package/dist/util/compareDependencyVersions.js.map +1 -1
- package/dist/util/determineIsApp.js +1 -1
- package/dist/util/determineIsApp.js.map +1 -1
- package/dist/util/errorMessages.js +2 -0
- package/dist/util/errorMessages.js.map +1 -1
- package/oclif.manifest.json +14 -1
- package/package.json +8 -8
- package/dist/actions/build/handlePrereleaseVersions.js +0 -44
- package/dist/actions/build/handlePrereleaseVersions.js.map +0 -1
- package/dist/actions/deploy/createStudioUserApplication.js.map +0 -1
- package/dist/actions/deploy/createUserApplicationForApp.js +0 -56
- package/dist/actions/deploy/createUserApplicationForApp.js.map +0 -1
- package/dist/actions/deploy/findUserApplicationForApp.js +0 -111
- package/dist/actions/deploy/findUserApplicationForApp.js.map +0 -1
- package/dist/actions/deploy/findUserApplicationForStudio.js +0 -172
- package/dist/actions/deploy/findUserApplicationForStudio.js.map +0 -1
- package/dist/actions/deploy/viewDeployment.js +0 -32
- package/dist/actions/deploy/viewDeployment.js.map +0 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds (or creates) the user application a deploy targets — the interactive
|
|
3
|
+
* adapter that turns the resolveDeployTarget verdicts into prompts, creation,
|
|
4
|
+
* and exits. Dry runs consume the same verdicts read-only (see deployChecks).
|
|
5
|
+
*/ import { select, Separator, spinner } from '@sanity/cli-core/ux';
|
|
6
|
+
import { createUserApplication } from '../../services/userApplications.js';
|
|
7
|
+
import { getAppId } from '../../util/appId.js';
|
|
8
|
+
import { getErrorMessage } from '../../util/getErrorMessage.js';
|
|
9
|
+
import { createFailFastReporter, describeAppTarget, describeAppTargetError, describeStudioTarget } from './deployChecks.js';
|
|
10
|
+
import { deployDebug } from './deployDebug.js';
|
|
11
|
+
import { resolveAppDeployTarget, resolveStudioDeployTarget } from './resolveDeployTarget.js';
|
|
12
|
+
export async function findUserApplication(options) {
|
|
13
|
+
const { cliConfig, organizationId, output, title, unattended = false } = options;
|
|
14
|
+
const spin = spinner('Checking application info...').start();
|
|
15
|
+
let resolution;
|
|
16
|
+
try {
|
|
17
|
+
resolution = await resolveAppDeployTarget({
|
|
18
|
+
appId: getAppId(cliConfig),
|
|
19
|
+
organizationId
|
|
20
|
+
});
|
|
21
|
+
deployDebug('Resolved app deploy target', resolution);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
spin.clear();
|
|
24
|
+
deployDebug('Error finding user application for app', error);
|
|
25
|
+
output.error(describeAppTargetError(error, organizationId), {
|
|
26
|
+
exit: 1
|
|
27
|
+
});
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (resolution.type === 'found') {
|
|
31
|
+
spin.succeed();
|
|
32
|
+
return resolution.application;
|
|
33
|
+
}
|
|
34
|
+
// null tells the caller to create. Unattended runs can only create with a
|
|
35
|
+
// --title; picking among existing apps (needs-input) always needs a prompt.
|
|
36
|
+
if (resolution.type === 'would-create' && (!unattended || title)) {
|
|
37
|
+
spin.info('No application ID configured');
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (resolution.type === 'needs-input' && !unattended) {
|
|
41
|
+
spin.info('No application ID configured');
|
|
42
|
+
return promptForExistingApp(resolution.existing);
|
|
43
|
+
}
|
|
44
|
+
spin.clear();
|
|
45
|
+
// 'blocked' diagnoses as a skip (its root cause fails an earlier check), so it
|
|
46
|
+
// needs an explicit exit here to not fall through to application creation
|
|
47
|
+
if (resolution.type === 'blocked') {
|
|
48
|
+
output.error(resolution.message, {
|
|
49
|
+
exit: 1
|
|
50
|
+
});
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
createFailFastReporter(output).report(describeAppTarget(resolution));
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
export async function findUserApplicationForStudio(options) {
|
|
57
|
+
const { appId, isExternal, output, projectId, studioHost, title, unattended = false, urlFlag } = options;
|
|
58
|
+
const urlType = isExternal ? 'external' : 'internal';
|
|
59
|
+
const spin = spinner('Checking project info').start();
|
|
60
|
+
let resolution;
|
|
61
|
+
try {
|
|
62
|
+
resolution = await resolveStudioDeployTarget({
|
|
63
|
+
appId,
|
|
64
|
+
isExternal,
|
|
65
|
+
projectId,
|
|
66
|
+
studioHost,
|
|
67
|
+
urlFlag
|
|
68
|
+
});
|
|
69
|
+
deployDebug('Resolved studio deploy target', resolution);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
spin.fail();
|
|
72
|
+
deployDebug('Error finding user application', error);
|
|
73
|
+
output.error(`Failed to resolve deploy target: ${getErrorMessage(error)}`, {
|
|
74
|
+
exit: 1
|
|
75
|
+
});
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
if (resolution.type === 'found') {
|
|
79
|
+
spin.succeed();
|
|
80
|
+
return resolution.application;
|
|
81
|
+
}
|
|
82
|
+
// The configured host isn't registered yet — a deploy registers it without prompting
|
|
83
|
+
if (resolution.type === 'would-create') {
|
|
84
|
+
spin.succeed();
|
|
85
|
+
return createFromConfiguredHost({
|
|
86
|
+
appHost: resolution.appHost,
|
|
87
|
+
output,
|
|
88
|
+
projectId,
|
|
89
|
+
title,
|
|
90
|
+
urlType
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (resolution.type === 'needs-input' && !unattended) {
|
|
94
|
+
spin.succeed();
|
|
95
|
+
// Nothing to select from — the caller prompts for a brand new host
|
|
96
|
+
if (resolution.existing.length === 0) return null;
|
|
97
|
+
return promptForExistingStudio({
|
|
98
|
+
existing: resolution.existing,
|
|
99
|
+
urlType
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
spin.fail();
|
|
103
|
+
// 'blocked' diagnoses as a skip (its root cause fails an earlier check), so it
|
|
104
|
+
// needs an explicit exit here
|
|
105
|
+
if (resolution.type === 'blocked') {
|
|
106
|
+
output.error(resolution.message, {
|
|
107
|
+
exit: 1
|
|
108
|
+
});
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
createFailFastReporter(output).report(describeStudioTarget(resolution, {
|
|
112
|
+
isExternal
|
|
113
|
+
}));
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The host is configured (studioHost or --url) but not registered yet:
|
|
118
|
+
* a deploy registers it without prompting.
|
|
119
|
+
*/ async function createFromConfiguredHost({ appHost, output, projectId, title, urlType }) {
|
|
120
|
+
if (urlType === 'external') {
|
|
121
|
+
output.log('Your project has not been registered with an external studio URL.');
|
|
122
|
+
output.log(`Registering ${appHost}`);
|
|
123
|
+
} else {
|
|
124
|
+
output.log('Your project has not been assigned a studio hostname.');
|
|
125
|
+
output.log(`Creating https://${appHost}.sanity.studio`);
|
|
126
|
+
}
|
|
127
|
+
output.log('');
|
|
128
|
+
const spin = spinner(urlType === 'external' ? 'Registering external studio' : 'Creating studio hostname').start();
|
|
129
|
+
try {
|
|
130
|
+
const response = await createUserApplication({
|
|
131
|
+
appType: 'studio',
|
|
132
|
+
body: {
|
|
133
|
+
appHost,
|
|
134
|
+
title,
|
|
135
|
+
type: 'studio',
|
|
136
|
+
urlType
|
|
137
|
+
},
|
|
138
|
+
projectId
|
|
139
|
+
});
|
|
140
|
+
spin.succeed();
|
|
141
|
+
return response;
|
|
142
|
+
} catch (e) {
|
|
143
|
+
spin.fail();
|
|
144
|
+
// if the name is taken, it should return a 409 so we relay to the user
|
|
145
|
+
if ([
|
|
146
|
+
402,
|
|
147
|
+
409
|
|
148
|
+
].includes(e?.statusCode)) {
|
|
149
|
+
output.error(e?.response?.body?.message || 'Bad request', {
|
|
150
|
+
exit: 1
|
|
151
|
+
});
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
// otherwise, it's a fatal error
|
|
155
|
+
deployDebug('Error creating user application from config', e);
|
|
156
|
+
output.error(`Error creating user application from config: ${e instanceof Error ? e.message : e}`, {
|
|
157
|
+
exit: 1
|
|
158
|
+
});
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async function promptForExistingApp(existing) {
|
|
163
|
+
const choices = existing.map((app)=>({
|
|
164
|
+
name: app.title ?? app.appHost,
|
|
165
|
+
value: app.appHost
|
|
166
|
+
}));
|
|
167
|
+
const selected = await select({
|
|
168
|
+
choices: [
|
|
169
|
+
{
|
|
170
|
+
name: 'New application deployment',
|
|
171
|
+
value: 'NEW_APP'
|
|
172
|
+
},
|
|
173
|
+
new Separator(' ════ Existing applications: ════ '),
|
|
174
|
+
...choices
|
|
175
|
+
],
|
|
176
|
+
loop: false,
|
|
177
|
+
message: 'Would you like to create a new application deployment, or deploy to an existing one?',
|
|
178
|
+
pageSize: 10
|
|
179
|
+
});
|
|
180
|
+
if (selected === 'NEW_APP') {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
return existing.find((app)=>app.appHost === selected);
|
|
184
|
+
}
|
|
185
|
+
async function promptForExistingStudio({ existing, urlType }) {
|
|
186
|
+
const newLabel = urlType === 'external' ? 'Register new external studio URL' : 'Create new studio hostname';
|
|
187
|
+
const selectMessage = urlType === 'external' ? 'Select existing external studio, or register a new one' : 'Select existing studio hostname, or create a new one';
|
|
188
|
+
const choices = existing.map((app)=>({
|
|
189
|
+
name: app.title ?? app.appHost,
|
|
190
|
+
value: app.appHost
|
|
191
|
+
}));
|
|
192
|
+
const selected = await select({
|
|
193
|
+
choices: [
|
|
194
|
+
{
|
|
195
|
+
name: newLabel,
|
|
196
|
+
value: 'NEW_STUDIO'
|
|
197
|
+
},
|
|
198
|
+
new Separator(),
|
|
199
|
+
...choices
|
|
200
|
+
],
|
|
201
|
+
message: selectMessage
|
|
202
|
+
});
|
|
203
|
+
if (selected === 'NEW_STUDIO') {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
return existing.find((app)=>app.appHost === selected);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
//# sourceMappingURL=findUserApplication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/findUserApplication.ts"],"sourcesContent":["/**\n * Finds (or creates) the user application a deploy targets — the interactive\n * adapter that turns the resolveDeployTarget verdicts into prompts, creation,\n * and exits. Dry runs consume the same verdicts read-only (see deployChecks).\n */\n\nimport {type CliConfig, type Output} from '@sanity/cli-core'\nimport {select, Separator, spinner} from '@sanity/cli-core/ux'\n\nimport {createUserApplication, type UserApplication} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {getErrorMessage} from '../../util/getErrorMessage.js'\nimport {\n createFailFastReporter,\n describeAppTarget,\n describeAppTargetError,\n describeStudioTarget,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {resolveAppDeployTarget, resolveStudioDeployTarget} from './resolveDeployTarget.js'\n\ninterface FindUserApplicationOptions {\n cliConfig: CliConfig\n organizationId: string\n output: Output\n\n title?: string\n unattended?: boolean\n}\n\nexport async function findUserApplication(\n options: FindUserApplicationOptions,\n): Promise<UserApplication | null> {\n const {cliConfig, organizationId, output, title, unattended = false} = options\n const spin = spinner('Checking application info...').start()\n\n let resolution\n try {\n resolution = await resolveAppDeployTarget({appId: getAppId(cliConfig), organizationId})\n deployDebug('Resolved app deploy target', resolution)\n } catch (error) {\n spin.clear()\n deployDebug('Error finding user application for app', error)\n output.error(describeAppTargetError(error, organizationId), {exit: 1})\n return null\n }\n\n if (resolution.type === 'found') {\n spin.succeed()\n return resolution.application\n }\n\n // null tells the caller to create. Unattended runs can only create with a\n // --title; picking among existing apps (needs-input) always needs a prompt.\n if (resolution.type === 'would-create' && (!unattended || title)) {\n spin.info('No application ID configured')\n return null\n }\n if (resolution.type === 'needs-input' && !unattended) {\n spin.info('No application ID configured')\n return promptForExistingApp(resolution.existing)\n }\n\n spin.clear()\n // 'blocked' diagnoses as a skip (its root cause fails an earlier check), so it\n // needs an explicit exit here to not fall through to application creation\n if (resolution.type === 'blocked') {\n output.error(resolution.message, {exit: 1})\n return null\n }\n createFailFastReporter(output).report(describeAppTarget(resolution))\n return null\n}\n\ninterface FindUserApplicationForStudioOptions {\n isExternal: boolean\n output: Output\n projectId: string\n\n appId?: string\n studioHost?: string\n title?: string\n unattended?: boolean\n urlFlag?: string\n}\n\nexport async function findUserApplicationForStudio(\n options: FindUserApplicationForStudioOptions,\n): Promise<UserApplication | null> {\n const {\n appId,\n isExternal,\n output,\n projectId,\n studioHost,\n title,\n unattended = false,\n urlFlag,\n } = options\n const urlType = isExternal ? 'external' : 'internal'\n const spin = spinner('Checking project info').start()\n\n let resolution\n try {\n resolution = await resolveStudioDeployTarget({\n appId,\n isExternal,\n projectId,\n studioHost,\n urlFlag,\n })\n deployDebug('Resolved studio deploy target', resolution)\n } catch (error) {\n spin.fail()\n deployDebug('Error finding user application', error)\n output.error(`Failed to resolve deploy target: ${getErrorMessage(error)}`, {exit: 1})\n return null\n }\n\n if (resolution.type === 'found') {\n spin.succeed()\n return resolution.application\n }\n\n // The configured host isn't registered yet — a deploy registers it without prompting\n if (resolution.type === 'would-create') {\n spin.succeed()\n return createFromConfiguredHost({\n appHost: resolution.appHost,\n output,\n projectId,\n title,\n urlType,\n })\n }\n\n if (resolution.type === 'needs-input' && !unattended) {\n spin.succeed()\n // Nothing to select from — the caller prompts for a brand new host\n if (resolution.existing.length === 0) return null\n return promptForExistingStudio({existing: resolution.existing, urlType})\n }\n\n spin.fail()\n // 'blocked' diagnoses as a skip (its root cause fails an earlier check), so it\n // needs an explicit exit here\n if (resolution.type === 'blocked') {\n output.error(resolution.message, {exit: 1})\n return null\n }\n createFailFastReporter(output).report(describeStudioTarget(resolution, {isExternal}))\n return null\n}\n\n/**\n * The host is configured (studioHost or --url) but not registered yet:\n * a deploy registers it without prompting.\n */\nasync function createFromConfiguredHost({\n appHost,\n output,\n projectId,\n title,\n urlType,\n}: {\n appHost: string\n output: Output\n projectId: string\n title?: string\n urlType: 'external' | 'internal'\n}): Promise<UserApplication | null> {\n if (urlType === 'external') {\n output.log('Your project has not been registered with an external studio URL.')\n output.log(`Registering ${appHost}`)\n } else {\n output.log('Your project has not been assigned a studio hostname.')\n output.log(`Creating https://${appHost}.sanity.studio`)\n }\n output.log('')\n\n const spin = spinner(\n urlType === 'external' ? 'Registering external studio' : 'Creating studio hostname',\n ).start()\n\n try {\n const response = await createUserApplication({\n appType: 'studio',\n body: {appHost, title, type: 'studio', urlType},\n projectId,\n })\n spin.succeed()\n return response\n } catch (e) {\n spin.fail()\n // if the name is taken, it should return a 409 so we relay to the user\n if ([402, 409].includes(e?.statusCode)) {\n output.error(e?.response?.body?.message || 'Bad request', {exit: 1})\n return null\n }\n // otherwise, it's a fatal error\n deployDebug('Error creating user application from config', e)\n output.error(\n `Error creating user application from config: ${e instanceof Error ? e.message : e}`,\n {exit: 1},\n )\n return null\n }\n}\n\nasync function promptForExistingApp(existing: UserApplication[]): Promise<UserApplication | null> {\n const choices = existing.map((app) => ({name: app.title ?? app.appHost, value: app.appHost}))\n\n const selected = await select({\n choices: [\n {name: 'New application deployment', value: 'NEW_APP'},\n new Separator(' ════ Existing applications: ════ '),\n ...choices,\n ],\n loop: false,\n message: 'Would you like to create a new application deployment, or deploy to an existing one?',\n pageSize: 10,\n })\n\n if (selected === 'NEW_APP') {\n return null\n }\n\n return existing.find((app) => app.appHost === selected)!\n}\n\nasync function promptForExistingStudio({\n existing,\n urlType,\n}: {\n existing: UserApplication[]\n urlType: 'external' | 'internal'\n}): Promise<UserApplication | null> {\n const newLabel =\n urlType === 'external' ? 'Register new external studio URL' : 'Create new studio hostname'\n const selectMessage =\n urlType === 'external'\n ? 'Select existing external studio, or register a new one'\n : 'Select existing studio hostname, or create a new one'\n\n const choices = existing.map((app) => ({name: app.title ?? app.appHost, value: app.appHost}))\n\n const selected = await select({\n choices: [{name: newLabel, value: 'NEW_STUDIO'}, new Separator(), ...choices],\n message: selectMessage,\n })\n\n if (selected === 'NEW_STUDIO') {\n return null\n }\n\n return existing.find((app) => app.appHost === selected)!\n}\n"],"names":["select","Separator","spinner","createUserApplication","getAppId","getErrorMessage","createFailFastReporter","describeAppTarget","describeAppTargetError","describeStudioTarget","deployDebug","resolveAppDeployTarget","resolveStudioDeployTarget","findUserApplication","options","cliConfig","organizationId","output","title","unattended","spin","start","resolution","appId","error","clear","exit","type","succeed","application","info","promptForExistingApp","existing","message","report","findUserApplicationForStudio","isExternal","projectId","studioHost","urlFlag","urlType","fail","createFromConfiguredHost","appHost","length","promptForExistingStudio","log","response","appType","body","e","includes","statusCode","Error","choices","map","app","name","value","selected","loop","pageSize","find","newLabel","selectMessage"],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { getUserApplication, getUserApplications } from '../../services/userApplications.js';
|
|
2
|
+
import { normalizeUrl, validateUrl } from './urlUtils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Owns the studio deploy-target rules: the --url flag over studioHost config,
|
|
5
|
+
* appId over appHost precedence, external URL normalization and validation.
|
|
6
|
+
* Both the real deploy and the dry run consume these verdicts.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/ export async function resolveStudioDeployTarget(options) {
|
|
10
|
+
const { appId, isExternal, projectId, studioHost, urlFlag } = options;
|
|
11
|
+
// appId wins over host config (and undeploy resolves it the same way): a
|
|
12
|
+
// configured appId deploys even when studioHost is stale or invalid, so it's
|
|
13
|
+
// resolved before any host validation.
|
|
14
|
+
if (appId) {
|
|
15
|
+
if (!projectId) {
|
|
16
|
+
return {
|
|
17
|
+
message: 'api.projectId is missing',
|
|
18
|
+
type: 'blocked'
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const application = await getUserApplication({
|
|
22
|
+
appId,
|
|
23
|
+
isSdkApp: false,
|
|
24
|
+
projectId
|
|
25
|
+
});
|
|
26
|
+
if (application) {
|
|
27
|
+
return {
|
|
28
|
+
application,
|
|
29
|
+
type: 'found'
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
message: `Cannot find app with app ID ${appId}`,
|
|
34
|
+
reason: 'app-not-found',
|
|
35
|
+
type: 'invalid'
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const { error: hostError, host: resolvedHost } = resolveAppHost({
|
|
39
|
+
isExternal,
|
|
40
|
+
studioHost,
|
|
41
|
+
url: urlFlag
|
|
42
|
+
});
|
|
43
|
+
if (hostError) {
|
|
44
|
+
return {
|
|
45
|
+
message: hostError,
|
|
46
|
+
reason: 'invalid-host',
|
|
47
|
+
type: 'invalid'
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// A host from config hasn't passed through the --url validation yet
|
|
51
|
+
let appHost = resolvedHost;
|
|
52
|
+
if (appHost && isExternal) {
|
|
53
|
+
appHost = normalizeUrl(appHost);
|
|
54
|
+
const validation = validateUrl(appHost);
|
|
55
|
+
if (validation !== true) {
|
|
56
|
+
return {
|
|
57
|
+
message: validation,
|
|
58
|
+
reason: 'invalid-host',
|
|
59
|
+
type: 'invalid'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (appHost) {
|
|
64
|
+
if (!projectId) {
|
|
65
|
+
return {
|
|
66
|
+
message: 'api.projectId is missing',
|
|
67
|
+
type: 'blocked'
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const application = await getUserApplication({
|
|
71
|
+
appHost,
|
|
72
|
+
isSdkApp: false,
|
|
73
|
+
projectId
|
|
74
|
+
});
|
|
75
|
+
if (application) {
|
|
76
|
+
return {
|
|
77
|
+
application,
|
|
78
|
+
type: 'found'
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
appHost,
|
|
83
|
+
type: 'would-create'
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// Neither appId nor host configured — a deploy would prompt.
|
|
87
|
+
// Without a project there is nothing to list; a deploy would still prompt.
|
|
88
|
+
const existing = projectId ? await listStudioApplications(projectId, isExternal) : [];
|
|
89
|
+
return {
|
|
90
|
+
existing,
|
|
91
|
+
type: 'needs-input'
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Owns the app deploy-target rules: appId lookup, falling back to listing the
|
|
96
|
+
* organization's applications. Both the real deploy and the dry run consume
|
|
97
|
+
* these verdicts.
|
|
98
|
+
*
|
|
99
|
+
* @internal
|
|
100
|
+
*/ export async function resolveAppDeployTarget(options) {
|
|
101
|
+
const { appId, organizationId } = options;
|
|
102
|
+
if (appId) {
|
|
103
|
+
const application = await getUserApplication({
|
|
104
|
+
appId,
|
|
105
|
+
isSdkApp: true
|
|
106
|
+
});
|
|
107
|
+
if (application) {
|
|
108
|
+
return {
|
|
109
|
+
application,
|
|
110
|
+
type: 'found'
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
message: `Cannot find app with app ID ${appId}`,
|
|
115
|
+
reason: 'app-not-found',
|
|
116
|
+
type: 'invalid'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (!organizationId) {
|
|
120
|
+
return {
|
|
121
|
+
message: 'app.organizationId is missing',
|
|
122
|
+
type: 'blocked'
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const existing = await getUserApplications({
|
|
126
|
+
appType: 'coreApp',
|
|
127
|
+
organizationId
|
|
128
|
+
});
|
|
129
|
+
if (existing?.length) {
|
|
130
|
+
return {
|
|
131
|
+
existing,
|
|
132
|
+
type: 'needs-input'
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
type: 'would-create'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async function listStudioApplications(projectId, isExternal) {
|
|
140
|
+
const urlType = isExternal ? 'external' : 'internal';
|
|
141
|
+
const applications = await getUserApplications({
|
|
142
|
+
appType: 'studio',
|
|
143
|
+
projectId
|
|
144
|
+
});
|
|
145
|
+
// External deploys should only see external studios and vice versa
|
|
146
|
+
return applications?.filter((application)=>application.urlType === urlType) ?? [];
|
|
147
|
+
}
|
|
148
|
+
function resolveAppHost({ isExternal, studioHost, url }) {
|
|
149
|
+
if (!url) {
|
|
150
|
+
return {
|
|
151
|
+
host: studioHost
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (isExternal) {
|
|
155
|
+
const normalized = normalizeUrl(url);
|
|
156
|
+
const validation = validateUrl(normalized);
|
|
157
|
+
if (validation !== true) {
|
|
158
|
+
return {
|
|
159
|
+
error: validation
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
host: normalized
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// For internal deploys, strip protocol prefix and .sanity.studio suffix if present
|
|
167
|
+
const hostname = url.replace(/^https?:\/\//i, '').replace(/\.sanity\.studio\/?$/i, '');
|
|
168
|
+
// If the result still looks like a URL (contains dots), the user likely meant --external
|
|
169
|
+
if (hostname.includes('.')) {
|
|
170
|
+
return {
|
|
171
|
+
error: `"${hostname}" does not look like a sanity.studio hostname. Did you mean to use --external?`
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// Validate hostname characters (alphanumeric and hyphens only)
|
|
175
|
+
if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/i.test(hostname)) {
|
|
176
|
+
return {
|
|
177
|
+
error: `Invalid studio hostname "${hostname}". Hostnames can only contain letters, numbers, and hyphens.`
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
host: hostname
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//# sourceMappingURL=resolveDeployTarget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/resolveDeployTarget.ts"],"sourcesContent":["import {\n getUserApplication,\n getUserApplications,\n type UserApplication,\n} from '../../services/userApplications.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.js'\n\n/**\n * The read-only outcome of resolving where a deploy would go.\n *\n * - `found` — the deploy targets this existing user application\n * - `would-create` — nothing registered yet; a deploy would create it without prompting\n * - `needs-input` — config doesn't determine a target; a deploy would prompt\n * (`existing` lists the applications a prompt would offer)\n * - `invalid` — the configured target can never resolve (bad host, unknown appId)\n * - `blocked` — resolution requires config that's missing (projectId/organizationId)\n *\n * Transport errors (network, permissions) throw — they're not verdicts.\n */\ntype CommonDeployTargetResolution =\n | {application: UserApplication; type: 'found'}\n | {existing: UserApplication[]; type: 'needs-input'}\n | {message: string; reason: 'app-not-found' | 'invalid-host'; type: 'invalid'}\n | {message: string; type: 'blocked'}\n\nexport type StudioDeployTargetResolution =\n | CommonDeployTargetResolution\n | {appHost: string; type: 'would-create'}\n\nexport type AppDeployTargetResolution = CommonDeployTargetResolution | {type: 'would-create'}\n\n/**\n * Owns the studio deploy-target rules: the --url flag over studioHost config,\n * appId over appHost precedence, external URL normalization and validation.\n * Both the real deploy and the dry run consume these verdicts.\n *\n * @internal\n */\nexport async function resolveStudioDeployTarget(options: {\n appId: string | undefined\n isExternal: boolean\n projectId: string | undefined\n studioHost: string | undefined\n urlFlag: string | undefined\n}): Promise<StudioDeployTargetResolution> {\n const {appId, isExternal, projectId, studioHost, urlFlag} = options\n\n // appId wins over host config (and undeploy resolves it the same way): a\n // configured appId deploys even when studioHost is stale or invalid, so it's\n // resolved before any host validation.\n if (appId) {\n if (!projectId) {\n return {message: 'api.projectId is missing', type: 'blocked'}\n }\n const application = await getUserApplication({appId, isSdkApp: false, projectId})\n if (application) {\n return {application, type: 'found'}\n }\n return {\n message: `Cannot find app with app ID ${appId}`,\n reason: 'app-not-found',\n type: 'invalid',\n }\n }\n\n const {error: hostError, host: resolvedHost} = resolveAppHost({\n isExternal,\n studioHost,\n url: urlFlag,\n })\n if (hostError) {\n return {message: hostError, reason: 'invalid-host', type: 'invalid'}\n }\n\n // A host from config hasn't passed through the --url validation yet\n let appHost = resolvedHost\n if (appHost && isExternal) {\n appHost = normalizeUrl(appHost)\n const validation = validateUrl(appHost)\n if (validation !== true) {\n return {message: validation, reason: 'invalid-host', type: 'invalid'}\n }\n }\n\n if (appHost) {\n if (!projectId) {\n return {message: 'api.projectId is missing', type: 'blocked'}\n }\n const application = await getUserApplication({appHost, isSdkApp: false, projectId})\n if (application) {\n return {application, type: 'found'}\n }\n return {appHost, type: 'would-create'}\n }\n\n // Neither appId nor host configured — a deploy would prompt.\n // Without a project there is nothing to list; a deploy would still prompt.\n const existing = projectId ? await listStudioApplications(projectId, isExternal) : []\n return {existing, type: 'needs-input'}\n}\n\n/**\n * Owns the app deploy-target rules: appId lookup, falling back to listing the\n * organization's applications. Both the real deploy and the dry run consume\n * these verdicts.\n *\n * @internal\n */\nexport async function resolveAppDeployTarget(options: {\n appId: string | undefined\n organizationId: string | undefined\n}): Promise<AppDeployTargetResolution> {\n const {appId, organizationId} = options\n\n if (appId) {\n const application = await getUserApplication({appId, isSdkApp: true})\n if (application) {\n return {application, type: 'found'}\n }\n return {\n message: `Cannot find app with app ID ${appId}`,\n reason: 'app-not-found',\n type: 'invalid',\n }\n }\n\n if (!organizationId) {\n return {message: 'app.organizationId is missing', type: 'blocked'}\n }\n\n const existing = await getUserApplications({appType: 'coreApp', organizationId})\n if (existing?.length) {\n return {existing, type: 'needs-input'}\n }\n\n return {type: 'would-create'}\n}\n\nasync function listStudioApplications(\n projectId: string,\n isExternal: boolean,\n): Promise<UserApplication[]> {\n const urlType = isExternal ? 'external' : 'internal'\n const applications = await getUserApplications({appType: 'studio', projectId})\n // External deploys should only see external studios and vice versa\n return applications?.filter((application) => application.urlType === urlType) ?? []\n}\n\nfunction resolveAppHost({\n isExternal,\n studioHost,\n url,\n}: {\n isExternal: boolean\n studioHost: string | undefined\n url: string | undefined\n}): {error?: string; host?: string} {\n if (!url) {\n return {host: studioHost}\n }\n\n if (isExternal) {\n const normalized = normalizeUrl(url)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n return {error: validation}\n }\n return {host: normalized}\n }\n\n // For internal deploys, strip protocol prefix and .sanity.studio suffix if present\n const hostname = url.replace(/^https?:\\/\\//i, '').replace(/\\.sanity\\.studio\\/?$/i, '')\n\n // If the result still looks like a URL (contains dots), the user likely meant --external\n if (hostname.includes('.')) {\n return {\n error: `\"${hostname}\" does not look like a sanity.studio hostname. Did you mean to use --external?`,\n }\n }\n\n // Validate hostname characters (alphanumeric and hyphens only)\n if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/i.test(hostname)) {\n return {\n error: `Invalid studio hostname \"${hostname}\". Hostnames can only contain letters, numbers, and hyphens.`,\n }\n }\n\n return {host: hostname}\n}\n"],"names":["getUserApplication","getUserApplications","normalizeUrl","validateUrl","resolveStudioDeployTarget","options","appId","isExternal","projectId","studioHost","urlFlag","message","type","application","isSdkApp","reason","error","hostError","host","resolvedHost","resolveAppHost","url","appHost","validation","existing","listStudioApplications","resolveAppDeployTarget","organizationId","appType","length","urlType","applications","filter","normalized","hostname","replace","includes","test"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SANITY_CACHE_DIR } from '@sanity/cli-build/_internal/build';
|
|
2
|
-
import { isWorkbenchApp } from '@sanity/cli
|
|
2
|
+
import { isWorkbenchApp } from '@sanity/workbench-cli';
|
|
3
3
|
import { checkForDeprecatedAppId, getAppId } from '../../util/appId.js';
|
|
4
4
|
import { getSharedServerConfig } from '../../util/getSharedServerConfig.js';
|
|
5
5
|
import { resolveReactStrictMode } from '../../util/resolveReactStrictMode.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/dev/devAction.ts"],"sourcesContent":["import {SANITY_CACHE_DIR} from '@sanity/cli-build/_internal/build'\nimport {type CliConfig
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/dev/devAction.ts"],"sourcesContent":["import {SANITY_CACHE_DIR} from '@sanity/cli-build/_internal/build'\nimport {type CliConfig} from '@sanity/cli-core'\nimport {isWorkbenchApp} from '@sanity/workbench-cli'\n\nimport {checkForDeprecatedAppId, getAppId} from '../../util/appId.js'\nimport {getSharedServerConfig} from '../../util/getSharedServerConfig.js'\nimport {resolveReactStrictMode} from '../../util/resolveReactStrictMode.js'\nimport {extractCoreAppManifest} from '../manifest/extractCoreAppManifest.js'\nimport {extractStudioManifest} from '../manifest/extractStudioManifest.js'\nimport {startAppDevServer} from './servers/startAppDevServer.js'\nimport {startStudioDevServer} from './servers/startStudioDevServer.js'\nimport {type DevActionOptions} from './types.js'\n\nconst noop = async () => {}\n\n/**\n * Entry point for `sanity dev`. A plain studio/app starts a single dev server, as\n * before workbench existed. A workbench app (via `unstable_defineApp`) delegates to\n * `@sanity/workbench-cli`, injecting the CLI-domain pieces (app server, manifest\n * extraction, app id) and loading the package lazily so plain projects never do.\n */\nexport async function devAction(options: DevActionOptions): Promise<{close: () => Promise<void>}> {\n const {cliConfig, flags, isApp, output, workDir} = options\n\n const {httpHost, httpPort} = getSharedServerConfig({\n cliConfig,\n flags: {host: flags.host, port: flags.port},\n workDir,\n })\n\n // The app/studio server, parameterized per call; `announceUrl` is false when\n // the workbench announces the URL on its behalf.\n const startAppServer = (params: {announceUrl: boolean; cliConfig: CliConfig; httpPort: number}) =>\n (isApp ? startAppDevServer : startStudioDevServer)({\n ...options,\n announceUrl: params.announceUrl,\n cliConfig: params.cliConfig,\n httpPort: params.httpPort,\n })\n\n if (isWorkbenchApp(cliConfig?.app)) {\n // Lazy so a non-workbench `sanity dev` never loads the package. `doImport`\n // is path-based and doesn't apply to a bare specifier.\n // eslint-disable-next-line no-restricted-syntax\n const {startWorkbenchDev} = await import('@sanity/workbench-cli/dev')\n return startWorkbenchDev({\n appId: getAppId(cliConfig),\n cacheDir: `${SANITY_CACHE_DIR}/vite`,\n checkForDeprecatedAppId: () => checkForDeprecatedAppId({cliConfig, output}),\n cliConfig,\n extractManifest: isApp\n ? ({workDir: wd}) => extractCoreAppManifest({workDir: wd})\n : (params) => extractStudioManifest(params),\n httpHost,\n httpPort,\n isApp,\n output,\n // Runtime template needs a concrete boolean; collapse an unset config to off.\n reactStrictMode: resolveReactStrictMode(cliConfig) ?? false,\n startAppServer,\n workDir,\n })\n }\n\n // Plain non-workbench studio/app: one dev server announcing its own URL.\n const result = await startAppServer({announceUrl: true, cliConfig, httpPort})\n return {close: result.started ? result.close : noop}\n}\n"],"names":["SANITY_CACHE_DIR","isWorkbenchApp","checkForDeprecatedAppId","getAppId","getSharedServerConfig","resolveReactStrictMode","extractCoreAppManifest","extractStudioManifest","startAppDevServer","startStudioDevServer","noop","devAction","options","cliConfig","flags","isApp","output","workDir","httpHost","httpPort","host","port","startAppServer","params","announceUrl","app","startWorkbenchDev","appId","cacheDir","extractManifest","wd","reactStrictMode","result","close","started"],"mappings":"AAAA,SAAQA,gBAAgB,QAAO,oCAAmC;AAElE,SAAQC,cAAc,QAAO,wBAAuB;AAEpD,SAAQC,uBAAuB,EAAEC,QAAQ,QAAO,sBAAqB;AACrE,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,sBAAsB,QAAO,uCAAsC;AAC3E,SAAQC,sBAAsB,QAAO,wCAAuC;AAC5E,SAAQC,qBAAqB,QAAO,uCAAsC;AAC1E,SAAQC,iBAAiB,QAAO,iCAAgC;AAChE,SAAQC,oBAAoB,QAAO,oCAAmC;AAGtE,MAAMC,OAAO,WAAa;AAE1B;;;;;CAKC,GACD,OAAO,eAAeC,UAAUC,OAAyB;IACvD,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAEC,KAAK,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGL;IAEnD,MAAM,EAACM,QAAQ,EAAEC,QAAQ,EAAC,GAAGf,sBAAsB;QACjDS;QACAC,OAAO;YAACM,MAAMN,MAAMM,IAAI;YAAEC,MAAMP,MAAMO,IAAI;QAAA;QAC1CJ;IACF;IAEA,6EAA6E;IAC7E,iDAAiD;IACjD,MAAMK,iBAAiB,CAACC,SACtB,AAACR,CAAAA,QAAQP,oBAAoBC,oBAAmB,EAAG;YACjD,GAAGG,OAAO;YACVY,aAAaD,OAAOC,WAAW;YAC/BX,WAAWU,OAAOV,SAAS;YAC3BM,UAAUI,OAAOJ,QAAQ;QAC3B;IAEF,IAAIlB,eAAeY,WAAWY,MAAM;QAClC,2EAA2E;QAC3E,uDAAuD;QACvD,gDAAgD;QAChD,MAAM,EAACC,iBAAiB,EAAC,GAAG,MAAM,MAAM,CAAC;QACzC,OAAOA,kBAAkB;YACvBC,OAAOxB,SAASU;YAChBe,UAAU,GAAG5B,iBAAiB,KAAK,CAAC;YACpCE,yBAAyB,IAAMA,wBAAwB;oBAACW;oBAAWG;gBAAM;YACzEH;YACAgB,iBAAiBd,QACb,CAAC,EAACE,SAASa,EAAE,EAAC,GAAKxB,uBAAuB;oBAACW,SAASa;gBAAE,KACtD,CAACP,SAAWhB,sBAAsBgB;YACtCL;YACAC;YACAJ;YACAC;YACA,8EAA8E;YAC9Ee,iBAAiB1B,uBAAuBQ,cAAc;YACtDS;YACAL;QACF;IACF;IAEA,yEAAyE;IACzE,MAAMe,SAAS,MAAMV,eAAe;QAACE,aAAa;QAAMX;QAAWM;IAAQ;IAC3E,OAAO;QAACc,OAAOD,OAAOE,OAAO,GAAGF,OAAOC,KAAK,GAAGvB;IAAI;AACrD"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { getSanityEnvVar
|
|
3
|
-
import { spinner } from '@sanity/cli-core/ux';
|
|
2
|
+
import { getSanityEnvVar } from '@sanity/cli-core';
|
|
3
|
+
import { logSymbols, spinner } from '@sanity/cli-core/ux';
|
|
4
|
+
import { isWorkbenchApp } from '@sanity/workbench-cli';
|
|
4
5
|
import { determineIsApp } from '../../../util/determineIsApp.js';
|
|
5
6
|
import { getSharedServerConfig } from '../../../util/getSharedServerConfig.js';
|
|
6
7
|
import { resolveReactStrictMode } from '../../../util/resolveReactStrictMode.js';
|
|
@@ -17,28 +18,39 @@ export function getDevServerConfig({ cliConfig, flags, httpPort, output, workDir
|
|
|
17
18
|
configSpinner.succeed();
|
|
18
19
|
const isApp = cliConfig ? determineIsApp(cliConfig) : false;
|
|
19
20
|
const reactStrictMode = resolveReactStrictMode(cliConfig);
|
|
20
|
-
// `views`
|
|
21
|
-
// app result rather than the legacy `app` config type.
|
|
21
|
+
// `views`/`services` are declared via `unstable_defineApp`, so read them off
|
|
22
|
+
// the branded app result rather than the legacy `app` config type.
|
|
22
23
|
const app = cliConfig?.app;
|
|
23
24
|
const envBasePath = getSanityEnvVar('BASEPATH', isApp ?? false);
|
|
24
25
|
if (envBasePath && cliConfig?.project?.basePath) {
|
|
25
26
|
output.warn(`Overriding configured base path (${cliConfig.project.basePath}) with value from environment variable (${envBasePath})`);
|
|
26
27
|
}
|
|
28
|
+
// Unstable opt-in to Vite's experimental bundled dev mode, via
|
|
29
|
+
// `unstable_bundledDev` in sanity.cli.ts. Defaults to off.
|
|
30
|
+
const bundledDev = cliConfig?.unstable_bundledDev ?? false;
|
|
31
|
+
if (bundledDev) {
|
|
32
|
+
output.log(`${logSymbols.info} Running dev server with experimental Vite bundled dev mode`);
|
|
33
|
+
}
|
|
27
34
|
return {
|
|
28
35
|
...baseConfig,
|
|
36
|
+
bundledDev,
|
|
29
37
|
// The app's navigable entry. A branded app that omits `entry` has no app
|
|
30
38
|
// view: the runtime/federation skip the `./App` render path entirely.
|
|
31
39
|
entry: app?.entry,
|
|
40
|
+
exposes: isWorkbenchApp(app) ? {
|
|
41
|
+
installationConfig: app.installationConfig,
|
|
42
|
+
services: app.services,
|
|
43
|
+
views: app.views
|
|
44
|
+
} : undefined,
|
|
32
45
|
// `devAction` passes an explicit port when a running workbench claimed the
|
|
33
46
|
// configured one; otherwise the shared resolution stands.
|
|
34
47
|
httpPort: httpPort ?? baseConfig.httpPort,
|
|
35
48
|
isWorkbenchApp: isWorkbenchApp(app),
|
|
36
49
|
reactCompiler: cliConfig && 'reactCompiler' in cliConfig ? cliConfig.reactCompiler : undefined,
|
|
37
50
|
reactStrictMode,
|
|
38
|
-
services: isWorkbenchApp(app) ? app.services : undefined,
|
|
39
51
|
staticPath: path.join(workDir, 'static'),
|
|
40
52
|
typegen: cliConfig?.typegen,
|
|
41
|
-
|
|
53
|
+
workbenchAppId: isWorkbenchApp(app) ? app.name : undefined
|
|
42
54
|
};
|
|
43
55
|
}
|
|
44
56
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/dev/servers/getDevServerConfig.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {type CliConfig, getSanityEnvVar,
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/dev/servers/getDevServerConfig.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {type CliConfig, getSanityEnvVar, type Output} from '@sanity/cli-core'\nimport {logSymbols, spinner} from '@sanity/cli-core/ux'\nimport {isWorkbenchApp} from '@sanity/workbench-cli'\n\nimport {type DevServerOptions} from '../../../server/devServer.js'\nimport {determineIsApp} from '../../../util/determineIsApp.js'\nimport {getSharedServerConfig} from '../../../util/getSharedServerConfig.js'\nimport {resolveReactStrictMode} from '../../../util/resolveReactStrictMode.js'\nimport {type DevFlags} from '../types.js'\n\nexport function getDevServerConfig({\n cliConfig,\n flags,\n httpPort,\n output,\n workDir,\n}: {\n cliConfig?: CliConfig\n flags: DevFlags\n httpPort?: number\n output: Output\n workDir: string\n}): Omit<DevServerOptions, 'spinner'> {\n const configSpinner = spinner('Checking configuration files...')\n\n const baseConfig = getSharedServerConfig({\n cliConfig,\n flags: {\n host: flags.host,\n port: flags.port,\n },\n workDir,\n })\n\n configSpinner.succeed()\n\n const isApp = cliConfig ? determineIsApp(cliConfig) : false\n const reactStrictMode = resolveReactStrictMode(cliConfig)\n // `views`/`services` are declared via `unstable_defineApp`, so read them off\n // the branded app result rather than the legacy `app` config type.\n const app = cliConfig?.app\n\n const envBasePath = getSanityEnvVar('BASEPATH', isApp ?? false)\n if (envBasePath && cliConfig?.project?.basePath) {\n output.warn(\n `Overriding configured base path (${cliConfig.project.basePath}) with value from environment variable (${envBasePath})`,\n )\n }\n\n // Unstable opt-in to Vite's experimental bundled dev mode, via\n // `unstable_bundledDev` in sanity.cli.ts. Defaults to off.\n const bundledDev = cliConfig?.unstable_bundledDev ?? false\n if (bundledDev) {\n output.log(`${logSymbols.info} Running dev server with experimental Vite bundled dev mode`)\n }\n\n return {\n ...baseConfig,\n bundledDev,\n // The app's navigable entry. A branded app that omits `entry` has no app\n // view: the runtime/federation skip the `./App` render path entirely.\n entry: app?.entry,\n exposes: isWorkbenchApp(app)\n ? {installationConfig: app.installationConfig, services: app.services, views: app.views}\n : undefined,\n // `devAction` passes an explicit port when a running workbench claimed the\n // configured one; otherwise the shared resolution stands.\n httpPort: httpPort ?? baseConfig.httpPort,\n isWorkbenchApp: isWorkbenchApp(app),\n reactCompiler: cliConfig && 'reactCompiler' in cliConfig ? cliConfig.reactCompiler : undefined,\n reactStrictMode,\n staticPath: path.join(workDir, 'static'),\n typegen: cliConfig?.typegen,\n workbenchAppId: isWorkbenchApp(app) ? app.name : undefined,\n }\n}\n"],"names":["path","getSanityEnvVar","logSymbols","spinner","isWorkbenchApp","determineIsApp","getSharedServerConfig","resolveReactStrictMode","getDevServerConfig","cliConfig","flags","httpPort","output","workDir","configSpinner","baseConfig","host","port","succeed","isApp","reactStrictMode","app","envBasePath","project","basePath","warn","bundledDev","unstable_bundledDev","log","info","entry","exposes","installationConfig","services","views","undefined","reactCompiler","staticPath","join","typegen","workbenchAppId","name"],"mappings":"AAAA,OAAOA,UAAU,YAAW;AAE5B,SAAwBC,eAAe,QAAoB,mBAAkB;AAC7E,SAAQC,UAAU,EAAEC,OAAO,QAAO,sBAAqB;AACvD,SAAQC,cAAc,QAAO,wBAAuB;AAGpD,SAAQC,cAAc,QAAO,kCAAiC;AAC9D,SAAQC,qBAAqB,QAAO,yCAAwC;AAC5E,SAAQC,sBAAsB,QAAO,0CAAyC;AAG9E,OAAO,SAASC,mBAAmB,EACjCC,SAAS,EACTC,KAAK,EACLC,QAAQ,EACRC,MAAM,EACNC,OAAO,EAOR;IACC,MAAMC,gBAAgBX,QAAQ;IAE9B,MAAMY,aAAaT,sBAAsB;QACvCG;QACAC,OAAO;YACLM,MAAMN,MAAMM,IAAI;YAChBC,MAAMP,MAAMO,IAAI;QAClB;QACAJ;IACF;IAEAC,cAAcI,OAAO;IAErB,MAAMC,QAAQV,YAAYJ,eAAeI,aAAa;IACtD,MAAMW,kBAAkBb,uBAAuBE;IAC/C,6EAA6E;IAC7E,mEAAmE;IACnE,MAAMY,MAAMZ,WAAWY;IAEvB,MAAMC,cAAcrB,gBAAgB,YAAYkB,SAAS;IACzD,IAAIG,eAAeb,WAAWc,SAASC,UAAU;QAC/CZ,OAAOa,IAAI,CACT,CAAC,iCAAiC,EAAEhB,UAAUc,OAAO,CAACC,QAAQ,CAAC,wCAAwC,EAAEF,YAAY,CAAC,CAAC;IAE3H;IAEA,+DAA+D;IAC/D,2DAA2D;IAC3D,MAAMI,aAAajB,WAAWkB,uBAAuB;IACrD,IAAID,YAAY;QACdd,OAAOgB,GAAG,CAAC,GAAG1B,WAAW2B,IAAI,CAAC,2DAA2D,CAAC;IAC5F;IAEA,OAAO;QACL,GAAGd,UAAU;QACbW;QACA,yEAAyE;QACzE,sEAAsE;QACtEI,OAAOT,KAAKS;QACZC,SAAS3B,eAAeiB,OACpB;YAACW,oBAAoBX,IAAIW,kBAAkB;YAAEC,UAAUZ,IAAIY,QAAQ;YAAEC,OAAOb,IAAIa,KAAK;QAAA,IACrFC;QACJ,2EAA2E;QAC3E,0DAA0D;QAC1DxB,UAAUA,YAAYI,WAAWJ,QAAQ;QACzCP,gBAAgBA,eAAeiB;QAC/Be,eAAe3B,aAAa,mBAAmBA,YAAYA,UAAU2B,aAAa,GAAGD;QACrFf;QACAiB,YAAYrC,KAAKsC,IAAI,CAACzB,SAAS;QAC/B0B,SAAS9B,WAAW8B;QACpBC,gBAAgBpC,eAAeiB,OAAOA,IAAIoB,IAAI,GAAGN;IACnD;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { styleText } from 'node:util';
|
|
2
|
-
import { isWorkbenchApp as determineIsWorkbenchApp } from '@sanity/cli
|
|
2
|
+
import { isWorkbenchApp as determineIsWorkbenchApp } from '@sanity/workbench-cli';
|
|
3
3
|
import { startDevServer } from '../../../server/devServer.js';
|
|
4
4
|
import { gracefulServerDeath } from '../../../server/gracefulServerDeath.js';
|
|
5
5
|
import { devDebug } from '../devDebug.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/dev/servers/startAppDevServer.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {isWorkbenchApp as determineIsWorkbenchApp} from '@sanity/cli
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/dev/servers/startAppDevServer.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {isWorkbenchApp as determineIsWorkbenchApp} from '@sanity/workbench-cli'\n\nimport {startDevServer} from '../../../server/devServer.js'\nimport {gracefulServerDeath} from '../../../server/gracefulServerDeath.js'\nimport {devDebug} from '../devDebug.js'\nimport {type DevActionOptions, type StartDevServerResult} from '../types.js'\nimport {getDashboardAppURL} from './getDashboardAppUrl.js'\nimport {getDevServerConfig} from './getDevServerConfig.js'\n\n// Bind-only addresses ('0.0.0.0', '::') aren't routable in every browser; the\n// displayed URL falls back to localhost. The bind address itself is untouched.\nfunction toDisplayHost(host: string | undefined): string {\n if (!host || host === '0.0.0.0' || host === '::' || host === '[::]') {\n return 'localhost'\n }\n return host\n}\n\nexport async function startAppDevServer(options: DevActionOptions): Promise<StartDevServerResult> {\n const {announceUrl = true, cliConfig, flags, httpPort, output, workDir} = options\n\n const isWorkbenchApp = determineIsWorkbenchApp(cliConfig?.app)\n\n // Workbench apps don't load through the dashboard, so the flag has no\n // meaning for them and is ignored.\n if (!isWorkbenchApp && !flags['load-in-dashboard']) {\n output.warn(`Apps cannot run without the Sanity dashboard`)\n output.warn(`Starting dev server with the --load-in-dashboard flag set to true`)\n }\n\n let organizationId: string | undefined\n if (cliConfig && 'app' in cliConfig && cliConfig.app?.organizationId) {\n organizationId = cliConfig.app.organizationId\n }\n\n if (!organizationId) {\n output.error(`Apps require an organization ID (orgId) specified in your sanity.cli.ts file`, {\n exit: 1,\n })\n return {reason: 'missing-organization-id', started: false}\n }\n\n const config = getDevServerConfig({cliConfig, flags, httpPort, output, workDir})\n\n try {\n output.log('Starting dev server')\n\n const appTitle = cliConfig && 'app' in cliConfig ? cliConfig.app?.title : undefined\n const {close, server} = await startDevServer({\n ...config,\n appTitle,\n isApp: true,\n })\n\n const {port} = server.config.server\n\n // Federated apps surface through the workbench, which announces the URL;\n // only the package-unavailable fallback announces from here.\n if (isWorkbenchApp && announceUrl) {\n const url = `http://${toDisplayHost(config.httpHost)}:${port}`\n output.log(`App dev server started at ${styleText(['blue', 'underline'], url)}`)\n } else if (!isWorkbenchApp) {\n const httpHost = config.httpHost || 'localhost'\n\n const dashboardAppUrl = await getDashboardAppURL({\n httpHost,\n httpPort: port,\n organizationId,\n })\n output.log(`Dev server started on port ${port}`)\n output.log(`View your app in the Sanity dashboard here:`)\n output.log(styleText(['blue', 'underline'], dashboardAppUrl))\n }\n\n return {close, server, started: true}\n } catch (err) {\n devDebug('Error starting app dev server', err)\n throw gracefulServerDeath('dev', config.httpHost, config.httpPort, err)\n }\n}\n"],"names":["styleText","isWorkbenchApp","determineIsWorkbenchApp","startDevServer","gracefulServerDeath","devDebug","getDashboardAppURL","getDevServerConfig","toDisplayHost","host","startAppDevServer","options","announceUrl","cliConfig","flags","httpPort","output","workDir","app","warn","organizationId","error","exit","reason","started","config","log","appTitle","title","undefined","close","server","isApp","port","url","httpHost","dashboardAppUrl","err"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,kBAAkBC,uBAAuB,QAAO,wBAAuB;AAE/E,SAAQC,cAAc,QAAO,+BAA8B;AAC3D,SAAQC,mBAAmB,QAAO,yCAAwC;AAC1E,SAAQC,QAAQ,QAAO,iBAAgB;AAEvC,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,kBAAkB,QAAO,0BAAyB;AAE1D,8EAA8E;AAC9E,+EAA+E;AAC/E,SAASC,cAAcC,IAAwB;IAC7C,IAAI,CAACA,QAAQA,SAAS,aAAaA,SAAS,QAAQA,SAAS,QAAQ;QACnE,OAAO;IACT;IACA,OAAOA;AACT;AAEA,OAAO,eAAeC,kBAAkBC,OAAyB;IAC/D,MAAM,EAACC,cAAc,IAAI,EAAEC,SAAS,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGN;IAE1E,MAAMV,iBAAiBC,wBAAwBW,WAAWK;IAE1D,sEAAsE;IACtE,mCAAmC;IACnC,IAAI,CAACjB,kBAAkB,CAACa,KAAK,CAAC,oBAAoB,EAAE;QAClDE,OAAOG,IAAI,CAAC,CAAC,4CAA4C,CAAC;QAC1DH,OAAOG,IAAI,CAAC,CAAC,iEAAiE,CAAC;IACjF;IAEA,IAAIC;IACJ,IAAIP,aAAa,SAASA,aAAaA,UAAUK,GAAG,EAAEE,gBAAgB;QACpEA,iBAAiBP,UAAUK,GAAG,CAACE,cAAc;IAC/C;IAEA,IAAI,CAACA,gBAAgB;QACnBJ,OAAOK,KAAK,CAAC,CAAC,4EAA4E,CAAC,EAAE;YAC3FC,MAAM;QACR;QACA,OAAO;YAACC,QAAQ;YAA2BC,SAAS;QAAK;IAC3D;IAEA,MAAMC,SAASlB,mBAAmB;QAACM;QAAWC;QAAOC;QAAUC;QAAQC;IAAO;IAE9E,IAAI;QACFD,OAAOU,GAAG,CAAC;QAEX,MAAMC,WAAWd,aAAa,SAASA,YAAYA,UAAUK,GAAG,EAAEU,QAAQC;QAC1E,MAAM,EAACC,KAAK,EAAEC,MAAM,EAAC,GAAG,MAAM5B,eAAe;YAC3C,GAAGsB,MAAM;YACTE;YACAK,OAAO;QACT;QAEA,MAAM,EAACC,IAAI,EAAC,GAAGF,OAAON,MAAM,CAACM,MAAM;QAEnC,yEAAyE;QACzE,6DAA6D;QAC7D,IAAI9B,kBAAkBW,aAAa;YACjC,MAAMsB,MAAM,CAAC,OAAO,EAAE1B,cAAciB,OAAOU,QAAQ,EAAE,CAAC,EAAEF,MAAM;YAC9DjB,OAAOU,GAAG,CAAC,CAAC,0BAA0B,EAAE1B,UAAU;gBAAC;gBAAQ;aAAY,EAAEkC,MAAM;QACjF,OAAO,IAAI,CAACjC,gBAAgB;YAC1B,MAAMkC,WAAWV,OAAOU,QAAQ,IAAI;YAEpC,MAAMC,kBAAkB,MAAM9B,mBAAmB;gBAC/C6B;gBACApB,UAAUkB;gBACVb;YACF;YACAJ,OAAOU,GAAG,CAAC,CAAC,2BAA2B,EAAEO,MAAM;YAC/CjB,OAAOU,GAAG,CAAC,CAAC,2CAA2C,CAAC;YACxDV,OAAOU,GAAG,CAAC1B,UAAU;gBAAC;gBAAQ;aAAY,EAAEoC;QAC9C;QAEA,OAAO;YAACN;YAAOC;YAAQP,SAAS;QAAI;IACtC,EAAE,OAAOa,KAAK;QACZhC,SAAS,iCAAiCgC;QAC1C,MAAMjC,oBAAoB,OAAOqB,OAAOU,QAAQ,EAAEV,OAAOV,QAAQ,EAAEsB;IACrE;AACF"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { styleText } from 'node:util';
|
|
2
2
|
import { checkRequiredDependencies, checkStudioDependencyVersions } from '@sanity/cli-build/_internal/build';
|
|
3
|
-
import { getLocalPackageVersion, isInteractive
|
|
3
|
+
import { getLocalPackageVersion, isInteractive } from '@sanity/cli-core';
|
|
4
4
|
import { confirm, logSymbols, spinner } from '@sanity/cli-core/ux';
|
|
5
|
+
import { isWorkbenchApp } from '@sanity/workbench-cli';
|
|
5
6
|
import { parse as semverParse } from 'semver';
|
|
6
7
|
import { startDevServer } from '../../../server/devServer.js';
|
|
7
8
|
import { gracefulServerDeath } from '../../../server/gracefulServerDeath.js';
|