@sanity/cli-core 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,6 +28,8 @@ const CLI_REQUEST_TAG_PREFIX = 'sanity.cli';
28
28
  ...apiHost ? {
29
29
  apiHost
30
30
  } : {},
31
+ // Suppress browser token warning since we mock browser environment in workers
32
+ ignoreBrowserTokenWarning: true,
31
33
  requester,
32
34
  requestTagPrefix: CLI_REQUEST_TAG_PREFIX,
33
35
  token,
@@ -58,6 +60,8 @@ const CLI_REQUEST_TAG_PREFIX = 'sanity.cli';
58
60
  ...apiHost ? {
59
61
  apiHost
60
62
  } : {},
63
+ // Suppress browser token warning since we mock browser environment in workers
64
+ ignoreBrowserTokenWarning: true,
61
65
  requester,
62
66
  requestTagPrefix: CLI_REQUEST_TAG_PREFIX,
63
67
  token,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/apiClient.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {\n type ClientConfig,\n type ClientError,\n createClient,\n requester as defaultRequester,\n isHttpError,\n type SanityClient,\n type ServerError,\n} from '@sanity/client'\n\nimport {generateHelpUrl} from '../util/generateHelpUrl.js'\nimport {getCliToken} from './getCliToken.js'\n\nconst apiHosts: Record<string, string | undefined> = {\n staging: 'https://api.sanity.work',\n}\n\nconst CLI_REQUEST_TAG_PREFIX = 'sanity.cli'\n\n/**\n * @public\n */\nexport interface GlobalCliClientOptions extends ClientConfig {\n /**\n * The API version to use for this client.\n */\n apiVersion: string\n\n /**\n * Whether to require a user to be authenticated to use this client.\n * Default: `false`.\n * Throws an error if `true` and user is not authenticated.\n */\n requireUser?: boolean\n\n /**\n * Whether to skip reading the stored CLI token. When `true`, the client will\n * have no token unless one is explicitly provided.\n * Default: `false`.\n */\n unauthenticated?: boolean\n}\n\n/**\n * Create a \"global\" (unscoped) Sanity API client.\n *\n * @public\n *\n * @param options - The options to use for the client.\n * @returns Promise that resolves to a configured Sanity API client.\n */\nexport async function getGlobalCliClient({\n requireUser,\n token: providedToken,\n unauthenticated,\n ...config\n}: GlobalCliClientOptions): Promise<SanityClient> {\n const requester = defaultRequester.clone()\n requester.use(authErrors())\n\n const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production'\n\n const apiHost = apiHosts[sanityEnv]\n\n // Use the provided token if set, otherwise fall back to the stored CLI token (unless unauthenticated)\n const token = providedToken || (unauthenticated ? undefined : await getCliToken())\n\n // If the token is not set and requireUser is true, throw an error\n if (!token && requireUser) {\n throw new Error('You must login first - run \"sanity login\"')\n }\n\n return createClient({\n ...(apiHost ? {apiHost} : {}),\n requester,\n requestTagPrefix: CLI_REQUEST_TAG_PREFIX,\n token,\n useCdn: false,\n useProjectHostname: false,\n ...config,\n })\n}\n\n/**\n * @public\n */\nexport interface ProjectCliClientOptions extends ClientConfig {\n /**\n * The API version to use for this client.\n */\n apiVersion: string\n\n /**\n * The project ID to use for this client.\n */\n projectId: string\n\n /**\n * The dataset to use for this client.\n */\n dataset?: string\n\n /**\n * Whether to require a user to be authenticated to use this client.\n * Default: `false`.\n * Throws an error if `true` and user is not authenticated.\n */\n requireUser?: boolean\n}\n\n/**\n * Create a \"project\" (scoped) Sanity API client.\n *\n * @public\n *\n * @param options - The options to use for the client.\n * @returns Promise that resolves to a configured Sanity API client.\n */\nexport async function getProjectCliClient({\n requireUser,\n token: providedToken,\n ...config\n}: ProjectCliClientOptions): Promise<SanityClient> {\n const requester = defaultRequester.clone()\n requester.use(authErrors())\n\n const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production'\n\n const apiHost = apiHosts[sanityEnv]\n\n // Use the provided token if it is set, otherwise get the token from the config file\n const token = providedToken || (await getCliToken())\n\n // If the token is not set and requireUser is true, throw an error\n if (!token && requireUser) {\n throw new Error('You must login first - run \"sanity login\"')\n }\n\n return createClient({\n ...(apiHost ? {apiHost} : {}),\n requester,\n requestTagPrefix: CLI_REQUEST_TAG_PREFIX,\n token,\n useCdn: false,\n useProjectHostname: true,\n ...config,\n })\n}\n\n/**\n * `get-it` middleware that checks for 401 authentication errors and extends the error with more\n * helpful guidance on what to do next.\n *\n * @returns get-it middleware with `onError` handler\n * @internal\n */\nfunction authErrors() {\n return {\n onError: (err: Error | null) => {\n if (!err || !isReqResError(err)) {\n return err\n }\n\n const statusCode = isHttpError(err) && err.response.body.statusCode\n if (statusCode === 401) {\n err.message = `${err.message}. You may need to login again with ${ux.colorize('cyan', 'sanity login')}.\\nFor more information, see ${generateHelpUrl('cli-errors')}.`\n }\n\n return err\n },\n }\n}\n\nfunction isReqResError(err: Error): err is ClientError | ServerError {\n return Object.prototype.hasOwnProperty.call(err, 'response')\n}\n"],"names":["ux","createClient","requester","defaultRequester","isHttpError","generateHelpUrl","getCliToken","apiHosts","staging","CLI_REQUEST_TAG_PREFIX","getGlobalCliClient","requireUser","token","providedToken","unauthenticated","config","clone","use","authErrors","sanityEnv","process","env","SANITY_INTERNAL_ENV","apiHost","undefined","Error","requestTagPrefix","useCdn","useProjectHostname","getProjectCliClient","onError","err","isReqResError","statusCode","response","body","message","colorize","Object","prototype","hasOwnProperty","call"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAGEC,YAAY,EACZC,aAAaC,gBAAgB,EAC7BC,WAAW,QAGN,iBAAgB;AAEvB,SAAQC,eAAe,QAAO,6BAA4B;AAC1D,SAAQC,WAAW,QAAO,mBAAkB;AAE5C,MAAMC,WAA+C;IACnDC,SAAS;AACX;AAEA,MAAMC,yBAAyB;AA0B/B;;;;;;;CAOC,GACD,OAAO,eAAeC,mBAAmB,EACvCC,WAAW,EACXC,OAAOC,aAAa,EACpBC,eAAe,EACf,GAAGC,QACoB;IACvB,MAAMb,YAAYC,iBAAiBa,KAAK;IACxCd,UAAUe,GAAG,CAACC;IAEd,MAAMC,YAAYC,QAAQC,GAAG,CAACC,mBAAmB,IAAI;IAErD,MAAMC,UAAUhB,QAAQ,CAACY,UAAU;IAEnC,sGAAsG;IACtG,MAAMP,QAAQC,iBAAkBC,CAAAA,kBAAkBU,YAAY,MAAMlB,aAAY;IAEhF,kEAAkE;IAClE,IAAI,CAACM,SAASD,aAAa;QACzB,MAAM,IAAIc,MAAM;IAClB;IAEA,OAAOxB,aAAa;QAClB,GAAIsB,UAAU;YAACA;QAAO,IAAI,CAAC,CAAC;QAC5BrB;QACAwB,kBAAkBjB;QAClBG;QACAe,QAAQ;QACRC,oBAAoB;QACpB,GAAGb,MAAM;IACX;AACF;AA6BA;;;;;;;CAOC,GACD,OAAO,eAAec,oBAAoB,EACxClB,WAAW,EACXC,OAAOC,aAAa,EACpB,GAAGE,QACqB;IACxB,MAAMb,YAAYC,iBAAiBa,KAAK;IACxCd,UAAUe,GAAG,CAACC;IAEd,MAAMC,YAAYC,QAAQC,GAAG,CAACC,mBAAmB,IAAI;IAErD,MAAMC,UAAUhB,QAAQ,CAACY,UAAU;IAEnC,oFAAoF;IACpF,MAAMP,QAAQC,iBAAkB,MAAMP;IAEtC,kEAAkE;IAClE,IAAI,CAACM,SAASD,aAAa;QACzB,MAAM,IAAIc,MAAM;IAClB;IAEA,OAAOxB,aAAa;QAClB,GAAIsB,UAAU;YAACA;QAAO,IAAI,CAAC,CAAC;QAC5BrB;QACAwB,kBAAkBjB;QAClBG;QACAe,QAAQ;QACRC,oBAAoB;QACpB,GAAGb,MAAM;IACX;AACF;AAEA;;;;;;CAMC,GACD,SAASG;IACP,OAAO;QACLY,SAAS,CAACC;YACR,IAAI,CAACA,OAAO,CAACC,cAAcD,MAAM;gBAC/B,OAAOA;YACT;YAEA,MAAME,aAAa7B,YAAY2B,QAAQA,IAAIG,QAAQ,CAACC,IAAI,CAACF,UAAU;YACnE,IAAIA,eAAe,KAAK;gBACtBF,IAAIK,OAAO,GAAG,GAAGL,IAAIK,OAAO,CAAC,mCAAmC,EAAEpC,GAAGqC,QAAQ,CAAC,QAAQ,gBAAgB,6BAA6B,EAAEhC,gBAAgB,cAAc,CAAC,CAAC;YACvK;YAEA,OAAO0B;QACT;IACF;AACF;AAEA,SAASC,cAAcD,GAAU;IAC/B,OAAOO,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACV,KAAK;AACnD"}
1
+ {"version":3,"sources":["../../src/services/apiClient.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {\n type ClientConfig,\n type ClientError,\n createClient,\n requester as defaultRequester,\n isHttpError,\n type SanityClient,\n type ServerError,\n} from '@sanity/client'\n\nimport {generateHelpUrl} from '../util/generateHelpUrl.js'\nimport {getCliToken} from './getCliToken.js'\n\nconst apiHosts: Record<string, string | undefined> = {\n staging: 'https://api.sanity.work',\n}\n\nconst CLI_REQUEST_TAG_PREFIX = 'sanity.cli'\n\n/**\n * @public\n */\nexport interface GlobalCliClientOptions extends ClientConfig {\n /**\n * The API version to use for this client.\n */\n apiVersion: string\n\n /**\n * Whether to require a user to be authenticated to use this client.\n * Default: `false`.\n * Throws an error if `true` and user is not authenticated.\n */\n requireUser?: boolean\n\n /**\n * Whether to skip reading the stored CLI token. When `true`, the client will\n * have no token unless one is explicitly provided.\n * Default: `false`.\n */\n unauthenticated?: boolean\n}\n\n/**\n * Create a \"global\" (unscoped) Sanity API client.\n *\n * @public\n *\n * @param options - The options to use for the client.\n * @returns Promise that resolves to a configured Sanity API client.\n */\nexport async function getGlobalCliClient({\n requireUser,\n token: providedToken,\n unauthenticated,\n ...config\n}: GlobalCliClientOptions): Promise<SanityClient> {\n const requester = defaultRequester.clone()\n requester.use(authErrors())\n\n const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production'\n\n const apiHost = apiHosts[sanityEnv]\n\n // Use the provided token if set, otherwise fall back to the stored CLI token (unless unauthenticated)\n const token = providedToken || (unauthenticated ? undefined : await getCliToken())\n\n // If the token is not set and requireUser is true, throw an error\n if (!token && requireUser) {\n throw new Error('You must login first - run \"sanity login\"')\n }\n\n return createClient({\n ...(apiHost ? {apiHost} : {}),\n // Suppress browser token warning since we mock browser environment in workers\n ignoreBrowserTokenWarning: true,\n requester,\n requestTagPrefix: CLI_REQUEST_TAG_PREFIX,\n token,\n useCdn: false,\n useProjectHostname: false,\n ...config,\n })\n}\n\n/**\n * @public\n */\nexport interface ProjectCliClientOptions extends ClientConfig {\n /**\n * The API version to use for this client.\n */\n apiVersion: string\n\n /**\n * The project ID to use for this client.\n */\n projectId: string\n\n /**\n * The dataset to use for this client.\n */\n dataset?: string\n\n /**\n * Whether to require a user to be authenticated to use this client.\n * Default: `false`.\n * Throws an error if `true` and user is not authenticated.\n */\n requireUser?: boolean\n}\n\n/**\n * Create a \"project\" (scoped) Sanity API client.\n *\n * @public\n *\n * @param options - The options to use for the client.\n * @returns Promise that resolves to a configured Sanity API client.\n */\nexport async function getProjectCliClient({\n requireUser,\n token: providedToken,\n ...config\n}: ProjectCliClientOptions): Promise<SanityClient> {\n const requester = defaultRequester.clone()\n requester.use(authErrors())\n\n const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production'\n\n const apiHost = apiHosts[sanityEnv]\n\n // Use the provided token if it is set, otherwise get the token from the config file\n const token = providedToken || (await getCliToken())\n\n // If the token is not set and requireUser is true, throw an error\n if (!token && requireUser) {\n throw new Error('You must login first - run \"sanity login\"')\n }\n\n return createClient({\n ...(apiHost ? {apiHost} : {}),\n // Suppress browser token warning since we mock browser environment in workers\n ignoreBrowserTokenWarning: true,\n requester,\n requestTagPrefix: CLI_REQUEST_TAG_PREFIX,\n token,\n useCdn: false,\n useProjectHostname: true,\n ...config,\n })\n}\n\n/**\n * `get-it` middleware that checks for 401 authentication errors and extends the error with more\n * helpful guidance on what to do next.\n *\n * @returns get-it middleware with `onError` handler\n * @internal\n */\nfunction authErrors() {\n return {\n onError: (err: Error | null) => {\n if (!err || !isReqResError(err)) {\n return err\n }\n\n const statusCode = isHttpError(err) && err.response.body.statusCode\n if (statusCode === 401) {\n err.message = `${err.message}. You may need to login again with ${ux.colorize('cyan', 'sanity login')}.\\nFor more information, see ${generateHelpUrl('cli-errors')}.`\n }\n\n return err\n },\n }\n}\n\nfunction isReqResError(err: Error): err is ClientError | ServerError {\n return Object.prototype.hasOwnProperty.call(err, 'response')\n}\n"],"names":["ux","createClient","requester","defaultRequester","isHttpError","generateHelpUrl","getCliToken","apiHosts","staging","CLI_REQUEST_TAG_PREFIX","getGlobalCliClient","requireUser","token","providedToken","unauthenticated","config","clone","use","authErrors","sanityEnv","process","env","SANITY_INTERNAL_ENV","apiHost","undefined","Error","ignoreBrowserTokenWarning","requestTagPrefix","useCdn","useProjectHostname","getProjectCliClient","onError","err","isReqResError","statusCode","response","body","message","colorize","Object","prototype","hasOwnProperty","call"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAGEC,YAAY,EACZC,aAAaC,gBAAgB,EAC7BC,WAAW,QAGN,iBAAgB;AAEvB,SAAQC,eAAe,QAAO,6BAA4B;AAC1D,SAAQC,WAAW,QAAO,mBAAkB;AAE5C,MAAMC,WAA+C;IACnDC,SAAS;AACX;AAEA,MAAMC,yBAAyB;AA0B/B;;;;;;;CAOC,GACD,OAAO,eAAeC,mBAAmB,EACvCC,WAAW,EACXC,OAAOC,aAAa,EACpBC,eAAe,EACf,GAAGC,QACoB;IACvB,MAAMb,YAAYC,iBAAiBa,KAAK;IACxCd,UAAUe,GAAG,CAACC;IAEd,MAAMC,YAAYC,QAAQC,GAAG,CAACC,mBAAmB,IAAI;IAErD,MAAMC,UAAUhB,QAAQ,CAACY,UAAU;IAEnC,sGAAsG;IACtG,MAAMP,QAAQC,iBAAkBC,CAAAA,kBAAkBU,YAAY,MAAMlB,aAAY;IAEhF,kEAAkE;IAClE,IAAI,CAACM,SAASD,aAAa;QACzB,MAAM,IAAIc,MAAM;IAClB;IAEA,OAAOxB,aAAa;QAClB,GAAIsB,UAAU;YAACA;QAAO,IAAI,CAAC,CAAC;QAC5B,8EAA8E;QAC9EG,2BAA2B;QAC3BxB;QACAyB,kBAAkBlB;QAClBG;QACAgB,QAAQ;QACRC,oBAAoB;QACpB,GAAGd,MAAM;IACX;AACF;AA6BA;;;;;;;CAOC,GACD,OAAO,eAAee,oBAAoB,EACxCnB,WAAW,EACXC,OAAOC,aAAa,EACpB,GAAGE,QACqB;IACxB,MAAMb,YAAYC,iBAAiBa,KAAK;IACxCd,UAAUe,GAAG,CAACC;IAEd,MAAMC,YAAYC,QAAQC,GAAG,CAACC,mBAAmB,IAAI;IAErD,MAAMC,UAAUhB,QAAQ,CAACY,UAAU;IAEnC,oFAAoF;IACpF,MAAMP,QAAQC,iBAAkB,MAAMP;IAEtC,kEAAkE;IAClE,IAAI,CAACM,SAASD,aAAa;QACzB,MAAM,IAAIc,MAAM;IAClB;IAEA,OAAOxB,aAAa;QAClB,GAAIsB,UAAU;YAACA;QAAO,IAAI,CAAC,CAAC;QAC5B,8EAA8E;QAC9EG,2BAA2B;QAC3BxB;QACAyB,kBAAkBlB;QAClBG;QACAgB,QAAQ;QACRC,oBAAoB;QACpB,GAAGd,MAAM;IACX;AACF;AAEA;;;;;;CAMC,GACD,SAASG;IACP,OAAO;QACLa,SAAS,CAACC;YACR,IAAI,CAACA,OAAO,CAACC,cAAcD,MAAM;gBAC/B,OAAOA;YACT;YAEA,MAAME,aAAa9B,YAAY4B,QAAQA,IAAIG,QAAQ,CAACC,IAAI,CAACF,UAAU;YACnE,IAAIA,eAAe,KAAK;gBACtBF,IAAIK,OAAO,GAAG,GAAGL,IAAIK,OAAO,CAAC,mCAAmC,EAAErC,GAAGsC,QAAQ,CAAC,QAAQ,gBAAgB,6BAA6B,EAAEjC,gBAAgB,cAAc,CAAC,CAAC;YACvK;YAEA,OAAO2B;QACT;IACF;AACF;AAEA,SAASC,cAAcD,GAAU;IAC/B,OAAOO,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACV,KAAK;AACnD"}
@@ -2,26 +2,39 @@ import { ux } from '@oclif/core';
2
2
  import { noopLogger } from '@sanity/telemetry';
3
3
  /**
4
4
  * @public
5
- * Symbol used to store the CLI telemetry store on globalThis.
6
- * Use `getCliTelemetry()` to access the store instead of accessing this directly.
5
+ * Symbol used to store CLI telemetry state on globalThis.
6
+ * Use the accessor functions instead of accessing this directly.
7
7
  */ export const CLI_TELEMETRY_SYMBOL = Symbol.for('sanity.cli.telemetry');
8
+ function getState() {
9
+ return globalThis[CLI_TELEMETRY_SYMBOL];
10
+ }
8
11
  /**
9
12
  * @public
10
13
  */ export function getCliTelemetry() {
11
- const global = globalThis;
14
+ const state = getState();
12
15
  // This should never happen, but if it does, we return a noop logger to avoid errors.
13
- if (!global[CLI_TELEMETRY_SYMBOL]) {
16
+ if (!state) {
14
17
  ux.warn('CLI telemetry not initialized, returning noop logger');
15
18
  return noopLogger;
16
19
  }
17
- return global[CLI_TELEMETRY_SYMBOL];
20
+ return state.logger;
18
21
  }
19
22
  /**
20
- * Sets the global CLI telemetry store.
23
+ * Sets the global CLI telemetry state.
21
24
  * @internal
22
- */ export function setCliTelemetry(telemetry) {
23
- const global = globalThis;
24
- global[CLI_TELEMETRY_SYMBOL] = telemetry;
25
+ */ export function setCliTelemetry(telemetry, options) {
26
+ ;
27
+ globalThis[CLI_TELEMETRY_SYMBOL] = {
28
+ logger: telemetry,
29
+ reportTraceError: options?.reportTraceError
30
+ };
31
+ }
32
+ /**
33
+ * Reports an error to the CLI command trace. Called from SanityCommand.catch()
34
+ * for real command errors (not user aborts).
35
+ * @internal
36
+ */ export function reportCliTraceError(error) {
37
+ getState()?.reportTraceError?.(error);
25
38
  }
26
39
  /**
27
40
  * Clears the global CLI telemetry store.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/getCliTelemetry.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {noopLogger} from '@sanity/telemetry'\n\nimport {type CLITelemetryStore} from '../telemetry/types.js'\n\n/**\n * @public\n * Symbol used to store the CLI telemetry store on globalThis.\n * Use `getCliTelemetry()` to access the store instead of accessing this directly.\n */\nexport const CLI_TELEMETRY_SYMBOL = Symbol.for('sanity.cli.telemetry')\n\ntype GlobalWithTelemetry = typeof globalThis & {\n [CLI_TELEMETRY_SYMBOL]?: CLITelemetryStore\n}\n\n/**\n * @public\n */\nexport function getCliTelemetry(): CLITelemetryStore {\n const global = globalThis as GlobalWithTelemetry\n // This should never happen, but if it does, we return a noop logger to avoid errors.\n if (!global[CLI_TELEMETRY_SYMBOL]) {\n ux.warn('CLI telemetry not initialized, returning noop logger')\n return noopLogger\n }\n\n return global[CLI_TELEMETRY_SYMBOL]\n}\n\n/**\n * Sets the global CLI telemetry store.\n * @internal\n */\nexport function setCliTelemetry(telemetry: CLITelemetryStore): void {\n const global = globalThis as GlobalWithTelemetry\n global[CLI_TELEMETRY_SYMBOL] = telemetry\n}\n\n/**\n * Clears the global CLI telemetry store.\n * @internal\n */\nexport function clearCliTelemetry(): void {\n const global = globalThis as GlobalWithTelemetry\n delete global[CLI_TELEMETRY_SYMBOL]\n}\n"],"names":["ux","noopLogger","CLI_TELEMETRY_SYMBOL","Symbol","for","getCliTelemetry","global","globalThis","warn","setCliTelemetry","telemetry","clearCliTelemetry"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAAQC,UAAU,QAAO,oBAAmB;AAI5C;;;;CAIC,GACD,OAAO,MAAMC,uBAAuBC,OAAOC,GAAG,CAAC,wBAAuB;AAMtE;;CAEC,GACD,OAAO,SAASC;IACd,MAAMC,SAASC;IACf,qFAAqF;IACrF,IAAI,CAACD,MAAM,CAACJ,qBAAqB,EAAE;QACjCF,GAAGQ,IAAI,CAAC;QACR,OAAOP;IACT;IAEA,OAAOK,MAAM,CAACJ,qBAAqB;AACrC;AAEA;;;CAGC,GACD,OAAO,SAASO,gBAAgBC,SAA4B;IAC1D,MAAMJ,SAASC;IACfD,MAAM,CAACJ,qBAAqB,GAAGQ;AACjC;AAEA;;;CAGC,GACD,OAAO,SAASC;IACd,MAAML,SAASC;IACf,OAAOD,MAAM,CAACJ,qBAAqB;AACrC"}
1
+ {"version":3,"sources":["../../src/util/getCliTelemetry.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {noopLogger} from '@sanity/telemetry'\n\nimport {type CLITelemetryStore} from '../telemetry/types.js'\n\n/**\n * @public\n * Symbol used to store CLI telemetry state on globalThis.\n * Use the accessor functions instead of accessing this directly.\n */\nexport const CLI_TELEMETRY_SYMBOL = Symbol.for('sanity.cli.telemetry')\n\ntype TraceErrorReporter = (error: Error) => void\n\ninterface CliTelemetryState {\n logger: CLITelemetryStore\n\n reportTraceError?: TraceErrorReporter\n}\n\ntype GlobalWithTelemetry = typeof globalThis & {\n [CLI_TELEMETRY_SYMBOL]?: CliTelemetryState\n}\n\nfunction getState(): CliTelemetryState | undefined {\n return (globalThis as GlobalWithTelemetry)[CLI_TELEMETRY_SYMBOL]\n}\n\n/**\n * @public\n */\nexport function getCliTelemetry(): CLITelemetryStore {\n const state = getState()\n // This should never happen, but if it does, we return a noop logger to avoid errors.\n if (!state) {\n ux.warn('CLI telemetry not initialized, returning noop logger')\n return noopLogger\n }\n\n return state.logger\n}\n\n/**\n * Sets the global CLI telemetry state.\n * @internal\n */\nexport function setCliTelemetry(\n telemetry: CLITelemetryStore,\n options?: {reportTraceError?: TraceErrorReporter},\n): void {\n ;(globalThis as GlobalWithTelemetry)[CLI_TELEMETRY_SYMBOL] = {\n logger: telemetry,\n reportTraceError: options?.reportTraceError,\n }\n}\n\n/**\n * Reports an error to the CLI command trace. Called from SanityCommand.catch()\n * for real command errors (not user aborts).\n * @internal\n */\nexport function reportCliTraceError(error: Error): void {\n getState()?.reportTraceError?.(error)\n}\n\n/**\n * Clears the global CLI telemetry store.\n * @internal\n */\nexport function clearCliTelemetry(): void {\n const global = globalThis as GlobalWithTelemetry\n delete global[CLI_TELEMETRY_SYMBOL]\n}\n"],"names":["ux","noopLogger","CLI_TELEMETRY_SYMBOL","Symbol","for","getState","globalThis","getCliTelemetry","state","warn","logger","setCliTelemetry","telemetry","options","reportTraceError","reportCliTraceError","error","clearCliTelemetry","global"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAAQC,UAAU,QAAO,oBAAmB;AAI5C;;;;CAIC,GACD,OAAO,MAAMC,uBAAuBC,OAAOC,GAAG,CAAC,wBAAuB;AActE,SAASC;IACP,OAAO,AAACC,UAAkC,CAACJ,qBAAqB;AAClE;AAEA;;CAEC,GACD,OAAO,SAASK;IACd,MAAMC,QAAQH;IACd,qFAAqF;IACrF,IAAI,CAACG,OAAO;QACVR,GAAGS,IAAI,CAAC;QACR,OAAOR;IACT;IAEA,OAAOO,MAAME,MAAM;AACrB;AAEA;;;CAGC,GACD,OAAO,SAASC,gBACdC,SAA4B,EAC5BC,OAAiD;;IAE/CP,UAAkC,CAACJ,qBAAqB,GAAG;QAC3DQ,QAAQE;QACRE,kBAAkBD,SAASC;IAC7B;AACF;AAEA;;;;CAIC,GACD,OAAO,SAASC,oBAAoBC,KAAY;IAC9CX,YAAYS,mBAAmBE;AACjC;AAEA;;;CAGC,GACD,OAAO,SAASC;IACd,MAAMC,SAASZ;IACf,OAAOY,MAAM,CAAChB,qBAAqB;AACrC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Runtime-detectable package managers (excludes 'manual' which is a UI-only choice).
3
+ */ /**
4
+ * Convenience wrapper that reads `process.env.npm_config_user_agent` and returns
5
+ * the detected package manager.
6
+ */ export function getRunningPackageManager() {
7
+ return detectPackageManagerFromAgent();
8
+ }
9
+ /**
10
+ * Extract the yarn major version from a `npm_config_user_agent` string.
11
+ *
12
+ * @param ua - User-agent string. Defaults to `process.env.npm_config_user_agent`.
13
+ * @returns The major version number, or `undefined` if yarn isn't detected.
14
+ */ export function getYarnMajorVersion(ua = process.env.npm_config_user_agent ?? '') {
15
+ const match = ua.match(/yarn\/(\d+)/);
16
+ return match ? Number.parseInt(match[1], 10) : undefined;
17
+ }
18
+ /**
19
+ * Return the CLI invocation command for the detected (or provided) package manager.
20
+ *
21
+ * @param options - Optional `bin` (defaults to `'sanity'`) and `userAgent` override.
22
+ * @returns A string like `"npx sanity"`, `"pnpm exec sanity"`, etc.
23
+ */ export function getBinCommand(options) {
24
+ const bin = options?.bin ?? 'sanity';
25
+ const ua = options?.userAgent ?? process.env.npm_config_user_agent ?? '';
26
+ const pm = detectPackageManagerFromAgent(ua);
27
+ if (pm === 'npm') return `npx ${bin}`;
28
+ if (pm === 'pnpm') return `pnpm exec ${bin}`;
29
+ if (pm === 'bun') return `bunx ${bin}`;
30
+ if (pm === 'yarn') {
31
+ const major = getYarnMajorVersion(ua);
32
+ if (major !== undefined && major >= 2) return `yarn run ${bin}`;
33
+ return `yarn ${bin}`;
34
+ }
35
+ return bin;
36
+ }
37
+ /**
38
+ * Parse the `npm_config_user_agent` string and return the detected package manager.
39
+ *
40
+ * The check order matters: yarn and pnpm set a user-agent that *also* contains
41
+ * `npm/?`, so we must test for them before falling back to the anchored npm regex.
42
+ *
43
+ * @param ua - User-agent string. Defaults to `process.env.npm_config_user_agent`.
44
+ * @returns The detected package manager, or `undefined` when unrecognisable.
45
+ */ export function detectPackageManagerFromAgent(ua = process.env.npm_config_user_agent ?? '') {
46
+ if (ua.includes('pnpm')) return 'pnpm';
47
+ if (ua.includes('yarn')) return 'yarn';
48
+ if (ua.includes('bun')) return 'bun';
49
+ // Anchored regex: yarn/pnpm/bun agents also contain "npm/?" so we require
50
+ // `npm/` followed by a digit to avoid false positives.
51
+ if (/^npm\/\d/.test(ua)) return 'npm';
52
+ return undefined;
53
+ }
54
+
55
+ //# sourceMappingURL=packageManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/packageManager.ts"],"sourcesContent":["/**\n * Runtime-detectable package managers (excludes 'manual' which is a UI-only choice).\n */\nexport type DetectedPackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn'\n\n/**\n * Convenience wrapper that reads `process.env.npm_config_user_agent` and returns\n * the detected package manager.\n */\nexport function getRunningPackageManager(): DetectedPackageManager | undefined {\n return detectPackageManagerFromAgent()\n}\n\n/**\n * Extract the yarn major version from a `npm_config_user_agent` string.\n *\n * @param ua - User-agent string. Defaults to `process.env.npm_config_user_agent`.\n * @returns The major version number, or `undefined` if yarn isn't detected.\n */\nexport function getYarnMajorVersion(\n ua: string = process.env.npm_config_user_agent ?? '',\n): number | undefined {\n const match = ua.match(/yarn\\/(\\d+)/)\n return match ? Number.parseInt(match[1], 10) : undefined\n}\n\n/**\n * Return the CLI invocation command for the detected (or provided) package manager.\n *\n * @param options - Optional `bin` (defaults to `'sanity'`) and `userAgent` override.\n * @returns A string like `\"npx sanity\"`, `\"pnpm exec sanity\"`, etc.\n */\nexport function getBinCommand(options?: {bin?: string; userAgent?: string}): string {\n const bin = options?.bin ?? 'sanity'\n const ua = options?.userAgent ?? process.env.npm_config_user_agent ?? ''\n const pm = detectPackageManagerFromAgent(ua)\n\n if (pm === 'npm') return `npx ${bin}`\n if (pm === 'pnpm') return `pnpm exec ${bin}`\n if (pm === 'bun') return `bunx ${bin}`\n if (pm === 'yarn') {\n const major = getYarnMajorVersion(ua)\n if (major !== undefined && major >= 2) return `yarn run ${bin}`\n return `yarn ${bin}`\n }\n return bin\n}\n\n/**\n * Parse the `npm_config_user_agent` string and return the detected package manager.\n *\n * The check order matters: yarn and pnpm set a user-agent that *also* contains\n * `npm/?`, so we must test for them before falling back to the anchored npm regex.\n *\n * @param ua - User-agent string. Defaults to `process.env.npm_config_user_agent`.\n * @returns The detected package manager, or `undefined` when unrecognisable.\n */\nexport function detectPackageManagerFromAgent(\n ua: string = process.env.npm_config_user_agent ?? '',\n): DetectedPackageManager | undefined {\n if (ua.includes('pnpm')) return 'pnpm'\n if (ua.includes('yarn')) return 'yarn'\n if (ua.includes('bun')) return 'bun'\n // Anchored regex: yarn/pnpm/bun agents also contain \"npm/?\" so we require\n // `npm/` followed by a digit to avoid false positives.\n if (/^npm\\/\\d/.test(ua)) return 'npm'\n return undefined\n}\n"],"names":["getRunningPackageManager","detectPackageManagerFromAgent","getYarnMajorVersion","ua","process","env","npm_config_user_agent","match","Number","parseInt","undefined","getBinCommand","options","bin","userAgent","pm","major","includes","test"],"mappings":"AAAA;;CAEC,GAGD;;;CAGC,GACD,OAAO,SAASA;IACd,OAAOC;AACT;AAEA;;;;;CAKC,GACD,OAAO,SAASC,oBACdC,KAAaC,QAAQC,GAAG,CAACC,qBAAqB,IAAI,EAAE;IAEpD,MAAMC,QAAQJ,GAAGI,KAAK,CAAC;IACvB,OAAOA,QAAQC,OAAOC,QAAQ,CAACF,KAAK,CAAC,EAAE,EAAE,MAAMG;AACjD;AAEA;;;;;CAKC,GACD,OAAO,SAASC,cAAcC,OAA4C;IACxE,MAAMC,MAAMD,SAASC,OAAO;IAC5B,MAAMV,KAAKS,SAASE,aAAaV,QAAQC,GAAG,CAACC,qBAAqB,IAAI;IACtE,MAAMS,KAAKd,8BAA8BE;IAEzC,IAAIY,OAAO,OAAO,OAAO,CAAC,IAAI,EAAEF,KAAK;IACrC,IAAIE,OAAO,QAAQ,OAAO,CAAC,UAAU,EAAEF,KAAK;IAC5C,IAAIE,OAAO,OAAO,OAAO,CAAC,KAAK,EAAEF,KAAK;IACtC,IAAIE,OAAO,QAAQ;QACjB,MAAMC,QAAQd,oBAAoBC;QAClC,IAAIa,UAAUN,aAAaM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAEH,KAAK;QAC/D,OAAO,CAAC,KAAK,EAAEA,KAAK;IACtB;IACA,OAAOA;AACT;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASZ,8BACdE,KAAaC,QAAQC,GAAG,CAACC,qBAAqB,IAAI,EAAE;IAEpD,IAAIH,GAAGc,QAAQ,CAAC,SAAS,OAAO;IAChC,IAAId,GAAGc,QAAQ,CAAC,SAAS,OAAO;IAChC,IAAId,GAAGc,QAAQ,CAAC,QAAQ,OAAO;IAC/B,0EAA0E;IAC1E,uDAAuD;IACvD,IAAI,WAAWC,IAAI,CAACf,KAAK,OAAO;IAChC,OAAOO;AACT"}
package/package.json CHANGED
@@ -1,27 +1,32 @@
1
1
  {
2
2
  "name": "@sanity/cli-core",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Sanity CLI core package",
5
5
  "keywords": [
6
- "sanity",
6
+ "cli",
7
7
  "cms",
8
+ "content",
8
9
  "headless",
9
10
  "realtime",
10
- "content",
11
- "cli",
11
+ "sanity",
12
12
  "tool"
13
13
  ],
14
14
  "homepage": "https://github.com/sanity-io/cli",
15
15
  "bugs": "https://github.com/sanity-io/cli/issues",
16
+ "license": "MIT",
17
+ "author": "Sanity.io <hello@sanity.io>",
16
18
  "repository": {
17
19
  "type": "git",
18
20
  "url": "git+https://github.com/sanity-io/cli.git",
19
21
  "directory": "packages/@sanity/cli-core"
20
22
  },
21
- "license": "MIT",
22
- "author": "Sanity.io <hello@sanity.io>",
23
- "sideEffects": false,
23
+ "files": [
24
+ "./dist"
25
+ ],
24
26
  "type": "module",
27
+ "sideEffects": false,
28
+ "main": "./dist/index.js",
29
+ "types": "dist/index.d.ts",
25
30
  "exports": {
26
31
  ".": {
27
32
  "source": "./src/index.ts",
@@ -35,13 +40,15 @@
35
40
  "source": "./src/_exports/request.ts",
36
41
  "default": "./dist/_exports/request.js"
37
42
  },
43
+ "./package-manager": {
44
+ "source": "./src/_exports/package-manager.ts",
45
+ "default": "./dist/_exports/package-manager.js"
46
+ },
38
47
  "./package.json": "./package.json"
39
48
  },
40
- "main": "./dist/index.js",
41
- "types": "dist/index.d.ts",
42
- "files": [
43
- "./dist"
44
- ],
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
45
52
  "dependencies": {
46
53
  "@inquirer/prompts": "^8.3.0",
47
54
  "@oclif/core": "^4.8.3",
@@ -67,7 +74,6 @@
67
74
  },
68
75
  "devDependencies": {
69
76
  "@eslint/compat": "^2.0.3",
70
- "@sanity/codegen": "^5.10.1",
71
77
  "@sanity/pkg-utils": "^10.4.8",
72
78
  "@sanity/telemetry": "^0.8.1",
73
79
  "@swc/cli": "^0.8.0",
@@ -77,12 +83,12 @@
77
83
  "@types/node": "^20.19.37",
78
84
  "eslint": "^9.39.4",
79
85
  "publint": "^0.3.18",
80
- "sanity": "^5.13.0",
86
+ "sanity": "^5.14.1",
81
87
  "typescript": "^5.9.3",
82
88
  "vitest": "^4.0.18",
83
89
  "@repo/package.config": "0.0.1",
84
- "@repo/tsconfig": "3.70.0",
85
- "@sanity/eslint-config-cli": "1.0.0"
90
+ "@sanity/eslint-config-cli": "1.0.0",
91
+ "@repo/tsconfig": "3.70.0"
86
92
  },
87
93
  "peerDependencies": {
88
94
  "@sanity/telemetry": ">=0.8.1 <0.9.0"
@@ -90,9 +96,6 @@
90
96
  "engines": {
91
97
  "node": ">=20.19.1 <22 || >=22.12"
92
98
  },
93
- "publishConfig": {
94
- "access": "public"
95
- },
96
99
  "scripts": {
97
100
  "build": "swc --delete-dir-on-start --strip-leading-paths --out-dir dist/ src --ignore '**/*.test.ts'",
98
101
  "build:types": "pkg-utils build --emitDeclarationOnly",