carddb 0.2.2 → 0.3.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.
@@ -245,6 +245,16 @@ module CardDB
245
245
  def to_json(*args)
246
246
  data.to_json(*args)
247
247
  end
248
+
249
+ private
250
+
251
+ def parse_time(value)
252
+ return nil unless value
253
+
254
+ Time.parse(value)
255
+ rescue ArgumentError
256
+ value
257
+ end
248
258
  end
249
259
 
250
260
  # Wrapper for Publisher objects
@@ -760,8 +770,8 @@ module CardDB
760
770
  def parse_resolved_links
761
771
  return {} unless data['resolvedLinks']
762
772
 
763
- data['resolvedLinks'].each_with_object({}) do |link, hash|
764
- hash[link['field']] = ResolvedLink.new(link, client: client)
773
+ data['resolvedLinks'].to_h do |link|
774
+ [link['field'], ResolvedLink.new(link, client: client)]
765
775
  end
766
776
  end
767
777
 
@@ -780,6 +790,30 @@ module CardDB
780
790
  data['id']
781
791
  end
782
792
 
793
+ def owner_type
794
+ data['ownerType']
795
+ end
796
+
797
+ def owner_account_id
798
+ data['ownerAccountId']
799
+ end
800
+
801
+ def owner_api_application_id
802
+ data['ownerApiApplicationId']
803
+ end
804
+
805
+ def environment
806
+ data['environment']
807
+ end
808
+
809
+ def created_by_account_id
810
+ data['createdByAccountId']
811
+ end
812
+
813
+ def created_by_api_application_id
814
+ data['createdByApiApplicationId']
815
+ end
816
+
783
817
  def account_id
784
818
  data['accountId']
785
819
  end
@@ -820,10 +854,54 @@ module CardDB
820
854
  data['visibility']
821
855
  end
822
856
 
857
+ def access_mode
858
+ data['accessMode']
859
+ end
860
+
861
+ def discoverability
862
+ data['discoverability']
863
+ end
864
+
865
+ def state
866
+ data['state']
867
+ end
868
+
869
+ def archived?
870
+ state == 'ARCHIVED'
871
+ end
872
+
873
+ def deleted?
874
+ state == 'DELETED'
875
+ end
876
+
877
+ def archived_at
878
+ parse_time(data['archivedAt'])
879
+ end
880
+
881
+ def deleted_at
882
+ parse_time(data['deletedAt'])
883
+ end
884
+
885
+ def unpublished_at
886
+ parse_time(data['unpublishedAt'])
887
+ end
888
+
889
+ def external_ref_api_application_id
890
+ data['externalRefApiApplicationId']
891
+ end
892
+
823
893
  def external_ref
824
894
  data['externalRef']
825
895
  end
826
896
 
897
+ def external_subject_ref
898
+ data['externalSubjectRef']
899
+ end
900
+
901
+ def ruleset_id
902
+ data['rulesetId']
903
+ end
904
+
827
905
  def source_url
828
906
  data['sourceUrl']
829
907
  end
@@ -836,6 +914,12 @@ module CardDB
836
914
  @entries ||= (data['entries'] || []).map { |entry| DeckEntry.new(entry, client: client) }
837
915
  end
838
916
 
917
+ def section_definitions
918
+ @section_definitions ||= (data['sectionDefinitions'] || []).map do |definition|
919
+ DeckSectionDefinition.new(definition, client: client)
920
+ end
921
+ end
922
+
839
923
  def latest_published_version
840
924
  @latest_published_version ||= data['latestPublishedVersion'] ? DeckVersion.new(data['latestPublishedVersion'], client: client) : nil
841
925
  end
@@ -844,6 +928,22 @@ module CardDB
844
928
  parse_time(data['publishedAt'])
845
929
  end
846
930
 
931
+ def draft_revision
932
+ data['draftRevision']
933
+ end
934
+
935
+ def draft_updated_at
936
+ parse_time(data['draftUpdatedAt'])
937
+ end
938
+
939
+ def draft_updated_by_account_id
940
+ data['draftUpdatedByAccountId']
941
+ end
942
+
943
+ def draft_updated_by_api_application_id
944
+ data['draftUpdatedByApiApplicationId']
945
+ end
946
+
847
947
  def has_unpublished_changes?
