@owlmeans/web-db 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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 OwlMeans Common — Fullstack typescript framework
3
+ Copyright (c) 2026 OwlMeans Common — Fullstack typescript framework
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,784 +1,63 @@
1
1
  # @owlmeans/web-db
2
2
 
3
- Web database implementation for OwlMeans Common applications. This package provides a robust client-side database service built on IndexedDB through the `idb-keyval` library, offering persistent storage for web applications with a simple key-value interface.
3
+ IndexedDB-backed client database service for OwlMeans web applications.
4
4
 
5
5
  ## Overview
6
6
 
7
- The `@owlmeans/web-db` package implements the `ClientDbService` interface from `@owlmeans/client-resource`, providing web-specific database functionality. It offers:
8
-
9
- - **IndexedDB Integration**: Leverages browser's IndexedDB for persistent storage
10
- - **Simple Key-Value API**: Clean, promise-based interface for data operations
11
- - **Multiple Database Support**: Manage multiple isolated database instances
12
- - **Automatic Namespacing**: Prevents key collisions between different resources
13
- - **Service Integration**: Seamless integration with OwlMeans context system
14
- - **Data Persistence**: Survives browser sessions and page reloads
15
- - **Cross-Tab Synchronization**: Data changes are visible across browser tabs
16
-
17
- This package is part of the OwlMeans database implementation family:
18
- - **@owlmeans/client-resource**: Client resource management interfaces
19
- - **@owlmeans/web-db**: Web IndexedDB implementation *(this package)*
20
- - **@owlmeans/native-db**: React Native database implementation
7
+ - `makeWebDbService(alias?)` creates an IndexedDB-backed `ClientDbService`
8
+ - `appendWebDbService(context, alias?)` — registers the DB service in the context
9
+ - Implements `ClientDb`: `get`, `set`, `has`, `del`, `erase` over `idb-keyval`
10
+ - Used internally by `@owlmeans/web-client`'s `makeContext` to back `client-resource` storage
21
11
 
22
12
  ## Installation
23
13
 
