@sanity/cli-core 0.0.2-alpha.2 → 0.1.0-alpha.10

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 (160) hide show
  1. package/dist/SanityCommand.js +34 -3
  2. package/dist/SanityCommand.js.map +1 -1
  3. package/dist/_exports/tree.d.ts +47 -0
  4. package/dist/_exports/tree.js +3 -0
  5. package/dist/_exports/tree.js.map +1 -0
  6. package/dist/_exports/ux.d.ts +40 -0
  7. package/dist/_exports/ux.js +6 -0
  8. package/dist/_exports/ux.js.map +1 -0
  9. package/dist/config/cli/getCliConfig.worker.js +2 -1
  10. package/dist/config/cli/getCliConfig.worker.js.map +1 -1
  11. package/dist/config/cli/schemas.js +5 -2
  12. package/dist/config/cli/schemas.js.map +1 -1
  13. package/dist/config/cli/types/cliConfig.js.map +1 -1
  14. package/dist/config/findProjectRoot.js +2 -2
  15. package/dist/config/findProjectRoot.js.map +1 -1
  16. package/dist/config/studio/getStudioConfig.js +0 -3
  17. package/dist/config/studio/getStudioConfig.js.map +1 -1
  18. package/dist/config/studio/getStudioWorkspaces.js +50 -0
  19. package/dist/config/studio/getStudioWorkspaces.js.map +1 -0
  20. package/dist/config/studio/isStudioConfig.js +19 -0
  21. package/dist/config/studio/isStudioConfig.js.map +1 -0
  22. package/dist/config/studio/readStudioConfig.js +13 -9
  23. package/dist/config/studio/readStudioConfig.js.map +1 -1
  24. package/dist/config/studio/readStudioConfig.worker.js +4 -30
  25. package/dist/config/studio/readStudioConfig.worker.js.map +1 -1
  26. package/dist/config/util/findStudioConfigPath.js +24 -3
  27. package/dist/config/util/findStudioConfigPath.js.map +1 -1
  28. package/dist/config/util/recursivelyResolveProjectRoot.js.map +1 -1
  29. package/dist/index.d.ts +6027 -36
  30. package/dist/index.js +14 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/loaders/studio/studioWorkerLoader.worker.js +10 -24
  33. package/dist/loaders/studio/studioWorkerLoader.worker.js.map +1 -1
  34. package/dist/loaders/studio/studioWorkerTask.js +41 -11
  35. package/dist/loaders/studio/studioWorkerTask.js.map +1 -1
  36. package/dist/loaders/tsx/tsxWorkerTask.js +3 -0
  37. package/dist/loaders/tsx/tsxWorkerTask.js.map +1 -1
  38. package/dist/services/apiClient.js +18 -17
  39. package/dist/services/apiClient.js.map +1 -1
  40. package/dist/telemetry/cleanupOldTelemetryFiles.js +30 -0
  41. package/dist/telemetry/cleanupOldTelemetryFiles.js.map +1 -0
  42. package/dist/telemetry/createTelemetryStore.js +95 -0
  43. package/dist/telemetry/createTelemetryStore.js.map +1 -0
  44. package/dist/telemetry/createTraceId.js +10 -0
  45. package/dist/telemetry/createTraceId.js.map +1 -0
  46. package/dist/telemetry/findTelemetryFiles.js +36 -0
  47. package/dist/telemetry/findTelemetryFiles.js.map +1 -0
  48. package/dist/telemetry/flushTelemetryFiles.js +107 -0
  49. package/dist/telemetry/flushTelemetryFiles.js.map +1 -0
  50. package/dist/telemetry/generateTelemetryFilePath.js +30 -0
  51. package/dist/telemetry/generateTelemetryFilePath.js.map +1 -0
  52. package/dist/telemetry/getTelemetryBaseInfo.js +33 -0
  53. package/dist/telemetry/getTelemetryBaseInfo.js.map +1 -0
  54. package/dist/telemetry/logger.js +54 -0
  55. package/dist/telemetry/logger.js.map +1 -0
  56. package/dist/telemetry/telemetryStoreDebug.js +7 -0
  57. package/dist/telemetry/telemetryStoreDebug.js.map +1 -0
  58. package/dist/telemetry/trace.js +150 -0
  59. package/dist/telemetry/trace.js.map +1 -0
  60. package/dist/telemetry/types.js +5 -0
  61. package/dist/telemetry/types.js.map +1 -0
  62. package/dist/types.js +2 -0
  63. package/dist/types.js.map +1 -1
  64. package/dist/util/doImport.js +16 -0
  65. package/dist/util/doImport.js.map +1 -0
  66. package/dist/util/environment/getStudioEnvironmentVariables.js +2 -1
  67. package/dist/util/environment/getStudioEnvironmentVariables.js.map +1 -1
  68. package/dist/util/getCliTelemetry.js +36 -0
  69. package/dist/util/getCliTelemetry.js.map +1 -0
  70. package/dist/util/isStaging.js +10 -0
  71. package/dist/util/isStaging.js.map +1 -0
  72. package/dist/util/normalizePath.js +12 -0
  73. package/dist/util/normalizePath.js.map +1 -0
  74. package/dist/util/parseStringFlag.js +19 -0
  75. package/dist/util/parseStringFlag.js.map +1 -0
  76. package/dist/util/readNDJSON.js +18 -0
  77. package/dist/util/readNDJSON.js.map +1 -0
  78. package/dist/util/resolveLocalPackage.js +34 -0
  79. package/dist/util/resolveLocalPackage.js.map +1 -0
  80. package/dist/util/tree.js +108 -0
  81. package/dist/util/tree.js.map +1 -0
  82. package/dist/util/waitForAsync.js +5 -0
  83. package/dist/util/waitForAsync.js.map +1 -0
  84. package/dist/ux/boxen.js +3 -0
  85. package/dist/ux/boxen.js.map +1 -0
  86. package/dist/ux/colorizeJson.js +6 -6
  87. package/dist/ux/colorizeJson.js.map +1 -1
  88. package/dist/ux/prompts.js +3 -0
  89. package/dist/ux/prompts.js.map +1 -0
  90. package/dist/ux/spinner.js +1 -1
  91. package/dist/ux/spinner.js.map +1 -1
  92. package/package.json +53 -28
  93. package/dist/SanityCommand.d.ts +0 -56
  94. package/dist/config/__tests__/cliToken.test.js +0 -74
  95. package/dist/config/__tests__/cliToken.test.js.map +0 -1
  96. package/dist/config/__tests__/cliUserConfig.test.js +0 -131
  97. package/dist/config/__tests__/cliUserConfig.test.js.map +0 -1
  98. package/dist/config/__tests__/findProjectRoot.test.js +0 -159
  99. package/dist/config/__tests__/findProjectRoot.test.js.map +0 -1
  100. package/dist/config/__tests__/findProjectRootSync.test.js +0 -112
  101. package/dist/config/__tests__/findProjectRootSync.test.js.map +0 -1
  102. package/dist/config/__tests__/getCliConfigSync.test.js +0 -31
  103. package/dist/config/__tests__/getCliConfigSync.test.js.map +0 -1
  104. package/dist/config/cli/getCliConfig.d.ts +0 -16
  105. package/dist/config/cli/getCliConfig.worker.d.ts +0 -1
  106. package/dist/config/cli/getCliConfigSync.d.ts +0 -12
  107. package/dist/config/cli/schemas.d.ts +0 -255
  108. package/dist/config/cli/types/cliConfig.d.ts +0 -74
  109. package/dist/config/cli/types/userViteConfig.d.ts +0 -5
  110. package/dist/config/findProjectRoot.d.ts +0 -14
  111. package/dist/config/findProjectRootSync.d.ts +0 -27
  112. package/dist/config/studio/getStudioConfig.d.ts +0 -14
  113. package/dist/config/studio/readStudioConfig.d.ts +0 -190
  114. package/dist/config/studio/readStudioConfig.worker.d.ts +0 -1
  115. package/dist/config/util/configPathsSync.d.ts +0 -17
  116. package/dist/config/util/findAppConfigPath.d.ts +0 -8
  117. package/dist/config/util/findConfigsPaths.d.ts +0 -16
  118. package/dist/config/util/findStudioConfigPath.d.ts +0 -9
  119. package/dist/config/util/isSanityV2StudioRoot.d.ts +0 -8
  120. package/dist/config/util/recursivelyResolveProjectRoot.d.ts +0 -27
  121. package/dist/debug.d.ts +0 -15
  122. package/dist/loaders/studio/studioWorkerLoader.worker.d.ts +0 -1
  123. package/dist/loaders/studio/studioWorkerTask.d.ts +0 -40
  124. package/dist/loaders/tsx/tsxWorkerLoader.worker.d.ts +0 -1
  125. package/dist/loaders/tsx/tsxWorkerTask.d.ts +0 -28
  126. package/dist/services/apiClient.d.ts +0 -53
  127. package/dist/services/cliUserConfig.d.ts +0 -57
  128. package/dist/services/getCliToken.d.ts +0 -7
  129. package/dist/types.d.ts +0 -7
  130. package/dist/util/NotFoundError.d.ts +0 -20
  131. package/dist/util/__tests__/createExpiringConfig.test.js +0 -400
  132. package/dist/util/__tests__/createExpiringConfig.test.js.map +0 -1
  133. package/dist/util/createExpiringConfig.d.ts +0 -37
  134. package/dist/util/environment/getStudioEnvironmentVariables.d.ts +0 -12
  135. package/dist/util/environment/mockBrowserEnvironment.d.ts +0 -17
  136. package/dist/util/environment/setupBrowserStubs.d.ts +0 -10
  137. package/dist/util/environment/stubs.d.ts +0 -254
  138. package/dist/util/fileExists.d.ts +0 -9
  139. package/dist/util/generateHelpUrl.d.ts +0 -8
  140. package/dist/util/getEmptyAuth.d.ts +0 -5
  141. package/dist/util/getSanityEnvVar.d.ts +0 -19
  142. package/dist/util/getSanityUrl.d.ts +0 -5
  143. package/dist/util/getUserConfig.d.ts +0 -2
  144. package/dist/util/isCi.d.ts +0 -1
  145. package/dist/util/isHttpError.d.ts +0 -29
  146. package/dist/util/isHttpError.js +0 -18
  147. package/dist/util/isHttpError.js.map +0 -1
  148. package/dist/util/isInteractive.d.ts +0 -1
  149. package/dist/util/isRecord.d.ts +0 -8
  150. package/dist/util/isTrueish.d.ts +0 -1
  151. package/dist/util/readJsonFile.d.ts +0 -14
  152. package/dist/util/safeStructuredClone.d.ts +0 -8
  153. package/dist/util/tryGetDefaultExport.d.ts +0 -5
  154. package/dist/util/writeJsonFile.d.ts +0 -9
  155. package/dist/ux/colorizeJson.d.ts +0 -1
  156. package/dist/ux/formatObject.d.ts +0 -1
  157. package/dist/ux/logSymbols.d.ts +0 -1
  158. package/dist/ux/printKeyValue.d.ts +0 -1
  159. package/dist/ux/spinner.d.ts +0 -1
  160. package/dist/ux/timer.d.ts +0 -12