848
948
  !!data['hasUnpublishedChanges']
849
949
  end
@@ -929,6 +1029,40 @@ module CardDB
929
1029
  data['computedDiff'] || {}
930
1030
  end
931
1031
 
1032
+ def ruleset_id
1033
+ data['rulesetId']
1034
+ end
1035
+
1036
+ def ruleset_version_id
1037
+ data['rulesetVersionId']
1038
+ end
1039
+
1040
+ def card_dataset_id
1041
+ data['cardDatasetId']
1042
+ end
1043
+
1044
+ def card_dataset_version_id
1045
+ data['cardDatasetVersionId']
1046
+ end
1047
+
1048
+ def validated_at
1049
+ parse_time(data['validatedAt'])
1050
+ end
1051
+
1052
+ def validation_summary
1053
+ data['validationSummary'] || {}
1054
+ end
1055
+
1056
+ def validated_against
1057
+ @validated_against ||= data['validatedAgainst'] ? DeckValidatedAgainst.new(data['validatedAgainst'], client: client) : nil
1058
+ end
1059
+
1060
+ def section_definitions
1061
+ @section_definitions ||= (data['sectionDefinitions'] || []).map do |definition|
1062
+ DeckSectionDefinition.new(definition, client: client)
1063
+ end
1064
+ end
1065
+
932
1066
  def published_by_account_id
933
1067
  data['publishedByAccountId']
934
1068
  end
@@ -993,6 +1127,49 @@ module CardDB
993
1127
  end
994
1128
  end
995
1129
 
1130
+ class DeckOwnershipTransferPayload < Resource
1131
+ def deck
1132
+ @deck ||= Deck.new(data['deck'], client: client)
1133
+ end
1134
+
1135
+ def retained_app_access? = !!data['retainedAppAccess']
1136
+ end
1137
+
1138
+ class DeckCopyPayload < DeckOwnershipTransferPayload
1139
+ def copied_from_deck_id = data['copiedFromDeckId']
1140
+ end
1141
+
1142
+ class DeckAccessApplication < Resource
1143
+ def id = data['id']
1144
+ def name = data['name']
1145
+ def description = data['description']
1146
+ def revoked_at = parse_time(data['revokedAt'])
1147
+ end
1148
+
1149
+ class DeckAPIApplicationAccess < Resource
1150
+ def id = data['id']
1151
+ def deck_id = data['deckId']
1152
+
1153
+ def deck
1154
+ @deck ||= data['deck'] ? Deck.new(data['deck'], client: client) : nil
1155
+ end
1156
+
1157
+ def api_application_id = data['apiApplicationId']
1158
+
1159
+ def api_application
1160
+ @api_application ||= data['apiApplication'] ? DeckAccessApplication.new(data['apiApplication'], client: client) : nil
1161
+ end
1162
+
1163
+ def role = data['role']
1164
+ def grant_source = data['grantSource']
1165
+ def external_ref = data['externalRef']
1166
+ def created_by_account_id = data['createdByAccountId']
1167
+ def created_by_api_application_id = data['createdByApiApplicationId']
1168
+ def revoked_at = parse_time(data['revokedAt'])
1169
+ def created_at = parse_time(data['createdAt'])
1170
+ def updated_at = parse_time(data['updatedAt'])
1171
+ end
1172
+
996
1173
  # Wrapper for deck preview token metadata
997
1174
  class DeckPreviewToken < Resource
998
1175
  def id
@@ -1049,6 +1226,329 @@ module CardDB
1049
1226
  end
1050
1227
  end
1051
1228
 