24
14
  ```bash
25
- npm install @owlmeans/web-db
26
- ```
27
-
28
- ## Core Concepts
29
-
30
- ### IndexedDB Foundation
31
- Built on IndexedDB, the standard web database API, providing reliable persistent storage that works offline and survives browser restarts.
32
-
33
- ### Namespaced Storage
34
- Each database instance uses a namespace prefix to prevent key collisions, allowing multiple resources to share the same underlying storage safely.
35
-
36
- ### Service Architecture
37
- Implements the ClientDbService interface, making it compatible with the OwlMeans resource system and context management.
38
-
39
- ## API Reference
40
-
41
- ### Factory Functions
42
-
43
- #### `makeWebDbService(alias?: string): WebDbService`
44
-
45
- Creates a web database service instance that manages IndexedDB storage.
46
-
47
- ```typescript
48
- import { makeWebDbService } from '@owlmeans/web-db'
49
-
50
- const dbService = makeWebDbService('main-db')
51
- ```
52
-
53
- **Parameters:**
54
- - `alias`: string (optional) - Service alias for registration, defaults to 'client-db'
55
-
56
- **Returns:** WebDbService instance ready for registration with context
57
-
58
- #### `appendWebDbService<C, T>(context: T, alias?: string): T`
59
-
60
- Appends a web database service to the application context.
61
-
62
- ```typescript
63
- import { appendWebDbService } from '@owlmeans/web-db'
64
- import { makeClientContext } from '@owlmeans/client-context'
65
-
66
- const context = makeClientContext(config)
67
- appendWebDbService(context)
68
-
69
- // Access the service
70
- const dbService = context.service<WebDbService>('client-db')
71
- ```
72
-
73
- **Parameters:**
74
- - `context`: T - The client context to append the service to
75
- - `alias`: string (optional) - Service alias, defaults to 'client-db'
76
-
77
- **Returns:** Enhanced context with the registered database service
78
-
79
- ### Core Interfaces
80
-
81
- #### `WebDbService`
82
-
83
- Main database service interface that extends both InitializedService and ClientDbService.
84
-
85
- ```typescript
86
- interface WebDbService extends InitializedService, ClientDbService {
87
- // Inherited from ClientDbService:
88
- initialize(alias?: string): Promise<ClientDb> // Create database instance
89
- erase(): Promise<void> // Clear all data
90
-
91
- // Inherited from InitializedService:
92
- initialized: boolean // Initialization status
93
- init?(): Promise<void> // Initialization method
94
- }
95
- ```
96
-
97
- #### `ClientDb`
98
-
99
- Database instance interface providing key-value operations.
100
-
101
- ```typescript
102
- interface ClientDb {
103
- get<T>(id: string): Promise<T> // Retrieve value by key
104
- set<T>(id: string, value: T): Promise<void> // Store value by key
105
- has(id: string): Promise<boolean> // Check if key exists
106
- del(id: string): Promise<boolean> // Delete key and return success
107
- }
108
- ```
109
-
110
- ### Database Methods Detailed Reference
111
-
112
- #### `initialize(alias?: string): Promise<ClientDb>`
113
-
114
- **Purpose**: Creates and returns a database instance with the specified namespace
115
-
116
- **Behavior**:
117
- - Creates a new ClientDb instance if one doesn't exist for the alias
118
- - Returns existing instance if already created for the alias
119
- - Automatically namespaces all keys with the alias prefix
120
- - Uses IndexedDB through idb-keyval for persistent storage
121
-
122
- **Usage**: Called by resources to get their database instance
123
-
124
- **Parameters**:
125
- - `alias`: string (optional) - Namespace for the database instance
126
-
127
- **Returns**: Promise that resolves to ClientDb instance
128
-
129
- ```typescript
130
- const dbService = context.service<WebDbService>('client-db')
131
-
132
- // Create database for users
133
- const userDb = await dbService.initialize('users')
134
-
135
- // Create database for settings
136
- const settingsDb = await dbService.initialize('settings')
137
-
138
- // Each database is isolated from others
139
- await userDb.set('john', { name: 'John Doe' })
140
- await settingsDb.set('theme', 'dark')
141
- ```
142
-
143
- #### `erase(): Promise<void>`
144
-
145
- **Purpose**: Completely clears all data from IndexedDB
146
-
147
- **Behavior**:
148
- - Removes all data across all database instances
149
- - Irreversible operation that clears entire IndexedDB store
150
- - Affects all namespaces and aliases
151
-
152
- **Usage**: Data cleanup, reset operations, testing
153
-
154
- **Warning**: This removes ALL data stored by the application
155
-
156
- ```typescript
157
- const dbService = context.service<WebDbService>('client-db')
158
-
159
- // WARNING: This clears ALL application data
160
- await dbService.erase()
161
- console.log('All database data has been erased')
162
- ```
163
-
164
- ### ClientDb Instance Methods
165
-
166
- #### `get<T>(id: string): Promise<T>`
167
-
168
- **Purpose**: Retrieves a value from storage by its key
169
-
170
- **Behavior**:
171
- - Returns the stored value if key exists
172
- - Returns undefined if key doesn't exist
173
- - Automatically deserializes complex objects
174
- - Type-safe with TypeScript generics
175
-
176
- **Usage**: Loading stored data
177
-
178
- ```typescript
179
- const userDb = await dbService.initialize('users')
180
-
181
- // Get user data
182
- const user = await userDb.get<UserData>('john')
183
- if (user) {
184
- console.log('User found:', user.name)
185
- } else {
186
- console.log('User not found')
187
- }
188
- ```
189
-
190
- #### `set<T>(id: string, value: T): Promise<void>`
191
-
192
- **Purpose**: Stores a value in the database with the specified key
193
-
194
- **Behavior**:
195
- - Stores any serializable JavaScript value
196
- - Overwrites existing value if key already exists
197
- - Automatically serializes complex objects
198
- - Type-safe with TypeScript generics
199
-
200
- **Usage**: Saving data to persistent storage
201
-
202
- ```typescript
203
- const userDb = await dbService.initialize('users')
204
-
205
- // Store user data
206
- await userDb.set('john', {
207
- name: 'John Doe',
208
- email: 'john@example.com',
209
- preferences: { theme: 'dark' }
210
- })
211
-
212
- // Store simple values
213
- await userDb.set('last-login', new Date())
214
- await userDb.set('session-count', 42)
215
- ```
216
-
217
- #### `has(id: string): Promise<boolean>`
218
-
219
- **Purpose**: Checks if a key exists in the database
220
-
221
- **Behavior**:
222
- - Returns true if key exists (even if value is null/undefined)
223
- - Returns false if key doesn't exist
224
- - Efficient check without retrieving the full value
225
-
226
- **Usage**: Existence checks before operations
227
-
228
- ```typescript
229
- const userDb = await dbService.initialize('users')
230
-
231
- // Check if user exists before loading
232
- const userExists = await userDb.has('john')
233
- if (userExists) {
234
- const user = await userDb.get('john')
235
- console.log('Loading existing user:', user.name)
236
- } else {
237
- console.log('User not found, creating new user')
238
- }
15
+ bun add @owlmeans/web-db
239
16
  ```
