dosipas-ts 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 (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +216 -0
  3. package/dist/decoder.d.ts +16 -0
  4. package/dist/decoder.d.ts.map +1 -0
  5. package/dist/decoder.js +265 -0
  6. package/dist/decoder.js.map +1 -0
  7. package/dist/encoder.d.ts +16 -0
  8. package/dist/encoder.d.ts.map +1 -0
  9. package/dist/encoder.js +171 -0
  10. package/dist/encoder.js.map +1 -0
  11. package/dist/fixtures.d.ts +14 -0
  12. package/dist/fixtures.d.ts.map +1 -0
  13. package/dist/fixtures.js +68 -0
  14. package/dist/fixtures.js.map +1 -0
  15. package/dist/index.d.ts +10 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +7 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/oids.d.ts +28 -0
  20. package/dist/oids.d.ts.map +1 -0
  21. package/dist/oids.js +43 -0
  22. package/dist/oids.js.map +1 -0
  23. package/dist/schemas.d.ts +11 -0
  24. package/dist/schemas.d.ts.map +1 -0
  25. package/dist/schemas.js +17 -0
  26. package/dist/schemas.js.map +1 -0
  27. package/dist/signature-fixtures.d.ts +110 -0
  28. package/dist/signature-fixtures.d.ts.map +1 -0
  29. package/dist/signature-fixtures.js +142 -0
  30. package/dist/signature-fixtures.js.map +1 -0
  31. package/dist/signature-utils.d.ts +29 -0
  32. package/dist/signature-utils.d.ts.map +1 -0
  33. package/dist/signature-utils.js +201 -0
  34. package/dist/signature-utils.js.map +1 -0
  35. package/dist/signed-data.d.ts +32 -0
  36. package/dist/signed-data.d.ts.map +1 -0
  37. package/dist/signed-data.js +87 -0
  38. package/dist/signed-data.js.map +1 -0
  39. package/dist/types.d.ts +273 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +8 -0
  42. package/dist/types.js.map +1 -0
  43. package/dist/verifier.d.ts +67 -0
  44. package/dist/verifier.d.ts.map +1 -0
  45. package/dist/verifier.js +309 -0
  46. package/dist/verifier.js.map +1 -0
  47. package/package.json +46 -0
  48. package/schemas/uic-barcode/intercode6.schema.json +204 -0
  49. package/schemas/uic-barcode/uicBarcodeHeader_v1.schema.json +376 -0
  50. package/schemas/uic-barcode/uicBarcodeHeader_v2.schema.json +484 -0
  51. package/schemas/uic-barcode/uicRailTicketData_v1.schema.json +31507 -0
  52. package/schemas/uic-barcode/uicRailTicketData_v2.schema.json +31623 -0
  53. package/schemas/uic-barcode/uicRailTicketData_v3.schema.json +32729 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Théophile Helleboid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,216 @@
1
+ # dosipas-ts
2
+
3
+ Decode, encode, and verify UIC barcode tickets with Intercode 6 extensions in TypeScript.
4
+
5
+ Handles the full UIC barcode envelope (header versions 1 and 2), FCB rail ticket data (versions 1, 2, and 3), Intercode 6 issuing extensions, dynamic data, and two-level ECDSA signature verification.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install dosipas-ts
11
+ ```
12
+
13
+ Requires Node.js 18+. ESM-only.
14
+
15
+ ## Decoding
16
+
17
+ ```ts
18
+ import { decodeTicket, decodeTicketFromBytes } from 'dosipas-ts';
19
+
20
+ // From a hex string (whitespace and trailing 'h' are stripped)
21
+ const ticket = decodeTicket('815563dd8e76...');
22
+
23
+ // From raw bytes
24
+ const ticket = decodeTicketFromBytes(bytes);
25
+ ```
26
+
27
+ The returned `UicBarcodeTicket` object contains:
28
+
29
+ ```ts
30
+ ticket.format // "U1" or "U2"
31
+ ticket.headerVersion // 1 or 2
32
+ ticket.security // SecurityInfo (provider, key IDs, algorithms, signatures)
33
+ ticket.railTickets // RailTicketData[] (FCB-decoded ticket data)
34
+ ticket.otherDataBlocks // DataBlock[] (non-FCB data blocks)
35
+ ticket.dynamicData // IntercodeDynamicData (Intercode 6 Level 2, if present)
36
+ ticket.level2Signature // Uint8Array (if present)
37
+ ```
38
+
39
+ Each rail ticket includes typed fields for issuing details, traveler info, transport documents, and control details:
40
+
41
+ ```ts
42
+ const rt = ticket.railTickets[0];
43
+
44
+ rt.fcbVersion // 1, 2, or 3
45
+ rt.issuingDetail?.issuerNum // RICS code
46
+ rt.issuingDetail?.issuingYear // e.g. 2025
47
+ rt.issuingDetail?.issuingDay // day of year
48
+ rt.issuingDetail?.intercodeIssuing // Intercode 6 issuing extension
49
+ rt.travelerDetail?.traveler?.[0].firstName // traveler name
50
+ rt.transportDocument?.[0].ticketType // e.g. "openTicket", "reservation"
51
+ rt.raw // full decoded object for fields not covered above
52
+ ```
53
+
54
+ ## Encoding
55
+
56
+ ```ts
57
+ import { encodeTicket, encodeTicketToBytes } from 'dosipas-ts';
58
+
59
+ const hex = encodeTicket({
60
+ headerVersion: 2,
61
+ fcbVersion: 2,
62
+ securityProviderNum: 3703,
63
+ keyId: 1,
64
+ level1KeyAlg: '1.2.840.10045.3.1.7',
65
+ level2KeyAlg: '1.2.840.10045.3.1.7',
66
+ level1SigningAlg: '1.2.840.10045.4.3.2',
67
+ level2SigningAlg: '1.2.840.10045.4.3.2',
68
+ level2PublicKey: publicKeyBytes,
69
+ level1Signature: level1SigBytes,
70
+ level2Signature: level2SigBytes,
71
+ railTicket: {
72
+ issuingDetail: {
73
+ securityProviderNum: 3703,
74
+ issuerNum: 3703,
75
+ issuingYear: 2025,
76
+ issuingDay: 44,
77
+ activated: true,
78
+ currency: 'EUR',
79
+ currencyFract: 2,
80
+ intercodeIssuing: {
81
+ networkId: new Uint8Array([0x11, 0x87]),
82
+ productRetailer: { retailChannel: 'mobileApplication' },
83
+ },
84
+ },
85
+ transportDocument: [
86
+ { ticketType: 'openTicket', ticket: { /* ... */ } },
87
+ ],
88
+ },
89
+ dynamicData: {
90
+ rics: 3703,
91
+ dynamicContentDay: 0,
92
+ dynamicContentTime: 720,
93
+ },
94
+ });
95
+
96
+ // Or get bytes directly
97
+ const bytes = encodeTicketToBytes({ /* same input */ });
98
+ ```
99
+
100
+ ## Signature verification
101
+
102
+ UIC barcodes use a two-level signature scheme:
103
+
104
+ - **Level 2** is self-contained: the public key is embedded in the barcode.
105
+ - **Level 1** requires an external public key from the UIC public key registry.
106
+
107
+ ### Verify Level 2 only (no external key needed)
108
+
109
+ ```ts
110
+ import { verifyLevel2Signature } from 'dosipas-ts';
111
+
112
+ const result = await verifyLevel2Signature(barcodeBytes);
113
+ // { valid: true, algorithm: 'ECDSA P-256 with SHA-256' }
114
+ ```
115
+
116
+ ### Verify both levels
117
+
118
+ ```ts
119
+ import { verifySignatures } from 'dosipas-ts';
120
+
121
+ const result = await verifySignatures(barcodeBytes, {
122
+ level1PublicKey: publicKeyBytes,
123
+ });
124
+ // { level1: { valid: true, ... }, level2: { valid: true, ... } }
125
+ ```
126
+
127
+ ### Using a key provider
128
+
129
+ ```ts
130
+ import { verifySignatures, findKeyInXml } from 'dosipas-ts';
131
+ import type { Level1KeyProvider } from 'dosipas-ts';
132
+
133
+ // Parse the UIC public key XML (from https://railpublickey.uic.org)
134
+ const xml = fs.readFileSync('uic-publickeys.xml', 'utf-8');
135
+
136
+ const provider: Level1KeyProvider = {
137
+ async getPublicKey(securityProvider, keyId) {
138
+ const key = findKeyInXml(xml, securityProvider.num!, keyId);
139
+ if (!key) throw new Error('Key not found');
140
+ return key;
141
+ },
142
+ };
143
+
144
+ const result = await verifySignatures(barcodeBytes, {
145
+ level1KeyProvider: provider,
146
+ });
147
+ ```
148
+
149
+ ### Verify Level 1 directly
150
+
151
+ ```ts
152
+ import { verifyLevel1Signature } from 'dosipas-ts';
153
+
154
+ const result = await verifyLevel1Signature(barcodeBytes, publicKeyBytes);
155
+ ```
156
+
157
+ ## Extracting signed data
158
+
159
+ For custom verification workflows, extract the exact signed bytes from a barcode:
160
+
161
+ ```ts
162
+ import { extractSignedData } from 'dosipas-ts';
163
+
164
+ const extracted = extractSignedData(barcodeBytes);
165
+
166
+ extracted.level1DataBytes // bytes signed by level1Signature
167
+ extracted.level2SignedBytes // bytes signed by level2Signature
168
+ extracted.security // security metadata (algorithms, keys, signatures)
169
+ ```
170
+
171
+ ## UIC public key XML utilities
172
+
173
+ ```ts
174
+ import { findKeyInXml, parseKeysXml } from 'dosipas-ts';
175
+
176
+ // Find a specific key
177
+ const key = findKeyInXml(xml, 1187, 1); // issuerCode, keyId
178
+ // Returns Uint8Array or null
179
+
180
+ // Parse all keys
181
+ const keys = parseKeysXml(xml);
182
+ // [{ issuerCode, id, issuerName, publicKey, signatureAlgorithm, ... }]
183
+ ```
184
+
185
+ ## Built-in fixtures
186
+
187
+ The package exports hex-encoded sample tickets for testing:
188
+
189
+ ```ts
190
+ import {
191
+ SAMPLE_TICKET_HEX,
192
+ SNCF_TER_TICKET_HEX,
193
+ SOLEA_TICKET_HEX,
194
+ CTS_TICKET_HEX,
195
+ GRAND_EST_U1_FCB3_HEX,
196
+ } from 'dosipas-ts';
197
+ ```
198
+
199
+ And signature fixture data:
200
+
201
+ ```ts
202
+ import { SNCF_TER_SIGNATURES, SOLEA_SIGNATURES, CTS_SIGNATURES } from 'dosipas-ts';
203
+ ```
204
+
205
+ ## Supported algorithms
206
+
207
+ | Algorithm | Signing | Key verification |
208
+ |-----------|---------|-----------------|
209
+ | ECDSA P-256 with SHA-256 | Yes | Yes |
210
+ | ECDSA P-384 with SHA-384 | Yes | Yes |
211
+ | ECDSA P-521 with SHA-512 | Yes | Yes |
212
+ | DSA with SHA-224/256 | Detected | Not supported |
213
+
214
+ ## License
215
+
216
+ MIT
@@ -0,0 +1,16 @@
1
+ import type { UicBarcodeTicket } from './types';
2
+ /**
3
+ * Decode a UIC barcode ticket from a hex string.
4
+ *
5
+ * @param hex - The hex-encoded barcode payload (whitespace and trailing 'h' are stripped).
6
+ * @returns A fully typed {@link UicBarcodeTicket} object.
7
+ */
8
+ export declare function decodeTicket(hex: string): UicBarcodeTicket;
9
+ /**
10
+ * Decode a UIC barcode ticket from raw bytes.
11
+ *
12
+ * @param bytes - The binary barcode payload.
13
+ * @returns A fully typed {@link UicBarcodeTicket} object.
14
+ */
15
+ export declare function decodeTicketFromBytes(bytes: Uint8Array): UicBarcodeTicket;
16
+ //# sourceMappingURL=decoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../src/decoder.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,gBAAgB,EAWjB,MAAM,SAAS,CAAC;AAsFjB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAG1D;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,GAAG,gBAAgB,CAkFzE"}
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Decoder for UIC barcode tickets with Intercode 6 extensions.
3
+ *
4
+ * Decodes a hex-encoded (or binary) UIC barcode payload into a typed
5
+ * {@link UicBarcodeTicket} object. Handles header version detection,
6
+ * FCB rail ticket data dispatch, and Intercode 6 extension decoding.
7
+ */
8
+ import { SchemaCodec, SchemaBuilder, BitBuffer, } from 'asn1-per-ts';
9
+ import { HEADER_SCHEMAS, RAIL_TICKET_SCHEMAS, INTERCODE_SCHEMAS } from './schemas';
10
+ // ---------------------------------------------------------------------------
11
+ // Codec caches
12
+ // ---------------------------------------------------------------------------
13
+ const headerCodecCache = new Map();
14
+ const ticketCodecCache = new Map();
15
+ let intercodeIssuingCodec;
16
+ let intercodeDynamicCodec;
17
+ function getHeaderCodec(version) {
18
+ let codec = headerCodecCache.get(version);
19
+ if (codec)
20
+ return codec;
21
+ const schemas = HEADER_SCHEMAS[version];
22
+ if (!schemas) {
23
+ throw new Error(`No schema for header v${version}. Supported: v1, v2`);
24
+ }
25
+ codec = new SchemaCodec(schemas.UicBarcodeHeader);
26
+ headerCodecCache.set(version, codec);
27
+ return codec;
28
+ }
29
+ function getTicketCodecs(version) {
30
+ let codecs = ticketCodecCache.get(version);
31
+ if (codecs)
32
+ return codecs;
33
+ const schemas = RAIL_TICKET_SCHEMAS[version];
34
+ if (!schemas) {
35
+ throw new Error(`No schema for FCB${version}. Supported: FCB1, FCB2, FCB3`);
36
+ }
37
+ codecs = SchemaBuilder.buildAll(schemas);
38
+ ticketCodecCache.set(version, codecs);
39
+ return codecs;
40
+ }
41
+ function getIntercodeIssuingCodec() {
42
+ if (intercodeIssuingCodec)
43
+ return intercodeIssuingCodec;
44
+ intercodeIssuingCodec = new SchemaCodec(INTERCODE_SCHEMAS.IntercodeIssuingData);
45
+ intercodeDynamicCodec = new SchemaCodec(INTERCODE_SCHEMAS.IntercodeDynamicData);
46
+ return intercodeIssuingCodec;
47
+ }
48
+ function getIntercodeDynamicCodec() {
49
+ if (intercodeDynamicCodec)
50
+ return intercodeDynamicCodec;
51
+ getIntercodeIssuingCodec();
52
+ return intercodeDynamicCodec;
53
+ }
54
+ // ---------------------------------------------------------------------------
55
+ // Pattern helpers
56
+ // ---------------------------------------------------------------------------
57
+ /**
58
+ * Match Intercode Part 6 issuing extension IDs:
59
+ * - `_<RICS>II1` — numeric RICS code prefix (e.g. `_3703II1`)
60
+ * - `+<CC>II1` — ISO 3166-1 alpha-2 country code prefix (e.g. `+FRII1`)
61
+ */
62
+ function isIntercodeIssuingExtension(extensionId) {
63
+ return /^[_+](\d+|[A-Z]{2})II1$/.test(extensionId);
64
+ }
65
+ /**
66
+ * Match Intercode Part 6 dynamic data formats:
67
+ * - `_<RICS>.ID1` — numeric RICS code prefix (e.g. `_3703.ID1`)
68
+ * - `FDC1` — French dynamic content variant
69
+ */
70
+ function isIntercodeDynamicData(dataFormat) {
71
+ return /^_\d+\.ID1$/.test(dataFormat) || dataFormat === 'FDC1';
72
+ }
73
+ // ---------------------------------------------------------------------------
74
+ // Hex / bytes helpers
75
+ // ---------------------------------------------------------------------------
76
+ function hexToBytes(hex) {
77
+ const clean = hex.replace(/\s+/g, '').replace(/h$/i, '').toLowerCase();
78
+ if (!/^[0-9a-f]*$/.test(clean))
79
+ throw new Error('Invalid hex characters');
80
+ if (clean.length === 0)
81
+ throw new Error('Hex input is empty');
82
+ if (clean.length % 2 !== 0)
83
+ throw new Error('Hex string must have even length');
84
+ return new Uint8Array(clean.match(/.{1,2}/g).map(b => parseInt(b, 16)));
85
+ }
86
+ // ---------------------------------------------------------------------------
87
+ // Public API
88
+ // ---------------------------------------------------------------------------
89
+ /**
90
+ * Decode a UIC barcode ticket from a hex string.
91
+ *
92
+ * @param hex - The hex-encoded barcode payload (whitespace and trailing 'h' are stripped).
93
+ * @returns A fully typed {@link UicBarcodeTicket} object.
94
+ */
95
+ export function decodeTicket(hex) {
96
+ const bytes = hexToBytes(hex);
97
+ return decodeTicketFromBytes(bytes);
98
+ }
99
+ /**
100
+ * Decode a UIC barcode ticket from raw bytes.
101
+ *
102
+ * @param bytes - The binary barcode payload.
103
+ * @returns A fully typed {@link UicBarcodeTicket} object.
104
+ */
105
+ export function decodeTicketFromBytes(bytes) {
106
+ // Step 1: Peek the header format using low-level BitBuffer
107
+ const peekBuf = BitBuffer.from(bytes);
108
+ peekBuf.readBit(); // skip optional bitmap (level2Signature present/absent)
109
+ const format = SchemaBuilder.build({ type: 'IA5String' }).decode(peekBuf);
110
+ const headerVersionMatch = format.match(/^U(\d+)$/);
111
+ if (!headerVersionMatch) {
112
+ throw new Error(`Unknown header format "${format}"`);
113
+ }
114
+ const headerVersion = parseInt(headerVersionMatch[1], 10);
115
+ // Step 2: Decode the full header with version-specific schema
116
+ const header = getHeaderCodec(headerVersion).decode(bytes);
117
+ const l2 = header.level2SignedData;
118
+ const l1 = l2.level1Data;
119
+ // Step 3: Extract security info
120
+ const security = {
121
+ securityProviderNum: l1.securityProviderNum,
122
+ securityProviderIA5: l1.securityProviderIA5,
123
+ keyId: l1.keyId,
124
+ level1KeyAlg: l1.level1KeyAlg,
125
+ level2KeyAlg: l1.level2KeyAlg,
126
+ level1SigningAlg: l1.level1SigningAlg,
127
+ level2SigningAlg: l1.level2SigningAlg,
128
+ level2PublicKey: l1.level2PublicKey,
129
+ level1Signature: l2.level1Signature,
130
+ endOfValidityYear: l1.endOfValidityYear,
131
+ endOfValidityDay: l1.endOfValidityDay,
132
+ endOfValidityTime: l1.endOfValidityTime,
133
+ validityDuration: l1.validityDuration,
134
+ };
135
+ // Step 4: Decode data blocks
136
+ const railTickets = [];
137
+ const otherDataBlocks = [];
138
+ for (const block of l1.dataSequence) {
139
+ const fcbMatch = block.dataFormat.match(/^FCB(\d+)$/);
140
+ if (fcbMatch) {
141
+ const fcbVersion = parseInt(fcbMatch[1], 10);
142
+ try {
143
+ const codecs = getTicketCodecs(fcbVersion);
144
+ const buf = BitBuffer.from(block.data);
145
+ const raw = codecs.UicRailTicketData.decode(buf);
146
+ railTickets.push(decodeRailTicket(fcbVersion, raw));
147
+ }
148
+ catch {
149
+ // If FCB decoding fails, add as raw block
150
+ otherDataBlocks.push({ dataFormat: block.dataFormat, data: block.data });
151
+ }
152
+ }
153
+ else {
154
+ otherDataBlocks.push({ dataFormat: block.dataFormat, data: block.data });
155
+ }
156
+ }
157
+ // Step 5: Decode Level 2 dynamic data
158
+ let dynamicData;
159
+ let level2DataBlock;
160
+ if (l2.level2Data) {
161
+ level2DataBlock = { dataFormat: l2.level2Data.dataFormat, data: l2.level2Data.data };
162
+ if (isIntercodeDynamicData(l2.level2Data.dataFormat)) {
163
+ try {
164
+ dynamicData = getIntercodeDynamicCodec().decode(l2.level2Data.data);
165
+ }
166
+ catch {
167
+ // leave as undefined if decoding fails
168
+ }
169
+ }
170
+ }
171
+ return {
172
+ format,
173
+ headerVersion,
174
+ level2Signature: header.level2Signature,
175
+ security,
176
+ railTickets,
177
+ otherDataBlocks,
178
+ dynamicData,
179
+ level2DataBlock,
180
+ };
181
+ }
182
+ // ---------------------------------------------------------------------------
183
+ // Rail ticket decoding helpers
184
+ // ---------------------------------------------------------------------------
185
+ function decodeRailTicket(fcbVersion, raw) {
186
+ const issuingDetail = raw.issuingDetail ? decodeIssuingDetail(raw.issuingDetail) : undefined;
187
+ const travelerDetail = raw.travelerDetail ? decodeTravelerDetail(raw.travelerDetail) : undefined;
188
+ const transportDocument = raw.transportDocument
189
+ ? decodeTransportDocuments(raw.transportDocument)
190
+ : undefined;
191
+ const controlDetail = raw.controlDetail ? raw.controlDetail : undefined;
192
+ return {
193
+ fcbVersion,
194
+ issuingDetail,
195
+ travelerDetail,
196
+ transportDocument,
197
+ controlDetail,
198
+ raw,
199
+ };
200
+ }
201
+ function decodeIssuingDetail(iss) {
202
+ const result = {
203
+ securityProviderNum: iss.securityProviderNum,
204
+ securityProviderIA5: iss.securityProviderIA5,
205
+ issuerNum: iss.issuerNum,
206
+ issuerIA5: iss.issuerIA5,
207
+ issuingYear: iss.issuingYear,
208
+ issuingDay: iss.issuingDay,
209
+ issuingTime: iss.issuingTime,
210
+ issuerName: iss.issuerName,
211
+ specimen: iss.specimen ?? false,
212
+ securePaperTicket: iss.securePaperTicket ?? false,
213
+ activated: iss.activated ?? false,
214
+ currency: iss.currency,
215
+ currencyFract: iss.currencyFract,
216
+ issuerPNR: iss.issuerPNR,
217
+ };
218
+ if (iss.extension) {
219
+ const ext = iss.extension;
220
+ if (isIntercodeIssuingExtension(ext.extensionId)) {
221
+ try {
222
+ result.intercodeIssuing = getIntercodeIssuingCodec().decode(ext.extensionData);
223
+ }
224
+ catch {
225
+ result.extension = { extensionId: ext.extensionId, extensionData: ext.extensionData };
226
+ }
227
+ }
228
+ else {
229
+ result.extension = { extensionId: ext.extensionId, extensionData: ext.extensionData };
230
+ }
231
+ }
232
+ return result;
233
+ }
234
+ function decodeTravelerDetail(td) {
235
+ return {
236
+ traveler: td.traveler,
237
+ preferredLanguage: td.preferredLanguage,
238
+ groupName: td.groupName,
239
+ };
240
+ }
241
+ function decodeTransportDocuments(docs) {
242
+ return docs.map((doc) => {
243
+ const ticket = doc.ticket || {};
244
+ const entries = Object.entries(ticket);
245
+ if (entries.length === 2 && entries[0][0] === 'key' && entries[1][0] === 'value') {
246
+ // CHOICE decoded as { key: "variantName", value: {...} }
247
+ return {
248
+ ticketType: entries[0][1],
249
+ ticket: entries[1][1],
250
+ };
251
+ }
252
+ // Single-key CHOICE
253
+ if (entries.length === 1) {
254
+ return {
255
+ ticketType: entries[0][0],
256
+ ticket: entries[0][1],
257
+ };
258
+ }
259
+ return {
260
+ ticketType: 'unknown',
261
+ ticket,
262
+ };
263
+ });
264
+ }
265
+ //# sourceMappingURL=decoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoder.js","sourceRoot":"","sources":["../src/decoder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { UicBarcodeTicketInput } from './types';
2
+ /**
3
+ * Encode a UIC barcode ticket to a hex string.
4
+ *
5
+ * @param input - The ticket data to encode.
6
+ * @returns Hex string of the encoded barcode payload.
7
+ */
8
+ export declare function encodeTicket(input: UicBarcodeTicketInput): string;
9
+ /**
10
+ * Encode a UIC barcode ticket to bytes.
11
+ *
12
+ * @param input - The ticket data to encode.
13
+ * @returns Uint8Array of the encoded barcode payload.
14
+ */
15
+ export declare function encodeTicketToBytes(input: UicBarcodeTicketInput): Uint8Array;
16
+ //# sourceMappingURL=encoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../src/encoder.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,qBAAqB,EAKtB,MAAM,SAAS,CAAC;AAoDjB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAkDjE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,qBAAqB,GAAG,UAAU,CAG5E"}