1229
+ class DeckEmbedToken < Resource
1230
+ def id = data['id']
1231
+ def deck_id = data['deckId']
1232
+ def api_application_id = data['apiApplicationId']
1233
+ def label = data['label']
1234
+ def read_mode = data['readMode']
1235
+ def allowed_origins = data['allowedOrigins'] || []
1236
+ def external_subject = data['externalSubject']
1237
+ def expires_at = parse_time(data['expiresAt'])
1238
+ def revoked_at = parse_time(data['revokedAt'])
1239
+ def last_used_at = parse_time(data['lastUsedAt'])
1240
+ def created_at = parse_time(data['createdAt'])
1241
+ def updated_at = parse_time(data['updatedAt'])
1242
+ end
1243
+
1244
+ class DeckEmbedTokenCreatePayload < Resource
1245
+ def token = data['token']
1246
+
1247
+ def embed_token
1248
+ @embed_token ||= data['embedToken'] ? DeckEmbedToken.new(data['embedToken'], client: client) : nil
1249
+ end
1250
+ end
1251
+
1252
+ class DeckAccessTokenIssuer < Resource
1253
+ def id = data['id']
1254
+ def deck_id = data['deckId']
1255
+ def api_application_id = data['apiApplicationId']
1256
+ def label = data['label']
1257
+ def read_modes = data['readModes'] || []
1258
+ def max_token_lifetime_seconds = data['maxTokenLifetimeSeconds']
1259
+ def direct_signing_alg = data['directSigningAlg']
1260
+ def direct_signing_key_id = data['directSigningKeyId']
1261
+ def direct_signing_public_key = data['directSigningPublicKey']
1262
+ def direct_signing_key_revoked_at = parse_time(data['directSigningKeyRevokedAt'])
1263
+ def revoked_at = parse_time(data['revokedAt'])
1264
+ def created_at = parse_time(data['createdAt'])
1265
+ def updated_at = parse_time(data['updatedAt'])
1266
+ end
1267
+
1268
+ class DeckAccessToken < Resource
1269
+ def id = data['id']
1270
+ def deck_id = data['deckId']
1271
+ def api_application_id = data['apiApplicationId']
1272
+ def issuer_id = data['issuerId']
1273
+ def read_mode = data['readMode']
1274
+ def external_subject = data['externalSubject']
1275
+ def expires_at = parse_time(data['expiresAt'])
1276
+ def revoked_at = parse_time(data['revokedAt'])
1277
+ def last_used_at = parse_time(data['lastUsedAt'])
1278
+ def created_at = parse_time(data['createdAt'])
1279
+ def updated_at = parse_time(data['updatedAt'])
1280
+ end
1281
+
1282
+ class DeckAccessTokenExchangePayload < Resource
1283
+ def token = data['token']
1284
+
1285
+ def access_token
1286
+ @access_token ||= data['accessToken'] ? DeckAccessToken.new(data['accessToken'], client: client) : nil
1287
+ end
1288
+ end
1289
+
1290
+ class DeckSectionDefinition < Resource
1291
+ def key = data['key']
1292
+ def label = data['label']
1293
+ def description = data['description']
1294
+ def order = data['order']
1295
+ def default? = !!data['default']
1296
+ def aliases = data['aliases'] || []
1297
+ def min_cards = data['minCards']
1298
+ def max_cards = data['maxCards']
1299
+ def excluded_from_deck_size? = !!data['excludedFromDeckSize']
1300
+ def legal_card_types = data['legalCardTypes'] || []
1301
+ def metadata = data['metadata'] || {}
1302
+ end
1303
+
1304
+ class DeckValidatedAgainst < Resource
1305
+ def ruleset_id = data['rulesetId']
1306
+ def ruleset_version_id = data['rulesetVersionId']
1307
+ def ruleset_version_label = data['rulesetVersionLabel']
1308
+ def card_dataset_id = data['cardDatasetId']
1309
+ def card_dataset_version_id = data['cardDatasetVersionId']
1310
+ def validated_at = parse_time(data['validatedAt'])
1311
+ def validation_result_summary = data['validationResultSummary'] || {}
1312
+ end
1313
+
1314
+ class DeckValidationIssue < Resource
1315
+ def code = data['code']
1316
+ def severity = data['severity']
1317
+ def message = data['message']
1318
+ def entry_ids = data['entryIds'] || []
1319
+ def section = data['section']
1320
+ def dataset_id = data['datasetId']
1321
+ def identifier = data['identifier']
1322
+ def metadata = data['metadata'] || {}
1323
+ end
1324
+
1325
+ class DeckValidationAffectedEntry < Resource
1326
+ def entry_id = data['entryId']
1327
+ def dataset_id = data['datasetId']
1328
+ def record_id = data['recordId']
1329
+ def identifier = data['identifier']
1330
+ def section = data['section']
1331
+ def quantity = data['quantity']
1332
+ end
1333
+
1334
+ class DeckValidation < Resource
1335
+ def deck_id = data['deckId']
1336
+ def valid? = !!data['valid']
1337
+ def checked_at = parse_time(data['checkedAt'])
1338
+
1339
+ def blockers
1340
+ @blockers ||= (data['blockers'] || []).map { |issue| DeckValidationIssue.new(issue, client: client) }
1341
+ end
1342
+
1343
+ def warnings
1344
+ @warnings ||= (data['warnings'] || []).map { |issue| DeckValidationIssue.new(issue, client: client) }
1345
+ end
1346
+
1347
+ def affected_entries
1348
+ @affected_entries ||= (data['affectedEntries'] || []).map do |entry|
1349
+ DeckValidationAffectedEntry.new(entry, client: client)
1350
+ end
1351
+ end
1352
+
1353
+ def validated_against
1354
+ @validated_against ||= DeckValidatedAgainst.new(data['validatedAgainst'], client: client)
1355
+ end
1356
+ end
1357
+
1358
+ class DeckDiff < Resource
1359
+ def deck_id = data['deckId']
1360
+ def from_version_id = data['fromVersionId']
1361
+ def to_version_id = data['toVersionId']
1362
+ def to_draft_revision = data['toDraftRevision']
1363
+ def changes? = !!data['hasChanges']
1364
+ def diff = data['diff'] || {}
1365
+ end
1366
+
1367
+ class DeckPublishPayload < Resource
1368
+ def deck
1369
+ @deck ||= Deck.new(data['deck'], client: client)
1370
+ end
1371
+
1372
+ def version
1373
+ @version ||= data['version'] ? DeckVersion.new(data['version'], client: client) : nil
1374
+ end
1375
+
1376
+ def validation
1377
+ @validation ||= DeckValidation.new(data['validation'], client: client)
1378
+ end
1379
+
1380
+ def blockers
1381
+ @blockers ||= (data['blockers'] || []).map { |issue| DeckValidationIssue.new(issue, client: client) }
1382
+ end
1383
+
1384
+ def warnings
1385
+ @warnings ||= (data['warnings'] || []).map { |issue| DeckValidationIssue.new(issue, client: client) }
1386
+ end
1387
+ end
1388
+
1389
+ class DeckEntryMutationPayload < Resource
1390
+ def deck
1391
+ @deck ||= Deck.new(data['deck'], client: client)
1392
+ end
1393
+
1394
+ def entry
1395
+ @entry ||= data['entry'] ? DeckEntry.new(data['entry'], client: client) : nil
1396
+ end
1397
+ end
1398
+
1399
+ class DeckEntryReorderPayload < Resource
1400
+ def deck
1401
+ @deck ||= Deck.new(data['deck'], client: client)
1402
+ end
1403
+
1404
+ def entries
1405
+ @entries ||= (data['entries'] || []).map { |entry| DeckEntry.new(entry, client: client) }
1406
+ end
1407
+ end
1408
+
1409
+ class DeckEntriesReplacePayload < DeckEntryReorderPayload; end
1410
+
1411
+ class DeckUpsertByExternalRefPayload < Resource
1412
+ def deck
1413
+ @deck ||= Deck.new(data['deck'], client: client)
1414
+ end
1415
+
1416
+ def created? = !!data['created']
1417
+ def idempotent_replay? = !!data['idempotentReplay']
1418
+ end
1419
+
1420
+ class DeckImportEntry < Resource
1421
+ def line_number = data['lineNumber']
1422
+ def raw = data['raw']
1423
+ def dataset_key = data['datasetKey']
1424
+ def dataset_id = data['datasetId']
1425
+ def record_id = data['recordId']
1426
+ def identifier = data['identifier']
1427
+ def quantity = data['quantity']
1428
+ def section = data['section']
1429
+ def sort_order = data['sortOrder']
1430
+ def display = data['display'] || {}
1431
+
1432
+ def record
1433
+ @record ||= data['record'] ? Record.new(data['record'], client: client) : nil
1434
+ end
1435
+ end
1436
+
1437
+ class DeckImportIssue < Resource
1438
+ def line_number = data['lineNumber']
1439
+ def raw = data['raw']
1440
+ def code = data['code']
1441
+ def message = data['message']
1442
+ end
1443
+
1444
+ class DeckImportUnmatchedEntry < DeckImportIssue
1445
+ def dataset_key = data['datasetKey']
1446
+ def identifier = data['identifier']
1447
+ def quantity = data['quantity']
1448
+ def section = data['section']
1449
+ end
1450
+
1451
+ class DeckImportCandidate < Resource
1452
+ def record_id = data['recordId']
1453
+ def identifier = data['identifier']
1454
+ def display = data['display'] || {}
1455
+ end
1456
+
1457
+ class DeckImportAmbiguousEntry < Resource
1458
+ def line_number = data['lineNumber']
1459
+ def raw = data['raw']
1460
+ def dataset_key = data['datasetKey']
1461
+ def identifier = data['identifier']
1462
+ def quantity = data['quantity']
1463
+ def section = data['section']
1464
+
1465
+ def candidates
1466
+ @candidates ||= (data['candidates'] || []).map { |candidate| DeckImportCandidate.new(candidate, client: client) }
1467
+ end
1468
+ end
1469
+
1470
+ class DeckImportFormatDefinition < Resource
1471
+ def id = data['id']
1472
+ def game_id = data['gameId']
1473
+ def key = data['key']
1474
+ def name = data['name']
1475
+ def description = data['description']
1476
+ def enabled? = !!data['enabled']
1477
+ def priority = data['priority']
1478
+ def dataset_key = data['datasetKey']
1479
+ def config = data['config'] || {}
1480
+ def archived_at = parse_time(data['archivedAt'])
1481
+ def archived? = !!data['isArchived']
1482
+ def created_at = parse_time(data['createdAt'])
1483
+ def updated_at = parse_time(data['updatedAt'])
1484
+ end
1485
+
1486
+ class DeckImportFormatDetection < Resource
1487
+ def format_id = data['formatId']
1488
+ def key = data['key']
1489
+ def name = data['name']
1490
+ def confidence = data['confidence']
1491
+ def reason = data['reason']
1492
+ end
1493
+
1494
+ class DeckHydrateEntriesPayload < Resource
1495
+ def entries
1496
+ @entries ||= (data['entries'] || []).map { |entry| DeckImportEntry.new(entry, client: client) }
1497
+ end
1498
+
1499
+ def unmatched
1500
+ @unmatched ||= (data['unmatched'] || []).map { |entry| DeckImportUnmatchedEntry.new(entry, client: client) }
1501
+ end
1502
+
1503
+ def ambiguous
1504
+ @ambiguous ||= (data['ambiguous'] || []).map { |entry| DeckImportAmbiguousEntry.new(entry, client: client) }
1505
+ end
1506
+ end
1507
+
1508
+ class DeckImportFormatTestPayload < DeckHydrateEntriesPayload
1509
+ def detection
1510
+ @detection ||= data['detection'] ? DeckImportFormatDetection.new(data['detection'], client: client) : nil
1511
+ end
1512
+
1513
+ def parse_errors
1514
+ @parse_errors ||= (data['parseErrors'] || []).map { |issue| DeckImportIssue.new(issue, client: client) }
1515
+ end
1516
+ end
1517
+
1518
+ class DeckImportPayload < DeckHydrateEntriesPayload
1519
+ def deck
1520
+ @deck ||= data['deck'] ? Deck.new(data['deck'], client: client) : nil
1521
+ end
1522
+
1523
+ def applied? = !!data['applied']
1524
+ def dry_run? = !!data['dryRun']
1525
+ def replace? = !!data['replace']
1526
+ def format = data['format']
1527
+
1528
+ def import_format
1529
+ @import_format ||= data['importFormat'] ? DeckImportFormatDefinition.new(data['importFormat'], client: client) : nil
1530
+ end
1531
+
1532
+ def detection
1533
+ @detection ||= data['detection'] ? DeckImportFormatDetection.new(data['detection'], client: client) : nil
1534
+ end
1535
+
1536
+ def parse_errors
1537
+ @parse_errors ||= (data['parseErrors'] || []).map { |issue| DeckImportIssue.new(issue, client: client) }
1538
+ end
1539
+
1540
+ def validation
1541
+ @validation ||= data['validation'] ? DeckValidation.new(data['validation'], client: client) : nil
1542
+ end
1543
+ end
1544
+
1545
+ class DeckExportPayload < Resource
1546
+ def deck_id = data['deckId']
1547
+ def format = data['format']
1548
+ def text = data['text']
1549
+ def entry_count = data['entryCount']
1550
+ end
1551
+
1052
1552
  # Wrapper for hosted DeckEntry objects
