@sanity/cli 6.0.0 → 6.1.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 +78 -111
- package/dist/actions/manifest/extractWorkspaceManifest.js +12 -5
- package/dist/actions/manifest/extractWorkspaceManifest.js.map +1 -1
- package/dist/actions/mcp/detectAvailableEditors.js +19 -10
- package/dist/actions/mcp/detectAvailableEditors.js.map +1 -1
- package/dist/actions/mcp/editorConfigs.js +222 -158
- package/dist/actions/mcp/editorConfigs.js.map +1 -1
- package/dist/actions/mcp/promptForMCPSetup.js +16 -7
- package/dist/actions/mcp/promptForMCPSetup.js.map +1 -1
- package/dist/actions/mcp/setupMCP.js +62 -23
- package/dist/actions/mcp/setupMCP.js.map +1 -1
- package/dist/actions/mcp/types.js.map +1 -1
- package/dist/actions/mcp/validateEditorTokens.js +56 -0
- package/dist/actions/mcp/validateEditorTokens.js.map +1 -0
- package/dist/actions/schema/uploadSchemaToLexicon.js +6 -4
- package/dist/actions/schema/uploadSchemaToLexicon.js.map +1 -1
- package/dist/actions/telemetry/telemetryDebug.js +2 -2
- package/dist/actions/telemetry/telemetryDebug.js.map +1 -1
- package/dist/commands/init.js +9 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp/configure.js +3 -1
- package/dist/commands/mcp/configure.js.map +1 -1
- package/dist/commands/preview.js +3 -4
- package/dist/commands/preview.js.map +1 -1
- package/dist/hooks/prerun/setupTelemetry.js +7 -7
- package/dist/hooks/prerun/setupTelemetry.js.map +1 -1
- package/dist/services/mcp.js +55 -1
- package/dist/services/mcp.js.map +1 -1
- package/dist/util/getLocalPackageVersion.js +4 -2
- package/dist/util/getLocalPackageVersion.js.map +1 -1
- package/dist/util/getProjectDefaults.js +22 -28
- package/dist/util/getProjectDefaults.js.map +1 -1
- package/dist/util/gitConfig.js +45 -0
- package/dist/util/gitConfig.js.map +1 -0
- package/dist/util/telemetry/telemetryStoreDebug.js +2 -2
- package/dist/util/telemetry/telemetryStoreDebug.js.map +1 -1
- package/oclif.manifest.json +83 -83
- package/package.json +4 -6
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import { checkbox } from '@sanity/cli-core/ux';
|
|
2
|
+
function getEditorLabel(editor) {
|
|
3
|
+
if (editor.configured && editor.authStatus === 'unauthorized') {
|
|
4
|
+
return `${editor.name} (auth expired)`;
|
|
5
|
+
}
|
|
6
|
+
if (editor.configured && !editor.existingToken) {
|
|
7
|
+
return `${editor.name} (missing credentials)`;
|
|
8
|
+
}
|
|
9
|
+
return editor.name;
|
|
10
|
+
}
|
|
2
11
|
/**
|
|
3
|
-
* Prompt user to select which editors to configure
|
|
4
|
-
*
|
|
5
|
-
*
|
|
12
|
+
* Prompt user to select which editors to configure.
|
|
13
|
+
*
|
|
14
|
+
* Expects only actionable editors (unconfigured, or configured with
|
|
15
|
+
* invalid/missing credentials). Annotates entries with auth status.
|
|
6
16
|
*/ export async function promptForMCPSetup(editors) {
|
|
7
17
|
const editorChoices = editors.map((e)=>({
|
|
8
|
-
checked:
|
|
9
|
-
name: e
|
|
18
|
+
checked: true,
|
|
19
|
+
name: getEditorLabel(e),
|
|
10
20
|
value: e.name
|
|
11
21
|
}));
|
|
12
|
-
const
|
|
22
|
+
const selectedNames = await checkbox({
|
|
13
23
|
choices: editorChoices,
|
|
14
24
|
message: 'Configure Sanity MCP server?'
|
|
15
25
|
});
|
|
16
|
-
const selectedNames = result;
|
|
17
26
|
// User can deselect all to skip
|
|
18
27
|
if (!selectedNames || selectedNames.length === 0) {
|
|
19
28
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/mcp/promptForMCPSetup.ts"],"sourcesContent":["import {checkbox} from '@sanity/cli-core/ux'\n\nimport {type Editor} from './types.js'\n\n/**\n * Prompt user to select which editors to configure
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/mcp/promptForMCPSetup.ts"],"sourcesContent":["import {checkbox} from '@sanity/cli-core/ux'\n\nimport {type Editor} from './types.js'\n\nfunction getEditorLabel(editor: Editor): string {\n if (editor.configured && editor.authStatus === 'unauthorized') {\n return `${editor.name} (auth expired)`\n }\n if (editor.configured && !editor.existingToken) {\n return `${editor.name} (missing credentials)`\n }\n return editor.name\n}\n\n/**\n * Prompt user to select which editors to configure.\n *\n * Expects only actionable editors (unconfigured, or configured with\n * invalid/missing credentials). Annotates entries with auth status.\n */\nexport async function promptForMCPSetup(editors: Editor[]): Promise<Editor[] | null> {\n const editorChoices = editors.map((e) => ({\n checked: true, // Pre-select all actionable editors\n name: getEditorLabel(e),\n value: e.name,\n }))\n\n const selectedNames = await checkbox({\n choices: editorChoices,\n message: 'Configure Sanity MCP server?',\n })\n\n // User can deselect all to skip\n if (!selectedNames || selectedNames.length === 0) {\n return null\n }\n\n return editors.filter((e) => selectedNames.includes(e.name))\n}\n"],"names":["checkbox","getEditorLabel","editor","configured","authStatus","name","existingToken","promptForMCPSetup","editors","editorChoices","map","e","checked","value","selectedNames","choices","message","length","filter","includes"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,sBAAqB;AAI5C,SAASC,eAAeC,MAAc;IACpC,IAAIA,OAAOC,UAAU,IAAID,OAAOE,UAAU,KAAK,gBAAgB;QAC7D,OAAO,GAAGF,OAAOG,IAAI,CAAC,eAAe,CAAC;IACxC;IACA,IAAIH,OAAOC,UAAU,IAAI,CAACD,OAAOI,aAAa,EAAE;QAC9C,OAAO,GAAGJ,OAAOG,IAAI,CAAC,sBAAsB,CAAC;IAC/C;IACA,OAAOH,OAAOG,IAAI;AACpB;AAEA;;;;;CAKC,GACD,OAAO,eAAeE,kBAAkBC,OAAiB;IACvD,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC,CAACC,IAAO,CAAA;YACxCC,SAAS;YACTP,MAAMJ,eAAeU;YACrBE,OAAOF,EAAEN,IAAI;QACf,CAAA;IAEA,MAAMS,gBAAgB,MAAMd,SAAS;QACnCe,SAASN;QACTO,SAAS;IACX;IAEA,gCAAgC;IAChC,IAAI,CAACF,iBAAiBA,cAAcG,MAAM,KAAK,GAAG;QAChD,OAAO;IACT;IAEA,OAAOT,QAAQU,MAAM,CAAC,CAACP,IAAMG,cAAcK,QAAQ,CAACR,EAAEN,IAAI;AAC5D"}
|
|
@@ -4,17 +4,20 @@ import { logSymbols } from '@sanity/cli-core/ux';
|
|
|
4
4
|
import { createMCPToken, MCP_SERVER_URL } from '../../services/mcp.js';
|
|
5
5
|
import { detectAvailableEditors } from './detectAvailableEditors.js';
|
|
6
6
|
import { promptForMCPSetup } from './promptForMCPSetup.js';
|
|
7
|
+
import { validateEditorTokens } from './validateEditorTokens.js';
|
|
7
8
|
import { writeMCPConfig } from './writeMCPConfig.js';
|
|
8
9
|
const mcpDebug = subdebug('mcp:setup');
|
|
9
10
|
const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`;
|
|
10
11
|
/**
|
|
11
12
|
* Main MCP setup orchestration
|
|
12
|
-
* Opt-out by default: runs automatically unless
|
|
13
|
-
*/ export async function setupMCP(
|
|
13
|
+
* Opt-out by default: runs automatically unless skip option is set
|
|
14
|
+
*/ export async function setupMCP(options) {
|
|
15
|
+
const { explicit = false, skip = false } = options ?? {};
|
|
14
16
|
// 1. Check for explicit opt-out
|
|
15
|
-
if (
|
|
17
|
+
if (skip) {
|
|
16
18
|
ux.warn('Skipping MCP configuration due to --no-mcp flag');
|
|
17
19
|
return {
|
|
20
|
+
alreadyConfiguredEditors: [],
|
|
18
21
|
configuredEditors: [],
|
|
19
22
|
detectedEditors: [],
|
|
20
23
|
skipped: true
|
|
@@ -25,44 +28,79 @@ const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server f
|
|
|
25
28
|
const detectedEditors = editors.map((e)=>e.name);
|
|
26
29
|
mcpDebug('Detected %d editors: %s', detectedEditors.length, detectedEditors);
|
|
27
30
|
if (editors.length === 0) {
|
|
28
|
-
|
|
31
|
+
if (explicit) {
|
|
32
|
+
ux.warn(NO_EDITORS_DETECTED_MESSAGE);
|
|
33
|
+
}
|
|
29
34
|
return {
|
|
35
|
+
alreadyConfiguredEditors: [],
|
|
30
36
|
configuredEditors: [],
|
|
31
37
|
detectedEditors,
|
|
32
38
|
skipped: true
|
|
33
39
|
};
|
|
34
40
|
}
|
|
35
|
-
// 3.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
// 3. Validate existing tokens against the Sanity API
|
|
42
|
+
await validateEditorTokens(editors);
|
|
43
|
+
// 4. Check if there's anything actionable
|
|
44
|
+
const actionable = editors.filter((e)=>!e.configured || e.authStatus !== 'valid');
|
|
45
|
+
if (actionable.length === 0) {
|
|
46
|
+
mcpDebug('All editors configured with valid credentials');
|
|
47
|
+
const alreadyConfiguredEditors = editors.filter((e)=>e.configured && e.authStatus === 'valid').map((e)=>e.name);
|
|
48
|
+
if (explicit) {
|
|
49
|
+
ux.stdout(`${logSymbols.success} All detected editors are already configured`);
|
|
50
|
+
}
|
|
40
51
|
return {
|
|
52
|
+
alreadyConfiguredEditors,
|
|
41
53
|
configuredEditors: [],
|
|
42
54
|
detectedEditors,
|
|
43
55
|
skipped: true
|
|
44
56
|
};
|
|
45
57
|
}
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
ux.warn(`Could not configure MCP: ${err.message}`);
|
|
54
|
-
ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
|
|
58
|
+
// Non-actionable editors are already configured with valid credentials
|
|
59
|
+
const alreadyConfiguredEditors = editors.filter((e)=>!actionable.includes(e)).map((e)=>e.name);
|
|
60
|
+
// 5. Prompt user (shows only actionable editors, annotates auth issues)
|
|
61
|
+
const selected = await promptForMCPSetup(actionable);
|
|
62
|
+
if (!selected || selected.length === 0) {
|
|
63
|
+
// User deselected all editors
|
|
64
|
+
ux.stdout('MCP configuration skipped');
|
|
55
65
|
return {
|
|
66
|
+
alreadyConfiguredEditors,
|
|
56
67
|
configuredEditors: [],
|
|
57
68
|
detectedEditors,
|
|
58
|
-
|
|
59
|
-
skipped: false
|
|
69
|
+
skipped: true
|
|
60
70
|
};
|
|
61
71
|
}
|
|
62
|
-
//
|
|
72
|
+
// 6. Get a token — reuse a valid existing one or create a new one
|
|
73
|
+
let token;
|
|
74
|
+
// Look for an existing valid token we can reuse
|
|
75
|
+
const validEditor = editors.find((e)=>e.authStatus === 'valid' && e.existingToken);
|
|
76
|
+
if (validEditor?.existingToken) {
|
|
77
|
+
mcpDebug('Reusing valid token from %s', validEditor.name);
|
|
78
|
+
token = validEditor.existingToken;
|
|
79
|
+
}
|
|
80
|
+
// Fall back to creating a new token
|
|
81
|
+
if (!token) {
|
|
82
|
+
try {
|
|
83
|
+
token = await createMCPToken();
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
86
|
+
mcpDebug('Error creating MCP token', error);
|
|
87
|
+
ux.warn(`Could not configure MCP: ${err.message}`);
|
|
88
|
+
ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
|
|
89
|
+
return {
|
|
90
|
+
alreadyConfiguredEditors,
|
|
91
|
+
configuredEditors: [],
|
|
92
|
+
detectedEditors,
|
|
93
|
+
error: err,
|
|
94
|
+
skipped: false
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// 7. Write configs for each selected editor
|
|
99
|
+
const configuredEditors = [];
|
|
63
100
|
try {
|
|
64
101
|
for (const editor of selected){
|
|
65
102
|
await writeMCPConfig(editor, token);
|
|
103
|
+
configuredEditors.push(editor.name);
|
|
66
104
|
}
|
|
67
105
|
} catch (error) {
|
|
68
106
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
@@ -70,15 +108,16 @@ const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server f
|
|
|
70
108
|
ux.warn(`Could not configure MCP: ${err.message}`);
|
|
71
109
|
ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
|
|
72
110
|
return {
|
|
73
|
-
|
|
111
|
+
alreadyConfiguredEditors,
|
|
112
|
+
configuredEditors,
|
|
74
113
|
detectedEditors,
|
|
75
114
|
error: err,
|
|
76
115
|
skipped: false
|
|
77
116
|
};
|
|
78
117
|
}
|
|
79
|
-
const configuredEditors = selected.map((e)=>e.name);
|
|
80
118
|
ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`);
|
|
81
119
|
return {
|
|
120
|
+
alreadyConfiguredEditors,
|
|
82
121
|
configuredEditors,
|
|
83
122
|
detectedEditors,
|
|
84
123
|
skipped: false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/mcp/setupMCP.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {subdebug} from '@sanity/cli-core'\nimport {logSymbols} from '@sanity/cli-core/ux'\n\nimport {createMCPToken, MCP_SERVER_URL} from '../../services/mcp.js'\nimport {detectAvailableEditors} from './detectAvailableEditors.js'\nimport {type EditorName} from './editorConfigs.js'\nimport {promptForMCPSetup} from './promptForMCPSetup.js'\nimport {writeMCPConfig} from './writeMCPConfig.js'\n\nconst mcpDebug = subdebug('mcp:setup')\n\nconst NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`\n\ninterface MCPSetupResult {\n configuredEditors: EditorName[]\n detectedEditors: EditorName[]\n skipped: boolean\n\n error?: Error\n}\n\n/**\n * Main MCP setup orchestration\n * Opt-out by default: runs automatically unless
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/mcp/setupMCP.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {subdebug} from '@sanity/cli-core'\nimport {logSymbols} from '@sanity/cli-core/ux'\n\nimport {createMCPToken, MCP_SERVER_URL} from '../../services/mcp.js'\nimport {detectAvailableEditors} from './detectAvailableEditors.js'\nimport {type EditorName} from './editorConfigs.js'\nimport {promptForMCPSetup} from './promptForMCPSetup.js'\nimport {validateEditorTokens} from './validateEditorTokens.js'\nimport {writeMCPConfig} from './writeMCPConfig.js'\n\nconst mcpDebug = subdebug('mcp:setup')\n\nconst NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`\n\ninterface MCPSetupOptions {\n /**\n * Whether the user explicitly requested MCP configuration (e.g. `sanity mcp configure`).\n * When true, shows status messages even when there's nothing to do.\n * When false/undefined (e.g. called from `sanity init`), stays quiet.\n */\n explicit?: boolean\n\n /**\n * If true, skip MCP configuration entirely (e.g. --no-mcp flag).\n */\n skip?: boolean\n}\n\ninterface MCPSetupResult {\n /** Editors that were already configured with valid credentials (nothing to do) */\n alreadyConfiguredEditors: EditorName[]\n configuredEditors: EditorName[]\n detectedEditors: EditorName[]\n skipped: boolean\n\n error?: Error\n}\n\n/**\n * Main MCP setup orchestration\n * Opt-out by default: runs automatically unless skip option is set\n */\nexport async function setupMCP(options?: MCPSetupOptions): Promise<MCPSetupResult> {\n const {explicit = false, skip = false} = options ?? {}\n\n // 1. Check for explicit opt-out\n if (skip) {\n ux.warn('Skipping MCP configuration due to --no-mcp flag')\n return {\n alreadyConfiguredEditors: [],\n configuredEditors: [],\n detectedEditors: [],\n skipped: true,\n }\n }\n\n // 2. Detect available editors (filters out unparseable configs)\n const editors = await detectAvailableEditors()\n const detectedEditors = editors.map((e) => e.name)\n\n mcpDebug('Detected %d editors: %s', detectedEditors.length, detectedEditors)\n\n if (editors.length === 0) {\n if (explicit) {\n ux.warn(NO_EDITORS_DETECTED_MESSAGE)\n }\n return {\n alreadyConfiguredEditors: [],\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // 3. Validate existing tokens against the Sanity API\n await validateEditorTokens(editors)\n\n // 4. Check if there's anything actionable\n const actionable = editors.filter((e) => !e.configured || e.authStatus !== 'valid')\n\n if (actionable.length === 0) {\n mcpDebug('All editors configured with valid credentials')\n const alreadyConfiguredEditors = editors\n .filter((e) => e.configured && e.authStatus === 'valid')\n .map((e) => e.name)\n if (explicit) {\n ux.stdout(`${logSymbols.success} All detected editors are already configured`)\n }\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // Non-actionable editors are already configured with valid credentials\n const alreadyConfiguredEditors = editors.filter((e) => !actionable.includes(e)).map((e) => e.name)\n\n // 5. Prompt user (shows only actionable editors, annotates auth issues)\n const selected = await promptForMCPSetup(actionable)\n\n if (!selected || selected.length === 0) {\n // User deselected all editors\n ux.stdout('MCP configuration skipped')\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // 6. Get a token — reuse a valid existing one or create a new one\n let token: string | undefined\n\n // Look for an existing valid token we can reuse\n const validEditor = editors.find((e) => e.authStatus === 'valid' && e.existingToken)\n if (validEditor?.existingToken) {\n mcpDebug('Reusing valid token from %s', validEditor.name)\n token = validEditor.existingToken\n }\n\n // Fall back to creating a new token\n if (!token) {\n try {\n token = await createMCPToken()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error creating MCP token', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n error: err,\n skipped: false,\n }\n }\n }\n\n // 7. Write configs for each selected editor\n const configuredEditors: EditorName[] = []\n try {\n for (const editor of selected) {\n await writeMCPConfig(editor, token)\n configuredEditors.push(editor.name)\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error writing MCP config', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n return {\n alreadyConfiguredEditors,\n configuredEditors,\n detectedEditors,\n error: err,\n skipped: false,\n }\n }\n\n ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`)\n\n return {\n alreadyConfiguredEditors,\n configuredEditors,\n detectedEditors,\n skipped: false,\n }\n}\n"],"names":["ux","subdebug","logSymbols","createMCPToken","MCP_SERVER_URL","detectAvailableEditors","promptForMCPSetup","validateEditorTokens","writeMCPConfig","mcpDebug","NO_EDITORS_DETECTED_MESSAGE","setupMCP","options","explicit","skip","warn","alreadyConfiguredEditors","configuredEditors","detectedEditors","skipped","editors","map","e","name","length","actionable","filter","configured","authStatus","stdout","success","includes","selected","token","validEditor","find","existingToken","error","err","Error","String","message","editor","push","join"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/mcp/types.ts"],"sourcesContent":["import {type EditorName} from './editorConfigs.js'\n\nexport interface Editor {\n configPath: string\n /** Whether Sanity MCP is already configured for this editor */\n configured: boolean\n name: EditorName\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/mcp/types.ts"],"sourcesContent":["import {type EditorName} from './editorConfigs.js'\n\n/** Auth credential status for a configured editor */\nexport type AuthStatus = 'unauthorized' | 'valid'\n\nexport interface Editor {\n configPath: string\n /** Whether Sanity MCP is already configured for this editor */\n configured: boolean\n name: EditorName\n\n /**\n * Auth status of the existing token. Only set for editors that have\n * a Sanity MCP config with a token that has been validated against the API.\n */\n authStatus?: AuthStatus\n /** The existing auth token found in the editor config, if any */\n existingToken?: string\n}\n"],"names":[],"mappings":"AAKA,WAaC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { subdebug } from '@sanity/cli-core';
|
|
2
|
+
import { validateMCPToken } from '../../services/mcp.js';
|
|
3
|
+
const debug = subdebug('mcp:validateEditorTokens');
|
|
4
|
+
/**
|
|
5
|
+
* Validate existing MCP tokens for all configured editors.
|
|
6
|
+
*
|
|
7
|
+
* Collects unique tokens, validates each once against the Sanity API,
|
|
8
|
+
* and sets `authStatus` on each editor that has a token.
|
|
9
|
+
* Editors without a config or token are left unchanged.
|
|
10
|
+
*/ export async function validateEditorTokens(editors) {
|
|
11
|
+
// Collect unique tokens and map them to their editors
|
|
12
|
+
const tokenToEditors = new Map();
|
|
13
|
+
for (const editor of editors){
|
|
14
|
+
if (editor.existingToken) {
|
|
15
|
+
const existing = tokenToEditors.get(editor.existingToken);
|
|
16
|
+
if (existing) {
|
|
17
|
+
existing.push(editor);
|
|
18
|
+
} else {
|
|
19
|
+
tokenToEditors.set(editor.existingToken, [
|
|
20
|
+
editor
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (tokenToEditors.size === 0) {
|
|
26
|
+
debug('No existing tokens to validate');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const editorCount = [
|
|
30
|
+
...tokenToEditors.values()
|
|
31
|
+
].reduce((sum, eds)=>sum + eds.length, 0);
|
|
32
|
+
debug('Validating %d unique token(s) across %d editor(s)', tokenToEditors.size, editorCount);
|
|
33
|
+
// Validate all unique tokens in parallel to avoid stacking timeouts
|
|
34
|
+
await Promise.all([
|
|
35
|
+
...tokenToEditors.entries()
|
|
36
|
+
].map(async ([token, tokenEditors])=>{
|
|
37
|
+
let status;
|
|
38
|
+
try {
|
|
39
|
+
const valid = await validateMCPToken(token);
|
|
40
|
+
status = valid ? 'valid' : 'unauthorized';
|
|
41
|
+
} catch (err) {
|
|
42
|
+
// Network errors, timeouts, or unexpected failures — assume the token
|
|
43
|
+
// is valid rather than falsely marking it as expired. We only mark
|
|
44
|
+
// tokens as unauthorized when the server explicitly says so (401/403).
|
|
45
|
+
debug('Token validation error (assuming valid): %s', err);
|
|
46
|
+
status = 'valid';
|
|
47
|
+
}
|
|
48
|
+
debug('Token ending ...%s is %s (used by %s)', token.slice(-4), status, tokenEditors.map((e)=>e.name).join(', '));
|
|
49
|
+
// Apply status to all editors sharing this token
|
|
50
|
+
for (const editor of tokenEditors){
|
|
51
|
+
editor.authStatus = status;
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=validateEditorTokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/mcp/validateEditorTokens.ts"],"sourcesContent":["import {subdebug} from '@sanity/cli-core'\n\nimport {validateMCPToken} from '../../services/mcp.js'\nimport {type AuthStatus, type Editor} from './types.js'\n\nconst debug = subdebug('mcp:validateEditorTokens')\n\n/**\n * Validate existing MCP tokens for all configured editors.\n *\n * Collects unique tokens, validates each once against the Sanity API,\n * and sets `authStatus` on each editor that has a token.\n * Editors without a config or token are left unchanged.\n */\nexport async function validateEditorTokens(editors: Editor[]): Promise<void> {\n // Collect unique tokens and map them to their editors\n const tokenToEditors = new Map<string, Editor[]>()\n for (const editor of editors) {\n if (editor.existingToken) {\n const existing = tokenToEditors.get(editor.existingToken)\n if (existing) {\n existing.push(editor)\n } else {\n tokenToEditors.set(editor.existingToken, [editor])\n }\n }\n }\n\n if (tokenToEditors.size === 0) {\n debug('No existing tokens to validate')\n return\n }\n\n const editorCount = [...tokenToEditors.values()].reduce((sum, eds) => sum + eds.length, 0)\n debug('Validating %d unique token(s) across %d editor(s)', tokenToEditors.size, editorCount)\n\n // Validate all unique tokens in parallel to avoid stacking timeouts\n await Promise.all(\n [...tokenToEditors.entries()].map(async ([token, tokenEditors]) => {\n let status: AuthStatus\n try {\n const valid = await validateMCPToken(token)\n status = valid ? 'valid' : 'unauthorized'\n } catch (err) {\n // Network errors, timeouts, or unexpected failures — assume the token\n // is valid rather than falsely marking it as expired. We only mark\n // tokens as unauthorized when the server explicitly says so (401/403).\n debug('Token validation error (assuming valid): %s', err)\n status = 'valid'\n }\n\n debug(\n 'Token ending ...%s is %s (used by %s)',\n token.slice(-4),\n status,\n tokenEditors.map((e) => e.name).join(', '),\n )\n\n // Apply status to all editors sharing this token\n for (const editor of tokenEditors) {\n editor.authStatus = status\n }\n }),\n )\n}\n"],"names":["subdebug","validateMCPToken","debug","validateEditorTokens","editors","tokenToEditors","Map","editor","existingToken","existing","get","push","set","size","editorCount","values","reduce","sum","eds","length","Promise","all","entries","map","token","tokenEditors","status","valid","err","slice","e","name","join","authStatus"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,mBAAkB;AAEzC,SAAQC,gBAAgB,QAAO,wBAAuB;AAGtD,MAAMC,QAAQF,SAAS;AAEvB;;;;;;CAMC,GACD,OAAO,eAAeG,qBAAqBC,OAAiB;IAC1D,sDAAsD;IACtD,MAAMC,iBAAiB,IAAIC;IAC3B,KAAK,MAAMC,UAAUH,QAAS;QAC5B,IAAIG,OAAOC,aAAa,EAAE;YACxB,MAAMC,WAAWJ,eAAeK,GAAG,CAACH,OAAOC,aAAa;YACxD,IAAIC,UAAU;gBACZA,SAASE,IAAI,CAACJ;YAChB,OAAO;gBACLF,eAAeO,GAAG,CAACL,OAAOC,aAAa,EAAE;oBAACD;iBAAO;YACnD;QACF;IACF;IAEA,IAAIF,eAAeQ,IAAI,KAAK,GAAG;QAC7BX,MAAM;QACN;IACF;IAEA,MAAMY,cAAc;WAAIT,eAAeU,MAAM;KAAG,CAACC,MAAM,CAAC,CAACC,KAAKC,MAAQD,MAAMC,IAAIC,MAAM,EAAE;IACxFjB,MAAM,qDAAqDG,eAAeQ,IAAI,EAAEC;IAEhF,oEAAoE;IACpE,MAAMM,QAAQC,GAAG,CACf;WAAIhB,eAAeiB,OAAO;KAAG,CAACC,GAAG,CAAC,OAAO,CAACC,OAAOC,aAAa;QAC5D,IAAIC;QACJ,IAAI;YACF,MAAMC,QAAQ,MAAM1B,iBAAiBuB;YACrCE,SAASC,QAAQ,UAAU;QAC7B,EAAE,OAAOC,KAAK;YACZ,sEAAsE;YACtE,mEAAmE;YACnE,uEAAuE;YACvE1B,MAAM,+CAA+C0B;YACrDF,SAAS;QACX;QAEAxB,MACE,yCACAsB,MAAMK,KAAK,CAAC,CAAC,IACbH,QACAD,aAAaF,GAAG,CAAC,CAACO,IAAMA,EAAEC,IAAI,EAAEC,IAAI,CAAC;QAGvC,iDAAiD;QACjD,KAAK,MAAMzB,UAAUkB,aAAc;YACjClB,OAAO0B,UAAU,GAAGP;QACtB;IACF;AAEJ"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { styleText } from 'node:util';
|
|
2
2
|
import { ux } from '@oclif/core/ux';
|
|
3
|
-
import { getProjectCliClient, resolveLocalPackage, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { doImport, getProjectCliClient, resolveLocalPackage, subdebug } from '@sanity/cli-core';
|
|
4
4
|
import { spinner } from '@sanity/cli-core/ux';
|
|
5
5
|
import { SCHEMA_API_VERSION } from '../../services/schemas.js';
|
|
6
6
|
import { getLocalPackageVersion } from '../../util/getLocalPackageVersion.js';
|
|
7
|
-
|
|
7
|
+
const iconResolverPath = new URL('../manifest/iconResolver.js', import.meta.url).href;
|
|
8
8
|
const debug = subdebug('uploadSchemaToLexicon');
|
|
9
9
|
/**
|
|
10
10
|
* Uploads the schemas to Lexicon and returns the studio manifest
|
|
@@ -52,12 +52,14 @@ const debug = subdebug('uploadSchemaToLexicon');
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
+
// Lazy import to avoid pulling in @sanity/ui at module load time
|
|
56
|
+
const { resolveIcon } = await doImport(iconResolverPath);
|
|
55
57
|
// Generate studio manifest using the shared utility
|
|
56
58
|
const manifest = await generateStudioManifest({
|
|
57
59
|
buildId: JSON.stringify(Date.now()),
|
|
58
60
|
bundleVersion,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
// @todo replace with import from @sanity/schema/_internal in future
|
|
62
|
+
resolveIcon: async (workspace)=>await resolveIcon({
|
|
61
63
|
icon: workspace.icon,
|
|
62
64
|
subtitle: workspace.subtitle,
|
|
63
65
|
title: workspace.title || workspace.name || 'default',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/schema/uploadSchemaToLexicon.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {ux} from '@oclif/core/ux'\nimport {getProjectCliClient, resolveLocalPackage, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type StudioManifest, type Workspace} from 'sanity'\n\nimport {SCHEMA_API_VERSION} from '../../services/schemas.js'\nimport {getLocalPackageVersion} from '../../util/getLocalPackageVersion.js'\
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/schema/uploadSchemaToLexicon.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {ux} from '@oclif/core/ux'\nimport {doImport, getProjectCliClient, resolveLocalPackage, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type StudioManifest, type Workspace} from 'sanity'\n\nimport {SCHEMA_API_VERSION} from '../../services/schemas.js'\nimport {getLocalPackageVersion} from '../../util/getLocalPackageVersion.js'\n\nconst iconResolverPath = new URL('../manifest/iconResolver.js', import.meta.url).href\n\ninterface UploadSchemaToLexiconOptions {\n projectId: string\n workDir: string\n workspaces: Workspace[]\n\n verbose?: boolean\n}\n\nconst debug = subdebug('uploadSchemaToLexicon')\n\n/**\n * Uploads the schemas to Lexicon and returns the studio manifest\n * @param options - The options for the uploadSchemaToLexicon function\n * @returns The studio manifest\n */\nexport async function uploadSchemaToLexicon(\n options: UploadSchemaToLexiconOptions,\n): Promise<StudioManifest | null> {\n const {projectId, verbose, workDir, workspaces} = options\n const spin = spinner('Generating studio manifest').start()\n\n try {\n const schemaDescriptors = new Map<string, string>()\n\n const client = await getProjectCliClient({\n apiVersion: SCHEMA_API_VERSION,\n projectId,\n requestTagPrefix: 'sanity.cli.deploy',\n requireUser: true,\n })\n\n const [bundleVersion, {generateStudioManifest, uploadSchema}] = await Promise.all([\n getLocalPackageVersion('sanity', workDir),\n resolveLocalPackage<typeof import('sanity')>('sanity', workDir),\n ])\n\n if (!bundleVersion) {\n throw new Error('Failed to find sanity version')\n }\n\n for (const workspace of workspaces) {\n const workspaceClient = client.withConfig({\n dataset: workspace.dataset,\n projectId: workspace.projectId,\n })\n\n try {\n debug('Uploading schema to lexicon for workspace %o', {\n dataset: workspace.dataset,\n projectId: workspace.projectId,\n })\n const descriptorId = await uploadSchema(workspace.schema, workspaceClient)\n\n if (!descriptorId) {\n throw new Error(\n `Failed to get schema descriptor ID for workspace \"${workspace.name}\": upload returned empty result`,\n )\n }\n\n schemaDescriptors.set(workspace.name, descriptorId)\n debug(\n `Uploaded schema for workspace \"${workspace.name}\" to Lexicon with descriptor ID: ${descriptorId}`,\n )\n } catch (error) {\n debug('Error uploading schema to lexicon for workspace %o', error)\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(\n `Failed to upload schema for workspace \"${workspace.name}\": ${errorMessage}`,\n {cause: error},\n )\n }\n }\n\n // Lazy import to avoid pulling in @sanity/ui at module load time\n const {resolveIcon} = await doImport(iconResolverPath)\n\n // Generate studio manifest using the shared utility\n const manifest = await generateStudioManifest({\n buildId: JSON.stringify(Date.now()),\n bundleVersion,\n // @todo replace with import from @sanity/schema/_internal in future\n resolveIcon: async (workspace) =>\n (await resolveIcon({\n icon: workspace.icon,\n subtitle: workspace.subtitle,\n title: workspace.title || workspace.name || 'default',\n workDir,\n })) ?? undefined,\n resolveSchemaDescriptorId: (workspace) => schemaDescriptors.get(workspace.name),\n workspaces,\n })\n\n spin.succeed('Generated studio manifest')\n\n const studioManifest = manifest.workspaces.length === 0 ? null : manifest\n\n if (verbose) {\n if (studioManifest) {\n for (const workspace of studioManifest.workspaces) {\n ux.stdout(\n styleText(\n 'gray',\n `↳ projectId: ${workspace.projectId}, dataset: ${workspace.dataset}, schemaDescriptorId: ${workspace.schemaDescriptorId}`,\n ),\n )\n }\n } else {\n ux.stdout(`${styleText('gray', '↳ No workspaces found')}`)\n }\n }\n\n return studioManifest\n } catch (error) {\n spin.fail(error instanceof Error ? error.message : 'Unknown error')\n throw error\n }\n}\n"],"names":["styleText","ux","doImport","getProjectCliClient","resolveLocalPackage","subdebug","spinner","SCHEMA_API_VERSION","getLocalPackageVersion","iconResolverPath","URL","url","href","debug","uploadSchemaToLexicon","options","projectId","verbose","workDir","workspaces","spin","start","schemaDescriptors","Map","client","apiVersion","requestTagPrefix","requireUser","bundleVersion","generateStudioManifest","uploadSchema","Promise","all","Error","workspace","workspaceClient","withConfig","dataset","descriptorId","schema","name","set","error","errorMessage","message","cause","resolveIcon","manifest","buildId","JSON","stringify","Date","now","icon","subtitle","title","undefined","resolveSchemaDescriptorId","get","succeed","studioManifest","length","stdout","schemaDescriptorId","fail"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/telemetry/telemetryDebug.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/telemetry/telemetryDebug.ts"],"sourcesContent":["import debugIt from 'debug'\n\nexport const telemetryDebug = debugIt('telemetry:sanity:cli')\n"],"names":["debugIt","telemetryDebug"],"mappings":"AAAA,OAAOA,aAAa,QAAO;AAE3B,OAAO,MAAMC,iBAAiBD,QAAQ,wBAAuB"}
|
package/dist/commands/init.js
CHANGED
|
@@ -399,7 +399,9 @@ export class InitCommand extends SanityCommand {
|
|
|
399
399
|
workDir
|
|
400
400
|
});
|
|
401
401
|
// Set up MCP integration
|
|
402
|
-
const mcpResult = await setupMCP(
|
|
402
|
+
const mcpResult = await setupMCP({
|
|
403
|
+
skip: !this.flags.mcp
|
|
404
|
+
});
|
|
403
405
|
this._trace.log({
|
|
404
406
|
configuredEditors: mcpResult.configuredEditors,
|
|
405
407
|
detectedEditors: mcpResult.detectedEditors,
|
|
@@ -410,6 +412,12 @@ export class InitCommand extends SanityCommand {
|
|
|
410
412
|
this._trace.error(mcpResult.error);
|
|
411
413
|
}
|
|
412
414
|
const mcpConfigured = mcpResult.configuredEditors;
|
|
415
|
+
// Show checkmark for editors that were already configured
|
|
416
|
+
const { alreadyConfiguredEditors } = mcpResult;
|
|
417
|
+
if (alreadyConfiguredEditors.length > 0) {
|
|
418
|
+
const label = alreadyConfiguredEditors.length === 1 ? `${alreadyConfiguredEditors[0]} already configured for Sanity MCP` : `${alreadyConfiguredEditors.length} editors already configured for Sanity MCP`;
|
|
419
|
+
spinner(label).start().succeed();
|
|
420
|
+
}
|
|
413
421
|
if (isNextJs) {
|
|
414
422
|
await checkNextJsReactCompatibility({
|
|
415
423
|
detectedFramework,
|
|
@@ -751,11 +759,9 @@ export class InitCommand extends SanityCommand {
|
|
|
751
759
|
userAction: 'none'
|
|
752
760
|
};
|
|
753
761
|
}
|
|
754
|
-
const datasetInfo = 'Your content will be stored in a dataset that can be public or private, depending on\nwhether you want to query your content with or without authentication.\nThe default dataset configuration has a public dataset named "production".';
|
|
755
762
|
if (datasets.length === 0) {
|
|
756
763
|
debug('No datasets found for project, prompting for name');
|
|
757
764
|
if (opts.showDefaultConfigPrompt) {
|
|
758
|
-
this.log(datasetInfo);
|
|
759
765
|
defaultConfig = await promptForDefaultConfig();
|
|
760
766
|
}
|
|
761
767
|
const name = defaultConfig ? 'production' : await promptForDatasetName({
|
|
@@ -793,7 +799,6 @@ export class InitCommand extends SanityCommand {
|
|
|
793
799
|
const existingDatasetNames = datasets.map((ds)=>ds.name);
|
|
794
800
|
debug('User wants to create a new dataset, prompting for name');
|
|
795
801
|
if (opts.showDefaultConfigPrompt && !existingDatasetNames.includes('production')) {
|
|
796
|
-
this.log(datasetInfo);
|
|
797
802
|
defaultConfig = await promptForDefaultConfig();
|
|
798
803
|
}
|
|
799
804
|
const newDatasetName = defaultConfig ? 'production' : await promptForDatasetName({
|