@mapletip/data 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.
Files changed (88) hide show
  1. package/NOTICE +52 -0
  2. package/README.md +209 -0
  3. package/client/contract-compatibility.d.mts +27 -0
  4. package/client/contract-compatibility.mjs +159 -0
  5. package/client/core.d.ts +150 -0
  6. package/client/core.js +359 -0
  7. package/client/equipment.d.ts +22 -0
  8. package/client/equipment.js +63 -0
  9. package/client/items.d.ts +22 -0
  10. package/client/items.js +63 -0
  11. package/client/media.d.ts +19 -0
  12. package/client/media.js +47 -0
  13. package/client/monster-client.d.ts +35 -0
  14. package/client/monster-client.js +155 -0
  15. package/client/monsters.d.ts +24 -0
  16. package/client/monsters.js +14 -0
  17. package/client/quests.d.ts +31 -0
  18. package/client/quests.js +124 -0
  19. package/client/release.d.ts +63 -0
  20. package/client/release.js +279 -0
  21. package/client/static-client.d.ts +40 -0
  22. package/client/static-client.js +44 -0
  23. package/client/static-domains.d.ts +48 -0
  24. package/client/static-domains.js +113 -0
  25. package/generated/contract-2-catalog-fact.d.ts +51 -0
  26. package/generated/equipment-catalog-2.d.ts +434 -0
  27. package/generated/equipment-catalog-2.validator.js +17 -0
  28. package/generated/equipment-detail-2.d.ts +350 -0
  29. package/generated/equipment-detail-2.validator.js +17 -0
  30. package/generated/equipment-evidence-pack-2.d.ts +243 -0
  31. package/generated/equipment-evidence-pack-2.validator.js +17 -0
  32. package/generated/equipment-pack-2.validator.js +17 -0
  33. package/generated/equipment-relationship-pack-2.d.ts +170 -0
  34. package/generated/equipment-relationship-pack-2.validator.js +17 -0
  35. package/generated/item-catalog-2.d.ts +366 -0
  36. package/generated/item-catalog-2.validator.js +17 -0
  37. package/generated/item-detail-2.d.ts +540 -0
  38. package/generated/item-detail-2.validator.js +17 -0
  39. package/generated/item-evidence-pack-2.d.ts +243 -0
  40. package/generated/item-evidence-pack-2.validator.js +17 -0
  41. package/generated/item-pack-2.validator.js +17 -0
  42. package/generated/item-relationship-pack-2.d.ts +170 -0
  43. package/generated/item-relationship-pack-2.validator.js +17 -0
  44. package/generated/media-catalog-2.d.ts +133 -0
  45. package/generated/media-catalog-2.validator.js +17 -0
  46. package/generated/media-detail-2.d.ts +125 -0
  47. package/generated/media-detail-2.validator.js +17 -0
  48. package/generated/media-pack-2.validator.js +17 -0
  49. package/generated/monster-catalog-2.d.ts +230 -0
  50. package/generated/monster-catalog-2.validator.js +17 -0
  51. package/generated/monster-catalog.d.ts +224 -0
  52. package/generated/monster-catalog.validator.js +1 -0
  53. package/generated/monster-core-relationship-pack-2.d.ts +208 -0
  54. package/generated/monster-core-relationship-pack-2.validator.js +17 -0
  55. package/generated/monster-detail-2.d.ts +372 -0
  56. package/generated/monster-detail-2.validator.js +17 -0
  57. package/generated/monster-detail.d.ts +799 -0
  58. package/generated/monster-detail.validator.js +17 -0
  59. package/generated/monster-evidence-pack-2.d.ts +378 -0
  60. package/generated/monster-evidence-pack-2.validator.js +17 -0
  61. package/generated/monster-evidence-pack.d.ts +269 -0
  62. package/generated/monster-evidence-pack.validator.js +17 -0
  63. package/generated/monster-location-pack-2.validator.js +1 -0
  64. package/generated/monster-pack-2.validator.js +17 -0
  65. package/generated/monster-pack.validator.js +17 -0
  66. package/generated/monster-relationship-pack.d.ts +126 -0
  67. package/generated/monster-relationship-pack.validator.js +1 -0
  68. package/generated/product-manifest.d.ts +188 -0
  69. package/generated/product-manifest.validator.js +1 -0
  70. package/generated/quest-auxiliary-pack-2.d.ts +391 -0
  71. package/generated/quest-auxiliary-pack-2.validator.js +17 -0
  72. package/generated/quest-browse-pack-2.d.ts +353 -0
  73. package/generated/quest-browse-pack-2.validator.js +17 -0
  74. package/generated/quest-catalog-2.d.ts +501 -0
  75. package/generated/quest-catalog-2.validator.js +17 -0
  76. package/generated/quest-evidence-pack-2.d.ts +269 -0
  77. package/generated/quest-evidence-pack-2.validator.js +17 -0
  78. package/generated/quest-pack-2.d.ts +410 -0
  79. package/generated/quest-pack-2.validator.js +17 -0
  80. package/generated/quest-relationship-pack-2.d.ts +868 -0
  81. package/generated/quest-relationship-pack-2.validator.js +17 -0
  82. package/generated/release-build-index.d.ts +42 -0
  83. package/generated/release-build-index.validator.js +1 -0
  84. package/generated/release-manifest.d.ts +24 -0
  85. package/generated/release-manifest.validator.js +1 -0
  86. package/generated/release-pin.d.ts +12 -0
  87. package/generated/release-pin.validator.js +1 -0
  88. package/package.json +155 -0