1053
1553
  class DeckEntry < Resource
1054
1554
  def id
@@ -1083,6 +1583,10 @@ module CardDB
1083
1583
  data['annotations'] || {}
1084
1584
  end
1085
1585
 
1586
+ def display
1587
+ data['display'] || {}
1588
+ end
1589
+
1086
1590
  def record
1087
1591
  @record ||= data['record'] ? Record.new(data['record'], client: client) : nil
1088
1592
  end
@@ -41,9 +41,21 @@ module CardDB
41
41
  # Default retry settings
42
42
  DEFAULT_MAX_RETRIES = 3
43
43
 
44
- # @return [String, nil] API key for authentication
44
+ # @return [String, nil] Legacy API key for authentication
45
45
  attr_accessor :api_key
46
46
 
47
+ # @return [String, nil] Browser-safe publishable API key for public reads
48
+ attr_accessor :publishable_key
49
+
50
+ # @return [String, nil] Server-side secret API key for trusted workflows
51
+ attr_accessor :secret_key
52
+
53
+ # @return [String, nil] OAuth bearer token for user-authorized requests
54
+ attr_accessor :access_token
55
+
56
+ # @return [String, nil] Client environment hint (`TEST` or `LIVE`)
57
+ attr_accessor :environment
58
+
47
59
  # @return [String] GraphQL endpoint URL
