@dotdo/postgres 0.1.1 → 0.1.3

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 (111) hide show
  1. package/README.md +73 -1
  2. package/dist/client/index.d.ts +47 -0
  3. package/dist/client/index.d.ts.map +1 -0
  4. package/dist/client/index.js +47 -0
  5. package/dist/client/index.js.map +1 -0
  6. package/dist/client/postgres-client.d.ts +273 -0
  7. package/dist/client/postgres-client.d.ts.map +1 -0
  8. package/dist/client/postgres-client.js +389 -0
  9. package/dist/client/postgres-client.js.map +1 -0
  10. package/dist/client/types.d.ts +167 -0
  11. package/dist/client/types.d.ts.map +1 -0
  12. package/dist/client/types.js +7 -0
  13. package/dist/client/types.js.map +1 -0
  14. package/dist/do/index.d.ts +18 -0
  15. package/dist/do/index.d.ts.map +1 -0
  16. package/dist/do/index.js +18 -0
  17. package/dist/do/index.js.map +1 -0
  18. package/dist/do/postgres.d.ts +110 -0
  19. package/dist/do/postgres.d.ts.map +1 -0
  20. package/dist/do/postgres.js +266 -0
  21. package/dist/do/postgres.js.map +1 -0
  22. package/dist/do/sql.d.ts +92 -0
  23. package/dist/do/sql.d.ts.map +1 -0
  24. package/dist/do/sql.js +204 -0
  25. package/dist/do/sql.js.map +1 -0
  26. package/dist/index.d.ts +25 -30
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +29 -30
  29. package/dist/index.js.map +1 -1
  30. package/dist/mcp/binding.d.ts +47 -0
  31. package/dist/mcp/binding.d.ts.map +1 -0
  32. package/dist/mcp/binding.js +183 -0
  33. package/dist/mcp/binding.js.map +1 -0
  34. package/dist/mcp/index.d.ts +92 -0
  35. package/dist/mcp/index.d.ts.map +1 -0
  36. package/dist/mcp/index.js +91 -0
  37. package/dist/mcp/index.js.map +1 -0
  38. package/dist/mcp/server.d.ts +62 -0
  39. package/dist/mcp/server.d.ts.map +1 -0
  40. package/dist/mcp/server.js +278 -0
  41. package/dist/mcp/server.js.map +1 -0
  42. package/dist/mcp/tools.d.ts +58 -0
  43. package/dist/mcp/tools.d.ts.map +1 -0
  44. package/dist/mcp/tools.js +356 -0
  45. package/dist/mcp/tools.js.map +1 -0
  46. package/dist/mcp/types.d.ts +139 -0
  47. package/dist/mcp/types.d.ts.map +1 -0
  48. package/dist/mcp/types.js +7 -0
  49. package/dist/mcp/types.js.map +1 -0
  50. package/dist/pglite/workers-pglite.d.ts +13 -4
  51. package/dist/pglite/workers-pglite.d.ts.map +1 -1
  52. package/dist/pglite/workers-pglite.js +110 -5
  53. package/dist/pglite/workers-pglite.js.map +1 -1
  54. package/dist/pglite-assets/pglite.data +0 -0
  55. package/dist/pglite-assets/pglite.wasm +0 -0
  56. package/dist/worker/auth.d.ts.map +1 -1
  57. package/dist/worker/auth.js +16 -6
  58. package/dist/worker/auth.js.map +1 -1
  59. package/dist/worker/background-pglite-manager.d.ts +243 -0
  60. package/dist/worker/background-pglite-manager.d.ts.map +1 -0
  61. package/dist/worker/background-pglite-manager.js +528 -0
  62. package/dist/worker/background-pglite-manager.js.map +1 -0
  63. package/dist/worker/do-pglite-manager.d.ts +77 -0
  64. package/dist/worker/do-pglite-manager.d.ts.map +1 -1
  65. package/dist/worker/do-pglite-manager.js +189 -12
  66. package/dist/worker/do-pglite-manager.js.map +1 -1
  67. package/dist/worker/entry.d.ts.map +1 -1
  68. package/dist/worker/entry.js +108 -26
  69. package/dist/worker/entry.js.map +1 -1
  70. package/dist/worker/index.d.ts +7 -1
  71. package/dist/worker/index.d.ts.map +1 -1
  72. package/dist/worker/index.js +19 -1
  73. package/dist/worker/index.js.map +1 -1
  74. package/dist/worker/lazy-pglite-manager.d.ts +242 -0
  75. package/dist/worker/lazy-pglite-manager.d.ts.map +1 -0
  76. package/dist/worker/lazy-pglite-manager.js +463 -0
  77. package/dist/worker/lazy-pglite-manager.js.map +1 -0
  78. package/package.json +20 -6
  79. package/src/client/index.ts +61 -0
  80. package/src/client/postgres-client.ts +442 -0
  81. package/src/client/types.ts +211 -0
  82. package/src/do/index.ts +18 -0
  83. package/src/do/postgres.ts +367 -0
  84. package/src/do/sql.ts +280 -0
  85. package/src/index.ts +50 -30
  86. package/src/mcp/binding.ts +236 -0
  87. package/src/mcp/index.ts +122 -0
  88. package/src/mcp/server.ts +361 -0
  89. package/src/mcp/tools.ts +464 -0
  90. package/src/mcp/types.ts +148 -0
  91. package/src/pglite/workers-pglite.ts +141 -12
  92. package/src/pglite-assets/pglite.data +0 -0
  93. package/src/pglite-assets/pglite.wasm +0 -0
  94. package/src/worker/auth.ts +17 -6
  95. package/src/worker/background-pglite-manager.ts +680 -0
  96. package/src/worker/do-pglite-manager.ts +235 -19
  97. package/src/worker/entry.ts +112 -30
  98. package/src/worker/index.ts +71 -1
  99. package/src/worker/lazy-pglite-manager.ts +595 -0
  100. package/dist/iceberg/duckdb-wasm.d.ts +0 -447
  101. package/dist/iceberg/duckdb-wasm.d.ts.map +0 -1
  102. package/dist/iceberg/duckdb-wasm.js +0 -600
  103. package/dist/iceberg/duckdb-wasm.js.map +0 -1
  104. package/dist/iceberg/test-fixtures.d.ts +0 -151
  105. package/dist/iceberg/test-fixtures.d.ts.map +0 -1
  106. package/dist/iceberg/test-fixtures.js +0 -446
  107. package/dist/iceberg/test-fixtures.js.map +0 -1
  108. package/dist/worker/__mocks__/cloudflare-workers.d.ts +0 -31
  109. package/dist/worker/__mocks__/cloudflare-workers.d.ts.map +0 -1
  110. package/dist/worker/__mocks__/cloudflare-workers.js +0 -33
  111. package/dist/worker/__mocks__/cloudflare-workers.js.map +0 -1