@@ -0,0 +1,155 @@
1
+ import validateCatalog from '../generated/monster-catalog.validator.js';
2
+ import validateCatalogV2 from '../generated/monster-catalog-2.validator.js';
3
+ import { MissingPageError, MissingRecordError, SchemaValidationError, UnsupportedProductError, assertEnvelopeVersion, assertSameScope, lazyValidator, memoized, openProductContext, rangeDescriptor, recordRangeDescriptor, } from './core.js';
4
+ const loadDetailPack = lazyValidator(() => import('../generated/monster-pack.validator.js'));
5
+ const loadDetail = lazyValidator(() => import('../generated/monster-detail.validator.js'));
6
+ const loadDetailPackV2 = lazyValidator(() => import('../generated/monster-pack-2.validator.js'));
7
+ const loadDetailV2 = lazyValidator(() => import('../generated/monster-detail-2.validator.js'));
8
+ const loadRelationships = lazyValidator(() => import('../generated/monster-relationship-pack.validator.js'));
9
+ const loadLocationsV2 = lazyValidator(() => import('../generated/monster-location-pack-2.validator.js'));
10
+ const loadCoreRelationshipsV2 = lazyValidator(() => import('../generated/monster-core-relationship-pack-2.validator.js'));
11
+ const loadEvidence = lazyValidator(() => import('../generated/monster-evidence-pack.validator.js'));
12
+ const loadEvidenceV2 = lazyValidator(() => import('../generated/monster-evidence-pack-2.validator.js'));
13
+ /** Build a Monster client over an already verified product manifest. */
14
+ export function monsterProductClient(context) {
15
+ const { manifest, contract2, fetchEnvelope } = context;
16
+ if (manifest.productId !== 'monsters')
17
+ throw new UnsupportedProductError(manifest.productId);
18
+ let catalogPromise;
19
+ const detailPackCache = new Map();
20
+ const detailPackV2Cache = new Map();
21
+ const relationshipPackCache = new Map();
22
+ const locationPackV2Cache = new Map();
23
+ const coreRelationshipPackCache = new Map();
24
+ const evidencePackCache = new Map();
25
+ const evidencePackV2Cache = new Map();
26
+ async function loadCatalog(operation) {
27
+ if (!catalogPromise) {
28
+ catalogPromise = contract2
29
+ ? fetchEnvelope(manifest.catalog, 'catalog', validateCatalogV2, operation)
30
+ : fetchEnvelope(manifest.catalog, 'catalog', validateCatalog, operation);
31
+ void catalogPromise.catch(() => { catalogPromise = undefined; });
32
+ }
33
+ const catalog = await catalogPromise;
34
+ if (catalog.records.length !== catalog.recordCount) {
35
+ throw new SchemaValidationError(manifest.catalog.path, 'recordCount does not match records length');
36
+ }
37
+ return catalog;
38
+ }
39
+ async function getDetail(key, operation) {
40
+ const descriptor = recordRangeDescriptor(manifest.detailPacks, key, 'detail', 'Monster');
41
+ if (contract2) {
42
+ const [validatePack, validateRecord] = await Promise.all([loadDetailPackV2(), loadDetailV2()]);
43
+ const pack = await memoized(detailPackV2Cache, descriptor.path, () => (fetchEnvelope(descriptor, 'detail', validatePack, operation)));
44
+ if (!Object.hasOwn(pack.records, key))
45
+ throw new MissingRecordError(key);
46
+ const detail = pack.records[key];
47
+ if (!detail)
48
+ throw new MissingRecordError(key);
49
+ if (!validateRecord(detail)) {
50
+ throw new SchemaValidationError(descriptor.path, JSON.stringify(validateRecord.errors ?? []));
51
+ }
52
+ assertEnvelopeVersion(detail.contractVersion, context.minimumVersion, key);
53
+ assertSameScope(detail.scope, manifest.scope, key);
54
+ return detail;
55
+ }
56
+ const [validatePack, validateRecord] = await Promise.all([loadDetailPack(), loadDetail()]);
57
+ const pack = await memoized(detailPackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'detail', validatePack, operation)));
58
+ if (!Object.hasOwn(pack.records, key))
59
+ throw new MissingRecordError(key);
60
+ const detail = pack.records[key];
61
+ if (!detail)
62
+ throw new MissingRecordError(key);
63
+ if (!validateRecord(detail)) {
64
+ throw new SchemaValidationError(descriptor.path, JSON.stringify(validateRecord.errors ?? []));
65
+ }
66
+ assertEnvelopeVersion(detail.contractVersion, context.minimumVersion, key);
67
+ assertSameScope(detail.scope, manifest.scope, key);
68
+ return detail;
69
+ }
70
+ async function getRelationshipPage(page, operation) {
71
+ if (contract2) {
72
+ if (page.recordKind !== 'locations')
73
+ throw new MissingPageError(page.recordKey, 'location');
74
+ const descriptor = rangeDescriptor(manifest.relationshipPacks, page.recordKey, 'location');
75
+ const validator = await loadLocationsV2();
76
+ const pack = await memoized(locationPackV2Cache, descriptor.path, () => (fetchEnvelope(descriptor, 'relationship', validator, operation)));
77
+ const record = pack.records[page.recordKey];
78
+ if (!record)
79
+ throw new MissingRecordError(page.recordKey);
80
+ if (record.occurrences.length !== page.count)
81
+ throw new MissingPageError(page.recordKey, 'location');
82
+ return record.occurrences;
83
+ }
84
+ if (page.recordKind !== 'relationships') {
85
+ throw new MissingPageError(page.recordKey, 'relationship');
86
+ }
87
+ const descriptor = rangeDescriptor(manifest.relationshipPacks, page.recordKey, 'relationship');
88
+ const validator = await loadRelationships();
89
+ const pack = await memoized(relationshipPackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'relationship', validator, operation)));
90
+ if (!Object.hasOwn(pack.records, page.recordKey)) {
91
+ throw new MissingRecordError(page.recordKey);
92
+ }
93
+ const records = pack.records[page.recordKey];
94
+ if (!records || records.length !== page.count)
95
+ throw new MissingPageError(page.recordKey, 'relationship');
96
+ return records;
97
+ }
98
+ async function getEvidencePage(page, operation) {
99
+ if (contract2) {
100
+ if (page.recordKind !== 'drop-evidence' && page.recordKind !== 'quests') {
101
+ throw new MissingPageError(page.recordKey, 'evidence');
102
+ }
103
+ const descriptor = rangeDescriptor(manifest.evidencePacks ?? [], page.recordKey, 'evidence');
104
+ const validator = await loadEvidenceV2();
105
+ const pack = await memoized(evidencePackV2Cache, descriptor.path, () => (fetchEnvelope(descriptor, 'evidence', validator, operation)));
106
+ const record = pack.records[page.recordKey];
107
+ if (!record || (record.dropAssertions?.length ?? 0) + (record.quests?.length ?? 0) + (record.sourceEvidence?.length ?? 0) !== page.count) {
108
+ throw new MissingPageError(page.recordKey, 'evidence');
109
+ }
110
+ return record;
111
+ }
112
+ if (page.recordKind !== 'evidence') {
113
+ throw new MissingPageError(page.recordKey, 'evidence');
114
+ }
115
+ const descriptor = rangeDescriptor(manifest.evidencePacks ?? [], page.recordKey, 'evidence');
116
+ const validator = await loadEvidence();
117
+ const pack = await memoized(evidencePackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'evidence', validator, operation)));
118
+ if (!Object.hasOwn(pack.records, page.recordKey)) {
119
+ throw new MissingRecordError(page.recordKey);
120
+ }
121
+ const records = pack.records[page.recordKey];
122
+ if (!records || records.drops.length + records.quests.length !== page.count) {
123
+ throw new MissingPageError(page.recordKey, 'evidence');
124
+ }
125
+ return records;
126
+ }
127
+ async function getCoreRelationshipPage(page, operation) {
128
+ if (!contract2 || page.recordKind !== 'core-relationships') {
129
+ throw new MissingPageError(page.recordKey, 'core relationship');
130
+ }
131
+ const descriptor = rangeDescriptor(manifest.coreRelationshipPacks ?? [], page.recordKey, 'core relationship');
132
+ const validator = await loadCoreRelationshipsV2();
133
+ const pack = await memoized(coreRelationshipPackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'core-relationship', validator, operation)));
134
+ const record = pack.records[page.recordKey];
135
+ if (!record || record.occurrences.length !== page.count) {
136
+ throw new MissingPageError(page.recordKey, 'core relationship');
137
+ }
138
+ return record;
139
+ }
140
+ return {
141
+ manifest,
142
+ loadCatalog,
143
+ getDetail,
144
+ getRelationshipPage,
145
+ getEvidencePage,
146
+ getCoreRelationshipPage,
147
+ };
148
+ }
149
+ /** Open one pinned Monster product. */
150
+ export async function openMonsterProduct(options) {
151
+ return monsterProductClient(await openProductContext(options));
152
+ }
153
+ export function isMonsterProductClient(client) {
154
+ return client.manifest.productId === 'monsters' || client.manifest.productId === undefined;
155
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `@mapletip/data/monsters` — Monster browse and Monster product operations.
3
+ *
4
+ * This entry pulls the verified release core and the Monster client (with its catalog
5
+ * validators) and nothing else: Item, Equipment, Media, Quest, static-domain code and
6
+ * Monster detail/relationship/evidence validators stay out of the initial graph.
7
+ */
8
+ import type { StaticMonsterCatalog } from './monster-client.js';
9
+ import { type OpenReleaseOptions } from './release.js';
10
+ export { isMonsterProductClient, openMonsterProduct } from './monster-client.js';
11
+ export type { StaticMonsterCatalog, StaticMonsterDetail, StaticMonsterEvidencePage, StaticProductClient, } from './monster-client.js';
12
+ export type { OpenReleaseOptions };
13
+ /** Options for the one-shot Monster catalog read: an opened release plus the build to read. */
14
+ export type GetMonsterBrowseOptions = OpenReleaseOptions & {
15
+ readonly buildId: string;
16
+ };
17
+ /**
18
+ * Read one build's verified Monster catalog in a single call.
19
+ *
20
+ * Equivalent to `openRelease(options)` → `openBuild(options.buildId)` →
21
+ * `loadCatalog()`; it adds no caching, fallback or alternate data path. Use the
22
+ * lower-level release client when several domain reads share one release.
23
+ */
24
+ export declare function getMonsterBrowse(options: GetMonsterBrowseOptions): Promise<StaticMonsterCatalog>;
@@ -0,0 +1,14 @@
1
+ import { openRelease } from './release.js';
2
+ export { isMonsterProductClient, openMonsterProduct } from './monster-client.js';
3
+ /**
4
+ * Read one build's verified Monster catalog in a single call.
5
+ *
6
+ * Equivalent to `openRelease(options)` → `openBuild(options.buildId)` →
7
+ * `loadCatalog()`; it adds no caching, fallback or alternate data path. Use the
8
+ * lower-level release client when several domain reads share one release.
9
+ */
10
+ export async function getMonsterBrowse(options) {
11
+ const release = await openRelease(options);
12
+ const monster = await release.openBuild(options.buildId);
13
+ return monster.loadCatalog({ signal: options.signal });
14
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Quest product client. Every Quest validator is loaded on the first operation that
3
+ * needs it, so a Quest browse or detail read never downloads the others and no other
4
+ * domain downloads Quest validators.
5
+ */
6
+ import type { QuestCatalog } from '../generated/quest-catalog-2.d.ts';
7
+ import type { QuestBrowsePack, QuestBrowseRecord } from '../generated/quest-browse-pack-2.d.ts';
8
+ import type { QuestDetailPack, QuestDetailRecord } from '../generated/quest-pack-2.d.ts';
9
+ import type { QuestRelationshipPack, QuestRelationshipRecord } from '../generated/quest-relationship-pack-2.d.ts';
10
+ import type { QuestAuxiliaryPack, QuestAuxiliaryPage } from '../generated/quest-auxiliary-pack-2.d.ts';
11
+ import type { QuestEvidencePack, QuestEvidencePage } from '../generated/quest-evidence-pack-2.d.ts';
12
+ import { type GetRelationshipOptions, type OpenProductOptions, type OperationOptions, type StaticProductManifest, type VerifiedProductContext } from './core.js';
13
+ export type { GetRelationshipOptions };
14
+ export type { QuestCatalog, QuestBrowsePack, QuestBrowseRecord, QuestDetailPack, QuestDetailRecord, QuestRelationshipPack, QuestRelationshipRecord, QuestAuxiliaryPack, QuestAuxiliaryPage, QuestEvidencePack, QuestEvidencePage, };
15
+ export interface StaticQuestProductClient {
16
+ readonly manifest: StaticProductManifest;
17
+ loadCatalog(options?: OperationOptions): Promise<QuestCatalog>;
18
+ loadBrowsePacks(options?: OperationOptions): Promise<readonly QuestBrowsePack[]>;
19
+ getBrowseRecord(key: string, options?: OperationOptions): Promise<QuestBrowseRecord>;
20
+ getDetail(key: string, options?: OperationOptions): Promise<QuestDetailRecord>;
21
+ getRelationshipPage(pageKey: string, options?: GetRelationshipOptions): Promise<QuestRelationshipRecord>;
22
+ getAuxiliaryPage(pageKey: string, options?: OperationOptions): Promise<QuestAuxiliaryPage>;
23
+ getEvidencePage(pageKey: string, options?: OperationOptions): Promise<QuestEvidencePage>;
24
+ }
25
+ /** Build a Quest client over an already verified product manifest. */
26
+ export declare function questProductClient(context: VerifiedProductContext): StaticQuestProductClient;
27
+ /** Open one pinned Quest product. */
28
+ export declare function openQuestProduct(options: OpenProductOptions): Promise<StaticQuestProductClient>;
29
+ export declare function isQuestProductClient(client: {
30
+ readonly manifest: StaticProductManifest;
31
+ }): client is StaticQuestProductClient;
@@ -0,0 +1,124 @@
1
+ import { MissingPageError, MissingRecordError, SchemaValidationError, ScopeError, UnsupportedCapabilityError, UnsupportedProductError, lazyValidator, memoized, openProductContext, rangeDescriptor, recordRangeDescriptor, } from './core.js';
2
+ const loadCatalogValidator = lazyValidator(() => import('../generated/quest-catalog-2.validator.js'));
3
+ const loadBrowsePackValidator = lazyValidator(() => import('../generated/quest-browse-pack-2.validator.js'));
4
+ const loadDetailPackValidator = lazyValidator(() => import('../generated/quest-pack-2.validator.js'));
5
+ const loadRelationshipPackValidator = lazyValidator(() => import('../generated/quest-relationship-pack-2.validator.js'));
6
+ const loadAuxiliaryPackValidator = lazyValidator(() => import('../generated/quest-auxiliary-pack-2.validator.js'));
7
+ const loadEvidencePackValidator = lazyValidator(() => import('../generated/quest-evidence-pack-2.validator.js'));
8
+ /** Build a Quest client over an already verified product manifest. */
9
+ export function questProductClient(context) {
10
+ const { manifest, fetchEnvelope } = context;
11
+ if (manifest.productId !== 'quests')
12
+ throw new UnsupportedProductError(manifest.productId);
13
+ let catalogPromise;
14
+ const browsePackCache = new Map();
15
+ const detailPackCache = new Map();
16
+ const relationshipPackCache = new Map();
17
+ const auxiliaryPackCache = new Map();
18
+ const evidencePackCache = new Map();
19
+ function loadCatalog(operation) {
20
+ if (!catalogPromise) {
21
+ catalogPromise = (async () => {
22
+ const validator = await loadCatalogValidator();
23
+ const catalog = await fetchEnvelope(manifest.catalog, 'catalog', validator, operation);
24
+ if (catalog.recordCount?.state === 'known' && catalog.records?.state === 'known') {
25
+ if (catalog.recordCount.value !== catalog.records.items.length) {
26
+ throw new SchemaValidationError(manifest.catalog.path, 'recordCount does not match records length');
27
+ }
28
+ }
29
+ return catalog;
30
+ })();
31
+ void catalogPromise.catch(() => { catalogPromise = undefined; });
32
+ }
33
+ return catalogPromise;
34
+ }
35
+ async function loadBrowsePacks(operation) {
36
+ if (!manifest.browsePacks) {
37
+ throw new UnsupportedCapabilityError('Quest product manifest does not provide browse packs');
38
+ }
39
+ const packs = manifest.browsePacks;
40
+ const validator = await loadBrowsePackValidator();
41
+ return Promise.all(packs.map((descriptor) => (memoized(browsePackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'browse', validator, operation))))));
42
+ }
43
+ async function getBrowseRecord(key, operation) {
44
+ if (!manifest.browsePacks) {
45
+ throw new UnsupportedCapabilityError('Quest product manifest does not provide browse packs');
46
+ }
47
+ const descriptor = recordRangeDescriptor(manifest.browsePacks, key, 'browse', 'Quest');
48
+ const validator = await loadBrowsePackValidator();
49
+ const pack = await memoized(browsePackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'browse', validator, operation)));
50
+ if (!Object.hasOwn(pack.records, key))
51
+ throw new MissingRecordError(key, 'Quest');
52
+ const record = pack.records[key];
53
+ if (!record || record.key !== key)
54
+ throw new MissingRecordError(key, 'Quest');
55
+ return record;
56
+ }
57
+ async function getDetail(key, operation) {
58
+ const descriptor = recordRangeDescriptor(manifest.detailPacks, key, 'detail', 'Quest');
59
+ const validator = await loadDetailPackValidator();
60
+ const pack = await memoized(detailPackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'detail', validator, operation)));
61
+ if (!Object.hasOwn(pack.records, key))
62
+ throw new MissingRecordError(key, 'Quest');
63
+ const detail = pack.records[key];
64
+ if (!detail || detail.key !== key)
65
+ throw new MissingRecordError(key, 'Quest');
66
+ return detail;
67
+ }
68
+ async function getRelationshipPage(pageKey, operation) {
69
+ const descriptor = rangeDescriptor(manifest.relationshipPacks, pageKey, 'relationship');
70
+ const validator = await loadRelationshipPackValidator();
71
+ const pack = await memoized(relationshipPackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'relationship', validator, operation)));
72
+ if (!Object.hasOwn(pack.records, pageKey))
73
+ throw new MissingPageError(pageKey, 'relationship');
74
+ const record = pack.records[pageKey];
75
+ if (!record || record.recordKey !== pageKey)
76
+ throw new MissingPageError(pageKey, 'relationship');
77
+ if (operation?.expectedOwnerKey !== undefined && record.ownerKey !== operation.expectedOwnerKey) {
78
+ throw new ScopeError(`Relationship page ${pageKey} owner ${record.ownerKey} does not match expected ${operation.expectedOwnerKey}`);
79
+ }
80
+ return record;
81
+ }
82
+ async function getAuxiliaryPage(pageKey, operation) {
83
+ if (!manifest.coreRelationshipPacks || manifest.coreRelationshipPacks.length === 0) {
84
+ throw new UnsupportedCapabilityError('Quest product manifest does not provide auxiliary (coreRelationshipPacks) packs');
85
+ }
86
+ const descriptor = rangeDescriptor(manifest.coreRelationshipPacks, pageKey, 'auxiliary');
87
+ const validator = await loadAuxiliaryPackValidator();
88
+ const pack = await memoized(auxiliaryPackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'auxiliary', validator, operation)));
89
+ if (!Object.hasOwn(pack.records, pageKey))
90
+ throw new MissingPageError(pageKey, 'auxiliary');
91
+ const page = pack.records[pageKey];
92
+ if (!page || page.recordKey !== pageKey)
93
+ throw new MissingPageError(pageKey, 'auxiliary');
94
+ return page;
95
+ }
96
+ async function getEvidencePage(pageKey, operation) {
97
+ const descriptor = rangeDescriptor(manifest.evidencePacks ?? [], pageKey, 'evidence');
98
+ const validator = await loadEvidencePackValidator();
99
+ const pack = await memoized(evidencePackCache, descriptor.path, () => (fetchEnvelope(descriptor, 'evidence', validator, operation)));
100
+ if (!Object.hasOwn(pack.records, pageKey))
101
+ throw new MissingPageError(pageKey, 'evidence');
102
+ const page = pack.records[pageKey];
103
+ if (!page || page.recordKey !== pageKey)
104
+ throw new MissingPageError(pageKey, 'evidence');
105
+ return page;
106
+ }
107
+ return {
108
+ manifest,
109
+ loadCatalog,
110
+ loadBrowsePacks,
111
+ getBrowseRecord,
112
+ getDetail,
113
+ getRelationshipPage,
114
+ getAuxiliaryPage,
115
+ getEvidencePage,
116
+ };
117
+ }
118
+ /** Open one pinned Quest product. */
119
+ export async function openQuestProduct(options) {
120
+ return questProductClient(await openProductContext(options));
121
+ }
122
+ export function isQuestProductClient(client) {
123
+ return client.manifest.productId === 'quests';
124
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Verified release selection: immutable pin, release manifest and build index
3
+ * verification plus build-scoped product openers.
4
+ *
5
+ * The Monster client is a static dependency because `openBuild` is the release
6
+ * client's primary build selector and `getMonsterBrowse` must not defer code it
7
+ * immediately needs. Every other domain opener loads its implementation on demand, so
8
+ * release metadata verification and Monster selection never pull Item, Equipment,
9
+ * Media, Quest or static-domain code into a consumer's initial graph.
10
+ */
11
+ import type { ReleaseBuildIndex } from '../generated/release-build-index.d.ts';
12
+ import type { ReleaseManifest } from '../generated/release-manifest.d.ts';
13
+ import type { ReleasePin } from '../generated/release-pin.d.ts';
14
+ import { type RequestLogHook } from './core.js';
15
+ import { type StaticProductClient } from './monster-client.js';
16
+ import type { StaticItemProductClient } from './items.js';
17
+ import type { StaticEquipmentProductClient } from './equipment.js';
18
+ import type { StaticQuestProductClient } from './quests.js';
19
+ import type { StaticMediaProductClient } from './media.js';
20
+ import type { StaticDomainProductClient } from './static-domains.js';
21
+ export type ReleaseProductDescriptor = ReleaseBuildIndex['builds'][number]['products'][number];
22
+ export interface StaticReleaseBuild {
23
+ readonly family: string;
24
+ readonly build: string;
25
+ readonly productDescriptor?: ReleaseProductDescriptor;
26
+ readonly monsterProductDescriptor?: ReleaseProductDescriptor;
27
+ readonly itemProductDescriptor?: ReleaseProductDescriptor;
28
+ readonly equipmentProductDescriptor?: ReleaseProductDescriptor;
29
+ readonly questProductDescriptor?: ReleaseProductDescriptor;
30
+ readonly mediaProductDescriptor?: ReleaseProductDescriptor;
31
+ readonly domainProductDescriptors: Readonly<Record<string, ReleaseProductDescriptor>>;
32
+ readonly productCapabilities: readonly string[];
33
+ }
34
+ export interface OpenReleaseOptions {
35
+ /** Directory URL containing the selected release's content-addressed files. */
36
+ readonly baseUrl: string | URL;
37
+ /** Immutable local release pin. Its digest and byte length pin the manifest. */
38
+ readonly pin: ReleasePin;
39
+ /** Caller-injected immutable release metadata, verified before parsing. */
40
+ readonly preloaded?: {
41
+ readonly releaseManifest: Uint8Array | string;
42
+ readonly buildIndex: Uint8Array | string;
43
+ };
44
+ readonly signal?: AbortSignal;
45
+ readonly fetch?: typeof globalThis.fetch;
46
+ readonly onRequest?: RequestLogHook;
47
+ }
48
+ export interface StaticReleaseClient {
49
+ readonly manifest: ReleaseManifest;
50
+ readonly builds: readonly StaticReleaseBuild[];
51
+ openBuild(buildId: string): Promise<StaticProductClient>;
52
+ openItemBuild(buildId: string): Promise<StaticItemProductClient>;
53
+ openEquipmentBuild(buildId: string): Promise<StaticEquipmentProductClient>;
54
+ openQuestBuild(buildId: string): Promise<StaticQuestProductClient>;
55
+ openMediaBuild(buildId: string): Promise<StaticMediaProductClient>;
56
+ openDomainBuild(buildId: string, domain: string): Promise<StaticDomainProductClient>;
57
+ }
58
+ export type TargetAvailability = 'available' | 'not-available' | 'unknown';
59
+ /** Resolve a target against the verified product roster in its build envelope. */
60
+ export declare function resolveTargetAvailability(build: Pick<StaticReleaseBuild, 'productCapabilities'>, target: Readonly<{
61
+ kind: string;
62
+ }>): TargetAvailability;
63
+ export declare function openRelease(options: OpenReleaseOptions): Promise<StaticReleaseClient>;