240
17
 
241
- #### `del(id: string): Promise<boolean>`
18
+ ## Usage
242
19
 
243
- **Purpose**: Deletes a key from the database
244
-
245
- **Behavior**:
246
- - Removes the key and its value from storage
247
- - Returns true if key existed and was deleted
248
- - Returns false if key didn't exist
249
- - Atomic operation
250
-
251
- **Usage**: Removing data from storage
252
-
253
- ```typescript
254
- const userDb = await dbService.initialize('users')
255
-
256
- // Delete user data
257
- const wasDeleted = await userDb.del('john')
258
- if (wasDeleted) {
259
- console.log('User john was deleted')
260
- } else {
261
- console.log('User john was not found')
262
- }
263
-
264
- // Verify deletion
265
- const stillExists = await userDb.has('john')
266
- console.log('User still exists:', stillExists) // false
267
- ```
268
-
269
- ### Constants
270
-
271
- #### `DEFAULT_ALIAS`
272
- Default service alias (`'client-db'`) imported from `@owlmeans/client-resource`.
273
-
274
- ## Usage Examples
275
-
276
- ### Basic Database Setup
20
+ This package is registered automatically when using `makeContext` from `@owlmeans/web-client`. Direct use is only needed for custom context setup:
277
21
 
278
22
  ```typescript
279
23
  import { appendWebDbService } from '@owlmeans/web-db'
280
- import { makeClientContext } from '@owlmeans/client-context'
281
24
 
282
- // Create context with database service
283
- const context = makeClientContext(config)
284
25
  appendWebDbService(context)
285
-
286
- // Initialize context
287
- await context.configure().init()
288
-
289
- // Access database service
290
- const dbService = context.service<WebDbService>('client-db')
291
- console.log('Database service ready:', dbService.initialized)
292
- ```
293
-
294
- ### Multiple Database Instances
295
-
296
- ```typescript
297
- const dbService = context.service<WebDbService>('client-db')
298
-
299
- // Create separate databases for different purposes
300
- const userDb = await dbService.initialize('users')
301
- const settingsDb = await dbService.initialize('settings')
302
- const cacheDb = await dbService.initialize('cache')
303
-
304
- // Each database is completely isolated
305
- await userDb.set('current-user', { id: '123', name: 'John' })
306
- await settingsDb.set('theme', 'dark')
307
- await cacheDb.set('api-response', { data: [...], timestamp: Date.now() })
308
-
309
- // No interference between databases
310
- const userTheme = await userDb.get('theme') // undefined
311
- const settingsTheme = await settingsDb.get('theme') // 'dark'
312
26
  ```
313
27
 
314
- ### User Data Management
28
+ Access the DB directly:
315
29
 
