@nextera.one/tps-standard 0.4.3 → 0.5.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.
- package/README.md +268 -49
- package/dist/index.d.ts +366 -2
- package/dist/index.js +724 -1
- package/dist/src/index.js +693 -0
- package/dist/test/src/index.js +960 -0
- package/dist/test/test/persian-calendar.test.js +488 -0
- package/dist/test/test/tps-uid.test.js +295 -0
- package/dist/test/tps-uid.test.js +240 -0
- package/package.json +3 -2
- package/src/index.ts +1031 -2
package/dist/index.d.ts
CHANGED
|
@@ -31,11 +31,61 @@ export interface TPSComponents {
|
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Interface for Calendar Driver plugins.
|
|
34
|
-
* Implementations
|
|
34
|
+
* Implementations provide conversion logic to/from Gregorian and support for
|
|
35
|
+
* external calendar libraries.
|
|
36
|
+
*
|
|
37
|
+
* @example Using a driver to parse a Hijri date string
|
|
38
|
+
* ```ts
|
|
39
|
+
* const driver = TPS.getDriver('hij');
|
|
40
|
+
* if (driver?.parseDate) {
|
|
41
|
+
* const components = driver.parseDate('1447-07-21');
|
|
42
|
+
* const gregDate = driver.toGregorian(components);
|
|
43
|
+
* const tpsString = TPS.fromDate(gregDate, 'hij');
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example Wrapping an external library (moment-hijri)
|
|
48
|
+
* ```ts
|
|
49
|
+
* import moment from 'moment-hijri';
|
|
50
|
+
*
|
|
51
|
+
* class HijriDriver implements CalendarDriver {
|
|
52
|
+
* readonly code = 'hij';
|
|
53
|
+
*
|
|
54
|
+
* parseDate(input: string, format?: string): Partial<TPSComponents> {
|
|
55
|
+
* const m = moment(input, format || 'iYYYY-iMM-iDD');
|
|
56
|
+
* return {
|
|
57
|
+
* calendar: 'hij',
|
|
58
|
+
* year: m.iYear(),
|
|
59
|
+
* month: m.iMonth() + 1,
|
|
60
|
+
* day: m.iDate()
|
|
61
|
+
* };
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* fromGregorian(date: Date): Partial<TPSComponents> {
|
|
65
|
+
* const m = moment(date);
|
|
66
|
+
* return {
|
|
67
|
+
* calendar: 'hij',
|
|
68
|
+
* year: m.iYear(),
|
|
69
|
+
* month: m.iMonth() + 1,
|
|
70
|
+
* day: m.iDate(),
|
|
71
|
+
* hour: m.hour(),
|
|
72
|
+
* minute: m.minute(),
|
|
73
|
+
* second: m.second()
|
|
74
|
+
* };
|
|
75
|
+
* }
|
|
76
|
+
*
|
|
77
|
+
* // ... other methods
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
35
80
|
*/
|
|
36
81
|
export interface CalendarDriver {
|
|
37
82
|
/** The calendar code this driver handles (e.g., 'hij', 'jul'). */
|
|
38
83
|
readonly code: CalendarCode;
|
|
84
|
+
/**
|
|
85
|
+
* Human-readable name for this calendar (optional).
|
|
86
|
+
* @example "Hijri (Islamic)"
|
|
87
|
+
*/
|
|
88
|
+
readonly name?: string;
|
|
39
89
|
/**
|
|
40
90
|
* Converts a Gregorian Date to this calendar's components.
|
|
41
91
|
* @param date - The Gregorian Date object.
|
|
@@ -51,9 +101,87 @@ export interface CalendarDriver {
|
|
|
51
101
|
/**
|
|
52
102
|
* Generates a TPS time string for this calendar from a Date.
|
|
53
103
|
* @param date - The Gregorian Date object.
|
|
54
|
-
* @returns A TPS time string (e.g., "T:hij.
|
|
104
|
+
* @returns A TPS time string (e.g., "T:hij.y1447.M07.d21...").
|
|
55
105
|
*/
|
|
56
106
|
fromDate(date: Date): string;
|
|
107
|
+
/**
|
|
108
|
+
* Parse a calendar-specific date string into TPS components.
|
|
109
|
+
* This allows drivers to handle native date formats from external libraries.
|
|
110
|
+
*
|
|
111
|
+
* @param input - Date string in calendar-native format (e.g., '1447-07-21' for Hijri)
|
|
112
|
+
* @param format - Optional format string (driver-specific, e.g., 'iYYYY-iMM-iDD')
|
|
113
|
+
* @returns Partial TPS components
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* // Hijri driver
|
|
118
|
+
* driver.parseDate('1447-07-21'); // → { year: 1447, month: 7, day: 21, calendar: 'hij' }
|
|
119
|
+
*
|
|
120
|
+
* // With time
|
|
121
|
+
* driver.parseDate('1447-07-21 14:30:00'); // → { year: 1447, month: 7, day: 21, hour: 14, ... }
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
parseDate?(input: string, format?: string): Partial<TPSComponents>;
|
|
125
|
+
/**
|
|
126
|
+
* Format TPS components to a calendar-specific date string.
|
|
127
|
+
* Inverse of parseDate().
|
|
128
|
+
*
|
|
129
|
+
* @param components - TPS components to format
|
|
130
|
+
* @param format - Optional format string (driver-specific)
|
|
131
|
+
* @returns Formatted date string in calendar-native format
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* driver.format({ year: 1447, month: 7, day: 21 }); // → '1447-07-21'
|
|
136
|
+
* driver.format({ year: 1447, month: 7, day: 21 }, 'short'); // → '21/7/1447'
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
format?(components: Partial<TPSComponents>, format?: string): string;
|
|
140
|
+
/**
|
|
141
|
+
* Validate a calendar-specific date string or components.
|
|
142
|
+
*
|
|
143
|
+
* @param input - Date string or components to validate
|
|
144
|
+
* @returns true if valid for this calendar
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* driver.validate('1447-13-01'); // → false (month 13 invalid)
|
|
149
|
+
* driver.validate({ year: 1447, month: 7, day: 31 }); // → false (Rajab has 30 days)
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
validate?(input: string | Partial<TPSComponents>): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Get calendar metadata (month names, day names, etc.).
|
|
155
|
+
* Useful for UI rendering.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* driver.getMetadata().monthNames
|
|
160
|
+
* // → ['Muharram', 'Safar', 'Rabi I', ...]
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
getMetadata?(): CalendarMetadata;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Metadata about a calendar system.
|
|
167
|
+
*/
|
|
168
|
+
export interface CalendarMetadata {
|
|
169
|
+
/** Human-readable calendar name */
|
|
170
|
+
name: string;
|
|
171
|
+
/** Month names in order (1-12 or 1-13) */
|
|
172
|
+
monthNames?: string[];
|
|
173
|
+
/** Short month names */
|
|
174
|
+
monthNamesShort?: string[];
|
|
175
|
+
/** Day of week names (Sunday=0 or locale-specific) */
|
|
176
|
+
dayNames?: string[];
|
|
177
|
+
/** Short day names */
|
|
178
|
+
dayNamesShort?: string[];
|
|
179
|
+
/** Whether this calendar is lunar-based */
|
|
180
|
+
isLunar?: boolean;
|
|
181
|
+
/** Number of months per year */
|
|
182
|
+
monthsPerYear?: number;
|
|
183
|
+
/** Epoch year (for reference) */
|
|
184
|
+
epochYear?: number;
|
|
57
185
|
}
|
|
58
186
|
export declare class TPS {
|
|
59
187
|
private static readonly drivers;
|
|
@@ -101,6 +229,242 @@ export declare class TPS {
|
|
|
101
229
|
* @returns JS Date object or `null` if invalid.
|
|
102
230
|
*/
|
|
103
231
|
static toDate(tpsString: string): Date | null;
|
|
232
|
+
/**
|
|
233
|
+
* Parse a calendar-specific date string into TPS components.
|
|
234
|
+
* Requires the driver to implement the optional `parseDate` method.
|
|
235
|
+
*
|
|
236
|
+
* @param calendar - The calendar code (e.g., 'hij')
|
|
237
|
+
* @param dateString - Date string in calendar-native format (e.g., '1447-07-21')
|
|
238
|
+
* @param format - Optional format string (driver-specific)
|
|
239
|
+
* @returns TPS components or null if parsing fails
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```ts
|
|
243
|
+
* const components = TPS.parseCalendarDate('hij', '1447-07-21');
|
|
244
|
+
* // { calendar: 'hij', year: 1447, month: 7, day: 21 }
|
|
245
|
+
*
|
|
246
|
+
* const uri = TPS.toURI({ ...components, latitude: 31.95, longitude: 35.91 });
|
|
247
|
+
* // "tps://31.95,35.91@T:hij.y1447.M07.d21"
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
static parseCalendarDate(calendar: CalendarCode, dateString: string, format?: string): Partial<TPSComponents> | null;
|
|
251
|
+
/**
|
|
252
|
+
* Convert a calendar-specific date string directly to a TPS URI.
|
|
253
|
+
* This is a convenience method that combines parseDate + toURI.
|
|
254
|
+
*
|
|
255
|
+
* @param calendar - The calendar code (e.g., 'hij')
|
|
256
|
+
* @param dateString - Date string in calendar-native format
|
|
257
|
+
* @param location - Optional location (lat/lon/alt or privacy flag)
|
|
258
|
+
* @returns Full TPS URI string
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```ts
|
|
262
|
+
* // With coordinates
|
|
263
|
+
* TPS.fromCalendarDate('hij', '1447-07-21', { latitude: 31.95, longitude: 35.91 });
|
|
264
|
+
* // "tps://31.95,35.91@T:hij.y1447.M07.d21"
|
|
265
|
+
*
|
|
266
|
+
* // With privacy flag
|
|
267
|
+
* TPS.fromCalendarDate('hij', '1447-07-21', { isHiddenLocation: true });
|
|
268
|
+
* // "tps://hidden@T:hij.y1447.M07.d21"
|
|
269
|
+
*
|
|
270
|
+
* // Without location
|
|
271
|
+
* TPS.fromCalendarDate('hij', '1447-07-21');
|
|
272
|
+
* // "tps://unknown@T:hij.y1447.M07.d21"
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
static fromCalendarDate(calendar: CalendarCode, dateString: string, location?: {
|
|
276
|
+
latitude?: number;
|
|
277
|
+
longitude?: number;
|
|
278
|
+
altitude?: number;
|
|
279
|
+
isUnknownLocation?: boolean;
|
|
280
|
+
isHiddenLocation?: boolean;
|
|
281
|
+
isRedactedLocation?: boolean;
|
|
282
|
+
}): string;
|
|
283
|
+
/**
|
|
284
|
+
* Format TPS components to a calendar-specific date string.
|
|
285
|
+
* Requires the driver to implement the optional `format` method.
|
|
286
|
+
*
|
|
287
|
+
* @param calendar - The calendar code
|
|
288
|
+
* @param components - TPS components to format
|
|
289
|
+
* @param format - Optional format string (driver-specific)
|
|
290
|
+
* @returns Formatted date string in calendar-native format
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```ts
|
|
294
|
+
* const tps = TPS.parse('tps://unknown@T:hij.y1447.M07.d21');
|
|
295
|
+
* const formatted = TPS.formatCalendarDate('hij', tps);
|
|
296
|
+
* // "1447-07-21"
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
static formatCalendarDate(calendar: CalendarCode, components: Partial<TPSComponents>, format?: string): string;
|
|
104
300
|
private static _mapGroupsToComponents;
|
|
105
301
|
private static pad;
|
|
106
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* Decoded result from TPSUID7RB binary format.
|
|
305
|
+
*/
|
|
306
|
+
export type TPSUID7RBDecodeResult = {
|
|
307
|
+
/** Version identifier */
|
|
308
|
+
version: 'tpsuid7rb';
|
|
309
|
+
/** Epoch milliseconds (UTC) */
|
|
310
|
+
epochMs: number;
|
|
311
|
+
/** Whether the TPS payload was compressed */
|
|
312
|
+
compressed: boolean;
|
|
313
|
+
/** 32-bit nonce for collision prevention */
|
|
314
|
+
nonce: number;
|
|
315
|
+
/** The original TPS string (exact reconstruction) */
|
|
316
|
+
tps: string;
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* Encoding options for TPSUID7RB.
|
|
320
|
+
*/
|
|
321
|
+
export type TPSUID7RBEncodeOptions = {
|
|
322
|
+
/** Enable zlib compression of TPS payload */
|
|
323
|
+
compress?: boolean;
|
|
324
|
+
/** Override epoch milliseconds (default: parsed from TPS) */
|
|
325
|
+
epochMs?: number;
|
|
326
|
+
};
|
|
327
|
+
/**
|
|
328
|
+
* TPS-UID v1 — Temporal Positioning System Identifier (Binary Reversible)
|
|
329
|
+
*
|
|
330
|
+
* A time-first, reversible identifier that binds an event to a TPS coordinate.
|
|
331
|
+
* Unlike UUIDs, TPS-UID identifies events in spacetime and allows exact
|
|
332
|
+
* reconstruction of the original TPS string.
|
|
333
|
+
*
|
|
334
|
+
* Binary Schema (all integers big-endian):
|
|
335
|
+
* ```
|
|
336
|
+
* MAGIC 4 bytes "TPU7"
|
|
337
|
+
* VER 1 byte 0x01
|
|
338
|
+
* FLAGS 1 byte bit0 = compression flag
|
|
339
|
+
* TIME 6 bytes epoch_ms (48-bit unsigned)
|
|
340
|
+
* NONCE 4 bytes 32-bit random
|
|
341
|
+
* LEN varint length of TPS payload
|
|
342
|
+
* TPS bytes UTF-8 TPS string (raw or zlib-compressed)
|
|
343
|
+
* ```
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```ts
|
|
347
|
+
* const tps = 'tps://31.95,35.91@T:greg.m3.c1.y26.M01.d09';
|
|
348
|
+
*
|
|
349
|
+
* // Encode to binary
|
|
350
|
+
* const bytes = TPSUID7RB.encodeBinary(tps);
|
|
351
|
+
*
|
|
352
|
+
* // Encode to base64url string
|
|
353
|
+
* const id = TPSUID7RB.encodeBinaryB64(tps);
|
|
354
|
+
* // → "tpsuid7rb_AFRQV..."
|
|
355
|
+
*
|
|
356
|
+
* // Decode back to original TPS
|
|
357
|
+
* const decoded = TPSUID7RB.decodeBinaryB64(id);
|
|
358
|
+
* console.log(decoded.tps); // exact original TPS
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
export declare class TPSUID7RB {
|
|
362
|
+
/** Magic bytes: "TPU7" */
|
|
363
|
+
private static readonly MAGIC;
|
|
364
|
+
/** Version 1 */
|
|
365
|
+
private static readonly VER;
|
|
366
|
+
/** String prefix for base64url encoded form */
|
|
367
|
+
private static readonly PREFIX;
|
|
368
|
+
/** Regex for validating base64url encoded form */
|
|
369
|
+
static readonly REGEX: RegExp;
|
|
370
|
+
/**
|
|
371
|
+
* Encode TPS string to binary bytes (Uint8Array).
|
|
372
|
+
* This is the canonical form for hashing, signing, and storage.
|
|
373
|
+
*
|
|
374
|
+
* @param tps - The TPS string to encode
|
|
375
|
+
* @param opts - Encoding options (compress, epochMs override)
|
|
376
|
+
* @returns Binary TPS-UID as Uint8Array
|
|
377
|
+
*/
|
|
378
|
+
static encodeBinary(tps: string, opts?: TPSUID7RBEncodeOptions): Uint8Array;
|
|
379
|
+
/**
|
|
380
|
+
* Decode binary bytes back to original TPS string.
|
|
381
|
+
*
|
|
382
|
+
* @param bytes - Binary TPS-UID
|
|
383
|
+
* @returns Decoded result with original TPS string
|
|
384
|
+
*/
|
|
385
|
+
static decodeBinary(bytes: Uint8Array): TPSUID7RBDecodeResult;
|
|
386
|
+
/**
|
|
387
|
+
* Encode TPS to base64url string with prefix.
|
|
388
|
+
* This is the transport/storage form.
|
|
389
|
+
*
|
|
390
|
+
* @param tps - The TPS string to encode
|
|
391
|
+
* @param opts - Encoding options
|
|
392
|
+
* @returns Base64url encoded TPS-UID with prefix
|
|
393
|
+
*/
|
|
394
|
+
static encodeBinaryB64(tps: string, opts?: TPSUID7RBEncodeOptions): string;
|
|
395
|
+
/**
|
|
396
|
+
* Decode base64url string back to original TPS string.
|
|
397
|
+
*
|
|
398
|
+
* @param id - Base64url encoded TPS-UID with prefix
|
|
399
|
+
* @returns Decoded result with original TPS string
|
|
400
|
+
*/
|
|
401
|
+
static decodeBinaryB64(id: string): TPSUID7RBDecodeResult;
|
|
402
|
+
/**
|
|
403
|
+
* Validate base64url encoded TPS-UID format.
|
|
404
|
+
* Note: This validates shape only; binary decode is authoritative.
|
|
405
|
+
*
|
|
406
|
+
* @param id - String to validate
|
|
407
|
+
* @returns true if format is valid
|
|
408
|
+
*/
|
|
409
|
+
static validateBinaryB64(id: string): boolean;
|
|
410
|
+
/**
|
|
411
|
+
* Generate a TPS-UID from the current time and optional location.
|
|
412
|
+
*
|
|
413
|
+
* @param opts - Generation options
|
|
414
|
+
* @returns Base64url encoded TPS-UID
|
|
415
|
+
*/
|
|
416
|
+
static generate(opts?: {
|
|
417
|
+
latitude?: number;
|
|
418
|
+
longitude?: number;
|
|
419
|
+
altitude?: number;
|
|
420
|
+
compress?: boolean;
|
|
421
|
+
}): string;
|
|
422
|
+
/**
|
|
423
|
+
* Generate a TPS string from a Date and optional location.
|
|
424
|
+
*/
|
|
425
|
+
private static generateTPSString;
|
|
426
|
+
/**
|
|
427
|
+
* Parse epoch milliseconds from a TPS string.
|
|
428
|
+
* Supports both URI format (tps://...) and time-only format (T:greg...)
|
|
429
|
+
*/
|
|
430
|
+
static epochMsFromTPSString(tps: string): number;
|
|
431
|
+
/** Write 48-bit unsigned integer (big-endian) */
|
|
432
|
+
private static writeU48;
|
|
433
|
+
/** Read 48-bit unsigned integer (big-endian) */
|
|
434
|
+
private static readU48;
|
|
435
|
+
/** Encode unsigned integer as LEB128 varint */
|
|
436
|
+
private static uvarintEncode;
|
|
437
|
+
/** Decode LEB128 varint */
|
|
438
|
+
private static uvarintDecode;
|
|
439
|
+
/** Encode bytes to base64url (no padding) */
|
|
440
|
+
private static base64UrlEncode;
|
|
441
|
+
/** Decode base64url to bytes */
|
|
442
|
+
private static base64UrlDecode;
|
|
443
|
+
/** Compress using zlib deflate raw */
|
|
444
|
+
private static deflateRaw;
|
|
445
|
+
/** Decompress using zlib inflate raw */
|
|
446
|
+
private static inflateRaw;
|
|
447
|
+
/**
|
|
448
|
+
* Seal (sign) a TPS string to create a cryptographically verifiable TPS-UID.
|
|
449
|
+
* This appends an Ed25519 signature to the binary form.
|
|
450
|
+
*
|
|
451
|
+
* @param tps - The TPS string to seal
|
|
452
|
+
* @param privateKey - Ed25519 private key (hex or buffer)
|
|
453
|
+
* @param opts - Encoding options
|
|
454
|
+
* @returns Sealed binary TPS-UID
|
|
455
|
+
*/
|
|
456
|
+
static seal(tps: string, privateKey: string | Buffer | Uint8Array, opts?: TPSUID7RBEncodeOptions): Uint8Array;
|
|
457
|
+
/**
|
|
458
|
+
* Verify a sealed TPS-UID and decode it.
|
|
459
|
+
* Throws if signature is invalid or not sealed.
|
|
460
|
+
*
|
|
461
|
+
* @param sealedBytes - The binary sealed TPS-UID
|
|
462
|
+
* @param publicKey - Ed25519 public key (hex or buffer) to verify against
|
|
463
|
+
* @returns Decoded result
|
|
464
|
+
*/
|
|
465
|
+
static verifyAndDecode(sealedBytes: Uint8Array, publicKey: string | Buffer | Uint8Array): TPSUID7RBDecodeResult;
|
|
466
|
+
private static signEd25519;
|
|
467
|
+
private static verifyEd25519;
|
|
468
|
+
/** Generate cryptographically secure random bytes */
|
|
469
|
+
private static randomBytes;
|
|
470
|
+
}
|