@sanity/cli-core 0.0.0-20260413145249 → 0.0.0-20260416133835

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.
@@ -471,6 +471,30 @@ export declare function getProjectCliClient({
471
471
  ...config
472
472
  }: ProjectCliClientOptions): Promise<SanityClient_2>;
473
473
 
474
+ /**
475
+ * Returns the base Sanity configuration directory for the current user.
476
+ * For persistent user settings (auth tokens, preferences, etc.).
477
+ * Respects `SANITY_INTERNAL_ENV=staging` to isolate staging instances.
478
+ *
479
+ * Layout: `~/.config/sanity{-staging}/`
480
+ *
481
+ * @returns Absolute path to the config directory
482
+ * @internal
483
+ */
484
+ export declare function getSanityConfigDir(): string;
485
+
486
+ /**
487
+ * Returns the base Sanity data directory for the current user.
488
+ * For ephemeral runtime state (dev-server registries, caches, etc.).
489
+ * Respects `SANITY_INTERNAL_ENV=staging` to isolate staging instances.
490
+ *
491
+ * Layout: `~/.sanity{-staging}/`
492
+ *
493
+ * @returns Absolute path to the data directory
494
+ * @internal
495
+ */
496
+ export declare function getSanityDataDir(): string;
497
+
474
498
  /**
475
499
  * Gets an environment variable with the appropriate Sanity prefix based on whether it's an app or studio.
476
500
  *
@@ -23,6 +23,7 @@ export { getTelemetryBaseInfo } from '../telemetry/getTelemetryBaseInfo.js';
23
23
  export { noopLogger } from '../telemetry/noopTelemetry.js';
24
24
  export { doImport } from '../util/doImport.js';
25
25
  export * from '../util/environment/mockBrowserEnvironment.js';
26
+ export * from '../util/getSanityConfigDir.js';
26
27
  export * from '../util/getSanityEnvVar.js';
27
28
  export * from '../util/getSanityUrl.js';
28
29
  export * from '../util/importModule.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/_exports/index.ts"],"sourcesContent":["export * from '../config/cli/getCliConfig.js'\nexport * from '../config/cli/getCliConfigSync.js'\nexport {type CliConfig} from '../config/cli/types/cliConfig.js'\nexport {type UserViteConfig} from '../config/cli/types/userViteConfig.js'\nexport * from '../config/findProjectRoot.js'\nexport * from '../config/findProjectRootSync.js'\nexport * from '../config/studio/getStudioConfig.js'\nexport * from '../config/studio/getStudioWorkspaces.js'\nexport * from '../config/studio/isStudioConfig.js'\nexport * from '../config/util/findConfigsPaths.js'\nexport * from '../config/util/findStudioConfigPath.js'\nexport {type ProjectRootResult} from '../config/util/recursivelyResolveProjectRoot.js'\nexport * from '../debug.js'\nexport * from '../errors/NonInteractiveError.js'\nexport * from '../errors/NotFoundError.js'\nexport * from '../errors/ProjectRootNotFoundError.js'\nexport * from '../exitCodes.js'\nexport * from '../loaders/studio/studioWorkerTask.js'\nexport * from '../loaders/tsx/tsxWorkerTask.js'\nexport * from '../SanityCommand.js'\nexport * from '../services/apiClient.js'\nexport * from '../services/cliUserConfig.js'\nexport * from '../services/getCliToken.js'\nexport {\n clearCliTelemetry,\n CLI_TELEMETRY_SYMBOL,\n getCliTelemetry,\n setCliTelemetry,\n} from '../telemetry/getCliTelemetry.js'\nexport {getTelemetryBaseInfo} from '../telemetry/getTelemetryBaseInfo.js'\nexport {noopLogger} from '../telemetry/noopTelemetry.js'\nexport {\n type CLITelemetryStore,\n type ConsentInformation,\n type TelemetryUserProperties,\n} from '../telemetry/types.js'\nexport {type Output, type SanityOrgUser} from '../types.js'\nexport {doImport} from '../util/doImport.js'\nexport * from '../util/environment/mockBrowserEnvironment.js'\nexport * from '../util/getSanityEnvVar.js'\nexport * from '../util/getSanityUrl.js'\nexport * from '../util/importModule.js'\nexport * from '../util/isCi.js'\nexport * from '../util/isInteractive.js'\nexport * from '../util/isStaging.js'\nexport * from '../util/normalizePath.js'\nexport * from '../util/promisifyWorker.js'\nexport * from '../util/readPackageJson.js'\nexport * from '../util/resolveLocalPackage.js'\nexport * from '../util/safeStructuredClone.js'\nexport * from '../ux/colorizeJson.js'\nexport * from '../ux/timer.js'\n"],"names":["clearCliTelemetry","CLI_TELEMETRY_SYMBOL","getCliTelemetry","setCliTelemetry","getTelemetryBaseInfo","noopLogger","doImport"],"mappings":"AAAA,cAAc,gCAA+B;AAC7C,cAAc,oCAAmC;AAGjD,cAAc,+BAA8B;AAC5C,cAAc,mCAAkC;AAChD,cAAc,sCAAqC;AACnD,cAAc,0CAAyC;AACvD,cAAc,qCAAoC;AAClD,cAAc,qCAAoC;AAClD,cAAc,yCAAwC;AAEtD,cAAc,cAAa;AAC3B,cAAc,mCAAkC;AAChD,cAAc,6BAA4B;AAC1C,cAAc,wCAAuC;AACrD,cAAc,kBAAiB;AAC/B,cAAc,wCAAuC;AACrD,cAAc,kCAAiC;AAC/C,cAAc,sBAAqB;AACnC,cAAc,2BAA0B;AACxC,cAAc,+BAA8B;AAC5C,cAAc,6BAA4B;AAC1C,SACEA,iBAAiB,EACjBC,oBAAoB,EACpBC,eAAe,EACfC,eAAe,QACV,kCAAiC;AACxC,SAAQC,oBAAoB,QAAO,uCAAsC;AACzE,SAAQC,UAAU,QAAO,gCAA+B;AAOxD,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,cAAc,gDAA+C;AAC7D,cAAc,6BAA4B;AAC1C,cAAc,0BAAyB;AACvC,cAAc,0BAAyB;AACvC,cAAc,kBAAiB;AAC/B,cAAc,2BAA0B;AACxC,cAAc,uBAAsB;AACpC,cAAc,2BAA0B;AACxC,cAAc,6BAA4B;AAC1C,cAAc,6BAA4B;AAC1C,cAAc,iCAAgC;AAC9C,cAAc,iCAAgC;AAC9C,cAAc,wBAAuB;AACrC,cAAc,iBAAgB"}
1
+ {"version":3,"sources":["../../src/_exports/index.ts"],"sourcesContent":["export * from '../config/cli/getCliConfig.js'\nexport * from '../config/cli/getCliConfigSync.js'\nexport {type CliConfig} from '../config/cli/types/cliConfig.js'\nexport {type UserViteConfig} from '../config/cli/types/userViteConfig.js'\nexport * from '../config/findProjectRoot.js'\nexport * from '../config/findProjectRootSync.js'\nexport * from '../config/studio/getStudioConfig.js'\nexport * from '../config/studio/getStudioWorkspaces.js'\nexport * from '../config/studio/isStudioConfig.js'\nexport * from '../config/util/findConfigsPaths.js'\nexport * from '../config/util/findStudioConfigPath.js'\nexport {type ProjectRootResult} from '../config/util/recursivelyResolveProjectRoot.js'\nexport * from '../debug.js'\nexport * from '../errors/NonInteractiveError.js'\nexport * from '../errors/NotFoundError.js'\nexport * from '../errors/ProjectRootNotFoundError.js'\nexport * from '../exitCodes.js'\nexport * from '../loaders/studio/studioWorkerTask.js'\nexport * from '../loaders/tsx/tsxWorkerTask.js'\nexport * from '../SanityCommand.js'\nexport * from '../services/apiClient.js'\nexport * from '../services/cliUserConfig.js'\nexport * from '../services/getCliToken.js'\nexport {\n clearCliTelemetry,\n CLI_TELEMETRY_SYMBOL,\n getCliTelemetry,\n setCliTelemetry,\n} from '../telemetry/getCliTelemetry.js'\nexport {getTelemetryBaseInfo} from '../telemetry/getTelemetryBaseInfo.js'\nexport {noopLogger} from '../telemetry/noopTelemetry.js'\nexport {\n type CLITelemetryStore,\n type ConsentInformation,\n type TelemetryUserProperties,\n} from '../telemetry/types.js'\nexport {type Output, type SanityOrgUser} from '../types.js'\nexport {doImport} from '../util/doImport.js'\nexport * from '../util/environment/mockBrowserEnvironment.js'\nexport * from '../util/getSanityConfigDir.js'\nexport * from '../util/getSanityEnvVar.js'\nexport * from '../util/getSanityUrl.js'\nexport * from '../util/importModule.js'\nexport * from '../util/isCi.js'\nexport * from '../util/isInteractive.js'\nexport * from '../util/isStaging.js'\nexport * from '../util/normalizePath.js'\nexport * from '../util/promisifyWorker.js'\nexport * from '../util/readPackageJson.js'\nexport * from '../util/resolveLocalPackage.js'\nexport * from '../util/safeStructuredClone.js'\nexport * from '../ux/colorizeJson.js'\nexport * from '../ux/timer.js'\n"],"names":["clearCliTelemetry","CLI_TELEMETRY_SYMBOL","getCliTelemetry","setCliTelemetry","getTelemetryBaseInfo","noopLogger","doImport"],"mappings":"AAAA,cAAc,gCAA+B;AAC7C,cAAc,oCAAmC;AAGjD,cAAc,+BAA8B;AAC5C,cAAc,mCAAkC;AAChD,cAAc,sCAAqC;AACnD,cAAc,0CAAyC;AACvD,cAAc,qCAAoC;AAClD,cAAc,qCAAoC;AAClD,cAAc,yCAAwC;AAEtD,cAAc,cAAa;AAC3B,cAAc,mCAAkC;AAChD,cAAc,6BAA4B;AAC1C,cAAc,wCAAuC;AACrD,cAAc,kBAAiB;AAC/B,cAAc,wCAAuC;AACrD,cAAc,kCAAiC;AAC/C,cAAc,sBAAqB;AACnC,cAAc,2BAA0B;AACxC,cAAc,+BAA8B;AAC5C,cAAc,6BAA4B;AAC1C,SACEA,iBAAiB,EACjBC,oBAAoB,EACpBC,eAAe,EACfC,eAAe,QACV,kCAAiC;AACxC,SAAQC,oBAAoB,QAAO,uCAAsC;AACzE,SAAQC,UAAU,QAAO,gCAA+B;AAOxD,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,cAAc,gDAA+C;AAC7D,cAAc,gCAA+B;AAC7C,cAAc,6BAA4B;AAC1C,cAAc,0BAAyB;AACvC,cAAc,0BAAyB;AACvC,cAAc,kBAAiB;AAC/B,cAAc,2BAA0B;AACxC,cAAc,uBAAsB;AACpC,cAAc,2BAA0B;AACxC,cAAc,6BAA4B;AAC1C,cAAc,6BAA4B;AAC1C,cAAc,iCAAgC;AAC9C,cAAc,iCAAgC;AAC9C,cAAc,wBAAuB;AACrC,cAAc,iBAAgB"}
@@ -1,8 +1,8 @@
1
1
  import { mkdirSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
2
  import { dirname, join as joinPath } from 'node:path';
4
3
  import { z } from 'zod/mini';
5
4
  import { debug } from '../debug.js';
5
+ import { getSanityConfigDir } from '../util/getSanityConfigDir.js';
6
6
  import { readJsonFileSync } from '../util/readJsonFileSync.js';
7
7
  import { writeJsonFileSync } from '../util/writeJsonFileSync.js';
8
8
  import { clearCliTokenCache } from './cliTokenCache.js';
@@ -136,9 +136,7 @@ const cliUserConfigSchema = {
136
136
  * @returns The path to the CLI configuration file.
137
137
  * @internal
138
138
  */ function getCliUserConfigPath() {
139
- const sanityEnvSuffix = process.env.SANITY_INTERNAL_ENV === 'staging' ? '-staging' : '';
140
- const cliConfigPath = process.env.SANITY_CLI_CONFIG_PATH || joinPath(homedir(), '.config', `sanity${sanityEnvSuffix}`, 'config.json');
141
- return cliConfigPath;
139
+ return process.env.SANITY_CLI_CONFIG_PATH || joinPath(getSanityConfigDir(), 'config.json');
142
140
  }