316
30
  ```typescript
317
- interface UserProfile {
318
- id: string
319
- name: string
320
- email: string
321
- preferences: {
322
- theme: 'light' | 'dark'
323
- language: string
324
- notifications: boolean
325
- }
326
- lastLogin: Date
327
- }
328
-
329
- const dbService = context.service<WebDbService>('client-db')
330
- const userDb = await dbService.initialize('user-profiles')
331
-
332
- // Save user profile
333
- const saveUserProfile = async (profile: UserProfile) => {
334
- await userDb.set(profile.id, profile)
335
- console.log('Profile saved for:', profile.name)
336
- }
337
-
338
- // Load user profile
339
- const loadUserProfile = async (userId: string): Promise<UserProfile | null> => {
340
- const hasProfile = await userDb.has(userId)
341
- if (!hasProfile) {
342
- return null
343
- }
344
-
345
- return await userDb.get<UserProfile>(userId)
346
- }
347
-
348
- // Update last login
349
- const updateLastLogin = async (userId: string) => {
350
- const profile = await loadUserProfile(userId)
351
- if (profile) {
352
- profile.lastLogin = new Date()
353
- await saveUserProfile(profile)
354
- }
355
- }
31
+ import { DEFAULT_ALIAS } from '@owlmeans/web-db'
32
+ import type { WebDbService } from '@owlmeans/web-db'
356
33
 
357
- // Usage
358
- await saveUserProfile({
359
- id: 'user-123',
360
- name: 'Alice Johnson',
361
- email: 'alice@example.com',
362
- preferences: {
363
- theme: 'dark',
364
- language: 'en',
365
- notifications: true
366
- },
367
- lastLogin: new Date()
368
- })
34
+ const dbService = context.service<WebDbService>(DEFAULT_ALIAS)
35
+ const db = await dbService.initialize('my-store')
369
36
 
370
- const profile = await loadUserProfile('user-123')
371
- console.log('Loaded profile:', profile?.name)
37
+ await db.set('key', { value: 123 })
38
+ const record = await db.get<MyType>('key')
39
+ await db.del('key')
372
40
  ```
373
41
 
374
- ### Settings Persistence
375
-
376
- ```typescript
377
- interface AppSettings {
378
- theme: 'light' | 'dark' | 'auto'
379
- language: string
380
- autoSave: boolean
381
- apiEndpoint: string
382
- debugMode: boolean
383
- }
384
-
385
- const dbService = context.service<WebDbService>('client-db')
386
- const settingsDb = await dbService.initialize('app-settings')
387
-
388
- class SettingsManager {
389
- private static readonly SETTINGS_KEY = 'app-settings'
390
-
391
- static async load(): Promise<AppSettings> {
392
- const hasSettings = await settingsDb.has(this.SETTINGS_KEY)
393
- if (!hasSettings) {
394
- return this.getDefaultSettings()
395
- }
396
-
397
- const saved = await settingsDb.get<AppSettings>(this.SETTINGS_KEY)
398
- return { ...this.getDefaultSettings(), ...saved }
399
- }
400
-
401
- static async save(settings: Partial<AppSettings>): Promise<void> {
402
- const current = await this.load()
403
- const updated = { ...current, ...settings }
404
- await settingsDb.set(this.SETTINGS_KEY, updated)
405
- }
406
-
407
- static async reset(): Promise<void> {
408
- await settingsDb.del(this.SETTINGS_KEY)
409
- }
410
-
411
- private static getDefaultSettings(): AppSettings {
412
- return {
413
- theme: 'auto',
414
- language: 'en',
415
- autoSave: true,
416
- apiEndpoint: '/api',
417
- debugMode: false
418
- }
419
- }
420
- }
421
-
422
- // Usage
423
- const settings = await SettingsManager.load()
424
- console.log('Current theme:', settings.theme)
425
-
426
- await SettingsManager.save({ theme: 'dark', debugMode: true })
427
- console.log('Settings updated')
428
- ```
429
-
430
- ### Caching System
431
-
432
- ```typescript
433
- interface CacheEntry<T> {
434
- data: T
435
- timestamp: number
436
- ttl: number // time to live in milliseconds
437
- }
438
-
439
- class WebCache {
440
- private db: ClientDb
441
-
442
- constructor(private dbService: WebDbService) {}
443
-
444
- async initialize() {
445
- this.db = await this.dbService.initialize('cache')
446
- }
447
-
448
- async set<T>(key: string, data: T, ttlMs: number = 300000): Promise<void> {
449
- const entry: CacheEntry<T> = {
450
- data,
451
- timestamp: Date.now(),
452
- ttl: ttlMs
453
- }
454
- await this.db.set(key, entry)
455
- }
456
-
457
- async get<T>(key: string): Promise<T | null> {
458
- const hasKey = await this.db.has(key)
459
- if (!hasKey) {
460
- return null
461
- }
462
-
463
- const entry = await this.db.get<CacheEntry<T>>(key)
464
- if (!entry) {
465
- return null
466
- }
467
-
468
- // Check if expired
469
- if (Date.now() - entry.timestamp > entry.ttl) {
470
- await this.db.del(key)
471
- return null
472
- }
473
-
474
- return entry.data
475
- }
476
-
477
- async clear(): Promise<void> {
478
- // Note: This is a simplified version
479
- // In practice, you'd need to track cache keys
480
- console.log('Cache clear not implemented - use dbService.erase() for full clear')
481
- }
482
- }
483
-
484
- // Usage
485
- const dbService = context.service<WebDbService>('client-db')
486
- const cache = new WebCache(dbService)
487
- await cache.initialize()
488
-
489
- // Cache API response for 5 minutes
490
- await cache.set('user-list', userData, 5 * 60 * 1000)
491
-
492
- // Try to get from cache
493
- const cachedUsers = await cache.get('user-list')
494
- if (cachedUsers) {
495
- console.log('Using cached data:', cachedUsers)
496
- } else {
497
- console.log('Cache miss, fetching fresh data')
498
- }
499
- ```
42
+ ## API
500
43
 