48
60
  attr_accessor :endpoint
49
61
 
@@ -93,6 +105,10 @@ module CardDB
93
105
  @timeout = DEFAULT_TIMEOUT
94
106
  @open_timeout = DEFAULT_OPEN_TIMEOUT
95
107
  @api_key = nil
108
+ @publishable_key = nil
109
+ @secret_key = nil
110
+ @access_token = nil
111
+ @environment = nil
96
112
  @default_publisher = nil
97
113
  @default_game = nil
98
114
  @allowed_publishers = nil
@@ -154,6 +170,16 @@ module CardDB
154
170
  validate_game!(publisher_slug, game_key) if publisher_slug && game_key
155
171
  end
156
172
 
173
+ def effective_api_key
174
+ api_key || publishable_key || secret_key
175
+ end
176
+
177
+ def require_secret_credential!(operation)
178
+ return if !access_token && (api_key || (secret_key && !publishable_key))
179
+
180
+ raise RestrictedError, "#{operation} requires a server-side secret_key or legacy api_key credential"
181
+ end
182
+
157
183
  # Resolves the publisher slug, using the default if not provided.
158
184
  #
159
185
  # @param publisher_slug [String, nil] The provided publisher slug
@@ -71,8 +71,11 @@ module CardDB
71
71
  f.headers['Accept'] = 'application/json'
72
72
  f.headers['User-Agent'] = "CardDB-SDK/ruby/#{CardDB::VERSION} (ruby/#{RUBY_VERSION})"
73
73
 
74
- # Set API key header if configured
75
- f.headers['X-API-Key'] = config.api_key if config.api_key
74
+ if config.access_token
75
+ f.headers['Authorization'] = "Bearer #{config.access_token}"
76
+ elsif config.effective_api_key
77
+ f.headers['X-API-Key'] = config.effective_api_key
78
+ end
76
79
 
77
80
  f.options.timeout = config.timeout
78
81
  f.options.open_timeout = config.open_timeout