143
141
 
144
142
  //# sourceMappingURL=cliUserConfig.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/cliUserConfig.ts"],"sourcesContent":["import {mkdirSync} from 'node:fs'\nimport {homedir} from 'node:os'\nimport {dirname, join as joinPath} from 'node:path'\n\nimport {z} from 'zod/mini'\n\nimport {debug} from '../debug.js'\nimport {readJsonFileSync} from '../util/readJsonFileSync.js'\nimport {writeJsonFileSync} from '../util/writeJsonFileSync.js'\nimport {clearCliTokenCache} from './cliTokenCache.js'\n\nconst cliUserConfigSchema = {\n authToken: z.optional(z.string()),\n}\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 function setCliUserConfig(prop: 'authToken', value: string | undefined): void {\n const config = readConfig()\n const result = cliUserConfigSchema[prop].safeParse(value)\n if (!result.success) {\n const message = result.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 mkdirSync(dirname(configPath), {recursive: true})\n\n // When value is undefined, explicitly delete the key rather than relying\n // on JSON.stringify silently dropping undefined values.\n if (value === undefined) {\n const {[prop]: _, ...rest} = config\n writeJsonFileSync(configPath, rest, {pretty: true})\n } else {\n writeJsonFileSync(configPath, {...config, [prop]: value}, {pretty: true})\n }\n\n // Invalidate the in-process token cache so subsequent getCliToken() calls\n // pick up the new value from disk.\n clearCliTokenCache()\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 function getCliUserConfig(prop: 'authToken'): string | undefined {\n const config = readConfig()\n const result = cliUserConfigSchema[prop].safeParse(config[prop])\n if (!result.success) {\n debug('Ignoring invalid stored value for \"%s\", returning undefined', prop)\n return undefined\n }\n\n return result.data\n}\n\n/**\n * A raw key-value store for CLI user configuration.\n * Unlike the typed `getCliUserConfig`/`setCliUserConfig`, this operates on\n * arbitrary keys without schema validation.\n *\n * @public\n */\nexport interface ConfigStore {\n /** Remove a key from the config file. */\n delete: (key: string) => void\n /** Read a value by key. Returns `undefined` if the key does not exist. */\n get: (key: string) => unknown\n /** Write a value by key, merging it into the existing config. */\n set: (key: string, value: unknown) => void\n}\n\n/**\n * Get a key-value store backed by the CLI user configuration file\n * (`~/.config/sanity/config.json`).\n *\n * Each call to `get`, `set`, or `delete` performs a full synchronous\n * read-modify-write cycle. This is intentional: sync I/O prevents\n * intra-process race conditions that occurred with the previous async\n * (configstore-backed) implementation.\n *\n * Note: there is no file-level locking, so concurrent writes from\n * separate CLI processes could still conflict. In practice this is\n * unlikely since CLI config writes are rare and user-initiated.\n *\n * @returns A {@link ConfigStore} for the CLI config file\n * @public\n */\nexport function getUserConfig(): ConfigStore {\n return {\n get(key: string): unknown {\n const config = readConfig()\n return config[key]\n },\n\n set(key: string, value: unknown): void {\n const config = readConfig()\n const configPath = getCliUserConfigPath()\n mkdirSync(dirname(configPath), {recursive: true})\n writeJsonFileSync(configPath, {...config, [key]: value}, {pretty: true})\n if (key === 'authToken') clearCliTokenCache()\n },\n\n // No mkdirSync needed: if readConfig() succeeded the directory already exists.\n delete(key: string): void {\n const config = readConfig()\n if (!(key in config)) return\n const {[key]: _, ...rest} = config\n writeJsonFileSync(getCliUserConfigPath(), rest, {pretty: true})\n if (key === 'authToken') clearCliTokenCache()\n },\n }\n}\n\n/**\n * Read the whole configuration from file system. If the file does not exist,\n * is corrupt, or otherwise unreadable, an empty object is returned. This is\n * intentional: the config only holds recoverable data (auth tokens, telemetry\n * consent) so silently resetting is preferable to blocking the user.\n *\n * @returns The whole CLI configuration.\n * @internal\n */\nfunction readConfig(): Record<string, unknown> {\n try {\n const config = readJsonFileSync(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 {}\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":["mkdirSync","homedir","dirname","join","joinPath","z","debug","readJsonFileSync","writeJsonFileSync","clearCliTokenCache","cliUserConfigSchema","authToken","optional","string","setCliUserConfig","prop","value","config","readConfig","result","safeParse","success","message","error","issues","map","path","Error","configPath","getCliUserConfigPath","recursive","undefined","_","rest","pretty","getCliUserConfig","data","getUserConfig","get","key","set","delete","Array","isArray","err","sanityEnvSuffix","process","env","SANITY_INTERNAL_ENV","cliConfigPath","SANITY_CLI_CONFIG_PATH"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/services/cliUserConfig.ts"],"sourcesContent":["import {mkdirSync} from 'node:fs'\nimport {dirname, join as joinPath} from 'node:path'\n\nimport {z} from 'zod/mini'\n\nimport {debug} from '../debug.js'\nimport {getSanityConfigDir} from '../util/getSanityConfigDir.js'\nimport {readJsonFileSync} from '../util/readJsonFileSync.js'\nimport {writeJsonFileSync} from '../util/writeJsonFileSync.js'\nimport {clearCliTokenCache} from './cliTokenCache.js'\n\nconst cliUserConfigSchema = {\n authToken: z.optional(z.string()),\n}\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 function setCliUserConfig(prop: 'authToken', value: string | undefined): void {\n const config = readConfig()\n const result = cliUserConfigSchema[prop].safeParse(value)\n if (!result.success) {\n const message = result.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 mkdirSync(dirname(configPath), {recursive: true})\n\n // When value is undefined, explicitly delete the key rather than relying\n // on JSON.stringify silently dropping undefined values.\n if (value === undefined) {\n const {[prop]: _, ...rest} = config\n writeJsonFileSync(configPath, rest, {pretty: true})\n } else {\n writeJsonFileSync(configPath, {...config, [prop]: value}, {pretty: true})\n }\n\n // Invalidate the in-process token cache so subsequent getCliToken() calls\n // pick up the new value from disk.\n clearCliTokenCache()\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 function getCliUserConfig(prop: 'authToken'): string | undefined {\n const config = readConfig()\n const result = cliUserConfigSchema[prop].safeParse(config[prop])\n if (!result.success) {\n debug('Ignoring invalid stored value for \"%s\", returning undefined', prop)\n return undefined\n }\n\n return result.data\n}\n\n/**\n * A raw key-value store for CLI user configuration.\n * Unlike the typed `getCliUserConfig`/`setCliUserConfig`, this operates on\n * arbitrary keys without schema validation.\n *\n * @public\n */\nexport interface ConfigStore {\n /** Remove a key from the config file. */\n delete: (key: string) => void\n /** Read a value by key. Returns `undefined` if the key does not exist. */\n get: (key: string) => unknown\n /** Write a value by key, merging it into the existing config. */\n set: (key: string, value: unknown) => void\n}\n\n/**\n * Get a key-value store backed by the CLI user configuration file\n * (`~/.config/sanity/config.json`).\n *\n * Each call to `get`, `set`, or `delete` performs a full synchronous\n * read-modify-write cycle. This is intentional: sync I/O prevents\n * intra-process race conditions that occurred with the previous async\n * (configstore-backed) implementation.\n *\n * Note: there is no file-level locking, so concurrent writes from\n * separate CLI processes could still conflict. In practice this is\n * unlikely since CLI config writes are rare and user-initiated.\n *\n * @returns A {@link ConfigStore} for the CLI config file\n * @public\n */\nexport function getUserConfig(): ConfigStore {\n return {\n get(key: string): unknown {\n const config = readConfig()\n return config[key]\n },\n\n set(key: string, value: unknown): void {\n const config = readConfig()\n const configPath = getCliUserConfigPath()\n mkdirSync(dirname(configPath), {recursive: true})\n writeJsonFileSync(configPath, {...config, [key]: value}, {pretty: true})\n if (key === 'authToken') clearCliTokenCache()\n },\n\n // No mkdirSync needed: if readConfig() succeeded the directory already exists.\n delete(key: string): void {\n const config = readConfig()\n if (!(key in config)) return\n const {[key]: _, ...rest} = config\n writeJsonFileSync(getCliUserConfigPath(), rest, {pretty: true})\n if (key === 'authToken') clearCliTokenCache()\n },\n }\n}\n\n/**\n * Read the whole configuration from file system. If the file does not exist,\n * is corrupt, or otherwise unreadable, an empty object is returned. This is\n * intentional: the config only holds recoverable data (auth tokens, telemetry\n * consent) so silently resetting is preferable to blocking the user.\n *\n * @returns The whole CLI configuration.\n * @internal\n */\nfunction readConfig(): Record<string, unknown> {\n try {\n const config = readJsonFileSync(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 {}\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 return process.env.SANITY_CLI_CONFIG_PATH || joinPath(getSanityConfigDir(), 'config.json')\n}\n"],"names":["mkdirSync","dirname","join","joinPath","z","debug","getSanityConfigDir","readJsonFileSync","writeJsonFileSync","clearCliTokenCache","cliUserConfigSchema","authToken","optional","string","setCliUserConfig","prop","value","config","readConfig","result","safeParse","success","message","error","issues","map","path","Error","configPath","getCliUserConfigPath","recursive","undefined","_","rest","pretty","getCliUserConfig","data","getUserConfig","get","key","set","delete","Array","isArray","err","process","env","SANITY_CLI_CONFIG_PATH"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { homedir } from 'node:os';
