@sanity/cli 7.5.0 → 7.7.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.
Files changed (69) hide show
  1. package/README.md +6 -2
  2. package/dist/actions/build/buildApp.js +7 -183
  3. package/dist/actions/build/buildApp.js.map +1 -1
  4. package/dist/actions/build/buildStudio.js +6 -213
  5. package/dist/actions/build/buildStudio.js.map +1 -1
  6. package/dist/actions/build/shouldAutoUpdate.js +100 -22
  7. package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
  8. package/dist/actions/deploy/{createStudioUserApplication.js → createUserApplication.js} +56 -5
  9. package/dist/actions/deploy/createUserApplication.js.map +1 -0
  10. package/dist/actions/deploy/deployApp.js +253 -183
  11. package/dist/actions/deploy/deployApp.js.map +1 -1
  12. package/dist/actions/deploy/deployChecks.js +284 -0
  13. package/dist/actions/deploy/deployChecks.js.map +1 -0
  14. package/dist/actions/deploy/deployRunner.js +78 -0
  15. package/dist/actions/deploy/deployRunner.js.map +1 -0
  16. package/dist/actions/deploy/deployStudio.js +200 -197
  17. package/dist/actions/deploy/deployStudio.js.map +1 -1
  18. package/dist/actions/deploy/deployStudioSchemasAndManifests.js +2 -3
  19. package/dist/actions/deploy/deployStudioSchemasAndManifests.js.map +1 -1
  20. package/dist/actions/deploy/deploymentPlan.js +117 -0
  21. package/dist/actions/deploy/deploymentPlan.js.map +1 -0
  22. package/dist/actions/deploy/findUserApplication.js +209 -0
  23. package/dist/actions/deploy/findUserApplication.js.map +1 -0
  24. package/dist/actions/deploy/resolveDeployTarget.js +185 -0
  25. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -0
  26. package/dist/actions/deploy/urlUtils.js +4 -0
  27. package/dist/actions/deploy/urlUtils.js.map +1 -1
  28. package/dist/actions/dev/devAction.js +1 -1
  29. package/dist/actions/dev/devAction.js.map +1 -1
  30. package/dist/actions/dev/servers/getDevServerConfig.js +18 -6
  31. package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
  32. package/dist/actions/dev/servers/startAppDevServer.js +1 -1
  33. package/dist/actions/dev/servers/startAppDevServer.js.map +1 -1
  34. package/dist/actions/dev/servers/startStudioDevServer.js +2 -1
  35. package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
  36. package/dist/actions/manifest/extractCoreAppManifest.js +15 -1
  37. package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
  38. package/dist/commands/deploy.js +31 -12
  39. package/dist/commands/deploy.js.map +1 -1
  40. package/dist/commands/dev.js +2 -1
  41. package/dist/commands/dev.js.map +1 -1
  42. package/dist/commands/init.js +2 -1
  43. package/dist/commands/init.js.map +1 -1
  44. package/dist/exports/index.d.ts +9 -0
  45. package/dist/exports/index.js +1 -8
  46. package/dist/exports/index.js.map +1 -1
  47. package/dist/server/devServer.js +27 -3
  48. package/dist/server/devServer.js.map +1 -1
  49. package/dist/services/userApplications.js.map +1 -1
  50. package/dist/util/appId.js +13 -5
  51. package/dist/util/appId.js.map +1 -1
  52. package/dist/util/compareDependencyVersions.js.map +1 -1
  53. package/dist/util/determineIsApp.js +1 -1
  54. package/dist/util/determineIsApp.js.map +1 -1
  55. package/dist/util/errorMessages.js +2 -0
  56. package/dist/util/errorMessages.js.map +1 -1
  57. package/oclif.manifest.json +223 -203
  58. package/package.json +8 -8
  59. package/dist/actions/build/handlePrereleaseVersions.js +0 -44
  60. package/dist/actions/build/handlePrereleaseVersions.js.map +0 -1
  61. package/dist/actions/deploy/createStudioUserApplication.js.map +0 -1
  62. package/dist/actions/deploy/createUserApplicationForApp.js +0 -56
  63. package/dist/actions/deploy/createUserApplicationForApp.js.map +0 -1
  64. package/dist/actions/deploy/findUserApplicationForApp.js +0 -111
  65. package/dist/actions/deploy/findUserApplicationForApp.js.map +0 -1
  66. package/dist/actions/deploy/findUserApplicationForStudio.js +0 -172
  67. package/dist/actions/deploy/findUserApplicationForStudio.js.map +0 -1
  68. package/dist/actions/deploy/viewDeployment.js +0 -32
  69. package/dist/actions/deploy/viewDeployment.js.map +0 -1
