@sanity/cli-core 0.1.0-alpha.9 → 1.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.
Files changed (108) hide show
  1. package/dist/SanityCommand.js +81 -5
  2. package/dist/SanityCommand.js.map +1 -1
  3. package/dist/_exports/package-manager.d.ts +33 -0
  4. package/dist/_exports/package-manager.js +3 -0
  5. package/dist/_exports/package-manager.js.map +1 -0
  6. package/dist/_exports/request.d.ts +79 -0
  7. package/dist/_exports/request.js +7 -0
  8. package/dist/_exports/request.js.map +1 -0
  9. package/dist/_exports/ux.d.ts +61 -26
  10. package/dist/_exports/ux.js +1 -0
  11. package/dist/_exports/ux.js.map +1 -1
  12. package/dist/config/cli/getCliConfig.js +33 -33
  13. package/dist/config/cli/getCliConfig.js.map +1 -1
  14. package/dist/config/cli/getCliConfigSync.js +1 -1
  15. package/dist/config/cli/getCliConfigSync.js.map +1 -1
  16. package/dist/config/cli/schemas.js +7 -0
  17. package/dist/config/cli/schemas.js.map +1 -1
  18. package/dist/config/cli/types/cliConfig.js.map +1 -1
  19. package/dist/config/findProjectRoot.js +6 -2
  20. package/dist/config/findProjectRoot.js.map +1 -1
  21. package/dist/config/findProjectRootSync.js +7 -3
  22. package/dist/config/findProjectRootSync.js.map +1 -1
  23. package/dist/config/studio/getStudioWorkspaces.js +14 -1
  24. package/dist/config/studio/getStudioWorkspaces.js.map +1 -1
  25. package/dist/config/studio/readStudioConfig.worker.js +6 -5
  26. package/dist/config/studio/readStudioConfig.worker.js.map +1 -1
  27. package/dist/errors/NonInteractiveError.js +18 -0
  28. package/dist/errors/NonInteractiveError.js.map +1 -0
  29. package/dist/{util → errors}/NotFoundError.js +1 -1
  30. package/dist/errors/NotFoundError.js.map +1 -0
  31. package/dist/errors/ProjectRootNotFoundError.js +35 -0
  32. package/dist/errors/ProjectRootNotFoundError.js.map +1 -0
  33. package/dist/index.d.ts +939 -5689
  34. package/dist/index.js +8 -14
  35. package/dist/index.js.map +1 -1
  36. package/dist/loaders/studio/studioWorkerLoader.worker.js +102 -23
  37. package/dist/loaders/studio/studioWorkerLoader.worker.js.map +1 -1
  38. package/dist/loaders/studio/studioWorkerTask.js +18 -27
  39. package/dist/loaders/studio/studioWorkerTask.js.map +1 -1
  40. package/dist/loaders/tsx/tsxWorkerLoader.worker.js +3 -4
  41. package/dist/loaders/tsx/tsxWorkerLoader.worker.js.map +1 -1
  42. package/dist/loaders/tsx/tsxWorkerTask.js +4 -34
  43. package/dist/loaders/tsx/tsxWorkerTask.js.map +1 -1
  44. package/dist/request/createRequester.js +83 -0
  45. package/dist/request/createRequester.js.map +1 -0
  46. package/dist/services/apiClient.js +7 -3
  47. package/dist/services/apiClient.js.map +1 -1
  48. package/dist/services/cliUserConfig.js +5 -5
  49. package/dist/services/cliUserConfig.js.map +1 -1
  50. package/dist/services/getCliToken.js +2 -2
  51. package/dist/services/getCliToken.js.map +1 -1
  52. package/dist/util/doImport.js +2 -1
  53. package/dist/util/doImport.js.map +1 -1
  54. package/dist/util/environment/mockBrowserEnvironment.js +1 -0
  55. package/dist/util/environment/mockBrowserEnvironment.js.map +1 -1
  56. package/dist/util/getCliTelemetry.js +6 -8
  57. package/dist/util/getCliTelemetry.js.map +1 -1
  58. package/dist/util/getSanityUrl.js +4 -3
  59. package/dist/util/getSanityUrl.js.map +1 -1
  60. package/dist/util/importModule.js +32 -0
  61. package/dist/util/importModule.js.map +1 -0
  62. package/dist/util/isInteractive.js +1 -1
  63. package/dist/util/isInteractive.js.map +1 -1
  64. package/dist/util/packageManager.js +55 -0
  65. package/dist/util/packageManager.js.map +1 -0
  66. package/dist/util/promisifyWorker.js +72 -0
  67. package/dist/util/promisifyWorker.js.map +1 -0
  68. package/dist/util/readPackageJson.js +74 -0
  69. package/dist/util/readPackageJson.js.map +1 -0
  70. package/dist/ux/prompts.js +49 -1
  71. package/dist/ux/prompts.js.map +1 -1
  72. package/package.json +44 -40
  73. package/dist/_exports/tree.d.ts +0 -47
  74. package/dist/_exports/tree.js +0 -3
  75. package/dist/_exports/tree.js.map +0 -1
  76. package/dist/config/cli/getCliConfig.worker.js +0 -15
  77. package/dist/config/cli/getCliConfig.worker.js.map +0 -1
  78. package/dist/telemetry/cleanupOldTelemetryFiles.js +0 -30
  79. package/dist/telemetry/cleanupOldTelemetryFiles.js.map +0 -1
  80. package/dist/telemetry/createTelemetryStore.js +0 -95
  81. package/dist/telemetry/createTelemetryStore.js.map +0 -1
  82. package/dist/telemetry/createTraceId.js +0 -10
  83. package/dist/telemetry/createTraceId.js.map +0 -1
  84. package/dist/telemetry/findTelemetryFiles.js +0 -36
  85. package/dist/telemetry/findTelemetryFiles.js.map +0 -1
  86. package/dist/telemetry/flushTelemetryFiles.js +0 -107
  87. package/dist/telemetry/flushTelemetryFiles.js.map +0 -1
  88. package/dist/telemetry/generateTelemetryFilePath.js +0 -30
  89. package/dist/telemetry/generateTelemetryFilePath.js.map +0 -1
  90. package/dist/telemetry/logger.js +0 -54
  91. package/dist/telemetry/logger.js.map +0 -1
  92. package/dist/telemetry/telemetryStoreDebug.js +0 -7
  93. package/dist/telemetry/telemetryStoreDebug.js.map +0 -1
  94. package/dist/telemetry/trace.js +0 -150
  95. package/dist/telemetry/trace.js.map +0 -1
  96. package/dist/util/NotFoundError.js.map +0 -1
  97. package/dist/util/createExpiringConfig.js +0 -60
  98. package/dist/util/createExpiringConfig.js.map +0 -1
  99. package/dist/util/parseStringFlag.js +0 -19
  100. package/dist/util/parseStringFlag.js.map +0 -1
  101. package/dist/util/tree.js +0 -108
  102. package/dist/util/tree.js.map +0 -1
  103. package/dist/util/waitForAsync.js +0 -5
  104. package/dist/util/waitForAsync.js.map +0 -1
  105. package/dist/ux/formatObject.js +0 -9
  106. package/dist/ux/formatObject.js.map +0 -1
  107. package/dist/ux/printKeyValue.js +0 -16
  108. package/dist/ux/printKeyValue.js.map +0 -1
@@ -13,13 +13,13 @@ const CLI_REQUEST_TAG_PREFIX = 'sanity.cli';
13
13
  *
14
14
  * @param options - The options to use for the client.
15
15
  * @returns Promise that resolves to a configured Sanity API client.
