@carddb/browser 0.1.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/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # @carddb/browser
2
+
3
+ CardDB client for browsers.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @carddb/browser
9
+ # or
10
+ bun add @carddb/browser
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import { CardDBClient, BrowserCache, gte, ilike } from '@carddb/browser'
17
+
18
+ const client = new CardDBClient({
19
+ apiKey: 'carddb_xxx...', // Optional, increases rate limits
20
+ cache: new BrowserCache(), // Optional localStorage-based caching
21
+ defaultPublisher: 'pokemon',
22
+ defaultGame: 'tcg',
23
+ })
24
+
25
+ // Search for cards with filtering
26
+ const cards = await client.records.search({
27
+ datasetKey: 'cards',
28
+ filter: (f) =>
29
+ f
30
+ .where('hp', gte(100))
31
+ .where('name', ilike('%pikachu%')),
32
+ })
33
+
34
+ // Iterate through all results (auto-paginates)
35
+ for await (const card of cards) {
36
+ console.log(card.data.name)
37
+ }
38
+ ```
39
+
40
+ ## BrowserCache
41
+
42
+ Browser-based cache using localStorage or sessionStorage:
43
+
44
+ ```typescript
45
+ import { BrowserCache } from '@carddb/browser'
46
+
47
+ // localStorage (default, persistent across sessions)
48
+ const persistentCache = new BrowserCache()
49
+
50
+ // sessionStorage (cleared when tab closes)
51
+ const sessionCache = new BrowserCache({ storage: 'sessionStorage' })
52
+
53
+ // Custom key prefix (default: 'carddb:')
54
+ const customCache = new BrowserCache({ prefix: 'myapp:carddb:' })
55
+
56
+ // Use with client
57
+ const client = new CardDBClient({
58
+ cache: persistentCache,
59
+ cacheTtl: 300, // 5 minutes default
60
+ cacheTtls: {
61
+ publishers: 3600, // 1 hour for publishers
62
+ records: 60, // 1 minute for records
63
+ },
64
+ })
65
+
66
+ // Manual cache management
67
+ cache.cleanup() // Remove expired entries
68
+ cache.clear() // Clear all CardDB entries
69
+ cache.size // Number of cached entries
70
+ ```
71
+
72
+ ## Bundle Size
73
+
74
+ The browser package is optimized for minimal bundle size. Tree-shaking is fully supported.
75
+
76
+ ## Full Documentation
77
+
78
+ See the [main README](../../README.md) for complete documentation.
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1,330 @@
1
+ var $=class{storage;prefix;constructor(t={}){let r=t.storage??"localStorage";this.storage=r==="sessionStorage"?globalThis.sessionStorage:globalThis.localStorage,this.prefix=t.prefix??"carddb:";}get(t){try{let r=this.storage.getItem(this.prefix+t);if(!r)return null;let s=JSON.parse(r);return s.expiresAt!==null&&Date.now()>s.expiresAt?(this.storage.removeItem(this.prefix+t),null):s.value}catch{return this.storage.removeItem(this.prefix+t),null}}set(t,r,s){try{let i={value:r,expiresAt:s!==void 0?Date.now()+s*1e3:null};this.storage.setItem(this.prefix+t,JSON.stringify(i));}catch(i){console.warn("[CardDB] Failed to write to cache:",i);}}delete(t){this.storage.removeItem(this.prefix+t);}clear(){let t=[];for(let r=0;r<this.storage.length;r++){let s=this.storage.key(r);s&&s.startsWith(this.prefix)&&t.push(s);}for(let r of t)this.storage.removeItem(r);}has(t){return this.get(t)!==null}get size(){let t=0;for(let r=0;r<this.storage.length;r++){let s=this.storage.key(r);s&&s.startsWith(this.prefix)&&t++;}return t}cleanup(){let t=Date.now(),r=[];for(let s=0;s<this.storage.length;s++){let i=this.storage.key(s);if(i&&i.startsWith(this.prefix))try{let a=this.storage.getItem(i);if(a){let n=JSON.parse(a);n.expiresAt!==null&&t>n.expiresAt&&r.push(i);}}catch{r.push(i);}}for(let s of r)this.storage.removeItem(s);}};var u=class T extends Error{response;constructor(t,r){super(t),this.name="CardDBError",this.response=r,Error.captureStackTrace&&Error.captureStackTrace(this,T);}},R=class extends u{constructor(e="Invalid or missing API key",t){super(e,t),this.name="AuthenticationError";}},b=class extends u{retryAfter;limit;remaining;resetAt;constructor(e="Rate limit exceeded",t={}){super(e,t.response),this.name="RateLimitError",this.retryAfter=t.retryAfter??null,this.limit=t.limit??null,this.remaining=t.remaining??null,this.resetAt=t.resetAt??null;}},le=class extends u{constructor(e="Resource not found",t){super(e,t),this.name="NotFoundError";}},k=class extends u{errors;constructor(e="Validation error",t={}){super(e,t.response),this.name="ValidationError",this.errors=t.errors??[];}},x=class extends u{constructor(e,t){super(e,t),this.name="RestrictedError";}},B=class extends u{errors;constructor(e="GraphQL error",t={}){super(e,t.response),this.name="GraphQLError",this.errors=t.errors??[];}},w=class extends u{constructor(e="Connection error",t){super(e,t),this.name="ConnectionError";}},S=class extends w{constructor(e="Request timed out",t){super(e,t),this.name="TimeoutError";}},D=class extends u{status;constructor(e="Server error",t={}){super(e,t.response),this.name="ServerError",this.status=t.status??null;}},de=class extends u{failures;partialResults;constructor(e="Some links could not be resolved",t={}){super(e,t.response),this.name="LinkResolutionError",this.failures=t.failures??[],this.partialResults=t.partialResults;}getFailuresForField(e){return this.failures.filter(t=>t.field===e)}hasFailuresForField(e){return this.failures.some(t=>t.field===e)}};function fe(e){return {eq:e}}function ye(e){return {neq:e}}function ge(e){return {gt:e}}function me(e){return {gte:e}}function we(e){return {lt:e}}function pe(e){return {lte:e}}function ve(e){return {in:e}}function be(e){return {nin:e}}function $e(e){return {contains:e}}function Re(e){return {like:e}}function ke(e){return {ilike:e}}function xe(){return {is_null:true}}function Se(){return {is_null:false}}var F=class C{conditions=[];orGroups=[];where(t,r){if(typeof t=="string")this.conditions.push({[t]:r});else for(let[s,i]of Object.entries(t))this.conditions.push({[s]:i});return this}any(t){let r=new C;t(r);let s=r.getConditions();return s.length>0&&this.orGroups.push({$or:s}),this}whereLink(t,r){let s={};for(let[i,a]of Object.entries(r))s[i]=a;return this.conditions.push({[`${t}._link`]:s}),this}whereAny(t,r){let s={};for(let[i,a]of Object.entries(r))s[i]=a;return this.conditions.push({[`${t}._any`]:s}),this}getConditions(){return this.conditions}build(){let t=[...this.conditions,...this.orGroups];return t.length===0?{}:t.length===1?t[0]:{$and:t}}};function E(e){if(e!==void 0){if(typeof e=="function"){let t=new F;e(t);let r=t.build();return Object.keys(r).length>0?r:void 0}return Object.keys(e).length>0?e:void 0}}var p=`
2
+ id
3
+ name
4
+ slug
5
+ status
6
+ description
7
+ website
8
+ createdAt
9
+ updatedAt
10
+ logoFile {
11
+ id
12
+ url
13
+ }
14
+ bannerFile {
15
+ id
16
+ url
17
+ }
18
+ `,m=`
19
+ id
20
+ publisherId
21
+ key
22
+ name
23
+ description
24
+ website
25
+ visibility
26
+ isArchived
27
+ createdAt
28
+ updatedAt
29
+ publisher {
30
+ id
31
+ name
32
+ slug
33
+ }
34
+ logoFile {
35
+ id
36
+ url
37
+ }
38
+ coverFile {
39
+ id
40
+ url
41
+ }
42
+ `,v=`
43
+ id
44
+ publisherId
45
+ gameId
46
+ key
47
+ name
48
+ description
49
+ purpose
50
+ visibility
51
+ isArchived
52
+ createdAt
53
+ updatedAt
54
+ publisher {
55
+ id
56
+ name
57
+ slug
58
+ }
59
+ game {
60
+ id
61
+ key
62
+ name
63
+ }
64
+ `,L=`
65
+ schema {
66
+ fields {
67
+ key
68
+ label
69
+ description
70
+ type
71
+ isRequired
72
+ filterable
73
+ searchable
74
+ isIdentifier
75
+ itemType
76
+ displayFormat
77
+ allowedValues
78
+ nestedFields {
79
+ key
80
+ label
81
+ description
82
+ type
83
+ isRequired
84
+ filterable
85
+ searchable
86
+ itemType
87
+ }
88
+ }
89
+ filterableFields
90
+ searchableFields
91
+ linkFields {
92
+ key
93
+ label
94
+ targetDatasetKey
95
+ targetDatasetName
96
+ targetDatasetId
97
+ }
98
+ }
99
+ `,d=`
100
+ id
101
+ datasetId
102
+ data
103
+ createdAt
104
+ updatedAt
105
+ dataset {
106
+ id
107
+ key
108
+ name
109
+ gameId
110
+ publisherId
111
+ }
112
+ `,y=`
113
+ id
114
+ accountId
115
+ apiApplicationId
116
+ gameId
117
+ title
118
+ description
119
+ formatKey
120
+ visibility
121
+ externalRef
122
+ sourceUrl
123
+ metadata
124
+ createdAt
125
+ updatedAt
126
+ game {
127
+ ${m}
128
+ }
129
+ entries {
130
+ id
131
+ datasetId
132
+ recordId
133
+ identifier
134
+ quantity
135
+ section
136
+ sortOrder
137
+ annotations
138
+ record {
139
+ ${d}
140
+ }
141
+ }
142
+ `,N=`
143
+ resolvedLinks {
144
+ field
145
+ linkFieldKey
146
+ values
147
+ records {
148
+ id
149
+ datasetId
150
+ data
151
+ }
152
+ }
153
+ `;function g(e){return `
154
+ totalCount
155
+ pageInfo {
156
+ hasNextPage
157
+ hasPreviousPage
158
+ startCursor
159
+ endCursor
160
+ }
161
+ edges {
162
+ cursor
163
+ node {
164
+ ${e}
165
+ }
166
+ }
167
+ `}var o={searchPublishers(e={}){let t={},r=[],s=[];e.search!==void 0&&(s.push("$search: String"),r.push("search: $search"),t.search=e.search),e.first!==void 0&&(s.push("$first: Int"),r.push("first: $first"),t.first=e.first),e.after!==void 0&&(s.push("$after: String"),r.push("after: $after"),t.after=e.after);let i=s.length>0?`(${s.join(", ")})`:"",a=r.length>0?`(${r.join(", ")})`:"";return {query:`
168
+ query SearchPublishers${i} {
169
+ searchPublishers${a} {
170
+ ${g(p)}
171
+ }
172
+ }
173
+ `,variables:t}},fetchPublisherById(){return {query:`
174
+ query FetchPublisher($id: UUID!) {
175
+ fetchPublisher(id: $id) {
176
+ ${p}
177
+ }
178
+ }
179
+ `}},fetchPublisherBySlug(){return {query:`
180
+ query FetchPublisher($slug: String!) {
181
+ fetchPublisher(slug: $slug) {
182
+ ${p}
183
+ }
184
+ }
185
+ `}},fetchPublishers(){return {query:`
186
+ query FetchPublishers($slugs: [String!]!) {
187
+ fetchPublishers(slugs: $slugs) {
188
+ ${p}
189
+ }
190
+ }
191
+ `}},searchGames(e={}){let t={},r=[],s=[];e.publisherSlug!==void 0&&(s.push("$publisherSlug: String"),r.push("publisherSlug: $publisherSlug"),t.publisherSlug=e.publisherSlug),e.search!==void 0&&(s.push("$search: String"),r.push("search: $search"),t.search=e.search),e.first!==void 0&&(s.push("$first: Int"),r.push("first: $first"),t.first=e.first),e.after!==void 0&&(s.push("$after: String"),r.push("after: $after"),t.after=e.after);let i=s.length>0?`(${s.join(", ")})`:"",a=r.length>0?`(${r.join(", ")})`:"";return {query:`
192
+ query SearchGames${i} {
193
+ searchGames${a} {
194
+ ${g(m)}
195
+ }
196
+ }
197
+ `,variables:t}},fetchGameById(){return {query:`
198
+ query FetchGame($id: UUID!) {
199
+ fetchGame(id: $id) {
200
+ ${m}
201
+ }
202
+ }
203
+ `}},fetchGameByKeys(){return {query:`
204
+ query FetchGame($publisherSlug: String!, $gameKey: String!) {
205
+ fetchGame(publisherSlug: $publisherSlug, gameKey: $gameKey) {
206
+ ${m}
207
+ }
208
+ }
209
+ `}},fetchGames(){return {query:`
210
+ query FetchGames($ids: [UUID!]!) {
211
+ fetchGames(ids: $ids) {
212
+ ${m}
213
+ }
214
+ }
215
+ `}},searchDatasets(e={}){let t={},r=[],s=[];e.publisherSlug!==void 0&&(s.push("$publisherSlug: String"),r.push("publisherSlug: $publisherSlug"),t.publisherSlug=e.publisherSlug),e.gameKey!==void 0&&(s.push("$gameKey: String"),r.push("gameKey: $gameKey"),t.gameKey=e.gameKey),e.search!==void 0&&(s.push("$search: String"),r.push("search: $search"),t.search=e.search),e.purpose!==void 0&&(s.push("$purpose: DatasetPurpose"),r.push("purpose: $purpose"),t.purpose=e.purpose),e.first!==void 0&&(s.push("$first: Int"),r.push("first: $first"),t.first=e.first),e.after!==void 0&&(s.push("$after: String"),r.push("after: $after"),t.after=e.after);let i=s.length>0?`(${s.join(", ")})`:"",a=r.length>0?`(${r.join(", ")})`:"";return {query:`
216
+ query SearchDatasets${i} {
217
+ searchDatasets${a} {
218
+ ${g(v)}
219
+ }
220
+ }
221
+ `,variables:t}},fetchDatasetById(){return {query:`
222
+ query FetchDataset($id: UUID!) {
223
+ fetchDataset(id: $id) {
224
+ ${v}
225
+ ${L}
226
+ }
227
+ }
228
+ `}},fetchDatasetByKeys(){return {query:`
229
+ query FetchDataset($publisherSlug: String!, $gameKey: String!, $datasetKey: String!) {
230
+ fetchDataset(publisherSlug: $publisherSlug, gameKey: $gameKey, datasetKey: $datasetKey) {
231
+ ${v}
232
+ ${L}
233
+ }
234
+ }
235
+ `}},fetchDatasets(){return {query:`
236
+ query FetchDatasets($ids: [UUID!]!) {
237
+ fetchDatasets(ids: $ids) {
238
+ ${v}
239
+ }
240
+ }
241
+ `}},searchRecords(e){let t={publisherSlug:e.publisherSlug,gameKey:e.gameKey,datasetKey:e.datasetKey},r=["publisherSlug: $publisherSlug","gameKey: $gameKey","datasetKey: $datasetKey"],s=["$publisherSlug: String!","$gameKey: String!","$datasetKey: String!"];e.filter!==void 0&&(s.push("$filter: JSON"),r.push("filter: $filter"),t.filter=e.filter),e.search!==void 0&&(s.push("$search: String"),r.push("search: $search"),t.search=e.search),e.orderBy!==void 0&&(s.push("$orderBy: String"),r.push("orderBy: $orderBy"),t.orderBy=e.orderBy),e.resolveLinks!==void 0&&(s.push("$resolveLinks: [String!]"),r.push("resolveLinks: $resolveLinks"),t.resolveLinks=e.resolveLinks),e.first!==void 0&&(s.push("$first: Int"),r.push("first: $first"),t.first=e.first),e.after!==void 0&&(s.push("$after: String"),r.push("after: $after"),t.after=e.after),e.validateSchema!==void 0&&(s.push("$validateSchema: Boolean"),r.push("validateSchema: $validateSchema"),t.validateSchema=e.validateSchema);let a=e.resolveLinks&&e.resolveLinks.length>0?`${d}
242
+ ${N}`:d;return {query:`
243
+ query SearchRecords(${s.join(", ")}) {
244
+ searchRecords(${r.join(", ")}) {
245
+ ${g(a)}
246
+ }
247
+ }
248
+ `,variables:t}},fetchRecordById(){return {query:`
249
+ query FetchRecord($id: UUID!) {
250
+ fetchRecord(id: $id) {
251
+ ${d}
252
+ }
253
+ }
254
+ `}},fetchRecordByIdentifier(){return {query:`
255
+ query FetchRecordByIdentifier($publisherSlug: String!, $gameKey: String!, $datasetKey: String!, $identifier: String!) {
256
+ fetchRecordByIdentifier(publisherSlug: $publisherSlug, gameKey: $gameKey, datasetKey: $datasetKey, identifier: $identifier) {
257
+ ${d}
258
+ }
259
+ }
260
+ `}},fetchRecordsByIdentifier(){return {query:`
261
+ query FetchRecordsByIdentifier($publisherSlug: String!, $gameKey: String!, $datasetKey: String!, $identifiers: [String!]!) {
262
+ fetchRecordsByIdentifier(publisherSlug: $publisherSlug, gameKey: $gameKey, datasetKey: $datasetKey, identifiers: $identifiers) {
263
+ ${d}
264
+ }
265
+ }
266
+ `}},fetchRecords(){return {query:`
267
+ query FetchRecords($ids: [UUID!]!) {
268
+ fetchRecords(ids: $ids) {
269
+ ${d}
270
+ }
271
+ }
272
+ `}},listMyDecks(e={}){let t={},r=[],s=[];e.first!==void 0&&(s.push("$first: Int"),r.push("first: $first"),t.first=e.first),e.after!==void 0&&(s.push("$after: String"),r.push("after: $after"),t.after=e.after);let i=s.length>0?`(${s.join(", ")})`:"",a=r.length>0?`(${r.join(", ")})`:"";return {query:`
273
+ query MyDecks${i} {
274
+ myDecks${a} {
275
+ ${g(y)}
276
+ }
277
+ }
278
+ `,variables:t}},fetchDeckById(){return {query:`
279
+ query FetchDeck($id: UUID!) {
280
+ fetchDeck(id: $id) {
281
+ ${y}
282
+ }
283
+ }
284
+ `}},fetchDeckByExternalRef(){return {query:`
285
+ query FetchDeckByExternalRef($externalRef: String!) {
286
+ fetchDeckByExternalRef(externalRef: $externalRef) {
287
+ ${y}
288
+ }
289
+ }
290
+ `}},createDeck(){return {query:`
291
+ mutation DeckCreate($input: DeckCreateInput!) {
292
+ deckCreate(input: $input) {
293
+ ${y}
294
+ }
295
+ }
296
+ `}},updateDeck(){return {query:`
297
+ mutation DeckUpdate($id: UUID!, $input: DeckUpdateInput!) {
298
+ deckUpdate(id: $id, input: $input) {
299
+ ${y}
300
+ }
301
+ }
302
+ `}},deleteDeck(){return {query:`
303
+ mutation DeckDelete($id: UUID!) {
304
+ deckDelete(id: $id)
305
+ }
306
+ `}},deckCreateVariables(e){return {input:e}},deckUpdateVariables(e,t){return {id:e,input:t}},fetchMe(){return {query:`
307
+ query FetchMe {
308
+ fetchMe {
309
+ application {
310
+ id
311
+ name
312
+ description
313
+ environment
314
+ apiKeyPrefix
315
+ allowedOrigins
316
+ allowedIps
317
+ createdAt
318
+ updatedAt
319
+ lastUsedAt
320
+ }
321
+ account {
322
+ id
323
+ displayName
324
+ createdAt
325
+ }
326
+ }
327
+ }
328
+ `}}},l=class{totalCount;pageInfo;items;nextPageLoader;constructor(e,t={}){this.totalCount=e.totalCount,this.pageInfo=e.pageInfo,this.items=e.edges.map(r=>t.itemTransformer?t.itemTransformer(r.node):r.node),this.nextPageLoader=t.nextPageLoader;}get hasNextPage(){return this.pageInfo.hasNextPage}get hasPreviousPage(){return this.pageInfo.hasPreviousPage}get endCursor(){return this.pageInfo.endCursor}get startCursor(){return this.pageInfo.startCursor}get length(){return this.items.length}get isEmpty(){return this.items.length===0}get first(){return this.items[0]}get last(){return this.items[this.items.length-1]}async nextPage(){if(!this.hasNextPage)return null;if(!this.nextPageLoader)throw new Error("No next page loader configured");return this.endCursor?this.nextPageLoader(this.endCursor):null}async*[Symbol.asyncIterator](){let e=this;for(;e;){for(let t of e.items)yield t;if(!e.hasNextPage)break;e=await e.nextPage();}}async forEach(e){let t=0;for await(let r of this)await e(r,t++);}async map(e){let t=[],r=0;for await(let s of this)t.push(await e(s,r++));return t}async filter(e){let t=[],r=0;for await(let s of this)await e(s,r++)&&t.push(s);return t}async find(e){let t=0;for await(let r of this)if(await e(r,t++))return r}async take(e){let t=[];for await(let r of this){if(t.length>=e)break;t.push(r);}return t}async toArray(){let e=[];for await(let t of this)e.push(t);return e}async*batches(){let e=this;for(;e&&(e.items.length>0&&(yield e.items),!!e.hasNextPage);)e=await e.nextPage();}each(){return this}};var U="https://carddb.xtda.org/query",M=3e4,_=1e4,O=300,j=3,V=2,X=1e3,Q=3e4,J=class P{apiKey;endpoint;timeout;openTimeout;defaultPublisher;defaultGame;allowedPublishers;allowedGames;logger;logLevel;retryOnRateLimit;maxRetries;retryOnNetworkError;maxNetworkRetries;retryBaseDelay;retryMaxDelay;cache;cacheTtl;cacheTtls;constructor(t={}){this.apiKey=t.apiKey,this.endpoint=t.endpoint??U,this.timeout=t.timeout??M,this.openTimeout=t.openTimeout??_,this.defaultPublisher=t.defaultPublisher,this.defaultGame=t.defaultGame,this.allowedPublishers=t.allowedPublishers,this.allowedGames=t.allowedGames,this.logger=t.logger,this.logLevel=t.logLevel??"info",this.retryOnRateLimit=t.retryOnRateLimit??false,this.maxRetries=t.maxRetries??j,this.retryOnNetworkError=t.retryOnNetworkError??true,this.maxNetworkRetries=t.maxNetworkRetries??V,this.retryBaseDelay=t.retryBaseDelay??X,this.retryMaxDelay=t.retryMaxDelay??Q,this.cache=t.cache,this.cacheTtl=t.cacheTtl??O,this.cacheTtls=t.cacheTtls??{};}calculateRetryDelay(t){let r=this.retryBaseDelay*Math.pow(2,t),s=Math.min(r,this.retryMaxDelay),i=s*.25*(Math.random()*2-1);return Math.round(s+i)}cacheTtlFor(t){return this.cacheTtls[t]??this.cacheTtl}resolvePublisher(t){return t??this.defaultPublisher}resolveGame(t){return t??this.defaultGame}validatePublisher(t){if(this.allowedPublishers&&!this.allowedPublishers.includes(t))throw new x(`Publisher '${t}' is not in the allowed publishers list`)}validateGame(t,r){if(!this.allowedGames)return;let s=this.allowedGames[t];if(s&&!s.includes(r))throw new x(`Game '${r}' is not allowed for publisher '${t}'`)}validateAccess(t,r){t&&(this.validatePublisher(t),r&&this.validateGame(t,r));}shouldLog(t){let r={debug:0,info:1,warn:2,error:3};return r[t]>=r[this.logLevel]}merge(t){return new P({apiKey:t.apiKey??this.apiKey,endpoint:t.endpoint??this.endpoint,timeout:t.timeout??this.timeout,openTimeout:t.openTimeout??this.openTimeout,defaultPublisher:t.defaultPublisher??this.defaultPublisher,defaultGame:t.defaultGame??this.defaultGame,allowedPublishers:t.allowedPublishers??this.allowedPublishers,allowedGames:t.allowedGames??this.allowedGames,logger:t.logger??this.logger,logLevel:t.logLevel??this.logLevel,retryOnRateLimit:t.retryOnRateLimit??this.retryOnRateLimit,maxRetries:t.maxRetries??this.maxRetries,retryOnNetworkError:t.retryOnNetworkError??this.retryOnNetworkError,maxNetworkRetries:t.maxNetworkRetries??this.maxNetworkRetries,retryBaseDelay:t.retryBaseDelay??this.retryBaseDelay,retryMaxDelay:t.retryMaxDelay??this.retryMaxDelay,cache:t.cache??this.cache,cacheTtl:t.cacheTtl??this.cacheTtl,cacheTtls:t.cacheTtls??this.cacheTtls})}},q="0.1.0";function W(){if(typeof globalThis<"u"&&"Bun"in globalThis){let e=globalThis.Bun&&typeof globalThis.Bun=="object"&&globalThis.Bun.version;return {name:"bun",version:typeof e=="string"?e:"unknown"}}if(typeof globalThis<"u"&&"Deno"in globalThis){let e=globalThis.Deno&&typeof globalThis.Deno=="object"&&globalThis.Deno.version&&typeof globalThis.Deno.version=="object"&&globalThis.Deno.version.deno;return {name:"deno",version:typeof e=="string"?e:"unknown"}}return typeof process<"u"&&process.versions&&process.versions.node?{name:"node",version:process.versions.node}:typeof navigator<"u"&&navigator.userAgent?H(navigator.userAgent):{name:"unknown",version:"unknown"}}function H(e){let t=e.match(/Edg\/(\d+(?:\.\d+)*)/);if(t)return {name:"edge",version:t[1]};let r=e.match(/Chrome\/(\d+(?:\.\d+)*)/);if(r&&!e.includes("Edg/"))return {name:"chrome",version:r[1]};let s=e.match(/Firefox\/(\d+(?:\.\d+)*)/);if(s)return {name:"firefox",version:s[1]};let i=e.match(/Version\/(\d+(?:\.\d+)*).*Safari/);return i?{name:"safari",version:i[1]}:{name:"browser",version:"unknown"}}function Y(){let e=W();return `CardDB-SDK/js/${q} (${e.name}/${e.version})`}function Ne(){return q}var A=null;function z(){return A}var Z=class{config;constructor(e){this.config=e;}async execute(e,t={}){let r=this.extractOperationName(e),s=0,i=0;for(;;)try{let a=Date.now();this.logRequest(r,t);let n=await this.fetch(e,t),c=Date.now()-a,h=await this.handleResponse(n);return this.logResponse(r,c),h}catch(a){if(a instanceof b&&this.config.retryOnRateLimit&&s<this.config.maxRetries){s++;let n=a.retryAfter??60;this.logRateLimitRetry(r,s,n),await this.sleep(n*1e3);continue}if(this.isRetryableNetworkError(a)&&this.config.retryOnNetworkError&&i<this.config.maxNetworkRetries){let n=this.config.calculateRetryDelay(i);this.logNetworkRetry(r,i+1,n,a),i++,await this.sleep(n);continue}if(a instanceof D&&this.config.retryOnNetworkError&&i<this.config.maxNetworkRetries){let n=this.config.calculateRetryDelay(i);this.logNetworkRetry(r,i+1,n,a),i++,await this.sleep(n);continue}throw a}}isRetryableNetworkError(e){return e instanceof w||e instanceof S}async fetch(e,t){let r=new AbortController,s=setTimeout(()=>r.abort(),this.config.timeout);try{return await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","User-Agent":Y(),...this.config.apiKey?{"X-API-Key":this.config.apiKey}:{}},body:JSON.stringify({query:e,variables:t}),signal:r.signal})}catch(i){throw i instanceof Error?i.name==="AbortError"?(this.logError("Request timed out"),new S("Request timed out")):(this.logError(`Connection failed: ${i.message}`),new w(`Connection failed: ${i.message}`)):new w("Connection failed")}finally{clearTimeout(s);}}async handleResponse(e){switch(this.extractRateLimitInfo(e),e.status){case 200:return this.handleSuccessResponse(e);case 401:throw new R("Invalid or missing API key");case 429:return this.handleRateLimitResponse(e);default:if(e.status>=400&&e.status<500)return this.handleClientError(e);if(e.status>=500){let t=await this.parseBody(e);throw new D(`Server error (${e.status})`,{status:e.status,response:t})}throw new u(`Unexpected response status: ${e.status}`)}}async handleSuccessResponse(e){let t=await this.parseBody(e);return t.errors&&t.errors.length>0&&this.handleGraphQLErrors(t.errors,t),t.data??{}}handleGraphQLErrors(e,t){let r=e[0],s=r.message||"GraphQL error";switch(r.extensions?.code){case "UNAUTHENTICATED":throw new R(s,t);case "RATE_LIMITED":throw new b(s,{response:t});case "NOT_FOUND":throw new u(s,t);case "VALIDATION_ERROR":case "BAD_USER_INPUT":throw new k(s,{errors:e,response:t});default:throw new B(s,{errors:e,response:t})}}async handleRateLimitResponse(e){let t=parseInt(e.headers.get("Retry-After")??"60",10),r=parseInt(e.headers.get("X-RateLimit-Limit")??"",10)||null,s=parseInt(e.headers.get("X-RateLimit-Remaining")??"",10)||null,i=parseInt(e.headers.get("X-RateLimit-Reset")??"",10)||null,a=i?new Date(i*1e3):null,n=await this.parseBody(e);throw new b("Rate limit exceeded",{retryAfter:t,limit:r,remaining:s,resetAt:a,response:n})}async handleClientError(e){let t=await this.parseBody(e),r=t.errors?.[0]?.message??`Client error (${e.status})`;throw new k(r,{response:t})}async parseBody(e){try{return await e.json()}catch{return {raw:await e.text()}}}extractRateLimitInfo(e){let t=parseInt(e.headers.get("X-RateLimit-Limit")??"",10)||null,r=parseInt(e.headers.get("X-RateLimit-Remaining")??"",10)||null,s=parseInt(e.headers.get("X-RateLimit-Reset")??"",10)||null;A={limit:t,remaining:r,reset:s};}extractOperationName(e){let t=e.match(/(?:query|mutation)\s+(\w+)/);return t?t[1]:"Unknown"}sleep(e){return new Promise(t=>setTimeout(t,e))}logRequest(e,t){!this.config.logger||!this.config.shouldLog("debug")||this.config.logger.debug(`[CardDB] Executing ${e}`,{variables:t});}logResponse(e,t){!this.config.logger||!this.config.shouldLog("info")||this.config.logger.info(`[CardDB] ${e} completed in ${t}ms`);}logRateLimitRetry(e,t,r){!this.config.logger||!this.config.shouldLog("warn")||this.config.logger.warn(`[CardDB] Rate limited on ${e}, retry ${t}/${this.config.maxRetries} after ${r}s`);}logNetworkRetry(e,t,r,s){if(!this.config.logger||!this.config.shouldLog("warn"))return;let i=s instanceof Error?s.name:"Unknown";this.config.logger.warn(`[CardDB] ${i} on ${e}, retry ${t}/${this.config.maxNetworkRetries} after ${r}ms`);}logError(e){!this.config.logger||!this.config.shouldLog("error")||this.config.logger.error(`[CardDB] ${e}`);}};function ee(e,t,r){let s=Object.entries(r).filter(([,i])=>i!==void 0).sort(([i],[a])=>i.localeCompare(a)).map(([i,a])=>`${i}=${JSON.stringify(a)}`).join("&");return `carddb:${e}:${t}:${s}`}async function te(e,t){let r=e.get(t);return r}async function re(e,t,r,s){let i=e.set(t,r,s);i instanceof Promise&&await i;}var f=class{connection;config;constructor(e,t){this.connection=e,this.config=t;}resolvePublisher(e){let t=this.config.resolvePublisher(e);if(!t)throw new Error("publisher_slug is required (no default configured)");return t}resolveGame(e){let t=this.config.resolveGame(e);if(!t)throw new Error("game_key is required (no default configured)");return t}validateAccess(e,t){this.config.validateAccess(e,t);}async withCache(e,t,r,s){let i=r.cache??!!this.config.cache,a=this.config.cache;if(!i||!a)return s();let n=await te(a,e);if(n!==null)return n;let c=await s();if(c!=null){let h=this.config.cacheTtlFor(t);await re(a,e,c,h);}return c}cacheKey(e,t,r){return ee(e,t,r)}},se=class extends f{constructor(e,t){super(e,t);}async search(e={}){let{query:t,variables:r}=o.searchPublishers({search:e.search,first:e.first,after:e.after}),s=this.cacheKey("publishers","search",r),i=await this.withCache(s,"publishers",e,async()=>(await this.connection.execute(t,r)).searchPublishers);return new l(i,{nextPageLoader:async a=>this.search({...e,after:a})})}async get(e,t={}){let r=this.isUUID(e),s=this.cacheKey("publishers","get",{[r?"id":"slug"]:e});return this.withCache(s,"publishers",t,async()=>{if(r){let{query:i}=o.fetchPublisherById();return (await this.connection.execute(i,{id:e})).fetchPublisher??null}else {let{query:i}=o.fetchPublisherBySlug();return (await this.connection.execute(i,{slug:e})).fetchPublisher??null}})}async getMany(e,t={}){if(e.length===0)return [];let r=this.cacheKey("publishers","getMany",{slugs:e});return this.withCache(r,"publishers",t,async()=>{let{query:s}=o.fetchPublishers();return (await this.connection.execute(s,{slugs:e})).fetchPublishers??[]})}isUUID(e){return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(e)}},ie=class extends f{constructor(e,t){super(e,t);}async search(e={}){let t=this.config.resolvePublisher(e.publisherSlug);t&&this.validateAccess(t);let{query:r,variables:s}=o.searchGames({publisherSlug:t,search:e.search,first:e.first,after:e.after}),i=this.cacheKey("games","search",s),a=await this.withCache(i,"games",e,async()=>(await this.connection.execute(r,s)).searchGames);return new l(a,{nextPageLoader:async n=>this.search({...e,after:n})})}async get(e,t,r){if(typeof t=="string"){let s=e,i=t,a=r??{};this.validateAccess(s,i);let n=this.cacheKey("games","getByKeys",{publisherSlug:s,gameKey:i});return this.withCache(n,"games",a,async()=>{let{query:c}=o.fetchGameByKeys();return (await this.connection.execute(c,{publisherSlug:s,gameKey:i})).fetchGame??null})}else {let s=e,i=t??{},a=this.cacheKey("games","get",{id:s});return this.withCache(a,"games",i,async()=>{let{query:n}=o.fetchGameById();return (await this.connection.execute(n,{id:s})).fetchGame??null})}}async getMany(e,t={}){if(e.length===0)return [];let r=this.cacheKey("games","getMany",{ids:e});return this.withCache(r,"games",t,async()=>{let{query:s}=o.fetchGames();return (await this.connection.execute(s,{ids:e})).fetchGames??[]})}},ae=class extends f{constructor(e,t){super(e,t);}async search(e={}){let t=this.config.resolvePublisher(e.publisherSlug),r=this.config.resolveGame(e.gameKey);t&&this.validateAccess(t,r);let{query:s,variables:i}=o.searchDatasets({publisherSlug:t,gameKey:r,search:e.search,purpose:e.purpose,first:e.first,after:e.after}),a=this.cacheKey("datasets","search",i),n=await this.withCache(a,"datasets",e,async()=>(await this.connection.execute(s,i)).searchDatasets);return new l(n,{nextPageLoader:async c=>this.search({...e,after:c})})}async get(e,t,r,s){if(typeof t=="string"&&typeof r=="string"){let i=e,a=t,n=s??{};this.validateAccess(i,a);let c=this.cacheKey("datasets","getByKeys",{publisherSlug:i,gameKey:a,datasetKey:r});return this.withCache(c,"datasets",n,async()=>{let{query:h}=o.fetchDatasetByKeys();return (await this.connection.execute(h,{publisherSlug:i,gameKey:a,datasetKey:r})).fetchDataset??null})}else {let i=e,a=t??{},n=this.cacheKey("datasets","get",{id:i});return this.withCache(n,"datasets",a,async()=>{let{query:c}=o.fetchDatasetById();return (await this.connection.execute(c,{id:i})).fetchDataset??null})}}async getMany(e,t={}){if(e.length===0)return [];let r=this.cacheKey("datasets","getMany",{ids:e});return this.withCache(r,"datasets",t,async()=>{let{query:s}=o.fetchDatasets();return (await this.connection.execute(s,{ids:e})).fetchDatasets??[]})}},ne=class extends f{constructor(e,t){super(e,t);}async fetch(e,t={}){let r=this.cacheKey("decks","fetch",{id:e});return this.withCache(r,"decks",t,async()=>{let{query:s}=o.fetchDeckById();return (await this.connection.execute(s,{id:e})).fetchDeck??null})}async fetchByExternalRef(e,t={}){let r=this.cacheKey("decks","fetchByExternalRef",{externalRef:e});return this.withCache(r,"decks",t,async()=>{let{query:s}=o.fetchDeckByExternalRef();return (await this.connection.execute(s,{externalRef:e})).fetchDeckByExternalRef??null})}async listMine(e={}){let{query:t,variables:r}=o.listMyDecks({first:e.first,after:e.after}),s=this.cacheKey("decks","listMine",r),i=await this.withCache(s,"decks",e,async()=>(await this.connection.execute(t,r)).myDecks);return new l(i,{nextPageLoader:async a=>this.listMine({...e,after:a})})}async create(e){let{query:t}=o.createDeck(),r=o.deckCreateVariables(e);return (await this.connection.execute(t,r)).deckCreate}async update(e,t){let{query:r}=o.updateDeck(),s=o.deckUpdateVariables(e,t);return (await this.connection.execute(r,s)).deckUpdate}async delete(e){let{query:t}=o.deleteDeck();return !!(await this.connection.execute(t,{id:e})).deckDelete}async hydrateEntries(e){if(e.entries.length===0)return [];let t=this.resolvePublisher(e.publisherSlug),r=this.resolveGame(e.gameKey);this.validateAccess(t,r);let s=e.entries.map(c=>c.identifier),i=this.cacheKey("decks","hydrateEntries",{publisherSlug:t,gameKey:r,datasetKey:e.datasetKey,identifiers:s}),a=await this.withCache(i,"decks",e,async()=>{let{query:c}=o.fetchRecordsByIdentifier();return (await this.connection.execute(c,{publisherSlug:t,gameKey:r,datasetKey:e.datasetKey,identifiers:s})).fetchRecordsByIdentifier}),n=ce(a,s,e.identifierField);return e.entries.map(c=>({...c,record:n.get(c.identifier)??null}))}};function ce(e,t,r){let s=new Set(t),i=new Map;for(let a of e){let n=r?a.data[r]:Object.values(a.data).find(h=>s.has(String(h)));if(n==null)continue;let c=String(n);s.has(c)&&(i.set(c,a),s.delete(c));}return i}var oe=class extends f{constructor(e,t){super(e,t);}async search(e){let t=this.resolvePublisher(e.publisherSlug),r=this.resolveGame(e.gameKey);this.validateAccess(t,r);let s=E(e.filter),{query:i,variables:a}=o.searchRecords({publisherSlug:t,gameKey:r,datasetKey:e.datasetKey,filter:s,search:e.search,orderBy:e.orderBy,resolveLinks:e.resolveLinks,first:e.first,after:e.after,validateSchema:e.validateSchema}),n=this.cacheKey("records","search",a),c=await this.withCache(n,"records",e,async()=>(await this.connection.execute(i,a)).searchRecords);return new l(c,{nextPageLoader:async h=>this.search({...e,after:h})})}async get(e,t={}){let r=this.cacheKey("records","get",{id:e});return this.withCache(r,"records",t,async()=>{let{query:s}=o.fetchRecordById();return (await this.connection.execute(s,{id:e})).fetchRecord??null})}async getByIdentifier(e){let t=this.resolvePublisher(e.publisherSlug),r=this.resolveGame(e.gameKey);this.validateAccess(t,r);let s=this.cacheKey("records","getByIdentifier",{publisherSlug:t,gameKey:r,datasetKey:e.datasetKey,identifier:e.identifier});return this.withCache(s,"records",e,async()=>{let{query:i}=o.fetchRecordByIdentifier();return (await this.connection.execute(i,{publisherSlug:t,gameKey:r,datasetKey:e.datasetKey,identifier:e.identifier})).fetchRecordByIdentifier??null})}async getManyByIdentifier(e){if(e.identifiers.length===0)return [];let t=this.resolvePublisher(e.publisherSlug),r=this.resolveGame(e.gameKey);this.validateAccess(t,r);let s=this.cacheKey("records","getManyByIdentifier",{publisherSlug:t,gameKey:r,datasetKey:e.datasetKey,identifiers:e.identifiers});return this.withCache(s,"records",e,async()=>{let{query:i}=o.fetchRecordsByIdentifier();return (await this.connection.execute(i,{publisherSlug:t,gameKey:r,datasetKey:e.datasetKey,identifiers:e.identifiers})).fetchRecordsByIdentifier??[]})}async getMany(e,t={}){if(e.length===0)return [];let r=this.cacheKey("records","getMany",{ids:e});return this.withCache(r,"records",t,async()=>{let{query:s}=o.fetchRecords();return (await this.connection.execute(s,{ids:e})).fetchRecords??[]})}},he=class extends f{constructor(e,t){super(e,t);}async datasets(e={}){let t=this.resolvePublisher(e.publisherSlug),r=this.resolveGame(e.gameKey);this.validateAccess(t,r);let{query:s,variables:i}=o.searchDatasets({publisherSlug:t,gameKey:r,search:e.search,purpose:"RULES",first:e.first,after:e.after}),a=this.cacheKey("rules","datasets",i),n=await this.withCache(a,"datasets",e,async()=>(await this.connection.execute(s,i)).searchDatasets);return new l(n,{nextPageLoader:async c=>this.datasets({...e,after:c})})}async list(e={}){return this.searchRuleRecords("rules",e)}async formats(e={}){return this.searchRuleRecords(e.datasetKey??"formats",e)}async searchRuleRecords(e,t){let r=this.resolvePublisher(t.publisherSlug),s=this.resolveGame(t.gameKey),i=t.datasetKey??e;this.validateAccess(r,s);let a=E(t.filter),{query:n,variables:c}=o.searchRecords({publisherSlug:r,gameKey:s,datasetKey:i,filter:a,search:t.search,orderBy:t.orderBy,resolveLinks:t.resolveLinks,first:t.first,after:t.after,validateSchema:t.validateSchema}),h=this.cacheKey("rules","records",c),I=await this.withCache(h,"records",t,async()=>(await this.connection.execute(n,c)).searchRecords);return new l(I,{nextPageLoader:async K=>this.searchRuleRecords(e,{...t,after:K})})}},Ue=class G{config;connection;publishers;games;datasets;records;decks;rules;constructor(t={}){this.config=new J(t),this.connection=new Z(this.config),this.publishers=new se(this.connection,this.config),this.games=new ie(this.connection,this.config),this.datasets=new ae(this.connection,this.config),this.records=new oe(this.connection,this.config),this.decks=new ne(this.connection,this.config),this.rules=new he(this.connection,this.config);}async me(){let{query:t}=o.fetchMe();return (await this.connection.execute(t)).fetchMe??null}getRateLimitInfo(){return z()}withConfig(t){let r=this.config.merge(t);return new G({apiKey:r.apiKey,endpoint:r.endpoint,timeout:r.timeout,openTimeout:r.openTimeout,defaultPublisher:r.defaultPublisher,defaultGame:r.defaultGame,allowedPublishers:r.allowedPublishers,allowedGames:r.allowedGames,logger:r.logger,logLevel:r.logLevel,retryOnRateLimit:r.retryOnRateLimit,maxRetries:r.maxRetries,retryOnNetworkError:r.retryOnNetworkError,maxNetworkRetries:r.maxNetworkRetries,retryBaseDelay:r.retryBaseDelay,retryMaxDelay:r.retryMaxDelay,cache:r.cache,cacheTtl:r.cacheTtl,cacheTtls:r.cacheTtls})}};
329
+ export{R as AuthenticationError,f as BaseResource,$ as BrowserCache,Ue as CardDBClient,u as CardDBError,l as Collection,J as Configuration,Z as Connection,w as ConnectionError,O as DEFAULT_CACHE_TTL,U as DEFAULT_ENDPOINT,V as DEFAULT_MAX_NETWORK_RETRIES,j as DEFAULT_MAX_RETRIES,_ as DEFAULT_OPEN_TIMEOUT,X as DEFAULT_RETRY_BASE_DELAY,Q as DEFAULT_RETRY_MAX_DELAY,M as DEFAULT_TIMEOUT,ae as DatasetsResource,ne as DecksResource,F as FilterBuilder,ie as GamesResource,B as GraphQLError,de as LinkResolutionError,le as NotFoundError,se as PublishersResource,o as QueryBuilder,b as RateLimitError,oe as RecordsResource,x as RestrictedError,he as RulesResource,D as ServerError,S as TimeoutError,k as ValidationError,ee as cacheKey,$e as contains,fe as eq,z as getRateLimitInfo,Ne as getSDKVersion,Y as getUserAgent,ge as gt,me as gte,ke as ilike,Se as isNotNull,xe as isNull,Re as like,we as lt,pe as lte,ye as neq,be as notWithin,te as readCache,E as resolveFilter,ve as within,re as writeCache};//# sourceMappingURL=index.js.map
330
+ //# sourceMappingURL=index.js.map