2
+ import { join as joinPath } from 'node:path';
3
+ import { isStaging } from './isStaging.js';
4
+ function envSuffix() {
5
+ return isStaging() ? '-staging' : '';
6
+ }
7
+ /**
8
+ * Returns the base Sanity configuration directory for the current user.
9
+ * For persistent user settings (auth tokens, preferences, etc.).
10
+ * Respects `SANITY_INTERNAL_ENV=staging` to isolate staging instances.
11
+ *
12
+ * Layout: `~/.config/sanity{-staging}/`
13
+ *
14
+ * @returns Absolute path to the config directory
15
+ * @internal
16
+ */ export function getSanityConfigDir() {
17
+ return joinPath(homedir(), '.config', `sanity${envSuffix()}`);
18
+ }
19
+ /**
20
+ * Returns the base Sanity data directory for the current user.
21
+ * For ephemeral runtime state (dev-server registries, caches, etc.).
22
+ * Respects `SANITY_INTERNAL_ENV=staging` to isolate staging instances.
23
+ *
24
+ * Layout: `~/.sanity{-staging}/`
25
+ *
26
+ * @returns Absolute path to the data directory
27
+ * @internal
28
+ */ export function getSanityDataDir() {
29
+ return joinPath(homedir(), `.sanity${envSuffix()}`);
30
+ }
31
+
32
+ //# sourceMappingURL=getSanityConfigDir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/getSanityConfigDir.ts"],"sourcesContent":["import {homedir} from 'node:os'\nimport {join as joinPath} from 'node:path'\n\nimport {isStaging} from './isStaging.js'\n\nfunction envSuffix(): string {\n return isStaging() ? '-staging' : ''\n}\n\n/**\n * Returns the base Sanity configuration directory for the current user.\n * For persistent user settings (auth tokens, preferences, etc.).\n * Respects `SANITY_INTERNAL_ENV=staging` to isolate staging instances.\n *\n * Layout: `~/.config/sanity{-staging}/`\n *\n * @returns Absolute path to the config directory\n * @internal\n */\nexport function getSanityConfigDir(): string {\n return joinPath(homedir(), '.config', `sanity${envSuffix()}`)\n}\n\n/**\n * Returns the base Sanity data directory for the current user.\n * For ephemeral runtime state (dev-server registries, caches, etc.).\n * Respects `SANITY_INTERNAL_ENV=staging` to isolate staging instances.\n *\n * Layout: `~/.sanity{-staging}/`\n *\n * @returns Absolute path to the data directory\n * @internal\n */\nexport function getSanityDataDir(): string {\n return joinPath(homedir(), `.sanity${envSuffix()}`)\n}\n"],"names":["homedir","join","joinPath","isStaging","envSuffix","getSanityConfigDir","getSanityDataDir"],"mappings":"AAAA,SAAQA,OAAO,QAAO,UAAS;AAC/B,SAAQC,QAAQC,QAAQ,QAAO,YAAW;AAE1C,SAAQC,SAAS,QAAO,iBAAgB;AAExC,SAASC;IACP,OAAOD,cAAc,aAAa;AACpC;AAEA;;;;;;;;;CASC,GACD,OAAO,SAASE;IACd,OAAOH,SAASF,WAAW,WAAW,CAAC,MAAM,EAAEI,aAAa;AAC9D;AAEA;;;;;;;;;CASC,GACD,OAAO,SAASE;IACd,OAAOJ,SAASF,WAAW,CAAC,OAAO,EAAEI,aAAa;AACpD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli-core",
3
- "version": "0.0.0-20260413145249",
3
+ "version": "0.0.0-20260416133835",
4
4
  "description": "Sanity CLI core package",
