@the_library/standard-adapters 0.0.0-stage → 1.0.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 (60) hide show
  1. package/README.md +191 -2
  2. package/dist/bbk/index.d.ts +9 -0
  3. package/dist/bbk/index.js +3 -0
  4. package/dist/bbk/index.js.map +1 -0
  5. package/dist/cc/index.d.ts +9 -0
  6. package/dist/cc/index.js +3 -0
  7. package/dist/cc/index.js.map +1 -0
  8. package/dist/chunk-3OK4JVCA.js +108 -0
  9. package/dist/chunk-3OK4JVCA.js.map +1 -0
  10. package/dist/chunk-AHIDYNLW.js +28 -0
  11. package/dist/chunk-AHIDYNLW.js.map +1 -0
  12. package/dist/chunk-C5WHAJXI.js +26 -0
  13. package/dist/chunk-C5WHAJXI.js.map +1 -0
  14. package/dist/chunk-D5QOJWWA.js +26 -0
  15. package/dist/chunk-D5QOJWWA.js.map +1 -0
  16. package/dist/chunk-DX6SH342.js +65 -0
  17. package/dist/chunk-DX6SH342.js.map +1 -0
  18. package/dist/chunk-GJJ6NIDQ.js +58 -0
  19. package/dist/chunk-GJJ6NIDQ.js.map +1 -0
  20. package/dist/chunk-IJYCM5NU.js +26 -0
  21. package/dist/chunk-IJYCM5NU.js.map +1 -0
  22. package/dist/chunk-INW2BUCX.js +26 -0
  23. package/dist/chunk-INW2BUCX.js.map +1 -0
  24. package/dist/chunk-KNGZ7NJF.js +82 -0
  25. package/dist/chunk-KNGZ7NJF.js.map +1 -0
  26. package/dist/chunk-KOHT5EA3.js +26 -0
  27. package/dist/chunk-KOHT5EA3.js.map +1 -0
  28. package/dist/chunk-VP4ER7MD.js +26 -0
  29. package/dist/chunk-VP4ER7MD.js.map +1 -0
  30. package/dist/clc/index.d.ts +9 -0
  31. package/dist/clc/index.js +3 -0
  32. package/dist/clc/index.js.map +1 -0
  33. package/dist/ddc/index.d.ts +9 -0
  34. package/dist/ddc/index.js +3 -0
  35. package/dist/ddc/index.js.map +1 -0
  36. package/dist/index.d.ts +21 -0
  37. package/dist/index.js +13 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/isbn/index.d.ts +30 -0
  40. package/dist/isbn/index.js +3 -0
  41. package/dist/isbn/index.js.map +1 -0
  42. package/dist/isni/index.d.ts +18 -0
  43. package/dist/isni/index.js +3 -0
  44. package/dist/isni/index.js.map +1 -0
  45. package/dist/issn/index.d.ts +18 -0
  46. package/dist/issn/index.js +3 -0
  47. package/dist/issn/index.js.map +1 -0
  48. package/dist/lcc/index.d.ts +9 -0
  49. package/dist/lcc/index.js +3 -0
  50. package/dist/lcc/index.js.map +1 -0
  51. package/dist/orcid/index.d.ts +24 -0
  52. package/dist/orcid/index.js +3 -0
  53. package/dist/orcid/index.js.map +1 -0
  54. package/dist/tlc/index.d.ts +9 -0
  55. package/dist/tlc/index.js +3 -0
  56. package/dist/tlc/index.js.map +1 -0
  57. package/dist/udc/index.d.ts +9 -0
  58. package/dist/udc/index.js +3 -0
  59. package/dist/udc/index.js.map +1 -0
  60. package/package.json +76 -4