16
- */ export async function getGlobalCliClient({ requireUser, token: providedToken, ...config }) {
16
+ */ export async function getGlobalCliClient({ requireUser, token: providedToken, unauthenticated, ...config }) {
17
17
  const requester = defaultRequester.clone();
18
18
  requester.use(authErrors());
19
19
  const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production';
20
20
  const apiHost = apiHosts[sanityEnv];
21
- // Use the provided token if it is set, otherwise get the token from the config file
22
- const token = providedToken || await getCliToken();
21
+ // Use the provided token if set, otherwise fall back to the stored CLI token (unless unauthenticated)
22
+ const token = providedToken || (unauthenticated ? undefined : await getCliToken());
23
23
  // If the token is not set and requireUser is true, throw an error
24
24
  if (!token && requireUser) {
25
25
  throw new Error('You must login first - run "sanity login"');
@@ -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/**\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 ...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 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: 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","config","clone","use","authErrors","sanityEnv","process","env","SANITY_INTERNAL_ENV","apiHost","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;AAmB/B;;;;;;;CAOC,GACD,OAAO,eAAeC,mBAAmB,EACvCC,WAAW,EACXC,OAAOC,aAAa,EACpB,GAAGC,QACoB;IACvB,MAAMZ,YAAYC,iBAAiBY,KAAK;IACxCb,UAAUc,GAAG,CAACC;IAEd,MAAMC,YAAYC,QAAQC,GAAG,CAACC,mBAAmB,IAAI;IAErD,MAAMC,UAAUf,QAAQ,CAACW,UAAU;IAEnC,oFAAoF;IACpF,MAAMN,QAAQC,iBAAkB,MAAMP;IAEtC,kEAAkE;IAClE,IAAI,CAACM,SAASD,aAAa;QACzB,MAAM,IAAIY,MAAM;IAClB;IAEA,OAAOtB,aAAa;QAClB,GAAIqB,UAAU;YAACA;QAAO,IAAI,CAAC,CAAC;QAC5BpB;QACAsB,kBAAkBf;QAClBG;QACAa,QAAQ;QACRC,oBAAoB;QACpB,GAAGZ,MAAM;IACX;AACF;AA6BA;;;;;;;CAOC,GACD,OAAO,eAAea,oBAAoB,EACxChB,WAAW,EACXC,OAAOC,aAAa,EACpB,GAAGC,QACqB;IACxB,MAAMZ,YAAYC,iBAAiBY,KAAK;IACxCb,UAAUc,GAAG,CAACC;IAEd,MAAMC,YAAYC,QAAQC,GAAG,CAACC,mBAAmB,IAAI;IAErD,MAAMC,UAAUf,QAAQ,CAACW,UAAU;IAEnC,oFAAoF;IACpF,MAAMN,QAAQC,iBAAkB,MAAMP;IAEtC,kEAAkE;IAClE,IAAI,CAACM,SAASD,aAAa;QACzB,MAAM,IAAIY,MAAM;IAClB;IAEA,OAAOtB,aAAa;QAClB,GAAIqB,UAAU;YAACA;QAAO,IAAI,CAAC,CAAC;QAC5BpB;QACAsB,kBAAkBf;QAClBG;QACAa,QAAQ;QACRC,oBAAoB;QACpB,GAAGZ,MAAM;IACX;AACF;AAEA;;;;;;CAMC,GACD,SAASG;IACP,OAAO;QACLW,SAAS,CAACC;YACR,IAAI,CAACA,OAAO,CAACC,cAAcD,MAAM;gBAC/B,OAAOA;YACT;YAEA,MAAME,aAAa3B,YAAYyB,QAAQA,IAAIG,QAAQ,CAACC,IAAI,CAACF,UAAU;YACnE,IAAIA,eAAe,KAAK;gBACtBF,IAAIK,OAAO,GAAG,GAAGL,IAAIK,OAAO,CAAC,mCAAmC,EAAElC,GAAGmC,QAAQ,CAAC,QAAQ,gBAAgB,6BAA6B,EAAE9B,gBAAgB,cAAc,CAAC,CAAC;YACvK;YAEA,OAAOwB;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"}
@@ -27,7 +27,7 @@ const cliUserConfigSchema = {
27
27
  * @param prop - The property to set the value for
28
28
  * @param value - The value to set
29
29
  * @internal
30
- */ export async function setConfig(prop, value) {
30
+ */ export async function setCliUserConfig(prop, value) {
31
31
  const config = await readConfig();
32
32
  const valueSchema = cliUserConfigSchema[prop];
33
33
  if (!valueSchema) {
@@ -55,16 +55,16 @@ const cliUserConfigSchema = {
55
55
  * @param prop - The property to get the value for
56
56
  * @returns The value of the given property
57
57
  * @internal
58
- */ export async function getConfig(prop) {
58
+ */ export async function getCliUserConfig(prop) {
59
59
  const config = await readConfig();
60
60
  const valueSchema = cliUserConfigSchema[prop];
61
61
  if (!valueSchema) {
62
62
  throw new Error(`No schema defined for config property "${prop}"`);
63
63
  }
64
- const { error, success } = valueSchema.safeParse(config[prop]);
64
+ const { success } = valueSchema.safeParse(config[prop]);
65
65
  if (!success) {
66
- const message = error.issues.map(({ message, path })=>`[${path.join('.')}] ${message}`).join('\n');
67
- throw new Error(`Invalid value for config property "${prop}": ${message}`);
66
+ debug('Ignoring invalid stored value for "%s", returning undefined', prop);
67
+ return undefined;
68
68
  }
69
69
  return config[prop];
70
70
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/cliUserConfig.ts"],"sourcesContent":["import {mkdir} from 'node:fs/promises'\nimport {homedir} from 'node:os'\nimport {dirname, join as joinPath} from 'node:path'\n\nimport {z} from 'zod'\n\nimport {debug} from '../debug.js'\nimport {readJsonFile} from '../util/readJsonFile.js'\nimport {writeJsonFile} from '../util/writeJsonFile.js'\n\nconst cliUserConfigSchema = {\n authToken: z.string().optional(),\n telemetryConsent: z\n .object({\n updatedAt: z.number().optional(),\n value: z\n .object({\n status: z.enum(['undetermined', 'unset', 'granted', 'denied']),\n type: z.string(),\n })\n .passthrough(),\n })\n .optional(),\n}\n\n/**\n * The CLI user configuration schema.\n *\n * @internal\n */\ntype CliUserConfig = z.infer<z.ZodObject<typeof cliUserConfigSchema>>\n\n/**\n * Set the config value for the given property.\n * Validates that the passed value adheres to the defined CLI config schema.\n *\n * @param prop - The property to set the value for\n * @param value - The value to set\n * @internal\n */\nexport async function setConfig<P extends keyof CliUserConfig>(prop: P, value: CliUserConfig[P]) {\n const config = await readConfig()\n const valueSchema = cliUserConfigSchema[prop]\n if (!valueSchema) {\n throw new Error(`No schema defined for config property \"${prop}\"`)\n }\n\n const {error, success} = valueSchema.safeParse(value)\n if (!success) {\n const message = error.issues\n .map(({message, path}) => `[${path.join('.')}] ${message}`)\n .join('\\n')\n\n throw new Error(`Invalid value for config property \"${prop}\": ${message}`)\n }\n\n const configPath = getCliUserConfigPath()\n await mkdir(dirname(configPath), {recursive: true})\n await writeJsonFile(configPath, {...config, [prop]: value}, {pretty: true})\n}\n\n/**\n * Get the config value for the given property\n *\n * @param prop - The property to get the value for\n * @returns The value of the given property\n * @internal\n */\nexport async function getConfig<P extends keyof CliUserConfig>(prop: P): Promise<CliUserConfig[P]> {\n const config = await readConfig()\n const valueSchema = cliUserConfigSchema[prop]\n if (!valueSchema) {\n throw new Error(`No schema defined for config property \"${prop}\"`)\n }\n\n const {error, success} = valueSchema.safeParse(config[prop])\n if (!success) {\n const message = error.issues\n .map(({message, path}) => `[${path.join('.')}] ${message}`)\n .join('\\n')\n\n throw new Error(`Invalid value for config property \"${prop}\": ${message}`)\n }\n\n return config[prop]\n}\n\n/**\n * Read the whole configuration from file system. If the file does not exist or could\n * not be loaded, an empty configuration object is returned.\n *\n * @returns The whole CLI configuration.\n * @internal\n */\nasync function readConfig(): Promise<CliUserConfig> {\n const defaultConfig: CliUserConfig = {}\n try {\n const config = await readJsonFile(getCliUserConfigPath())\n if (!config || typeof config !== 'object' || Array.isArray(config)) {\n throw new Error('Invalid config file - expected an object')\n }\n return config\n } catch (err: unknown) {\n debug('Failed to read CLI config file: %s', err instanceof Error ? err.message : `${err}`)\n return defaultConfig\n }\n}\n\n/**\n * Get the file system location for the CLI user configuration file.\n * Takes into account the active environment (staging vs production).\n * The file is located in the user's home directory under the `.config` directory.\n *\n * @returns The path to the CLI configuration file.\n * @internal\n */\nfunction getCliUserConfigPath() {\n const sanityEnvSuffix = process.env.SANITY_INTERNAL_ENV === 'staging' ? '-staging' : ''\n const cliConfigPath =\n process.env.SANITY_CLI_CONFIG_PATH ||\n joinPath(homedir(), '.config', `sanity${sanityEnvSuffix}`, 'config.json')\n\n return cliConfigPath\n}\n"],"names":["mkdir","homedir","dirname","join","joinPath","z","debug","readJsonFile","writeJsonFile","cliUserConfigSchema","authToken","string","optional","telemetryConsent","object","updatedAt","number","value","status","enum","type","passthrough","setConfig","prop","config","readConfig","valueSchema","Error","error","success","safeParse","message","issues","map","path","configPath","getCliUserConfigPath","recursive","pretty","getConfig","defaultConfig","Array","isArray","err","sanityEnvSuffix","process","env","SANITY_INTERNAL_ENV","cliConfigPath","SANITY_CLI_CONFIG_PATH"],"mappings":"AAAA,SAAQA,KAAK,QAAO,mBAAkB;AACtC,SAAQC,OAAO,QAAO,UAAS;AAC/B,SAAQC,OAAO,EAAEC,QAAQC,QAAQ,QAAO,YAAW;AAEnD,SAAQC,CAAC,QAAO,MAAK;AAErB,SAAQC,KAAK,QAAO,cAAa;AACjC,SAAQC,YAAY,QAAO,0BAAyB;AACpD,SAAQC,aAAa,QAAO,2BAA0B;AAEtD,MAAMC,sBAAsB;IAC1BC,WAAWL,EAAEM,MAAM,GAAGC,QAAQ;IAC9BC,kBAAkBR,EACfS,MAAM,CAAC;QACNC,WAAWV,EAAEW,MAAM,GAAGJ,QAAQ;QAC9BK,OAAOZ,EACJS,MAAM,CAAC;YACNI,QAAQb,EAAEc,IAAI,CAAC;gBAAC;gBAAgB;gBAAS;gBAAW;aAAS;YAC7DC,MAAMf,EAAEM,MAAM;QAChB,GACCU,WAAW;IAChB,GACCT,QAAQ;AACb;AASA;;;;;;;CAOC,GACD,OAAO,eAAeU,UAAyCC,IAAO,EAAEN,KAAuB;IAC7F,MAAMO,SAAS,MAAMC;IACrB,MAAMC,cAAcjB,mBAAmB,CAACc,KAAK;IAC7C,IAAI,CAACG,aAAa;QAChB,MAAM,IAAIC,MAAM,CAAC,uCAAuC,EAAEJ,KAAK,CAAC,CAAC;IACnE;IAEA,MAAM,EAACK,KAAK,EAAEC,OAAO,EAAC,GAAGH,YAAYI,SAAS,CAACb;IAC/C,IAAI,CAACY,SAAS;QACZ,MAAME,UAAUH,MAAMI,MAAM,CACzBC,GAAG,CAAC,CAAC,EAACF,OAAO,EAAEG,IAAI,EAAC,GAAK,CAAC,CAAC,EAAEA,KAAK/B,IAAI,CAAC,KAAK,EAAE,EAAE4B,SAAS,EACzD5B,IAAI,CAAC;QAER,MAAM,IAAIwB,MAAM,CAAC,mCAAmC,EAAEJ,KAAK,GAAG,EAAEQ,SAAS;IAC3E;IAEA,MAAMI,aAAaC;IACnB,MAAMpC,MAAME,QAAQiC,aAAa;QAACE,WAAW;IAAI;IACjD,MAAM7B,cAAc2B,YAAY;QAAC,GAAGX,MAAM;QAAE,CAACD,KAAK,EAAEN;IAAK,GAAG;QAACqB,QAAQ;IAAI;AAC3E;AAEA;;;;;;CAMC,GACD,OAAO,eAAeC,UAAyChB,IAAO;IACpE,MAAMC,SAAS,MAAMC;IACrB,MAAMC,cAAcjB,mBAAmB,CAACc,KAAK;IAC7C,IAAI,CAACG,aAAa;QAChB,MAAM,IAAIC,MAAM,CAAC,uCAAuC,EAAEJ,KAAK,CAAC,CAAC;IACnE;IAEA,MAAM,EAACK,KAAK,EAAEC,OAAO,EAAC,GAAGH,YAAYI,SAAS,CAACN,MAAM,CAACD,KAAK;IAC3D,IAAI,CAACM,SAAS;QACZ,MAAME,UAAUH,MAAMI,MAAM,CACzBC,GAAG,CAAC,CAAC,EAACF,OAAO,EAAEG,IAAI,EAAC,GAAK,CAAC,CAAC,EAAEA,KAAK/B,IAAI,CAAC,KAAK,EAAE,EAAE4B,SAAS,EACzD5B,IAAI,CAAC;QAER,MAAM,IAAIwB,MAAM,CAAC,mCAAmC,EAAEJ,KAAK,GAAG,EAAEQ,SAAS;IAC3E;IAEA,OAAOP,MAAM,CAACD,KAAK;AACrB;AAEA;;;;;;CAMC,GACD,eAAeE;IACb,MAAMe,gBAA+B,CAAC;IACtC,IAAI;QACF,MAAMhB,SAAS,MAAMjB,aAAa6B;QAClC,IAAI,CAACZ,UAAU,OAAOA,WAAW,YAAYiB,MAAMC,OAAO,CAAClB,SAAS;YAClE,MAAM,IAAIG,MAAM;QAClB;QACA,OAAOH;IACT,EAAE,OAAOmB,KAAc;QACrBrC,MAAM,sCAAsCqC,eAAehB,QAAQgB,IAAIZ,OAAO,GAAG,GAAGY,KAAK;QACzF,OAAOH;IACT;AACF;AAEA;;;;;;;CAOC,GACD,SAASJ;IACP,MAAMQ,kBAAkBC,QAAQC,GAAG,CAACC,mBAAmB,KAAK,YAAY,aAAa;IACrF,MAAMC,gBACJH,QAAQC,GAAG,CAACG,sBAAsB,IAClC7C,SAASH,WAAW,WAAW,CAAC,MAAM,EAAE2C,iBAAiB,EAAE;IAE7D,OAAOI;AACT"}
1
+ {"version":3,"sources":["../../src/services/cliUserConfig.ts"],"sourcesContent":["import {mkdir} from 'node:fs/promises'\nimport {homedir} from 'node:os'\nimport {dirname, join as joinPath} from 'node:path'\n\nimport {z} from 'zod'\n\nimport {debug} from '../debug.js'\nimport {readJsonFile} from '../util/readJsonFile.js'\nimport {writeJsonFile} from '../util/writeJsonFile.js'\n\nconst cliUserConfigSchema = {\n authToken: z.string().optional(),\n telemetryConsent: z\n .object({\n updatedAt: z.number().optional(),\n value: z\n .object({\n status: z.enum(['undetermined', 'unset', 'granted', 'denied']),\n type: z.string(),\n })\n .passthrough(),\n })\n .optional(),\n}\n\n/**\n * The CLI user configuration schema.\n *\n * @internal\n */\ntype CliUserConfig = z.infer<z.ZodObject<typeof cliUserConfigSchema>>\n\n/**\n * Set the config value for the given property.\n * Validates that the passed value adheres to the defined CLI config schema.\n *\n * @param prop - The property to set the value for\n * @param value - The value to set\n * @internal\n */\nexport async function setCliUserConfig<P extends keyof CliUserConfig>(\n prop: P,\n value: CliUserConfig[P],\n) {\n const config = await readConfig()\n const valueSchema = cliUserConfigSchema[prop]\n if (!valueSchema) {\n throw new Error(`No schema defined for config property \"${prop}\"`)\n }\n\n const {error, success} = valueSchema.safeParse(value)\n if (!success) {\n const message = error.issues\n .map(({message, path}) => `[${path.join('.')}] ${message}`)\n .join('\\n')\n\n throw new Error(`Invalid value for config property \"${prop}\": ${message}`)\n }\n\n const configPath = getCliUserConfigPath()\n await mkdir(dirname(configPath), {recursive: true})\n await writeJsonFile(configPath, {...config, [prop]: value}, {pretty: true})\n}\n\n/**\n * Get the config value for the given property\n *\n * @param prop - The property to get the value for\n * @returns The value of the given property\n * @internal\n */\nexport async function getCliUserConfig<P extends keyof CliUserConfig>(\n prop: P,\n): Promise<CliUserConfig[P]> {\n const config = await readConfig()\n const valueSchema = cliUserConfigSchema[prop]\n if (!valueSchema) {\n throw new Error(`No schema defined for config property \"${prop}\"`)\n }\n\n const {success} = valueSchema.safeParse(config[prop])\n if (!success) {\n debug('Ignoring invalid stored value for \"%s\", returning undefined', prop)\n return undefined as CliUserConfig[P]\n }\n\n return config[prop]\n}\n\n/**\n * Read the whole configuration from file system. If the file does not exist or could\n * not be loaded, an empty configuration object is returned.\n *\n * @returns The whole CLI configuration.\n * @internal\n */\nasync function readConfig(): Promise<CliUserConfig> {\n const defaultConfig: CliUserConfig = {}\n try {\n const config = await readJsonFile(getCliUserConfigPath())\n if (!config || typeof config !== 'object' || Array.isArray(config)) {\n throw new Error('Invalid config file - expected an object')\n }\n return config\n } catch (err: unknown) {\n debug('Failed to read CLI config file: %s', err instanceof Error ? err.message : `${err}`)\n return defaultConfig\n }\n}\n\n/**\n * Get the file system location for the CLI user configuration file.\n * Takes into account the active environment (staging vs production).\n * The file is located in the user's home directory under the `.config` directory.\n *\n * @returns The path to the CLI configuration file.\n * @internal\n */\nfunction getCliUserConfigPath() {\n const sanityEnvSuffix = process.env.SANITY_INTERNAL_ENV === 'staging' ? '-staging' : ''\n const cliConfigPath =\n process.env.SANITY_CLI_CONFIG_PATH ||\n joinPath(homedir(), '.config', `sanity${sanityEnvSuffix}`, 'config.json')\n\n return cliConfigPath\n}\n"],"names":["mkdir","homedir","dirname","join","joinPath","z","debug","readJsonFile","writeJsonFile","cliUserConfigSchema","authToken","string","optional","telemetryConsent","object","updatedAt","number","value","status","enum","type","passthrough","setCliUserConfig","prop","config","readConfig","valueSchema","Error","error","success","safeParse","message","issues","map","path","configPath","getCliUserConfigPath","recursive","pretty","getCliUserConfig","undefined","defaultConfig","Array","isArray","err","sanityEnvSuffix","process","env","SANITY_INTERNAL_ENV","cliConfigPath","SANITY_CLI_CONFIG_PATH"],"mappings":"AAAA,SAAQA,KAAK,QAAO,mBAAkB;AACtC,SAAQC,OAAO,QAAO,UAAS;AAC/B,SAAQC,OAAO,EAAEC,QAAQC,QAAQ,QAAO,YAAW;AAEnD,SAAQC,CAAC,QAAO,MAAK;AAErB,SAAQC,KAAK,QAAO,cAAa;AACjC,SAAQC,YAAY,QAAO,0BAAyB;AACpD,SAAQC,aAAa,QAAO,2BAA0B;AAEtD,MAAMC,sBAAsB;IAC1BC,WAAWL,EAAEM,MAAM,GAAGC,QAAQ;IAC9BC,kBAAkBR,EACfS,MAAM,CAAC;QACNC,WAAWV,EAAEW,MAAM,GAAGJ,QAAQ;QAC9BK,OAAOZ,EACJS,MAAM,CAAC;YACNI,QAAQb,EAAEc,IAAI,CAAC;gBAAC;gBAAgB;gBAAS;gBAAW;aAAS;YAC7DC,MAAMf,EAAEM,MAAM;QAChB,GACCU,WAAW;IAChB,GACCT,QAAQ;AACb;AASA;;;;;;;CAOC,GACD,OAAO,eAAeU,iBACpBC,IAAO,EACPN,KAAuB;IAEvB,MAAMO,SAAS,MAAMC;IACrB,MAAMC,cAAcjB,mBAAmB,CAACc,KAAK;IAC7C,IAAI,CAACG,aAAa;QAChB,MAAM,IAAIC,MAAM,CAAC,uCAAuC,EAAEJ,KAAK,CAAC,CAAC;IACnE;IAEA,MAAM,EAACK,KAAK,EAAEC,OAAO,EAAC,GAAGH,YAAYI,SAAS,CAACb;IAC/C,IAAI,CAACY,SAAS;QACZ,MAAME,UAAUH,MAAMI,MAAM,CACzBC,GAAG,CAAC,CAAC,EAACF,OAAO,EAAEG,IAAI,EAAC,GAAK,CAAC,CAAC,EAAEA,KAAK/B,IAAI,CAAC,KAAK,EAAE,EAAE4B,SAAS,EACzD5B,IAAI,CAAC;QAER,MAAM,IAAIwB,MAAM,CAAC,mCAAmC,EAAEJ,KAAK,GAAG,EAAEQ,SAAS;IAC3E;IAEA,MAAMI,aAAaC;IACnB,MAAMpC,MAAME,QAAQiC,aAAa;QAACE,WAAW;IAAI;IACjD,MAAM7B,cAAc2B,YAAY;QAAC,GAAGX,MAAM;QAAE,CAACD,KAAK,EAAEN;IAAK,GAAG;QAACqB,QAAQ;IAAI;AAC3E;AAEA;;;;;;CAMC,GACD,OAAO,eAAeC,iBACpBhB,IAAO;IAEP,MAAMC,SAAS,MAAMC;IACrB,MAAMC,cAAcjB,mBAAmB,CAACc,KAAK;IAC7C,IAAI,CAACG,aAAa;QAChB,MAAM,IAAIC,MAAM,CAAC,uCAAuC,EAAEJ,KAAK,CAAC,CAAC;IACnE;IAEA,MAAM,EAACM,OAAO,EAAC,GAAGH,YAAYI,SAAS,CAACN,MAAM,CAACD,KAAK;IACpD,IAAI,CAACM,SAAS;QACZvB,MAAM,+DAA+DiB;QACrE,OAAOiB;IACT;IAEA,OAAOhB,MAAM,CAACD,KAAK;AACrB;AAEA;;;;;;CAMC,GACD,eAAeE;IACb,MAAMgB,gBAA+B,CAAC;IACtC,IAAI;QACF,MAAMjB,SAAS,MAAMjB,aAAa6B;QAClC,IAAI,CAACZ,UAAU,OAAOA,WAAW,YAAYkB,MAAMC,OAAO,CAACnB,SAAS;YAClE,MAAM,IAAIG,MAAM;QAClB;QACA,OAAOH;IACT,EAAE,OAAOoB,KAAc;QACrBtC,MAAM,sCAAsCsC,eAAejB,QAAQiB,IAAIb,OAAO,GAAG,GAAGa,KAAK;QACzF,OAAOH;IACT;AACF;AAEA;;;;;;;CAOC,GACD,SAASL;IACP,MAAMS,kBAAkBC,QAAQC,GAAG,CAACC,mBAAmB,KAAK,YAAY,aAAa;IACrF,MAAMC,gBACJH,QAAQC,GAAG,CAACG,sBAAsB,IAClC9C,SAASH,WAAW,WAAW,CAAC,MAAM,EAAE4C,iBAAiB,EAAE;IAE7D,OAAOI;AACT"}
@@ -1,4 +1,4 @@
1
- import { getConfig } from './cliUserConfig.js';
1
+ import { getCliUserConfig } from './cliUserConfig.js';
2
2
  let cachedToken;
3
3
  /**
4
4
  * Get the CLI authentication token from the environment or the config file
@@ -14,7 +14,7 @@ let cachedToken;
14
14
  cachedToken = token.trim();
15
15
  return cachedToken;
16
16
  }
17
- cachedToken = await getConfig('authToken');
17
+ cachedToken = await getCliUserConfig('authToken');
18
18
  return cachedToken;
19
19
  }
20
20
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/getCliToken.ts"],"sourcesContent":["import {getConfig} from './cliUserConfig.js'\n\nlet cachedToken: string | undefined\n\n/**\n * Get the CLI authentication token from the environment or the config file\n *\n * @returns A promise that resolves to a CLI token, or undefined if no token is found\n * @internal\n */\nexport async function getCliToken(): Promise<string | undefined> {\n if (cachedToken !== undefined) {\n return cachedToken\n }\n\n const token = process.env.SANITY_AUTH_TOKEN\n if (token) {\n cachedToken = token.trim()\n return cachedToken\n }\n\n cachedToken = await getConfig('authToken')\n return cachedToken\n}\n"],"names":["getConfig","cachedToken","getCliToken","undefined","token","process","env","SANITY_AUTH_TOKEN","trim"],"mappings":"AAAA,SAAQA,SAAS,QAAO,qBAAoB;AAE5C,IAAIC;AAEJ;;;;;CAKC,GACD,OAAO,eAAeC;IACpB,IAAID,gBAAgBE,WAAW;QAC7B,OAAOF;IACT;IAEA,MAAMG,QAAQC,QAAQC,GAAG,CAACC,iBAAiB;IAC3C,IAAIH,OAAO;QACTH,cAAcG,MAAMI,IAAI;QACxB,OAAOP;IACT;IAEAA,cAAc,MAAMD,UAAU;IAC9B,OAAOC;AACT"}
1
+ {"version":3,"sources":["../../src/services/getCliToken.ts"],"sourcesContent":["import {getCliUserConfig} from './cliUserConfig.js'\n\nlet cachedToken: string | undefined\n\n/**\n * Get the CLI authentication token from the environment or the config file\n *\n * @returns A promise that resolves to a CLI token, or undefined if no token is found\n * @internal\n */\nexport async function getCliToken(): Promise<string | undefined> {\n if (cachedToken !== undefined) {\n return cachedToken\n }\n\n const token = process.env.SANITY_AUTH_TOKEN\n if (token) {\n cachedToken = token.trim()\n return cachedToken\n }\n\n cachedToken = await getCliUserConfig('authToken')\n return cachedToken\n}\n"],"names":["getCliUserConfig","cachedToken","getCliToken","undefined","token","process","env","SANITY_AUTH_TOKEN","trim"],"mappings":"AAAA,SAAQA,gBAAgB,QAAO,qBAAoB;AAEnD,IAAIC;AAEJ;;;;;CAKC,GACD,OAAO,eAAeC;IACpB,IAAID,gBAAgBE,WAAW;QAC7B,OAAOF;IACT;IAEA,MAAMG,QAAQC,QAAQC,GAAG,CAACC,iBAAiB;IAC3C,IAAIH,OAAO;QACTH,cAAcG,MAAMI,IAAI;QACxB,OAAOP;IACT;IAEAA,cAAc,MAAMD,iBAAiB;IACrC,OAAOC;AACT"}
@@ -9,8 +9,9 @@ import { pathToFileURL } from 'node:url';
9
9
  // Absolute paths in windows are not valid URLs and are not supported by import().
10
10
  // We need to convert the path to a file URL.
11
11
  // See: https://github.com/nodejs/node/issues/31710
12
+ const url = /^file:\/\//.test(source) ? source : pathToFileURL(source).href;
12
13
  // eslint-disable-next-line no-restricted-syntax
13
- return import(/^file:\/\//.test(source) ? source : pathToFileURL(source).href);
14
+ return import(/* @vite-ignore */ url);
14
15
  }
15
16
 
16
17
  //# sourceMappingURL=doImport.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/doImport.ts"],"sourcesContent":["// Only file that should be using dynamic import\nimport {pathToFileURL} from 'node:url'\n\n/**\n * This function is a replacement for built in dynamic import\n * This handles the case for windows file paths especially for absolute paths.\n *\n * @param source - File path\n */\nexport function doImport(source: string) {\n // Absolute paths in windows are not valid URLs and are not supported by import().\n // We need to convert the path to a file URL.\n // See: https://github.com/nodejs/node/issues/31710\n // eslint-disable-next-line no-restricted-syntax\n return import(/^file:\\/\\//.test(source) ? source : pathToFileURL(source).href)\n}\n"],"names":["pathToFileURL","doImport","source","test","href"],"mappings":"AAAA,gDAAgD;AAChD,SAAQA,aAAa,QAAO,WAAU;AAEtC;;;;;CAKC,GACD,OAAO,SAASC,SAASC,MAAc;IACrC,kFAAkF;IAClF,6CAA6C;IAC7C,mDAAmD;IACnD,gDAAgD;IAChD,OAAO,MAAM,CAAC,aAAaC,IAAI,CAACD,UAAUA,SAASF,cAAcE,QAAQE,IAAI;AAC/E"}
1
+ {"version":3,"sources":["../../src/util/doImport.ts"],"sourcesContent":["// Only file that should be using dynamic import\nimport {pathToFileURL} from 'node:url'\n\n/**\n * This function is a replacement for built in dynamic import\n * This handles the case for windows file paths especially for absolute paths.\n *\n * @param source - File path\n */\nexport function doImport(source: string) {\n // Absolute paths in windows are not valid URLs and are not supported by import().\n // We need to convert the path to a file URL.\n // See: https://github.com/nodejs/node/issues/31710\n const url = /^file:\\/\\//.test(source) ? source : pathToFileURL(source).href\n // eslint-disable-next-line no-restricted-syntax\n return import(\n /* @vite-ignore */\n url\n )\n}\n"],"names":["pathToFileURL","doImport","source","url","test","href"],"mappings":"AAAA,gDAAgD;AAChD,SAAQA,aAAa,QAAO,WAAU;AAEtC;;;;;CAKC,GACD,OAAO,SAASC,SAASC,MAAc;IACrC,kFAAkF;IAClF,6CAA6C;IAC7C,mDAAmD;IACnD,MAAMC,MAAM,aAAaC,IAAI,CAACF,UAAUA,SAASF,cAAcE,QAAQG,IAAI;IAC3E,gDAAgD;IAChD,OAAO,MAAM,CACX,gBAAgB,GAChBF;AAEJ"}
@@ -1,3 +1,4 @@
1
+ // TODO(SDK-983): Consider moving to @sanity/cli — only used there
1
2
  import { getStudioEnvironmentVariables } from './getStudioEnvironmentVariables.js';
2
3
  import { setupBrowserStubs } from './setupBrowserStubs.js';
3
4
  /**
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/util/environment/mockBrowserEnvironment.ts"],"sourcesContent":["import {getStudioEnvironmentVariables} from './getStudioEnvironmentVariables.js'\nimport {setupBrowserStubs} from './setupBrowserStubs.js'\n\n/**\n * Mocks a browser-like environment for processes in the main thread by:\n * - Injecting browser globals (window, document, ResizeObserver, etc.)\n * - Loading studio environment variables from the project's sanity installation into process.env\n *\n * This is useful for commands like `sanity exec` that have to run user scripts\n * in the main thread of the process (but in a child process).\n *\n * Be cautious when using this, since it will pollute the global namespace with browser globals.\n *\n * If your code can run in a worker thread, you should use the `studioWorkerTask` function instead.\n *\n * @param basePath - The root path of the Sanity Studio project\n * @returns A cleanup function that removes the injected globals and environment variables\n * @internal\n */\nexport async function mockBrowserEnvironment(basePath: string): Promise<() => void> {\n // 1. Setup browser globals\n const cleanupBrowserStubs = await setupBrowserStubs()\n\n // 2. Load and set environment variables into process.env\n const envVars = await getStudioEnvironmentVariables(basePath)\n const setEnvKeys: string[] = []\n const originalEnvValues: Record<string, string | undefined> = {}\n\n for (const [key, value] of Object.entries(envVars)) {\n // Store original value (if any) so we can restore it\n originalEnvValues[key] = process.env[key]\n process.env[key] = value\n setEnvKeys.push(key)\n }\n\n // Return cleanup function\n return () => {\n // Restore or delete environment variables\n for (const key of setEnvKeys) {\n if (originalEnvValues[key] === undefined) {\n delete process.env[key]\n } else {\n process.env[key] = originalEnvValues[key]\n }\n }\n\n // Clean up browser stubs\n cleanupBrowserStubs()\n }\n}\n"],"names":["getStudioEnvironmentVariables","setupBrowserStubs","mockBrowserEnvironment","basePath","cleanupBrowserStubs","envVars","setEnvKeys","originalEnvValues","key","value","Object","entries","process","env","push","undefined"],"mappings":"AAAA,SAAQA,6BAA6B,QAAO,qCAAoC;AAChF,SAAQC,iBAAiB,QAAO,yBAAwB;AAExD;;;;;;;;;;;;;;;CAeC,GACD,OAAO,eAAeC,uBAAuBC,QAAgB;IAC3D,2BAA2B;IAC3B,MAAMC,sBAAsB,MAAMH;IAElC,yDAAyD;IACzD,MAAMI,UAAU,MAAML,8BAA8BG;IACpD,MAAMG,aAAuB,EAAE;IAC/B,MAAMC,oBAAwD,CAAC;IAE/D,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACN,SAAU;QAClD,qDAAqD;QACrDE,iBAAiB,CAACC,IAAI,GAAGI,QAAQC,GAAG,CAACL,IAAI;QACzCI,QAAQC,GAAG,CAACL,IAAI,GAAGC;QACnBH,WAAWQ,IAAI,CAACN;IAClB;IAEA,0BAA0B;IAC1B,OAAO;QACL,0CAA0C;QAC1C,KAAK,MAAMA,OAAOF,WAAY;YAC5B,IAAIC,iBAAiB,CAACC,IAAI,KAAKO,WAAW;gBACxC,OAAOH,QAAQC,GAAG,CAACL,IAAI;YACzB,OAAO;gBACLI,QAAQC,GAAG,CAACL,IAAI,GAAGD,iBAAiB,CAACC,IAAI;YAC3C;QACF;QAEA,yBAAyB;QACzBJ;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/util/environment/mockBrowserEnvironment.ts"],"sourcesContent":["// TODO(SDK-983): Consider moving to @sanity/cli — only used there\nimport {getStudioEnvironmentVariables} from './getStudioEnvironmentVariables.js'\nimport {setupBrowserStubs} from './setupBrowserStubs.js'\n\n/**\n * Mocks a browser-like environment for processes in the main thread by:\n * - Injecting browser globals (window, document, ResizeObserver, etc.)\n * - Loading studio environment variables from the project's sanity installation into process.env\n *\n * This is useful for commands like `sanity exec` that have to run user scripts\n * in the main thread of the process (but in a child process).\n *\n * Be cautious when using this, since it will pollute the global namespace with browser globals.\n *\n * If your code can run in a worker thread, you should use the `studioWorkerTask` function instead.\n *\n * @param basePath - The root path of the Sanity Studio project\n * @returns A cleanup function that removes the injected globals and environment variables\n * @internal\n */\nexport async function mockBrowserEnvironment(basePath: string): Promise<() => void> {\n // 1. Setup browser globals\n const cleanupBrowserStubs = await setupBrowserStubs()\n\n // 2. Load and set environment variables into process.env\n const envVars = await getStudioEnvironmentVariables(basePath)\n const setEnvKeys: string[] = []\n const originalEnvValues: Record<string, string | undefined> = {}\n\n for (const [key, value] of Object.entries(envVars)) {\n // Store original value (if any) so we can restore it\n originalEnvValues[key] = process.env[key]\n process.env[key] = value\n setEnvKeys.push(key)\n }\n\n // Return cleanup function\n return () => {\n // Restore or delete environment variables\n for (const key of setEnvKeys) {\n if (originalEnvValues[key] === undefined) {\n delete process.env[key]\n } else {\n process.env[key] = originalEnvValues[key]\n }\n }\n\n // Clean up browser stubs\n cleanupBrowserStubs()\n }\n}\n"],"names":["getStudioEnvironmentVariables","setupBrowserStubs","mockBrowserEnvironment","basePath","cleanupBrowserStubs","envVars","setEnvKeys","originalEnvValues","key","value","Object","entries","process","env","push","undefined"],"mappings":"AAAA,kEAAkE;AAClE,SAAQA,6BAA6B,QAAO,qCAAoC;AAChF,SAAQC,iBAAiB,QAAO,yBAAwB;AAExD;;;;;;;;;;;;;;;CAeC,GACD,OAAO,eAAeC,uBAAuBC,QAAgB;IAC3D,2BAA2B;IAC3B,MAAMC,sBAAsB,MAAMH;IAElC,yDAAyD;IACzD,MAAMI,UAAU,MAAML,8BAA8BG;IACpD,MAAMG,aAAuB,EAAE;IAC/B,MAAMC,oBAAwD,CAAC;IAE/D,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACN,SAAU;QAClD,qDAAqD;QACrDE,iBAAiB,CAACC,IAAI,GAAGI,QAAQC,GAAG,CAACL,IAAI;QACzCI,QAAQC,GAAG,CAACL,IAAI,GAAGC;QACnBH,WAAWQ,IAAI,CAACN;IAClB;IAEA,0BAA0B;IAC1B,OAAO;QACL,0CAA0C;QAC1C,KAAK,MAAMA,OAAOF,WAAY;YAC5B,IAAIC,iBAAiB,CAACC,IAAI,KAAKO,WAAW;gBACxC,OAAOH,QAAQC,GAAG,CAACL,IAAI;YACzB,OAAO;gBACLI,QAAQC,GAAG,CAACL,IAAI,GAAGD,iBAAiB,CAACC,IAAI;YAC3C;QACF;QAEA,yBAAyB;QACzBJ;IACF;AACF"}
@@ -1,5 +1,5 @@
1
- import { CLIError } from '@oclif/core/errors';
2
- import { isTrueish } from './isTrueish.js';
1
+ import { ux } from '@oclif/core';
2
+ import { noopLogger } from '@sanity/telemetry';
3
3
  /**
4
4
  * @public
5
5
  * Symbol used to store the CLI telemetry store on globalThis.
@@ -9,12 +9,10 @@ import { isTrueish } from './isTrueish.js';
9
9
  * @public
10
10
  */ export function getCliTelemetry() {
11
11
  const global = globalThis;
12
- // This should never happen, but just in case.
13
- // Ignore this error in tests to avoid failing tests as tests don't run to
14
- if (!global[CLI_TELEMETRY_SYMBOL] && !isTrueish(process.env.TEST)) {
15
- throw new CLIError('CLI telemetry not initialized', {
16
- exit: 1
17
- });
12
+ // This should never happen, but if it does, we return a noop logger to avoid errors.
13
+ if (!global[CLI_TELEMETRY_SYMBOL]) {
14
+ ux.warn('CLI telemetry not initialized, returning noop logger');
15
+ return noopLogger;
18
16
  }
19
17
  return global[CLI_TELEMETRY_SYMBOL];
20
18
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/getCliTelemetry.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\n\nimport {type CLITelemetryStore} from '../telemetry/types.js'\nimport {isTrueish} from './isTrueish.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 just in case.\n // Ignore this error in tests to avoid failing tests as tests don't run to\n if (!global[CLI_TELEMETRY_SYMBOL] && !isTrueish(process.env.TEST)) {\n throw new CLIError('CLI telemetry not initialized', {exit: 1})\n }\n\n return global[CLI_TELEMETRY_SYMBOL] as CLITelemetryStore\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":["CLIError","isTrueish","CLI_TELEMETRY_SYMBOL","Symbol","for","getCliTelemetry","global","globalThis","process","env","TEST","exit","setCliTelemetry","telemetry","clearCliTelemetry"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,qBAAoB;AAG3C,SAAQC,SAAS,QAAO,iBAAgB;AAExC;;;;CAIC,GACD,OAAO,MAAMC,uBAAuBC,OAAOC,GAAG,CAAC,wBAAuB;AAMtE;;CAEC,GACD,OAAO,SAASC;IACd,MAAMC,SAASC;IACf,8CAA8C;IAC9C,0EAA0E;IAC1E,IAAI,CAACD,MAAM,CAACJ,qBAAqB,IAAI,CAACD,UAAUO,QAAQC,GAAG,CAACC,IAAI,GAAG;QACjE,MAAM,IAAIV,SAAS,iCAAiC;YAACW,MAAM;QAAC;IAC9D;IAEA,OAAOL,MAAM,CAACJ,qBAAqB;AACrC;AAEA;;;CAGC,GACD,OAAO,SAASU,gBAAgBC,SAA4B;IAC1D,MAAMP,SAASC;IACfD,MAAM,CAACJ,qBAAqB,GAAGW;AACjC;AAEA;;;CAGC,GACD,OAAO,SAASC;IACd,MAAMR,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 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,8 +1,9 @@
1
1
  /**
2
2
  * @internal
3
- * @returns The domain for sanity depending on the environment
4
- */ export function getSanityUrl() {
5
- return process.env.SANITY_INTERNAL_ENV === 'staging' ? 'https://www.sanity.work' : 'https://www.sanity.io';
3
+ * @returns The Sanity URL for the given path, using the correct domain based on the environment
4
+ */ export function getSanityUrl(path = '/') {
5
+ const domain = process.env.SANITY_INTERNAL_ENV === 'staging' ? 'https://www.sanity.work' : 'https://www.sanity.io';
6
+ return `${domain}${path.startsWith('/') ? path : `/${path}`}`;
6
7
  }
7
8
 
8
9
  //# sourceMappingURL=getSanityUrl.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/getSanityUrl.ts"],"sourcesContent":["/**\n * @internal\n * @returns The domain for sanity depending on the environment\n */\nexport function getSanityUrl() {\n return process.env.SANITY_INTERNAL_ENV === 'staging'\n ? 'https://www.sanity.work'\n : 'https://www.sanity.io'\n}\n"],"names":["getSanityUrl","process","env","SANITY_INTERNAL_ENV"],"mappings":"AAAA;;;CAGC,GACD,OAAO,SAASA;IACd,OAAOC,QAAQC,GAAG,CAACC,mBAAmB,KAAK,YACvC,4BACA;AACN"}
1
+ {"version":3,"sources":["../../src/util/getSanityUrl.ts"],"sourcesContent":["/**\n * @internal\n * @returns The Sanity URL for the given path, using the correct domain based on the environment\n */\nexport function getSanityUrl(path = '/') {\n const domain =\n process.env.SANITY_INTERNAL_ENV === 'staging'\n ? 'https://www.sanity.work'\n : 'https://www.sanity.io'\n return `${domain}${path.startsWith('/') ? path : `/${path}`}`\n}\n"],"names":["getSanityUrl","path","domain","process","env","SANITY_INTERNAL_ENV","startsWith"],"mappings":"AAAA;;;CAGC,GACD,OAAO,SAASA,aAAaC,OAAO,GAAG;IACrC,MAAMC,SACJC,QAAQC,GAAG,CAACC,mBAAmB,KAAK,YAChC,4BACA;IACN,OAAO,GAAGH,SAASD,KAAKK,UAAU,CAAC,OAAOL,OAAO,CAAC,CAAC,EAAEA,MAAM,EAAE;AAC/D"}
@@ -0,0 +1,32 @@
1
+ import { fileURLToPath, pathToFileURL } from 'node:url';
2
+ import { createJiti } from '@rexxars/jiti';
3
+ import { subdebug } from '../debug.js';
4
+ const debug = subdebug('importModule');
5
+ /**
6
+ * Imports a module using jiti and returns its exports.
7
+ * This is a thin wrapper around tsx to allow swapping out the underlying implementation in the future if needed.
8
+ *
9
+ * @param filePath - Path to the module to import.
10
+ * @param options - Options for the importModule function.
11
+ * @returns The exported module.
12
+ *
13
+ * @internal
14
+ */ export async function importModule(filePath, options = {}) {
15
+ const { default: returnDefault = true, tsconfigPath } = options;
16
+ const jiti = createJiti(import.meta.url, {
17
+ debug: debug.enabled,
18
+ tsconfigPaths: typeof tsconfigPath === 'string' ? tsconfigPath : true
19
+ });
20
+ const fileURL = typeof filePath === 'string' ? pathToFileURL(filePath) : filePath;
21
+ debug(`Loading module: ${fileURLToPath(fileURL)}`, {
22
+ tsconfigPath
23
+ });
24
+ const jitiOptions = {};
25
+ // If the default option is true, add it to the jiti options
26
+ if (returnDefault) {
27
+ jitiOptions.default = true;
28
+ }
29
+ return jiti.import(fileURLToPath(fileURL), jitiOptions);
30
+ }
31
+
32
+ //# sourceMappingURL=importModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/importModule.ts"],"sourcesContent":["import {fileURLToPath, pathToFileURL} from 'node:url'\n\nimport {createJiti, type JitiResolveOptions} from '@rexxars/jiti'\n\nimport {subdebug} from '../debug.js'\n\ninterface ImportModuleOptions {\n /**\n * Whether to return the default export of the module.\n * Default: true\n */\n default?: boolean\n\n /**\n * Path to the tsconfig file to use for the import. If not provided, the tsconfig\n * will be inferred from the nearest `tsconfig.json` file.\n */\n tsconfigPath?: string\n}\n\nconst debug = subdebug('importModule')\n\n/**\n * Imports a module using jiti and returns its exports.\n * This is a thin wrapper around tsx to allow swapping out the underlying implementation in the future if needed.\n *\n * @param filePath - Path to the module to import.\n * @param options - Options for the importModule function.\n * @returns The exported module.\n *\n * @internal\n */\nexport async function importModule<T = unknown>(\n filePath: string | URL,\n options: ImportModuleOptions = {},\n): Promise<T> {\n const {default: returnDefault = true, tsconfigPath} = options\n\n const jiti = createJiti(import.meta.url, {\n debug: debug.enabled,\n tsconfigPaths: typeof tsconfigPath === 'string' ? tsconfigPath : true,\n })\n\n const fileURL = typeof filePath === 'string' ? pathToFileURL(filePath) : filePath\n\n debug(`Loading module: ${fileURLToPath(fileURL)}`, {tsconfigPath})\n\n const jitiOptions: JitiResolveOptions & {default?: true} = {}\n\n // If the default option is true, add it to the jiti options\n if (returnDefault) {\n jitiOptions.default = true\n }\n\n return jiti.import<T>(fileURLToPath(fileURL), jitiOptions)\n}\n"],"names":["fileURLToPath","pathToFileURL","createJiti","subdebug","debug","importModule","filePath","options","default","returnDefault","tsconfigPath","jiti","url","enabled","tsconfigPaths","fileURL","jitiOptions","import"],"mappings":"AAAA,SAAQA,aAAa,EAAEC,aAAa,QAAO,WAAU;AAErD,SAAQC,UAAU,QAAgC,gBAAe;AAEjE,SAAQC,QAAQ,QAAO,cAAa;AAgBpC,MAAMC,QAAQD,SAAS;AAEvB;;;;;;;;;CASC,GACD,OAAO,eAAeE,aACpBC,QAAsB,EACtBC,UAA+B,CAAC,CAAC;IAEjC,MAAM,EAACC,SAASC,gBAAgB,IAAI,EAAEC,YAAY,EAAC,GAAGH;IAEtD,MAAMI,OAAOT,WAAW,YAAYU,GAAG,EAAE;QACvCR,OAAOA,MAAMS,OAAO;QACpBC,eAAe,OAAOJ,iBAAiB,WAAWA,eAAe;IACnE;IAEA,MAAMK,UAAU,OAAOT,aAAa,WAAWL,cAAcK,YAAYA;IAEzEF,MAAM,CAAC,gBAAgB,EAAEJ,cAAce,UAAU,EAAE;QAACL;IAAY;IAEhE,MAAMM,cAAqD,CAAC;IAE5D,4DAA4D;IAC5D,IAAIP,eAAe;QACjBO,YAAYR,OAAO,GAAG;IACxB;IAEA,OAAOG,KAAKM,MAAM,CAAIjB,cAAce,UAAUC;AAChD"}
@@ -1,5 +1,5 @@
1
1
  export function isInteractive() {
2
- return process.stdout.isTTY && process.env.TERM !== 'dumb' && !('CI' in process.env);
2
+ return Boolean(process.stdin.isTTY) && process.env.TERM !== 'dumb' && !('CI' in process.env);
3
3
  }
4
4
 
5
5
  //# sourceMappingURL=isInteractive.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/isInteractive.ts"],"sourcesContent":["export function isInteractive(): boolean {\n return process.stdout.isTTY && process.env.TERM !== 'dumb' && !('CI' in process.env)\n}\n"],"names":["isInteractive","process","stdout","isTTY","env","TERM"],"mappings":"AAAA,OAAO,SAASA;IACd,OAAOC,QAAQC,MAAM,CAACC,KAAK,IAAIF,QAAQG,GAAG,CAACC,IAAI,KAAK,UAAU,CAAE,CAAA,QAAQJ,QAAQG,GAAG,AAAD;AACpF"}
1
+ {"version":3,"sources":["../../src/util/isInteractive.ts"],"sourcesContent":["export function isInteractive(): boolean {\n return Boolean(process.stdin.isTTY) && process.env.TERM !== 'dumb' && !('CI' in process.env)\n}\n"],"names":["isInteractive","Boolean","process","stdin","isTTY","env","TERM"],"mappings":"AAAA,OAAO,SAASA;IACd,OAAOC,QAAQC,QAAQC,KAAK,CAACC,KAAK,KAAKF,QAAQG,GAAG,CAACC,IAAI,KAAK,UAAU,CAAE,CAAA,QAAQJ,QAAQG,GAAG,AAAD;AAC5F"}
@@ -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"}
@@ -0,0 +1,72 @@
1
+ import { Worker } from 'node:worker_threads';
2
+ import { subdebug } from '../debug.js';
3
+ const debug = subdebug('promisifyWorker');
4
+ /**
5
+ * Creates a Node.js Worker from the given file path and options, and wraps it
6
+ * in a Promise that resolves with the first message the worker sends, and
7
+ * rejects on error, message deserialization failure, or non-zero exit code.
8
+ * The worker is terminated after a message or error is received.
9
+ *
10
+ * @param filePath - URL to the worker file
11
+ * @param options - Options to pass to the Worker constructor
12
+ * @returns A promise that resolves with the first message from the worker
13
+ * @throws If the worker emits an error, a message deserialization error, or exits with a non-zero code
14
+ * @internal
15
+ */ export function promisifyWorker(filePath, options) {
16
+ const { timeout, ...workerOptions } = options ?? {};
17
+ const worker = new Worker(filePath, workerOptions);
18
+ const fileName = `[${filePath.pathname}]`;
19
+ return new Promise((resolve, reject)=>{
20
+ let settled = false;
21
+ let timeoutId;
22
+ if (timeout !== undefined && timeout > 0) {
23
+ timeoutId = setTimeout(()=>{
24
+ settled = true;
25
+ reject(new Error(`Worker timed out after ${timeout}ms`));
26
+ void worker.terminate();
27
+ worker.removeAllListeners();
28
+ }, timeout);
29
+ }
30
+ worker.addListener('error', function onWorkerError(err) {
31
+ settled = true;
32
+ clearTimeout(timeoutId);
33
+ debug(`Worker error: ${err.message}`, err);
34
+ reject(new Error(`Worker error: ${err.message}`, {
35
+ cause: err
36
+ }));
37
+ cleanup();
38
+ });
39
+ // No cleanup() here — the worker is already dead after exiting,
40
+ // so there is nothing to terminate or remove listeners from.
41
+ worker.addListener('exit', function onWorkerExit(code) {
42
+ clearTimeout(timeoutId);
43
+ if (code > 0) {
44
+ debug(`${fileName} exited with code ${code}`);
45
+ reject(new Error(`Worker exited with code ${code}`));
46
+ } else if (!settled) {
47
+ debug(`${fileName} exited with code 0 without sending a message`);
48
+ reject(new Error('Worker exited without sending a message'));
49
+ }
50
+ });
51
+ worker.addListener('messageerror', function onWorkerMessageError(err) {
52
+ settled = true;
53
+ clearTimeout(timeoutId);
54
+ debug(`${fileName} message error: ${err.message}`, err);
55
+ reject(new Error(`Failed to deserialize worker message: ${err}`));
56
+ cleanup();
57
+ });
58
+ worker.addListener('message', function onWorkerMessage(message) {
59
+ settled = true;
60
+ clearTimeout(timeoutId);
61
+ debug(`${fileName} message %o`, message);
62
+ resolve(message);
63
+ cleanup();
64
+ });
65
+ function cleanup() {
66
+ setImmediate(()=>worker.terminate());
67
+ worker.removeAllListeners();
68
+ }
69
+ });
70
+ }
71
+
72
+ //# sourceMappingURL=promisifyWorker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/promisifyWorker.ts"],"sourcesContent":["import {Worker, type WorkerOptions} from 'node:worker_threads'\n\nimport {subdebug} from '../debug.js'\n\nconst debug = subdebug('promisifyWorker')\n\ninterface PromisifyWorkerOptions extends WorkerOptions {\n /** Optional timeout in milliseconds. If the worker does not respond within this time, it will be terminated and the promise rejected. */\n timeout?: number\n}\n\n/**\n * Creates a Node.js Worker from the given file path and options, and wraps it\n * in a Promise that resolves with the first message the worker sends, and\n * rejects on error, message deserialization failure, or non-zero exit code.\n * The worker is terminated after a message or error is received.\n *\n * @param filePath - URL to the worker file\n * @param options - Options to pass to the Worker constructor\n * @returns A promise that resolves with the first message from the worker\n * @throws If the worker emits an error, a message deserialization error, or exits with a non-zero code\n * @internal\n */\nexport function promisifyWorker<T = unknown>(\n filePath: URL,\n options?: PromisifyWorkerOptions,\n): Promise<T> {\n const {timeout, ...workerOptions} = options ?? {}\n const worker = new Worker(filePath, workerOptions)\n\n const fileName = `[${filePath.pathname}]`\n\n return new Promise<T>((resolve, reject) => {\n let settled = false\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n\n if (timeout !== undefined && timeout > 0) {\n timeoutId = setTimeout(() => {\n settled = true\n reject(new Error(`Worker timed out after ${timeout}ms`))\n void worker.terminate()\n worker.removeAllListeners()\n }, timeout)\n }\n\n worker.addListener('error', function onWorkerError(err) {\n settled = true\n clearTimeout(timeoutId)\n debug(`Worker error: ${err.message}`, err)\n reject(new Error(`Worker error: ${err.message}`, {cause: err}))\n cleanup()\n })\n // No cleanup() here — the worker is already dead after exiting,\n // so there is nothing to terminate or remove listeners from.\n worker.addListener('exit', function onWorkerExit(code) {\n clearTimeout(timeoutId)\n if (code > 0) {\n debug(`${fileName} exited with code ${code}`)\n reject(new Error(`Worker exited with code ${code}`))\n } else if (!settled) {\n debug(`${fileName} exited with code 0 without sending a message`)\n reject(new Error('Worker exited without sending a message'))\n }\n })\n worker.addListener('messageerror', function onWorkerMessageError(err) {\n settled = true\n clearTimeout(timeoutId)\n debug(`${fileName} message error: ${err.message}`, err)\n reject(new Error(`Failed to deserialize worker message: ${err}`))\n cleanup()\n })\n worker.addListener('message', function onWorkerMessage(message) {\n settled = true\n clearTimeout(timeoutId)\n debug(`${fileName} message %o`, message)\n resolve(message)\n cleanup()\n })\n\n function cleanup() {\n setImmediate(() => worker.terminate())\n worker.removeAllListeners()\n }\n })\n}\n"],"names":["Worker","subdebug","debug","promisifyWorker","filePath","options","timeout","workerOptions","worker","fileName","pathname","Promise","resolve","reject","settled","timeoutId","undefined","setTimeout","Error","terminate","removeAllListeners","addListener","onWorkerError","err","clearTimeout","message","cause","cleanup","onWorkerExit","code","onWorkerMessageError","onWorkerMessage","setImmediate"],"mappings":"AAAA,SAAQA,MAAM,QAA2B,sBAAqB;AAE9D,SAAQC,QAAQ,QAAO,cAAa;AAEpC,MAAMC,QAAQD,SAAS;AAOvB;;;;;;;;;;;CAWC,GACD,OAAO,SAASE,gBACdC,QAAa,EACbC,OAAgC;IAEhC,MAAM,EAACC,OAAO,EAAE,GAAGC,eAAc,GAAGF,WAAW,CAAC;IAChD,MAAMG,SAAS,IAAIR,OAAOI,UAAUG;IAEpC,MAAME,WAAW,CAAC,CAAC,EAAEL,SAASM,QAAQ,CAAC,CAAC,CAAC;IAEzC,OAAO,IAAIC,QAAW,CAACC,SAASC;QAC9B,IAAIC,UAAU;QACd,IAAIC;QAEJ,IAAIT,YAAYU,aAAaV,UAAU,GAAG;YACxCS,YAAYE,WAAW;gBACrBH,UAAU;gBACVD,OAAO,IAAIK,MAAM,CAAC,uBAAuB,EAAEZ,QAAQ,EAAE,CAAC;gBACtD,KAAKE,OAAOW,SAAS;gBACrBX,OAAOY,kBAAkB;YAC3B,GAAGd;QACL;QAEAE,OAAOa,WAAW,CAAC,SAAS,SAASC,cAAcC,GAAG;YACpDT,UAAU;YACVU,aAAaT;YACbb,MAAM,CAAC,cAAc,EAAEqB,IAAIE,OAAO,EAAE,EAAEF;YACtCV,OAAO,IAAIK,MAAM,CAAC,cAAc,EAAEK,IAAIE,OAAO,EAAE,EAAE;gBAACC,OAAOH;YAAG;YAC5DI;QACF;QACA,gEAAgE;QAChE,6DAA6D;QAC7DnB,OAAOa,WAAW,CAAC,QAAQ,SAASO,aAAaC,IAAI;YACnDL,aAAaT;YACb,IAAIc,OAAO,GAAG;gBACZ3B,MAAM,GAAGO,SAAS,kBAAkB,EAAEoB,MAAM;gBAC5ChB,OAAO,IAAIK,MAAM,CAAC,wBAAwB,EAAEW,MAAM;YACpD,OAAO,IAAI,CAACf,SAAS;gBACnBZ,MAAM,GAAGO,SAAS,6CAA6C,CAAC;gBAChEI,OAAO,IAAIK,MAAM;YACnB;QACF;QACAV,OAAOa,WAAW,CAAC,gBAAgB,SAASS,qBAAqBP,GAAG;YAClET,UAAU;YACVU,aAAaT;YACbb,MAAM,GAAGO,SAAS,gBAAgB,EAAEc,IAAIE,OAAO,EAAE,EAAEF;YACnDV,OAAO,IAAIK,MAAM,CAAC,sCAAsC,EAAEK,KAAK;YAC/DI;QACF;QACAnB,OAAOa,WAAW,CAAC,WAAW,SAASU,gBAAgBN,OAAO;YAC5DX,UAAU;YACVU,aAAaT;YACbb,MAAM,GAAGO,SAAS,WAAW,CAAC,EAAEgB;YAChCb,QAAQa;YACRE;QACF;QAEA,SAASA;YACPK,aAAa,IAAMxB,OAAOW,SAAS;YACnCX,OAAOY,kBAAkB;QAC3B;IACF;AACF"}
@@ -0,0 +1,74 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { z } from 'zod';
3
+ /**
4
+ * Comprehensive package.json schema including all common properties.
5
+ * Feel free to add properties to this,
6
+ * 🟠ℹ️ BUT ENSURE OPTIONAL STUFF IS ACTUALLY OPTIONAL ℹ️🟠
7
+ * 🟠ℹ️ SINCE THIS IS USED IN A NUMBER OF LOCATIONS WHERE ℹ️🟠
8
+ * 🟠ℹ️ WE CANNOT ENFORCE/GUARANTEE ANY PARTICULAR PROPS ℹ️🟠
9
+ */ const packageJsonSchema = z.looseObject({
10
+ // Required fields
11
+ name: z.string(),
12
+ version: z.string(),
13
+ // Dependencies (optional)
14
+ dependencies: z.record(z.string(), z.string()).optional(),
15
+ devDependencies: z.record(z.string(), z.string()).optional(),
16
+ peerDependencies: z.record(z.string(), z.string()).optional(),
17
+ // Module structure (optional)
18
+ exports: z.record(z.string(), z.any()).optional(),
19
+ main: z.string().optional(),
20
+ types: z.string().optional(),
21
+ // Metadata (optional)
22
+ author: z.string().optional(),
23
+ description: z.string().optional(),
24
+ engines: z.record(z.string(), z.string()).optional(),
25
+ license: z.string().optional(),
26
+ private: z.boolean().optional(),
27
+ repository: z.object({
28
+ type: z.string(),
29
+ url: z.string()
30
+ }).optional(),
31
+ scripts: z.record(z.string(), z.string()).optional(),
32
+ type: z.enum([
33
+ 'module',
34
+ 'commonjs'
35
+ ]).optional()
36
+ });
37
+ /**
38
+ * Read the `package.json` file at the given path
39
+ *
40
+ * @param filePath - Path to package.json to read
41
+ * @param options - Options object for controlling read behavior
42
+ * @returns The parsed package.json
43
+ * @public
44
+ */ export async function readPackageJson(filePath, options = {}) {
45
+ const { defaults = {}, skipSchemaValidation = false } = options;
46
+ // Read and parse the file
47
+ let pkg;
48
+ try {
49
+ pkg = JSON.parse(await readFile(filePath, 'utf8'));
50
+ } catch (err) {
51
+ throw new Error(`Failed to read "${filePath}"`, {
52
+ cause: err
53
+ });
54
+ }
55
+ // Merge with defaults (parsed values take precedence)
56
+ const merged = {
57
+ ...defaults,
58
+ ...pkg
59
+ };
60
+ // Validate with schema unless skipped
61
+ let validated;
62
+ if (skipSchemaValidation) {
63
+ validated = merged;
64
+ } else {
65
+ const { data, error, success } = packageJsonSchema.safeParse(merged);
66
+ if (!success) {
67
+ throw new Error(`Invalid package.json at "${filePath}": ${error.issues.map((err)=>err.message).join('\n')}`);
68
+ }
69
+ validated = data;
70
+ }
71
+ return validated;
72
+ }
73
+
74
+ //# sourceMappingURL=readPackageJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/readPackageJson.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\n\nimport {z} from 'zod'\n\n/**\n * Comprehensive package.json schema including all common properties.\n * Feel free to add properties to this,\n * 🟠ℹ️ BUT ENSURE OPTIONAL STUFF IS ACTUALLY OPTIONAL ℹ️🟠\n * 🟠ℹ️ SINCE THIS IS USED IN A NUMBER OF LOCATIONS WHERE ℹ️🟠\n * 🟠ℹ️ WE CANNOT ENFORCE/GUARANTEE ANY PARTICULAR PROPS ℹ️🟠\n */\nconst packageJsonSchema = z.looseObject({\n // Required fields\n name: z.string(),\n version: z.string(),\n\n // Dependencies (optional)\n dependencies: z.record(z.string(), z.string()).optional(),\n devDependencies: z.record(z.string(), z.string()).optional(),\n peerDependencies: z.record(z.string(), z.string()).optional(),\n\n // Module structure (optional)\n exports: z.record(z.string(), z.any()).optional(),\n main: z.string().optional(),\n types: z.string().optional(),\n\n // Metadata (optional)\n author: z.string().optional(),\n description: z.string().optional(),\n engines: z.record(z.string(), z.string()).optional(),\n license: z.string().optional(),\n private: z.boolean().optional(),\n repository: z\n .object({\n type: z.string(),\n url: z.string(),\n })\n .optional(),\n scripts: z.record(z.string(), z.string()).optional(),\n type: z.enum(['module', 'commonjs']).optional(),\n})\n\n/**\n * Comprehensive representation of a package.json file.\n * Consolidates all properties from previous type definitions.\n *\n * @public\n */\nexport type PackageJson = z.infer<typeof packageJsonSchema>\n\n/**\n * Options for reading package.json files\n *\n * @public\n */\nexport interface ReadPackageJsonOptions {\n /**\n * Default values to merge with the parsed package.json.\n * Parsed values take precedence over defaults.\n */\n defaults?: Partial<PackageJson>\n\n /**\n * Skip Zod schema validation. When true, the file is parsed but not validated.\n * Defaults to false.\n */\n skipSchemaValidation?: boolean\n}\n\n/**\n * Read the `package.json` file at the given path\n *\n * @param filePath - Path to package.json to read\n * @param options - Options object for controlling read behavior\n * @returns The parsed package.json\n * @public\n */\nexport async function readPackageJson(\n filePath: string | URL,\n options: ReadPackageJsonOptions = {},\n): Promise<PackageJson> {\n const {defaults = {}, skipSchemaValidation = false} = options\n\n // Read and parse the file\n let pkg: Record<string, unknown>\n try {\n pkg = JSON.parse(await readFile(filePath, 'utf8'))\n } catch (err: unknown) {\n throw new Error(`Failed to read \"${filePath}\"`, {cause: err})\n }\n\n // Merge with defaults (parsed values take precedence)\n const merged = {...defaults, ...pkg}\n\n // Validate with schema unless skipped\n let validated: PackageJson\n if (skipSchemaValidation) {\n validated = merged as PackageJson\n } else {\n const {data, error, success} = packageJsonSchema.safeParse(merged)\n if (!success) {\n throw new Error(\n `Invalid package.json at \"${filePath}\": ${error.issues.map((err) => err.message).join('\\n')}`,\n )\n }\n validated = data\n }\n\n return validated\n}\n"],"names":["readFile","z","packageJsonSchema","looseObject","name","string","version","dependencies","record","optional","devDependencies","peerDependencies","exports","any","main","types","author","description","engines","license","private","boolean","repository","object","type","url","scripts","enum","readPackageJson","filePath","options","defaults","skipSchemaValidation","pkg","JSON","parse","err","Error","cause","merged","validated","data","error","success","safeParse","issues","map","message","join"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,mBAAkB;AAEzC,SAAQC,CAAC,QAAO,MAAK;AAErB;;;;;;CAMC,GACD,MAAMC,oBAAoBD,EAAEE,WAAW,CAAC;IACtC,kBAAkB;IAClBC,MAAMH,EAAEI,MAAM;IACdC,SAASL,EAAEI,MAAM;IAEjB,0BAA0B;IAC1BE,cAAcN,EAAEO,MAAM,CAACP,EAAEI,MAAM,IAAIJ,EAAEI,MAAM,IAAII,QAAQ;IACvDC,iBAAiBT,EAAEO,MAAM,CAACP,EAAEI,MAAM,IAAIJ,EAAEI,MAAM,IAAII,QAAQ;IAC1DE,kBAAkBV,EAAEO,MAAM,CAACP,EAAEI,MAAM,IAAIJ,EAAEI,MAAM,IAAII,QAAQ;IAE3D,8BAA8B;IAC9BG,SAASX,EAAEO,MAAM,CAACP,EAAEI,MAAM,IAAIJ,EAAEY,GAAG,IAAIJ,QAAQ;IAC/CK,MAAMb,EAAEI,MAAM,GAAGI,QAAQ;IACzBM,OAAOd,EAAEI,MAAM,GAAGI,QAAQ;IAE1B,sBAAsB;IACtBO,QAAQf,EAAEI,MAAM,GAAGI,QAAQ;IAC3BQ,aAAahB,EAAEI,MAAM,GAAGI,QAAQ;IAChCS,SAASjB,EAAEO,MAAM,CAACP,EAAEI,MAAM,IAAIJ,EAAEI,MAAM,IAAII,QAAQ;IAClDU,SAASlB,EAAEI,MAAM,GAAGI,QAAQ;IAC5BW,SAASnB,EAAEoB,OAAO,GAAGZ,QAAQ;IAC7Ba,YAAYrB,EACTsB,MAAM,CAAC;QACNC,MAAMvB,EAAEI,MAAM;QACdoB,KAAKxB,EAAEI,MAAM;IACf,GACCI,QAAQ;IACXiB,SAASzB,EAAEO,MAAM,CAACP,EAAEI,MAAM,IAAIJ,EAAEI,MAAM,IAAII,QAAQ;IAClDe,MAAMvB,EAAE0B,IAAI,CAAC;QAAC;QAAU;KAAW,EAAElB,QAAQ;AAC/C;AA6BA;;;;;;;CAOC,GACD,OAAO,eAAemB,gBACpBC,QAAsB,EACtBC,UAAkC,CAAC,CAAC;IAEpC,MAAM,EAACC,WAAW,CAAC,CAAC,EAAEC,uBAAuB,KAAK,EAAC,GAAGF;IAEtD,0BAA0B;IAC1B,IAAIG;IACJ,IAAI;QACFA,MAAMC,KAAKC,KAAK,CAAC,MAAMnC,SAAS6B,UAAU;IAC5C,EAAE,OAAOO,KAAc;QACrB,MAAM,IAAIC,MAAM,CAAC,gBAAgB,EAAER,SAAS,CAAC,CAAC,EAAE;YAACS,OAAOF;QAAG;IAC7D;IAEA,sDAAsD;IACtD,MAAMG,SAAS;QAAC,GAAGR,QAAQ;QAAE,GAAGE,GAAG;IAAA;IAEnC,sCAAsC;IACtC,IAAIO;IACJ,IAAIR,sBAAsB;QACxBQ,YAAYD;IACd,OAAO;QACL,MAAM,EAACE,IAAI,EAAEC,KAAK,EAAEC,OAAO,EAAC,GAAGzC,kBAAkB0C,SAAS,CAACL;QAC3D,IAAI,CAACI,SAAS;YACZ,MAAM,IAAIN,MACR,CAAC,yBAAyB,EAAER,SAAS,GAAG,EAAEa,MAAMG,MAAM,CAACC,GAAG,CAAC,CAACV,MAAQA,IAAIW,OAAO,EAAEC,IAAI,CAAC,OAAO;QAEjG;QACAR,YAAYC;IACd;IAEA,OAAOD;AACT"}