501
- ### Data Migration
44
+ ### `makeWebDbService(alias?): WebDbService`
502
45
 
503
- ```typescript
504
- class DataMigration {
505
- private dbService: WebDbService
506
-
507
- constructor(dbService: WebDbService) {
508
- this.dbService = dbService
509
- }
510
-
511
- async migrateUserData() {
512
- const userDb = await this.dbService.initialize('users')
513
- const migrationDb = await this.dbService.initialize('migration')
514
-
515
- // Check if migration already done
516
- const migrationDone = await migrationDb.has('user-data-v2')
517
- if (migrationDone) {
518
- console.log('Migration already completed')
519
- return
520
- }
521
-
522
- // Simulate migration from old format to new format
523
- const oldUserData = await userDb.get('old-format-user')
524
- if (oldUserData) {
525
- const newUserData = this.transformUserData(oldUserData)
526
- await userDb.set('new-format-user', newUserData)
527
- await userDb.del('old-format-user')
528
- }
529
-
530
- // Mark migration as complete
531
- await migrationDb.set('user-data-v2', { completed: new Date() })
532
- console.log('User data migration completed')
533
- }
534
-
535
- private transformUserData(oldData: any): any {
536
- // Transform old data format to new format
537
- return {
538
- ...oldData,
539
- version: 2,
540
- migrated: true
541
- }
542
- }
543
- }
544
-
545
- // Usage
546
- const dbService = context.service<WebDbService>('client-db')
547
- const migration = new DataMigration(dbService)
548
- await migration.migrateUserData()
549
- ```
550
-
551
- ### Integration with React Components
552
-
553
- ```typescript
554
- import React, { useState, useEffect } from 'react'
555
- import { useContext } from '@owlmeans/client'
556
-
557
- interface UserPreferences {
558
- theme: string
559
- language: string
560
- notifications: boolean
561
- }
562
-
563
- function UserSettings() {
564
- const context = useContext()
565
- const [preferences, setPreferences] = useState<UserPreferences | null>(null)
566
- const [loading, setLoading] = useState(true)
567
-
568
- useEffect(() => {
569
- const loadPreferences = async () => {
570
- try {
571
- const dbService = context.service<WebDbService>('client-db')
572
- const settingsDb = await dbService.initialize('user-settings')
573
-
574
- const saved = await settingsDb.get<UserPreferences>('preferences')
575
- setPreferences(saved || {
576
- theme: 'light',
577
- language: 'en',
578
- notifications: true
579
- })
580
- } catch (error) {
581
- console.error('Failed to load preferences:', error)
582
- } finally {
583
- setLoading(false)
584
- }
585
- }
586
-
587
- loadPreferences()
588
- }, [])
589
-
590
- const savePreferences = async (newPrefs: UserPreferences) => {
591
- try {
592
- const dbService = context.service<WebDbService>('client-db')
593
- const settingsDb = await dbService.initialize('user-settings')
594
-
595
- await settingsDb.set('preferences', newPrefs)
596
- setPreferences(newPrefs)
597
- console.log('Preferences saved')
598
- } catch (error) {
599
- console.error('Failed to save preferences:', error)
600
- }
601
- }
602
-
603
- if (loading) {
604
- return <div>Loading preferences...</div>
605
- }
606
-
607
- return (
608
- <div>
609
- <h3>User Settings</h3>
610
- <label>
611
- Theme:
612
- <select
613
- value={preferences?.theme}
614
- onChange={(e) => savePreferences({ ...preferences!, theme: e.target.value })}
615
- >
616
- <option value="light">Light</option>
617
- <option value="dark">Dark</option>
618
- </select>
619
- </label>
620
-
621
- <label>
622
- <input
623
- type="checkbox"
624
- checked={preferences?.notifications}
625
- onChange={(e) => savePreferences({ ...preferences!, notifications: e.target.checked })}
626
- />
627
- Enable notifications
628
- </label>
629
- </div>
630
- )
631
- }
632
- ```
633
-
634
- ### Advanced Database Operations
635
-
636
- ```typescript
637
- class DatabaseManager {
638
- private dbService: WebDbService
639
-
640
- constructor(dbService: WebDbService) {
641
- this.dbService = dbService
642
- }
643
-
644
- async exportData(): Promise<Record<string, any>> {
645
- const databases = ['users', 'settings', 'cache']
646
- const exportData: Record<string, any> = {}
647
-
648
- for (const dbName of databases) {
649
- const db = await this.dbService.initialize(dbName)
650
- exportData[dbName] = {}
651
-
652
- // Note: This is simplified - in practice you'd need to track keys
653
- // or implement a proper iteration mechanism
654
- }
655
-
656
- return exportData
657
- }
658
-
659
- async importData(data: Record<string, any>): Promise<void> {
660
- for (const [dbName, dbData] of Object.entries(data)) {
661
- const db = await this.dbService.initialize(dbName)
662
-
663
- for (const [key, value] of Object.entries(dbData)) {
664
- await db.set(key, value)
665
- }
666
- }
667
- }
668
-
669
- async getStorageUsage(): Promise<{ estimated: boolean; quota?: number; usage?: number }> {
670
- if ('storage' in navigator && 'estimate' in navigator.storage) {
671
- return await navigator.storage.estimate()
672
- }
673
- return { estimated: false }
674
- }
675
-
676
- async clearAllData(): Promise<void> {
677
- await this.dbService.erase()
678
- console.log('All application data cleared')
679
- }
680
- }
681
-
682
- // Usage
683
- const dbService = context.service<WebDbService>('client-db')
684
- const dbManager = new DatabaseManager(dbService)
685
-
686
- // Check storage usage
687
- const usage = await dbManager.getStorageUsage()
688
- console.log('Storage usage:', usage)
689
-
690
- // Clear all data if needed
691
- // await dbManager.clearAllData()
692
- ```
693
-
694
- ## Browser Compatibility
695
-
696
- The package works in all modern browsers that support IndexedDB:
697
-
698
- - **Chrome**: 24+
699
- - **Firefox**: 16+
700
- - **Safari**: 10+
701
- - **Edge**: 12+
702
- - **Mobile browsers**: iOS 10+, Android 4.4+
703
-
704
- ## Performance Considerations
705
-
706
- 1. **Async Operations**: All database operations are asynchronous and return promises
707
- 2. **Namespacing**: Each database instance is isolated for performance and organization
708
- 3. **IndexedDB Limits**: Be aware of browser storage quotas (typically 50MB+)
709
- 4. **Serialization**: Complex objects are automatically serialized/deserialized
710
- 5. **Batching**: Consider batching multiple operations when possible
711
-
712
- ## Error Handling
713
-
714
- ```typescript
715
- import { WebDbService } from '@owlmeans/web-db'
716
-
717
- const handleDatabaseOperation = async () => {
718
- try {
719
- const dbService = context.service<WebDbService>('client-db')
720
- const db = await dbService.initialize('users')
721
-
722
- await db.set('user123', userData)
723
- } catch (error) {
724
- if (error.name === 'QuotaExceededError') {
725
- console.error('Storage quota exceeded')
726
- } else if (error.name === 'DataError') {
727
- console.error('Invalid data for storage')
728
- } else {
729
- console.error('Database error:', error.message)
730
- }
731
- }
732
- }
733
- ```
734
-
735
- ## Integration with Other Packages
736
-
737
- ### Client Resource Integration
738
- ```typescript
739
- import { appendClientResource } from '@owlmeans/client-resource'
740
- import { appendWebDbService } from '@owlmeans/web-db'
741
-
742
- // Setup database service first
743
- appendWebDbService(context)
744
-
745
- // Then setup resources that will use it
746
- appendClientResource(context, 'users')
747
- appendClientResource(context, 'settings')
748
- ```
749
-
750
- ### Context Integration
751
- ```typescript
752
- import { makeClientContext } from '@owlmeans/client-context'
753
- import { appendWebDbService } from '@owlmeans/web-db'
754
-
755
- const context = makeClientContext(config)
756
- appendWebDbService(context)
757
-
758
- await context.configure().init()
759
- ```
46
+ Creates an IndexedDB service. `alias` defaults to `DEFAULT_ALIAS`.
760
47
 
