@sanity/sdk 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@ import {pick} from 'lodash-es'
2
2
 
3
3
  import {type SanityConfig} from '../config/sanityConfig'
4
4
  import {insecureRandomId} from '../utils/ids'
5
+ import {createLogger, type InstanceContext} from '../utils/logger'
5
6
 
6
7
  /**
7
8
  * Represents a Sanity.io resource instance with its own configuration and lifecycle
@@ -76,15 +77,51 @@ export function createSanityInstance(config: SanityConfig = {}): SanityInstance
76
77
  const disposeListeners = new Map<string, () => void>()
77
78
  const disposed = {current: false}
78
79
 
80
+ // Create instance context for logging
81
+ const instanceContext: InstanceContext = {
82
+ instanceId,
83
+ projectId: config.projectId,
84
+ dataset: config.dataset,
85
+ }
86
+
87
+ // Create logger with instance context
88
+ const logger = createLogger('sdk', {instanceContext})
89
+
90
+ // Log instance creation
91
+ logger.info('Sanity instance created', {
92
+ hasProjectId: !!config.projectId,
93
+ hasDataset: !!config.dataset,
94
+ hasAuth: !!config.auth,
95
+ hasPerspective: !!config.perspective,
96
+ })
97
+
98
+ // Log configuration details at debug level
99
+ logger.debug('Instance configuration', {
100
+ projectId: config.projectId,
101
+ dataset: config.dataset,
102
+ perspective: config.perspective,
103
+ studioMode: config.studioMode?.enabled,
104
+ hasAuthProviders: !!config.auth?.providers,
105
+ hasAuthToken: !!config.auth?.token,
106
+ })
107
+
79
108
  const instance: SanityInstance = {
80
109
  instanceId,
81
110
  config,
82
111
  isDisposed: () => disposed.current,
83
112
  dispose: () => {
84
- if (disposed.current) return
113
+ if (disposed.current) {
114
+ logger.trace('Dispose called on already disposed instance', {internal: true})
115
+ return
116
+ }
117
+ logger.trace('Disposing instance', {
118
+ internal: true,
119
+ listenerCount: disposeListeners.size,
120
+ })
85
121
  disposed.current = true
86
122
  disposeListeners.forEach((listener) => listener())
87
123
  disposeListeners.clear()
124
+ logger.info('Instance disposed')
88
125
  },
89
126
  onDispose: (cb) => {
90
127
  const listenerId = insecureRandomId()
@@ -94,8 +131,14 @@ export function createSanityInstance(config: SanityConfig = {}): SanityInstance
94
131
  }
95
132
  },
96
133
  getParent: () => undefined,
97
- createChild: (next) =>
98
- Object.assign(
134
+ createChild: (next) => {
135
+ logger.debug('Creating child instance', {
136
+ parentInstanceId: instanceId.slice(0, 8),
137
+ overridingProjectId: !!next.projectId,
138
+ overridingDataset: !!next.dataset,
139
+ overridingAuth: !!next.auth,
140
+ })
141
+ const child = Object.assign(
99
142
  createSanityInstance({
100
143
  ...config,
101
144
  ...next,
@@ -104,7 +147,13 @@ export function createSanityInstance(config: SanityConfig = {}): SanityInstance
104
147
  : config.auth && next.auth && {auth: {...config.auth, ...next.auth}}),
105
148
  }),
106
149
  {getParent: () => instance},
107
- ),
150
+ )
151
+ logger.trace('Child instance created', {
152
+ internal: true,
153
+ childInstanceId: child.instanceId.slice(0, 8),
154
+ })
155
+ return child
156
+ },
108
157
  match: (targetConfig) => {
109
158
  if (
110
159
  Object.entries(pick(targetConfig, 'auth', 'projectId', 'dataset')).every(
@@ -0,0 +1,141 @@
1
+ # Logger Usage Examples
2
+
3
+ This document shows how to use the logging infrastructure in different scenarios.
4
+
5
+ ## For SDK Users
6
+
7
+ ### Basic Setup
8
+
9
+ ```typescript
10
+ import {configureLogging, createSanityInstance} from '@sanity/sdk'
11
+
12
+ // Enable logging in development
13
+ if (process.env.NODE_ENV === 'development') {
14
+ configureLogging({
15
+ level: 'info',
16
+ namespaces: ['auth', 'document', 'query'],
17
+ })
18
+ }
19
+
20
+ const instance = createSanityInstance({
21
+ projectId: 'my-project',
22
+ dataset: 'production',
23
+ })
24
+ ```
25
+
26
+ ### Expected Output
27
+
28
+ ```
29
+ [2024-12-01T22:15:29.000Z] [INFO] [sdk] Logging configured
30
+ level: "info"
31
+ namespaces: ["auth", "document", "query"]
32
+ [2024-12-01T22:15:30.123Z] [INFO] [auth] Checking URL for auth code
33
+ [2024-12-01T22:15:30.456Z] [INFO] [auth] [project:my-project] [dataset:production] User logged in
34
+ userId: "user-123"
35
+ [2024-12-01T22:15:31.789Z] [INFO] [document] [project:my-project] [dataset:production] Document synced
36
+ documentId: "draft.post-1"
37
+ ```
38
+
39
+ ## For SDK Maintainers
40
+
41
+ ### Using Logger in Stores
42
+
43
+ ```typescript
44
+ // In authStore.ts
45
+ import {createLogger, getInstanceContext} from '../utils/logger'
46
+ import {defineStore} from '../store/defineStore'
47
+
48
+ export const authStore = defineStore<AuthStoreState>({
49
+ name: 'Auth',
50
+
51
+ initialize(context) {
52
+ const {instance} = context
53
+
54
+ // Create logger with instance context
55
+ const logger = createLogger('auth', {
56
+ instanceContext: getInstanceContext(instance),
57
+ })
58
+
59
+ // Logs will automatically include [project:x] [dataset:y]
60
+ logger.info('Auth store initialized')
61
+
62
+ // With additional context
63
+ logger.debug('Fetching current user', {
64
+ method: 'cookie',
65
+ projectId: instance.config.projectId,
66
+ })
67
+ },
68
+ })
69
+ ```
70
+
71
+ ### Using Logger in Static Utils
72
+
73
+ ```typescript
74
+ // In utils/ids.ts (no instance context)
75
+ import {createLogger} from './logger'
76
+
77
+ const logger = createLogger('sdk')
78
+
79
+ export function getDraftId(id: string): string {
80
+ logger.trace('Converting to draft ID', {inputId: id})
81
+ return `drafts.${id}`
82
+ }
83
+ ```
84
+
85
+ ### Performance Timing
86
+
87
+ ```typescript
88
+ import {createTimer} from '../utils/logger'
89
+
90
+ async function fetchDocument(id: string) {
91
+ const timer = createTimer('document', 'fetchDocument')
92
+
93
+ try {
94
+ const doc = await client.fetch(query, {id})
95
+ timer.end('Document fetched successfully', {documentId: id})
96
+ return doc
97
+ } catch (error) {
98
+ timer.end('Document fetch failed', {documentId: id, error})
99
+ throw error
100
+ }
101
+ }
102
+ ```
103
+
104
+ ## Multi-Instance Debugging
105
+
106
+ When working with multiple instances, logs automatically show which instance they came from:
107
+
108
+ ```typescript
109
+ const prodInstance = createSanityInstance({
110
+ projectId: 'my-project',
111
+ dataset: 'production',
112
+ })
113
+
114
+ const stagingInstance = createSanityInstance({
115
+ projectId: 'my-project',
116
+ dataset: 'staging',
117
+ })
118
+
119
+ // Logs will clearly show which instance:
120
+ // [INFO] [query] [project:my-project] [dataset:production] Query executed
121
+ // [INFO] [query] [project:my-project] [dataset:staging] Query executed
122
+ ```
123
+
124
+ ## Environment-Based Configuration
125
+
126
+ ```typescript
127
+ // Configure based on environment
128
+ const logLevel = process.env.SANITY_LOG_LEVEL || 'warn'
129
+ const logNamespaces = process.env.SANITY_LOG_NAMESPACES?.split(',') || []
130
+
131
+ configureLogging({
132
+ level: logLevel as LogLevel,
133
+ namespaces: logNamespaces,
134
+ })
135
+ ```
136
+
137
+ Then run your app with:
138
+
139
+ ```bash
140
+ SANITY_LOG_LEVEL=debug SANITY_LOG_NAMESPACES=auth,document npm start
141
+ ```