@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.
@@ -0,0 +1,840 @@
1
+ /**
2
+ * Core types for CardDB JavaScript clients
3
+ */
4
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
5
+ type ResourceType = 'publishers' | 'games' | 'datasets' | 'records' | 'decks';
6
+ interface Logger {
7
+ debug(message: string, ...args: unknown[]): void;
8
+ info(message: string, ...args: unknown[]): void;
9
+ warn(message: string, ...args: unknown[]): void;
10
+ error(message: string, ...args: unknown[]): void;
11
+ }
12
+ interface Cache {
13
+ get<T>(key: string): T | null | Promise<T | null>;
14
+ set<T>(key: string, value: T, ttl?: number): void | Promise<void>;
15
+ delete(key: string): void | Promise<void>;
16
+ clear?(): void | Promise<void>;
17
+ }
18
+ interface CardDBConfig {
19
+ /** API key for authentication (increases rate limits) */
20
+ apiKey?: string;
21
+ /** GraphQL endpoint URL (defaults to production) */
22
+ endpoint?: string;
23
+ /** Request timeout in milliseconds */
24
+ timeout?: number;
25
+ /** Connection open timeout in milliseconds */
26
+ openTimeout?: number;
27
+ /** Default publisher slug for queries */
28
+ defaultPublisher?: string;
29
+ /** Default game key for queries */
30
+ defaultGame?: string;
31
+ /** Allowed publisher slugs (undefined = all allowed) */
32
+ allowedPublishers?: string[];
33
+ /** Map of publisher slug to allowed game keys */
34
+ allowedGames?: Record<string, string[]>;
35
+ /** Logger instance for debug output */
36
+ logger?: Logger;
37
+ /** Log level threshold */
38
+ logLevel?: LogLevel;
39
+ /** Whether to automatically retry on rate limit errors */
40
+ retryOnRateLimit?: boolean;
41
+ /** Maximum number of retries on rate limit */
42
+ maxRetries?: number;
43
+ /** Whether to automatically retry on network errors (connection, timeout) */
44
+ retryOnNetworkError?: boolean;
45
+ /** Maximum number of retries for network errors */
46
+ maxNetworkRetries?: number;
47
+ /** Base delay in milliseconds for exponential backoff (default: 1000) */
48
+ retryBaseDelay?: number;
49
+ /** Maximum delay in milliseconds for exponential backoff (default: 30000) */
50
+ retryMaxDelay?: number;
51
+ /** Cache instance (must implement Cache interface) */
52
+ cache?: Cache;
53
+ /** Default cache TTL in seconds */
54
+ cacheTtl?: number;
55
+ /** Per-resource cache TTLs in seconds */
56
+ cacheTtls?: Partial<Record<ResourceType, number>>;
57
+ }
58
+ interface PageInfo {
59
+ hasNextPage: boolean;
60
+ hasPreviousPage: boolean;
61
+ startCursor: string | null;
62
+ endCursor: string | null;
63
+ }
64
+ interface Edge<T> {
65
+ cursor: string;
66
+ node: T;
67
+ }
68
+ interface Connection<T> {
69
+ totalCount: number;
70
+ pageInfo: PageInfo;
71
+ edges: Edge<T>[];
72
+ }
73
+ interface FileInfo {
74
+ id: string;
75
+ url: string;
76
+ }
77
+ type PublisherStatus = 'ACTIVE' | 'DEACTIVATED';
78
+ interface Publisher {
79
+ id: string;
80
+ name: string;
81
+ slug: string;
82
+ status: PublisherStatus;
83
+ description: string | null;
84
+ website: string | null;
85
+ logoFile: FileInfo | null;
86
+ bannerFile: FileInfo | null;
87
+ createdAt: string;
88
+ updatedAt: string;
89
+ }
90
+ interface PublisherRef {
91
+ id: string;
92
+ name: string;
93
+ slug: string;
94
+ }
95
+ interface Game {
96
+ id: string;
97
+ publisherId: string;
98
+ key: string;
99
+ name: string;
100
+ description: string | null;
101
+ website: string | null;
102
+ visibility: string;
103
+ isArchived: boolean;
104
+ publisher: PublisherRef | null;
105
+ logoFile: FileInfo | null;
106
+ coverFile: FileInfo | null;
107
+ createdAt: string;
108
+ updatedAt: string;
109
+ }
110
+ interface GameRef {
111
+ id: string;
112
+ key: string;
113
+ name: string;
114
+ }
115
+ interface Dataset {
116
+ id: string;
117
+ publisherId: string;
118
+ gameId: string;
119
+ key: string;
120
+ name: string;
121
+ description: string | null;
122
+ purpose: 'DATA' | 'RULES';
123
+ visibility: string;
124
+ isArchived: boolean;
125
+ publisher: PublisherRef | null;
126
+ game: GameRef | null;
127
+ schema: DatasetSchema | null;
128
+ createdAt: string;
129
+ updatedAt: string;
130
+ }
131
+ interface DatasetRef {
132
+ id: string;
133
+ key: string;
134
+ name: string;
135
+ gameId: string;
136
+ publisherId: string;
137
+ }
138
+ interface DatasetRecord {
139
+ id: string;
140
+ datasetId: string;
141
+ data: Record<string, unknown>;
142
+ dataset: DatasetRef | null;
143
+ resolvedLinks?: ResolvedLink[];
144
+ createdAt: string;
145
+ updatedAt: string;
146
+ }
147
+ type DeckVisibility = 'PRIVATE' | 'UNLISTED' | 'PUBLIC';
148
+ interface Deck {
149
+ id: string;
150
+ accountId: string;
151
+ apiApplicationId: string | null;
152
+ gameId: string;
153
+ game: Game;
154
+ title: string;
155
+ description: string | null;
156
+ formatKey: string | null;
157
+ visibility: DeckVisibility;
158
+ externalRef: string | null;
159
+ sourceUrl: string | null;
160
+ metadata: Record<string, unknown>;
161
+ entries: DeckEntry[];
162
+ createdAt: string;
163
+ updatedAt: string;
164
+ }
165
+ interface DeckEntry {
166
+ id: string;
167
+ datasetId: string;
168
+ recordId: string | null;
169
+ identifier: string;
170
+ quantity: number;
171
+ section: string;
172
+ sortOrder: number;
173
+ annotations: Record<string, unknown>;
174
+ record: DatasetRecord | null;
175
+ }
176
+ interface DeckEntryInput {
177
+ datasetKey: string;
178
+ identifier: string;
179
+ quantity: number;
180
+ section?: string;
181
+ sortOrder?: number;
182
+ annotations?: Record<string, unknown>;
183
+ }
184
+ interface DeckCreateInput {
185
+ publisherSlug: string;
186
+ gameKey: string;
187
+ title: string;
188
+ description?: string;
189
+ formatKey?: string;
190
+ visibility?: DeckVisibility;
191
+ externalRef?: string;
192
+ sourceUrl?: string;
193
+ metadata?: Record<string, unknown>;
194
+ entries: DeckEntryInput[];
195
+ }
196
+ interface DeckUpdateInput {
197
+ title?: string;
198
+ description?: string;
199
+ formatKey?: string;
200
+ visibility?: DeckVisibility;
201
+ externalRef?: string;
202
+ sourceUrl?: string;
203
+ metadata?: Record<string, unknown>;
204
+ entries?: DeckEntryInput[];
205
+ }
206
+ interface HydrateDeckEntryInput {
207
+ identifier: string;
208
+ quantity: number;
209
+ section?: string;
210
+ sortOrder?: number;
211
+ annotations?: Record<string, unknown>;
212
+ }
213
+ interface HydratedDeckEntry extends HydrateDeckEntryInput {
214
+ record: DatasetRecord | null;
215
+ }
216
+ interface ResolvedRecord {
217
+ id: string;
218
+ datasetId: string;
219
+ data: Record<string, unknown>;
220
+ }
221
+ interface ResolvedLink {
222
+ field: string;
223
+ linkFieldKey: string;
224
+ values: string[];
225
+ records: (ResolvedRecord | null)[];
226
+ }
227
+ type FieldType = 'STRING' | 'INTEGER' | 'FLOAT' | 'BOOLEAN' | 'DATE' | 'DATETIME' | 'URL' | 'IMAGE' | 'LINK' | 'ARRAY' | 'HASH';
228
+ interface FieldInfo {
229
+ key: string;
230
+ label: string | null;
231
+ description: string | null;
232
+ type: FieldType;
233
+ isRequired: boolean;
234
+ filterable: boolean;
235
+ searchable: boolean;
236
+ isIdentifier: boolean;
237
+ itemType: FieldType | null;
238
+ displayFormat: string | null;
239
+ allowedValues: string[] | null;
240
+ nestedFields: FieldInfo[] | null;
241
+ }
242
+ interface LinkFieldInfo {
243
+ key: string;
244
+ label: string | null;
245
+ targetDatasetKey: string;
246
+ targetDatasetName: string | null;
247
+ targetDatasetId: string;
248
+ }
249
+ interface DatasetSchema {
250
+ fields: FieldInfo[];
251
+ filterableFields: string[];
252
+ searchableFields: string[];
253
+ linkFields: LinkFieldInfo[];
254
+ }
255
+ interface APIApplication {
256
+ id: string;
257
+ name: string;
258
+ description: string | null;
259
+ environment: string;
260
+ apiKeyPrefix: string;
261
+ allowedOrigins: string[] | null;
262
+ allowedIps: string[] | null;
263
+ createdAt: string;
264
+ updatedAt: string;
265
+ lastUsedAt: string | null;
266
+ }
267
+ interface APIAccount {
268
+ id: string;
269
+ displayName: string;
270
+ createdAt: string;
271
+ }
272
+ interface APIKeyInfo {
273
+ application: APIApplication;
274
+ account: APIAccount;
275
+ }
276
+ type FilterOperatorValue = {
277
+ eq: unknown;
278
+ } | {
279
+ neq: unknown;
280
+ } | {
281
+ gt: number;
282
+ } | {
283
+ gte: number;
284
+ } | {
285
+ lt: number;
286
+ } | {
287
+ lte: number;
288
+ } | {
289
+ in: unknown[];
290
+ } | {
291
+ nin: unknown[];
292
+ } | {
293
+ contains: unknown;
294
+ } | {
295
+ like: string;
296
+ } | {
297
+ ilike: string;
298
+ } | {
299
+ is_null: boolean;
300
+ };
301
+ type FilterValue = unknown | FilterOperatorValue;
302
+ interface FilterCondition {
303
+ [field: string]: FilterValue | FilterCondition | FilterCondition[];
304
+ }
305
+ type FilterInput = FilterCondition | ((builder: FilterBuilderInterface) => void);
306
+ interface FilterBuilderInterface {
307
+ where(field: string, value: FilterValue): this;
308
+ where(conditions: Record<string, FilterValue>): this;
309
+ any(callback: (builder: FilterBuilderInterface) => void): this;
310
+ whereLink(field: string, conditions: Record<string, FilterValue>): this;
311
+ whereAny(field: string, conditions: Record<string, FilterValue>): this;
312
+ build(): FilterCondition;
313
+ }
314
+ interface RateLimitInfo {
315
+ limit: number | null;
316
+ remaining: number | null;
317
+ reset: number | null;
318
+ }
319
+
320
+ /**
321
+ * Error classes for CardDB clients
322
+ */
323
+ interface GraphQLErrorInfo {
324
+ message: string;
325
+ path?: string[];
326
+ extensions?: Record<string, unknown>;
327
+ }
328
+ /**
329
+ * Base error class for all CardDB errors
330
+ */
331
+ declare class CardDBError extends Error {
332
+ /** The full response body if available */
333
+ readonly response?: unknown;
334
+ constructor(message: string, response?: unknown);
335
+ }
336
+ /**
337
+ * Raised when authentication fails (invalid API key or token)
338
+ */
339
+ declare class AuthenticationError extends CardDBError {
340
+ constructor(message?: string, response?: unknown);
341
+ }
342
+ /**
343
+ * Raised when rate limits are exceeded
344
+ */
345
+ declare class RateLimitError extends CardDBError {
346
+ /** Seconds until rate limit resets */
347
+ readonly retryAfter: number | null;
348
+ /** Maximum requests allowed */
349
+ readonly limit: number | null;
350
+ /** Remaining requests in window */
351
+ readonly remaining: number | null;
352
+ /** Time when the rate limit resets */
353
+ readonly resetAt: Date | null;
354
+ constructor(message?: string, options?: {
355
+ retryAfter?: number | null;
356
+ limit?: number | null;
357
+ remaining?: number | null;
358
+ resetAt?: Date | null;
359
+ response?: unknown;
360
+ });
361
+ }
362
+ /**
363
+ * Raised when a requested resource is not found
364
+ */
365
+ declare class NotFoundError extends CardDBError {
366
+ constructor(message?: string, response?: unknown);
367
+ }
368
+ /**
369
+ * Raised when request validation fails
370
+ */
371
+ declare class ValidationError extends CardDBError {
372
+ /** List of validation errors */
373
+ readonly errors: GraphQLErrorInfo[];
374
+ constructor(message?: string, options?: {
375
+ errors?: GraphQLErrorInfo[];
376
+ response?: unknown;
377
+ });
378
+ }
379
+ /**
380
+ * Raised when accessing a restricted publisher or game
381
+ */
382
+ declare class RestrictedError extends CardDBError {
383
+ constructor(message: string, response?: unknown);
384
+ }
385
+ /**
386
+ * Raised for GraphQL-level errors
387
+ */
388
+ declare class GraphQLError extends CardDBError {
389
+ /** List of GraphQL errors */
390
+ readonly errors: GraphQLErrorInfo[];
391
+ constructor(message?: string, options?: {
392
+ errors?: GraphQLErrorInfo[];
393
+ response?: unknown;
394
+ });
395
+ }
396
+ /**
397
+ * Raised for network/connection issues
398
+ */
399
+ declare class ConnectionError extends CardDBError {
400
+ constructor(message?: string, response?: unknown);
401
+ }
402
+ /**
403
+ * Raised when request times out
404
+ */
405
+ declare class TimeoutError extends ConnectionError {
406
+ constructor(message?: string, response?: unknown);
407
+ }
408
+ /**
409
+ * Raised when the server returns an unexpected response
410
+ */
411
+ declare class ServerError extends CardDBError {
412
+ /** HTTP status code */
413
+ readonly status: number | null;
414
+ constructor(message?: string, options?: {
415
+ status?: number | null;
416
+ response?: unknown;
417
+ });
418
+ }
419
+ /**
420
+ * Information about a failed link resolution
421
+ */
422
+ interface LinkResolutionFailure {
423
+ /** The link field key that failed */
424
+ field: string;
425
+ /** The value that couldn't be resolved */
426
+ value: string | null;
427
+ /** The reason for the failure */
428
+ reason: 'not_found' | 'invalid' | 'permission_denied' | 'unknown';
429
+ /** Optional error message from the server */
430
+ message?: string;
431
+ }
432
+ /**
433
+ * Raised when link resolution fails for one or more links
434
+ *
435
+ * This is a warning-level error that contains the partial results along with
436
+ * information about which links failed to resolve. The application can choose
437
+ * to handle this gracefully or treat it as a fatal error.
438
+ */
439
+ declare class LinkResolutionError extends CardDBError {
440
+ /** List of link resolution failures */
441
+ readonly failures: LinkResolutionFailure[];
442
+ /** Partial results that were successfully resolved */
443
+ readonly partialResults?: unknown;
444
+ constructor(message?: string, options?: {
445
+ failures?: LinkResolutionFailure[];
446
+ partialResults?: unknown;
447
+ response?: unknown;
448
+ });
449
+ /**
450
+ * Get failures for a specific field
451
+ */
452
+ getFailuresForField(field: string): LinkResolutionFailure[];
453
+ /**
454
+ * Check if a specific field had resolution failures
455
+ */
456
+ hasFailuresForField(field: string): boolean;
457
+ }
458
+
459
+ /**
460
+ * Filter operator helper functions
461
+ *
462
+ * These functions create operator objects that can be used in filters.
463
+ *
464
+ * @example
465
+ * // With filter builder
466
+ * filter: (f) => f
467
+ * .where('hp', gte(100))
468
+ * .where('types', contains('Pokemon'))
469
+ *
470
+ * @example
471
+ * // With object literal
472
+ * filter: {
473
+ * hp: gte(100),
474
+ * types: contains('Pokemon')
475
+ * }
476
+ */
477
+
478
+ /** Equality operator */
479
+ declare function eq(value: unknown): FilterOperatorValue;
480
+ /** Not equal operator */
481
+ declare function neq(value: unknown): FilterOperatorValue;
482
+ /** Greater than operator */
483
+ declare function gt(value: number): FilterOperatorValue;
484
+ /** Greater than or equal operator */
485
+ declare function gte(value: number): FilterOperatorValue;
486
+ /** Less than operator */
487
+ declare function lt(value: number): FilterOperatorValue;
488
+ /** Less than or equal operator */
489
+ declare function lte(value: number): FilterOperatorValue;
490
+ /** Value in array operator */
491
+ declare function within(values: unknown[]): FilterOperatorValue;
492
+ /** Value not in array operator */
493
+ declare function notWithin(values: unknown[]): FilterOperatorValue;
494
+ /** Array contains value operator */
495
+ declare function contains(value: unknown): FilterOperatorValue;
496
+ /** Case-sensitive pattern match (SQL LIKE) */
497
+ declare function like(pattern: string): FilterOperatorValue;
498
+ /** Case-insensitive pattern match (SQL ILIKE) */
499
+ declare function ilike(pattern: string): FilterOperatorValue;
500
+ /** Is null operator */
501
+ declare function isNull(): FilterOperatorValue;
502
+ /** Is not null operator */
503
+ declare function isNotNull(): FilterOperatorValue;
504
+
505
+ /**
506
+ * Filter builder for constructing complex filter queries
507
+ *
508
+ * Supports both builder pattern and object literal styles:
509
+ *
510
+ * @example Builder pattern
511
+ * filter: (f) => f
512
+ * .where('hp', gte(100))
513
+ * .where('types', contains('Pokemon'))
514
+ * .any(or => or
515
+ * .where('rarity', 'rare')
516
+ * .where('rarity', 'mythic')
517
+ * )
518
+ *
519
+ * @example Object literal
520
+ * filter: {
521
+ * hp: { gte: 100 },
522
+ * types: { contains: 'Pokemon' },
523
+ * $or: [
524
+ * { rarity: 'rare' },
525
+ * { rarity: 'mythic' }
526
+ * ]
527
+ * }
528
+ */
529
+
530
+ declare class FilterBuilder {
531
+ private conditions;
532
+ private orGroups;
533
+ /**
534
+ * Add a condition to the filter
535
+ *
536
+ * @example Single field
537
+ * .where('name', 'Pikachu')
538
+ * .where('hp', gte(100))
539
+ *
540
+ * @example Multiple fields (object)
541
+ * .where({ name: 'Pikachu', hp: gte(100) })
542
+ */
543
+ where(field: string, value: FilterValue): this;
544
+ where(conditions: Record<string, FilterValue>): this;
545
+ /**
546
+ * Add an OR group (any of the conditions must match)
547
+ *
548
+ * @example
549
+ * .where('type', 'creature')
550
+ * .any(or => or
551
+ * .where('color', 'red')
552
+ * .where('color', 'blue')
553
+ * )
554
+ */
555
+ any(callback: (builder: FilterBuilder) => void): this;
556
+ /**
557
+ * Add a link filter condition (filter on linked records)
558
+ *
559
+ * @example
560
+ * .whereLink('set_id', { code: 'DMU' })
561
+ * .whereLink('set_id', { name: ilike('%dominaria%') })
562
+ */
563
+ whereLink(field: string, conditions: Record<string, FilterValue>): this;
564
+ /**
565
+ * Add an array element filter (for ARRAY of HASH fields)
566
+ * Matches if any element in the array matches all conditions
567
+ *
568
+ * @example
569
+ * .whereAny('attacks', { damage: gte(50) })
570
+ * .whereAny('attacks', { name: ilike('%thunder%') })
571
+ */
572
+ whereAny(field: string, conditions: Record<string, FilterValue>): this;
573
+ /**
574
+ * Get the conditions array (used internally for OR groups)
575
+ */
576
+ getConditions(): FilterCondition[];
577
+ /**
578
+ * Build the final filter object
579
+ */
580
+ build(): FilterCondition;
581
+ }
582
+ /**
583
+ * Resolve a filter input to a filter condition object
584
+ *
585
+ * Handles both builder functions and object literals
586
+ */
587
+ declare function resolveFilter(input: FilterInput | undefined): FilterCondition | undefined;
588
+
589
+ /**
590
+ * GraphQL query builder for CardDB API
591
+ */
592
+
593
+ interface SearchPublishersParams {
594
+ search?: string;
595
+ first?: number;
596
+ after?: string;
597
+ }
598
+ interface SearchGamesParams {
599
+ publisherSlug?: string;
600
+ search?: string;
601
+ first?: number;
602
+ after?: string;
603
+ }
604
+ interface SearchDatasetsParams {
605
+ publisherSlug?: string;
606
+ gameKey?: string;
607
+ search?: string;
608
+ purpose?: 'DATA' | 'RULES';
609
+ first?: number;
610
+ after?: string;
611
+ }
612
+ interface SearchRecordsParams {
613
+ publisherSlug: string;
614
+ gameKey: string;
615
+ datasetKey: string;
616
+ filter?: FilterCondition;
617
+ search?: string;
618
+ orderBy?: string;
619
+ resolveLinks?: string[];
620
+ first?: number;
621
+ after?: string;
622
+ validateSchema?: boolean;
623
+ }
624
+ interface ListDecksParams {
625
+ first?: number;
626
+ after?: string;
627
+ }
628
+ declare const QueryBuilder: {
629
+ searchPublishers(params?: SearchPublishersParams): {
630
+ query: string;
631
+ variables: Record<string, unknown>;
632
+ };
633
+ fetchPublisherById(): {
634
+ query: string;
635
+ };
636
+ fetchPublisherBySlug(): {
637
+ query: string;
638
+ };
639
+ fetchPublishers(): {
640
+ query: string;
641
+ };
642
+ searchGames(params?: SearchGamesParams): {
643
+ query: string;
644
+ variables: Record<string, unknown>;
645
+ };
646
+ fetchGameById(): {
647
+ query: string;
648
+ };
649
+ fetchGameByKeys(): {
650
+ query: string;
651
+ };
652
+ fetchGames(): {
653
+ query: string;
654
+ };
655
+ searchDatasets(params?: SearchDatasetsParams): {
656
+ query: string;
657
+ variables: Record<string, unknown>;
658
+ };
659
+ fetchDatasetById(): {
660
+ query: string;
661
+ };
662
+ fetchDatasetByKeys(): {
663
+ query: string;
664
+ };
665
+ fetchDatasets(): {
666
+ query: string;
667
+ };
668
+ searchRecords(params: SearchRecordsParams): {
669
+ query: string;
670
+ variables: Record<string, unknown>;
671
+ };
672
+ fetchRecordById(): {
673
+ query: string;
674
+ };
675
+ fetchRecordByIdentifier(): {
676
+ query: string;
677
+ };
678
+ fetchRecordsByIdentifier(): {
679
+ query: string;
680
+ };
681
+ fetchRecords(): {
682
+ query: string;
683
+ };
684
+ listMyDecks(params?: ListDecksParams): {
685
+ query: string;
686
+ variables: Record<string, unknown>;
687
+ };
688
+ fetchDeckById(): {
689
+ query: string;
690
+ };
691
+ fetchDeckByExternalRef(): {
692
+ query: string;
693
+ };
694
+ createDeck(): {
695
+ query: string;
696
+ };
697
+ updateDeck(): {
698
+ query: string;
699
+ };
700
+ deleteDeck(): {
701
+ query: string;
702
+ };
703
+ deckCreateVariables(input: DeckCreateInput): Record<string, unknown>;
704
+ deckUpdateVariables(id: string, input: DeckUpdateInput): Record<string, unknown>;
705
+ fetchMe(): {
706
+ query: string;
707
+ };
708
+ };
709
+
710
+ /**
711
+ * Collection class for paginated results with async iteration support
712
+ */
713
+
714
+ type NextPageLoader<T> = (cursor: string) => Promise<Collection<T>>;
715
+ /**
716
+ * Represents a paginated collection of results from the API.
717
+ * Implements AsyncIterable for easy iteration through all pages.
718
+ */
719
+ declare class Collection<T> implements AsyncIterable<T> {
720
+ /** Total count of matching records across all pages */
721
+ readonly totalCount: number;
722
+ /** Pagination info */
723
+ readonly pageInfo: PageInfo;
724
+ /** Items in the current page */
725
+ readonly items: T[];
726
+ /** Function to load the next page */
727
+ private nextPageLoader?;
728
+ constructor(data: Connection<T>, options?: {
729
+ nextPageLoader?: NextPageLoader<T>;
730
+ itemTransformer?: (node: T) => T;
731
+ });
732
+ /** Check if there are more pages */
733
+ get hasNextPage(): boolean;
734
+ /** Check if there are previous pages */
735
+ get hasPreviousPage(): boolean;
736
+ /** Get the cursor for the next page */
737
+ get endCursor(): string | null;
738
+ /** Get the cursor for the previous page */
739
+ get startCursor(): string | null;
740
+ /** Number of items in the current page */
741
+ get length(): number;
742
+ /** Check if the current page is empty */
743
+ get isEmpty(): boolean;
744
+ /** Get the first item */
745
+ get first(): T | undefined;
746
+ /** Get the last item */
747
+ get last(): T | undefined;
748
+ /**
749
+ * Fetch the next page of results
750
+ *
751
+ * @returns The next page collection, or null if no more pages
752
+ * @throws Error if no next page loader is configured
753
+ */
754
+ nextPage(): Promise<Collection<T> | null>;
755
+ /**
756
+ * Async iterator that automatically paginates through all results
757
+ *
758
+ * @example
759
+ * for await (const record of collection) {
760
+ * console.log(record.name)
761
+ * }
762
+ *
763
+ * @example
764
+ * const allRecords = []
765
+ * for await (const record of collection) {
766
+ * allRecords.push(record)
767
+ * }
768
+ */
769
+ [Symbol.asyncIterator](): AsyncIterator<T>;
770
+ /**
771
+ * Iterate through all results, calling a callback for each item
772
+ * Similar to Array.forEach but async and auto-paginating
773
+ *
774
+ * @example
775
+ * await collection.forEach(async (record) => {
776
+ * await processRecord(record)
777
+ * })
778
+ */
779
+ forEach(callback: (item: T, index: number) => void | Promise<void>): Promise<void>;
780
+ /**
781
+ * Map over all results, returning a new array
782
+ * Auto-paginates through all pages
783
+ *
784
+ * @example
785
+ * const names = await collection.map(record => record.name)
786
+ */
787
+ map<U>(callback: (item: T, index: number) => U | Promise<U>): Promise<U[]>;
788
+ /**
789
+ * Filter results, returning items that match the predicate
790
+ * Auto-paginates through all pages
791
+ *
792
+ * @example
793
+ * const rareCards = await collection.filter(card => card.rarity === 'rare')
794
+ */
795
+ filter(predicate: (item: T, index: number) => boolean | Promise<boolean>): Promise<T[]>;
796
+ /**
797
+ * Find the first item matching a predicate
798
+ * Stops iterating once found
799
+ *
800
+ * @example
801
+ * const pikachu = await collection.find(card => card.name === 'Pikachu')
802
+ */
803
+ find(predicate: (item: T, index: number) => boolean | Promise<boolean>): Promise<T | undefined>;
804
+ /**
805
+ * Take the first n items
806
+ * Stops fetching pages once n items are collected
807
+ *
808
+ * @example
809
+ * const first100 = await collection.take(100)
810
+ */
811
+ take(n: number): Promise<T[]>;
812
+ /**
813
+ * Collect all items into an array
814
+ * Auto-paginates through all pages
815
+ *
816
+ * @example
817
+ * const allRecords = await collection.toArray()
818
+ */
819
+ toArray(): Promise<T[]>;
820
+ /**
821
+ * Iterate in batches (similar to Rails find_in_batches)
822
+ *
823
+ * @example
824
+ * for await (const batch of collection.batches()) {
825
+ * await processBatch(batch)
826
+ * }
827
+ */
828
+ batches(): AsyncGenerator<T[]>;
829
+ /**
830
+ * Iterate one item at a time with batched fetching (similar to Rails find_each)
831
+ *
832
+ * @example
833
+ * for await (const item of collection.each()) {
834
+ * await processItem(item)
835
+ * }
836
+ */
837
+ each(): AsyncIterable<T>;
838
+ }
839
+
840
+ export { type APIAccount, type APIApplication, type APIKeyInfo, AuthenticationError, type Cache, type CardDBConfig, CardDBError, Collection, type Connection, ConnectionError, type Dataset, type DatasetRecord, type DatasetRef, type DatasetSchema, type Deck, type DeckCreateInput, type DeckEntry, type DeckEntryInput, type DeckUpdateInput, type DeckVisibility, type Edge, type FieldInfo, type FieldType, type FileInfo, FilterBuilder, type FilterBuilderInterface, type FilterCondition, type FilterInput, type FilterOperatorValue, type FilterValue, type Game, type GameRef, GraphQLError, type GraphQLErrorInfo, type HydrateDeckEntryInput, type HydratedDeckEntry, type LinkFieldInfo, LinkResolutionError, type LinkResolutionFailure, type ListDecksParams, type LogLevel, type Logger, type NextPageLoader, NotFoundError, type PageInfo, type Publisher, type PublisherRef, type PublisherStatus, QueryBuilder, RateLimitError, type RateLimitInfo, type ResolvedLink, type ResourceType, RestrictedError, type SearchDatasetsParams, type SearchGamesParams, type SearchPublishersParams, type SearchRecordsParams, ServerError, TimeoutError, ValidationError, contains, eq, gt, gte, ilike, isNotNull, isNull, like, lt, lte, neq, notWithin, resolveFilter, within };