@@ -0,0 +1,36 @@
1
+ import { join } from 'node:path';
2
+ import { glob } from 'tinyglobby';
3
+ import { normalizePath } from '../util/normalizePath.js';
4
+ import { getTelemetryBaseInfo } from './getTelemetryBaseInfo.js';
5
+ import { telemetryStoreDebug } from './telemetryStoreDebug.js';
6
+ /**
7
+ * Discovers and returns paths to all telemetry files for the current user/environment.
8
+ *
9
+ * This function is used during:
10
+ * - Flush operations: to collect and send events from all CLI sessions
11
+ * - Cleanup operations: to find old files that should be removed
12
+ *
13
+ * Uses glob patterns to match files across all sessions (not just the current one).
14
+ *
15
+ * @returns Promise resolving to array of file paths, empty if no files exist
16
+ * @internal
17
+ */ export async function findTelemetryFiles() {
18
+ try {
19
+ const { basePattern, directory } = await getTelemetryBaseInfo();
20
+ const pattern = `${basePattern}-*.ndjson`;
21
+ const fullPattern = join(directory, pattern);
22
+ telemetryStoreDebug('Looking for files matching pattern: %s', fullPattern);
23
+ // Converts windows backslashes to forward slashes for glob pattern
24
+ const matchingFiles = await glob(normalizePath(fullPattern));
25
+ telemetryStoreDebug('Found %d matching telemetry files', matchingFiles.length);
26
+ return matchingFiles;
27
+ } catch (error) {
28
+ if (error.code === 'ENOENT') {
29
+ telemetryStoreDebug('Telemetry directory does not exist yet');
30
+ return [];
31
+ }
32
+ throw error;
33
+ }
34
+ }
35
+
36
+ //# sourceMappingURL=findTelemetryFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/telemetry/findTelemetryFiles.ts"],"sourcesContent":["import {join} from 'node:path'\n\nimport {glob} from 'tinyglobby'\n\nimport {normalizePath} from '../util/normalizePath.js'\nimport {getTelemetryBaseInfo} from './getTelemetryBaseInfo.js'\nimport {telemetryStoreDebug} from './telemetryStoreDebug.js'\n\n/**\n * Discovers and returns paths to all telemetry files for the current user/environment.\n *\n * This function is used during:\n * - Flush operations: to collect and send events from all CLI sessions\n * - Cleanup operations: to find old files that should be removed\n *\n * Uses glob patterns to match files across all sessions (not just the current one).\n *\n * @returns Promise resolving to array of file paths, empty if no files exist\n * @internal\n */\nexport async function findTelemetryFiles(): Promise<string[]> {\n try {\n const {basePattern, directory} = await getTelemetryBaseInfo()\n const pattern = `${basePattern}-*.ndjson`\n const fullPattern = join(directory, pattern)\n telemetryStoreDebug('Looking for files matching pattern: %s', fullPattern)\n\n // Converts windows backslashes to forward slashes for glob pattern\n const matchingFiles = await glob(normalizePath(fullPattern))\n telemetryStoreDebug('Found %d matching telemetry files', matchingFiles.length)\n return matchingFiles\n } catch (error) {\n if ((error as {code?: string}).code === 'ENOENT') {\n telemetryStoreDebug('Telemetry directory does not exist yet')\n return []\n }\n throw error\n }\n}\n"],"names":["join","glob","normalizePath","getTelemetryBaseInfo","telemetryStoreDebug","findTelemetryFiles","basePattern","directory","pattern","fullPattern","matchingFiles","length","error","code"],"mappings":"AAAA,SAAQA,IAAI,QAAO,YAAW;AAE9B,SAAQC,IAAI,QAAO,aAAY;AAE/B,SAAQC,aAAa,QAAO,2BAA0B;AACtD,SAAQC,oBAAoB,QAAO,4BAA2B;AAC9D,SAAQC,mBAAmB,QAAO,2BAA0B;AAE5D;;;;;;;;;;;CAWC,GACD,OAAO,eAAeC;IACpB,IAAI;QACF,MAAM,EAACC,WAAW,EAAEC,SAAS,EAAC,GAAG,MAAMJ;QACvC,MAAMK,UAAU,GAAGF,YAAY,SAAS,CAAC;QACzC,MAAMG,cAAcT,KAAKO,WAAWC;QACpCJ,oBAAoB,0CAA0CK;QAE9D,mEAAmE;QACnE,MAAMC,gBAAgB,MAAMT,KAAKC,cAAcO;QAC/CL,oBAAoB,qCAAqCM,cAAcC,MAAM;QAC7E,OAAOD;IACT,EAAE,OAAOE,OAAO;QACd,IAAI,AAACA,MAA0BC,IAAI,KAAK,UAAU;YAChDT,oBAAoB;YACpB,OAAO,EAAE;QACX;QACA,MAAMQ;IACR;AACF"}
@@ -0,0 +1,107 @@
1
+ import { rm } from 'node:fs/promises';
2
+ import { catchError, defer, from, lastValueFrom, mergeMap, of, reduce, switchMap, tap } from 'rxjs';
3
+ import { readNDJSON } from '../util/readNDJSON.js';
4
+ import { cleanupOldTelemetryFiles } from './cleanupOldTelemetryFiles.js';
5
+ import { findTelemetryFiles } from './findTelemetryFiles.js';
6
+ import { telemetryStoreDebug } from './telemetryStoreDebug.js';
7
+ /**
8
+ * Standalone, stateless function to flush telemetry files.
9
+ *
10
+ * This function can be used independently of the telemetry store, making it
11
+ * suitable for use in child processes or other contexts where store state
12
+ * is not available.
13
+ *
14
+ * @param options - Configuration for consent resolution and event sending
15
+ * @returns Promise that resolves when flush operation is complete
16
+ *
17
+ * @internal
18
+ */ export async function flushTelemetryFiles(options) {
19
+ telemetryStoreDebug('Starting standalone flush operation');
20
+ // Helper function for deleting files with consistent error handling
21
+ const deleteFiles = (files, reason)=>{
22
+ if (files.length === 0) {
23
+ // of() is not same as of(undefined) in rxjs
24
+ // eslint-disable-next-line unicorn/no-useless-undefined
25
+ return of(undefined);
26
+ }
27
+ return from(files).pipe(mergeMap((filePath)=>from(rm(filePath, {
28
+ force: true
29
+ })).pipe(tap(()=>{
30
+ telemetryStoreDebug(`Deleted file ${reason}: %s`, filePath);
31
+ }), catchError((error)=>{
32
+ telemetryStoreDebug('Error deleting file %s: %o', filePath, error);
33
+ // of() is not same as of(undefined) in rxjs
34
+ // eslint-disable-next-line unicorn/no-useless-undefined
35
+ return of(undefined);
36
+ }))), // of() is not same as of(undefined) in rxjs
37
+ // eslint-disable-next-line unicorn/no-useless-undefined
38
+ switchMap(()=>of(undefined)));
39
+ };
40
+ const flush$ = defer(()=>from(options.resolveConsent())).pipe(tap((currentConsent)=>{
41
+ telemetryStoreDebug('Current consent status for flush: %s', currentConsent.status);
42
+ }), switchMap((currentConsent)=>{
43
+ // First cleanup old files, then process current files
44
+ return defer(()=>from(cleanupOldTelemetryFiles())).pipe(switchMap(()=>defer(()=>from(findTelemetryFiles()))), switchMap((filePaths)=>{
45
+ if (filePaths.length === 0) {
46
+ telemetryStoreDebug('No telemetry files found, nothing to flush');
47
+ return of({
48
+ allEvents: [],
49
+ consent: currentConsent,
50
+ filesToDelete: []
51
+ });
52
+ }
53
+ telemetryStoreDebug('Found %d telemetry files to process', filePaths.length);
54
+ return from(filePaths).pipe(mergeMap((filePath)=>{
55
+ return defer(()=>from(readNDJSON(filePath))).pipe(tap((events)=>{
56
+ telemetryStoreDebug('Read %d events from %s', events.length, filePath);
57
+ }), catchError((error)=>{
58
+ if (error.code === 'ENOENT') {
59
+ telemetryStoreDebug('File %s no longer exists, skipping', filePath);
60
+ return of([]);
61
+ }
62
+ telemetryStoreDebug('Error reading file %s: %o', filePath, error);
63
+ return of([]);
64
+ }), switchMap((events)=>of({
65
+ events,
66
+ filePath: events.length > 0 ? filePath : ''
67
+ })));
68
+ }), reduce((acc, current)=>{
69
+ if (current.filePath) {
70
+ acc.allEvents.push(...current.events);
71
+ acc.filesToDelete.push(current.filePath);
72
+ }
73
+ return acc;
74
+ }, {
75
+ allEvents: [],
76
+ filesToDelete: []
77
+ }), switchMap((result)=>of({
78
+ ...result,
79
+ consent: currentConsent
80
+ })));
81
+ }));
82
+ }), switchMap(({ allEvents, consent, filesToDelete })=>{
83
+ telemetryStoreDebug('Found %d total events to flush from %d files', allEvents.length, filesToDelete.length);
84
+ if (consent.status !== 'granted' || allEvents.length === 0) {
85
+ if (consent.status === 'granted') {
86
+ telemetryStoreDebug('No events to send, cleaning up empty files');
87
+ return deleteFiles(filesToDelete, 'empty files');
88
+ } else {
89
+ telemetryStoreDebug('Consent not granted (%s), cleaning up %d files without sending events', consent.status, filesToDelete.length);
90
+ return deleteFiles(filesToDelete, `without sending (consent: ${consent.status})`);
91
+ }
92
+ }
93
+ // Send events and then delete files
94
+ telemetryStoreDebug('Sending %d events to backend', allEvents.length);
95
+ return defer(()=>from(options.sendEvents(allEvents))).pipe(tap(()=>{
96
+ telemetryStoreDebug('Successfully sent events, deleting %d files', filesToDelete.length);
97
+ }), switchMap(()=>deleteFiles(filesToDelete, 'after successful send')));
98
+ }), tap(()=>{
99
+ telemetryStoreDebug('Standalone flush operation completed successfully');
100
+ }), switchMap(()=>of(undefined)), catchError((error)=>{
101
+ telemetryStoreDebug('Error during standalone flush operation: %o', error);
102
+ throw error;
103
+ }));
104
+ return lastValueFrom(flush$);
105
+ }
106
+
107
+ //# sourceMappingURL=flushTelemetryFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/telemetry/flushTelemetryFiles.ts"],"sourcesContent":["import {rm} from 'node:fs/promises'\n\nimport {type TelemetryEvent} from '@sanity/telemetry'\nimport {catchError, defer, from, lastValueFrom, mergeMap, of, reduce, switchMap, tap} from 'rxjs'\n\nimport {readNDJSON} from '../util/readNDJSON.js'\nimport {cleanupOldTelemetryFiles} from './cleanupOldTelemetryFiles.js'\nimport {findTelemetryFiles} from './findTelemetryFiles.js'\nimport {telemetryStoreDebug} from './telemetryStoreDebug.js'\nimport {type ConsentInformation} from './types.js'\n\ninterface FlushTelemetryFilesOptions {\n resolveConsent: () => Promise<ConsentInformation>\n sendEvents: (events: TelemetryEvent[]) => Promise<void>\n}\n\n/**\n * Standalone, stateless function to flush telemetry files.\n *\n * This function can be used independently of the telemetry store, making it\n * suitable for use in child processes or other contexts where store state\n * is not available.\n *\n * @param options - Configuration for consent resolution and event sending\n * @returns Promise that resolves when flush operation is complete\n *\n * @internal\n */\nexport async function flushTelemetryFiles(options: FlushTelemetryFilesOptions): Promise<void> {\n telemetryStoreDebug('Starting standalone flush operation')\n\n // Helper function for deleting files with consistent error handling\n const deleteFiles = (files: string[], reason: string) => {\n if (files.length === 0) {\n // of() is not same as of(undefined) in rxjs\n // eslint-disable-next-line unicorn/no-useless-undefined\n return of(undefined)\n }\n\n return from(files).pipe(\n mergeMap((filePath) =>\n from(rm(filePath, {force: true})).pipe(\n tap(() => {\n telemetryStoreDebug(`Deleted file ${reason}: %s`, filePath)\n }),\n catchError((error) => {\n telemetryStoreDebug('Error deleting file %s: %o', filePath, error)\n // of() is not same as of(undefined) in rxjs\n // eslint-disable-next-line unicorn/no-useless-undefined\n return of(undefined)\n }),\n ),\n ),\n // of() is not same as of(undefined) in rxjs\n // eslint-disable-next-line unicorn/no-useless-undefined\n switchMap(() => of(undefined)),\n )\n }\n\n const flush$ = defer(() => from(options.resolveConsent())).pipe(\n tap((currentConsent) => {\n telemetryStoreDebug('Current consent status for flush: %s', currentConsent.status)\n }),\n switchMap((currentConsent) => {\n // First cleanup old files, then process current files\n return defer(() => from(cleanupOldTelemetryFiles())).pipe(\n switchMap(() => defer(() => from(findTelemetryFiles()))),\n switchMap((filePaths) => {\n if (filePaths.length === 0) {\n telemetryStoreDebug('No telemetry files found, nothing to flush')\n return of({allEvents: [], consent: currentConsent, filesToDelete: []})\n }\n\n telemetryStoreDebug('Found %d telemetry files to process', filePaths.length)\n\n return from(filePaths).pipe(\n mergeMap((filePath) => {\n return defer(() => from(readNDJSON<TelemetryEvent>(filePath))).pipe(\n tap((events) => {\n telemetryStoreDebug('Read %d events from %s', events.length, filePath)\n }),\n catchError((error) => {\n if ((error as {code?: string}).code === 'ENOENT') {\n telemetryStoreDebug('File %s no longer exists, skipping', filePath)\n return of([])\n }\n telemetryStoreDebug('Error reading file %s: %o', filePath, error)\n return of([])\n }),\n switchMap((events) => of({events, filePath: events.length > 0 ? filePath : ''})),\n )\n }),\n reduce(\n (acc: {allEvents: TelemetryEvent[]; filesToDelete: string[]}, current) => {\n if (current.filePath) {\n acc.allEvents.push(...current.events)\n acc.filesToDelete.push(current.filePath)\n }\n return acc\n },\n {allEvents: [], filesToDelete: []},\n ),\n switchMap((result) => of({...result, consent: currentConsent})),\n )\n }),\n )\n }),\n switchMap(({allEvents, consent, filesToDelete}) => {\n telemetryStoreDebug(\n 'Found %d total events to flush from %d files',\n allEvents.length,\n filesToDelete.length,\n )\n\n if (consent.status !== 'granted' || allEvents.length === 0) {\n if (consent.status === 'granted') {\n telemetryStoreDebug('No events to send, cleaning up empty files')\n return deleteFiles(filesToDelete, 'empty files')\n } else {\n telemetryStoreDebug(\n 'Consent not granted (%s), cleaning up %d files without sending events',\n consent.status,\n filesToDelete.length,\n )\n return deleteFiles(filesToDelete, `without sending (consent: ${consent.status})`)\n }\n }\n\n // Send events and then delete files\n telemetryStoreDebug('Sending %d events to backend', allEvents.length)\n\n return defer(() => from(options.sendEvents(allEvents))).pipe(\n tap(() => {\n telemetryStoreDebug('Successfully sent events, deleting %d files', filesToDelete.length)\n }),\n switchMap(() => deleteFiles(filesToDelete, 'after successful send')),\n )\n }),\n tap(() => {\n telemetryStoreDebug('Standalone flush operation completed successfully')\n }),\n switchMap(() => of(undefined as void)),\n catchError((error) => {\n telemetryStoreDebug('Error during standalone flush operation: %o', error)\n throw error\n }),\n )\n\n return lastValueFrom(flush$)\n}\n"],"names":["rm","catchError","defer","from","lastValueFrom","mergeMap","of","reduce","switchMap","tap","readNDJSON","cleanupOldTelemetryFiles","findTelemetryFiles","telemetryStoreDebug","flushTelemetryFiles","options","deleteFiles","files","reason","length","undefined","pipe","filePath","force","error","flush$","resolveConsent","currentConsent","status","filePaths","allEvents","consent","filesToDelete","events","code","acc","current","push","result","sendEvents"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { join } from 'node:path';
2
+ import { getTelemetryBaseInfo } from './getTelemetryBaseInfo.js';
3
+ import { telemetryStoreDebug } from './telemetryStoreDebug.js';
4
+ /**
5
+ * Generates a unique telemetry file path for a specific CLI session.
6
+ *
7
+ * File format: `telemetry-\{hashedToken\}-\{env\}-\{sessionId\}.ndjson`
8
+ *
9
+ * The sessionId ensures each CLI process writes to its own file, preventing:
10
+ * - File write conflicts when multiple CLI commands run concurrently
11
+ * - Race conditions during file operations
12
+ * - Data corruption from simultaneous writes
13
+ *
14
+ * During flush, all session files are discovered and aggregated together.
15
+ *
16
+ * @param sessionId - Unique identifier for this CLI session
17
+ * @returns Promise resolving to the full file path for this session's telemetry
18
+ * @internal
19
+ */ export async function generateTelemetryFilePath(sessionId) {
20
+ telemetryStoreDebug('Generating telemetry file path for sessionId: %s', sessionId);
21
+ const { basePattern, directory, environment, hashedToken } = await getTelemetryBaseInfo();
22
+ telemetryStoreDebug('Generated token hash: %s', hashedToken);
23
+ telemetryStoreDebug('Detected environment: %s', environment);
24
+ const fileName = `${basePattern}-${sessionId}.ndjson`;
25
+ const filePath = join(directory, fileName);
26
+ telemetryStoreDebug('Telemetry file path: %s', filePath);
27
+ return filePath;
28
+ }
29
+
30
+ //# sourceMappingURL=generateTelemetryFilePath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/telemetry/generateTelemetryFilePath.ts"],"sourcesContent":["import {join} from 'node:path'\n\nimport {getTelemetryBaseInfo} from './getTelemetryBaseInfo.js'\nimport {telemetryStoreDebug} from './telemetryStoreDebug.js'\n\n/**\n * Generates a unique telemetry file path for a specific CLI session.\n *\n * File format: `telemetry-\\{hashedToken\\}-\\{env\\}-\\{sessionId\\}.ndjson`\n *\n * The sessionId ensures each CLI process writes to its own file, preventing:\n * - File write conflicts when multiple CLI commands run concurrently\n * - Race conditions during file operations\n * - Data corruption from simultaneous writes\n *\n * During flush, all session files are discovered and aggregated together.\n *\n * @param sessionId - Unique identifier for this CLI session\n * @returns Promise resolving to the full file path for this session's telemetry\n * @internal\n */\nexport async function generateTelemetryFilePath(sessionId: string): Promise<string> {\n telemetryStoreDebug('Generating telemetry file path for sessionId: %s', sessionId)\n\n const {basePattern, directory, environment, hashedToken} = await getTelemetryBaseInfo()\n\n telemetryStoreDebug('Generated token hash: %s', hashedToken)\n telemetryStoreDebug('Detected environment: %s', environment)\n\n const fileName = `${basePattern}-${sessionId}.ndjson`\n const filePath = join(directory, fileName)\n telemetryStoreDebug('Telemetry file path: %s', filePath)\n\n return filePath\n}\n"],"names":["join","getTelemetryBaseInfo","telemetryStoreDebug","generateTelemetryFilePath","sessionId","basePattern","directory","environment","hashedToken","fileName","filePath"],"mappings":"AAAA,SAAQA,IAAI,QAAO,YAAW;AAE9B,SAAQC,oBAAoB,QAAO,4BAA2B;AAC9D,SAAQC,mBAAmB,QAAO,2BAA0B;AAE5D;;;;;;;;;;;;;;;CAeC,GACD,OAAO,eAAeC,0BAA0BC,SAAiB;IAC/DF,oBAAoB,oDAAoDE;IAExE,MAAM,EAACC,WAAW,EAAEC,SAAS,EAAEC,WAAW,EAAEC,WAAW,EAAC,GAAG,MAAMP;IAEjEC,oBAAoB,4BAA4BM;IAChDN,oBAAoB,4BAA4BK;IAEhD,MAAME,WAAW,GAAGJ,YAAY,CAAC,EAAED,UAAU,OAAO,CAAC;IACrD,MAAMM,WAAWV,KAAKM,WAAWG;IACjCP,oBAAoB,2BAA2BQ;IAE/C,OAAOA;AACT"}
@@ -0,0 +1,33 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { getCliToken } from '../services/getCliToken.js';
5
+ import { isStaging } from '../util/isStaging.js';
6
+ /**
7
+ * Gets the base telemetry information needed for file operations.
8
+ *
9
+ * This shared utility extracts common logic used by:
10
+ * - `generateTelemetryFilePath` - for generating session-specific file paths
11
+ * - `findTelemetryFiles` - for discovering all telemetry files via glob patterns
12
+ *
13
+ * @returns Promise resolving to base telemetry information
14
+ * @throws Error if no auth token is found
15
+ * @internal
16
+ */ export async function getTelemetryBaseInfo() {
17
+ const token = await getCliToken();
18
+ if (!token) {
19
+ throw new Error('No auth token found - user must be logged in for telemetry');
20
+ }
21
+ const hashedToken = createHash('sha256').update(token).digest('hex').slice(0, 8);
22
+ const environment = isStaging() ? 'staging' : 'production';
23
+ const directory = join(tmpdir(), '.config', 'sanity');
24
+ const basePattern = `telemetry-${hashedToken}-${environment}`;
25
+ return {
26
+ basePattern,
27
+ directory,
28
+ environment,
29
+ hashedToken
30
+ };
31
+ }
32
+
33
+ //# sourceMappingURL=getTelemetryBaseInfo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/telemetry/getTelemetryBaseInfo.ts"],"sourcesContent":["import {createHash} from 'node:crypto'\nimport {tmpdir} from 'node:os'\nimport {join} from 'node:path'\n\nimport {getCliToken} from '../services/getCliToken.js'\nimport {isStaging} from '../util/isStaging.js'\n\n/**\n * Base information needed for telemetry file operations.\n * Contains common data used by both file path generation and pattern matching.\n */\ninterface TelemetryBaseInfo {\n /** Base filename pattern without sessionId suffix */\n basePattern: string\n /** Base directory where telemetry files are stored */\n directory: string\n /** Environment: 'staging' or 'production' */\n environment: string\n /** Hashed token (first 8 chars of SHA256) for privacy */\n hashedToken: string\n}\n\n/**\n * Gets the base telemetry information needed for file operations.\n *\n * This shared utility extracts common logic used by:\n * - `generateTelemetryFilePath` - for generating session-specific file paths\n * - `findTelemetryFiles` - for discovering all telemetry files via glob patterns\n *\n * @returns Promise resolving to base telemetry information\n * @throws Error if no auth token is found\n * @internal\n */\nexport async function getTelemetryBaseInfo(): Promise<TelemetryBaseInfo> {\n const token = await getCliToken()\n if (!token) {\n throw new Error('No auth token found - user must be logged in for telemetry')\n }\n\n const hashedToken = createHash('sha256').update(token).digest('hex').slice(0, 8)\n const environment = isStaging() ? 'staging' : 'production'\n const directory = join(tmpdir(), '.config', 'sanity')\n const basePattern = `telemetry-${hashedToken}-${environment}`\n\n return {\n basePattern,\n directory,\n environment,\n hashedToken,\n }\n}\n"],"names":["createHash","tmpdir","join","getCliToken","isStaging","getTelemetryBaseInfo","token","Error","hashedToken","update","digest","slice","environment","directory","basePattern"],"mappings":"AAAA,SAAQA,UAAU,QAAO,cAAa;AACtC,SAAQC,MAAM,QAAO,UAAS;AAC9B,SAAQC,IAAI,QAAO,YAAW;AAE9B,SAAQC,WAAW,QAAO,6BAA4B;AACtD,SAAQC,SAAS,QAAO,uBAAsB;AAiB9C;;;;;;;;;;CAUC,GACD,OAAO,eAAeC;IACpB,MAAMC,QAAQ,MAAMH;IACpB,IAAI,CAACG,OAAO;QACV,MAAM,IAAIC,MAAM;IAClB;IAEA,MAAMC,cAAcR,WAAW,UAAUS,MAAM,CAACH,OAAOI,MAAM,CAAC,OAAOC,KAAK,CAAC,GAAG;IAC9E,MAAMC,cAAcR,cAAc,YAAY;IAC9C,MAAMS,YAAYX,KAAKD,UAAU,WAAW;IAC5C,MAAMa,cAAc,CAAC,UAAU,EAAEN,YAAY,CAAC,EAAEI,aAAa;IAE7D,OAAO;QACLE;QACAD;QACAD;QACAJ;IACF;AACF"}
@@ -0,0 +1,54 @@
1
+ import { telemetryStoreDebug } from './telemetryStoreDebug.js';
2
+ import { createTrace } from './trace.js';
3
+ // Sample rate tracking for log events
4
+ const logSampleTracker = new Map();
5
+ /**
6
+ * Creates a telemetry logger that emits events via the provided emit function
7
+ * @internal
8
+ */ export function createLogger(sessionId, emit) {
9
+ telemetryStoreDebug('Creating logger for session: %s', sessionId);
10
+ const log = (event, data)=>{
11
+ telemetryStoreDebug('Logging event: %s', event.name);
12
+ // Handle sampling if maxSampleRate is specified
13
+ if (event.maxSampleRate && event.maxSampleRate > 0) {
14
+ const now = Date.now();
15
+ const lastEmit = logSampleTracker.get(event.name) || 0;
16
+ if (now - lastEmit < event.maxSampleRate) {
17
+ telemetryStoreDebug('Skipping event %s due to sampling (maxSampleRate: %d)', event.name, event.maxSampleRate);
18
+ return; // Skip due to sampling
19
+ }
20
+ logSampleTracker.set(event.name, now);
21
+ telemetryStoreDebug('Event %s passed sampling check', event.name);
22
+ }
23
+ const logEvent = {
24
+ createdAt: new Date().toISOString(),
25
+ data: data ?? null,
26
+ name: event.name,
27
+ sessionId,
28
+ type: 'log',
29
+ version: event.version
30
+ };
31
+ emit(logEvent);
32
+ };
33
+ const trace = (event, context)=>{
34
+ telemetryStoreDebug('Creating trace: %s', event.name);
35
+ return createTrace(event, context, sessionId, emit, createLogger);
36
+ };
37
+ const updateUserProperties = (properties)=>{
38
+ telemetryStoreDebug('Updating user properties: %o', properties);
39
+ const userPropsEvent = {
40
+ createdAt: new Date().toISOString(),
41
+ properties,
42
+ sessionId,
43
+ type: 'userProperties'
44
+ };
45
+ emit(userPropsEvent);
46
+ };
47
+ return {
48
+ log,
49
+ trace,
50
+ updateUserProperties
51
+ };
52
+ }
53
+
54
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/telemetry/logger.ts"],"sourcesContent":["import {\n type DefinedTelemetryLog,\n type DefinedTelemetryTrace,\n type TelemetryEvent,\n type TelemetryLogger,\n type TelemetryTrace,\n} from '@sanity/telemetry'\n\nimport {telemetryStoreDebug} from './telemetryStoreDebug.js'\nimport {createTrace} from './trace.js'\n\n// Sample rate tracking for log events\nconst logSampleTracker = new Map<string, number>()\n\n/**\n * Creates a telemetry logger that emits events via the provided emit function\n * @internal\n */\nexport function createLogger<UserProperties>(\n sessionId: string,\n emit: (event: TelemetryEvent) => void,\n): TelemetryLogger<UserProperties> {\n telemetryStoreDebug('Creating logger for session: %s', sessionId)\n\n const log = <Data>(event: DefinedTelemetryLog<Data>, data?: Data) => {\n telemetryStoreDebug('Logging event: %s', event.name)\n\n // Handle sampling if maxSampleRate is specified\n if (event.maxSampleRate && event.maxSampleRate > 0) {\n const now = Date.now()\n const lastEmit = logSampleTracker.get(event.name) || 0\n\n if (now - lastEmit < event.maxSampleRate) {\n telemetryStoreDebug(\n 'Skipping event %s due to sampling (maxSampleRate: %d)',\n event.name,\n event.maxSampleRate,\n )\n return // Skip due to sampling\n }\n\n logSampleTracker.set(event.name, now)\n telemetryStoreDebug('Event %s passed sampling check', event.name)\n }\n\n const logEvent: TelemetryEvent = {\n createdAt: new Date().toISOString(),\n data: data ?? null,\n name: event.name,\n sessionId,\n type: 'log',\n version: event.version,\n }\n\n emit(logEvent)\n }\n\n const trace = <Data, Context = unknown>(\n event: DefinedTelemetryTrace<Data, Context>,\n context?: Context,\n ): TelemetryTrace<UserProperties, Data> => {\n telemetryStoreDebug('Creating trace: %s', event.name)\n return createTrace(event, context, sessionId, emit, createLogger)\n }\n\n const updateUserProperties = (properties: UserProperties) => {\n telemetryStoreDebug('Updating user properties: %o', properties)\n const userPropsEvent: TelemetryEvent = {\n createdAt: new Date().toISOString(),\n properties,\n sessionId,\n type: 'userProperties',\n }\n\n emit(userPropsEvent)\n }\n\n return {\n log,\n trace,\n updateUserProperties,\n }\n}\n"],"names":["telemetryStoreDebug","createTrace","logSampleTracker","Map","createLogger","sessionId","emit","log","event","data","name","maxSampleRate","now","Date","lastEmit","get","set","logEvent","createdAt","toISOString","type","version","trace","context","updateUserProperties","properties","userPropsEvent"],"mappings":"AAQA,SAAQA,mBAAmB,QAAO,2BAA0B;AAC5D,SAAQC,WAAW,QAAO,aAAY;AAEtC,sCAAsC;AACtC,MAAMC,mBAAmB,IAAIC;AAE7B;;;CAGC,GACD,OAAO,SAASC,aACdC,SAAiB,EACjBC,IAAqC;IAErCN,oBAAoB,mCAAmCK;IAEvD,MAAME,MAAM,CAAOC,OAAkCC;QACnDT,oBAAoB,qBAAqBQ,MAAME,IAAI;QAEnD,gDAAgD;QAChD,IAAIF,MAAMG,aAAa,IAAIH,MAAMG,aAAa,GAAG,GAAG;YAClD,MAAMC,MAAMC,KAAKD,GAAG;YACpB,MAAME,WAAWZ,iBAAiBa,GAAG,CAACP,MAAME,IAAI,KAAK;YAErD,IAAIE,MAAME,WAAWN,MAAMG,aAAa,EAAE;gBACxCX,oBACE,yDACAQ,MAAME,IAAI,EACVF,MAAMG,aAAa;gBAErB,QAAO,uBAAuB;YAChC;YAEAT,iBAAiBc,GAAG,CAACR,MAAME,IAAI,EAAEE;YACjCZ,oBAAoB,kCAAkCQ,MAAME,IAAI;QAClE;QAEA,MAAMO,WAA2B;YAC/BC,WAAW,IAAIL,OAAOM,WAAW;YACjCV,MAAMA,QAAQ;YACdC,MAAMF,MAAME,IAAI;YAChBL;YACAe,MAAM;YACNC,SAASb,MAAMa,OAAO;QACxB;QAEAf,KAAKW;IACP;IAEA,MAAMK,QAAQ,CACZd,OACAe;QAEAvB,oBAAoB,sBAAsBQ,MAAME,IAAI;QACpD,OAAOT,YAAYO,OAAOe,SAASlB,WAAWC,MAAMF;IACtD;IAEA,MAAMoB,uBAAuB,CAACC;QAC5BzB,oBAAoB,gCAAgCyB;QACpD,MAAMC,iBAAiC;YACrCR,WAAW,IAAIL,OAAOM,WAAW;YACjCM;YACApB;YACAe,MAAM;QACR;QAEAd,KAAKoB;IACP;IAEA,OAAO;QACLnB;QACAe;QACAE;IACF;AACF"}
@@ -0,0 +1,7 @@
1
+ import { subdebug } from '../debug.js';
2
+ /**
3
+ * Debug logger for telemetry store operations
4
+ * @internal
5
+ */ export const telemetryStoreDebug = subdebug('telemetry:telemetryStore');
6
+
7
+ //# sourceMappingURL=telemetryStoreDebug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/telemetry/telemetryStoreDebug.ts"],"sourcesContent":["import {subdebug} from '../debug.js'\n\n/**\n * Debug logger for telemetry store operations\n * @internal\n */\nexport const telemetryStoreDebug = subdebug('telemetry:telemetryStore')\n"],"names":["subdebug","telemetryStoreDebug"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,cAAa;AAEpC;;;CAGC,GACD,OAAO,MAAMC,sBAAsBD,SAAS,4BAA2B"}
@@ -0,0 +1,150 @@
1
+ import { createTraceId } from './createTraceId.js';
2
+ import { telemetryStoreDebug } from './telemetryStoreDebug.js';
3
+ /**
4
+ * Creates a trace instance that can emit trace lifecycle events
5
+ * @internal
6
+ */ export function createTrace(definition, context, sessionId, emit, createLoggerFn) {
7
+ const traceId = createTraceId();
8
+ telemetryStoreDebug('Creating trace %s with traceId: %s', definition.name, traceId);
9
+ let isStarted = false;
10
+ let isCompleted = false;
11
+ const emitTraceEvent = (type, data)=>{
12
+ if (isCompleted && type !== 'trace.start') return;
13
+ const baseEvent = {
14
+ context: context,
15
+ createdAt: new Date().toISOString(),
16
+ name: definition.name,
17
+ sessionId,
18
+ traceId,
19
+ version: definition.version
20
+ };
21
+ let traceEvent;
22
+ switch(type){
23
+ case 'trace.complete':
24
+ {
25
+ traceEvent = {
26
+ ...baseEvent,
27
+ type: 'trace.complete',
28
+ ...data && {
29
+ data
30
+ }
31
+ };
32
+ break;
33
+ }
34
+ case 'trace.error':
35
+ {
36
+ traceEvent = {
37
+ ...baseEvent,
38
+ data,
39
+ type: 'trace.error'
40
+ };
41
+ break;
42
+ }
43
+ case 'trace.log':
44
+ {
45
+ traceEvent = {
46
+ ...baseEvent,
47
+ data,
48
+ type: 'trace.log'
49
+ };
50
+ break;
51
+ }
52
+ case 'trace.start':
53
+ {
54
+ traceEvent = {
55
+ ...baseEvent,
56
+ type: 'trace.start'
57
+ };
58
+ break;
59
+ }
60
+ default:
61
+ {
62
+ return; // Unknown type
63
+ }
64
+ }
65
+ emit(traceEvent);
66
+ };
67
+ const start = ()=>{
68
+ if (isStarted) {
69
+ telemetryStoreDebug('Trace %s already started', traceId);
70
+ return;
71
+ }
72
+ telemetryStoreDebug('Starting trace %s', traceId);
73
+ isStarted = true;
74
+ emitTraceEvent('trace.start');
75
+ };
76
+ const log = (data)=>{
77
+ telemetryStoreDebug('Logging data for trace %s', traceId);
78
+ if (!isStarted) start();
79
+ emitTraceEvent('trace.log', data);
80
+ };
81
+ const complete = ()=>{
82
+ if (isCompleted) {
83
+ telemetryStoreDebug('Trace %s already completed', traceId);
84
+ return;
85
+ }
86
+ telemetryStoreDebug('Completing trace %s', traceId);
87
+ if (!isStarted) start();
88
+ emitTraceEvent('trace.complete');
89
+ isCompleted = true;
90
+ };
91
+ const error = (err)=>{
92
+ if (isCompleted) {
93
+ telemetryStoreDebug('Trace %s already completed, ignoring error', traceId);
94
+ return;
95
+ }
96
+ telemetryStoreDebug('Error in trace %s: %s', traceId, err.message);
97
+ if (!isStarted) start();
98
+ // Convert Error to serializable object
99
+ const errorData = {
100
+ message: err.message,
101
+ name: err.name,
102
+ stack: err.stack
103
+ };
104
+ emitTraceEvent('trace.error', errorData);
105
+ isCompleted = true;
106
+ };
107
+ const awaitPromise = (promise, finalData)=>{
108
+ if (!isStarted) start();
109
+ return promise.then((result)=>{
110
+ if (finalData !== undefined) {
111
+ log(finalData);
112
+ }
113
+ complete();
114
+ return result;
115
+ }).catch((err)=>{
116
+ error(err);
117
+ throw err;
118
+ });
119
+ };
120
+ const newContext = (name)=>{
121
+ const contextEmit = (event)=>{
122
+ // For trace events, we can add context, but for log events we need to be careful
123
+ if (event.type.startsWith('trace.')) {
124
+ const existingContext = event.context;
125
+ emit({
126
+ ...event,
127
+ context: {
128
+ ...typeof existingContext === 'object' && existingContext ? existingContext : {},
129
+ contextName: name
130
+ }
131
+ });
132
+ } else {
133
+ // For log events, we can't add context as it's not part of TelemetryLogEvent
134
+ // Just emit as-is
135
+ emit(event);
136
+ }
137
+ };
138
+ return createLoggerFn(sessionId, contextEmit);
139
+ };
140
+ return {
141
+ await: awaitPromise,
142
+ complete,
143
+ error,
144
+ log,
145
+ newContext,
146
+ start
147
+ };
148
+ }
149
+
150
+ //# sourceMappingURL=trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/telemetry/trace.ts"],"sourcesContent":["import {\n type DefinedTelemetryTrace,\n type TelemetryEvent,\n type TelemetryLogger,\n type TelemetryTrace,\n} from '@sanity/telemetry'\n\nimport {createTraceId} from './createTraceId.js'\nimport {telemetryStoreDebug} from './telemetryStoreDebug.js'\n\n/**\n * Creates a trace instance that can emit trace lifecycle events\n * @internal\n */\nexport function createTrace<Data, Context = unknown, UserProperties = unknown>(\n definition: DefinedTelemetryTrace<Data, Context>,\n context: Context | undefined,\n sessionId: string,\n emit: (event: TelemetryEvent) => void,\n createLoggerFn: <UserProperties>(\n sessionId: string,\n emit: (event: TelemetryEvent) => void,\n ) => TelemetryLogger<UserProperties>,\n): TelemetryTrace<UserProperties, Data> {\n const traceId = createTraceId()\n telemetryStoreDebug('Creating trace %s with traceId: %s', definition.name, traceId)\n\n let isStarted = false\n let isCompleted = false\n\n const emitTraceEvent = (type: string, data?: Data | Error) => {\n if (isCompleted && type !== 'trace.start') return\n\n const baseEvent = {\n context: context as Context,\n createdAt: new Date().toISOString(),\n name: definition.name,\n sessionId,\n traceId,\n version: definition.version,\n }\n\n let traceEvent: TelemetryEvent\n\n switch (type) {\n case 'trace.complete': {\n traceEvent = {\n ...baseEvent,\n type: 'trace.complete',\n ...(data && {data}),\n } as TelemetryEvent\n\n break\n }\n case 'trace.error': {\n traceEvent = {\n ...baseEvent,\n data,\n type: 'trace.error',\n } as TelemetryEvent\n\n break\n }\n case 'trace.log': {\n traceEvent = {\n ...baseEvent,\n data,\n type: 'trace.log',\n } as TelemetryEvent\n\n break\n }\n case 'trace.start': {\n traceEvent = {\n ...baseEvent,\n type: 'trace.start',\n } as TelemetryEvent\n\n break\n }\n default: {\n return // Unknown type\n }\n }\n\n emit(traceEvent)\n }\n\n const start = () => {\n if (isStarted) {\n telemetryStoreDebug('Trace %s already started', traceId)\n return\n }\n telemetryStoreDebug('Starting trace %s', traceId)\n isStarted = true\n emitTraceEvent('trace.start')\n }\n\n const log = (data: Data) => {\n telemetryStoreDebug('Logging data for trace %s', traceId)\n if (!isStarted) start()\n emitTraceEvent('trace.log', data)\n }\n\n const complete = () => {\n if (isCompleted) {\n telemetryStoreDebug('Trace %s already completed', traceId)\n return\n }\n telemetryStoreDebug('Completing trace %s', traceId)\n if (!isStarted) start()\n emitTraceEvent('trace.complete')\n isCompleted = true\n }\n\n const error = (err: Error) => {\n if (isCompleted) {\n telemetryStoreDebug('Trace %s already completed, ignoring error', traceId)\n return\n }\n telemetryStoreDebug('Error in trace %s: %s', traceId, err.message)\n if (!isStarted) start()\n // Convert Error to serializable object\n const errorData = {\n message: err.message,\n name: err.name,\n stack: err.stack,\n }\n emitTraceEvent('trace.error', errorData)\n isCompleted = true\n }\n\n const awaitPromise = <P extends Promise<unknown>>(promise: P, finalData?: Data): P => {\n if (!isStarted) start()\n\n return promise\n .then((result) => {\n if (finalData !== undefined) {\n log(finalData)\n }\n complete()\n return result\n })\n .catch((err) => {\n error(err)\n throw err\n }) as P\n }\n\n const newContext = (name: string): TelemetryLogger<UserProperties> => {\n const contextEmit = (event: TelemetryEvent) => {\n // For trace events, we can add context, but for log events we need to be careful\n if (event.type.startsWith('trace.')) {\n const existingContext = (event as {context?: unknown}).context\n emit({\n ...event,\n context: {\n ...(typeof existingContext === 'object' && existingContext ? existingContext : {}),\n contextName: name,\n },\n } as TelemetryEvent)\n } else {\n // For log events, we can't add context as it's not part of TelemetryLogEvent\n // Just emit as-is\n emit(event)\n }\n }\n\n return createLoggerFn<UserProperties>(sessionId, contextEmit)\n }\n\n return {\n await: awaitPromise,\n complete,\n error,\n log,\n newContext,\n start,\n }\n}\n"],"names":["createTraceId","telemetryStoreDebug","createTrace","definition","context","sessionId","emit","createLoggerFn","traceId","name","isStarted","isCompleted","emitTraceEvent","type","data","baseEvent","createdAt","Date","toISOString","version","traceEvent","start","log","complete","error","err","message","errorData","stack","awaitPromise","promise","finalData","then","result","undefined","catch","newContext","contextEmit","event","startsWith","existingContext","contextName","await"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @public
3
+ */ export { };
4
+
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/telemetry/types.ts"],"sourcesContent":["import {type ConsentStatus, type TelemetryLogger} from '@sanity/telemetry'\n\nexport type ConsentInformation =\n | {\n reason: 'fetchError' | 'unauthenticated'\n status: Extract<ConsentStatus, 'undetermined'>\n }\n | {\n reason?: 'localOverride'\n status: Extract<ConsentStatus, 'denied'>\n }\n | {\n reason?: never\n status: Extract<ConsentStatus, 'granted'>\n }\n | {\n reason?: never\n status: Extract<ConsentStatus, 'unset'>\n }\n\n/**\n * @public\n */\nexport interface TelemetryUserProperties {\n cliVersion: string\n cpuArchitecture: string\n machinePlatform: string\n runtime: string\n runtimeVersion: string\n\n dataset?: string\n projectId?: string\n}\n\n/**\n * @public\n */\nexport type CLITelemetryStore = TelemetryLogger<TelemetryUserProperties>\n"],"names":[],"mappings":"AAkCA;;CAEC,GACD,WAAwE"}
package/dist/types.js CHANGED
@@ -1,3 +1,5 @@
1
+ // @todo
2
+ // Replace with SanityUser type from client once implemented
1
3
  export { };