761
- ## Best Practices
48
+ ### `appendWebDbService<C, T>(context, alias?): T`
762
49
 
763
- 1. **Namespace Usage**: Use descriptive database aliases to organize data
764
- 2. **Error Handling**: Always handle database operation errors gracefully
765
- 3. **Data Validation**: Validate data before storing to prevent corruption
766
- 4. **Storage Limits**: Monitor storage usage and implement cleanup strategies
767
- 5. **Performance**: Use appropriate data structures and avoid storing large objects
768
- 6. **Testing**: Test database operations across different browsers
769
- 7. **Migration**: Plan for data format changes with migration strategies
50
+ Registers the DB service in the context.
770
51
 
771
- ## Dependencies
52
+ ### `WebDbService`
772
53
 
773
- This package depends on:
774
- - `@owlmeans/client-context` - Client context management
775
- - `@owlmeans/client-resource` - Client resource interfaces
776
- - `@owlmeans/context` - Core context system
777
- - `idb-keyval` - IndexedDB key-value library
54
+ Extends `ClientDbService` with `initialize(alias?)` returning a `ClientDb`:
55
+ - `get<T>(id): Promise<T>`
56
+ - `set<T>(id, value): Promise<void>`
57
+ - `has(id): Promise<boolean>`
58
+ - `del(id): Promise<boolean>`
778
59
 
