@carddb/browser 0.1.5 → 0.2.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.
package/dist/index.cjs CHANGED
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var client = require('@carddb/client');
4
+ var core = require('@carddb/core');
5
+
6
+ // src/index.ts
4
7
 
5
8
  // src/cache.ts
6
9
  var BrowserCache = class {
@@ -115,8 +118,24 @@ var BrowserCache = class {
115
118
  }
116
119
  }
117
120
  };
121
+ var CardDBClient = class extends client.CardDBClient {
122
+ constructor(config = {}) {
123
+ if ("apiKey" in config && config.apiKey !== void 0) {
124
+ throw new core.RestrictedError(
125
+ "apiKey is not accepted in browsers; use publishableKey or accessToken"
126
+ );
127
+ }
128
+ if ("secretKey" in config && config.secretKey !== void 0) {
129
+ throw new core.RestrictedError(
130
+ "secretKey is server-only; use publishableKey or accessToken in browsers"
131
+ );
132
+ }
133
+ super(config);
134
+ }
135
+ };
118
136
 
119
137
  exports.BrowserCache = BrowserCache;
138
+ exports.CardDBClient = CardDBClient;
120
139
  Object.keys(client).forEach(function (k) {
121
140
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
122
141
  enumerable: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cache.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Browser-based cache implementations using localStorage/sessionStorage\n */\n\nimport type { Cache } from '@carddb/core'\n\ninterface CacheEntry<T> {\n value: T\n expiresAt: number | null\n}\n\ntype StorageType = 'localStorage' | 'sessionStorage'\n\n/**\n * Browser cache using localStorage or sessionStorage.\n *\n * Uses localStorage by default for persistent caching across sessions.\n * Use sessionStorage for per-session caching that clears when the tab is closed.\n *\n * @example localStorage (default, persistent)\n * import { CardDBClient, BrowserCache } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * cache: new BrowserCache(),\n * cacheTtl: 300 // 5 minutes\n * })\n *\n * @example sessionStorage (per-session)\n * import { CardDBClient, BrowserCache } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * cache: new BrowserCache({ storage: 'sessionStorage' }),\n * cacheTtl: 300\n * })\n *\n * @example Custom prefix\n * const cache = new BrowserCache({ prefix: 'myapp:carddb:' })\n */\nexport class BrowserCache implements Cache {\n private storage: Storage\n private prefix: string\n\n constructor(options: { storage?: StorageType; prefix?: string } = {}) {\n const storageType = options.storage ?? 'localStorage'\n this.storage =\n storageType === 'sessionStorage' ? globalThis.sessionStorage : globalThis.localStorage\n this.prefix = options.prefix ?? 'carddb:'\n }\n\n /**\n * Get a value from the cache\n */\n get<T>(key: string): T | null {\n try {\n const raw = this.storage.getItem(this.prefix + key)\n if (!raw) return null\n\n const entry = JSON.parse(raw) as CacheEntry<T>\n\n // Check if expired\n if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {\n this.storage.removeItem(this.prefix + key)\n return null\n }\n\n return entry.value\n } catch {\n // If parsing fails, remove the invalid entry\n this.storage.removeItem(this.prefix + key)\n return null\n }\n }\n\n /**\n * Set a value in the cache\n *\n * @param key - The cache key\n * @param value - The value to cache (must be JSON-serializable)\n * @param ttl - Time to live in seconds (optional, undefined = no expiry)\n */\n set<T>(key: string, value: T, ttl?: number): void {\n try {\n const entry: CacheEntry<T> = {\n value,\n expiresAt: ttl !== undefined ? Date.now() + ttl * 1000 : null,\n }\n this.storage.setItem(this.prefix + key, JSON.stringify(entry))\n } catch (e) {\n // Storage might be full or disabled - silently fail\n // In the future, we could implement LRU eviction here\n console.warn('[CardDB] Failed to write to cache:', e)\n }\n }\n\n /**\n * Delete a value from the cache\n */\n delete(key: string): void {\n this.storage.removeItem(this.prefix + key)\n }\n\n /**\n * Clear all CardDB cached values (only keys with our prefix)\n */\n clear(): void {\n const keysToRemove: string[] = []\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i)\n if (key && key.startsWith(this.prefix)) {\n keysToRemove.push(key)\n }\n }\n for (const key of keysToRemove) {\n this.storage.removeItem(key)\n }\n }\n\n /**\n * Check if a key exists and is not expired\n */\n has(key: string): boolean {\n return this.get(key) !== null\n }\n\n /**\n * Get approximate number of cached entries (only counts our prefixed keys)\n */\n get size(): number {\n let count = 0\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i)\n if (key && key.startsWith(this.prefix)) {\n count++\n }\n }\n return count\n }\n\n /**\n * Clean up expired entries\n * Call this periodically if you want to reclaim storage space from expired entries\n */\n cleanup(): void {\n const now = Date.now()\n const keysToRemove: string[] = []\n\n for (let i = 0; i < this.storage.length; i++) {\n const fullKey = this.storage.key(i)\n if (fullKey && fullKey.startsWith(this.prefix)) {\n try {\n const raw = this.storage.getItem(fullKey)\n if (raw) {\n const entry = JSON.parse(raw) as CacheEntry<unknown>\n if (entry.expiresAt !== null && now > entry.expiresAt) {\n keysToRemove.push(fullKey)\n }\n }\n } catch {\n // Invalid entry, remove it\n keysToRemove.push(fullKey)\n }\n }\n }\n\n for (const key of keysToRemove) {\n this.storage.removeItem(key)\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/cache.ts","../src/index.ts"],"names":["SharedCardDBClient","RestrictedError"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Browser-based cache implementations using localStorage/sessionStorage\n */\n\nimport type { Cache } from '@carddb/core'\n\ninterface CacheEntry<T> {\n value: T\n expiresAt: number | null\n}\n\ntype StorageType = 'localStorage' | 'sessionStorage'\n\n/**\n * Browser cache using localStorage or sessionStorage.\n *\n * Uses localStorage by default for persistent caching across sessions.\n * Use sessionStorage for per-session caching that clears when the tab is closed.\n *\n * @example localStorage (default, persistent)\n * import { CardDBClient, BrowserCache } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * cache: new BrowserCache(),\n * cacheTtl: 300 // 5 minutes\n * })\n *\n * @example sessionStorage (per-session)\n * import { CardDBClient, BrowserCache } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * cache: new BrowserCache({ storage: 'sessionStorage' }),\n * cacheTtl: 300\n * })\n *\n * @example Custom prefix\n * const cache = new BrowserCache({ prefix: 'myapp:carddb:' })\n */\nexport class BrowserCache implements Cache {\n private storage: Storage\n private prefix: string\n\n constructor(options: { storage?: StorageType; prefix?: string } = {}) {\n const storageType = options.storage ?? 'localStorage'\n this.storage =\n storageType === 'sessionStorage' ? globalThis.sessionStorage : globalThis.localStorage\n this.prefix = options.prefix ?? 'carddb:'\n }\n\n /**\n * Get a value from the cache\n */\n get<T>(key: string): T | null {\n try {\n const raw = this.storage.getItem(this.prefix + key)\n if (!raw) return null\n\n const entry = JSON.parse(raw) as CacheEntry<T>\n\n // Check if expired\n if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {\n this.storage.removeItem(this.prefix + key)\n return null\n }\n\n return entry.value\n } catch {\n // If parsing fails, remove the invalid entry\n this.storage.removeItem(this.prefix + key)\n return null\n }\n }\n\n /**\n * Set a value in the cache\n *\n * @param key - The cache key\n * @param value - The value to cache (must be JSON-serializable)\n * @param ttl - Time to live in seconds (optional, undefined = no expiry)\n */\n set<T>(key: string, value: T, ttl?: number): void {\n try {\n const entry: CacheEntry<T> = {\n value,\n expiresAt: ttl !== undefined ? Date.now() + ttl * 1000 : null,\n }\n this.storage.setItem(this.prefix + key, JSON.stringify(entry))\n } catch (e) {\n // Storage might be full or disabled - silently fail\n // In the future, we could implement LRU eviction here\n console.warn('[CardDB] Failed to write to cache:', e)\n }\n }\n\n /**\n * Delete a value from the cache\n */\n delete(key: string): void {\n this.storage.removeItem(this.prefix + key)\n }\n\n /**\n * Clear all CardDB cached values (only keys with our prefix)\n */\n clear(): void {\n const keysToRemove: string[] = []\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i)\n if (key && key.startsWith(this.prefix)) {\n keysToRemove.push(key)\n }\n }\n for (const key of keysToRemove) {\n this.storage.removeItem(key)\n }\n }\n\n /**\n * Check if a key exists and is not expired\n */\n has(key: string): boolean {\n return this.get(key) !== null\n }\n\n /**\n * Get approximate number of cached entries (only counts our prefixed keys)\n */\n get size(): number {\n let count = 0\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i)\n if (key && key.startsWith(this.prefix)) {\n count++\n }\n }\n return count\n }\n\n /**\n * Clean up expired entries\n * Call this periodically if you want to reclaim storage space from expired entries\n */\n cleanup(): void {\n const now = Date.now()\n const keysToRemove: string[] = []\n\n for (let i = 0; i < this.storage.length; i++) {\n const fullKey = this.storage.key(i)\n if (fullKey && fullKey.startsWith(this.prefix)) {\n try {\n const raw = this.storage.getItem(fullKey)\n if (raw) {\n const entry = JSON.parse(raw) as CacheEntry<unknown>\n if (entry.expiresAt !== null && now > entry.expiresAt) {\n keysToRemove.push(fullKey)\n }\n }\n } catch {\n // Invalid entry, remove it\n keysToRemove.push(fullKey)\n }\n }\n }\n\n for (const key of keysToRemove) {\n this.storage.removeItem(key)\n }\n }\n}\n","/**\n * @carddb/browser - CardDB client for browsers\n *\n * @example\n * import { CardDBClient, BrowserCache, gte, ilike } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * publishableKey: 'carddb_pk_xxx...',\n * cache: new BrowserCache(), // localStorage-based\n * defaultPublisher: 'pokemon',\n * defaultGame: 'tcg'\n * })\n *\n * // Search for cards with filtering\n * const cards = await client.records.search({\n * datasetKey: 'cards',\n * filter: f => f\n * .where('hp', gte(100))\n * .where('name', ilike('%pikachu%'))\n * })\n *\n * // Iterate through all results (auto-paginates)\n * for await (const card of cards) {\n * console.log(card.data.name)\n * }\n *\n * @example Session-based caching\n * const client = new CardDBClient({\n * cache: new BrowserCache({ storage: 'sessionStorage' })\n * })\n */\n\nimport { CardDBClient as SharedCardDBClient } from '@carddb/client'\nimport { RestrictedError } from '@carddb/core'\nimport type { CardDBConfig } from '@carddb/core'\n\nexport type BrowserCardDBConfig = Omit<CardDBConfig, 'apiKey' | 'secretKey'> & {\n /** Legacy apiKey is ambiguous in browsers; use publishableKey or accessToken. */\n apiKey?: never\n /** Secret keys are server-only and are rejected by the browser client. */\n secretKey?: never\n}\n\nexport class CardDBClient extends SharedCardDBClient {\n constructor(config: BrowserCardDBConfig = {}) {\n if ('apiKey' in config && config.apiKey !== undefined) {\n throw new RestrictedError(\n 'apiKey is not accepted in browsers; use publishableKey or accessToken'\n )\n }\n\n if ('secretKey' in config && config.secretKey !== undefined) {\n throw new RestrictedError(\n 'secretKey is server-only; use publishableKey or accessToken in browsers'\n )\n }\n\n super(config)\n }\n}\n\n// Browser-specific cache implementation\nexport { BrowserCache } from './cache.js'\n\n// Re-export everything from @carddb/client\nexport * from '@carddb/client'\n"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
- import { Cache } from '@carddb/core';
1
+ import { CardDBClient as CardDBClient$1 } from '@carddb/client';
2
2
  export * from '@carddb/client';
3
+ import { Cache, CardDBConfig } from '@carddb/core';
3
4
 
4
5
  /**
5
6
  * Browser-based cache implementations using localStorage/sessionStorage
@@ -73,4 +74,46 @@ declare class BrowserCache implements Cache {
73
74
  cleanup(): void;
74
75
  }
75
76
 
76
- export { BrowserCache };
77
+ /**
78
+ * @carddb/browser - CardDB client for browsers
79
+ *
80
+ * @example
81
+ * import { CardDBClient, BrowserCache, gte, ilike } from '@carddb/browser'
82
+ *
83
+ * const client = new CardDBClient({
84
+ * publishableKey: 'carddb_pk_xxx...',
85
+ * cache: new BrowserCache(), // localStorage-based
86
+ * defaultPublisher: 'pokemon',
87
+ * defaultGame: 'tcg'
88
+ * })
89
+ *
90
+ * // Search for cards with filtering
91
+ * const cards = await client.records.search({
92
+ * datasetKey: 'cards',
93
+ * filter: f => f
94
+ * .where('hp', gte(100))
95
+ * .where('name', ilike('%pikachu%'))
96
+ * })
97
+ *
98
+ * // Iterate through all results (auto-paginates)
99
+ * for await (const card of cards) {
100
+ * console.log(card.data.name)
101
+ * }
102
+ *
103
+ * @example Session-based caching
104
+ * const client = new CardDBClient({
105
+ * cache: new BrowserCache({ storage: 'sessionStorage' })
106
+ * })
107
+ */
108
+
109
+ type BrowserCardDBConfig = Omit<CardDBConfig, 'apiKey' | 'secretKey'> & {
110
+ /** Legacy apiKey is ambiguous in browsers; use publishableKey or accessToken. */
111
+ apiKey?: never;
112
+ /** Secret keys are server-only and are rejected by the browser client. */
113
+ secretKey?: never;
114
+ };
115
+ declare class CardDBClient extends CardDBClient$1 {
116
+ constructor(config?: BrowserCardDBConfig);
117
+ }
118
+
119
+ export { BrowserCache, type BrowserCardDBConfig, CardDBClient };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { Cache } from '@carddb/core';
1
+ import { CardDBClient as CardDBClient$1 } from '@carddb/client';
2
2
  export * from '@carddb/client';
3
+ import { Cache, CardDBConfig } from '@carddb/core';
3
4
 
4
5
  /**
5
6
  * Browser-based cache implementations using localStorage/sessionStorage
@@ -73,4 +74,46 @@ declare class BrowserCache implements Cache {
73
74
  cleanup(): void;
74
75
  }
75
76
 
76
- export { BrowserCache };
77
+ /**
78
+ * @carddb/browser - CardDB client for browsers
79
+ *
80
+ * @example
81
+ * import { CardDBClient, BrowserCache, gte, ilike } from '@carddb/browser'
82
+ *
83
+ * const client = new CardDBClient({
84
+ * publishableKey: 'carddb_pk_xxx...',
85
+ * cache: new BrowserCache(), // localStorage-based
86
+ * defaultPublisher: 'pokemon',
87
+ * defaultGame: 'tcg'
88
+ * })
89
+ *
90
+ * // Search for cards with filtering
91
+ * const cards = await client.records.search({
92
+ * datasetKey: 'cards',
93
+ * filter: f => f
94
+ * .where('hp', gte(100))
95
+ * .where('name', ilike('%pikachu%'))
96
+ * })
97
+ *
98
+ * // Iterate through all results (auto-paginates)
99
+ * for await (const card of cards) {
100
+ * console.log(card.data.name)
101
+ * }
102
+ *
103
+ * @example Session-based caching
104
+ * const client = new CardDBClient({
105
+ * cache: new BrowserCache({ storage: 'sessionStorage' })
106
+ * })
107
+ */
108
+
109
+ type BrowserCardDBConfig = Omit<CardDBConfig, 'apiKey' | 'secretKey'> & {
110
+ /** Legacy apiKey is ambiguous in browsers; use publishableKey or accessToken. */
111
+ apiKey?: never;
112
+ /** Secret keys are server-only and are rejected by the browser client. */
113
+ secretKey?: never;
114
+ };
115
+ declare class CardDBClient extends CardDBClient$1 {
116
+ constructor(config?: BrowserCardDBConfig);
117
+ }
118
+
119
+ export { BrowserCache, type BrowserCardDBConfig, CardDBClient };
package/dist/index.js CHANGED
@@ -1,4 +1,8 @@
1
+ import { CardDBClient as CardDBClient$1 } from '@carddb/client';
1
2
  export * from '@carddb/client';
3
+ import { RestrictedError } from '@carddb/core';
4
+
5
+ // src/index.ts
2
6
 
3
7
  // src/cache.ts
4
8
  var BrowserCache = class {
@@ -113,7 +117,22 @@ var BrowserCache = class {
113
117
  }
114
118
  }
115
119
  };
120
+ var CardDBClient = class extends CardDBClient$1 {
121
+ constructor(config = {}) {
122
+ if ("apiKey" in config && config.apiKey !== void 0) {
123
+ throw new RestrictedError(
124
+ "apiKey is not accepted in browsers; use publishableKey or accessToken"
125
+ );
126
+ }
127
+ if ("secretKey" in config && config.secretKey !== void 0) {
128
+ throw new RestrictedError(
129
+ "secretKey is server-only; use publishableKey or accessToken in browsers"
130
+ );
131
+ }
132
+ super(config);
133
+ }
134
+ };
116
135
 
117
- export { BrowserCache };
136
+ export { BrowserCache, CardDBClient };
118
137
  //# sourceMappingURL=index.js.map
119
138
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cache.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Browser-based cache implementations using localStorage/sessionStorage\n */\n\nimport type { Cache } from '@carddb/core'\n\ninterface CacheEntry<T> {\n value: T\n expiresAt: number | null\n}\n\ntype StorageType = 'localStorage' | 'sessionStorage'\n\n/**\n * Browser cache using localStorage or sessionStorage.\n *\n * Uses localStorage by default for persistent caching across sessions.\n * Use sessionStorage for per-session caching that clears when the tab is closed.\n *\n * @example localStorage (default, persistent)\n * import { CardDBClient, BrowserCache } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * cache: new BrowserCache(),\n * cacheTtl: 300 // 5 minutes\n * })\n *\n * @example sessionStorage (per-session)\n * import { CardDBClient, BrowserCache } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * cache: new BrowserCache({ storage: 'sessionStorage' }),\n * cacheTtl: 300\n * })\n *\n * @example Custom prefix\n * const cache = new BrowserCache({ prefix: 'myapp:carddb:' })\n */\nexport class BrowserCache implements Cache {\n private storage: Storage\n private prefix: string\n\n constructor(options: { storage?: StorageType; prefix?: string } = {}) {\n const storageType = options.storage ?? 'localStorage'\n this.storage =\n storageType === 'sessionStorage' ? globalThis.sessionStorage : globalThis.localStorage\n this.prefix = options.prefix ?? 'carddb:'\n }\n\n /**\n * Get a value from the cache\n */\n get<T>(key: string): T | null {\n try {\n const raw = this.storage.getItem(this.prefix + key)\n if (!raw) return null\n\n const entry = JSON.parse(raw) as CacheEntry<T>\n\n // Check if expired\n if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {\n this.storage.removeItem(this.prefix + key)\n return null\n }\n\n return entry.value\n } catch {\n // If parsing fails, remove the invalid entry\n this.storage.removeItem(this.prefix + key)\n return null\n }\n }\n\n /**\n * Set a value in the cache\n *\n * @param key - The cache key\n * @param value - The value to cache (must be JSON-serializable)\n * @param ttl - Time to live in seconds (optional, undefined = no expiry)\n */\n set<T>(key: string, value: T, ttl?: number): void {\n try {\n const entry: CacheEntry<T> = {\n value,\n expiresAt: ttl !== undefined ? Date.now() + ttl * 1000 : null,\n }\n this.storage.setItem(this.prefix + key, JSON.stringify(entry))\n } catch (e) {\n // Storage might be full or disabled - silently fail\n // In the future, we could implement LRU eviction here\n console.warn('[CardDB] Failed to write to cache:', e)\n }\n }\n\n /**\n * Delete a value from the cache\n */\n delete(key: string): void {\n this.storage.removeItem(this.prefix + key)\n }\n\n /**\n * Clear all CardDB cached values (only keys with our prefix)\n */\n clear(): void {\n const keysToRemove: string[] = []\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i)\n if (key && key.startsWith(this.prefix)) {\n keysToRemove.push(key)\n }\n }\n for (const key of keysToRemove) {\n this.storage.removeItem(key)\n }\n }\n\n /**\n * Check if a key exists and is not expired\n */\n has(key: string): boolean {\n return this.get(key) !== null\n }\n\n /**\n * Get approximate number of cached entries (only counts our prefixed keys)\n */\n get size(): number {\n let count = 0\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i)\n if (key && key.startsWith(this.prefix)) {\n count++\n }\n }\n return count\n }\n\n /**\n * Clean up expired entries\n * Call this periodically if you want to reclaim storage space from expired entries\n */\n cleanup(): void {\n const now = Date.now()\n const keysToRemove: string[] = []\n\n for (let i = 0; i < this.storage.length; i++) {\n const fullKey = this.storage.key(i)\n if (fullKey && fullKey.startsWith(this.prefix)) {\n try {\n const raw = this.storage.getItem(fullKey)\n if (raw) {\n const entry = JSON.parse(raw) as CacheEntry<unknown>\n if (entry.expiresAt !== null && now > entry.expiresAt) {\n keysToRemove.push(fullKey)\n }\n }\n } catch {\n // Invalid entry, remove it\n keysToRemove.push(fullKey)\n }\n }\n }\n\n for (const key of keysToRemove) {\n this.storage.removeItem(key)\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/cache.ts","../src/index.ts"],"names":["SharedCardDBClient"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Browser-based cache implementations using localStorage/sessionStorage\n */\n\nimport type { Cache } from '@carddb/core'\n\ninterface CacheEntry<T> {\n value: T\n expiresAt: number | null\n}\n\ntype StorageType = 'localStorage' | 'sessionStorage'\n\n/**\n * Browser cache using localStorage or sessionStorage.\n *\n * Uses localStorage by default for persistent caching across sessions.\n * Use sessionStorage for per-session caching that clears when the tab is closed.\n *\n * @example localStorage (default, persistent)\n * import { CardDBClient, BrowserCache } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * cache: new BrowserCache(),\n * cacheTtl: 300 // 5 minutes\n * })\n *\n * @example sessionStorage (per-session)\n * import { CardDBClient, BrowserCache } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * cache: new BrowserCache({ storage: 'sessionStorage' }),\n * cacheTtl: 300\n * })\n *\n * @example Custom prefix\n * const cache = new BrowserCache({ prefix: 'myapp:carddb:' })\n */\nexport class BrowserCache implements Cache {\n private storage: Storage\n private prefix: string\n\n constructor(options: { storage?: StorageType; prefix?: string } = {}) {\n const storageType = options.storage ?? 'localStorage'\n this.storage =\n storageType === 'sessionStorage' ? globalThis.sessionStorage : globalThis.localStorage\n this.prefix = options.prefix ?? 'carddb:'\n }\n\n /**\n * Get a value from the cache\n */\n get<T>(key: string): T | null {\n try {\n const raw = this.storage.getItem(this.prefix + key)\n if (!raw) return null\n\n const entry = JSON.parse(raw) as CacheEntry<T>\n\n // Check if expired\n if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {\n this.storage.removeItem(this.prefix + key)\n return null\n }\n\n return entry.value\n } catch {\n // If parsing fails, remove the invalid entry\n this.storage.removeItem(this.prefix + key)\n return null\n }\n }\n\n /**\n * Set a value in the cache\n *\n * @param key - The cache key\n * @param value - The value to cache (must be JSON-serializable)\n * @param ttl - Time to live in seconds (optional, undefined = no expiry)\n */\n set<T>(key: string, value: T, ttl?: number): void {\n try {\n const entry: CacheEntry<T> = {\n value,\n expiresAt: ttl !== undefined ? Date.now() + ttl * 1000 : null,\n }\n this.storage.setItem(this.prefix + key, JSON.stringify(entry))\n } catch (e) {\n // Storage might be full or disabled - silently fail\n // In the future, we could implement LRU eviction here\n console.warn('[CardDB] Failed to write to cache:', e)\n }\n }\n\n /**\n * Delete a value from the cache\n */\n delete(key: string): void {\n this.storage.removeItem(this.prefix + key)\n }\n\n /**\n * Clear all CardDB cached values (only keys with our prefix)\n */\n clear(): void {\n const keysToRemove: string[] = []\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i)\n if (key && key.startsWith(this.prefix)) {\n keysToRemove.push(key)\n }\n }\n for (const key of keysToRemove) {\n this.storage.removeItem(key)\n }\n }\n\n /**\n * Check if a key exists and is not expired\n */\n has(key: string): boolean {\n return this.get(key) !== null\n }\n\n /**\n * Get approximate number of cached entries (only counts our prefixed keys)\n */\n get size(): number {\n let count = 0\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i)\n if (key && key.startsWith(this.prefix)) {\n count++\n }\n }\n return count\n }\n\n /**\n * Clean up expired entries\n * Call this periodically if you want to reclaim storage space from expired entries\n */\n cleanup(): void {\n const now = Date.now()\n const keysToRemove: string[] = []\n\n for (let i = 0; i < this.storage.length; i++) {\n const fullKey = this.storage.key(i)\n if (fullKey && fullKey.startsWith(this.prefix)) {\n try {\n const raw = this.storage.getItem(fullKey)\n if (raw) {\n const entry = JSON.parse(raw) as CacheEntry<unknown>\n if (entry.expiresAt !== null && now > entry.expiresAt) {\n keysToRemove.push(fullKey)\n }\n }\n } catch {\n // Invalid entry, remove it\n keysToRemove.push(fullKey)\n }\n }\n }\n\n for (const key of keysToRemove) {\n this.storage.removeItem(key)\n }\n }\n}\n","/**\n * @carddb/browser - CardDB client for browsers\n *\n * @example\n * import { CardDBClient, BrowserCache, gte, ilike } from '@carddb/browser'\n *\n * const client = new CardDBClient({\n * publishableKey: 'carddb_pk_xxx...',\n * cache: new BrowserCache(), // localStorage-based\n * defaultPublisher: 'pokemon',\n * defaultGame: 'tcg'\n * })\n *\n * // Search for cards with filtering\n * const cards = await client.records.search({\n * datasetKey: 'cards',\n * filter: f => f\n * .where('hp', gte(100))\n * .where('name', ilike('%pikachu%'))\n * })\n *\n * // Iterate through all results (auto-paginates)\n * for await (const card of cards) {\n * console.log(card.data.name)\n * }\n *\n * @example Session-based caching\n * const client = new CardDBClient({\n * cache: new BrowserCache({ storage: 'sessionStorage' })\n * })\n */\n\nimport { CardDBClient as SharedCardDBClient } from '@carddb/client'\nimport { RestrictedError } from '@carddb/core'\nimport type { CardDBConfig } from '@carddb/core'\n\nexport type BrowserCardDBConfig = Omit<CardDBConfig, 'apiKey' | 'secretKey'> & {\n /** Legacy apiKey is ambiguous in browsers; use publishableKey or accessToken. */\n apiKey?: never\n /** Secret keys are server-only and are rejected by the browser client. */\n secretKey?: never\n}\n\nexport class CardDBClient extends SharedCardDBClient {\n constructor(config: BrowserCardDBConfig = {}) {\n if ('apiKey' in config && config.apiKey !== undefined) {\n throw new RestrictedError(\n 'apiKey is not accepted in browsers; use publishableKey or accessToken'\n )\n }\n\n if ('secretKey' in config && config.secretKey !== undefined) {\n throw new RestrictedError(\n 'secretKey is server-only; use publishableKey or accessToken in browsers'\n )\n }\n\n super(config)\n }\n}\n\n// Browser-specific cache implementation\nexport { BrowserCache } from './cache.js'\n\n// Re-export everything from @carddb/client\nexport * from '@carddb/client'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carddb/browser",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "CardDB client for browsers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -49,8 +49,8 @@
49
49
  "url": "https://github.com/carddb/carddb-js/issues"
50
50
  },
51
51
  "dependencies": {
52
- "@carddb/client": "0.1.5",
53
- "@carddb/core": "0.1.5"
52
+ "@carddb/client": "0.2.0",
53
+ "@carddb/core": "0.2.0"
54
54
  },
55
55
  "sideEffects": false
56
56
  }