@@ -11,6 +11,11 @@
11
11
  * - Properly handles fsBundle as ArrayBuffer or Blob
12
12
  * - Provides query/exec/transaction interface compatible with PostgresDO
13
13
  *
14
+ * IMPORTANT: This module uses dynamic imports to ensure environment patches
15
+ * are applied BEFORE pglite.js is evaluated. The Emscripten-generated code
16
+ * checks `typeof WorkerGlobalScope` at module load time, which must happen
17
+ * AFTER we've patched the global environment.
18
+ *
14
19
  * @example
15
20
  * ```typescript
16
21
  * import { createWorkersPGLite } from './workers-pglite'
@@ -28,11 +33,14 @@
28
33
  * ```
29
34
  */
30
35
 
31
- import { PGlite, type PGliteOptions, type DebugLevel } from '@dotdo/pglite'
36
+ // NOTE: We intentionally DO NOT import @dotdo/pglite at the top level.
37
+ // The import must be done dynamically AFTER applying environment patches.
38
+ // See the create() method for details.
39
+
40
+ // Type imports are safe - they don't cause module evaluation
41
+ import type { PGliteOptions, DebugLevel } from '@dotdo/pglite'
32
42
 
33
43
  // Type alias for backwards compatibility
34
- type PGliteWorkers = PGlite
35
- type PGliteWorkersOptions = PGliteOptions
36
44
  type QueryResult<T = unknown> = {
37
45
  rows: T[]
38
46
  fields: { name: string; dataTypeID: number }[]
@@ -91,24 +99,107 @@ export interface WorkersPGLiteLike {
91
99
  ready?: boolean
92
100
  }
93
101
 
102
+ // Flag to track if patches have been applied
103
+ let patchesApplied = false
104
+
94
105
  /**
95
- * Wrapper around PGliteWorkers that provides a compatible interface
106
+ * Apply Cloudflare Workers compatibility patches for Emscripten.
107
+ *
108
+ * CRITICAL: This must be called BEFORE importing @dotdo/pglite.
109
+ * The pglite.js module checks `typeof WorkerGlobalScope` at module load time
110
+ * to determine if it's running in a web worker. In Cloudflare Workers,
111
+ * WorkerGlobalScope exists but the environment is not a full web worker,
112
+ * causing Emscripten to use incompatible code paths.
113
+ *
114
+ * This function patches the global environment to make Emscripten think
115
+ * it's running in a regular web browser environment.
116
+ */
117
+ function applyWorkersPatches(): void {
118
+ if (patchesApplied) {
119
+ return
120
+ }
121
+
122
+ const g = globalThis as Record<string, unknown>
123
+
124
+ // Create a minimal browser-like environment
125
+ // This helps Emscripten's ENVIRONMENT=web mode work in CF Workers
126
+ const mockLocation = {
127
+ href: 'https://localhost/',
128
+ pathname: '/',
129
+ protocol: 'https:',
130
+ host: 'localhost',
131
+ hostname: 'localhost',
132
+ port: '',
133
+ search: '',
134
+ hash: '',
135
+ origin: 'https://localhost',
136
+ }
137
+
138
+ g.window = {
139
+ sessionStorage: {},
140
+ localStorage: {},
141
+ location: mockLocation,
142
+ encodeURIComponent: encodeURIComponent,
143
+ decodeURIComponent: decodeURIComponent,
144
+ encodeURI: encodeURI,
145
+ decodeURI: decodeURI,
146
+ atob: atob,
147
+ btoa: btoa,
148
+ fetch: fetch,
149
+ URL: URL,
150
+ Blob: Blob,
151
+ crypto: crypto,
152
+ }
153
+
154
+ g.document = {
155
+ createElement: () => ({}),
156
+ currentScript: null,
157
+ location: mockLocation,
158
+ }
159
+
160
+ g.location = mockLocation
161
+ g.sessionStorage = {}
162
+
163
+ // CRITICAL: Disable WorkerGlobalScope to prevent Emscripten from detecting
164
+ // this as a worker and trying to use worker-specific APIs that CF Workers
165
+ // don't fully support
166
+ g.WorkerGlobalScope = undefined
167
+
168
+ patchesApplied = true
169
+ }
170
+
171
+ /**
172
+ * Wrapper around PGlite that provides a compatible interface
96
173
  * for PostgresDO and handles fsBundle conversion
97
174
  */
98
175
  export class WorkersPGLite implements WorkersPGLiteLike {
99
- private pglite: PGliteWorkers
176
+ // Using 'any' here because PGlite type is not available at compile time
177
+ // due to dynamic import. The actual type is PGlite from @dotdo/pglite.
178
+ private pglite: any
100
179
  private _ready: boolean = false
101
180
 
102
- private constructor(pglite: PGliteWorkers) {
181
+ private constructor(pglite: any) {
103
182
  this.pglite = pglite
104
183
  this._ready = true
105
184
  }
106
185
 
107
186
  /**
108
187
  * Create a new WorkersPGLite instance
188
+ *
189
+ * IMPORTANT: This method uses dynamic import to load @dotdo/pglite
190
+ * AFTER applying environment patches. This is necessary because
191
+ * pglite.js evaluates environment detection code at module load time.
109
192
  */
110
193
  static async create(options: WorkersPGLiteOptions): Promise<WorkersPGLite> {
111
- // Convert fsBundle to ArrayBuffer if needed
194
+ // Step 1: Apply Cloudflare Workers compatibility patches FIRST
195
+ // This MUST happen before importing @dotdo/pglite
196
+ applyWorkersPatches()
197
+
198
+ // Step 2: Now dynamically import @dotdo/pglite
199
+ // The patches are already applied, so Emscripten will see the correct environment
200
+ const { PGlite } = await import('@dotdo/pglite')
201
+
202
+ // Step 3: Convert fsBundle to ArrayBuffer if needed
112
203
  let fsBundleBuffer: ArrayBuffer
113
204
 
114
205
  if (options.fsBundle instanceof ArrayBuffer) {
@@ -135,16 +226,48 @@ export class WorkersPGLite implements WorkersPGLiteLike {
135
226
  fsBundleBuffer = options.fsBundle as ArrayBuffer
136
227
  }
137
228
 
138
- // Create PGliteWorkers instance
229
+ // Step 4: Create PGlite instance
139
230
  // fsBundle expects Blob | File, so wrap the ArrayBuffer in a Blob
140
- const pgliteOptions: PGliteWorkersOptions = {
231
+ const pgliteOptions: PGliteOptions = {
141
232
  wasmModule: options.wasmModule,
142
233
  fsBundle: new Blob([fsBundleBuffer]),
143
234
  database: options.database ?? 'postgres',
144
235
  debug: options.debug ?? 0,
145
236
  }
146
237
 
147
- const pglite = await PGlite.create(pgliteOptions)
238
+ console.log('[WorkersPGLite] Starting PGlite initialization...')
239
+ console.log('[WorkersPGLite] wasmModule type:', typeof options.wasmModule)
240
+ console.log('[WorkersPGLite] fsBundle size:', fsBundleBuffer.byteLength)
241
+ console.log('[WorkersPGLite] Patches applied before import:', patchesApplied)
242
+
243
+ // Environment debug info
244
+ const g = globalThis as Record<string, unknown>
245
+ console.log('[WorkersPGLite] ENV CHECK - window:', typeof g.window)
246
+ console.log('[WorkersPGLite] ENV CHECK - WorkerGlobalScope:', typeof g.WorkerGlobalScope)
247
+ console.log('[WorkersPGLite] ENV CHECK - document:', typeof g.document)
248
+ console.log('[WorkersPGLite] ENV CHECK - location:', typeof g.location)
249
+ console.log('[WorkersPGLite] ENV CHECK - process:', typeof g.process)
250
+
251
+ let pglite: InstanceType<typeof PGlite>
252
+ try {
253
+ console.log('[WorkersPGLite] Calling PGlite.create()...')
254
+ pglite = await PGlite.create(pgliteOptions)
255
+ console.log('[WorkersPGLite] PGlite created successfully')
256
+ } catch (error) {
257
+ console.error('[WorkersPGLite] PGlite.create failed:', error)
258
+ // Try to get more information about the error
259
+ if (error instanceof Error) {
260
+ console.error('[WorkersPGLite] Error name:', error.name)
261
+ console.error('[WorkersPGLite] Error message:', error.message)
262
+ console.error('[WorkersPGLite] Error stack:', error.stack)
263
+ }
264
+ throw error
265
+ }
266
+
267
+ // Note: We intentionally do NOT restore the original globals after initialization
268
+ // because pglite.js caches the environment detection results and may still need
269
+ // the mocked globals for subsequent operations.
270
+
148
271
  return new WorkersPGLite(pglite)
149
272
  }
150
273
 
@@ -174,7 +297,11 @@ export class WorkersPGLite implements WorkersPGLiteLike {
174
297
  }> {
175
298
  // Pass parameters directly to PGlite which uses the PostgreSQL
176
299
  // Extended Query protocol with proper prepared statement safety
177
- const result = await this.pglite.query<T>(sql, params)
300
+ const result = await this.pglite.query(sql, params) as {
301
+ rows: T[]
302
+ fields?: { name: string; dataTypeID: number }[]
303
+ affectedRows?: number
304
+ }
178
305
 
179
306
  const queryResult: {
180
307
  rows: T[]
@@ -221,4 +348,6 @@ export function isWorkersPGLite(value: unknown): value is WorkersPGLite {
221
348
  }
222
349
 
223
350
  // Re-export types for convenience
224
- export type { PGliteWorkersOptions, QueryResult }
351
+ export type { QueryResult }
352
+ // PGliteWorkersOptions is now just WorkersPGLiteOptions
353
+ export type PGliteWorkersOptions = WorkersPGLiteOptions
Binary file
Binary file
@@ -737,9 +737,17 @@ const DEFAULT_CACHE_CONFIG: TokenCacheConfig = {
737
737
 
738
738
  /**
739
739
  * Global token validation cache instance.
740
+ * Lazy-initialized to avoid global scope async operations in Cloudflare Workers.
740
741
  * @internal
741
742
  */
742
- let tokenCache = new TokenCache(DEFAULT_CACHE_CONFIG)
743
+ let tokenCache: TokenCache | null = null
744
+
745
+ function getTokenCache(): TokenCache {
746
+ if (!tokenCache) {
747
+ tokenCache = new TokenCache(DEFAULT_CACHE_CONFIG)
748
+ }
749
+ return tokenCache
750
+ }
743
751
 
744
752
  /**
745
753
  * Reconfigures the global token cache with new settings.
@@ -756,7 +764,9 @@ let tokenCache = new TokenCache(DEFAULT_CACHE_CONFIG)
756
764
  * ```
757
765
  */
758
766
  export function configureTokenCache(config: TokenCacheConfig): void {
759
- tokenCache.dispose()
767
+ if (tokenCache) {
768
+ tokenCache.dispose()
769
+ }
760
770
  tokenCache = new TokenCache({
761
771
  ...DEFAULT_CACHE_CONFIG,
762
772
  ...config,
@@ -769,7 +779,7 @@ export function configureTokenCache(config: TokenCacheConfig): void {
769
779
  * @returns Cache stats including hits, misses, and size
770
780
  */
771
781
  export function getTokenCacheStats(): CacheStats {
772
- return tokenCache.stats
782
+ return getTokenCache().stats
773
783
  }
774
784
 
775
785
  /**
@@ -779,7 +789,7 @@ export function getTokenCacheStats(): CacheStats {
779
789
  * a thundering herd to the OAuth provider.
780
790
  */
781
791
  export function clearTokenCache(): void {
782
- tokenCache.clear()
792
+ getTokenCache().clear()
783
793
  }
784
794
 
785
795
  export { extractBearerToken }
@@ -902,7 +912,8 @@ export function createAuthMiddleware(config: AuthConfig = {}): MiddlewareHandler
902
912
  )
903
913
  }
904
914
 
905
- let validationResult = tokenCache.get(token)
915
+ const cache = getTokenCache()
916
+ let validationResult = cache.get(token)
906
917
 
907
918
  if (!validationResult) {
908
919
  validationResult = validateToken
@@ -910,7 +921,7 @@ export function createAuthMiddleware(config: AuthConfig = {}): MiddlewareHandler
910
921
  : await sharedValidateToken(token, { oauthUrl })
911
922
 
912
923
  if (validationResult.valid) {
913
- tokenCache.set(token, validationResult, tokenCacheTTL)
924
+ cache.set(token, validationResult, tokenCacheTTL)
914
925
  }
915
926
  }
916
927