@carddb/core 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/dist/index.js ADDED
@@ -0,0 +1,1123 @@
1
+ // src/errors.ts
2
+ var CardDBError = class _CardDBError extends Error {
3
+ /** The full response body if available */
4
+ response;
5
+ constructor(message, response) {
6
+ super(message);
7
+ this.name = "CardDBError";
8
+ this.response = response;
9
+ if (Error.captureStackTrace) {
10
+ Error.captureStackTrace(this, _CardDBError);
11
+ }
12
+ }
13
+ };
14
+ var AuthenticationError = class extends CardDBError {
15
+ constructor(message = "Invalid or missing API key", response) {
16
+ super(message, response);
17
+ this.name = "AuthenticationError";
18
+ }
19
+ };
20
+ var RateLimitError = class extends CardDBError {
21
+ /** Seconds until rate limit resets */
22
+ retryAfter;
23
+ /** Maximum requests allowed */
24
+ limit;
25
+ /** Remaining requests in window */
26
+ remaining;
27
+ /** Time when the rate limit resets */
28
+ resetAt;
29
+ constructor(message = "Rate limit exceeded", options = {}) {
30
+ super(message, options.response);
31
+ this.name = "RateLimitError";
32
+ this.retryAfter = options.retryAfter ?? null;
33
+ this.limit = options.limit ?? null;
34
+ this.remaining = options.remaining ?? null;
35
+ this.resetAt = options.resetAt ?? null;
36
+ }
37
+ };
38
+ var NotFoundError = class extends CardDBError {
39
+ constructor(message = "Resource not found", response) {
40
+ super(message, response);
41
+ this.name = "NotFoundError";
42
+ }
43
+ };
44
+ var ValidationError = class extends CardDBError {
45
+ /** List of validation errors */
46
+ errors;
47
+ constructor(message = "Validation error", options = {}) {
48
+ super(message, options.response);
49
+ this.name = "ValidationError";
50
+ this.errors = options.errors ?? [];
51
+ }
52
+ };
53
+ var RestrictedError = class extends CardDBError {
54
+ constructor(message, response) {
55
+ super(message, response);
56
+ this.name = "RestrictedError";
57
+ }
58
+ };
59
+ var GraphQLError = class extends CardDBError {
60
+ /** List of GraphQL errors */
61
+ errors;
62
+ constructor(message = "GraphQL error", options = {}) {
63
+ super(message, options.response);
64
+ this.name = "GraphQLError";
65
+ this.errors = options.errors ?? [];
66
+ }
67
+ };
68
+ var ConnectionError = class extends CardDBError {
69
+ constructor(message = "Connection error", response) {
70
+ super(message, response);
71
+ this.name = "ConnectionError";
72
+ }
73
+ };
74
+ var TimeoutError = class extends ConnectionError {
75
+ constructor(message = "Request timed out", response) {
76
+ super(message, response);
77
+ this.name = "TimeoutError";
78
+ }
79
+ };
80
+ var ServerError = class extends CardDBError {
81
+ /** HTTP status code */
82
+ status;
83
+ constructor(message = "Server error", options = {}) {
84
+ super(message, options.response);
85
+ this.name = "ServerError";
86
+ this.status = options.status ?? null;
87
+ }
88
+ };
89
+ var LinkResolutionError = class extends CardDBError {
90
+ /** List of link resolution failures */
91
+ failures;
92
+ /** Partial results that were successfully resolved */
93
+ partialResults;
94
+ constructor(message = "Some links could not be resolved", options = {}) {
95
+ super(message, options.response);
96
+ this.name = "LinkResolutionError";
97
+ this.failures = options.failures ?? [];
98
+ this.partialResults = options.partialResults;
99
+ }
100
+ /**
101
+ * Get failures for a specific field
102
+ */
103
+ getFailuresForField(field) {
104
+ return this.failures.filter((f) => f.field === field);
105
+ }
106
+ /**
107
+ * Check if a specific field had resolution failures
108
+ */
109
+ hasFailuresForField(field) {
110
+ return this.failures.some((f) => f.field === field);
111
+ }
112
+ };
113
+
114
+ // src/operators.ts
115
+ function eq(value) {
116
+ return { eq: value };
117
+ }
118
+ function neq(value) {
119
+ return { neq: value };
120
+ }
121
+ function gt(value) {
122
+ return { gt: value };
123
+ }
124
+ function gte(value) {
125
+ return { gte: value };
126
+ }
127
+ function lt(value) {
128
+ return { lt: value };
129
+ }
130
+ function lte(value) {
131
+ return { lte: value };
132
+ }
133
+ function within(values) {
134
+ return { in: values };
135
+ }
136
+ function notWithin(values) {
137
+ return { nin: values };
138
+ }
139
+ function contains(value) {
140
+ return { contains: value };
141
+ }
142
+ function like(pattern) {
143
+ return { like: pattern };
144
+ }
145
+ function ilike(pattern) {
146
+ return { ilike: pattern };
147
+ }
148
+ function isNull() {
149
+ return { is_null: true };
150
+ }
151
+ function isNotNull() {
152
+ return { is_null: false };
153
+ }
154
+
155
+ // src/filter-builder.ts
156
+ var FilterBuilder = class _FilterBuilder {
157
+ conditions = [];
158
+ orGroups = [];
159
+ where(fieldOrConditions, value) {
160
+ if (typeof fieldOrConditions === "string") {
161
+ this.conditions.push({ [fieldOrConditions]: value });
162
+ } else {
163
+ for (const [field, val] of Object.entries(fieldOrConditions)) {
164
+ this.conditions.push({ [field]: val });
165
+ }
166
+ }
167
+ return this;
168
+ }
169
+ /**
170
+ * Add an OR group (any of the conditions must match)
171
+ *
172
+ * @example
173
+ * .where('type', 'creature')
174
+ * .any(or => or
175
+ * .where('color', 'red')
176
+ * .where('color', 'blue')
177
+ * )
178
+ */
179
+ any(callback) {
180
+ const orBuilder = new _FilterBuilder();
181
+ callback(orBuilder);
182
+ const orConditions = orBuilder.getConditions();
183
+ if (orConditions.length > 0) {
184
+ this.orGroups.push({ $or: orConditions });
185
+ }
186
+ return this;
187
+ }
188
+ /**
189
+ * Add a link filter condition (filter on linked records)
190
+ *
191
+ * @example
192
+ * .whereLink('set_id', { code: 'DMU' })
193
+ * .whereLink('set_id', { name: ilike('%dominaria%') })
194
+ */
195
+ whereLink(field, conditions) {
196
+ const linkFilter = {};
197
+ for (const [key, val] of Object.entries(conditions)) {
198
+ linkFilter[key] = val;
199
+ }
200
+ this.conditions.push({ [`${field}._link`]: linkFilter });
201
+ return this;
202
+ }
203
+ /**
204
+ * Add an array element filter (for ARRAY of HASH fields)
205
+ * Matches if any element in the array matches all conditions
206
+ *
207
+ * @example
208
+ * .whereAny('attacks', { damage: gte(50) })
209
+ * .whereAny('attacks', { name: ilike('%thunder%') })
210
+ */
211
+ whereAny(field, conditions) {
212
+ const anyFilter = {};
213
+ for (const [key, val] of Object.entries(conditions)) {
214
+ anyFilter[key] = val;
215
+ }
216
+ this.conditions.push({ [`${field}._any`]: anyFilter });
217
+ return this;
218
+ }
219
+ /**
220
+ * Get the conditions array (used internally for OR groups)
221
+ */
222
+ getConditions() {
223
+ return this.conditions;
224
+ }
225
+ /**
226
+ * Build the final filter object
227
+ */
228
+ build() {
229
+ const allConditions = [...this.conditions, ...this.orGroups];
230
+ if (allConditions.length === 0) {
231
+ return {};
232
+ }
233
+ if (allConditions.length === 1) {
234
+ return allConditions[0];
235
+ }
236
+ return { $and: allConditions };
237
+ }
238
+ };
239
+ function resolveFilter(input) {
240
+ if (input === void 0) {
241
+ return void 0;
242
+ }
243
+ if (typeof input === "function") {
244
+ const builder = new FilterBuilder();
245
+ input(builder);
246
+ const result = builder.build();
247
+ return Object.keys(result).length > 0 ? result : void 0;
248
+ }
249
+ return Object.keys(input).length > 0 ? input : void 0;
250
+ }
251
+
252
+ // src/query-builder.ts
253
+ var PUBLISHER_FIELDS = `
254
+ id
255
+ name
256
+ slug
257
+ status
258
+ description
259
+ website
260
+ createdAt
261
+ updatedAt
262
+ logoFile {
263
+ id
264
+ url
265
+ }
266
+ bannerFile {
267
+ id
268
+ url
269
+ }
270
+ `;
271
+ var GAME_FIELDS = `
272
+ id
273
+ publisherId
274
+ key
275
+ name
276
+ description
277
+ website
278
+ visibility
279
+ isArchived
280
+ createdAt
281
+ updatedAt
282
+ publisher {
283
+ id
284
+ name
285
+ slug
286
+ }
287
+ logoFile {
288
+ id
289
+ url
290
+ }
291
+ coverFile {
292
+ id
293
+ url
294
+ }
295
+ `;
296
+ var DATASET_FIELDS = `
297
+ id
298
+ publisherId
299
+ gameId
300
+ key
301
+ name
302
+ description
303
+ purpose
304
+ visibility
305
+ isArchived
306
+ createdAt
307
+ updatedAt
308
+ publisher {
309
+ id
310
+ name
311
+ slug
312
+ }
313
+ game {
314
+ id
315
+ key
316
+ name
317
+ }
318
+ `;
319
+ var SCHEMA_FIELDS = `
320
+ schema {
321
+ fields {
322
+ key
323
+ label
324
+ description
325
+ type
326
+ isRequired
327
+ filterable
328
+ searchable
329
+ isIdentifier
330
+ itemType
331
+ displayFormat
332
+ allowedValues
333
+ nestedFields {
334
+ key
335
+ label
336
+ description
337
+ type
338
+ isRequired
339
+ filterable
340
+ searchable
341
+ itemType
342
+ }
343
+ }
344
+ filterableFields
345
+ searchableFields
346
+ linkFields {
347
+ key
348
+ label
349
+ targetDatasetKey
350
+ targetDatasetName
351
+ targetDatasetId
352
+ }
353
+ }
354
+ `;
355
+ var RECORD_FIELDS = `
356
+ id
357
+ datasetId
358
+ data
359
+ createdAt
360
+ updatedAt
361
+ dataset {
362
+ id
363
+ key
364
+ name
365
+ gameId
366
+ publisherId
367
+ }
368
+ `;
369
+ var DECK_FIELDS = `
370
+ id
371
+ accountId
372
+ apiApplicationId
373
+ gameId
374
+ title
375
+ description
376
+ formatKey
377
+ visibility
378
+ externalRef
379
+ sourceUrl
380
+ metadata
381
+ createdAt
382
+ updatedAt
383
+ game {
384
+ ${GAME_FIELDS}
385
+ }
386
+ entries {
387
+ id
388
+ datasetId
389
+ recordId
390
+ identifier
391
+ quantity
392
+ section
393
+ sortOrder
394
+ annotations
395
+ record {
396
+ ${RECORD_FIELDS}
397
+ }
398
+ }
399
+ `;
400
+ var RESOLVED_LINKS_FIELDS = `
401
+ resolvedLinks {
402
+ field
403
+ linkFieldKey
404
+ values
405
+ records {
406
+ id
407
+ datasetId
408
+ data
409
+ }
410
+ }
411
+ `;
412
+ function connectionFields(nodeFields) {
413
+ return `
414
+ totalCount
415
+ pageInfo {
416
+ hasNextPage
417
+ hasPreviousPage
418
+ startCursor
419
+ endCursor
420
+ }
421
+ edges {
422
+ cursor
423
+ node {
424
+ ${nodeFields}
425
+ }
426
+ }
427
+ `;
428
+ }
429
+ var QueryBuilder = {
430
+ // Publishers
431
+ searchPublishers(params = {}) {
432
+ const variables = {};
433
+ const args = [];
434
+ const defs = [];
435
+ if (params.search !== void 0) {
436
+ defs.push("$search: String");
437
+ args.push("search: $search");
438
+ variables["search"] = params.search;
439
+ }
440
+ if (params.first !== void 0) {
441
+ defs.push("$first: Int");
442
+ args.push("first: $first");
443
+ variables["first"] = params.first;
444
+ }
445
+ if (params.after !== void 0) {
446
+ defs.push("$after: String");
447
+ args.push("after: $after");
448
+ variables["after"] = params.after;
449
+ }
450
+ const defStr = defs.length > 0 ? `(${defs.join(", ")})` : "";
451
+ const argStr = args.length > 0 ? `(${args.join(", ")})` : "";
452
+ return {
453
+ query: `
454
+ query SearchPublishers${defStr} {
455
+ searchPublishers${argStr} {
456
+ ${connectionFields(PUBLISHER_FIELDS)}
457
+ }
458
+ }
459
+ `,
460
+ variables
461
+ };
462
+ },
463
+ fetchPublisherById() {
464
+ return {
465
+ query: `
466
+ query FetchPublisher($id: UUID!) {
467
+ fetchPublisher(id: $id) {
468
+ ${PUBLISHER_FIELDS}
469
+ }
470
+ }
471
+ `
472
+ };
473
+ },
474
+ fetchPublisherBySlug() {
475
+ return {
476
+ query: `
477
+ query FetchPublisher($slug: String!) {
478
+ fetchPublisher(slug: $slug) {
479
+ ${PUBLISHER_FIELDS}
480
+ }
481
+ }
482
+ `
483
+ };
484
+ },
485
+ fetchPublishers() {
486
+ return {
487
+ query: `
488
+ query FetchPublishers($slugs: [String!]!) {
489
+ fetchPublishers(slugs: $slugs) {
490
+ ${PUBLISHER_FIELDS}
491
+ }
492
+ }
493
+ `
494
+ };
495
+ },
496
+ // Games
497
+ searchGames(params = {}) {
498
+ const variables = {};
499
+ const args = [];
500
+ const defs = [];
501
+ if (params.publisherSlug !== void 0) {
502
+ defs.push("$publisherSlug: String");
503
+ args.push("publisherSlug: $publisherSlug");
504
+ variables["publisherSlug"] = params.publisherSlug;
505
+ }
506
+ if (params.search !== void 0) {
507
+ defs.push("$search: String");
508
+ args.push("search: $search");
509
+ variables["search"] = params.search;
510
+ }
511
+ if (params.first !== void 0) {
512
+ defs.push("$first: Int");
513
+ args.push("first: $first");
514
+ variables["first"] = params.first;
515
+ }
516
+ if (params.after !== void 0) {
517
+ defs.push("$after: String");
518
+ args.push("after: $after");
519
+ variables["after"] = params.after;
520
+ }
521
+ const defStr = defs.length > 0 ? `(${defs.join(", ")})` : "";
522
+ const argStr = args.length > 0 ? `(${args.join(", ")})` : "";
523
+ return {
524
+ query: `
525
+ query SearchGames${defStr} {
526
+ searchGames${argStr} {
527
+ ${connectionFields(GAME_FIELDS)}
528
+ }
529
+ }
530
+ `,
531
+ variables
532
+ };
533
+ },
534
+ fetchGameById() {
535
+ return {
536
+ query: `
537
+ query FetchGame($id: UUID!) {
538
+ fetchGame(id: $id) {
539
+ ${GAME_FIELDS}
540
+ }
541
+ }
542
+ `
543
+ };
544
+ },
545
+ fetchGameByKeys() {
546
+ return {
547
+ query: `
548
+ query FetchGame($publisherSlug: String!, $gameKey: String!) {
549
+ fetchGame(publisherSlug: $publisherSlug, gameKey: $gameKey) {
550
+ ${GAME_FIELDS}
551
+ }
552
+ }
553
+ `
554
+ };
555
+ },
556
+ fetchGames() {
557
+ return {
558
+ query: `
559
+ query FetchGames($ids: [UUID!]!) {
560
+ fetchGames(ids: $ids) {
561
+ ${GAME_FIELDS}
562
+ }
563
+ }
564
+ `
565
+ };
566
+ },
567
+ // Datasets
568
+ searchDatasets(params = {}) {
569
+ const variables = {};
570
+ const args = [];
571
+ const defs = [];
572
+ if (params.publisherSlug !== void 0) {
573
+ defs.push("$publisherSlug: String");
574
+ args.push("publisherSlug: $publisherSlug");
575
+ variables["publisherSlug"] = params.publisherSlug;
576
+ }
577
+ if (params.gameKey !== void 0) {
578
+ defs.push("$gameKey: String");
579
+ args.push("gameKey: $gameKey");
580
+ variables["gameKey"] = params.gameKey;
581
+ }
582
+ if (params.search !== void 0) {
583
+ defs.push("$search: String");
584
+ args.push("search: $search");
585
+ variables["search"] = params.search;
586
+ }
587
+ if (params.purpose !== void 0) {
588
+ defs.push("$purpose: DatasetPurpose");
589
+ args.push("purpose: $purpose");
590
+ variables["purpose"] = params.purpose;
591
+ }
592
+ if (params.first !== void 0) {
593
+ defs.push("$first: Int");
594
+ args.push("first: $first");
595
+ variables["first"] = params.first;
596
+ }
597
+ if (params.after !== void 0) {
598
+ defs.push("$after: String");
599
+ args.push("after: $after");
600
+ variables["after"] = params.after;
601
+ }
602
+ const defStr = defs.length > 0 ? `(${defs.join(", ")})` : "";
603
+ const argStr = args.length > 0 ? `(${args.join(", ")})` : "";
604
+ return {
605
+ query: `
606
+ query SearchDatasets${defStr} {
607
+ searchDatasets${argStr} {
608
+ ${connectionFields(DATASET_FIELDS)}
609
+ }
610
+ }
611
+ `,
612
+ variables
613
+ };
614
+ },
615
+ fetchDatasetById() {
616
+ return {
617
+ query: `
618
+ query FetchDataset($id: UUID!) {
619
+ fetchDataset(id: $id) {
620
+ ${DATASET_FIELDS}
621
+ ${SCHEMA_FIELDS}
622
+ }
623
+ }
624
+ `
625
+ };
626
+ },
627
+ fetchDatasetByKeys() {
628
+ return {
629
+ query: `
630
+ query FetchDataset($publisherSlug: String!, $gameKey: String!, $datasetKey: String!) {
631
+ fetchDataset(publisherSlug: $publisherSlug, gameKey: $gameKey, datasetKey: $datasetKey) {
632
+ ${DATASET_FIELDS}
633
+ ${SCHEMA_FIELDS}
634
+ }
635
+ }
636
+ `
637
+ };
638
+ },
639
+ fetchDatasets() {
640
+ return {
641
+ query: `
642
+ query FetchDatasets($ids: [UUID!]!) {
643
+ fetchDatasets(ids: $ids) {
644
+ ${DATASET_FIELDS}
645
+ }
646
+ }
647
+ `
648
+ };
649
+ },
650
+ // Records
651
+ searchRecords(params) {
652
+ const variables = {
653
+ publisherSlug: params.publisherSlug,
654
+ gameKey: params.gameKey,
655
+ datasetKey: params.datasetKey
656
+ };
657
+ const args = [
658
+ "publisherSlug: $publisherSlug",
659
+ "gameKey: $gameKey",
660
+ "datasetKey: $datasetKey"
661
+ ];
662
+ const defs = ["$publisherSlug: String!", "$gameKey: String!", "$datasetKey: String!"];
663
+ if (params.filter !== void 0) {
664
+ defs.push("$filter: JSON");
665
+ args.push("filter: $filter");
666
+ variables["filter"] = params.filter;
667
+ }
668
+ if (params.search !== void 0) {
669
+ defs.push("$search: String");
670
+ args.push("search: $search");
671
+ variables["search"] = params.search;
672
+ }
673
+ if (params.orderBy !== void 0) {
674
+ defs.push("$orderBy: String");
675
+ args.push("orderBy: $orderBy");
676
+ variables["orderBy"] = params.orderBy;
677
+ }
678
+ if (params.resolveLinks !== void 0) {
679
+ defs.push("$resolveLinks: [String!]");
680
+ args.push("resolveLinks: $resolveLinks");
681
+ variables["resolveLinks"] = params.resolveLinks;
682
+ }
683
+ if (params.first !== void 0) {
684
+ defs.push("$first: Int");
685
+ args.push("first: $first");
686
+ variables["first"] = params.first;
687
+ }
688
+ if (params.after !== void 0) {
689
+ defs.push("$after: String");
690
+ args.push("after: $after");
691
+ variables["after"] = params.after;
692
+ }
693
+ if (params.validateSchema !== void 0) {
694
+ defs.push("$validateSchema: Boolean");
695
+ args.push("validateSchema: $validateSchema");
696
+ variables["validateSchema"] = params.validateSchema;
697
+ }
698
+ const includeResolvedLinks = params.resolveLinks && params.resolveLinks.length > 0;
699
+ const nodeFields = includeResolvedLinks ? `${RECORD_FIELDS}
700
+ ${RESOLVED_LINKS_FIELDS}` : RECORD_FIELDS;
701
+ return {
702
+ query: `
703
+ query SearchRecords(${defs.join(", ")}) {
704
+ searchRecords(${args.join(", ")}) {
705
+ ${connectionFields(nodeFields)}
706
+ }
707
+ }
708
+ `,
709
+ variables
710
+ };
711
+ },
712
+ fetchRecordById() {
713
+ return {
714
+ query: `
715
+ query FetchRecord($id: UUID!) {
716
+ fetchRecord(id: $id) {
717
+ ${RECORD_FIELDS}
718
+ }
719
+ }
720
+ `
721
+ };
722
+ },
723
+ fetchRecordByIdentifier() {
724
+ return {
725
+ query: `
726
+ query FetchRecordByIdentifier($publisherSlug: String!, $gameKey: String!, $datasetKey: String!, $identifier: String!) {
727
+ fetchRecordByIdentifier(publisherSlug: $publisherSlug, gameKey: $gameKey, datasetKey: $datasetKey, identifier: $identifier) {
728
+ ${RECORD_FIELDS}
729
+ }
730
+ }
731
+ `
732
+ };
733
+ },
734
+ fetchRecordsByIdentifier() {
735
+ return {
736
+ query: `
737
+ query FetchRecordsByIdentifier($publisherSlug: String!, $gameKey: String!, $datasetKey: String!, $identifiers: [String!]!) {
738
+ fetchRecordsByIdentifier(publisherSlug: $publisherSlug, gameKey: $gameKey, datasetKey: $datasetKey, identifiers: $identifiers) {
739
+ ${RECORD_FIELDS}
740
+ }
741
+ }
742
+ `
743
+ };
744
+ },
745
+ fetchRecords() {
746
+ return {
747
+ query: `
748
+ query FetchRecords($ids: [UUID!]!) {
749
+ fetchRecords(ids: $ids) {
750
+ ${RECORD_FIELDS}
751
+ }
752
+ }
753
+ `
754
+ };
755
+ },
756
+ // Decks
757
+ listMyDecks(params = {}) {
758
+ const variables = {};
759
+ const args = [];
760
+ const defs = [];
761
+ if (params.first !== void 0) {
762
+ defs.push("$first: Int");
763
+ args.push("first: $first");
764
+ variables["first"] = params.first;
765
+ }
766
+ if (params.after !== void 0) {
767
+ defs.push("$after: String");
768
+ args.push("after: $after");
769
+ variables["after"] = params.after;
770
+ }
771
+ const defStr = defs.length > 0 ? `(${defs.join(", ")})` : "";
772
+ const argStr = args.length > 0 ? `(${args.join(", ")})` : "";
773
+ return {
774
+ query: `
775
+ query MyDecks${defStr} {
776
+ myDecks${argStr} {
777
+ ${connectionFields(DECK_FIELDS)}
778
+ }
779
+ }
780
+ `,
781
+ variables
782
+ };
783
+ },
784
+ fetchDeckById() {
785
+ return {
786
+ query: `
787
+ query FetchDeck($id: UUID!) {
788
+ fetchDeck(id: $id) {
789
+ ${DECK_FIELDS}
790
+ }
791
+ }
792
+ `
793
+ };
794
+ },
795
+ fetchDeckByExternalRef() {
796
+ return {
797
+ query: `
798
+ query FetchDeckByExternalRef($externalRef: String!) {
799
+ fetchDeckByExternalRef(externalRef: $externalRef) {
800
+ ${DECK_FIELDS}
801
+ }
802
+ }
803
+ `
804
+ };
805
+ },
806
+ createDeck() {
807
+ return {
808
+ query: `
809
+ mutation DeckCreate($input: DeckCreateInput!) {
810
+ deckCreate(input: $input) {
811
+ ${DECK_FIELDS}
812
+ }
813
+ }
814
+ `
815
+ };
816
+ },
817
+ updateDeck() {
818
+ return {
819
+ query: `
820
+ mutation DeckUpdate($id: UUID!, $input: DeckUpdateInput!) {
821
+ deckUpdate(id: $id, input: $input) {
822
+ ${DECK_FIELDS}
823
+ }
824
+ }
825
+ `
826
+ };
827
+ },
828
+ deleteDeck() {
829
+ return {
830
+ query: `
831
+ mutation DeckDelete($id: UUID!) {
832
+ deckDelete(id: $id)
833
+ }
834
+ `
835
+ };
836
+ },
837
+ deckCreateVariables(input) {
838
+ return { input };
839
+ },
840
+ deckUpdateVariables(id, input) {
841
+ return { id, input };
842
+ },
843
+ // API Key Info
844
+ fetchMe() {
845
+ return {
846
+ query: `
847
+ query FetchMe {
848
+ fetchMe {
849
+ application {
850
+ id
851
+ name
852
+ description
853
+ environment
854
+ apiKeyPrefix
855
+ allowedOrigins
856
+ allowedIps
857
+ createdAt
858
+ updatedAt
859
+ lastUsedAt
860
+ }
861
+ account {
862
+ id
863
+ displayName
864
+ createdAt
865
+ }
866
+ }
867
+ }
868
+ `
869
+ };
870
+ }
871
+ };
872
+
873
+ // src/collection.ts
874
+ var Collection = class {
875
+ /** Total count of matching records across all pages */
876
+ totalCount;
877
+ /** Pagination info */
878
+ pageInfo;
879
+ /** Items in the current page */
880
+ items;
881
+ /** Function to load the next page */
882
+ nextPageLoader;
883
+ constructor(data, options = {}) {
884
+ this.totalCount = data.totalCount;
885
+ this.pageInfo = data.pageInfo;
886
+ this.items = data.edges.map(
887
+ (edge) => options.itemTransformer ? options.itemTransformer(edge.node) : edge.node
888
+ );
889
+ this.nextPageLoader = options.nextPageLoader;
890
+ }
891
+ /** Check if there are more pages */
892
+ get hasNextPage() {
893
+ return this.pageInfo.hasNextPage;
894
+ }
895
+ /** Check if there are previous pages */
896
+ get hasPreviousPage() {
897
+ return this.pageInfo.hasPreviousPage;
898
+ }
899
+ /** Get the cursor for the next page */
900
+ get endCursor() {
901
+ return this.pageInfo.endCursor;
902
+ }
903
+ /** Get the cursor for the previous page */
904
+ get startCursor() {
905
+ return this.pageInfo.startCursor;
906
+ }
907
+ /** Number of items in the current page */
908
+ get length() {
909
+ return this.items.length;
910
+ }
911
+ /** Check if the current page is empty */
912
+ get isEmpty() {
913
+ return this.items.length === 0;
914
+ }
915
+ /** Get the first item */
916
+ get first() {
917
+ return this.items[0];
918
+ }
919
+ /** Get the last item */
920
+ get last() {
921
+ return this.items[this.items.length - 1];
922
+ }
923
+ /**
924
+ * Fetch the next page of results
925
+ *
926
+ * @returns The next page collection, or null if no more pages
927
+ * @throws Error if no next page loader is configured
928
+ */
929
+ async nextPage() {
930
+ if (!this.hasNextPage) {
931
+ return null;
932
+ }
933
+ if (!this.nextPageLoader) {
934
+ throw new Error("No next page loader configured");
935
+ }
936
+ if (!this.endCursor) {
937
+ return null;
938
+ }
939
+ return this.nextPageLoader(this.endCursor);
940
+ }
941
+ /**
942
+ * Async iterator that automatically paginates through all results
943
+ *
944
+ * @example
945
+ * for await (const record of collection) {
946
+ * console.log(record.name)
947
+ * }
948
+ *
949
+ * @example
950
+ * const allRecords = []
951
+ * for await (const record of collection) {
952
+ * allRecords.push(record)
953
+ * }
954
+ */
955
+ async *[Symbol.asyncIterator]() {
956
+ let current = this;
957
+ while (current) {
958
+ for (const item of current.items) {
959
+ yield item;
960
+ }
961
+ if (!current.hasNextPage) {
962
+ break;
963
+ }
964
+ current = await current.nextPage();
965
+ }
966
+ }
967
+ /**
968
+ * Iterate through all results, calling a callback for each item
969
+ * Similar to Array.forEach but async and auto-paginating
970
+ *
971
+ * @example
972
+ * await collection.forEach(async (record) => {
973
+ * await processRecord(record)
974
+ * })
975
+ */
976
+ async forEach(callback) {
977
+ let index = 0;
978
+ for await (const item of this) {
979
+ await callback(item, index++);
980
+ }
981
+ }
982
+ /**
983
+ * Map over all results, returning a new array
984
+ * Auto-paginates through all pages
985
+ *
986
+ * @example
987
+ * const names = await collection.map(record => record.name)
988
+ */
989
+ async map(callback) {
990
+ const results = [];
991
+ let index = 0;
992
+ for await (const item of this) {
993
+ results.push(await callback(item, index++));
994
+ }
995
+ return results;
996
+ }
997
+ /**
998
+ * Filter results, returning items that match the predicate
999
+ * Auto-paginates through all pages
1000
+ *
1001
+ * @example
1002
+ * const rareCards = await collection.filter(card => card.rarity === 'rare')
1003
+ */
1004
+ async filter(predicate) {
1005
+ const results = [];
1006
+ let index = 0;
1007
+ for await (const item of this) {
1008
+ if (await predicate(item, index++)) {
1009
+ results.push(item);
1010
+ }
1011
+ }
1012
+ return results;
1013
+ }
1014
+ /**
1015
+ * Find the first item matching a predicate
1016
+ * Stops iterating once found
1017
+ *
1018
+ * @example
1019
+ * const pikachu = await collection.find(card => card.name === 'Pikachu')
1020
+ */
1021
+ async find(predicate) {
1022
+ let index = 0;
1023
+ for await (const item of this) {
1024
+ if (await predicate(item, index++)) {
1025
+ return item;
1026
+ }
1027
+ }
1028
+ return void 0;
1029
+ }
1030
+ /**
1031
+ * Take the first n items
1032
+ * Stops fetching pages once n items are collected
1033
+ *
1034
+ * @example
1035
+ * const first100 = await collection.take(100)
1036
+ */
1037
+ async take(n) {
1038
+ const results = [];
1039
+ for await (const item of this) {
1040
+ if (results.length >= n) {
1041
+ break;
1042
+ }
1043
+ results.push(item);
1044
+ }
1045
+ return results;
1046
+ }
1047
+ /**
1048
+ * Collect all items into an array
1049
+ * Auto-paginates through all pages
1050
+ *
1051
+ * @example
1052
+ * const allRecords = await collection.toArray()
1053
+ */
1054
+ async toArray() {
1055
+ const results = [];
1056
+ for await (const item of this) {
1057
+ results.push(item);
1058
+ }
1059
+ return results;
1060
+ }
1061
+ /**
1062
+ * Iterate in batches (similar to Rails find_in_batches)
1063
+ *
1064
+ * @example
1065
+ * for await (const batch of collection.batches()) {
1066
+ * await processBatch(batch)
1067
+ * }
1068
+ */
1069
+ async *batches() {
1070
+ let current = this;
1071
+ while (current) {
1072
+ if (current.items.length > 0) {
1073
+ yield current.items;
1074
+ }
1075
+ if (!current.hasNextPage) {
1076
+ break;
1077
+ }
1078
+ current = await current.nextPage();
1079
+ }
1080
+ }
1081
+ /**
1082
+ * Iterate one item at a time with batched fetching (similar to Rails find_each)
1083
+ *
1084
+ * @example
1085
+ * for await (const item of collection.each()) {
1086
+ * await processItem(item)
1087
+ * }
1088
+ */
1089
+ each() {
1090
+ return this;
1091
+ }
1092
+ };
1093
+ export {
1094
+ AuthenticationError,
1095
+ CardDBError,
1096
+ Collection,
1097
+ ConnectionError,
1098
+ FilterBuilder,
1099
+ GraphQLError,
1100
+ LinkResolutionError,
1101
+ NotFoundError,
1102
+ QueryBuilder,
1103
+ RateLimitError,
1104
+ RestrictedError,
1105
+ ServerError,
1106
+ TimeoutError,
1107
+ ValidationError,
1108
+ contains,
1109
+ eq,
1110
+ gt,
1111
+ gte,
1112
+ ilike,
1113
+ isNotNull,
1114
+ isNull,
1115
+ like,
1116
+ lt,
1117
+ lte,
1118
+ neq,
1119
+ notWithin,
1120
+ resolveFilter,
1121
+ within
1122
+ };
1123
+ //# sourceMappingURL=index.js.map