package/README.md CHANGED
@@ -1,3 +1,192 @@
1
- # Temporary Holding Version
1
+ # `@the_library/standard-adapters`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Runtime `StandardAdapter` implementations for every international identifier and classification standard defined in the companion package [`@the_library/canonical-schemas`](../canonical-schemas). This package ships **executable code** — normalization, validation, check-digit algorithms, and external API lookups. `canonical-schemas` ships the JSON governance data and TypeScript interfaces those implementations satisfy.
4
+
5
+ > If `canonical-schemas` answers "what is an ISBN and what props does it contribute?", `standard-adapters` answers "given a string, is it a valid ISBN, and how do I fetch metadata for it?"
6
+
7
+ ---
8
+
9
+ ## Licence
10
+
11
+ Published under the **D-Open Code Sovereign Licence v1.0**, the same licence covering `canonical-schemas` and the rest of the D-SAFE engine. See [`canonical-schemas/README.md`](../canonical-schemas/README.md#the-d-open-code-sovereign-licence--source-code) for the full licence architecture.
12
+
13
+ ---
14
+
15
+ ## Package layout
16
+
17
+ ```
18
+ packages/standard-adapters/
19
+ src/
20
+ index.ts Barrel export — all 11 adapters + apiKeyDictionary
21
+ api-keys.ts apiKeyDictionary singleton (set/get/require)
22
+
23
+ isbn/index.ts ISBNAdapter — Open Library + Google Books APIs
24
+ isbn/types.ts OpenLibraryBookResult, GoogleBooksVolumeResult
25
+ isbn/isbn.test.ts
26
+
27
+ issn/index.ts ISSNAdapter
28
+ isni/index.ts ISNIAdapter — ISNI SRU API
29
+ orcid/index.ts ORCIDAdapter — ORCID Public Record + Search APIs
30
+
31
+ ddc/index.ts DDCAdapter — classification, no external API
32
+ lcc/index.ts LCCAdapter — classification, no external API
33
+ udc/index.ts UDCAdapter — classification, no external API
34
+ clc/index.ts CLCAdapter — classification, no external API
35
+ bbk/index.ts BBKAdapter — classification, no external API
36
+ tlc/index.ts TLCAdapter — classification, no external API
37
+ cc/index.ts CCAdapter — classification, no external API
38
+
39
+ tsup.config.ts Per-adapter entry points → subpath exports
40
+ vitest.config.ts include: src/**/*.test.ts
41
+ ```
42
+
43
+ Each identifier standard (`isbn`, `issn`, `isni`, `orcid`) also has a `types.ts` declaring the shape of its external API responses, and a `*.test.ts` covering `normalize` / `validate` / `toLinkedDataUri` plus an `INTEGRATION`-gated live-API test (see [Testing](#testing) below). Classification standards (`ddc`, `lcc`, `udc`, `clc`, `bbk`, `tlc`, `cc`) have no external lookup — a classifier assigns the notation manually — so they carry no `types.ts` and an empty `apis: {}`.
44
+
45
+ ---
46
+
47
+ ## The `StandardAdapter` contract
48
+
49
+ Every export in this package implements the interface defined in `@the_library/canonical-schemas/types/StandardAdapter`:
50
+
51
+ ```typescript
52
+ export interface StandardAdapter<TProps, TApis> {
53
+ readonly standardId: string;
54
+ readonly uriScheme: string | null;
55
+ readonly apis: TApis;
56
+ normalize(value: string): string;
57
+ display(value: string): string;
58
+ validate(value: string | null | undefined): ValidationResult;
59
+ toLinkedDataUri(value: string): string;
60
+ }
61
+ ```
62
+
63
+ - **`normalize`** — canonicalizes input into the standard's authoritative storage form (e.g. ISBN-10 → ISBN-13, hyphens stripped). This is the form persisted on-chain.
64
+ - **`display`** — re-hyphenates/formats the normalized value for UI presentation (e.g. `978-0-262-03384-8`).
65
+ - **`validate`** — runs pattern matching and, where applicable, the standard's check-digit algorithm (`isbn-13-luhn`, `iso7064-mod11-2`). Returns `{ valid, error? }` rather than throwing, so callers can surface the reason inline.
66
+ - **`toLinkedDataUri`** — produces the RDF/LOD-compatible URI (`urn:isbn:...`, `https://orcid.org/...`, `https://id.loc.gov/authorities/classification/...`) used for external linked-data output.
67
+ - **`apis`** — a map of `StandardApiAdapter<TProps, TResult>` objects (`{ apiId, name, fetch(props) }`) for standards with external lookups. Empty (`{}`) for classification standards.
68
+
69
+ Governance policy (see `canonical-schemas/governance/GOVERNANCE.md`) requires each adapter's `apis` keys to match the `externalApis[].id` entries declared in the corresponding `canonical-schemas/standards/<id>.json` file 1:1. **Note:** as of this writing, `packages/db_schemas/src/compiler.ts` enforces standard existence, `uriScheme` presence, and prop-name collisions for `uidStrategy`/`instanceUidStrategy` — it does not yet cross-check `externalApis[].id` against an adapter's `apis` object keys at build time. Keeping the two in sync is currently a code-review convention, not a compiler-enforced invariant.
70
+
71
+ ### Example: `ISBNAdapter`
72
+
73
+ ```typescript
74
+ import { ISBNAdapter } from '@the_library/standard-adapters/isbn';
75
+
76
+ ISBNAdapter.normalize('0-262-03384-4'); // '9780262033848'
77
+ ISBNAdapter.display('9780262033848'); // '978-0-262-03384-8'
78
+ ISBNAdapter.validate('978-0-262-03384-8'); // { valid: true }
79
+ ISBNAdapter.toLinkedDataUri('9780262033848'); // 'urn:isbn:9780262033848'
80
+
81
+ const meta = await ISBNAdapter.apis.openlibrary.fetch({ isbn: '9780262033848' });
82
+ // { title, authors, publishDate, pageCount, coverUrl, description }
83
+ ```
84
+
85
+ ### Example: a classification adapter (no external API)
86
+
87
+ ```typescript
88
+ import { DDCAdapter } from '@the_library/standard-adapters/ddc';
89
+
90
+ DDCAdapter.validate('813.54'); // { valid: true }
91
+ DDCAdapter.apis; // {}
92
+ ```
93
+
94
+ ---
95
+
96
+ ## `apiKeyDictionary`
97
+
98
+ Adapters that call an API requiring credentials (`googlebooks` today; `requiresApiKey: true` in the standard's `externalApis[]` entry) read from a package-local singleton rather than accepting keys as arguments:
99
+
100
+ ```typescript
101
+ import { apiKeyDictionary } from '@the_library/standard-adapters';
102
+
103
+ apiKeyDictionary.set('googlebooks', import.meta.env.VITE_GOOGLE_BOOKS_API_KEY);
104
+ ```
105
+
106
+ - `set(apiId, value)` — throws if `value` is empty.
107
+ - `get(apiId)` — returns `undefined` if unset.
108
+ - `require(apiId)` — used internally by adapters; throws immediately with a message naming the missing key if not configured. Fail fast at configuration time, not mid-request.
109
+
110
+ This singleton, and all network calls, live entirely in this package. `canonical-schemas` has no knowledge of it and no runtime dependency on `fetch`.
111
+
112
+ ---
113
+
114
+ ## Standards implemented
115
+
116
+ | Adapter | Standard ID | External APIs | Check digit |
117
+ |---|---|---|---|
118
+ | `ISBNAdapter` | `isbn` | Open Library, Google Books (`requiresApiKey`) | `isbn-13-luhn` |
119
+ | `ISSNAdapter` | `issn` | — | `iso7064-mod11-2` |
120
+ | `ISNIAdapter` | `isni` | ISNI SRU | `iso7064-mod11-2` |
121
+ | `ORCIDAdapter` | `orcid` | ORCID Public Record, ORCID Public Search | `iso7064-mod11-2` |
122
+ | `DDCAdapter` | `ddc` | — | — |
123
+ | `LCCAdapter` | `lcc` | — | — |
124
+ | `UDCAdapter` | `udc` | — | — |
125
+ | `CLCAdapter` | `clc` | — | — |
126
+ | `BBKAdapter` | `bbk` | — | — |
127
+ | `TLCAdapter` | `tlc` | — | — |
128
+ | `CCAdapter` | `cc` | — | — |
129
+
130
+ Full governance metadata (governing body, ISO reference, revision cycle, field mappings) for each of these lives in the matching `canonical-schemas/standards/<id>.json` file, not here — this package only implements behavior, it doesn't restate governance facts.
131
+
132
+ ---
133
+
134
+ ## Consumers
135
+
136
+ ```
137
+ @the_library/standard-adapters
138
+ │
139
+ ▼
140
+ packages/public/src/models/ (models_v2 schema generator + generated model classes)
141
+ │ imports adapters by subpath, e.g. "@the_library/standard-adapters/isbn"
142
+ │ wires them into generated fetchFrom{ApiId}() / searchFrom{ApiId}() methods
143
+ │
144
+ ▼
145
+ apps/vue.datapond.earth, apps/book-manager
146
+ ```
147
+
148
+ The `models_v2` codegen (`packages/public/src/models/schemaGenerator.ts`) reads each canonical model's `uidStrategy` / `instanceUidStrategy`, imports the matching adapter via its **subpath export** (`@the_library/standard-adapters/isbn`, not the root barrel), and generates typed fetch/search methods on the model class from the adapter's `TApis` map.
149
+
150
+ Consumers should generally import by subpath (`@the_library/standard-adapters/ddc`) rather than the root `@the_library/standard-adapters` barrel, so bundlers only pull in the adapters actually referenced.
151
+
152
+ ---
153
+
154
+ ## Build
155
+
156
+ `tsup.config.ts` declares one entry point per adapter plus the root barrel, producing per-adapter ESM output and matching `.d.ts` files. `package.json`'s `exports` map exposes each as a subpath (`./isbn`, `./issn`, `./isni`, `./orcid`, `./ddc`, `./lcc`, `./udc`, `./clc`, `./bbk`, `./tlc`, `./cc`) so a consumer that only needs `DDCAdapter` doesn't bundle the `fetch`-calling identifier adapters.
157
+
158
+ ```sh
159
+ pnpm run build # tsup — builds dist/, one output per adapter
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Testing
165
+
166
+ ```sh
167
+ pnpm test # vitest run — normalize/validate/toLinkedDataUri, no network
168
+ pnpm run test:integration # INTEGRATION=true vitest run — also hits live external APIs
169
+ ```
170
+
171
+ Each identifier adapter's test file gates its live-API assertions behind `describe.skipIf(!process.env.INTEGRATION)`, so ordinary `pnpm test` runs are fast, deterministic, and offline — check-digit and normalization logic is covered without any network dependency. Only `test:integration` actually calls Open Library, Google Books, ISNI SRU, and ORCID.
172
+
173
+ ---
174
+
175
+ ## Adding a new standard
176
+
177
+ A new standard always requires **two coordinated PRs**, reviewed and merged together per governance policy (see the compiler caveat above — this is currently enforced by review, not by the build):
178
+
179
+ 1. **`canonical-schemas`** — add `standards/<id>.json` (`StandardDefinition`), including `externalApis[]` if applicable.
180
+ 2. **`standard-adapters`** (this package) — add `src/<id>/index.ts` implementing `StandardAdapter`, matching `apis` keys 1:1 with the JSON's `externalApis[].id` entries; add the entry point to `tsup.config.ts` and the subpath to `package.json#exports`; export it from `src/index.ts`.
181
+
182
+ See [`canonical-schemas/governance/GOVERNANCE.md`](../canonical-schemas/governance/GOVERNANCE.md) for the review and versioning rules — a new standard is a coordinated **minor** bump on both packages.
183
+
184
+ ---
185
+
186
+ ## Related packages
187
+
188
+ | Package | Role |
189
+ |---|---|
190
+ | [`@the_library/canonical-schemas`](../canonical-schemas) | Governance JSON + `StandardAdapter`/`StandardDefinition` TypeScript interfaces this package implements |
191
+ | [`packages/db_schemas`](../db_schemas) | ORM compiler (internally still logged as `db_schema_v2`); enforces `uidStrategy` standard existence, `uriScheme`, and prop collisions — does not yet cross-check `apis` keys against `externalApis[]` |
192
+ | [`packages/public`](../public) | `models_v2` schema generator; imports adapters by subpath into generated model classes |
@@ -0,0 +1,9 @@
1
+ import { StandardAdapter } from '@the_library/canonical-schemas/types/StandardAdapter';
2
+
3
+ interface BBKProps extends Record<string, string | null> {
4
+ bbkNotation: string | null;
5
+ }
6
+ type BBKApis = Record<string, never>;
7
+ declare const BBKAdapter: StandardAdapter<BBKProps, BBKApis>;
8
+
9
+ export { BBKAdapter };
@@ -0,0 +1,3 @@
1
+ export { BBKAdapter } from '../chunk-INW2BUCX.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,9 @@
1
+ import { StandardAdapter } from '@the_library/canonical-schemas/types/StandardAdapter';
2
+
3
+ interface CCProps extends Record<string, string | null> {
4
+ ccNotation: string | null;
5
+ }
6
+ type CCApis = Record<string, never>;
7
+ declare const CCAdapter: StandardAdapter<CCProps, CCApis>;
8
+
9
+ export { CCAdapter };
@@ -0,0 +1,3 @@
1
+ export { CCAdapter } from '../chunk-KOHT5EA3.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,108 @@
1
+ // src/api-keys.ts
2
+ var _keys = /* @__PURE__ */ new Map();
3
+ var apiKeyDictionary = {
4
+ set(apiId, value) {
5
+ if (!value) throw new Error(`[apiKeyDictionary] Empty value passed for apiId "${apiId}".`);
6
+ _keys.set(apiId, value);
7
+ },
8
+ get(apiId) {
9
+ return _keys.get(apiId);
10
+ },
11
+ require(apiId) {
12
+ const key = _keys.get(apiId);
13
+ if (!key) throw new Error(
14
+ `[${apiId}] API key is not configured. Call apiKeyDictionary.set("${apiId}", "<your-key>") before using this adapter.`
15
+ );
16
+ return key;
17
+ }
18
+ };
19
+
20
+ // src/isbn/index.ts
21
+ function validateISBN13Luhn(isbn13) {
22
+ if (isbn13.length !== 13) return { valid: false, error: `Expected 13 digits, got ${isbn13.length}` };
23
+ let sum = 0;
24
+ for (let i = 0; i < 12; i++) sum += parseInt(isbn13[i], 10) * (i % 2 === 0 ? 1 : 3);
25
+ const expected = (10 - sum % 10) % 10;
26
+ if (expected !== parseInt(isbn13[12], 10))
27
+ return { valid: false, error: `Check digit mismatch: expected ${expected}, got ${isbn13[12]}` };
28
+ return { valid: true };
29
+ }
30
+ var ISBNAdapter = {
31
+ standardId: "isbn",
32
+ uriScheme: "ISBN",
33
+ normalize(value) {
34
+ const digits = value.replace(/[\s-]/g, "");
35
+ if (digits.length === 10) {
36
+ const base = "978" + digits.slice(0, 9);
37
+ let sum = 0;
38
+ for (let i = 0; i < 12; i++) sum += parseInt(base[i], 10) * (i % 2 === 0 ? 1 : 3);
39
+ return base + (10 - sum % 10) % 10;
40
+ }
41
+ return digits;
42
+ },
43
+ display(value) {
44
+ const n = ISBNAdapter.normalize(value);
45
+ if (n.length === 13) return `${n.slice(0, 3)}-${n[3]}-${n.slice(4, 7)}-${n.slice(7, 12)}-${n[12]}`;
46
+ return n;
47
+ },
48
+ validate(value) {
49
+ if (!value) return { valid: false, error: "ISBN is absent" };
50
+ const normalized = ISBNAdapter.normalize(value);
51
+ if (!/^97[89][0-9]{10}$/.test(normalized))
52
+ return { valid: false, error: `ISBN does not match pattern: ${normalized}` };
53
+ return validateISBN13Luhn(normalized);
54
+ },
55
+ toLinkedDataUri(value) {
56
+ return `urn:isbn:${ISBNAdapter.normalize(value)}`;
57
+ },
58
+ apis: {
59
+ openlibrary: {
60
+ apiId: "openlibrary",
61
+ name: "Open Library Books API",
62
+ async fetch({ isbn }) {
63
+ if (!isbn) return {};
64
+ const res = await fetch(
65
+ `https://openlibrary.org/api/books?bibkeys=ISBN:${isbn}&format=json&jscmd=data`
66
+ );
67
+ if (!res.ok) return {};
68
+ const data = await res.json();
69
+ const book = data[`ISBN:${isbn}`] ?? {};
70
+ return {
71
+ title: book.title,
72
+ authors: book.authors?.map((a) => a.name),
73
+ publishDate: book.publish_date,
74
+ pageCount: book.number_of_pages,
75
+ coverUrl: book.cover?.medium,
76
+ description: book.excerpts?.[0]?.text
77
+ };
78
+ }
79
+ },
80
+ googlebooks: {
81
+ apiId: "googlebooks",
82
+ name: "Google Books API",
83
+ async fetch({ isbn }) {
84
+ if (!isbn) return {};
85
+ const key = apiKeyDictionary.require("googlebooks");
86
+ const res = await fetch(
87
+ `https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}&key=${key}`
88
+ );
89
+ if (!res.ok) return {};
90
+ const data = await res.json();
91
+ const info = data.items?.[0]?.volumeInfo ?? {};
92
+ return {
93
+ title: info.title,
94
+ authors: info.authors,
95
+ publishedDate: info.publishedDate,
96
+ pageCount: info.pageCount,
97
+ language: info.language,
98
+ description: info.description,
99
+ thumbnail: info.imageLinks?.thumbnail
100
+ };
101
+ }
102
+ }
103
+ }
104
+ };
105
+
106
+ export { ISBNAdapter, apiKeyDictionary };
107
+ //# sourceMappingURL=chunk-3OK4JVCA.js.map
108
+ //# sourceMappingURL=chunk-3OK4JVCA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api-keys.ts","../src/isbn/index.ts"],"names":[],"mappings":";AAoBA,IAAM,KAAA,uBAAY,GAAA,EAAoB;AAE/B,IAAM,gBAAA,GAAqC;AAAA,EAChD,GAAA,CAAI,OAAe,KAAA,EAAqB;AACtC,IAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,CAAA,iDAAA,EAAoD,KAAK,CAAA,EAAA,CAAI,CAAA;AACzF,IAAA,KAAA,CAAM,GAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EACxB,CAAA;AAAA,EAEA,IAAI,KAAA,EAAmC;AACrC,IAAA,OAAO,KAAA,CAAM,IAAI,KAAK,CAAA;AAAA,EACxB,CAAA;AAAA,EAEA,QAAQ,KAAA,EAAuB;AAC7B,IAAA,MAAM,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,KAAK,CAAA;AAC3B,IAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA;AAAA,MAClB,CAAA,CAAA,EAAI,KAAK,CAAA,wDAAA,EACqB,KAAK,CAAA,2CAAA;AAAA,KACrC;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AACF;;;ACdA,SAAS,mBAAmB,MAAA,EAAkC;AAC5D,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,EAAA,EAAI,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA,wBAAA,EAA2B,MAAA,CAAO,MAAM,CAAA,CAAA,EAAG;AACnG,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,EAAA,EAAI,KAAK,GAAA,IAAO,QAAA,CAAS,MAAA,CAAO,CAAC,GAAG,EAAE,CAAA,IAAK,CAAA,GAAI,CAAA,KAAM,IAAI,CAAA,GAAI,CAAA,CAAA;AACjF,EAAA,MAAM,QAAA,GAAA,CAAY,EAAA,GAAM,GAAA,GAAM,EAAA,IAAO,EAAA;AACrC,EAAA,IAAI,QAAA,KAAa,QAAA,CAAS,MAAA,CAAO,EAAE,GAAG,EAAE,CAAA;AACtC,IAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA,+BAAA,EAAkC,QAAQ,CAAA,MAAA,EAAS,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA,EAAG;AAChG,EAAA,OAAO,EAAE,OAAO,IAAA,EAAK;AACvB;AAEO,IAAM,WAAA,GAAoD;AAAA,EAC/D,UAAA,EAAY,MAAA;AAAA,EACZ,SAAA,EAAY,MAAA;AAAA,EAEZ,UAAU,KAAA,EAAuB;AAC/B,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AACzC,IAAA,IAAI,MAAA,CAAO,WAAW,EAAA,EAAI;AACxB,MAAA,MAAM,IAAA,GAAO,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AACtC,MAAA,IAAI,GAAA,GAAM,CAAA;AACV,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,EAAA,EAAI,KAAK,GAAA,IAAO,QAAA,CAAS,IAAA,CAAK,CAAC,GAAG,EAAE,CAAA,IAAK,CAAA,GAAI,CAAA,KAAM,IAAI,CAAA,GAAI,CAAA,CAAA;AAC/E,MAAA,OAAO,IAAA,GAAA,CAAQ,EAAA,GAAM,GAAA,GAAM,EAAA,IAAO,EAAA;AAAA,IACpC;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AAAA,EAEA,QAAQ,KAAA,EAAuB;AAC7B,IAAA,MAAM,CAAA,GAAI,WAAA,CAAY,SAAA,CAAU,KAAK,CAAA;AACrC,IAAA,IAAI,CAAA,CAAE,MAAA,KAAW,EAAA,EAAI,OAAO,CAAA,EAAG,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,EAAE,CAAC,CAAA,CAAA;AAChG,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AAAA,EAEA,SAAS,KAAA,EAAoD;AAC3D,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,gBAAA,EAAiB;AAC3D,IAAA,MAAM,UAAA,GAAa,WAAA,CAAY,SAAA,CAAU,KAAK,CAAA;AAC9C,IAAA,IAAI,CAAC,mBAAA,CAAoB,IAAA,CAAK,UAAU,CAAA;AACtC,MAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA,6BAAA,EAAgC,UAAU,CAAA,CAAA,EAAG;AAC7E,IAAA,OAAO,mBAAmB,UAAU,CAAA;AAAA,EACtC,CAAA;AAAA,EAEA,gBAAgB,KAAA,EAAuB;AACrC,IAAA,OAAO,CAAA,SAAA,EAAY,WAAA,CAAY,SAAA,CAAU,KAAK,CAAC,CAAA,CAAA;AAAA,EACjD,CAAA;AAAA,EAEA,IAAA,EAAM;AAAA,IACJ,WAAA,EAAa;AAAA,MACX,KAAA,EAAO,aAAA;AAAA,MACP,IAAA,EAAO,wBAAA;AAAA,MACP,MAAM,KAAA,CAAM,EAAE,IAAA,EAAK,EAAmC;AACpD,QAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAC;AACnB,QAAA,MAAM,MAAM,MAAM,KAAA;AAAA,UAChB,kDAAkD,IAAI,CAAA,uBAAA;AAAA,SACxD;AACA,QAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,OAAO,EAAC;AACrB,QAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,QAAA,MAAM,OAAQ,IAAA,CAAK,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAE,KAAK,EAAC;AACvC,QAAA,OAAO;AAAA,UACL,OAAa,IAAA,CAAK,KAAA;AAAA,UAClB,SAAc,IAAA,CAAK,OAAA,EAA4C,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,IAAI,CAAA;AAAA,UAC9E,aAAa,IAAA,CAAK,YAAA;AAAA,UAClB,WAAa,IAAA,CAAK,eAAA;AAAA,UAClB,QAAA,EAAc,KAAK,KAAA,EAA2C,MAAA;AAAA,UAC9D,WAAA,EAAc,IAAA,CAAK,QAAA,GAA8C,CAAC,CAAA,EAAG;AAAA,SACvE;AAAA,MACF;AAAA,KACF;AAAA,IACA,WAAA,EAAa;AAAA,MACX,KAAA,EAAO,aAAA;AAAA,MACP,IAAA,EAAO,kBAAA;AAAA,MACP,MAAM,KAAA,CAAM,EAAE,IAAA,EAAK,EAAqC;AACtD,QAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAC;AACnB,QAAA,MAAM,GAAA,GAAO,gBAAA,CAAiB,OAAA,CAAQ,aAAa,CAAA;AACnD,QAAA,MAAM,MAAO,MAAM,KAAA;AAAA,UACjB,CAAA,mDAAA,EAAsD,IAAI,CAAA,KAAA,EAAQ,GAAG,CAAA;AAAA,SACvE;AACA,QAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,OAAO,EAAC;AACrB,QAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,QAAA,MAAM,OAAO,IAAA,CAAK,KAAA,GAAQ,CAAC,CAAA,EAAG,cAAc,EAAC;AAC7C,QAAA,OAAO;AAAA,UACL,OAAe,IAAA,CAAK,KAAA;AAAA,UACpB,SAAe,IAAA,CAAK,OAAA;AAAA,UACpB,eAAe,IAAA,CAAK,aAAA;AAAA,UACpB,WAAe,IAAA,CAAK,SAAA;AAAA,UACpB,UAAe,IAAA,CAAK,QAAA;AAAA,UACpB,aAAe,IAAA,CAAK,WAAA;AAAA,UACpB,SAAA,EAAgB,KAAK,UAAA,EAAmD;AAAA,SAC1E;AAAA,MACF;AAAA;AACF;AAEJ","file":"chunk-3OK4JVCA.js","sourcesContent":["/*\n * Copyright (c) 2026 DataPond D-Library Pty Ltd. (\"The Sanctuary\")\n * Non-Profit Public Library — The World Library\n * \n * D-SAFE Certification issued by POND Enterprise.\n * Published under the D-Open Code Sovereign Licence v1.0 framework\n * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.\n * https://registry.world.bibliotech.com/licence\n * Source code donated to DataPond D-Library by it's author: data pond.\n * \n * Technical Guardian (\"The Shield\"): Pond Enterprise Pty Ltd. (ACN 694 747 987)\n * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.\n * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.\n */\nexport interface ApiKeyDictionary {\n set(apiId: string, value: string): void;\n get(apiId: string): string | undefined;\n require(apiId: string): string;\n}\n\nconst _keys = new Map<string, string>();\n\nexport const apiKeyDictionary: ApiKeyDictionary = {\n set(apiId: string, value: string): void {\n if (!value) throw new Error(`[apiKeyDictionary] Empty value passed for apiId \"${apiId}\".`);\n _keys.set(apiId, value);\n },\n\n get(apiId: string): string | undefined {\n return _keys.get(apiId);\n },\n\n require(apiId: string): string {\n const key = _keys.get(apiId);\n if (!key) throw new Error(\n `[${apiId}] API key is not configured. ` +\n `Call apiKeyDictionary.set(\"${apiId}\", \"<your-key>\") before using this adapter.`\n );\n return key;\n },\n};\n","/*\n * Copyright (c) 2026 DataPond D-Library Pty Ltd. (\"The Sanctuary\")\n * Non-Profit Public Library — The World Library\n * \n * D-SAFE Certification issued by POND Enterprise.\n * Published under the D-Open Code Sovereign Licence v1.0 framework\n * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.\n * https://registry.world.bibliotech.com/licence\n * Source code donated to DataPond D-Library by it's author: data pond.\n * \n * Technical Guardian (\"The Shield\"): Pond Enterprise Pty Ltd. (ACN 694 747 987)\n * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.\n * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.\n */\nimport type { StandardAdapter, StandardApiAdapter, ValidationResult }\n from '@the_library/canonical-schemas/types/StandardAdapter';\nimport { apiKeyDictionary } from '../api-keys';\nimport type { OpenLibraryBookResult, GoogleBooksVolumeResult } from './types';\n\ninterface ISBNProps extends Record<string, string | null> { isbn: string | null; }\n\ntype ISBNApis = {\n openlibrary: StandardApiAdapter<ISBNProps, OpenLibraryBookResult>;\n googlebooks: StandardApiAdapter<ISBNProps, GoogleBooksVolumeResult>;\n};\n\nfunction validateISBN13Luhn(isbn13: string): ValidationResult {\n if (isbn13.length !== 13) return { valid: false, error: `Expected 13 digits, got ${isbn13.length}` };\n let sum = 0;\n for (let i = 0; i < 12; i++) sum += parseInt(isbn13[i], 10) * (i % 2 === 0 ? 1 : 3);\n const expected = (10 - (sum % 10)) % 10;\n if (expected !== parseInt(isbn13[12], 10))\n return { valid: false, error: `Check digit mismatch: expected ${expected}, got ${isbn13[12]}` };\n return { valid: true };\n}\n\nexport const ISBNAdapter: StandardAdapter<ISBNProps, ISBNApis> = {\n standardId: 'isbn',\n uriScheme: 'ISBN',\n\n normalize(value: string): string {\n const digits = value.replace(/[\\s-]/g, '');\n if (digits.length === 10) {\n const base = '978' + digits.slice(0, 9);\n let sum = 0;\n for (let i = 0; i < 12; i++) sum += parseInt(base[i], 10) * (i % 2 === 0 ? 1 : 3);\n return base + (10 - (sum % 10)) % 10;\n }\n return digits;\n },\n\n display(value: string): string {\n const n = ISBNAdapter.normalize(value);\n if (n.length === 13) return `${n.slice(0, 3)}-${n[3]}-${n.slice(4, 7)}-${n.slice(7, 12)}-${n[12]}`;\n return n;\n },\n\n validate(value: string | null | undefined): ValidationResult {\n if (!value) return { valid: false, error: 'ISBN is absent' };\n const normalized = ISBNAdapter.normalize(value);\n if (!/^97[89][0-9]{10}$/.test(normalized))\n return { valid: false, error: `ISBN does not match pattern: ${normalized}` };\n return validateISBN13Luhn(normalized);\n },\n\n toLinkedDataUri(value: string): string {\n return `urn:isbn:${ISBNAdapter.normalize(value)}`;\n },\n\n apis: {\n openlibrary: {\n apiId: 'openlibrary',\n name: 'Open Library Books API',\n async fetch({ isbn }): Promise<OpenLibraryBookResult> {\n if (!isbn) return {};\n const res = await fetch(\n `https://openlibrary.org/api/books?bibkeys=ISBN:${isbn}&format=json&jscmd=data`\n );\n if (!res.ok) return {};\n const data = await res.json() as Record<string, unknown>;\n const book = (data[`ISBN:${isbn}`] ?? {}) as Record<string, unknown>;\n return {\n title: book.title as string | undefined,\n authors: (book.authors as { name: string }[] | undefined)?.map(a => a.name),\n publishDate: book.publish_date as string | undefined,\n pageCount: book.number_of_pages as number | undefined,\n coverUrl: (book.cover as { medium?: string } | undefined)?.medium,\n description: (book.excerpts as { text: string }[] | undefined)?.[0]?.text,\n };\n },\n },\n googlebooks: {\n apiId: 'googlebooks',\n name: 'Google Books API',\n async fetch({ isbn }): Promise<GoogleBooksVolumeResult> {\n if (!isbn) return {};\n const key = apiKeyDictionary.require('googlebooks');\n const res = await fetch(\n `https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}&key=${key}`\n );\n if (!res.ok) return {};\n const data = await res.json() as { items?: { volumeInfo: Record<string, unknown> }[] };\n const info = data.items?.[0]?.volumeInfo ?? {};\n return {\n title: info.title as string | undefined,\n authors: info.authors as string[] | undefined,\n publishedDate: info.publishedDate as string | undefined,\n pageCount: info.pageCount as number | undefined,\n language: info.language as string | undefined,\n description: info.description as string | undefined,\n thumbnail: (info.imageLinks as { thumbnail?: string } | undefined)?.thumbnail,\n };\n },\n },\n },\n};\n"]}
@@ -0,0 +1,28 @@
1
+ // src/ddc/index.ts
2
+ var DDCAdapter = {
3
+ standardId: "ddc",
4
+ uriScheme: "DDC",
5
+ normalize(value) {
6
+ let trimmed = value.trim();
7
+ if (trimmed.includes(".")) trimmed = trimmed.replace(/\.?0+$/, "");
8
+ return trimmed;
9
+ },
10
+ display(value) {
11
+ return DDCAdapter.normalize(value);
12
+ },
13
+ validate(value) {
14
+ if (!value) return { valid: false, error: "DDC notation is absent" };
15
+ const normalized = DDCAdapter.normalize(value);
16
+ if (!/^[0-9]{3}(\.[0-9]+)?$/.test(normalized))
17
+ return { valid: false, error: `DDC notation does not match pattern: ${normalized}` };
18
+ return { valid: true };
19
+ },
20
+ toLinkedDataUri(value) {
21
+ return `https://id.loc.gov/authorities/classification/${DDCAdapter.normalize(value)}`;
22
+ },
23
+ apis: {}
24
+ };
25
+
26
+ export { DDCAdapter };
27
+ //# sourceMappingURL=chunk-AHIDYNLW.js.map
28
+ //# sourceMappingURL=chunk-AHIDYNLW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ddc/index.ts"],"names":[],"mappings":";AAqBO,IAAM,UAAA,GAAiD;AAAA,EAC5D,UAAA,EAAY,KAAA;AAAA,EACZ,SAAA,EAAY,KAAA;AAAA,EAEZ,UAAU,KAAA,EAAuB;AAC/B,IAAA,IAAI,OAAA,GAAU,MAAM,IAAA,EAAK;AACzB,IAAA,IAAI,OAAA,CAAQ,SAAS,GAAG,CAAA,YAAa,OAAA,CAAQ,OAAA,CAAQ,UAAU,EAAE,CAAA;AACjE,IAAA,OAAO,OAAA;AAAA,EACT,CAAA;AAAA,EAEA,QAAQ,KAAA,EAAuB;AAC7B,IAAA,OAAO,UAAA,CAAW,UAAU,KAAK,CAAA;AAAA,EACnC,CAAA;AAAA,EAEA,SAAS,KAAA,EAAoD;AAC3D,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,wBAAA,EAAyB;AACnE,IAAA,MAAM,UAAA,GAAa,UAAA,CAAW,SAAA,CAAU,KAAK,CAAA;AAC7C,IAAA,IAAI,CAAC,uBAAA,CAAwB,IAAA,CAAK,UAAU,CAAA;AAC1C,MAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA,qCAAA,EAAwC,UAAU,CAAA,CAAA,EAAG;AACrF,IAAA,OAAO,EAAE,OAAO,IAAA,EAAK;AAAA,EACvB,CAAA;AAAA,EAEA,gBAAgB,KAAA,EAAuB;AACrC,IAAA,OAAO,CAAA,8CAAA,EAAiD,UAAA,CAAW,SAAA,CAAU,KAAK,CAAC,CAAA,CAAA;AAAA,EACrF,CAAA;AAAA,EAEA,MAAM;AACR","file":"chunk-AHIDYNLW.js","sourcesContent":["/*\n * Copyright (c) 2026 DataPond D-Library Pty Ltd. (\"The Sanctuary\")\n * Non-Profit Public Library — The World Library\n * \n * D-SAFE Certification issued by POND Enterprise.\n * Published under the D-Open Code Sovereign Licence v1.0 framework\n * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.\n * https://registry.world.bibliotech.com/licence\n * Source code donated to DataPond D-Library by it's author: data pond.\n * \n * Technical Guardian (\"The Shield\"): Pond Enterprise Pty Ltd. (ACN 694 747 987)\n * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.\n * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.\n */\nimport type { StandardAdapter, ValidationResult }\n from '@the_library/canonical-schemas/types/StandardAdapter';\n\ninterface DDCProps extends Record<string, string | null> { ddcNotation: string | null; }\n\ntype DDCApis = Record<string, never>;\n\nexport const DDCAdapter: StandardAdapter<DDCProps, DDCApis> = {\n standardId: 'ddc',\n uriScheme: 'DDC',\n\n normalize(value: string): string {\n let trimmed = value.trim();\n if (trimmed.includes('.')) trimmed = trimmed.replace(/\\.?0+$/, '');\n return trimmed;\n },\n\n display(value: string): string {\n return DDCAdapter.normalize(value);\n },\n\n validate(value: string | null | undefined): ValidationResult {\n if (!value) return { valid: false, error: 'DDC notation is absent' };\n const normalized = DDCAdapter.normalize(value);\n if (!/^[0-9]{3}(\\.[0-9]+)?$/.test(normalized))\n return { valid: false, error: `DDC notation does not match pattern: ${normalized}` };\n return { valid: true };\n },\n\n toLinkedDataUri(value: string): string {\n return `https://id.loc.gov/authorities/classification/${DDCAdapter.normalize(value)}`;\n },\n\n apis: {},\n};\n"]}
@@ -0,0 +1,26 @@
1
+ // src/udc/index.ts
2
+ var UDCAdapter = {
3
+ standardId: "udc",
4
+ uriScheme: "UDC",
5
+ normalize(value) {
6
+ return value.trim();
7
+ },
8
+ display(value) {
9
+ return UDCAdapter.normalize(value);
10
+ },
11
+ validate(value) {
12
+ if (!value) return { valid: false, error: "UDC notation is absent" };
13
+ const normalized = UDCAdapter.normalize(value);
14
+ if (!/^[0-9\.\-\:\+\/\(\)\[\]\=\*\"\s]+$/.test(normalized))
15
+ return { valid: false, error: `UDC notation does not match pattern: ${normalized}` };
16
+ return { valid: true };
17
+ },
18
+ toLinkedDataUri(value) {
19
+ return `https://udcsummary.info/php/index.php?c=${UDCAdapter.normalize(value)}`;
20
+ },
21
+ apis: {}
22
+ };
23
+
24
+ export { UDCAdapter };
25
+ //# sourceMappingURL=chunk-C5WHAJXI.js.map
26
+ //# sourceMappingURL=chunk-C5WHAJXI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/udc/index.ts"],"names":[],"mappings":";AAqBO,IAAM,UAAA,GAAiD;AAAA,EAC5D,UAAA,EAAY,KAAA;AAAA,EACZ,SAAA,EAAY,KAAA;AAAA,EAEZ,UAAU,KAAA,EAAuB;AAC/B,IAAA,OAAO,MAAM,IAAA,EAAK;AAAA,EACpB,CAAA;AAAA,EAEA,QAAQ,KAAA,EAAuB;AAC7B,IAAA,OAAO,UAAA,CAAW,UAAU,KAAK,CAAA;AAAA,EACnC,CAAA;AAAA,EAEA,SAAS,KAAA,EAAoD;AAC3D,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,wBAAA,EAAyB;AACnE,IAAA,MAAM,UAAA,GAAa,UAAA,CAAW,SAAA,CAAU,KAAK,CAAA;AAC7C,IAAA,IAAI,CAAC,oCAAA,CAAqC,IAAA,CAAK,UAAU,CAAA;AACvD,MAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA,qCAAA,EAAwC,UAAU,CAAA,CAAA,EAAG;AACrF,IAAA,OAAO,EAAE,OAAO,IAAA,EAAK;AAAA,EACvB,CAAA;AAAA,EAEA,gBAAgB,KAAA,EAAuB;AACrC,IAAA,OAAO,CAAA,wCAAA,EAA2C,UAAA,CAAW,SAAA,CAAU,KAAK,CAAC,CAAA,CAAA;AAAA,EAC/E,CAAA;AAAA,EAEA,MAAM;AACR","file":"chunk-C5WHAJXI.js","sourcesContent":["/*\n * Copyright (c) 2026 DataPond D-Library Pty Ltd. (\"The Sanctuary\")\n * Non-Profit Public Library — The World Library\n * \n * D-SAFE Certification issued by POND Enterprise.\n * Published under the D-Open Code Sovereign Licence v1.0 framework\n * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.\n * https://registry.world.bibliotech.com/licence\n * Source code donated to DataPond D-Library by it's author: data pond.\n * \n * Technical Guardian (\"The Shield\"): Pond Enterprise Pty Ltd. (ACN 694 747 987)\n * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.\n * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.\n */\nimport type { StandardAdapter, ValidationResult }\n from '@the_library/canonical-schemas/types/StandardAdapter';\n\ninterface UDCProps extends Record<string, string | null> { udcNotation: string | null; }\n\ntype UDCApis = Record<string, never>;\n\nexport const UDCAdapter: StandardAdapter<UDCProps, UDCApis> = {\n standardId: 'udc',\n uriScheme: 'UDC',\n\n normalize(value: string): string {\n return value.trim();\n },\n\n display(value: string): string {\n return UDCAdapter.normalize(value);\n },\n\n validate(value: string | null | undefined): ValidationResult {\n if (!value) return { valid: false, error: 'UDC notation is absent' };\n const normalized = UDCAdapter.normalize(value);\n if (!/^[0-9\\.\\-\\:\\+\\/\\(\\)\\[\\]\\=\\*\\\"\\s]+$/.test(normalized))\n return { valid: false, error: `UDC notation does not match pattern: ${normalized}` };\n return { valid: true };\n },\n\n toLinkedDataUri(value: string): string {\n return `https://udcsummary.info/php/index.php?c=${UDCAdapter.normalize(value)}`;\n },\n\n apis: {},\n};\n"]}
@@ -0,0 +1,26 @@
1
+ // src/tlc/index.ts
2
+ var TLCAdapter = {
3
+ standardId: "tlc",
4
+ uriScheme: "TLC",
5
+ normalize(value) {
6
+ return value.trim();
7
+ },
8
+ display(value) {
9
+ return TLCAdapter.normalize(value);
10
+ },
11
+ validate(value) {
12
+ if (!value) return { valid: false, error: "TLC notation is absent" };
13
+ const normalized = TLCAdapter.normalize(value);
14
+ if (!/^[A-Z0-9\.\-\s]+$/.test(normalized))
15
+ return { valid: false, error: `TLC notation does not match pattern: ${normalized}` };
16
+ return { valid: true };
17
+ },
18
+ toLinkedDataUri(value) {
19
+ return `https://nlt.go.th/tlc/${TLCAdapter.normalize(value)}`;
20
+ },
21
+ apis: {}
22
+ };
23
+
24
+ export { TLCAdapter };
25
+ //# sourceMappingURL=chunk-D5QOJWWA.js.map
26
+ //# sourceMappingURL=chunk-D5QOJWWA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tlc/index.ts"],"names":[],"mappings":";AAqBO,IAAM,UAAA,GAAiD;AAAA,EAC5D,UAAA,EAAY,KAAA;AAAA,EACZ,SAAA,EAAY,KAAA;AAAA,EAEZ,UAAU,KAAA,EAAuB;AAC/B,IAAA,OAAO,MAAM,IAAA,EAAK;AAAA,EACpB,CAAA;AAAA,EAEA,QAAQ,KAAA,EAAuB;AAC7B,IAAA,OAAO,UAAA,CAAW,UAAU,KAAK,CAAA;AAAA,EACnC,CAAA;AAAA,EAEA,SAAS,KAAA,EAAoD;AAC3D,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,wBAAA,EAAyB;AACnE,IAAA,MAAM,UAAA,GAAa,UAAA,CAAW,SAAA,CAAU,KAAK,CAAA;AAC7C,IAAA,IAAI,CAAC,mBAAA,CAAoB,IAAA,CAAK,UAAU,CAAA;AACtC,MAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA,qCAAA,EAAwC,UAAU,CAAA,CAAA,EAAG;AACrF,IAAA,OAAO,EAAE,OAAO,IAAA,EAAK;AAAA,EACvB,CAAA;AAAA,EAEA,gBAAgB,KAAA,EAAuB;AACrC,IAAA,OAAO,CAAA,sBAAA,EAAyB,UAAA,CAAW,SAAA,CAAU,KAAK,CAAC,CAAA,CAAA;AAAA,EAC7D,CAAA;AAAA,EAEA,MAAM;AACR","file":"chunk-D5QOJWWA.js","sourcesContent":["/*\n * Copyright (c) 2026 DataPond D-Library Pty Ltd. (\"The Sanctuary\")\n * Non-Profit Public Library — The World Library\n * \n * D-SAFE Certification issued by POND Enterprise.\n * Published under the D-Open Code Sovereign Licence v1.0 framework\n * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.\n * https://registry.world.bibliotech.com/licence\n * Source code donated to DataPond D-Library by it's author: data pond.\n * \n * Technical Guardian (\"The Shield\"): Pond Enterprise Pty Ltd. (ACN 694 747 987)\n * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.\n * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.\n */\nimport type { StandardAdapter, ValidationResult }\n from '@the_library/canonical-schemas/types/StandardAdapter';\n\ninterface TLCProps extends Record<string, string | null> { tlcNotation: string | null; }\n\ntype TLCApis = Record<string, never>;\n\nexport const TLCAdapter: StandardAdapter<TLCProps, TLCApis> = {\n standardId: 'tlc',\n uriScheme: 'TLC',\n\n normalize(value: string): string {\n return value.trim();\n },\n\n display(value: string): string {\n return TLCAdapter.normalize(value);\n },\n\n validate(value: string | null | undefined): ValidationResult {\n if (!value) return { valid: false, error: 'TLC notation is absent' };\n const normalized = TLCAdapter.normalize(value);\n if (!/^[A-Z0-9\\.\\-\\s]+$/.test(normalized))\n return { valid: false, error: `TLC notation does not match pattern: ${normalized}` };\n return { valid: true };\n },\n\n toLinkedDataUri(value: string): string {\n return `https://nlt.go.th/tlc/${TLCAdapter.normalize(value)}`;\n },\n\n apis: {},\n};\n"]}
@@ -0,0 +1,65 @@
1
+ // src/isni/index.ts
2
+ function validateISNIMod11_2(compact) {
3
+ if (compact.length !== 16) return { valid: false, error: `Expected 16 chars, got ${compact.length}` };
4
+ let p = 0;
5
+ for (let i = 0; i < 15; i++) {
6
+ const d = parseInt(compact[i], 10);
7
+ if (isNaN(d)) return { valid: false, error: `Non-digit character at position ${i}` };
8
+ p = (p + d) * 2 % 11;
9
+ }
10
+ const checkVal = (12 - p) % 11;
11
+ const checkChar = checkVal === 10 ? "X" : String(checkVal);
12
+ if (compact[15].toUpperCase() !== checkChar)
13
+ return { valid: false, error: `Check digit mismatch: expected ${checkChar}, got ${compact[15]}` };
14
+ return { valid: true };
15
+ }
16
+ var ISNIAdapter = {
17
+ standardId: "isni",
18
+ uriScheme: "ISNI",
19
+ normalize(value) {
20
+ return value.replace(/[\s-]/g, "");
21
+ },
22
+ display(value) {
23
+ const compact = ISNIAdapter.normalize(value);
24
+ if (compact.length === 16)
25
+ return `${compact.slice(0, 4)} ${compact.slice(4, 8)} ${compact.slice(8, 12)} ${compact.slice(12)}`;
26
+ return compact;
27
+ },
28
+ validate(value) {
29
+ if (!value) return { valid: false, error: "ISNI is absent" };
30
+ const compact = ISNIAdapter.normalize(value);
31
+ if (!/^[0-9]{15}[0-9X]$/.test(compact))
32
+ return { valid: false, error: `ISNI does not match pattern: ${compact}` };
33
+ return validateISNIMod11_2(compact);
34
+ },
35
+ toLinkedDataUri(value) {
36
+ return `https://isni.org/isni/${ISNIAdapter.normalize(value)}`;
37
+ },
38
+ apis: {
39
+ "isni-sru": {
40
+ apiId: "isni-sru",
41
+ name: "ISNI SRU API",
42
+ async fetch({ isniId }) {
43
+ if (!isniId) return [];
44
+ const query = `pica.isn%3D${encodeURIComponent(isniId)}`;
45
+ const url = `https://isni.oclc.org/sru/DB=1.2/?operation=searchRetrieve&query=${query}&recordSchema=isni-b&maximumRecords=10`;
46
+ const res = await fetch(url, { headers: { Accept: "application/xml" } });
47
+ if (!res.ok) return [];
48
+ const text = await res.text();
49
+ const isniMatch = text.match(/<isniUnformatted>([0-9X]+)<\/isniUnformatted>/);
50
+ const forenameMatch = text.match(/<forename>([^<]+)<\/forename>/);
51
+ const surnameMatch = text.match(/<surname>([^<]+)<\/surname>/);
52
+ if (!isniMatch) return [];
53
+ return [{
54
+ isni: isniMatch[1],
55
+ forename: forenameMatch?.[1],
56
+ surname: surnameMatch?.[1]
57
+ }];
58
+ }
59
+ }
60
+ }
61
+ };
62
+
63
+ export { ISNIAdapter };
64
+ //# sourceMappingURL=chunk-DX6SH342.js.map
65
+ //# sourceMappingURL=chunk-DX6SH342.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/isni/index.ts"],"names":[],"mappings":"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","file":"chunk-DX6SH342.js","sourcesContent":["/*\n * Copyright (c) 2026 DataPond D-Library Pty Ltd. (\"The Sanctuary\")\n * Non-Profit Public Library — The World Library\n * \n * D-SAFE Certification issued by POND Enterprise.\n * Published under the D-Open Code Sovereign Licence v1.0 framework\n * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.\n * https://registry.world.bibliotech.com/licence\n * Source code donated to DataPond D-Library by it's author: data pond.\n * \n * Technical Guardian (\"The Shield\"): Pond Enterprise Pty Ltd. (ACN 694 747 987)\n * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.\n * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.\n */\nimport type { StandardAdapter, StandardApiAdapter, ValidationResult }\n from '@the_library/canonical-schemas/types/StandardAdapter';\nimport type { IsniSruResult } from './types';\n\ninterface ISNIProps extends Record<string, string | null> { isniId: string | null; }\n\ntype ISNIApis = {\n 'isni-sru': StandardApiAdapter<ISNIProps, IsniSruResult[]>;\n};\n\nfunction validateISNIMod11_2(compact: string): ValidationResult {\n if (compact.length !== 16) return { valid: false, error: `Expected 16 chars, got ${compact.length}` };\n let p = 0;\n for (let i = 0; i < 15; i++) {\n const d = parseInt(compact[i], 10);\n if (isNaN(d)) return { valid: false, error: `Non-digit character at position ${i}` };\n p = ((p + d) * 2) % 11;\n }\n const checkVal = (12 - p) % 11;\n const checkChar = checkVal === 10 ? 'X' : String(checkVal);\n if (compact[15].toUpperCase() !== checkChar)\n return { valid: false, error: `Check digit mismatch: expected ${checkChar}, got ${compact[15]}` };\n return { valid: true };\n}\n\nexport const ISNIAdapter: StandardAdapter<ISNIProps, ISNIApis> = {\n standardId: 'isni',\n uriScheme: 'ISNI',\n\n normalize(value: string): string {\n return value.replace(/[\\s-]/g, '');\n },\n\n display(value: string): string {\n const compact = ISNIAdapter.normalize(value);\n if (compact.length === 16)\n return `${compact.slice(0, 4)} ${compact.slice(4, 8)} ${compact.slice(8, 12)} ${compact.slice(12)}`;\n return compact;\n },\n\n validate(value: string | null | undefined): ValidationResult {\n if (!value) return { valid: false, error: 'ISNI is absent' };\n const compact = ISNIAdapter.normalize(value);\n if (!/^[0-9]{15}[0-9X]$/.test(compact))\n return { valid: false, error: `ISNI does not match pattern: ${compact}` };\n return validateISNIMod11_2(compact);\n },\n\n toLinkedDataUri(value: string): string {\n return `https://isni.org/isni/${ISNIAdapter.normalize(value)}`;\n },\n\n apis: {\n 'isni-sru': {\n apiId: 'isni-sru',\n name: 'ISNI SRU API',\n async fetch({ isniId }): Promise<IsniSruResult[]> {\n if (!isniId) return [];\n const query = `pica.isn%3D${encodeURIComponent(isniId)}`;\n const url = `https://isni.oclc.org/sru/DB=1.2/?operation=searchRetrieve&query=${query}&recordSchema=isni-b&maximumRecords=10`;\n const res = await fetch(url, { headers: { Accept: 'application/xml' } });\n if (!res.ok) return [];\n const text = await res.text();\n const isniMatch = text.match(/<isniUnformatted>([0-9X]+)<\\/isniUnformatted>/);\n const forenameMatch = text.match(/<forename>([^<]+)<\\/forename>/);\n const surnameMatch = text.match(/<surname>([^<]+)<\\/surname>/);\n if (!isniMatch) return [];\n return [{\n isni: isniMatch[1],\n forename: forenameMatch?.[1],\n surname: surnameMatch?.[1],\n }];\n },\n },\n },\n};\n"]}
@@ -0,0 +1,58 @@
1
+ // src/issn/index.ts
2
+ function validateISSNMod11_2(issn) {
3
+ const clean = issn.replace("-", "");
4
+ if (clean.length !== 8) return { valid: false, error: `Expected 8 chars, got ${clean.length}` };
5
+ const weights = [8, 7, 6, 5, 4, 3, 2];
6
+ let sum = 0;
7
+ for (let i = 0; i < 7; i++) sum += parseInt(clean[i], 10) * weights[i];
8
+ const remainder = sum % 11;
9
+ const checkVal = remainder === 0 ? 0 : 11 - remainder;
10
+ const checkChar = checkVal === 10 ? "X" : String(checkVal);
11
+ if (clean[7].toUpperCase() !== checkChar)
12
+ return { valid: false, error: `Check digit mismatch: expected ${checkChar}, got ${clean[7]}` };
13
+ return { valid: true };
14
+ }
15
+ var ISSNAdapter = {
16
+ standardId: "issn",
17
+ uriScheme: "ISSN",
18
+ normalize(value) {
19
+ const digits = value.replace(/[\s-]/g, "");
20
+ if (digits.length === 8) return `${digits.slice(0, 4)}-${digits.slice(4)}`;
21
+ return value.trim();
22
+ },
23
+ display(value) {
24
+ return ISSNAdapter.normalize(value);
25
+ },
26
+ validate(value) {
27
+ if (!value) return { valid: false, error: "ISSN is absent" };
28
+ const normalized = ISSNAdapter.normalize(value);
29
+ if (!/^[0-9]{4}-[0-9]{3}[0-9X]$/.test(normalized))
30
+ return { valid: false, error: `ISSN does not match pattern: ${normalized}` };
31
+ return validateISSNMod11_2(normalized);
32
+ },
33
+ toLinkedDataUri(value) {
34
+ return `https://portal.issn.org/resource/ISSN/${ISSNAdapter.normalize(value)}`;
35
+ },
36
+ apis: {
37
+ "issn-portal": {
38
+ apiId: "issn-portal",
39
+ name: "ISSN Portal",
40
+ async fetch({ issn }) {
41
+ if (!issn) return {};
42
+ const res = await fetch(`https://portal.issn.org/resource/ISSN/${issn}?format=json`);
43
+ if (!res.ok) return {};
44
+ const data = await res.json();
45
+ return {
46
+ title: data["dc:title"],
47
+ medium: data["dc:format"],
48
+ country: data["dc:publisher"],
49
+ issn
50
+ };
51
+ }
52
+ }
53
+ }
54
+ };
55
+
56
+ export { ISSNAdapter };
57
+ //# sourceMappingURL=chunk-GJJ6NIDQ.js.map
58
+ //# sourceMappingURL=chunk-GJJ6NIDQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/issn/index.ts"],"names":[],"mappings":"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","file":"chunk-GJJ6NIDQ.js","sourcesContent":["/*\n * Copyright (c) 2026 DataPond D-Library Pty Ltd. (\"The Sanctuary\")\n * Non-Profit Public Library — The World Library\n * \n * D-SAFE Certification issued by POND Enterprise.\n * Published under the D-Open Code Sovereign Licence v1.0 framework\n * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.\n * https://registry.world.bibliotech.com/licence\n * Source code donated to DataPond D-Library by it's author: data pond.\n * \n * Technical Guardian (\"The Shield\"): Pond Enterprise Pty Ltd. (ACN 694 747 987)\n * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.\n * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.\n */\nimport type { StandardAdapter, StandardApiAdapter, ValidationResult }\n from '@the_library/canonical-schemas/types/StandardAdapter';\nimport type { IssnPortalResult } from './types';\n\ninterface ISSNProps extends Record<string, string | null> { issn: string | null; }\n\ntype ISSNApis = {\n 'issn-portal': StandardApiAdapter<ISSNProps, IssnPortalResult>;\n};\n\nfunction validateISSNMod11_2(issn: string): ValidationResult {\n const clean = issn.replace('-', '');\n if (clean.length !== 8) return { valid: false, error: `Expected 8 chars, got ${clean.length}` };\n const weights = [8, 7, 6, 5, 4, 3, 2];\n let sum = 0;\n for (let i = 0; i < 7; i++) sum += parseInt(clean[i], 10) * weights[i];\n const remainder = sum % 11;\n const checkVal = remainder === 0 ? 0 : 11 - remainder;\n const checkChar = checkVal === 10 ? 'X' : String(checkVal);\n if (clean[7].toUpperCase() !== checkChar)\n return { valid: false, error: `Check digit mismatch: expected ${checkChar}, got ${clean[7]}` };\n return { valid: true };\n}\n\nexport const ISSNAdapter: StandardAdapter<ISSNProps, ISSNApis> = {\n standardId: 'issn',\n uriScheme: 'ISSN',\n\n normalize(value: string): string {\n const digits = value.replace(/[\\s-]/g, '');\n if (digits.length === 8) return `${digits.slice(0, 4)}-${digits.slice(4)}`;\n return value.trim();\n },\n\n display(value: string): string {\n return ISSNAdapter.normalize(value);\n },\n\n validate(value: string | null | undefined): ValidationResult {\n if (!value) return { valid: false, error: 'ISSN is absent' };\n const normalized = ISSNAdapter.normalize(value);\n if (!/^[0-9]{4}-[0-9]{3}[0-9X]$/.test(normalized))\n return { valid: false, error: `ISSN does not match pattern: ${normalized}` };\n return validateISSNMod11_2(normalized);\n },\n\n toLinkedDataUri(value: string): string {\n return `https://portal.issn.org/resource/ISSN/${ISSNAdapter.normalize(value)}`;\n },\n\n apis: {\n 'issn-portal': {\n apiId: 'issn-portal',\n name: 'ISSN Portal',\n async fetch({ issn }): Promise<IssnPortalResult> {\n if (!issn) return {};\n const res = await fetch(`https://portal.issn.org/resource/ISSN/${issn}?format=json`);\n if (!res.ok) return {};\n const data = await res.json() as Record<string, unknown>;\n return {\n title: data['dc:title'] as string | undefined,\n medium: data['dc:format'] as string | undefined,\n country: data['dc:publisher'] as string | undefined,\n issn,\n };\n },\n },\n },\n};\n"]}