5
5
  "keywords": [
6
6
  "cli",
@@ -52,16 +52,16 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@inquirer/prompts": "^8.3.0",
55
- "@oclif/core": "^4.10.3",
55
+ "@oclif/core": "^4.10.5",
56
56
  "@rexxars/jiti": "^2.6.2",
57
- "@sanity/client": "^7.20.0",
57
+ "@sanity/client": "^7.21.0",
58
58
  "babel-plugin-react-compiler": "^1.0.0",
59
59
  "boxen": "^8.0.1",
60
60
  "debug": "^4.4.3",
61
61
  "get-it": "^8.7.0",
62
62
  "get-tsconfig": "^4.13.7",
63
63
  "import-meta-resolve": "^4.2.0",
64
- "jsdom": "^29.0.1",
64
+ "jsdom": "^29.0.2",
65
65
  "json-lexer": "^1.2.0",
66
66
  "log-symbols": "^7.0.1",
67
67
  "ora": "^9.0.0",
@@ -74,7 +74,7 @@
74
74
  },
75
75
  "devDependencies": {
76
76
  "@eslint/compat": "^2.0.3",
77
- "@sanity/pkg-utils": "^10.4.13",
77
+ "@sanity/pkg-utils": "^10.4.14",
78
78
  "@sanity/telemetry": "^0.9.0",
79
79
  "@swc/cli": "^0.8.1",
80
80
  "@swc/core": "^1.15.24",
@@ -83,7 +83,7 @@
83
83
  "@types/node": "^20.19.39",
84
84
  "eslint": "^10.1.0",
85
85
  "publint": "^0.3.18",
86
- "sanity": "^5.18.0",
86
+ "sanity": "^5.20.0",
87
87
  "typescript": "^5.9.3",
88
88
  "vitest": "^4.1.2",
89
89
  "@repo/package.config": "0.0.1",