779
60
  ## Related Packages
780
61
 
781
- - [`@owlmeans/client-resource`](../client-resource) - Client resource management
782
- - [`@owlmeans/native-db`](../native-db) - React Native database implementation
783
- - [`@owlmeans/client-context`](../client-context) - Client context management
784
- - [`@owlmeans/web-client`](../web-client) - Web client with database integration
62
+ - [`@owlmeans/client-resource`](../client-resource) `ClientDbService` interface this implements
63
+ - [`@owlmeans/web-client`](../web-client) calls `appendWebDbService` inside `makeContext`
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@owlmeans/web-db",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
+ "license": "MIT",
4
5
  "type": "module",
5
6
  "scripts": {
6
7
  "build": "tsc -b",
@@ -20,14 +21,15 @@
20
21
  }
21
22
  },
22
23
  "dependencies": {
23
- "@owlmeans/client-context": "^0.1.1",
24
- "@owlmeans/client-resource": "^0.1.1",
25
- "@owlmeans/context": "^0.1.1",
24
+ "@owlmeans/client-context": "^0.1.3",
25
+ "@owlmeans/client-resource": "^0.1.3",
26
+ "@owlmeans/context": "^0.1.3",
26
27
  "idb-keyval": "^6.2.1"
27
28
  },
28
29
  "devDependencies": {
30
+ "@owlmeans/dep-config": "workspace:*",
29
31
  "nodemon": "^3.1.11",
30
- "typescript": "^5.8.3"
32
+ "typescript": "^6.0.2"
31
33
  },
32
34
  "publishConfig": {
33
35
  "access": "public"
package/tsconfig.json CHANGED
@@ -1,14 +1,10 @@
1
1
  {
2
2
  "extends": [
3
- "../tsconfig.default.json",
3
+ "@owlmeans/dep-config/tsconfig.base.json"
4
4
  ],
5
5
  "compilerOptions": {
6
- "rootDir": "./src/", /* Specify the root folder within your source files. */
7
- "outDir": "./build/", /* Specify an output folder for all emitted files. */
6
+ "rootDir": "./src/",
7
+ "outDir": "./build/"
8
8
  },
9
- "exclude": [
10
- "./dist/**/*",
11
- "./build/**/*",
12
- "./*.ts"
13
- ]
14
- }
9
+ "exclude": ["./dist/**/*", "./build/**/*", "./*.ts"]
10
+ }