@@ -1,37 +1,115 @@
1
1
  import { styleText } from 'node:util';
2
2
  /**
3
- * Compares parameters from various sources to determine whether or not to auto-update.
4
- * @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.
3
+ * Owns the auto-update rules: flag-over-config precedence, the deprecated
4
+ * top-level `autoUpdates` config, and the old/new config conflict.
5
+ * Returns plain facts so each surface (deploy warnings, dry-run checks)
6
+ * decides its own presentation.
7
+ *
5
8
  * @internal
6
- */ export function shouldAutoUpdate({ cliConfig, flags, output }) {
7
- // Auto updates in flags is deprecated; throw a warning if used
9
+ */ export function resolveAutoUpdates({ cliConfig, flags }) {
10
+ // Flags always take precedence over config
8
11
  if ('auto-updates' in flags) {
9
- const flagUsed = flags['auto-updates'] ? '--auto-updates' : '--no-auto-updates';
10
- output.warn(`The ${flagUsed} 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.`);
11
- // Flags always take precedence over config
12
- return Boolean(flags['auto-updates']);
12
+ const enabled = Boolean(flags['auto-updates']);
13
+ return {
14
+ enabled,
15
+ issue: {
16
+ flag: enabled ? '--auto-updates' : '--no-auto-updates',
17
+ type: 'deprecated-flag'
18
+ }
19
+ };
13
20
  }
14
21
  const hasOldConfig = cliConfig && 'autoUpdates' in cliConfig;
15
22
  const hasNewConfig = cliConfig && 'deployment' in cliConfig && cliConfig.deployment && 'autoUpdates' in cliConfig.deployment;
16
- if (hasOldConfig && hasNewConfig) {
17
- output.error('Found both `autoUpdates` (deprecated) and `deployment.autoUpdates` in sanity.cli.js/.ts. Please remove the deprecated top level `autoUpdates` config.', {
18
- exit: 1
19
- });
23
+ if (hasNewConfig) {
24
+ return {
25
+ enabled: Boolean(cliConfig?.deployment?.autoUpdates),
26
+ issue: hasOldConfig ? {
27
+ type: 'conflicting-config'
28
+ } : null
29
+ };
20
30
  }
21
31
  if (hasOldConfig) {
22
- output.warn('The autoUpdates config has moved to deployment.autoUpdates.');
23
- output.warn(`Please update sanity.cli.ts or sanity.cli.js and make the following change:
24
- ${styleText('red', `- autoUpdates: ${cliConfig.autoUpdates},`)}
25
- ${styleText('green', `+ deployment: {autoUpdates: ${cliConfig.autoUpdates}}`)}
26
- `);
32
+ return {
33
+ enabled: Boolean(cliConfig?.autoUpdates),
34
+ issue: {
35
+ type: 'deprecated-config'
36
+ }
37
+ };
27
38
  }
28
- if (hasNewConfig) {
29
- return Boolean(cliConfig?.deployment?.autoUpdates);
39
+ return {
40
+ enabled: false,
41
+ issue: null
42
+ };
43
+ }
44
+ /**
45
+ * The user-facing message for an auto-update configuration problem.
46
+ * Shared by every surface that reports the issue (deploy warnings, dry-run
47
+ * checks) so the wording has one home.
48
+ *
49
+ * @internal
50
+ */ export function getAutoUpdateIssueMessage(issue) {
51
+ switch(issue.type){
52
+ case 'conflicting-config':
53
+ {
54
+ return 'Found both `autoUpdates` (deprecated) and `deployment.autoUpdates` in sanity.cli.js/.ts. Please remove the deprecated top level `autoUpdates` config.';
55
+ }
56
+ case 'deprecated-config':
57
+ {
58
+ return 'The autoUpdates config has moved to deployment.autoUpdates.';
59
+ }
60
+ case 'deprecated-flag':
61
+ {
62
+ 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.`;
63
+ }
30
64
  }
31
- if (hasOldConfig) {
32
- return Boolean(cliConfig?.autoUpdates);
65
+ }
66
+ /**
67
+ * The styled before/after edit that migrates the deprecated top-level
68
+ * `autoUpdates` to `deployment.autoUpdates`. Lives here so every surface that
69
+ * reports the deprecated config (deploy warnings, dry-run checks) shows the
70
+ * same migration hint.
71
+ *
72
+ * @internal
73
+ */ export function getAutoUpdateMigrationHint(currentValue) {
74
+ return `Please update sanity.cli.ts or sanity.cli.js and make the following change:
75
+ ${styleText('red', `- autoUpdates: ${currentValue},`)}
76
+ ${styleText('green', `+ deployment: {autoUpdates: ${currentValue}}`)}
77
+ `;
78
+ }
79
+ /**
80
+ * Resolves the auto-update setting and prints any configuration problem.
81
+ * @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.
82
+ * @internal
83
+ */ export function shouldAutoUpdate({ cliConfig, flags, output }) {
84
+ const { enabled, issue } = resolveAutoUpdates({
85
+ cliConfig,
86
+ flags
87
+ });
88
+ switch(issue?.type){
89
+ case 'conflicting-config':
90
+ {
91
+ output.error(getAutoUpdateIssueMessage(issue), {
92
+ exit: 1
93
+ });
94
+ break;
95
+ }
96
+ case 'deprecated-config':
97
+ {
98
+ output.warn(getAutoUpdateIssueMessage(issue));
99
+ output.warn(getAutoUpdateMigrationHint(cliConfig.autoUpdates));
100
+ break;
101
+ }
102
+ case 'deprecated-flag':
103
+ {
104
+ output.warn(getAutoUpdateIssueMessage(issue));
105
+ break;
106
+ }
107
+ default:
108
+ {
109
+ break;
110
+ }
33
111
  }
34
- return false;
112
+ return enabled;
35
113
  }
36
114
 
37
115
  //# sourceMappingURL=shouldAutoUpdate.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/shouldAutoUpdate.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, 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 output: Output\n}\n\n/**\n * Compares parameters from various sources to determine whether or not to auto-update.\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({cliConfig, flags, output}: AutoUpdateSources): boolean {\n // Auto updates in flags is deprecated; throw a warning if used\n if ('auto-updates' in flags) {\n const flagUsed = flags['auto-updates'] ? '--auto-updates' : '--no-auto-updates'\n output.warn(\n `The ${flagUsed} 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 // Flags always take precedence over config\n return Boolean(flags['auto-updates'])\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 (hasOldConfig && hasNewConfig) {\n output.error(\n 'Found both `autoUpdates` (deprecated) and `deployment.autoUpdates` in sanity.cli.js/.ts. Please remove the deprecated top level `autoUpdates` config.',\n {\n exit: 1,\n },\n )\n }\n\n if (hasOldConfig) {\n output.warn('The autoUpdates config has moved to deployment.autoUpdates.')\n output.warn(`Please update sanity.cli.ts or sanity.cli.js and make the following change:\n ${styleText('red', `- autoUpdates: ${cliConfig.autoUpdates},`)}\n ${styleText('green', `+ deployment: {autoUpdates: ${cliConfig.autoUpdates}}`)}\n`)\n }\n\n if (hasNewConfig) {\n return Boolean(cliConfig?.deployment?.autoUpdates)\n }\n\n if (hasOldConfig) {\n return Boolean(cliConfig?.autoUpdates)\n }\n\n return false\n}\n"],"names":["styleText","shouldAutoUpdate","cliConfig","flags","output","flagUsed","warn","Boolean","hasOldConfig","hasNewConfig","deployment","error","exit","autoUpdates"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAcnC;;;;CAIC,GACD,OAAO,SAASC,iBAAiB,EAACC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAoB;IAC5E,+DAA+D;IAC/D,IAAI,kBAAkBD,OAAO;QAC3B,MAAME,WAAWF,KAAK,CAAC,eAAe,GAAG,mBAAmB;QAC5DC,OAAOE,IAAI,CACT,CAAC,IAAI,EAAED,SAAS,kJAAkJ,CAAC;QAErK,2CAA2C;QAC3C,OAAOE,QAAQJ,KAAK,CAAC,eAAe;IACtC;IAEA,MAAMK,eAAeN,aAAa,iBAAiBA;IAEnD,MAAMO,eACJP,aACA,gBAAgBA,aAChBA,UAAUQ,UAAU,IACpB,iBAAiBR,UAAUQ,UAAU;IAEvC,IAAIF,gBAAgBC,cAAc;QAChCL,OAAOO,KAAK,CACV,yJACA;YACEC,MAAM;QACR;IAEJ;IAEA,IAAIJ,cAAc;QAChBJ,OAAOE,IAAI,CAAC;QACZF,OAAOE,IAAI,CAAC,CAAC;EACf,EAAEN,UAAU,OAAO,CAAC,gBAAgB,EAAEE,UAAUW,WAAW,CAAC,CAAC,CAAC,EAAE;EAChE,EAAEb,UAAU,SAAS,CAAC,6BAA6B,EAAEE,UAAUW,WAAW,CAAC,CAAC,CAAC,EAAE;AACjF,CAAC;IACC;IAEA,IAAIJ,cAAc;QAChB,OAAOF,QAAQL,WAAWQ,YAAYG;IACxC;IAEA,IAAIL,cAAc;QAChB,OAAOD,QAAQL,WAAWW;IAC5B;IAEA,OAAO;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/build/shouldAutoUpdate.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, 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: flag-over-config precedence, the deprecated\n * top-level `autoUpdates` config, and the old/new config conflict.\n * Returns plain facts so each surface (deploy warnings, dry-run checks)\n * 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: 1})\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","resolveAutoUpdates","cliConfig","flags","enabled","Boolean","issue","flag","type","hasOldConfig","hasNewConfig","deployment","autoUpdates","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","currentValue","shouldAutoUpdate","output","error","exit","warn"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AA4BnC;;;;;;;CAOC,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,EAAEf,UAAU,OAAO,CAAC,gBAAgB,EAAEe,aAAa,CAAC,CAAC,EAAE;EACvD,EAAEf,UAAU,SAAS,CAAC,6BAA6B,EAAEe,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,MAAM;gBAAC;gBACvD;YACF;QACA,KAAK;YAAqB;gBACxBF,OAAOG,IAAI,CAACP,0BAA0BP;gBACtCW,OAAOG,IAAI,CAACN,2BAA2BZ,UAAUU,WAAW;gBAC5D;YACF;QACA,KAAK;YAAmB;gBACtBK,OAAOG,IAAI,CAACP,0BAA0BP;gBACtC;YACF;QACA;YAAS;gBACP;YACF;IACF;IAEA,OAAOF;AACT"}
@@ -1,6 +1,8 @@
1
1
  import { CLIError } from '@oclif/core/errors';
2
- import { input } from '@sanity/cli-core/ux';
3
- import { createUserApplication } from '../../services/userApplications.js';
2
+ import { input, spinner } from '@sanity/cli-core/ux';
3
+ import { customAlphabet } from 'nanoid';
4
+ import { createUserApplication as createUserApplicationRequest } from '../../services/userApplications.js';
5
+ import { NO_ORGANIZATION_ID } from '../../util/errorMessages.js';
4
6
  import { deployDebug } from './deployDebug.js';
5
7
  import { normalizeUrl, validateUrl } from './urlUtils.js';
6
8
  // TODO: replace with `Promise.withResolvers()` once it lands in node 22
@@ -18,7 +20,7 @@ function promiseWithResolvers() {
18
20
  };
19
21
  }
20
22
  export async function createStudioUserApplication(options) {
21
- const { projectId, urlType = 'internal' } = options;
23
+ const { projectId, title, urlType = 'internal' } = options;
22
24
  const { promise, resolve } = promiseWithResolvers();
23
25
  const isExternal = urlType === 'external';
24
26
  await input({
@@ -38,10 +40,11 @@ export async function createStudioUserApplication(options) {
38
40
  appHost = inp.replace(/\.sanity\.studio$/i, '');
39
41
  }
40
42
  try {
41
- const response = await createUserApplication({
43
+ const response = await createUserApplicationRequest({
42
44
  appType: 'studio',
43
45
  body: {
44
46
  appHost,
47
+ title,
45
48
  type: 'studio',
46
49
  urlType
47
50
  },
@@ -68,5 +71,53 @@ export async function createStudioUserApplication(options) {
68
71
  });
69
72
  return await promise;
70
73
  }
74
+ export async function createUserApplication(organizationId, title) {
75
+ if (!organizationId) {
76
+ throw new Error(NO_ORGANIZATION_ID);
77
+ }
78
+ const resolvedTitle = title ?? await input({
79
+ message: 'Enter a title for your application:',
80
+ validate: (value)=>value.length > 0 || 'Title is required'
81
+ });
82
+ return tryCreateApp(resolvedTitle, organizationId);
83
+ }
84
+ // appHosts have some restrictions (no uppercase, must start with a letter)
85
+ const generateId = ()=>{
86
+ const letters = 'abcdefghijklmnopqrstuvwxyz';
87
+ const firstChar = customAlphabet(letters, 1)();
88
+ const rest = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789', 11)();
89
+ return `${firstChar}${rest}`;
90
+ };
91
+ const tryCreateApp = async (title, organizationId)=>{
92
+ // we will likely prepend this with an org ID or other parameter in the future
93
+ const appHost = generateId();
94
+ const spin = spinner('Creating application').start();
95
+ try {
96
+ const response = await createUserApplicationRequest({
97
+ appType: 'coreApp',
98
+ body: {
99
+ appHost,
100
+ title,
101
+ type: 'coreApp',
102
+ urlType: 'internal'
103
+ },
104
+ organizationId
105
+ });
106
+ spin.succeed();
107
+ return response;
108
+ } catch (e) {
109
+ // if the name is taken, generate a new one and try again
110
+ if ([
111
+ 402,
112
+ 409
113
+ ].includes(e?.statusCode)) {
114
+ deployDebug('App host taken, retrying with new host');
115
+ return tryCreateApp(title, organizationId);
116
+ }
117
+ spin.fail();
118
+ deployDebug('Error creating core application', e);
119
+ throw e;
120
+ }
121
+ };
71
122
 
72
- //# sourceMappingURL=createStudioUserApplication.js.map
123
+ //# sourceMappingURL=createUserApplication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/deploy/createUserApplication.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {input, spinner} from '@sanity/cli-core/ux'\nimport {customAlphabet} from 'nanoid'\n\nimport {\n createUserApplication as createUserApplicationRequest,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {deployDebug} from './deployDebug.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.js'\n\n// TODO: replace with `Promise.withResolvers()` once it lands in node 22\nfunction promiseWithResolvers<T>() {\n let resolve!: (t: T) => void\n let reject!: (err: unknown) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n return {promise, reject, resolve}\n}\n\ninterface CreateStudioUserApplicationOptions {\n projectId: string\n\n title?: string\n urlType?: 'external' | 'internal'\n}\n\nexport async function createStudioUserApplication(options: CreateStudioUserApplicationOptions) {\n const {projectId, title, urlType = 'internal'} = options\n const {promise, resolve} = promiseWithResolvers<UserApplication>()\n\n const isExternal = urlType === 'external'\n\n await input({\n message: isExternal ? 'Studio URL (https://...):' : 'Studio hostname (<value>.sanity.studio):',\n // if a string is returned here, it is relayed to the user and prompt allows\n // the user to try again until this function returns true\n validate: async (inp: string) => {\n let appHost: string\n\n if (isExternal) {\n const normalized = normalizeUrl(inp)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n return validation\n }\n appHost = normalized\n } else {\n appHost = inp.replace(/\\.sanity\\.studio$/i, '')\n }\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'studio',\n body: {appHost, title, type: 'studio', urlType},\n projectId,\n })\n resolve(response)\n return true\n } catch (e) {\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 return e?.response?.body?.message || 'Bad request' // just in case\n }\n\n deployDebug('Error creating user application', e)\n // otherwise, it's a fatal error\n throw new CLIError('Error creating user application', {exit: 1})\n }\n },\n })\n\n return await promise\n}\n\nexport async function createUserApplication(\n organizationId?: string,\n title?: string,\n): Promise<UserApplicationResolved> {\n if (!organizationId) {\n throw new Error(NO_ORGANIZATION_ID)\n }\n\n const resolvedTitle =\n title ??\n (await input({\n message: 'Enter a title for your application:',\n validate: (value: string) => value.length > 0 || 'Title is required',\n }))\n\n return tryCreateApp(resolvedTitle, organizationId)\n}\n\n// appHosts have some restrictions (no uppercase, must start with a letter)\nconst generateId = () => {\n const letters = 'abcdefghijklmnopqrstuvwxyz'\n const firstChar = customAlphabet(letters, 1)()\n const rest = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789', 11)()\n return `${firstChar}${rest}`\n}\n\nconst tryCreateApp = async (title: string, organizationId: string) => {\n // we will likely prepend this with an org ID or other parameter in the future\n const appHost = generateId()\n\n const spin = spinner('Creating application').start()\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'coreApp',\n body: {appHost, title, type: 'coreApp', urlType: 'internal'},\n organizationId,\n })\n\n spin.succeed()\n return response\n } catch (e) {\n // if the name is taken, generate a new one and try again\n if ([402, 409].includes(e?.statusCode)) {\n deployDebug('App host taken, retrying with new host')\n return tryCreateApp(title, organizationId)\n }\n\n spin.fail()\n\n deployDebug('Error creating core application', e)\n throw e\n }\n}\n"],"names":["CLIError","input","spinner","customAlphabet","createUserApplication","createUserApplicationRequest","NO_ORGANIZATION_ID","deployDebug","normalizeUrl","validateUrl","promiseWithResolvers","resolve","reject","promise","Promise","res","rej","createStudioUserApplication","options","projectId","title","urlType","isExternal","message","validate","inp","appHost","normalized","validation","replace","response","appType","body","type","e","includes","statusCode","exit","organizationId","Error","resolvedTitle","value","length","tryCreateApp","generateId","letters","firstChar","rest","spin","start","succeed","fail"],"mappings":"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"}