2
4
 
3
5
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import {type Command} from '@oclif/core'\n\nexport interface Output {\n error: Command['error']\n log: Command['log']\n warn: Command['warn']\n}\n\nexport type RequireProps<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>\n"],"names":[],"mappings":"AAQA,WAAkF"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import {type Command} from '@oclif/core'\n\nexport interface Output {\n error: Command['error']\n log: Command['log']\n warn: Command['warn']\n}\n\nexport type RequireProps<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>\n\n// @todo\n// Replace with SanityUser type from client once implemented\nexport type SanityOrgUser = {\n email: string\n id: string\n name: string\n profileImage?: string\n provider: 'github' | 'google' | 'sanity' | `saml-${string}`\n tosAcceptedAt?: string\n}\n"],"names":[],"mappings":"AAUA,QAAQ;AACR,4DAA4D;AAC5D,WAOC"}
@@ -0,0 +1,16 @@
1
+ // Only file that should be using dynamic import
2
+ import { pathToFileURL } from 'node:url';
3
+ /**
4
+ * This function is a replacement for built in dynamic import
5
+ * This handles the case for windows file paths especially for absolute paths.
6
+ *
7
+ * @param source - File path
8
+ */ export function doImport(source) {
9
+ // Absolute paths in windows are not valid URLs and are not supported by import().
10
+ // We need to convert the path to a file URL.
11
+ // See: https://github.com/nodejs/node/issues/31710
12
+ // eslint-disable-next-line no-restricted-syntax
13
+ return import(/^file:\/\//.test(source) ? source : pathToFileURL(source).href);
14
+ }
15
+
16
+ //# sourceMappingURL=doImport.js.map
@@ -0,0 +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,6 +1,7 @@
1
1
  import { resolve } from 'node:path';
2
2
  import { pathToFileURL } from 'node:url';
3
3
  import { moduleResolve } from 'import-meta-resolve';
4
+ import { doImport } from '../doImport.js';
4
5
  /**
5
6
  * Loads the `getStudioEnvironmentVariables` function from the studio's
6
7
  * installed `sanity` package and returns the environment variables.
@@ -19,7 +20,7 @@ import { moduleResolve } from 'import-meta-resolve';
19
20
  // running, in order to ensure we're using the same version as the studio would.
20
21
  const sanityCliUrl = moduleResolve('sanity/cli', fakeConfigUrl);
21
22
  try {
22
- const { getStudioEnvironmentVariables: getEnvVars } = await import(sanityCliUrl.href);
23
+ const { getStudioEnvironmentVariables: getEnvVars } = await doImport(sanityCliUrl.href);
23
24
  if (typeof getEnvVars !== 'function') {
24
25
  throw new TypeError('Expected `getStudioEnvironmentVariables` from `sanity/cli` to be a function');
25
26
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/util/environment/getStudioEnvironmentVariables.ts"],"sourcesContent":["import {resolve} from 'node:path'\nimport {pathToFileURL} from 'node:url'\n\nimport {moduleResolve} from 'import-meta-resolve'\n\n/**\n * Loads the `getStudioEnvironmentVariables` function from the studio's\n * installed `sanity` package and returns the environment variables.\n *\n * This is used to ensure we're using the same version of environment variable\n * logic as the studio itself.\n *\n * @param rootPath - The root path of the Sanity Studio project\n * @returns Object containing studio environment variables\n * @internal\n */\nexport async function getStudioEnvironmentVariables(\n rootPath: string,\n): Promise<Record<string, string>> {\n // Create a fake config URL - doesn't have to be correct, just need the root path\n const fakeConfigUrl = pathToFileURL(resolve(rootPath, 'sanity.config.mjs'))\n\n // Load `getStudioEnvironmentVariables` from the `sanity/cli` module installed\n // relative to where the studio is located, instead of resolving from where this CLI is\n // running, in order to ensure we're using the same version as the studio would.\n const sanityCliUrl = moduleResolve('sanity/cli', fakeConfigUrl)\n try {\n const {getStudioEnvironmentVariables: getEnvVars} = await import(sanityCliUrl.href)\n if (typeof getEnvVars !== 'function') {\n throw new TypeError(\n 'Expected `getStudioEnvironmentVariables` from `sanity/cli` to be a function',\n )\n }\n return getEnvVars(rootPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(\n `Failed to import getStudioEnvironmentVariables from sanity/cli module: ${message}`,\n )\n }\n}\n"],"names":["resolve","pathToFileURL","moduleResolve","getStudioEnvironmentVariables","rootPath","fakeConfigUrl","sanityCliUrl","getEnvVars","href","TypeError","err","message","Error","String"],"mappings":"AAAA,SAAQA,OAAO,QAAO,YAAW;AACjC,SAAQC,aAAa,QAAO,WAAU;AAEtC,SAAQC,aAAa,QAAO,sBAAqB;AAEjD;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,8BACpBC,QAAgB;IAEhB,iFAAiF;IACjF,MAAMC,gBAAgBJ,cAAcD,QAAQI,UAAU;IAEtD,8EAA8E;IAC9E,uFAAuF;IACvF,gFAAgF;IAChF,MAAME,eAAeJ,cAAc,cAAcG;IACjD,IAAI;QACF,MAAM,EAACF,+BAA+BI,UAAU,EAAC,GAAG,MAAM,MAAM,CAACD,aAAaE,IAAI;QAClF,IAAI,OAAOD,eAAe,YAAY;YACpC,MAAM,IAAIE,UACR;QAEJ;QACA,OAAOF,WAAWH;IACpB,EAAE,OAAOM,KAAK;QACZ,MAAMC,UAAUD,eAAeE,QAAQF,IAAIC,OAAO,GAAGE,OAAOH;QAC5D,MAAM,IAAIE,MACR,CAAC,uEAAuE,EAAED,SAAS;IAEvF;AACF"}
1
+ {"version":3,"sources":["../../../src/util/environment/getStudioEnvironmentVariables.ts"],"sourcesContent":["import {resolve} from 'node:path'\nimport {pathToFileURL} from 'node:url'\n\nimport {moduleResolve} from 'import-meta-resolve'\n\nimport {doImport} from '../doImport.js'\n\n/**\n * Loads the `getStudioEnvironmentVariables` function from the studio's\n * installed `sanity` package and returns the environment variables.\n *\n * This is used to ensure we're using the same version of environment variable\n * logic as the studio itself.\n *\n * @param rootPath - The root path of the Sanity Studio project\n * @returns Object containing studio environment variables\n * @internal\n */\nexport async function getStudioEnvironmentVariables(\n rootPath: string,\n): Promise<Record<string, string>> {\n // Create a fake config URL - doesn't have to be correct, just need the root path\n const fakeConfigUrl = pathToFileURL(resolve(rootPath, 'sanity.config.mjs'))\n\n // Load `getStudioEnvironmentVariables` from the `sanity/cli` module installed\n // relative to where the studio is located, instead of resolving from where this CLI is\n // running, in order to ensure we're using the same version as the studio would.\n const sanityCliUrl = moduleResolve('sanity/cli', fakeConfigUrl)\n try {\n const {getStudioEnvironmentVariables: getEnvVars} = await doImport(sanityCliUrl.href)\n if (typeof getEnvVars !== 'function') {\n throw new TypeError(\n 'Expected `getStudioEnvironmentVariables` from `sanity/cli` to be a function',\n )\n }\n return getEnvVars(rootPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(\n `Failed to import getStudioEnvironmentVariables from sanity/cli module: ${message}`,\n )\n }\n}\n"],"names":["resolve","pathToFileURL","moduleResolve","doImport","getStudioEnvironmentVariables","rootPath","fakeConfigUrl","sanityCliUrl","getEnvVars","href","TypeError","err","message","Error","String"],"mappings":"AAAA,SAAQA,OAAO,QAAO,YAAW;AACjC,SAAQC,aAAa,QAAO,WAAU;AAEtC,SAAQC,aAAa,QAAO,sBAAqB;AAEjD,SAAQC,QAAQ,QAAO,iBAAgB;AAEvC;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,8BACpBC,QAAgB;IAEhB,iFAAiF;IACjF,MAAMC,gBAAgBL,cAAcD,QAAQK,UAAU;IAEtD,8EAA8E;IAC9E,uFAAuF;IACvF,gFAAgF;IAChF,MAAME,eAAeL,cAAc,cAAcI;IACjD,IAAI;QACF,MAAM,EAACF,+BAA+BI,UAAU,EAAC,GAAG,MAAML,SAASI,aAAaE,IAAI;QACpF,IAAI,OAAOD,eAAe,YAAY;YACpC,MAAM,IAAIE,UACR;QAEJ;QACA,OAAOF,WAAWH;IACpB,EAAE,OAAOM,KAAK;QACZ,MAAMC,UAAUD,eAAeE,QAAQF,IAAIC,OAAO,GAAGE,OAAOH;QAC5D,MAAM,IAAIE,MACR,CAAC,uEAAuE,EAAED,SAAS;IAEvF;AACF"}
@@ -0,0 +1,36 @@
1
+ import { CLIError } from '@oclif/core/errors';
2
+ import { isTrueish } from './isTrueish.js';
3
+ /**
4
+ * @public
5
+ * Symbol used to store the CLI telemetry store on globalThis.
6
+ * Use `getCliTelemetry()` to access the store instead of accessing this directly.
7
+ */ export const CLI_TELEMETRY_SYMBOL = Symbol.for('sanity.cli.telemetry');
8
+ /**
9
+ * @public
10
+ */ export function getCliTelemetry() {
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
+ });
18
+ }
19
+ return global[CLI_TELEMETRY_SYMBOL];
20
+ }
21
+ /**
22
+ * Sets the global CLI telemetry store.
23
+ * @internal
24
+ */ export function setCliTelemetry(telemetry) {
25
+ const global = globalThis;
26
+ global[CLI_TELEMETRY_SYMBOL] = telemetry;
27
+ }
28
+ /**
29
+ * Clears the global CLI telemetry store.
30
+ * @internal
31
+ */ export function clearCliTelemetry() {
32
+ const global = globalThis;
33
+ delete global[CLI_TELEMETRY_SYMBOL];
34
+ }
35
+
36
+ //# sourceMappingURL=getCliTelemetry.js.map
@@ -0,0 +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"}