@sanity/cli 7.18.0 → 8.0.1
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 +74 -4
- package/dist/SanityHelp.js +1 -35
- package/dist/SanityHelp.js.map +1 -1
- package/dist/actions/assets/assetFileError.js +9 -0
- package/dist/actions/assets/assetFileError.js.map +1 -0
- package/dist/actions/assets/uploadAssetFromFile.js +40 -0
- package/dist/actions/assets/uploadAssetFromFile.js.map +1 -0
- package/dist/actions/assets/uploadAssetWithProgress.js +76 -0
- package/dist/actions/assets/uploadAssetWithProgress.js.map +1 -0
- package/dist/actions/deploy/deployApp.js +39 -44
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployChecks.js +21 -13
- package/dist/actions/deploy/deployChecks.js.map +1 -1
- package/dist/actions/deploy/deployRunner.js +8 -7
- package/dist/actions/deploy/deployRunner.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +55 -35
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/deploy/deploymentPlan.js +17 -29
- package/dist/actions/deploy/deploymentPlan.js.map +1 -1
- package/dist/actions/deploy/resolveDeployTarget.js +2 -8
- package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
- package/dist/actions/dev/servers/getDevServerConfig.js +2 -8
- package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
- package/dist/actions/dev/servers/startStudioDevServer.js +7 -1
- package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
- package/dist/actions/init/bootstrapRemoteTemplate.js +2 -2
- package/dist/actions/init/bootstrapRemoteTemplate.js.map +1 -1
- package/dist/actions/init/sdkAppDependencies.js +1 -1
- package/dist/actions/init/sdkAppDependencies.js.map +1 -1
- package/dist/actions/init/studioDependencies.js +1 -1
- package/dist/actions/init/studioDependencies.js.map +1 -1
- package/dist/actions/schema/listSchemas.js +1 -1
- package/dist/actions/schema/listSchemas.js.map +1 -1
- package/dist/actions/tokens/constants.js +2 -2
- package/dist/actions/tokens/constants.js.map +1 -1
- package/dist/actions/tokens/expiry.js +35 -0
- package/dist/actions/tokens/expiry.js.map +1 -0
- package/dist/actions/tokens/types.js.map +1 -1
- package/dist/actions/tokens/validateRole.js +5 -2
- package/dist/actions/tokens/validateRole.js.map +1 -1
- package/dist/actions/typegen/count.js +6 -0
- package/dist/actions/typegen/count.js.map +1 -0
- package/dist/actions/typegen/formatPath.js +5 -0
- package/dist/actions/typegen/formatPath.js.map +1 -0
- package/dist/actions/typegen/percent.js +8 -0
- package/dist/actions/typegen/percent.js.map +1 -0
- package/dist/actions/typegen/renderTypegenProgress.js +88 -0
- package/dist/actions/typegen/renderTypegenProgress.js.map +1 -0
- package/dist/actions/undeploy/adapters.js +6 -9
- package/dist/actions/undeploy/adapters.js.map +1 -1
- package/dist/actions/undeploy/runUndeploy.js +12 -4
- package/dist/actions/undeploy/runUndeploy.js.map +1 -1
- package/dist/actions/undeploy/undeployPlan.js +6 -14
- package/dist/actions/undeploy/undeployPlan.js.map +1 -1
- package/dist/commands/assets/upload.js +160 -0
- package/dist/commands/assets/upload.js.map +1 -0
- package/dist/commands/backups/list.js +1 -1
- package/dist/commands/backups/list.js.map +1 -1
- package/dist/commands/datasets/copy.js +1 -1
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/commands/login.js +2 -8
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/mcp/configure.js.map +1 -1
- package/dist/commands/migrations/list.js +1 -1
- package/dist/commands/migrations/list.js.map +1 -1
- package/dist/commands/migrations/run.js +67 -3
- package/dist/commands/migrations/run.js.map +1 -1
- package/dist/commands/new.js +4 -3
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/organizations/list.js +1 -1
- package/dist/commands/organizations/list.js.map +1 -1
- package/dist/commands/projects/list.js +39 -12
- package/dist/commands/projects/list.js.map +1 -1
- package/dist/commands/projects/unclaimed.js +39 -33
- package/dist/commands/projects/unclaimed.js.map +1 -1
- package/dist/commands/tokens/create.js +92 -7
- package/dist/commands/tokens/create.js.map +1 -1
- package/dist/commands/tokens/delete.js +2 -2
- package/dist/commands/tokens/delete.js.map +1 -1
- package/dist/commands/tokens/list.js +12 -11
- package/dist/commands/tokens/list.js.map +1 -1
- package/dist/commands/tokens/rotate.js +95 -0
- package/dist/commands/tokens/rotate.js.map +1 -0
- package/dist/commands/typegen/generate.js +222 -0
- package/dist/commands/typegen/generate.js.map +1 -0
- package/dist/commands/users/list.js +8 -8
- package/dist/commands/users/list.js.map +1 -1
- package/dist/exports/_internal.d.ts +29 -0
- package/dist/exports/_internal.js +1 -0
- package/dist/exports/_internal.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/exports/invokeSanityCli/help.js +4 -0
- package/dist/exports/invokeSanityCli/help.js.map +1 -1
- package/dist/exports/invokeSanityCli/index.js +2 -0
- package/dist/exports/invokeSanityCli/index.js.map +1 -1
- package/dist/hooks/commandNotFound/topicAliases.js +13 -40
- package/dist/hooks/commandNotFound/topicAliases.js.map +1 -1
- package/dist/hooks/prerun/setupTelemetry.js +3 -2
- package/dist/hooks/prerun/setupTelemetry.js.map +1 -1
- package/dist/server/vite/plugin-typegen.js +4 -16
- package/dist/server/vite/plugin-typegen.js.map +1 -1
- package/dist/services/assets.js +46 -0
- package/dist/services/assets.js.map +1 -0
- package/dist/services/tokens.js +81 -31
- package/dist/services/tokens.js.map +1 -1
- package/dist/topicAliases.js +43 -0
- package/dist/topicAliases.js.map +1 -1
- package/dist/util/parseArguments.js +7 -2
- package/dist/util/parseArguments.js.map +1 -1
- package/dist/util/readTokenFromStdin.js +17 -0
- package/dist/util/readTokenFromStdin.js.map +1 -0
- package/dist/util/responsiveTable.js +97 -0
- package/dist/util/responsiveTable.js.map +1 -0
- package/dist/util/telemetry/commandTelemetry.js +34 -0
- package/dist/util/telemetry/commandTelemetry.js.map +1 -0
- package/dist/util/unclaimedProjects.js +10 -0
- package/dist/util/unclaimedProjects.js.map +1 -1
- package/oclif.config.js +2 -4
- package/oclif.manifest.json +688 -476
- package/package.json +12 -10
- package/templates/shopify/components/inputs/ShopifyMetafield.tsx +20 -0
- package/templates/shopify/docs/features.md +24 -0
- package/templates/shopify/schemaTypes/index.ts +2 -0
- package/templates/shopify/schemaTypes/objects/shopify/shopifyCollectionType.ts +18 -1
- package/templates/shopify/schemaTypes/objects/shopify/shopifyMetafieldType.ts +47 -0
- package/templates/shopify/schemaTypes/objects/shopify/shopifyProductType.ts +17 -0
- package/templates/shopify/utils/formatMetafieldValue.ts +30 -0
- package/templates/shopify-online-storefront/components/inputs/ShopifyMetafield.tsx +22 -0
- package/templates/shopify-online-storefront/schemaTypes/index.ts +4 -0
- package/templates/shopify-online-storefront/schemaTypes/objects/shop.ts +16 -0
- package/templates/shopify-online-storefront/schemaTypes/objects/shopifyCollection.ts +19 -0
- package/templates/shopify-online-storefront/schemaTypes/objects/shopifyMetafield.ts +53 -0
- package/templates/shopify-online-storefront/schemaTypes/objects/shopifyProduct.ts +19 -0
- package/templates/shopify-online-storefront/utils/formatMetafieldValue.ts +30 -0
package/dist/commands/login.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { text } from 'node:stream/consumers';
|
|
2
1
|
import { Flags } from '@oclif/core';
|
|
3
2
|
import { exitCodes, SanityCommand } from '@sanity/cli-core';
|
|
4
3
|
import { login } from '../actions/auth/login/login.js';
|
|
5
4
|
import { LOGIN_PROVIDER_IDS } from '../actions/auth/login/loginInstructions.js';
|
|
5
|
+
import { readTokenFromStdin } from '../util/readTokenFromStdin.js';
|
|
6
6
|
export class LoginCommand extends SanityCommand {
|
|
7
7
|
static description = 'Log in to your Sanity account';
|
|
8
8
|
static examples = [
|
|
@@ -73,7 +73,7 @@ export class LoginCommand extends SanityCommand {
|
|
|
73
73
|
const { flags } = await this.parse(LoginCommand);
|
|
74
74
|
const { 'sso-provider': ssoProvider, 'with-token': withToken, ...loginFlags } = flags;
|
|
75
75
|
try {
|
|
76
|
-
const token = withToken ? await readTokenFromStdin() : undefined;
|
|
76
|
+
const token = withToken ? await readTokenFromStdin('Token is required on standard input. Run `sanity login --with-token < token.txt`.') : undefined;
|
|
77
77
|
await login({
|
|
78
78
|
...loginFlags,
|
|
79
79
|
output: this.output,
|
|
@@ -90,11 +90,5 @@ export class LoginCommand extends SanityCommand {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
async function readTokenFromStdin() {
|
|
94
|
-
if (process.stdin.isTTY) {
|
|
95
|
-
throw new Error('Token is required on standard input. Run `sanity login --with-token < token.txt`.');
|
|
96
|
-
}
|
|
97
|
-
return text(process.stdin);
|
|
98
|
-
}
|
|
99
93
|
|
|
100
94
|
//# sourceMappingURL=login.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/login.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../src/commands/login.ts"],"sourcesContent":["import {Command, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\n\nimport {login} from '../actions/auth/login/login.js'\nimport {LOGIN_PROVIDER_IDS} from '../actions/auth/login/loginInstructions.js'\nimport {readTokenFromStdin} from '../util/readTokenFromStdin.js'\n\nexport class LoginCommand extends SanityCommand<typeof LoginCommand> {\n static override description = 'Log in to your Sanity account'\n static override examples: Array<Command.Example> = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Log in using default settings',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --with-token < token.txt',\n description: 'Log in using a token from standard input',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --provider github --no-open',\n description: 'Login with GitHub provider, but do not open a browser window automatically',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sso my-organization',\n description: 'Log in using Single Sign-On with the \"my-organization\" slug',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> --sso my-organization --sso-provider \"Okta SSO\"',\n description: 'Log in using a specific SSO provider within an organization',\n },\n ]\n static override flags = {\n 'with-token': Flags.boolean({\n description: 'Read token from standard input',\n exclusive: ['provider', 'sso'],\n }),\n // eslint-disable-next-line perfectionist/sort-objects -- Keep token login first in generated usage.\n experimental: Flags.boolean({\n default: false,\n hidden: true,\n }),\n open: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Open a browser window to log in (`--no-open` only prints URL)',\n }),\n provider: Flags.string({\n description: `Log in using a provider ID (${LOGIN_PROVIDER_IDS.join(', ')})`,\n exclusive: ['sso', 'with-token'],\n helpValue: '<providerId>',\n }),\n sso: Flags.string({\n description: 'Log in using Single Sign-On, using the given organization slug',\n exclusive: ['provider', 'with-token'],\n helpValue: '<slug>',\n }),\n 'sso-provider': Flags.string({\n dependsOn: ['sso'],\n description: 'Select a specific SSO provider by name (use with --sso)',\n helpValue: '<name>',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(LoginCommand)\n const {'sso-provider': ssoProvider, 'with-token': withToken, ...loginFlags} = flags\n\n try {\n const token = withToken\n ? await readTokenFromStdin(\n 'Token is required on standard input. Run `sanity login --with-token < token.txt`.',\n )\n : undefined\n\n await login({\n ...loginFlags,\n output: this.output,\n ssoProvider,\n telemetry: this.telemetry,\n token,\n })\n this.log('Login successful')\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n this.error(`Login failed: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","login","LOGIN_PROVIDER_IDS","readTokenFromStdin","LoginCommand","description","examples","command","flags","boolean","exclusive","experimental","default","hidden","open","allowNo","provider","string","join","helpValue","sso","dependsOn","run","parse","ssoProvider","withToken","loginFlags","token","undefined","output","telemetry","log","error","message","Error","String","exit","RUNTIME_ERROR"],"mappings":"AAAA,SAAiBA,KAAK,QAAO,cAAa;AAE1C,SAAQC,SAAS,EAAEC,aAAa,QAAO,mBAAkB;AAEzD,SAAQC,KAAK,QAAO,iCAAgC;AACpD,SAAQC,kBAAkB,QAAO,6CAA4C;AAC7E,SAAQC,kBAAkB,QAAO,gCAA+B;AAEhE,OAAO,MAAMC,qBAAqBJ;IAChC,OAAgBK,cAAc,gCAA+B;IAC7D,OAAgBC,WAAmC;QACjD;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SACE;YACFF,aAAa;QACf;KACD,CAAA;IACD,OAAgBG,QAAQ;QACtB,cAAcV,MAAMW,OAAO,CAAC;YAC1BJ,aAAa;YACbK,WAAW;gBAAC;gBAAY;aAAM;QAChC;QACA,oGAAoG;QACpGC,cAAcb,MAAMW,OAAO,CAAC;YAC1BG,SAAS;YACTC,QAAQ;QACV;QACAC,MAAMhB,MAAMW,OAAO,CAAC;YAClBM,SAAS;YACTH,SAAS;YACTP,aAAa;QACf;QACAW,UAAUlB,MAAMmB,MAAM,CAAC;YACrBZ,aAAa,CAAC,4BAA4B,EAAEH,mBAAmBgB,IAAI,CAAC,MAAM,CAAC,CAAC;YAC5ER,WAAW;gBAAC;gBAAO;aAAa;YAChCS,WAAW;QACb;QACAC,KAAKtB,MAAMmB,MAAM,CAAC;YAChBZ,aAAa;YACbK,WAAW;gBAAC;gBAAY;aAAa;YACrCS,WAAW;QACb;QACA,gBAAgBrB,MAAMmB,MAAM,CAAC;YAC3BI,WAAW;gBAAC;aAAM;YAClBhB,aAAa;YACbc,WAAW;QACb;IACF,EAAqB;IAErB,MAAaG,MAAqB;QAChC,MAAM,EAACd,KAAK,EAAC,GAAG,MAAM,IAAI,CAACe,KAAK,CAACnB;QACjC,MAAM,EAAC,gBAAgBoB,WAAW,EAAE,cAAcC,SAAS,EAAE,GAAGC,YAAW,GAAGlB;QAE9E,IAAI;YACF,MAAMmB,QAAQF,YACV,MAAMtB,mBACJ,uFAEFyB;YAEJ,MAAM3B,MAAM;gBACV,GAAGyB,UAAU;gBACbG,QAAQ,IAAI,CAACA,MAAM;gBACnBL;gBACAM,WAAW,IAAI,CAACA,SAAS;gBACzBH;YACF;YACA,IAAI,CAACI,GAAG,CAAC;QACX,EAAE,OAAOC,OAAO;YACd,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAGE,OAAOH;YAChE,IAAI,CAACA,KAAK,CAAC,CAAC,cAAc,EAAEC,SAAS,EAAE;gBAACG,MAAMrC,UAAUsC,aAAa;YAAA;QACvE;IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/mcp/configure.ts"],"sourcesContent":["import {exitCodes, isInteractive, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage, toError} from '@sanity/cli-core/errors'\n\nimport {ensureAuthenticated} from '../../actions/auth/ensureAuthenticated.js'\nimport {setupMCP} from '../../actions/mcp/setupMCP.js'\nimport {LoginError} from '../../errors/LoginError.js'\nimport {MCPConfigureTrace} from '../../telemetry/mcp.telemetry.js'\n\nconst debug = subdebug('mcp:configure')\n\nexport class ConfigureMcpCommand extends SanityCommand<typeof ConfigureMcpCommand> {\n static override description =\n 'Configure Sanity MCP server for AI editors (Antigravity, Claude Code, Cline, Cline CLI, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, MCPorter, OpenCode, VS Code, VS Code Insiders, Zed)'\n
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/mcp/configure.ts"],"sourcesContent":["import {exitCodes, isInteractive, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage, toError} from '@sanity/cli-core/errors'\n\nimport {ensureAuthenticated} from '../../actions/auth/ensureAuthenticated.js'\nimport {setupMCP} from '../../actions/mcp/setupMCP.js'\nimport {LoginError} from '../../errors/LoginError.js'\nimport {MCPConfigureTrace} from '../../telemetry/mcp.telemetry.js'\n\nconst debug = subdebug('mcp:configure')\n\nexport class ConfigureMcpCommand extends SanityCommand<typeof ConfigureMcpCommand> {\n static override description =\n 'Configure Sanity MCP server for AI editors (Antigravity, Claude Code, Cline, Cline CLI, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, MCPorter, OpenCode, VS Code, VS Code Insiders, Zed)'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Configure Sanity MCP server for detected AI editors',\n },\n ]\n\n public async run(): Promise<void> {\n const trace = this.telemetry.trace(MCPConfigureTrace)\n trace.start()\n\n try {\n await ensureAuthenticated({output: this.output, telemetry: this.telemetry})\n } catch (error) {\n debug('Authentication check failed: %O', error)\n trace.error(toError(error))\n\n if (error instanceof LoginError) {\n this.error(\n `Failed to verify authentication credentials: ${error.message}. Try running \\`sanity login\\`.`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n this.error(`Failed to check authentication: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n try {\n const mcpResult = await setupMCP({\n explicit: true,\n mode: isInteractive() ? 'prompt' : 'auto',\n output: this.output,\n skillsMode: 'skip',\n })\n\n trace.log({\n configuredEditors: mcpResult.configuredEditors,\n detectedEditors: mcpResult.detectedEditors,\n })\n\n if (mcpResult.error) {\n trace.error(mcpResult.error)\n } else {\n trace.complete()\n }\n } catch (error) {\n trace.error(toError(error))\n this.error(getErrorMessage(error), {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n}\n"],"names":["exitCodes","isInteractive","SanityCommand","subdebug","getErrorMessage","toError","ensureAuthenticated","setupMCP","LoginError","MCPConfigureTrace","debug","ConfigureMcpCommand","description","examples","command","run","trace","telemetry","start","output","error","message","exit","RUNTIME_ERROR","mcpResult","explicit","mode","skillsMode","log","configuredEditors","detectedEditors","complete"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,aAAa,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AAClF,SAAQC,eAAe,EAAEC,OAAO,QAAO,0BAAyB;AAEhE,SAAQC,mBAAmB,QAAO,4CAA2C;AAC7E,SAAQC,QAAQ,QAAO,gCAA+B;AACtD,SAAQC,UAAU,QAAO,6BAA4B;AACrD,SAAQC,iBAAiB,QAAO,mCAAkC;AAElE,MAAMC,QAAQP,SAAS;AAEvB,OAAO,MAAMQ,4BAA4BT;IACvC,OAAgBU,cACd,iMAAgM;IAClM,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,MAAaG,MAAqB;QAChC,MAAMC,QAAQ,IAAI,CAACC,SAAS,CAACD,KAAK,CAACP;QACnCO,MAAME,KAAK;QAEX,IAAI;YACF,MAAMZ,oBAAoB;gBAACa,QAAQ,IAAI,CAACA,MAAM;gBAAEF,WAAW,IAAI,CAACA,SAAS;YAAA;QAC3E,EAAE,OAAOG,OAAO;YACdV,MAAM,mCAAmCU;YACzCJ,MAAMI,KAAK,CAACf,QAAQe;YAEpB,IAAIA,iBAAiBZ,YAAY;gBAC/B,IAAI,CAACY,KAAK,CACR,CAAC,6CAA6C,EAAEA,MAAMC,OAAO,CAAC,+BAA+B,CAAC,EAC9F;oBAACC,MAAMtB,UAAUuB,aAAa;gBAAA;YAElC;YAEA,IAAI,CAACH,KAAK,CAAC,CAAC,gCAAgC,EAAEhB,gBAAgBgB,QAAQ,EAAE;gBACtEE,MAAMtB,UAAUuB,aAAa;YAC/B;QACF;QAEA,IAAI;YACF,MAAMC,YAAY,MAAMjB,SAAS;gBAC/BkB,UAAU;gBACVC,MAAMzB,kBAAkB,WAAW;gBACnCkB,QAAQ,IAAI,CAACA,MAAM;gBACnBQ,YAAY;YACd;YAEAX,MAAMY,GAAG,CAAC;gBACRC,mBAAmBL,UAAUK,iBAAiB;gBAC9CC,iBAAiBN,UAAUM,eAAe;YAC5C;YAEA,IAAIN,UAAUJ,KAAK,EAAE;gBACnBJ,MAAMI,KAAK,CAACI,UAAUJ,KAAK;YAC7B,OAAO;gBACLJ,MAAMe,QAAQ;YAChB;QACF,EAAE,OAAOX,OAAO;YACdJ,MAAMI,KAAK,CAACf,QAAQe;YACpB,IAAI,CAACA,KAAK,CAAChB,gBAAgBgB,QAAQ;gBAACE,MAAMtB,UAAUuB,aAAa;YAAA;QACnE;IACF;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { styleText } from 'node:util';
|
|
2
2
|
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
-
import { Table } from 'console-table-printer';
|
|
4
3
|
import { resolveMigrations } from '../../actions/migration/resolveMigrations.js';
|
|
4
|
+
import { Table } from '../../util/responsiveTable.js';
|
|
5
5
|
const listMigrationDebug = subdebug('migration:list');
|
|
6
6
|
export class ListMigrationCommand extends SanityCommand {
|
|
7
7
|
static description = 'List available migrations';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/migrations/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/migrations/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\n\nimport {resolveMigrations} from '../../actions/migration/resolveMigrations.js'\nimport {Table} from '../../util/responsiveTable.js'\n\nconst listMigrationDebug = subdebug('migration:list')\n\nexport class ListMigrationCommand extends SanityCommand<typeof ListMigrationCommand> {\n static override description = 'List available migrations'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all available migrations in the project',\n },\n ]\n\n static override hiddenAliases = ['migration:list']\n\n public async run(): Promise<void> {\n const {directory: workDir} = await this.getProjectRoot()\n\n try {\n const migrations = await resolveMigrations(workDir)\n\n if (migrations.length === 0) {\n this.log('No migrations found in migrations folder of the project')\n this.log(\n `\\nRun ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`,\n )\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'title', title: 'Title'},\n ],\n title: `Found ${migrations.length} migrations in project`,\n })\n\n for (const definedMigration of migrations) {\n table.addRow({id: definedMigration.id, title: definedMigration.migration.title})\n }\n this.log(table.render())\n this.log('\\nRun `sanity migration run <ID>` to run a migration')\n listMigrationDebug(`Successfully listed ${migrations.length} migrations`)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n this.log('No migrations folder found in the project')\n this.log(\n `\\nRun ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`,\n )\n return\n }\n listMigrationDebug('Failed to list migrations:', error)\n this.error(\n `List migrations failed: ${error instanceof Error ? error.message : String(error)}`,\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n }\n}\n"],"names":["styleText","exitCodes","SanityCommand","subdebug","resolveMigrations","Table","listMigrationDebug","ListMigrationCommand","description","examples","command","hiddenAliases","run","directory","workDir","getProjectRoot","migrations","length","log","table","columns","alignment","name","title","definedMigration","addRow","id","migration","render","error","code","Error","message","String","exit","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AAEnE,SAAQC,iBAAiB,QAAO,+CAA8C;AAC9E,SAAQC,KAAK,QAAO,gCAA+B;AAEnD,MAAMC,qBAAqBH,SAAS;AAEpC,OAAO,MAAMI,6BAA6BL;IACxC,OAAgBM,cAAc,4BAA2B;IAEzD,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,OAAgBG,gBAAgB;QAAC;KAAiB,CAAA;IAElD,MAAaC,MAAqB;QAChC,MAAM,EAACC,WAAWC,OAAO,EAAC,GAAG,MAAM,IAAI,CAACC,cAAc;QAEtD,IAAI;YACF,MAAMC,aAAa,MAAMZ,kBAAkBU;YAE3C,IAAIE,WAAWC,MAAM,KAAK,GAAG;gBAC3B,IAAI,CAACC,GAAG,CAAC;gBACT,IAAI,CAACA,GAAG,CACN,CAAC,MAAM,EAAElB,UAAU,SAAS,oCAAoC,0BAA0B,CAAC;gBAE7F;YACF;YAEA,MAAMmB,QAAQ,IAAId,MAAM;gBACtBe,SAAS;oBACP;wBAACC,WAAW;wBAAQC,MAAM;wBAAMC,OAAO;oBAAI;oBAC3C;wBAACF,WAAW;wBAAQC,MAAM;wBAASC,OAAO;oBAAO;iBAClD;gBACDA,OAAO,CAAC,MAAM,EAAEP,WAAWC,MAAM,CAAC,sBAAsB,CAAC;YAC3D;YAEA,KAAK,MAAMO,oBAAoBR,WAAY;gBACzCG,MAAMM,MAAM,CAAC;oBAACC,IAAIF,iBAAiBE,EAAE;oBAAEH,OAAOC,iBAAiBG,SAAS,CAACJ,KAAK;gBAAA;YAChF;YACA,IAAI,CAACL,GAAG,CAACC,MAAMS,MAAM;YACrB,IAAI,CAACV,GAAG,CAAC;YACTZ,mBAAmB,CAAC,oBAAoB,EAAEU,WAAWC,MAAM,CAAC,WAAW,CAAC;QAC1E,EAAE,OAAOY,OAAO;YACd,IAAI,AAACA,MAAgCC,IAAI,KAAK,UAAU;gBACtD,IAAI,CAACZ,GAAG,CAAC;gBACT,IAAI,CAACA,GAAG,CACN,CAAC,MAAM,EAAElB,UAAU,SAAS,oCAAoC,0BAA0B,CAAC;gBAE7F;YACF;YACAM,mBAAmB,8BAA8BuB;YACjD,IAAI,CAACA,KAAK,CACR,CAAC,wBAAwB,EAAEA,iBAAiBE,QAAQF,MAAMG,OAAO,GAAGC,OAAOJ,QAAQ,EACnF;gBACEK,MAAMjC,UAAUkC,aAAa;YAC/B;QAEJ;IACF;AACF"}
|
|
@@ -3,14 +3,33 @@ import { styleText } from 'node:util';
|
|
|
3
3
|
import { Args, Flags } from '@oclif/core';
|
|
4
4
|
import { exitCodes, getProjectCliClient, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
5
5
|
import { confirm, spinner } from '@sanity/cli-core/ux';
|
|
6
|
-
import { DEFAULT_MUTATION_CONCURRENCY, dryRun, MAX_MUTATION_CONCURRENCY, run } from '@sanity/migrate';
|
|
7
|
-
import { Table } from 'console-table-printer';
|
|
6
|
+
import { DEFAULT_MUTATION_CONCURRENCY, dryRun, MAX_MUTATION_CONCURRENCY, run, UnknownTransactionOutcomeError } from '@sanity/migrate';
|
|
8
7
|
import { DEFAULT_API_VERSION, MIGRATIONS_DIRECTORY } from '../../actions/migration/constants.js';
|
|
9
8
|
import { ensureApiVersionFormat } from '../../actions/migration/ensureApiVersionFormat.js';
|
|
10
9
|
import { prettyFormat } from '../../actions/migration/prettyMutationFormatter.js';
|
|
11
10
|
import { resolveMigrations } from '../../actions/migration/resolveMigrations.js';
|
|
12
11
|
import { isLoadableMigrationScript, resolveMigrationScript } from '../../actions/migration/resolveMigrationScript.js';
|
|
12
|
+
import { Table } from '../../util/responsiveTable.js';
|
|
13
13
|
const runMigrationDebug = subdebug('migration:run');
|
|
14
|
+
/**
|
|
15
|
+
* Renders the `cause` chain of an error the way oclif's own error printer would.
|
|
16
|
+
*
|
|
17
|
+
* Used when printing an error ourselves to bypass oclif's hard word wrapping:
|
|
18
|
+
* the underlying transport error (a timeout, a dropped connection) is the part
|
|
19
|
+
* that explains _why_ the outcome is unknown, so it should not be dropped just
|
|
20
|
+
* because the top-level message is printed separately.
|
|
21
|
+
*/ function formatCauseChain(error) {
|
|
22
|
+
const lines = [];
|
|
23
|
+
let cause = error instanceof Error ? error.cause : undefined;
|
|
24
|
+
while(cause instanceof Error){
|
|
25
|
+
lines.push(`Caused by: ${cause.name}: ${cause.message}`);
|
|
26
|
+
if ('code' in cause && typeof cause.code === 'string') {
|
|
27
|
+
lines.push(`Code: ${cause.code}`);
|
|
28
|
+
}
|
|
29
|
+
cause = cause.cause;
|
|
30
|
+
}
|
|
31
|
+
return lines;
|
|
32
|
+
}
|
|
14
33
|
export class RunMigrationCommand extends SanityCommand {
|
|
15
34
|
static args = {
|
|
16
35
|
id: Args.string({
|
|
@@ -213,12 +232,36 @@ export class RunMigrationCommand extends SanityCommand {
|
|
|
213
232
|
await this.promptConfirmMigrate(apiConfig);
|
|
214
233
|
}
|
|
215
234
|
const spin = spinner(`Running migration "${id}"`).start();
|
|
235
|
+
const onProgress = this.createProgress(spin, flags, id, dry, apiConfig, migration);
|
|
236
|
+
let lastProgress;
|
|
216
237
|
try {
|
|
217
238
|
await run({
|
|
218
239
|
api: apiConfig,
|
|
219
240
|
concurrency,
|
|
220
|
-
onProgress:
|
|
241
|
+
onProgress: (progress)=>{
|
|
242
|
+
lastProgress = progress;
|
|
243
|
+
onProgress(progress);
|
|
244
|
+
}
|
|
221
245
|
}, migration);
|
|
246
|
+
} catch (err) {
|
|
247
|
+
// ora's `stop()` clears the spinner region, taking the multi-line progress
|
|
248
|
+
// block with it. Persist a failure summary first, so the transaction counts
|
|
249
|
+
// (the only record of what was committed before the failure) survive.
|
|
250
|
+
this.persistFailureSummary(spin, flags, id, apiConfig, lastProgress);
|
|
251
|
+
if (err instanceof UnknownTransactionOutcomeError) {
|
|
252
|
+
// oclif hard-wraps error messages, which splits the transaction log URLs
|
|
253
|
+
// across lines and makes them impossible to copy. Print the recovery
|
|
254
|
+
// instructions ourselves and rethrow something short for the exit code.
|
|
255
|
+
this.logToStderr(err.message);
|
|
256
|
+
for (const line of formatCauseChain(err)){
|
|
257
|
+
this.logToStderr(line);
|
|
258
|
+
}
|
|
259
|
+
const count = err.transactionIds.length;
|
|
260
|
+
this.error(`Migration "${id}" failed: the ${count === 1 ? 'outcome' : 'outcomes'} of ${count} ${count === 1 ? 'transaction' : 'transactions'} ${count === 1 ? 'is' : 'are'} unknown. See the transaction log details above.`, {
|
|
261
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
throw err;
|
|
222
265
|
} finally{
|
|
223
266
|
spin.stop();
|
|
224
267
|
}
|
|
@@ -286,6 +329,27 @@ export class RunMigrationCommand extends SanityCommand {
|
|
|
286
329
|
}));
|
|
287
330
|
}
|
|
288
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* Persist the last reported progress with a failure marker.
|
|
334
|
+
*
|
|
335
|
+
* Only the `progress.done` path finalizes the spinner on its own, so without
|
|
336
|
+
* this the entire progress block is wiped when the migration fails partway.
|
|
337
|
+
*/ persistFailureSummary(progressSpinner, flags, id, apiConfig, progress) {
|
|
338
|
+
// With `--no-progress` the spinner was already stopped and nothing was ever
|
|
339
|
+
// rendered; a `done` progress event has already persisted its own summary.
|
|
340
|
+
if (!flags.progress || !progress || progress.done) return;
|
|
341
|
+
progressSpinner.text = `Migration "${id}" failed.
|
|
342
|
+
|
|
343
|
+
Project id: ${styleText('bold', apiConfig.projectId)}
|
|
344
|
+
Dataset: ${styleText('bold', apiConfig.dataset)}
|
|
345
|
+
|
|
346
|
+
${progress.documents} documents processed.
|
|
347
|
+
${progress.mutations} mutations generated.
|
|
348
|
+
${styleText('green', String(progress.completedTransactions.length))} transactions committed.`;
|
|
349
|
+
progressSpinner.stopAndPersist({
|
|
350
|
+
symbol: styleText('red', '✖')
|
|
351
|
+
});
|
|
352
|
+
}
|
|
289
353
|
async promptConfirmMigrate(apiConfig) {
|
|
290
354
|
const response = await confirm({
|
|
291
355
|
message: `This migration will run on the ${styleText([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/migrations/run.ts"],"sourcesContent":["import path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, getProjectCliClient, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {\n type APIConfig,\n DEFAULT_MUTATION_CONCURRENCY,\n dryRun,\n MAX_MUTATION_CONCURRENCY,\n type Migration,\n type MigrationProgress,\n run,\n} from '@sanity/migrate'\nimport {Table} from 'console-table-printer'\n\nimport {DEFAULT_API_VERSION, MIGRATIONS_DIRECTORY} from '../../actions/migration/constants.js'\nimport {ensureApiVersionFormat} from '../../actions/migration/ensureApiVersionFormat.js'\nimport {prettyFormat} from '../../actions/migration/prettyMutationFormatter.js'\nimport {resolveMigrations} from '../../actions/migration/resolveMigrations.js'\nimport {\n isLoadableMigrationScript,\n resolveMigrationScript,\n} from '../../actions/migration/resolveMigrationScript.js'\n\nconst runMigrationDebug = subdebug('migration:run')\n\nexport type RunMigrationFlags = RunMigrationCommand['flags']\n\nexport class RunMigrationCommand extends SanityCommand<typeof RunMigrationCommand> {\n static override args = {\n id: Args.string({\n description: 'ID',\n required: false,\n }),\n }\n\n static override description = 'Run a migration against a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> <id>',\n description: 'dry run the migration',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> <id> --no-dry-run --project xyz --dataset staging',\n description: 'execute the migration against a dataset',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> <id> --from-export=production.tar.gz --no-dry-run --project xyz --dataset staging',\n description: 'execute the migration using a dataset export as the source',\n },\n ]\n\n static override flags = {\n 'api-version': Flags.string({\n description: `API version to use when migrating. Defaults to ${DEFAULT_API_VERSION}.`,\n }),\n concurrency: Flags.integer({\n default: DEFAULT_MUTATION_CONCURRENCY,\n description: `How many mutation requests to run in parallel. Must be between 1 and ${MAX_MUTATION_CONCURRENCY}. Default: ${DEFAULT_MUTATION_CONCURRENCY}.`,\n }),\n confirm: Flags.boolean({\n allowNo: true,\n default: true,\n description:\n 'Prompt for confirmation before running the migration (default: true). Use --no-confirm to skip.',\n }),\n dataset: Flags.string({\n description:\n 'Dataset to migrate. Defaults to the dataset configured in your Sanity CLI config.',\n }),\n 'dry-run': Flags.boolean({\n allowNo: true,\n default: true,\n description:\n 'By default the migration runs in dry mode. Use --no-dry-run to migrate dataset.',\n }),\n 'from-export': Flags.string({\n description:\n 'Use a local dataset export as source for migration instead of calling the Sanity API. Note: this is only supported for dry runs.',\n }),\n progress: Flags.boolean({\n allowNo: true,\n default: true,\n description:\n 'Display progress during migration (default: true). Use --no-progress to hide output.',\n }),\n project: Flags.string({\n description:\n 'Project ID of the dataset to migrate. Defaults to the projectId configured in your Sanity CLI config.',\n }),\n }\n\n static override hiddenAliases = ['migration:run']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(RunMigrationCommand)\n const {directory: workDir} = await this.getProjectRoot()\n const id = args.id\n const migrationsDirectoryPath = path.join(workDir, MIGRATIONS_DIRECTORY)\n\n // Listing migrations (no id given) only needs a project root, mirroring\n // `sanity migrations list` — it must not require api.projectId/dataset.\n if (!id) {\n this.warn(styleText('red', 'Error: Migration ID must be provided'))\n\n let migrations: Awaited<ReturnType<typeof resolveMigrations>> = []\n try {\n migrations = await resolveMigrations(workDir)\n } catch (error) {\n // A missing migrations folder is expected for a fresh project; surface\n // any other failure (e.g. a syntax error in a migration file).\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n this.error(\n `Failed to list migrations: ${error instanceof Error ? error.message : String(error)}`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n }\n\n if (migrations.length === 0) {\n this.log('\\nNo migrations found in the project')\n this.log(\n `Run ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`,\n )\n this.exit(exitCodes.RUNTIME_ERROR)\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'title', title: 'Title'},\n ],\n title: `Migrations found in project`,\n })\n\n for (const definedMigration of migrations) {\n table.addRow({id: definedMigration.id, title: definedMigration.migration.title})\n }\n this.log(table.render())\n this.log('\\nRun `sanity migration run <ID>` to run a migration')\n\n this.exit(exitCodes.RUNTIME_ERROR)\n }\n\n const cliConfig = await this.getCliConfig()\n const projectId = await this.getProjectId({deprecatedFlagName: 'project'})\n const datasetFromConfig = cliConfig.api?.dataset\n\n const fromExport = flags['from-export']\n const dry = flags['dry-run']\n const dataset = flags.dataset\n const project = flags.project\n const apiVersion = ensureApiVersionFormat(flags['api-version'] ?? DEFAULT_API_VERSION)\n\n if ((dataset && !project) || (project && !dataset)) {\n this.error('If either --dataset or --project is provided, both must be provided', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (!project && !projectId) {\n this.error(\n 'sanity.cli.js does not contain a project identifier (\"api.projectId\") and no --project option was provided.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n if (!dataset && !datasetFromConfig) {\n this.error(\n 'sanity.cli.js does not contain a dataset identifier (\"api.dataset\") and no --dataset option was provided.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n const candidates = await resolveMigrationScript(workDir, id)\n const resolvedScripts = candidates.filter((candidate) => isLoadableMigrationScript(candidate))\n\n if (resolvedScripts.length > 1) {\n // todo: consider prompt user about which one to run? note: it's likely a mistake if multiple files resolve to the same name\n this.error(\n `Found multiple migrations for \"${id}\" in ${styleText('cyan', migrationsDirectoryPath)}: \\n - ${candidates\n .map((candidate) => path.relative(migrationsDirectoryPath, candidate.absolutePath))\n .join('\\n - ')}`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n const script = resolvedScripts[0]\n if (!script) {\n this.error(\n `No migration found for \"${id}\" in ${styleText('cyan', migrationsDirectoryPath)}. Make sure that the migration file exists and exports a valid migration as its default export.\\n\n Tried the following files:\\n - ${candidates\n .map((candidate) => path.relative(migrationsDirectoryPath, candidate.absolutePath))\n .join('\\n - ')}`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n const mod = script.mod\n if ('up' in mod || 'down' in mod) {\n // todo: consider adding support for up/down as separate named exports\n // For now, make sure we reserve the names for future use\n this.error(\n 'Named \"up\"/\"down\" migration exports are not supported at this time, please export your migration as the default export',\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n\n const migration: Migration = mod.default\n\n if (fromExport && !dry) {\n this.error('Can only dry run migrations from a dataset export file', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const concurrency = flags.concurrency\n if (concurrency !== undefined) {\n if (concurrency > MAX_MUTATION_CONCURRENCY) {\n this.error(`Concurrency exceeds the maximum allowed value of ${MAX_MUTATION_CONCURRENCY}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (concurrency < 1) {\n this.error(`Concurrency must be a positive number, got ${concurrency}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n const projectClient = await getProjectCliClient({\n apiVersion,\n projectId: (project ?? projectId)!,\n requireUser: true,\n })\n const projectConfig = projectClient.config()\n\n const apiConfig: APIConfig = {\n apiHost: projectConfig.apiHost,\n apiVersion,\n dataset: (dataset ?? datasetFromConfig)!,\n projectId: (project ?? projectId)!,\n token: projectConfig.token!,\n } as const\n if (dry) {\n await this.dryRunHandler(id, migration, apiConfig, fromExport)\n return\n }\n\n this.log(\n `\\n${styleText(['yellow', 'bold'], 'Note: During migrations, your webhooks stay active.')}`,\n )\n this.log(\n `To adjust them, launch the management interface with ${styleText('cyan', 'sanity manage')}, navigate to the API settings, and toggle the webhooks before and after the migration as needed.\\n`,\n )\n\n if (flags.confirm) {\n await this.promptConfirmMigrate(apiConfig)\n }\n\n const spin = spinner(`Running migration \"${id}\"`).start()\n try {\n await run(\n {\n api: apiConfig,\n concurrency,\n onProgress: this.createProgress(spin, flags, id, dry, apiConfig, migration),\n },\n migration,\n )\n } finally {\n spin.stop()\n }\n }\n\n private createProgress(\n progressSpinner: ReturnType<typeof spinner>,\n flags: RunMigrationFlags,\n id: string,\n dry: boolean,\n apiConfig: APIConfig,\n migration: Migration,\n ) {\n return function onProgress(progress: MigrationProgress) {\n if (!flags.progress) {\n progressSpinner.stop()\n return\n }\n if (progress.done) {\n progressSpinner.text = `Migration \"${id}\" completed.\n\n Project id: ${styleText('bold', apiConfig.projectId)}\n Dataset: ${styleText('bold', apiConfig.dataset)}\n\n ${progress.documents} documents processed.\n ${progress.mutations} mutations generated.\n ${styleText('green', String(progress.completedTransactions.length))} transactions committed.`\n progressSpinner.stopAndPersist({symbol: styleText('green', '✔')})\n return\n }\n\n for (const transaction of [null, ...progress.currentTransactions]) {\n progressSpinner.text = `Running migration \"${id}\" ${dry ? 'in dry mode...' : '...'}\n\n Project id: ${styleText('bold', apiConfig.projectId)}\n Dataset: ${styleText('bold', apiConfig.dataset)}\n Document type: ${styleText('bold', migration.documentTypes?.join(',') ?? '')}\n\n ${progress.documents} documents processed…\n ${progress.mutations} mutations generated…\n ${styleText('blue', String(progress.pending))} requests pending…\n ${styleText('green', String(progress.completedTransactions.length))} transactions committed.\n\n ${\n transaction && !progress.done\n ? `» ${prettyFormat({indentSize: 2, migration, subject: transaction})}`\n : ''\n }`\n }\n }\n }\n\n private async dryRunHandler(\n id: string,\n migration: Migration,\n apiConfig: APIConfig,\n fromExport: string | undefined,\n ) {\n this.log(`Running migration \"${id}\" in dry mode`)\n\n if (fromExport) {\n this.log(`Using export ${styleText('cyan', fromExport)}`)\n }\n\n this.log()\n this.log(`Project id: ${styleText('bold', apiConfig.projectId)}`)\n this.log(`Dataset: ${styleText('bold', apiConfig.dataset)}`)\n\n for await (const mutation of dryRun({api: apiConfig, exportPath: fromExport}, migration)) {\n if (!mutation) continue\n this.log()\n this.log(\n prettyFormat({\n migration,\n subject: mutation,\n }),\n )\n }\n }\n\n private async promptConfirmMigrate(apiConfig: APIConfig) {\n const response = await confirm({\n message: `This migration will run on the ${styleText(\n ['yellow', 'bold'],\n apiConfig.dataset,\n )} dataset in ${styleText(['yellow', 'bold'], apiConfig.projectId)} project. Are you sure?`,\n })\n\n if (!response) {\n runMigrationDebug('User aborted migration')\n this.exit(exitCodes.RUNTIME_ERROR)\n }\n }\n}\n"],"names":["path","styleText","Args","Flags","exitCodes","getProjectCliClient","SanityCommand","subdebug","confirm","spinner","DEFAULT_MUTATION_CONCURRENCY","dryRun","MAX_MUTATION_CONCURRENCY","run","Table","DEFAULT_API_VERSION","MIGRATIONS_DIRECTORY","ensureApiVersionFormat","prettyFormat","resolveMigrations","isLoadableMigrationScript","resolveMigrationScript","runMigrationDebug","RunMigrationCommand","args","id","string","description","required","examples","command","flags","concurrency","integer","default","boolean","allowNo","dataset","progress","project","hiddenAliases","parse","directory","workDir","getProjectRoot","migrationsDirectoryPath","join","warn","migrations","error","code","Error","message","String","exit","RUNTIME_ERROR","length","log","table","columns","alignment","name","title","definedMigration","addRow","migration","render","cliConfig","getCliConfig","projectId","getProjectId","deprecatedFlagName","datasetFromConfig","api","fromExport","dry","apiVersion","candidates","resolvedScripts","filter","candidate","map","relative","absolutePath","script","mod","undefined","projectClient","requireUser","projectConfig","config","apiConfig","apiHost","token","dryRunHandler","promptConfirmMigrate","spin","start","onProgress","createProgress","stop","progressSpinner","done","text","documents","mutations","completedTransactions","stopAndPersist","symbol","transaction","currentTransactions","documentTypes","pending","indentSize","subject","mutation","exportPath","response"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/migrations/run.ts"],"sourcesContent":["import path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, getProjectCliClient, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {\n type APIConfig,\n DEFAULT_MUTATION_CONCURRENCY,\n dryRun,\n MAX_MUTATION_CONCURRENCY,\n type Migration,\n type MigrationProgress,\n run,\n UnknownTransactionOutcomeError,\n} from '@sanity/migrate'\n\nimport {DEFAULT_API_VERSION, MIGRATIONS_DIRECTORY} from '../../actions/migration/constants.js'\nimport {ensureApiVersionFormat} from '../../actions/migration/ensureApiVersionFormat.js'\nimport {prettyFormat} from '../../actions/migration/prettyMutationFormatter.js'\nimport {resolveMigrations} from '../../actions/migration/resolveMigrations.js'\nimport {\n isLoadableMigrationScript,\n resolveMigrationScript,\n} from '../../actions/migration/resolveMigrationScript.js'\nimport {Table} from '../../util/responsiveTable.js'\n\nconst runMigrationDebug = subdebug('migration:run')\n\n/**\n * Renders the `cause` chain of an error the way oclif's own error printer would.\n *\n * Used when printing an error ourselves to bypass oclif's hard word wrapping:\n * the underlying transport error (a timeout, a dropped connection) is the part\n * that explains _why_ the outcome is unknown, so it should not be dropped just\n * because the top-level message is printed separately.\n */\nfunction formatCauseChain(error: unknown): string[] {\n const lines: string[] = []\n let cause: unknown = error instanceof Error ? error.cause : undefined\n\n while (cause instanceof Error) {\n lines.push(`Caused by: ${cause.name}: ${cause.message}`)\n if ('code' in cause && typeof cause.code === 'string') {\n lines.push(`Code: ${cause.code}`)\n }\n cause = cause.cause\n }\n\n return lines\n}\n\nexport type RunMigrationFlags = RunMigrationCommand['flags']\n\nexport class RunMigrationCommand extends SanityCommand<typeof RunMigrationCommand> {\n static override args = {\n id: Args.string({\n description: 'ID',\n required: false,\n }),\n }\n\n static override description = 'Run a migration against a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> <id>',\n description: 'dry run the migration',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> <id> --no-dry-run --project xyz --dataset staging',\n description: 'execute the migration against a dataset',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> <id> --from-export=production.tar.gz --no-dry-run --project xyz --dataset staging',\n description: 'execute the migration using a dataset export as the source',\n },\n ]\n\n static override flags = {\n 'api-version': Flags.string({\n description: `API version to use when migrating. Defaults to ${DEFAULT_API_VERSION}.`,\n }),\n concurrency: Flags.integer({\n default: DEFAULT_MUTATION_CONCURRENCY,\n description: `How many mutation requests to run in parallel. Must be between 1 and ${MAX_MUTATION_CONCURRENCY}. Default: ${DEFAULT_MUTATION_CONCURRENCY}.`,\n }),\n confirm: Flags.boolean({\n allowNo: true,\n default: true,\n description:\n 'Prompt for confirmation before running the migration (default: true). Use --no-confirm to skip.',\n }),\n dataset: Flags.string({\n description:\n 'Dataset to migrate. Defaults to the dataset configured in your Sanity CLI config.',\n }),\n 'dry-run': Flags.boolean({\n allowNo: true,\n default: true,\n description:\n 'By default the migration runs in dry mode. Use --no-dry-run to migrate dataset.',\n }),\n 'from-export': Flags.string({\n description:\n 'Use a local dataset export as source for migration instead of calling the Sanity API. Note: this is only supported for dry runs.',\n }),\n progress: Flags.boolean({\n allowNo: true,\n default: true,\n description:\n 'Display progress during migration (default: true). Use --no-progress to hide output.',\n }),\n project: Flags.string({\n description:\n 'Project ID of the dataset to migrate. Defaults to the projectId configured in your Sanity CLI config.',\n }),\n }\n\n static override hiddenAliases = ['migration:run']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(RunMigrationCommand)\n const {directory: workDir} = await this.getProjectRoot()\n const id = args.id\n const migrationsDirectoryPath = path.join(workDir, MIGRATIONS_DIRECTORY)\n\n // Listing migrations (no id given) only needs a project root, mirroring\n // `sanity migrations list` — it must not require api.projectId/dataset.\n if (!id) {\n this.warn(styleText('red', 'Error: Migration ID must be provided'))\n\n let migrations: Awaited<ReturnType<typeof resolveMigrations>> = []\n try {\n migrations = await resolveMigrations(workDir)\n } catch (error) {\n // A missing migrations folder is expected for a fresh project; surface\n // any other failure (e.g. a syntax error in a migration file).\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n this.error(\n `Failed to list migrations: ${error instanceof Error ? error.message : String(error)}`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n }\n\n if (migrations.length === 0) {\n this.log('\\nNo migrations found in the project')\n this.log(\n `Run ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`,\n )\n this.exit(exitCodes.RUNTIME_ERROR)\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'title', title: 'Title'},\n ],\n title: `Migrations found in project`,\n })\n\n for (const definedMigration of migrations) {\n table.addRow({id: definedMigration.id, title: definedMigration.migration.title})\n }\n this.log(table.render())\n this.log('\\nRun `sanity migration run <ID>` to run a migration')\n\n this.exit(exitCodes.RUNTIME_ERROR)\n }\n\n const cliConfig = await this.getCliConfig()\n const projectId = await this.getProjectId({deprecatedFlagName: 'project'})\n const datasetFromConfig = cliConfig.api?.dataset\n\n const fromExport = flags['from-export']\n const dry = flags['dry-run']\n const dataset = flags.dataset\n const project = flags.project\n const apiVersion = ensureApiVersionFormat(flags['api-version'] ?? DEFAULT_API_VERSION)\n\n if ((dataset && !project) || (project && !dataset)) {\n this.error('If either --dataset or --project is provided, both must be provided', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (!project && !projectId) {\n this.error(\n 'sanity.cli.js does not contain a project identifier (\"api.projectId\") and no --project option was provided.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n if (!dataset && !datasetFromConfig) {\n this.error(\n 'sanity.cli.js does not contain a dataset identifier (\"api.dataset\") and no --dataset option was provided.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n const candidates = await resolveMigrationScript(workDir, id)\n const resolvedScripts = candidates.filter((candidate) => isLoadableMigrationScript(candidate))\n\n if (resolvedScripts.length > 1) {\n // todo: consider prompt user about which one to run? note: it's likely a mistake if multiple files resolve to the same name\n this.error(\n `Found multiple migrations for \"${id}\" in ${styleText('cyan', migrationsDirectoryPath)}: \\n - ${candidates\n .map((candidate) => path.relative(migrationsDirectoryPath, candidate.absolutePath))\n .join('\\n - ')}`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n const script = resolvedScripts[0]\n if (!script) {\n this.error(\n `No migration found for \"${id}\" in ${styleText('cyan', migrationsDirectoryPath)}. Make sure that the migration file exists and exports a valid migration as its default export.\\n\n Tried the following files:\\n - ${candidates\n .map((candidate) => path.relative(migrationsDirectoryPath, candidate.absolutePath))\n .join('\\n - ')}`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n const mod = script.mod\n if ('up' in mod || 'down' in mod) {\n // todo: consider adding support for up/down as separate named exports\n // For now, make sure we reserve the names for future use\n this.error(\n 'Named \"up\"/\"down\" migration exports are not supported at this time, please export your migration as the default export',\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n\n const migration: Migration = mod.default\n\n if (fromExport && !dry) {\n this.error('Can only dry run migrations from a dataset export file', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const concurrency = flags.concurrency\n if (concurrency !== undefined) {\n if (concurrency > MAX_MUTATION_CONCURRENCY) {\n this.error(`Concurrency exceeds the maximum allowed value of ${MAX_MUTATION_CONCURRENCY}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (concurrency < 1) {\n this.error(`Concurrency must be a positive number, got ${concurrency}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n const projectClient = await getProjectCliClient({\n apiVersion,\n projectId: (project ?? projectId)!,\n requireUser: true,\n })\n const projectConfig = projectClient.config()\n\n const apiConfig: APIConfig = {\n apiHost: projectConfig.apiHost,\n apiVersion,\n dataset: (dataset ?? datasetFromConfig)!,\n projectId: (project ?? projectId)!,\n token: projectConfig.token!,\n } as const\n if (dry) {\n await this.dryRunHandler(id, migration, apiConfig, fromExport)\n return\n }\n\n this.log(\n `\\n${styleText(['yellow', 'bold'], 'Note: During migrations, your webhooks stay active.')}`,\n )\n this.log(\n `To adjust them, launch the management interface with ${styleText('cyan', 'sanity manage')}, navigate to the API settings, and toggle the webhooks before and after the migration as needed.\\n`,\n )\n\n if (flags.confirm) {\n await this.promptConfirmMigrate(apiConfig)\n }\n\n const spin = spinner(`Running migration \"${id}\"`).start()\n const onProgress = this.createProgress(spin, flags, id, dry, apiConfig, migration)\n let lastProgress: MigrationProgress | undefined\n\n try {\n await run(\n {\n api: apiConfig,\n concurrency,\n onProgress: (progress) => {\n lastProgress = progress\n onProgress(progress)\n },\n },\n migration,\n )\n } catch (err) {\n // ora's `stop()` clears the spinner region, taking the multi-line progress\n // block with it. Persist a failure summary first, so the transaction counts\n // (the only record of what was committed before the failure) survive.\n this.persistFailureSummary(spin, flags, id, apiConfig, lastProgress)\n\n if (err instanceof UnknownTransactionOutcomeError) {\n // oclif hard-wraps error messages, which splits the transaction log URLs\n // across lines and makes them impossible to copy. Print the recovery\n // instructions ourselves and rethrow something short for the exit code.\n this.logToStderr(err.message)\n for (const line of formatCauseChain(err)) {\n this.logToStderr(line)\n }\n\n const count = err.transactionIds.length\n this.error(\n `Migration \"${id}\" failed: the ${count === 1 ? 'outcome' : 'outcomes'} of ${count} ${\n count === 1 ? 'transaction' : 'transactions'\n } ${count === 1 ? 'is' : 'are'} unknown. See the transaction log details above.`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n throw err\n } finally {\n spin.stop()\n }\n }\n\n private createProgress(\n progressSpinner: ReturnType<typeof spinner>,\n flags: RunMigrationFlags,\n id: string,\n dry: boolean,\n apiConfig: APIConfig,\n migration: Migration,\n ) {\n return function onProgress(progress: MigrationProgress) {\n if (!flags.progress) {\n progressSpinner.stop()\n return\n }\n if (progress.done) {\n progressSpinner.text = `Migration \"${id}\" completed.\n\n Project id: ${styleText('bold', apiConfig.projectId)}\n Dataset: ${styleText('bold', apiConfig.dataset)}\n\n ${progress.documents} documents processed.\n ${progress.mutations} mutations generated.\n ${styleText('green', String(progress.completedTransactions.length))} transactions committed.`\n progressSpinner.stopAndPersist({symbol: styleText('green', '✔')})\n return\n }\n\n for (const transaction of [null, ...progress.currentTransactions]) {\n progressSpinner.text = `Running migration \"${id}\" ${dry ? 'in dry mode...' : '...'}\n\n Project id: ${styleText('bold', apiConfig.projectId)}\n Dataset: ${styleText('bold', apiConfig.dataset)}\n Document type: ${styleText('bold', migration.documentTypes?.join(',') ?? '')}\n\n ${progress.documents} documents processed…\n ${progress.mutations} mutations generated…\n ${styleText('blue', String(progress.pending))} requests pending…\n ${styleText('green', String(progress.completedTransactions.length))} transactions committed.\n\n ${\n transaction && !progress.done\n ? `» ${prettyFormat({indentSize: 2, migration, subject: transaction})}`\n : ''\n }`\n }\n }\n }\n\n private async dryRunHandler(\n id: string,\n migration: Migration,\n apiConfig: APIConfig,\n fromExport: string | undefined,\n ) {\n this.log(`Running migration \"${id}\" in dry mode`)\n\n if (fromExport) {\n this.log(`Using export ${styleText('cyan', fromExport)}`)\n }\n\n this.log()\n this.log(`Project id: ${styleText('bold', apiConfig.projectId)}`)\n this.log(`Dataset: ${styleText('bold', apiConfig.dataset)}`)\n\n for await (const mutation of dryRun({api: apiConfig, exportPath: fromExport}, migration)) {\n if (!mutation) continue\n this.log()\n this.log(\n prettyFormat({\n migration,\n subject: mutation,\n }),\n )\n }\n }\n\n /**\n * Persist the last reported progress with a failure marker.\n *\n * Only the `progress.done` path finalizes the spinner on its own, so without\n * this the entire progress block is wiped when the migration fails partway.\n */\n private persistFailureSummary(\n progressSpinner: ReturnType<typeof spinner>,\n flags: RunMigrationFlags,\n id: string,\n apiConfig: APIConfig,\n progress: MigrationProgress | undefined,\n ) {\n // With `--no-progress` the spinner was already stopped and nothing was ever\n // rendered; a `done` progress event has already persisted its own summary.\n if (!flags.progress || !progress || progress.done) return\n\n progressSpinner.text = `Migration \"${id}\" failed.\n\n Project id: ${styleText('bold', apiConfig.projectId)}\n Dataset: ${styleText('bold', apiConfig.dataset)}\n\n ${progress.documents} documents processed.\n ${progress.mutations} mutations generated.\n ${styleText('green', String(progress.completedTransactions.length))} transactions committed.`\n progressSpinner.stopAndPersist({symbol: styleText('red', '✖')})\n }\n\n private async promptConfirmMigrate(apiConfig: APIConfig) {\n const response = await confirm({\n message: `This migration will run on the ${styleText(\n ['yellow', 'bold'],\n apiConfig.dataset,\n )} dataset in ${styleText(['yellow', 'bold'], apiConfig.projectId)} project. Are you sure?`,\n })\n\n if (!response) {\n runMigrationDebug('User aborted migration')\n this.exit(exitCodes.RUNTIME_ERROR)\n }\n }\n}\n"],"names":["path","styleText","Args","Flags","exitCodes","getProjectCliClient","SanityCommand","subdebug","confirm","spinner","DEFAULT_MUTATION_CONCURRENCY","dryRun","MAX_MUTATION_CONCURRENCY","run","UnknownTransactionOutcomeError","DEFAULT_API_VERSION","MIGRATIONS_DIRECTORY","ensureApiVersionFormat","prettyFormat","resolveMigrations","isLoadableMigrationScript","resolveMigrationScript","Table","runMigrationDebug","formatCauseChain","error","lines","cause","Error","undefined","push","name","message","code","RunMigrationCommand","args","id","string","description","required","examples","command","flags","concurrency","integer","default","boolean","allowNo","dataset","progress","project","hiddenAliases","parse","directory","workDir","getProjectRoot","migrationsDirectoryPath","join","warn","migrations","String","exit","RUNTIME_ERROR","length","log","table","columns","alignment","title","definedMigration","addRow","migration","render","cliConfig","getCliConfig","projectId","getProjectId","deprecatedFlagName","datasetFromConfig","api","fromExport","dry","apiVersion","candidates","resolvedScripts","filter","candidate","map","relative","absolutePath","script","mod","projectClient","requireUser","projectConfig","config","apiConfig","apiHost","token","dryRunHandler","promptConfirmMigrate","spin","start","onProgress","createProgress","lastProgress","err","persistFailureSummary","logToStderr","line","count","transactionIds","stop","progressSpinner","done","text","documents","mutations","completedTransactions","stopAndPersist","symbol","transaction","currentTransactions","documentTypes","pending","indentSize","subject","mutation","exportPath","response"],"mappings":"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"}
|
package/dist/commands/new.js
CHANGED
|
@@ -213,12 +213,13 @@ export class NewCommand extends SanityCommand {
|
|
|
213
213
|
flow.note(styleText('dim', 'If you are an agent: give this claim URL to the person you are working for. They have ' + 'to open it themselves before the deadline.'));
|
|
214
214
|
flow.gap();
|
|
215
215
|
}
|
|
216
|
+
const studioUrl = `http://localhost:3333/#token=${encodeURIComponent(project.token)}` + `&claim=${encodeURIComponent(project.claimUrl)}`;
|
|
216
217
|
const printStudioInstructions = ()=>{
|
|
217
218
|
flow.highlight('Start your Studio:');
|
|
218
219
|
flow.gap();
|
|
219
|
-
flow.command(`cd ${STUDIO_DIR} && npx sanity dev`);
|
|
220
|
+
flow.command(`cd ${STUDIO_DIR} && npx sanity@latest dev`);
|
|
220
221
|
flow.gap();
|
|
221
|
-
flow.link(
|
|
222
|
+
flow.link(studioUrl, {
|
|
222
223
|
label: 'Then open this link:'
|
|
223
224
|
});
|
|
224
225
|
flow.gap();
|
|
@@ -308,7 +309,7 @@ export class NewCommand extends SanityCommand {
|
|
|
308
309
|
flow.result('Project created without scaffolding');
|
|
309
310
|
flow.line('No folders or env files were created. Use the project ID and dataset above in your own setup.');
|
|
310
311
|
flow.gap();
|
|
311
|
-
flow.link(
|
|
312
|
+
flow.link(studioUrl, {
|
|
312
313
|
label: 'Once a Studio is running on http://localhost:3333, sign in with:'
|
|
313
314
|
});
|
|
314
315
|
flow.gap();
|
package/dist/commands/new.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/new.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {createFlow, input} from '@sanity/cli-core/ux'\n\nimport {\n FRONTEND_DIR,\n FRONTEND_ENV_FILE,\n getUnavailableScaffoldTarget,\n scaffoldProject,\n type ScaffoldResult,\n STUDIO_DIR,\n STUDIO_ENV_FILE,\n} from '../actions/scaffold/scaffoldProject.js'\nimport {type MintedProject, mintUnclaimedProject} from '../services/mintProject.js'\nimport {\n fetchNewInstructions,\n INSTRUCTIONS_URL,\n InstructionsUnavailableError,\n} from '../services/newInstructions.js'\nimport {formatClaimDeadline} from '../util/formatClaimDeadline.js'\nimport {CLAIM_WINDOW_HOURS, SANITY_NEW_URL} from '../util/mintProjectConstants.js'\nimport {renderNewCommandSplash} from '../util/newCommandSplash.js'\nimport {recordUnclaimedProject} from '../util/unclaimedProjects.js'\n\nconst DEFAULT_PROJECT_NAME = 'My Sanity project'\nconst HELP_DESCRIPTION_WIDTH = 78\n\n/**\n * Prepended to the fetched instructions so an agent cannot read this command's success as the\n * project already existing. The only addition to an otherwise verbatim document.\n */\nconst INSTRUCTIONS_HEADER = '# Nothing has been created yet — follow these steps.'\n\nfunction formatHelpDescription(...paragraphs: string[]): string {\n return paragraphs\n .map((paragraph) => {\n const lines: string[] = []\n let line = ''\n\n for (const word of paragraph.split(/\\s+/u)) {\n if (!line || line.length + word.length + 1 <= HELP_DESCRIPTION_WIDTH) {\n line = line ? `${line} ${word}` : word\n } else {\n lines.push(line)\n line = word\n }\n }\n\n if (line) lines.push(line)\n return lines.join('\\n')\n })\n .join('\\n\\n')\n}\n\nconst FRONTEND_DEV_COMMANDS: Record<\n NonNullable<ScaffoldResult['frontendPackageManager']>,\n string\n> = {\n bun: 'bun dev',\n manual: 'npm run dev',\n npm: 'npm run dev',\n pnpm: 'pnpm dev',\n yarn: 'yarn dev',\n}\n\nfunction frontendDevCommand(packageManager: ScaffoldResult['frontendPackageManager']): string {\n return packageManager ? FRONTEND_DEV_COMMANDS[packageManager] : 'npm run dev'\n}\n\nfunction frontendInstallCommand(packageManager: ScaffoldResult['frontendPackageManager']): string {\n switch (packageManager) {\n case 'bun': {\n return 'bun add next-sanity'\n }\n case 'pnpm': {\n return 'pnpm add --save-prod next-sanity'\n }\n case 'yarn': {\n return 'yarn add next-sanity'\n }\n default: {\n return 'npm install next-sanity'\n }\n }\n}\n\nexport interface NewProjectResult {\n apiHost: string\n claimApiUrl: string\n claimToken: string\n claimUrl: string\n dataset: string\n expiresAt: string\n projectId: string\n terms: {\n notice: string\n url: string\n }\n token: string\n}\n\nfunction toResult(project: MintedProject): NewProjectResult {\n return {\n apiHost: project.apiHost,\n claimApiUrl: project.claimApiUrl,\n claimToken: project.claimToken,\n claimUrl: project.claimUrl,\n dataset: project.datasetName,\n expiresAt: project.expiresAt,\n projectId: project.resourceId,\n terms: {notice: project.termsNotice, url: project.termsUrl},\n token: project.token,\n }\n}\n\nexport class NewCommand extends SanityCommand<typeof NewCommand> {\n static override args = {\n projectName: Args.string({\n description: 'Display name for the new project',\n required: false,\n }),\n }\n\n static override description = formatHelpDescription(\n `Sets up two folders here: ./${STUDIO_DIR}, a Studio where you write and edit your content, ` +\n `and ./${FRONTEND_DIR}, a Next.js website that reads it. Both are already connected to your ` +\n 'new project, so you can start them straight away. Use --no-scaffold if you just want the ' +\n 'project and nothing else.',\n `The project is real and works immediately, but it is only yours for ${CLAIM_WINDOW_HOURS} hours. Claim it with ` +\n 'a Sanity account before the deadline and everything you have built stays exactly as it is. ' +\n 'Claiming is free and takes about a minute. Miss the deadline and the project and its ' +\n 'content are deleted.',\n 'Two things to keep private: the claim link, because anyone who opens it becomes the owner, ' +\n `and the access token saved in ./${STUDIO_ENV_FILE} and ./${FRONTEND_ENV_FILE}, because it ` +\n 'can read and change everything in the project. Keep both env files out of git, and never ' +\n 'put the token in code that runs in the browser.',\n 'Run this command with --instructions for the full agent setup guide.',\n )\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Create a project with a Studio and a website',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My New Project\"',\n description: 'Create a project called \"My New Project\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --yes',\n description: 'Create a project without being asked anything',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --no-scaffold',\n description: 'Create the project only, with no Studio or website',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'Create a project and print its details as JSON',\n },\n\n {\n command: '<%= config.bin %> <%= command.id %> --instructions',\n description: 'Print the full setup guide for an AI agent, without creating anything',\n },\n ]\n\n static override flags = {\n instructions: Flags.boolean({\n default: false,\n description: `Print the full setup guide from ${SANITY_NEW_URL} and exit, creating nothing`,\n }),\n scaffold: Flags.boolean({\n allowNo: true,\n default: true,\n description: `Set up a Studio in ./${STUDIO_DIR} and a Next.js website in ./${FRONTEND_DIR} (on by default)`,\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: `Skip prompts and use defaults (project: \"${DEFAULT_PROJECT_NAME}\")`,\n }),\n }\n\n static override summary = `Create a Sanity project without an account, and claim it within ${CLAIM_WINDOW_HOURS} hours to keep it.`\n\n public async run(): Promise<NewProjectResult | undefined> {\n const {output} = this\n const json = this.jsonEnabled()\n const flow = createFlow(output.log)\n const invoked = [this.config.bin, ...(this.id?.split(':') ?? [])].join(' ')\n const cwd = process.cwd()\n\n // Runs before every precondition and side effect: this flag creates nothing.\n if (this.flags.instructions) {\n // oclif's `exclusive` does not cover the json flag added by enableJsonFlag, so guard it here.\n if (json) {\n throw new CLIError('--instructions cannot be combined with --json.', {\n code: 'INSTRUCTIONS_JSON_CONFLICT',\n exit: exitCodes.USAGE_ERROR,\n suggestions: [\n `Run \\`${invoked} --instructions\\` for the setup guide as markdown`,\n `Or run \\`${invoked} --json\\` to create a project and print its details as JSON`,\n ],\n })\n }\n\n await this.printInstructions()\n return undefined\n }\n\n const unavailableScaffoldTarget =\n !json && this.flags.scaffold ? await getUnavailableScaffoldTarget(cwd) : undefined\n if (unavailableScaffoldTarget) {\n throw new CLIError(\n `./${unavailableScaffoldTarget} is not an empty directory. No project was created.`,\n {\n code:\n unavailableScaffoldTarget === STUDIO_DIR\n ? 'EXISTING_STUDIO_DIRECTORY'\n : 'EXISTING_FRONTEND_DIRECTORY',\n exit: exitCodes.RUNTIME_ERROR,\n suggestions: [\n `Run this command where ./${unavailableScaffoldTarget} does not exist or is an empty directory`,\n `Or run \\`${invoked} --no-scaffold\\` to create the project without changing ./${unavailableScaffoldTarget}`,\n ],\n },\n )\n }\n\n if (!json) {\n renderNewCommandSplash(output.log)\n flow.intro('Setting up your Sanity project.')\n flow.gap()\n\n if (!this.isUnattended()) {\n flow.note(\n `${styleText('cyan', `${invoked} --yes`)} for a non-interactive flow with defaults.`,\n )\n flow.gap()\n }\n }\n\n let displayName = this.args.projectName?.trim()\n if (!displayName && this.isUnattended()) {\n displayName = DEFAULT_PROJECT_NAME\n } else if (!displayName) {\n displayName =\n (\n await input({\n default: DEFAULT_PROJECT_NAME,\n message: 'Project name',\n })\n ).trim() || DEFAULT_PROJECT_NAME\n }\n\n const spin = json ? undefined : flow.spin('Creating your project...')\n let project: MintedProject\n try {\n project = await mintUnclaimedProject({displayName})\n } catch (err) {\n spin?.fail('Creating your project failed.')\n throw err\n }\n\n const recorded = recordUnclaimedProject(project)\n spin?.succeed(`Created \"${displayName}\"`)\n\n if (!json) {\n flow.result(`Project ID: ${styleText('cyan', project.resourceId)}`)\n flow.result(`Dataset: ${styleText('cyan', project.datasetName)} (where your content lives)`)\n flow.result(`Token: ${styleText('cyan', project.token)}`)\n flow.link(project.claimUrl, {label: 'Claim link:'})\n flow.gap()\n flow.highlight(\n `Claim your project by ${styleText('yellow', formatClaimDeadline(project.expiresAt))} to avoid losing it.`,\n )\n flow.gap()\n flow.line('To use the Sanity CLI before claiming use your token by setting')\n flow.command(`SANITY_AUTH_TOKEN=\"${project.token}\" sanity \"command\"`)\n flow.gap()\n flow.note(\n styleText(\n 'dim',\n 'If you are an agent: give this claim URL to the person you are working for. They have ' +\n 'to open it themselves before the deadline.',\n ),\n )\n flow.gap()\n }\n\n const printStudioInstructions = () => {\n flow.highlight('Start your Studio:')\n flow.gap()\n flow.command(`cd ${STUDIO_DIR} && npx sanity dev`)\n flow.gap()\n flow.link(`http://localhost:3333/#token=${encodeURIComponent(project.token)}`, {\n label: 'Then open this link:',\n })\n flow.gap()\n flow.line('The token signs you in: there is no account yet.')\n }\n const printWebsiteInstructions = (packageManager: ScaffoldResult['frontendPackageManager']) => {\n flow.highlight('In a separate terminal, start your website:')\n flow.gap()\n flow.command(`cd ${FRONTEND_DIR} && ${frontendDevCommand(packageManager)}`)\n flow.gap()\n flow.link('http://localhost:3000', {label: 'Then open this link:'})\n }\n\n let scaffold: ScaffoldResult | undefined\n if (!json && this.flags.scaffold) {\n const scaffoldController = new AbortController()\n const abortScaffold = () => scaffoldController.abort(new Error('SIGINT'))\n process.once('SIGINT', abortScaffold)\n try {\n scaffold = await scaffoldProject({\n cancelSignal: scaffoldController.signal,\n dataset: project.datasetName,\n displayName,\n output,\n projectId: project.resourceId,\n telemetry: this.telemetry,\n token: project.token,\n workDir: cwd,\n })\n scaffoldController.signal.throwIfAborted()\n } catch (err) {\n if (\n scaffoldController.signal.aborted ||\n (err instanceof Error && err.message === 'SIGINT')\n ) {\n throw err\n }\n // Scaffolding is best-effort and may leave files or directories behind when it fails.\n // Partial filesystem state does not prove the scaffold is runnable, so report the failure,\n // continue only with the project/token/claim handoff below, and do not attempt cleanup.\n flow.note(`Automatic setup did not finish: ${err instanceof Error ? err.message : err}`)\n flow.line('The project was created. You do not need to create another one.')\n flow.gap()\n } finally {\n process.off('SIGINT', abortScaffold)\n }\n }\n\n if (scaffold) {\n if (scaffold.frontendPath) {\n flow.result('Created two folders')\n flow.line(`./${STUDIO_DIR}: your Studio, where you write and edit content`)\n flow.line(`./${FRONTEND_DIR}: your website, a Next.js app that reads it`)\n flow.gap()\n printStudioInstructions()\n if (scaffold.frontendDependenciesInstalled === false) {\n flow.gap()\n if (scaffold.frontendDependencyError) {\n flow.line(`Installing website dependencies failed: ${scaffold.frontendDependencyError}`)\n flow.gap()\n }\n flow.highlight('Finish installing your website dependencies')\n flow.gap()\n flow.command(\n `cd ${FRONTEND_DIR} && ${frontendInstallCommand(scaffold.frontendPackageManager)}`,\n )\n }\n flow.gap()\n printWebsiteInstructions(scaffold.frontendPackageManager)\n } else if (scaffold.detectedFramework) {\n flow.result(`Created ./${STUDIO_DIR} for your existing ${scaffold.detectedFramework} app`)\n flow.line(`./${STUDIO_DIR}: your Studio, where you write and edit content`)\n flow.line(`Your existing ${scaffold.detectedFramework} frontend was left unchanged.`)\n flow.gap()\n printStudioInstructions()\n } else {\n flow.result(`Created ./${STUDIO_DIR}`)\n flow.line(`./${STUDIO_DIR}: your Studio, where you write and edit content`)\n flow.line(\n `The website was not created: ${scaffold.frontendCreationError ?? 'automatic setup did not finish'}`,\n )\n flow.gap()\n printStudioInstructions()\n }\n flow.gap()\n }\n\n if (recorded === false && !json) {\n flow.note('The local recovery record was not saved.')\n flow.line('Keep the claim URL and access token from this output.')\n flow.gap()\n }\n\n if (!json) {\n if (!scaffold && !this.flags.scaffold) {\n flow.result('Project created without scaffolding')\n flow.line(\n 'No folders or env files were created. Use the project ID and dataset above in your own setup.',\n )\n flow.gap()\n flow.link(`http://localhost:3333/#token=${encodeURIComponent(project.token)}`, {\n label: 'Once a Studio is running on http://localhost:3333, sign in with:',\n })\n flow.gap()\n flow.line('The token signs you in: there is no account yet.')\n flow.gap()\n }\n\n flow.line('Your content is private until you claim, to read it, you need the token.')\n flow.line(\"Treat your token as a password and don't expose it publicly in your app.\")\n flow.gap()\n flow.line(\n 'The claim link and token are printed above but you can recover them ' +\n `with ${styleText('cyan', 'sanity projects unclaimed')} before the timer runs out on ${formatClaimDeadline(project.expiresAt)}.`,\n )\n flow.gap()\n flow.line(project.termsNotice)\n flow.link(project.termsUrl, {label: 'Terms of Service:'})\n flow.gap()\n flow.line('For more information on how claiming works or how to build your app')\n flow.link(SANITY_NEW_URL, {label: 'visit', outro: true})\n }\n\n return toResult(project)\n }\n\n /**\n * Dumps the guide from sanity.new verbatim, so an agent gets the whole document rather than a\n * summary produced by whatever fetched it.\n */\n private async printInstructions(): Promise<void> {\n let instructions: string\n try {\n instructions = await fetchNewInstructions()\n } catch (err) {\n if (err instanceof InstructionsUnavailableError) {\n throw new CLIError(err.message, {\n code: 'INSTRUCTIONS_UNAVAILABLE',\n exit: exitCodes.RUNTIME_ERROR,\n suggestions: [\n `Fetch them directly: curl -sSL ${INSTRUCTIONS_URL}`,\n `Or open ${SANITY_NEW_URL} in a browser`,\n ],\n })\n }\n throw err\n }\n\n this.output.log(`${INSTRUCTIONS_HEADER}\\n\\n${instructions}`)\n }\n}\n"],"names":["styleText","Args","Flags","CLIError","exitCodes","SanityCommand","createFlow","input","FRONTEND_DIR","FRONTEND_ENV_FILE","getUnavailableScaffoldTarget","scaffoldProject","STUDIO_DIR","STUDIO_ENV_FILE","mintUnclaimedProject","fetchNewInstructions","INSTRUCTIONS_URL","InstructionsUnavailableError","formatClaimDeadline","CLAIM_WINDOW_HOURS","SANITY_NEW_URL","renderNewCommandSplash","recordUnclaimedProject","DEFAULT_PROJECT_NAME","HELP_DESCRIPTION_WIDTH","INSTRUCTIONS_HEADER","formatHelpDescription","paragraphs","map","paragraph","lines","line","word","split","length","push","join","FRONTEND_DEV_COMMANDS","bun","manual","npm","pnpm","yarn","frontendDevCommand","packageManager","frontendInstallCommand","toResult","project","apiHost","claimApiUrl","claimToken","claimUrl","dataset","datasetName","expiresAt","projectId","resourceId","terms","notice","termsNotice","url","termsUrl","token","NewCommand","args","projectName","string","description","required","enableJsonFlag","examples","command","flags","instructions","boolean","default","scaffold","allowNo","yes","char","summary","run","output","json","jsonEnabled","flow","log","invoked","config","bin","id","cwd","process","code","exit","USAGE_ERROR","suggestions","printInstructions","undefined","unavailableScaffoldTarget","RUNTIME_ERROR","intro","gap","isUnattended","note","displayName","trim","message","spin","err","fail","recorded","succeed","result","link","label","highlight","printStudioInstructions","encodeURIComponent","printWebsiteInstructions","scaffoldController","AbortController","abortScaffold","abort","Error","once","cancelSignal","signal","telemetry","workDir","throwIfAborted","aborted","off","frontendPath","frontendDependenciesInstalled","frontendDependencyError","frontendPackageManager","detectedFramework","frontendCreationError","outro"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/new.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {createFlow, input} from '@sanity/cli-core/ux'\n\nimport {\n FRONTEND_DIR,\n FRONTEND_ENV_FILE,\n getUnavailableScaffoldTarget,\n scaffoldProject,\n type ScaffoldResult,\n STUDIO_DIR,\n STUDIO_ENV_FILE,\n} from '../actions/scaffold/scaffoldProject.js'\nimport {type MintedProject, mintUnclaimedProject} from '../services/mintProject.js'\nimport {\n fetchNewInstructions,\n INSTRUCTIONS_URL,\n InstructionsUnavailableError,\n} from '../services/newInstructions.js'\nimport {formatClaimDeadline} from '../util/formatClaimDeadline.js'\nimport {CLAIM_WINDOW_HOURS, SANITY_NEW_URL} from '../util/mintProjectConstants.js'\nimport {renderNewCommandSplash} from '../util/newCommandSplash.js'\nimport {recordUnclaimedProject} from '../util/unclaimedProjects.js'\n\nconst DEFAULT_PROJECT_NAME = 'My Sanity project'\nconst HELP_DESCRIPTION_WIDTH = 78\n\n/**\n * Prepended to the fetched instructions so an agent cannot read this command's success as the\n * project already existing. The only addition to an otherwise verbatim document.\n */\nconst INSTRUCTIONS_HEADER = '# Nothing has been created yet — follow these steps.'\n\nfunction formatHelpDescription(...paragraphs: string[]): string {\n return paragraphs\n .map((paragraph) => {\n const lines: string[] = []\n let line = ''\n\n for (const word of paragraph.split(/\\s+/u)) {\n if (!line || line.length + word.length + 1 <= HELP_DESCRIPTION_WIDTH) {\n line = line ? `${line} ${word}` : word\n } else {\n lines.push(line)\n line = word\n }\n }\n\n if (line) lines.push(line)\n return lines.join('\\n')\n })\n .join('\\n\\n')\n}\n\nconst FRONTEND_DEV_COMMANDS: Record<\n NonNullable<ScaffoldResult['frontendPackageManager']>,\n string\n> = {\n bun: 'bun dev',\n manual: 'npm run dev',\n npm: 'npm run dev',\n pnpm: 'pnpm dev',\n yarn: 'yarn dev',\n}\n\nfunction frontendDevCommand(packageManager: ScaffoldResult['frontendPackageManager']): string {\n return packageManager ? FRONTEND_DEV_COMMANDS[packageManager] : 'npm run dev'\n}\n\nfunction frontendInstallCommand(packageManager: ScaffoldResult['frontendPackageManager']): string {\n switch (packageManager) {\n case 'bun': {\n return 'bun add next-sanity'\n }\n case 'pnpm': {\n return 'pnpm add --save-prod next-sanity'\n }\n case 'yarn': {\n return 'yarn add next-sanity'\n }\n default: {\n return 'npm install next-sanity'\n }\n }\n}\n\nexport interface NewProjectResult {\n apiHost: string\n claimApiUrl: string\n claimToken: string\n claimUrl: string\n dataset: string\n expiresAt: string\n projectId: string\n terms: {\n notice: string\n url: string\n }\n token: string\n}\n\nfunction toResult(project: MintedProject): NewProjectResult {\n return {\n apiHost: project.apiHost,\n claimApiUrl: project.claimApiUrl,\n claimToken: project.claimToken,\n claimUrl: project.claimUrl,\n dataset: project.datasetName,\n expiresAt: project.expiresAt,\n projectId: project.resourceId,\n terms: {notice: project.termsNotice, url: project.termsUrl},\n token: project.token,\n }\n}\n\nexport class NewCommand extends SanityCommand<typeof NewCommand> {\n static override args = {\n projectName: Args.string({\n description: 'Display name for the new project',\n required: false,\n }),\n }\n\n static override description = formatHelpDescription(\n `Sets up two folders here: ./${STUDIO_DIR}, a Studio where you write and edit your content, ` +\n `and ./${FRONTEND_DIR}, a Next.js website that reads it. Both are already connected to your ` +\n 'new project, so you can start them straight away. Use --no-scaffold if you just want the ' +\n 'project and nothing else.',\n `The project is real and works immediately, but it is only yours for ${CLAIM_WINDOW_HOURS} hours. Claim it with ` +\n 'a Sanity account before the deadline and everything you have built stays exactly as it is. ' +\n 'Claiming is free and takes about a minute. Miss the deadline and the project and its ' +\n 'content are deleted.',\n 'Two things to keep private: the claim link, because anyone who opens it becomes the owner, ' +\n `and the access token saved in ./${STUDIO_ENV_FILE} and ./${FRONTEND_ENV_FILE}, because it ` +\n 'can read and change everything in the project. Keep both env files out of git, and never ' +\n 'put the token in code that runs in the browser.',\n 'Run this command with --instructions for the full agent setup guide.',\n )\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Create a project with a Studio and a website',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My New Project\"',\n description: 'Create a project called \"My New Project\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --yes',\n description: 'Create a project without being asked anything',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --no-scaffold',\n description: 'Create the project only, with no Studio or website',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'Create a project and print its details as JSON',\n },\n\n {\n command: '<%= config.bin %> <%= command.id %> --instructions',\n description: 'Print the full setup guide for an AI agent, without creating anything',\n },\n ]\n\n static override flags = {\n instructions: Flags.boolean({\n default: false,\n description: `Print the full setup guide from ${SANITY_NEW_URL} and exit, creating nothing`,\n }),\n scaffold: Flags.boolean({\n allowNo: true,\n default: true,\n description: `Set up a Studio in ./${STUDIO_DIR} and a Next.js website in ./${FRONTEND_DIR} (on by default)`,\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: `Skip prompts and use defaults (project: \"${DEFAULT_PROJECT_NAME}\")`,\n }),\n }\n\n static override summary = `Create a Sanity project without an account, and claim it within ${CLAIM_WINDOW_HOURS} hours to keep it.`\n\n public async run(): Promise<NewProjectResult | undefined> {\n const {output} = this\n const json = this.jsonEnabled()\n const flow = createFlow(output.log)\n const invoked = [this.config.bin, ...(this.id?.split(':') ?? [])].join(' ')\n const cwd = process.cwd()\n\n // Runs before every precondition and side effect: this flag creates nothing.\n if (this.flags.instructions) {\n // oclif's `exclusive` does not cover the json flag added by enableJsonFlag, so guard it here.\n if (json) {\n throw new CLIError('--instructions cannot be combined with --json.', {\n code: 'INSTRUCTIONS_JSON_CONFLICT',\n exit: exitCodes.USAGE_ERROR,\n suggestions: [\n `Run \\`${invoked} --instructions\\` for the setup guide as markdown`,\n `Or run \\`${invoked} --json\\` to create a project and print its details as JSON`,\n ],\n })\n }\n\n await this.printInstructions()\n return undefined\n }\n\n const unavailableScaffoldTarget =\n !json && this.flags.scaffold ? await getUnavailableScaffoldTarget(cwd) : undefined\n if (unavailableScaffoldTarget) {\n throw new CLIError(\n `./${unavailableScaffoldTarget} is not an empty directory. No project was created.`,\n {\n code:\n unavailableScaffoldTarget === STUDIO_DIR\n ? 'EXISTING_STUDIO_DIRECTORY'\n : 'EXISTING_FRONTEND_DIRECTORY',\n exit: exitCodes.RUNTIME_ERROR,\n suggestions: [\n `Run this command where ./${unavailableScaffoldTarget} does not exist or is an empty directory`,\n `Or run \\`${invoked} --no-scaffold\\` to create the project without changing ./${unavailableScaffoldTarget}`,\n ],\n },\n )\n }\n\n if (!json) {\n renderNewCommandSplash(output.log)\n flow.intro('Setting up your Sanity project.')\n flow.gap()\n\n if (!this.isUnattended()) {\n flow.note(\n `${styleText('cyan', `${invoked} --yes`)} for a non-interactive flow with defaults.`,\n )\n flow.gap()\n }\n }\n\n let displayName = this.args.projectName?.trim()\n if (!displayName && this.isUnattended()) {\n displayName = DEFAULT_PROJECT_NAME\n } else if (!displayName) {\n displayName =\n (\n await input({\n default: DEFAULT_PROJECT_NAME,\n message: 'Project name',\n })\n ).trim() || DEFAULT_PROJECT_NAME\n }\n\n const spin = json ? undefined : flow.spin('Creating your project...')\n let project: MintedProject\n try {\n project = await mintUnclaimedProject({displayName})\n } catch (err) {\n spin?.fail('Creating your project failed.')\n throw err\n }\n\n const recorded = recordUnclaimedProject(project)\n spin?.succeed(`Created \"${displayName}\"`)\n\n if (!json) {\n flow.result(`Project ID: ${styleText('cyan', project.resourceId)}`)\n flow.result(`Dataset: ${styleText('cyan', project.datasetName)} (where your content lives)`)\n flow.result(`Token: ${styleText('cyan', project.token)}`)\n flow.link(project.claimUrl, {label: 'Claim link:'})\n flow.gap()\n flow.highlight(\n `Claim your project by ${styleText('yellow', formatClaimDeadline(project.expiresAt))} to avoid losing it.`,\n )\n flow.gap()\n flow.line('To use the Sanity CLI before claiming use your token by setting')\n flow.command(`SANITY_AUTH_TOKEN=\"${project.token}\" sanity \"command\"`)\n flow.gap()\n flow.note(\n styleText(\n 'dim',\n 'If you are an agent: give this claim URL to the person you are working for. They have ' +\n 'to open it themselves before the deadline.',\n ),\n )\n flow.gap()\n }\n\n const studioUrl =\n `http://localhost:3333/#token=${encodeURIComponent(project.token)}` +\n `&claim=${encodeURIComponent(project.claimUrl)}`\n\n const printStudioInstructions = () => {\n flow.highlight('Start your Studio:')\n flow.gap()\n flow.command(`cd ${STUDIO_DIR} && npx sanity@latest dev`)\n flow.gap()\n flow.link(studioUrl, {label: 'Then open this link:'})\n flow.gap()\n flow.line('The token signs you in: there is no account yet.')\n }\n const printWebsiteInstructions = (packageManager: ScaffoldResult['frontendPackageManager']) => {\n flow.highlight('In a separate terminal, start your website:')\n flow.gap()\n flow.command(`cd ${FRONTEND_DIR} && ${frontendDevCommand(packageManager)}`)\n flow.gap()\n flow.link('http://localhost:3000', {label: 'Then open this link:'})\n }\n\n let scaffold: ScaffoldResult | undefined\n if (!json && this.flags.scaffold) {\n const scaffoldController = new AbortController()\n const abortScaffold = () => scaffoldController.abort(new Error('SIGINT'))\n process.once('SIGINT', abortScaffold)\n try {\n scaffold = await scaffoldProject({\n cancelSignal: scaffoldController.signal,\n dataset: project.datasetName,\n displayName,\n output,\n projectId: project.resourceId,\n telemetry: this.telemetry,\n token: project.token,\n workDir: cwd,\n })\n scaffoldController.signal.throwIfAborted()\n } catch (err) {\n if (\n scaffoldController.signal.aborted ||\n (err instanceof Error && err.message === 'SIGINT')\n ) {\n throw err\n }\n // Scaffolding is best-effort and may leave files or directories behind when it fails.\n // Partial filesystem state does not prove the scaffold is runnable, so report the failure,\n // continue only with the project/token/claim handoff below, and do not attempt cleanup.\n flow.note(`Automatic setup did not finish: ${err instanceof Error ? err.message : err}`)\n flow.line('The project was created. You do not need to create another one.')\n flow.gap()\n } finally {\n process.off('SIGINT', abortScaffold)\n }\n }\n\n if (scaffold) {\n if (scaffold.frontendPath) {\n flow.result('Created two folders')\n flow.line(`./${STUDIO_DIR}: your Studio, where you write and edit content`)\n flow.line(`./${FRONTEND_DIR}: your website, a Next.js app that reads it`)\n flow.gap()\n printStudioInstructions()\n if (scaffold.frontendDependenciesInstalled === false) {\n flow.gap()\n if (scaffold.frontendDependencyError) {\n flow.line(`Installing website dependencies failed: ${scaffold.frontendDependencyError}`)\n flow.gap()\n }\n flow.highlight('Finish installing your website dependencies')\n flow.gap()\n flow.command(\n `cd ${FRONTEND_DIR} && ${frontendInstallCommand(scaffold.frontendPackageManager)}`,\n )\n }\n flow.gap()\n printWebsiteInstructions(scaffold.frontendPackageManager)\n } else if (scaffold.detectedFramework) {\n flow.result(`Created ./${STUDIO_DIR} for your existing ${scaffold.detectedFramework} app`)\n flow.line(`./${STUDIO_DIR}: your Studio, where you write and edit content`)\n flow.line(`Your existing ${scaffold.detectedFramework} frontend was left unchanged.`)\n flow.gap()\n printStudioInstructions()\n } else {\n flow.result(`Created ./${STUDIO_DIR}`)\n flow.line(`./${STUDIO_DIR}: your Studio, where you write and edit content`)\n flow.line(\n `The website was not created: ${scaffold.frontendCreationError ?? 'automatic setup did not finish'}`,\n )\n flow.gap()\n printStudioInstructions()\n }\n flow.gap()\n }\n\n if (recorded === false && !json) {\n flow.note('The local recovery record was not saved.')\n flow.line('Keep the claim URL and access token from this output.')\n flow.gap()\n }\n\n if (!json) {\n if (!scaffold && !this.flags.scaffold) {\n flow.result('Project created without scaffolding')\n flow.line(\n 'No folders or env files were created. Use the project ID and dataset above in your own setup.',\n )\n flow.gap()\n flow.link(studioUrl, {\n label: 'Once a Studio is running on http://localhost:3333, sign in with:',\n })\n flow.gap()\n flow.line('The token signs you in: there is no account yet.')\n flow.gap()\n }\n\n flow.line('Your content is private until you claim, to read it, you need the token.')\n flow.line(\"Treat your token as a password and don't expose it publicly in your app.\")\n flow.gap()\n flow.line(\n 'The claim link and token are printed above but you can recover them ' +\n `with ${styleText('cyan', 'sanity projects unclaimed')} before the timer runs out on ${formatClaimDeadline(project.expiresAt)}.`,\n )\n flow.gap()\n flow.line(project.termsNotice)\n flow.link(project.termsUrl, {label: 'Terms of Service:'})\n flow.gap()\n flow.line('For more information on how claiming works or how to build your app')\n flow.link(SANITY_NEW_URL, {label: 'visit', outro: true})\n }\n\n return toResult(project)\n }\n\n /**\n * Dumps the guide from sanity.new verbatim, so an agent gets the whole document rather than a\n * summary produced by whatever fetched it.\n */\n private async printInstructions(): Promise<void> {\n let instructions: string\n try {\n instructions = await fetchNewInstructions()\n } catch (err) {\n if (err instanceof InstructionsUnavailableError) {\n throw new CLIError(err.message, {\n code: 'INSTRUCTIONS_UNAVAILABLE',\n exit: exitCodes.RUNTIME_ERROR,\n suggestions: [\n `Fetch them directly: curl -sSL ${INSTRUCTIONS_URL}`,\n `Or open ${SANITY_NEW_URL} in a browser`,\n ],\n })\n }\n throw err\n }\n\n this.output.log(`${INSTRUCTIONS_HEADER}\\n\\n${instructions}`)\n }\n}\n"],"names":["styleText","Args","Flags","CLIError","exitCodes","SanityCommand","createFlow","input","FRONTEND_DIR","FRONTEND_ENV_FILE","getUnavailableScaffoldTarget","scaffoldProject","STUDIO_DIR","STUDIO_ENV_FILE","mintUnclaimedProject","fetchNewInstructions","INSTRUCTIONS_URL","InstructionsUnavailableError","formatClaimDeadline","CLAIM_WINDOW_HOURS","SANITY_NEW_URL","renderNewCommandSplash","recordUnclaimedProject","DEFAULT_PROJECT_NAME","HELP_DESCRIPTION_WIDTH","INSTRUCTIONS_HEADER","formatHelpDescription","paragraphs","map","paragraph","lines","line","word","split","length","push","join","FRONTEND_DEV_COMMANDS","bun","manual","npm","pnpm","yarn","frontendDevCommand","packageManager","frontendInstallCommand","toResult","project","apiHost","claimApiUrl","claimToken","claimUrl","dataset","datasetName","expiresAt","projectId","resourceId","terms","notice","termsNotice","url","termsUrl","token","NewCommand","args","projectName","string","description","required","enableJsonFlag","examples","command","flags","instructions","boolean","default","scaffold","allowNo","yes","char","summary","run","output","json","jsonEnabled","flow","log","invoked","config","bin","id","cwd","process","code","exit","USAGE_ERROR","suggestions","printInstructions","undefined","unavailableScaffoldTarget","RUNTIME_ERROR","intro","gap","isUnattended","note","displayName","trim","message","spin","err","fail","recorded","succeed","result","link","label","highlight","studioUrl","encodeURIComponent","printStudioInstructions","printWebsiteInstructions","scaffoldController","AbortController","abortScaffold","abort","Error","once","cancelSignal","signal","telemetry","workDir","throwIfAborted","aborted","off","frontendPath","frontendDependenciesInstalled","frontendDependencyError","frontendPackageManager","detectedFramework","frontendCreationError","outro"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
2
2
|
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
3
|
-
import { Table } from 'console-table-printer';
|
|
4
3
|
import { listOrganizations } from '../../services/organizations.js';
|
|
5
4
|
import { organizationAliases } from '../../util/organizationAliases.js';
|
|
5
|
+
import { Table } from '../../util/responsiveTable.js';
|
|
6
6
|
const listOrgsDebug = subdebug('organizations:list');
|
|
7
7
|
export class ListOrganizationsCommand extends SanityCommand {
|
|
8
8
|
static description = 'List organizations you are a member of';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/organizations/list.ts"],"sourcesContent":["import {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/organizations/list.ts"],"sourcesContent":["import {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\n\nimport {listOrganizations} from '../../services/organizations.js'\nimport {organizationAliases} from '../../util/organizationAliases.js'\nimport {Table} from '../../util/responsiveTable.js'\n\nconst listOrgsDebug = subdebug('organizations:list')\n\nexport class ListOrganizationsCommand extends SanityCommand<typeof ListOrganizationsCommand> {\n static override description = 'List organizations you are a member of'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all your organizations',\n },\n ]\n\n static override hiddenAliases = organizationAliases('list')\n\n public async run(): Promise<void> {\n let organizations\n try {\n organizations = await listOrganizations()\n } catch (error) {\n listOrgsDebug('Error listing organizations', error)\n this.error(`Failed to list organizations: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (organizations.length === 0) {\n this.log('No organizations found')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'name', title: 'Name'},\n {alignment: 'left', name: 'slug', title: 'Slug'},\n ],\n })\n\n for (const {id, name, slug} of organizations) {\n table.addRow({id, name, slug: slug ?? '-'})\n }\n\n this.log(table.render())\n }\n}\n"],"names":["exitCodes","SanityCommand","subdebug","getErrorMessage","listOrganizations","organizationAliases","Table","listOrgsDebug","ListOrganizationsCommand","description","examples","command","hiddenAliases","run","organizations","error","exit","RUNTIME_ERROR","length","log","table","columns","alignment","name","title","id","slug","addRow","render"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AAEvD,SAAQC,iBAAiB,QAAO,kCAAiC;AACjE,SAAQC,mBAAmB,QAAO,oCAAmC;AACrE,SAAQC,KAAK,QAAO,gCAA+B;AAEnD,MAAMC,gBAAgBL,SAAS;AAE/B,OAAO,MAAMM,iCAAiCP;IAC5C,OAAgBQ,cAAc,yCAAwC;IAEtE,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,OAAgBG,gBAAgBP,oBAAoB,QAAO;IAE3D,MAAaQ,MAAqB;QAChC,IAAIC;QACJ,IAAI;YACFA,gBAAgB,MAAMV;QACxB,EAAE,OAAOW,OAAO;YACdR,cAAc,+BAA+BQ;YAC7C,IAAI,CAACA,KAAK,CAAC,CAAC,8BAA8B,EAAEZ,gBAAgBY,QAAQ,EAAE;gBACpEC,MAAMhB,UAAUiB,aAAa;YAC/B;QACF;QAEA,IAAIH,cAAcI,MAAM,KAAK,GAAG;YAC9B,IAAI,CAACC,GAAG,CAAC;YACT;QACF;QAEA,MAAMC,QAAQ,IAAId,MAAM;YACtBe,SAAS;gBACP;oBAACC,WAAW;oBAAQC,MAAM;oBAAMC,OAAO;gBAAI;gBAC3C;oBAACF,WAAW;oBAAQC,MAAM;oBAAQC,OAAO;gBAAM;gBAC/C;oBAACF,WAAW;oBAAQC,MAAM;oBAAQC,OAAO;gBAAM;aAChD;QACH;QAEA,KAAK,MAAM,EAACC,EAAE,EAAEF,IAAI,EAAEG,IAAI,EAAC,IAAIZ,cAAe;YAC5CM,MAAMO,MAAM,CAAC;gBAACF;gBAAIF;gBAAMG,MAAMA,QAAQ;YAAG;QAC3C;QAEA,IAAI,CAACP,GAAG,CAACC,MAAMQ,MAAM;IACvB;AACF"}
|