@hkdigital/lib-sveltekit 0.1.58 → 0.1.59
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/dist/constants/bases.d.ts +10 -0
- package/dist/constants/bases.js +13 -0
- package/dist/constants/time.d.ts +1 -2
- package/dist/constants/time.js +2 -2
- package/dist/util/bases/base58.d.ts +58 -0
- package/dist/util/bases/base58.js +262 -0
- package/dist/util/bases/index.d.ts +1 -0
- package/dist/util/bases/index.js +1 -0
- package/dist/util/time/index.d.ts +2 -9
- package/dist/util/time/index.js +11 -35
- package/dist/util/unique/index.d.ts +81 -0
- package/dist/util/unique/index.js +249 -0
- package/package.json +1 -1
@@ -0,0 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* Characters selected for their visually distinct shapes to improve
|
3
|
+
* human readability and reduce confusion.
|
4
|
+
*/
|
5
|
+
export const ALPHABET_BASE_HUMAN: "3456789abcdefghjkmnpqrstuvwxy";
|
6
|
+
/**
|
7
|
+
* Base58 character set: alphanumeric characters excluding similar-looking
|
8
|
+
* ones (0, O, I, l) to prevent visual ambiguity.
|
9
|
+
*/
|
10
|
+
export const ALPHABET_BASE_58: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
/**
|
3
|
+
* Characters selected for their visually distinct shapes to improve
|
4
|
+
* human readability and reduce confusion.
|
5
|
+
*/
|
6
|
+
export const ALPHABET_BASE_HUMAN = '3456789abcdefghjkmnpqrstuvwxy';
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Base58 character set: alphanumeric characters excluding similar-looking
|
10
|
+
* ones (0, O, I, l) to prevent visual ambiguity.
|
11
|
+
*/
|
12
|
+
export const ALPHABET_BASE_58 =
|
13
|
+
'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
package/dist/constants/time.d.ts
CHANGED
package/dist/constants/time.js
CHANGED
@@ -24,5 +24,5 @@ export const INTERVALS_MS = {
|
|
24
24
|
|
25
25
|
// > Offsets
|
26
26
|
|
27
|
-
export const
|
28
|
-
export const TIME_2100_01_01 = 4102444800000; // 2100-01-01T00:00:00.000Z
|
27
|
+
export const TIME_2025_01_01 = 1577836800000; // 2020-01-01T00:00:00.000Z
|
28
|
+
// export const TIME_2100_01_01 = 4102444800000; // 2100-01-01T00:00:00.000Z
|
@@ -0,0 +1,58 @@
|
|
1
|
+
/**
|
2
|
+
* Convert a number to a base 58 encoded string
|
3
|
+
*
|
4
|
+
* @param {number|BigInt} num - Number to encode
|
5
|
+
*
|
6
|
+
* @returns {string} string encoded using base 58
|
7
|
+
*/
|
8
|
+
export function base58fromNumber(num: number | bigint): string;
|
9
|
+
/**
|
10
|
+
* Returns true if the specified string only contains base 58 characters
|
11
|
+
*
|
12
|
+
* @param {string} str [description]
|
13
|
+
*
|
14
|
+
* @returns {boolean} true if the string only contains base 58 characters
|
15
|
+
*/
|
16
|
+
export function isBase58(str: string): boolean;
|
17
|
+
/**
|
18
|
+
* Convert a string encoded as base 58 to a number (BigInt)
|
19
|
+
*
|
20
|
+
* @param {string} str - String to decode
|
21
|
+
*
|
22
|
+
* @param {number} [exceptionValue]
|
23
|
+
* If specified, the exceptionValue will be returned instead of
|
24
|
+
* throwing an exception
|
25
|
+
*
|
26
|
+
* @returns {number} decoded decimal numerical representation
|
27
|
+
*/
|
28
|
+
export function base58toNumber(str: string, exceptionValue?: number, ...args: any[]): number;
|
29
|
+
/**
|
30
|
+
* Convert a base58 encoded string to an Uint8Array (bytes)
|
31
|
+
* - A base58 encoded string actually represents a (potentially very big)
|
32
|
+
* number. This method converts that number into a bytes representation
|
33
|
+
* - A byte can hold 256 values, a base58 character only 58, so there will be
|
34
|
+
* less bytes needed to encode the value of the base58 encoded string
|
35
|
+
*
|
36
|
+
* @param {string} str - String to convert
|
37
|
+
*
|
38
|
+
* @returns {Uint8Array} bytes that represent the base58 encoded string value
|
39
|
+
*/
|
40
|
+
export function base58toBytes(str: string): Uint8Array;
|
41
|
+
/**
|
42
|
+
* Convert a base58 encoded string to a (base256) byte string
|
43
|
+
*
|
44
|
+
* @param {string} str
|
45
|
+
*
|
46
|
+
* @returns {string} byte string
|
47
|
+
*/
|
48
|
+
export function base58toByteString(str: string): string;
|
49
|
+
/**
|
50
|
+
* Convert bytes to number
|
51
|
+
*
|
52
|
+
* @param {Uint8Array} bytes
|
53
|
+
*
|
54
|
+
* @returns {BigInt} numeric value
|
55
|
+
*/
|
56
|
+
export function bytesToNumber(bytes: Uint8Array): bigint;
|
57
|
+
export const ALPHABET_BASE_58: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
58
|
+
export const ALPHABET_BASE_58_MAP: Map<string, number>;
|
@@ -0,0 +1,262 @@
|
|
1
|
+
/**
|
2
|
+
* base-58.js
|
3
|
+
*
|
4
|
+
* @description
|
5
|
+
* This file contains code for working with base 58 encoding
|
6
|
+
*
|
7
|
+
* @example
|
8
|
+
*
|
9
|
+
* import { base58fromNumber } from "./base-58.js";
|
10
|
+
*
|
11
|
+
* console.log( base58fromNumber( 1234513245 ) ) // base 58 encoded string
|
12
|
+
*/
|
13
|
+
|
14
|
+
/* ------------------------------------------------------------------ Imports */
|
15
|
+
|
16
|
+
import * as expect from '../expect';
|
17
|
+
|
18
|
+
/* ------------------------------------------------------------------ Exports */
|
19
|
+
|
20
|
+
// Base 58 helper functions
|
21
|
+
//
|
22
|
+
// Inspired by
|
23
|
+
// https://github.com/jimeh/node-base58/blob/master/src/base58.js
|
24
|
+
//
|
25
|
+
// @note
|
26
|
+
// Two different commonly used alphabets exist
|
27
|
+
//
|
28
|
+
// Bitcoin, IPFS (respects default sort order):
|
29
|
+
// 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
|
30
|
+
//
|
31
|
+
// Short URLs for Flickr
|
32
|
+
// 123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ
|
33
|
+
//
|
34
|
+
// @see https://en.wikipedia.org/wiki/StdBase58Helper
|
35
|
+
//
|
36
|
+
|
37
|
+
export const ALPHABET_BASE_58 =
|
38
|
+
'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
39
|
+
|
40
|
+
//export
|
41
|
+
const BASE_SIZE = BigInt(ALPHABET_BASE_58.length);
|
42
|
+
|
43
|
+
// Create a lookup table to fetch character index
|
44
|
+
|
45
|
+
export const ALPHABET_BASE_58_MAP =
|
46
|
+
new Map( [...ALPHABET_BASE_58].map( ( char, index ) => [ char, index ] ) );
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Convert a number to a base 58 encoded string
|
50
|
+
*
|
51
|
+
* @param {number|BigInt} num - Number to encode
|
52
|
+
*
|
53
|
+
* @returns {string} string encoded using base 58
|
54
|
+
*/
|
55
|
+
export function base58fromNumber( num )
|
56
|
+
{
|
57
|
+
let str = '';
|
58
|
+
|
59
|
+
if( typeof num !== 'bigint' )
|
60
|
+
{
|
61
|
+
if( Number.isNaN( num ) ||
|
62
|
+
num < 0 ||
|
63
|
+
num > Number.MAX_SAFE_INTEGER ||
|
64
|
+
Math.floor( num ) !== num )
|
65
|
+
{
|
66
|
+
throw new Error(
|
67
|
+
'Invalid parameter [num], expected not negative safe integer');
|
68
|
+
}
|
69
|
+
|
70
|
+
num = BigInt(num);
|
71
|
+
}
|
72
|
+
|
73
|
+
while( num >= BASE_SIZE )
|
74
|
+
{
|
75
|
+
const mod = Number(num % BASE_SIZE);
|
76
|
+
|
77
|
+
str = ALPHABET_BASE_58[ mod ] + str;
|
78
|
+
|
79
|
+
// num = Math.floor( num / BASE_SIZE );
|
80
|
+
//
|
81
|
+
num = num / BASE_SIZE; // BigInts are integers, automatically rounded down
|
82
|
+
}
|
83
|
+
|
84
|
+
return ALPHABET_BASE_58[ Number(num) ] + str;
|
85
|
+
}
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Returns true if the specified string only contains base 58 characters
|
89
|
+
*
|
90
|
+
* @param {string} str [description]
|
91
|
+
*
|
92
|
+
* @returns {boolean} true if the string only contains base 58 characters
|
93
|
+
*/
|
94
|
+
export function isBase58( str )
|
95
|
+
{
|
96
|
+
expect.string( str );
|
97
|
+
|
98
|
+
for( let j = 0, n = str.length; j < n; j = j + 1 )
|
99
|
+
{
|
100
|
+
const char = str.charAt(j);
|
101
|
+
if( !ALPHABET_BASE_58_MAP.has( char ) )
|
102
|
+
{
|
103
|
+
return false;
|
104
|
+
}
|
105
|
+
} // end for
|
106
|
+
|
107
|
+
return true;
|
108
|
+
}
|
109
|
+
|
110
|
+
// -----------------------------------------------------------------------------
|
111
|
+
|
112
|
+
/**
|
113
|
+
* Convert a string encoded as base 58 to a number (BigInt)
|
114
|
+
*
|
115
|
+
* @param {string} str - String to decode
|
116
|
+
*
|
117
|
+
* @param {number} [exceptionValue]
|
118
|
+
* If specified, the exceptionValue will be returned instead of
|
119
|
+
* throwing an exception
|
120
|
+
*
|
121
|
+
* @returns {number} decoded decimal numerical representation
|
122
|
+
*/
|
123
|
+
export function base58toNumber( str, exceptionValue )
|
124
|
+
{
|
125
|
+
expect.string( str, 'Missing or invalid parameter [str]' );
|
126
|
+
|
127
|
+
let num = BigInt(0);
|
128
|
+
|
129
|
+
const n = str.length;
|
130
|
+
const n_1 = n - 1;
|
131
|
+
|
132
|
+
for( let j = 0; j < n; j = j + 1 )
|
133
|
+
{
|
134
|
+
const char = str.charAt(j);
|
135
|
+
const value = ALPHABET_BASE_58_MAP.get( char );
|
136
|
+
|
137
|
+
if( value === undefined )
|
138
|
+
{
|
139
|
+
if( 1 === arguments.length )
|
140
|
+
{
|
141
|
+
throw new Error(
|
142
|
+
`Invalid character [${char}] found in string (expected base58`);
|
143
|
+
}
|
144
|
+
else {
|
145
|
+
return exceptionValue;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
num = num + BigInt(value) * BigInt(58) ** BigInt( n_1 - j );
|
150
|
+
|
151
|
+
// console.log("num", num );
|
152
|
+
|
153
|
+
} // end for
|
154
|
+
|
155
|
+
return num;
|
156
|
+
}
|
157
|
+
|
158
|
+
// -----------------------------------------------------------------------------
|
159
|
+
|
160
|
+
/**
|
161
|
+
* Convert a base58 encoded string to an Uint8Array (bytes)
|
162
|
+
* - A base58 encoded string actually represents a (potentially very big)
|
163
|
+
* number. This method converts that number into a bytes representation
|
164
|
+
* - A byte can hold 256 values, a base58 character only 58, so there will be
|
165
|
+
* less bytes needed to encode the value of the base58 encoded string
|
166
|
+
*
|
167
|
+
* @param {string} str - String to convert
|
168
|
+
*
|
169
|
+
* @returns {Uint8Array} bytes that represent the base58 encoded string value
|
170
|
+
*/
|
171
|
+
export function base58toBytes( str )
|
172
|
+
{
|
173
|
+
const num = base58toNumber( str );
|
174
|
+
|
175
|
+
let numBase16 = num.toString(16);
|
176
|
+
|
177
|
+
if( 1 === numBase16.length % 2 )
|
178
|
+
{
|
179
|
+
//
|
180
|
+
// String contains inpair number of characters -> prefix a "0"
|
181
|
+
//
|
182
|
+
numBase16 = '0' + numBase16;
|
183
|
+
}
|
184
|
+
|
185
|
+
const n = numBase16.length;
|
186
|
+
|
187
|
+
const out = new Uint8Array( numBase16.length >> 1 );
|
188
|
+
|
189
|
+
for( let j = n - 1; j > 0; j = j - 2 )
|
190
|
+
{
|
191
|
+
const low16 = parseInt( numBase16[ j ], 16 );
|
192
|
+
const high16 = parseInt( numBase16[ j - 1 ], 16 );
|
193
|
+
|
194
|
+
// // const low16 = (j < n_1) ? parseInt(numBase16[ j + 1 ], 10) : 0;
|
195
|
+
|
196
|
+
// const low16 = (j < n_1) ? parseInt( numBase16[ j + 1 ], 16 ) : 0;
|
197
|
+
|
198
|
+
const value256 = (high16 << 4) + low16;
|
199
|
+
|
200
|
+
out[ j >> 1 ] = value256;
|
201
|
+
|
202
|
+
// console.log(
|
203
|
+
// {
|
204
|
+
// numBase16,
|
205
|
+
// n,
|
206
|
+
// j,
|
207
|
+
// high16,
|
208
|
+
// low16,
|
209
|
+
// value256,
|
210
|
+
// out
|
211
|
+
// } );
|
212
|
+
|
213
|
+
} // end for
|
214
|
+
|
215
|
+
return out;
|
216
|
+
}
|
217
|
+
|
218
|
+
// -----------------------------------------------------------------------------
|
219
|
+
|
220
|
+
/**
|
221
|
+
* Convert a base58 encoded string to a (base256) byte string
|
222
|
+
*
|
223
|
+
* @param {string} str
|
224
|
+
*
|
225
|
+
* @returns {string} byte string
|
226
|
+
*/
|
227
|
+
export function base58toByteString( str )
|
228
|
+
{
|
229
|
+
return new TextDecoder().decode( base58toBytes( str ) );
|
230
|
+
}
|
231
|
+
|
232
|
+
// -----------------------------------------------------------------------------
|
233
|
+
|
234
|
+
/**
|
235
|
+
* Convert bytes to number
|
236
|
+
*
|
237
|
+
* @param {Uint8Array} bytes
|
238
|
+
*
|
239
|
+
* @returns {BigInt} numeric value
|
240
|
+
*/
|
241
|
+
export function bytesToNumber( bytes )
|
242
|
+
{
|
243
|
+
let sum = BigInt(0);
|
244
|
+
|
245
|
+
// console.log( "check", bytes.length );
|
246
|
+
|
247
|
+
for( let j = 0, n = bytes.length; j < n; j = j + 1 )
|
248
|
+
{
|
249
|
+
const base = BigInt(256) ** BigInt( n - 1 - j );
|
250
|
+
const value = bytes[ j ];
|
251
|
+
|
252
|
+
// console.log(
|
253
|
+
// {
|
254
|
+
// base,
|
255
|
+
// value
|
256
|
+
// } );
|
257
|
+
|
258
|
+
sum = sum + base * BigInt( value );
|
259
|
+
}
|
260
|
+
|
261
|
+
return sum;
|
262
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./base58.js";
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './base58.js';
|
@@ -15,9 +15,9 @@
|
|
15
15
|
export function delay(delayOrMinDelayMs: number, maxDelayMs?: number): Promise<any>;
|
16
16
|
/**
|
17
17
|
* Get the number of milliseconds since the specified time stamp of the default
|
18
|
-
* reference time stamp
|
18
|
+
* reference time stamp TIME_2025_01_01
|
19
19
|
*
|
20
|
-
* @param {number} [sinceMs=
|
20
|
+
* @param {number} [sinceMs=TIME_2025_01_01]
|
21
21
|
*
|
22
22
|
* @returns {number} number of milliseconds since the specified time
|
23
23
|
*/
|
@@ -111,10 +111,3 @@ export function getTimeAtStartOfDay(dateOrTimestamp: Date | number): number;
|
|
111
111
|
* @returns {number} timestamp of start of the day
|
112
112
|
*/
|
113
113
|
export function getTimeAtEndOfDay(dateOrTimestamp: Date | number): number;
|
114
|
-
export const SECOND_MS: 1000;
|
115
|
-
export const MINUTE_MS: number;
|
116
|
-
export const HOUR_MS: number;
|
117
|
-
export const DAY_MS: number;
|
118
|
-
export const WEEK_MS: number;
|
119
|
-
export const TIME_2020_01_01: 1577836800000;
|
120
|
-
export const TIME_2100_01_01: 4102444800000;
|
package/dist/util/time/index.js
CHANGED
@@ -28,24 +28,16 @@
|
|
28
28
|
* }).format(d);
|
29
29
|
*/
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
import {
|
32
|
+
SECOND_MS,
|
33
|
+
MINUTE_MS,
|
34
|
+
HOUR_MS,
|
35
|
+
DAY_MS,
|
36
|
+
TIME_2025_01_01 } from '../../constants/time.js';
|
37
|
+
|
38
|
+
import * as expect from '../expect';
|
34
39
|
import { HkPromise } from '../../classes/promise/index.js';
|
35
40
|
|
36
|
-
/* ---------------------------------------------------------------- Internals */
|
37
|
-
|
38
|
-
/* ------------------------------------------------------------------ Exports */
|
39
|
-
|
40
|
-
export const SECOND_MS = 1000;
|
41
|
-
export const MINUTE_MS = 60 * SECOND_MS;
|
42
|
-
export const HOUR_MS = 60 * MINUTE_MS;
|
43
|
-
export const DAY_MS = 24 * HOUR_MS;
|
44
|
-
export const WEEK_MS = 7 * DAY_MS;
|
45
|
-
|
46
|
-
export const TIME_2020_01_01 = 1577836800000; // 2020-01-01T00:00:00.000Z
|
47
|
-
export const TIME_2100_01_01 = 4102444800000; // 2100-01-01T00:00:00.000Z
|
48
|
-
|
49
41
|
/**
|
50
42
|
* Returns a promise that resolves after a specified timeout
|
51
43
|
* - If the returned promise is rejected, the timeout is cancelled
|
@@ -92,22 +84,18 @@ export function delay(delayOrMinDelayMs, maxDelayMs) {
|
|
92
84
|
return promise;
|
93
85
|
}
|
94
86
|
|
95
|
-
// -----------------------------------------------------------------------------
|
96
|
-
|
97
87
|
/**
|
98
88
|
* Get the number of milliseconds since the specified time stamp of the default
|
99
|
-
* reference time stamp
|
89
|
+
* reference time stamp TIME_2025_01_01
|
100
90
|
*
|
101
|
-
* @param {number} [sinceMs=
|
91
|
+
* @param {number} [sinceMs=TIME_2025_01_01]
|
102
92
|
*
|
103
93
|
* @returns {number} number of milliseconds since the specified time
|
104
94
|
*/
|
105
|
-
export function sinceMs(sinceMs =
|
95
|
+
export function sinceMs(sinceMs = TIME_2025_01_01) {
|
106
96
|
return Date.now() - sinceMs;
|
107
97
|
}
|
108
98
|
|
109
|
-
// -----------------------------------------------------------------------------
|
110
|
-
|
111
99
|
/**
|
112
100
|
* Get a string that represents the time in a readable
|
113
101
|
* string format: [DD:][HH:]MM:SS.mmm
|
@@ -149,8 +137,6 @@ export function timeToString(timeMs) {
|
|
149
137
|
return str;
|
150
138
|
}
|
151
139
|
|
152
|
-
// -----------------------------------------------------------------------------
|
153
|
-
|
154
140
|
/**
|
155
141
|
* Returns a Date object
|
156
142
|
* - The input can be a Date object or a numeric timestamp
|
@@ -171,8 +157,6 @@ export function toDate(dateOrTimestamp) {
|
|
171
157
|
throw new Error('Missing or invalid parameter [dateOrTimestamp]');
|
172
158
|
}
|
173
159
|
|
174
|
-
// -----------------------------------------------------------------------------
|
175
|
-
|
176
160
|
/**
|
177
161
|
* Get the ISO 8601 week number of the specified date
|
178
162
|
*
|
@@ -228,8 +212,6 @@ export function getWeekNumber(dateOrTimestamp) {
|
|
228
212
|
return 1 + Math.ceil((firstThursday - target) / 604800000);
|
229
213
|
}
|
230
214
|
|
231
|
-
// -----------------------------------------------------------------------------
|
232
|
-
|
233
215
|
/**
|
234
216
|
* Get the name of the month
|
235
217
|
* - Returns the English name of the month
|
@@ -255,8 +237,6 @@ export function getMonthName(dateOrTimestamp) {
|
|
255
237
|
// return MONTH_NAME_LABELS_EN[toDate(dateOrTimestamp).getMonth()];
|
256
238
|
}
|
257
239
|
|
258
|
-
// -----------------------------------------------------------------------------
|
259
|
-
|
260
240
|
/**
|
261
241
|
* Get the name of the day
|
262
242
|
* - Returns the English name of the day
|
@@ -282,8 +262,6 @@ export function getDayName(dateOrTimestamp) {
|
|
282
262
|
// return DAY_NAME_LABELS_EN[toDate(dateOrTimestamp).getDay()];
|
283
263
|
}
|
284
264
|
|
285
|
-
// -----------------------------------------------------------------------------
|
286
|
-
|
287
265
|
/**
|
288
266
|
* Return the timestamp of the start of the day
|
289
267
|
* - Midnight
|
@@ -310,8 +288,6 @@ export function getTimeAtStartOfDay(dateOrTimestamp) {
|
|
310
288
|
return d.getTime();
|
311
289
|
}
|
312
290
|
|
313
|
-
// -----------------------------------------------------------------------------
|
314
|
-
|
315
291
|
/**
|
316
292
|
* Return the timestamp of the end of the day
|
317
293
|
* - Midnight - 1 millisecond
|
@@ -0,0 +1,81 @@
|
|
1
|
+
/**
|
2
|
+
* Returns a three character prefix that is calculated at boot
|
3
|
+
*
|
4
|
+
* @returns {string} boot time prefix
|
5
|
+
*/
|
6
|
+
export function bootTimePrefix(): string;
|
7
|
+
/**
|
8
|
+
* Create a string that contains random characters from the base58 alphabet
|
9
|
+
*
|
10
|
+
* @param {number} [length=48]
|
11
|
+
*
|
12
|
+
* @returns {string} a base 58 encoded random string
|
13
|
+
*/
|
14
|
+
export function randomStringBase58(length?: number): string;
|
15
|
+
/**
|
16
|
+
* Create a string that contains random characters from a for human's not
|
17
|
+
* ambiguous alphabet
|
18
|
+
*
|
19
|
+
* @param {number} [length=48]
|
20
|
+
*
|
21
|
+
* @returns {string} a human friendly encoded random string
|
22
|
+
*/
|
23
|
+
export function randomStringBaseHuman(length?: number): string;
|
24
|
+
/**
|
25
|
+
* Create a string that contains random characters from the specified alphabet
|
26
|
+
*
|
27
|
+
* @param {number} [length=48]
|
28
|
+
* @param {string} [ALPHABET=ALPHABET_BASE_58]
|
29
|
+
*
|
30
|
+
* @returns {string} a base 58 encoded random string
|
31
|
+
*/
|
32
|
+
export function randomString(length?: number, ALPHABET?: string): string;
|
33
|
+
/**
|
34
|
+
* Create an access code: a string that contains 48 random characters from the
|
35
|
+
* base58 alphabet
|
36
|
+
*
|
37
|
+
* @returns {string} a base 58 encoded random string of length 48
|
38
|
+
*/
|
39
|
+
export function randomAccessCode(): string;
|
40
|
+
/**
|
41
|
+
* Generate client session id
|
42
|
+
*
|
43
|
+
* @returns {string} a base 58 encoded random string of length 48
|
44
|
+
*/
|
45
|
+
export function generateClientSessionId(): string;
|
46
|
+
/**
|
47
|
+
* Generates and returns a new unique local id
|
48
|
+
* - The generated id is garanteed to be unique on the currently running
|
49
|
+
* local system
|
50
|
+
*
|
51
|
+
* @param {number} [timeMs]
|
52
|
+
* Custom time value to be used instead of Date.now()
|
53
|
+
*
|
54
|
+
* @returns {string} local id
|
55
|
+
*/
|
56
|
+
export function generateLocalId(timeMs?: number): string;
|
57
|
+
/**
|
58
|
+
* Returns a time based number that changes every 30 seconds
|
59
|
+
*
|
60
|
+
* @param {number} [timeMs=sinceMs()]
|
61
|
+
* Custom time value to be used instead of sinceMs()
|
62
|
+
*
|
63
|
+
* @returns {number} time based numerical that changes every 30 seconds
|
64
|
+
*/
|
65
|
+
export function getTimeBasedNumber30s(timeMs?: number): number;
|
66
|
+
/**
|
67
|
+
* Returns two character base58 encoded string that changes every 10
|
68
|
+
* milliseconds
|
69
|
+
*
|
70
|
+
* - The function output changes every 9 milliseconds
|
71
|
+
* - Returns a two character string
|
72
|
+
* - The string is base58 encoded
|
73
|
+
* - After 58 * 58 * 10ms = 33,6 seconds, the function output repeats
|
74
|
+
*
|
75
|
+
* @param {number} [timeMs]
|
76
|
+
* Custom time value to be used instead of Date.now()
|
77
|
+
*
|
78
|
+
* @returns {string} time based value
|
79
|
+
*/
|
80
|
+
export function getTwoChar10ms(timeMs?: number): string;
|
81
|
+
export const BOOT_STAMP: string;
|
@@ -0,0 +1,249 @@
|
|
1
|
+
/**
|
2
|
+
* unique.js
|
3
|
+
*
|
4
|
+
* @description
|
5
|
+
* This file contains functionality to generate unique data
|
6
|
+
*
|
7
|
+
* @example
|
8
|
+
*
|
9
|
+
* import { generateLocalId } from './unqiue.js';
|
10
|
+
*
|
11
|
+
* async function test()
|
12
|
+
* {
|
13
|
+
* console.log( `Id 1 [${generateLocalId()}]` );
|
14
|
+
* console.log( `Id 2 [${generateLocalId()}]` );
|
15
|
+
* }
|
16
|
+
*/
|
17
|
+
|
18
|
+
/* ------------------------------------------------------------------ Imports */
|
19
|
+
|
20
|
+
import { ALPHABET_BASE_HUMAN, ALPHABET_BASE_58 } from '../../constants/bases.js';
|
21
|
+
|
22
|
+
import { base58fromNumber } from '../bases';
|
23
|
+
|
24
|
+
import { TIME_2025_01_01 } from '../../constants/time';
|
25
|
+
|
26
|
+
import { sinceMs } from '../time';
|
27
|
+
|
28
|
+
/**
|
29
|
+
* @type {{
|
30
|
+
* bootTimePrefix?:string,
|
31
|
+
* lastTimeBasedNumber?: number,
|
32
|
+
* lastTimeBasedValue58?: string,
|
33
|
+
* lastCountBasedNumber?: number
|
34
|
+
* }}
|
35
|
+
*/
|
36
|
+
var vars = {}; /* @note use 'var declaration' for hoisting */
|
37
|
+
|
38
|
+
export const BOOT_STAMP = ( Date.now() - TIME_2025_01_01 ).toString(36);
|
39
|
+
|
40
|
+
/* ------------------------------------------------------------------ Exports */
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Returns a three character prefix that is calculated at boot
|
44
|
+
*
|
45
|
+
* @returns {string} boot time prefix
|
46
|
+
*/
|
47
|
+
export function bootTimePrefix()
|
48
|
+
{
|
49
|
+
if( !vars.bootTimePrefix )
|
50
|
+
{
|
51
|
+
vars.bootTimePrefix = '3' + getTwoChar10ms();
|
52
|
+
}
|
53
|
+
|
54
|
+
return vars.bootTimePrefix;
|
55
|
+
}
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Create a string that contains random characters from the base58 alphabet
|
59
|
+
*
|
60
|
+
* @param {number} [length=48]
|
61
|
+
*
|
62
|
+
* @returns {string} a base 58 encoded random string
|
63
|
+
*/
|
64
|
+
export function randomStringBase58( length=48 )
|
65
|
+
{
|
66
|
+
return randomString( length, ALPHABET_BASE_58 );
|
67
|
+
}
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Create a string that contains random characters from a for human's not
|
71
|
+
* ambiguous alphabet
|
72
|
+
*
|
73
|
+
* @param {number} [length=48]
|
74
|
+
*
|
75
|
+
* @returns {string} a human friendly encoded random string
|
76
|
+
*/
|
77
|
+
export function randomStringBaseHuman( length=48 )
|
78
|
+
{
|
79
|
+
return randomString( length, ALPHABET_BASE_HUMAN );
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Create a string that contains random characters from the specified alphabet
|
84
|
+
*
|
85
|
+
* @param {number} [length=48]
|
86
|
+
* @param {string} [ALPHABET=ALPHABET_BASE_58]
|
87
|
+
*
|
88
|
+
* @returns {string} a base 58 encoded random string
|
89
|
+
*/
|
90
|
+
export function randomString( length=48, ALPHABET=ALPHABET_BASE_58 )
|
91
|
+
{
|
92
|
+
if( typeof length !== 'number' || length < 1 )
|
93
|
+
{
|
94
|
+
throw new Error('Invalid parameter [length]');
|
95
|
+
}
|
96
|
+
|
97
|
+
if( typeof ALPHABET !== 'string' || !ALPHABET.length )
|
98
|
+
{
|
99
|
+
throw new Error('Invalid parameter [ALPHABET]');
|
100
|
+
}
|
101
|
+
|
102
|
+
let str = '';
|
103
|
+
|
104
|
+
const n = ALPHABET.length;
|
105
|
+
|
106
|
+
for( let j = length; j > 0; j = j - 1 )
|
107
|
+
{
|
108
|
+
const num = n * Math.random() & -1; // number [0...n-1]
|
109
|
+
str += ALPHABET[ num ];
|
110
|
+
}
|
111
|
+
|
112
|
+
return str;
|
113
|
+
}
|
114
|
+
|
115
|
+
/**
|
116
|
+
* Create an access code: a string that contains 48 random characters from the
|
117
|
+
* base58 alphabet
|
118
|
+
*
|
119
|
+
* @returns {string} a base 58 encoded random string of length 48
|
120
|
+
*/
|
121
|
+
export function randomAccessCode()
|
122
|
+
{
|
123
|
+
return randomStringBase58( 48 );
|
124
|
+
}
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Generate client session id
|
128
|
+
*
|
129
|
+
* @returns {string} a base 58 encoded random string of length 48
|
130
|
+
*/
|
131
|
+
export function generateClientSessionId()
|
132
|
+
{
|
133
|
+
return randomStringBase58( 48 );
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Generates and returns a new unique local id
|
138
|
+
* - The generated id is garanteed to be unique on the currently running
|
139
|
+
* local system
|
140
|
+
*
|
141
|
+
* @param {number} [timeMs]
|
142
|
+
* Custom time value to be used instead of Date.now()
|
143
|
+
*
|
144
|
+
* @returns {string} local id
|
145
|
+
*/
|
146
|
+
export function generateLocalId( timeMs )
|
147
|
+
{
|
148
|
+
const timeBasedNumber = getTimeBasedNumber30s( timeMs );
|
149
|
+
|
150
|
+
let timeBasedValue58;
|
151
|
+
|
152
|
+
let countBasedNumber;
|
153
|
+
|
154
|
+
if( vars.lastTimeBasedNumber !== timeBasedNumber )
|
155
|
+
{
|
156
|
+
// -- Time stamp based number changed -> reset counter to zero
|
157
|
+
|
158
|
+
countBasedNumber =
|
159
|
+
vars.lastCountBasedNumber = 0;
|
160
|
+
|
161
|
+
// -- Calculate timeBasedValue58 and update cache
|
162
|
+
|
163
|
+
vars.lastTimeBasedNumber = timeBasedNumber;
|
164
|
+
|
165
|
+
// cache string representation
|
166
|
+
timeBasedValue58 =
|
167
|
+
vars.lastTimeBasedValue58 = base58fromNumber( timeBasedNumber );
|
168
|
+
}
|
169
|
+
else {
|
170
|
+
// -- Same time stamp based number -> increment counter
|
171
|
+
|
172
|
+
countBasedNumber =
|
173
|
+
vars.lastCountBasedNumber = vars.lastCountBasedNumber + 1;
|
174
|
+
|
175
|
+
// -- Use cached lastTimeBasedNumber
|
176
|
+
|
177
|
+
timeBasedValue58 = vars.lastTimeBasedValue58;
|
178
|
+
}
|
179
|
+
|
180
|
+
const countBasedValue58 = base58fromNumber( countBasedNumber );
|
181
|
+
|
182
|
+
// Combine parts into single identifier string
|
183
|
+
//
|
184
|
+
// @note ALPHABET_BASE_58 is used because it is faster than
|
185
|
+
// base58fromNumber for single character encoding
|
186
|
+
//
|
187
|
+
const id =
|
188
|
+
// idFormatPrefix
|
189
|
+
bootTimePrefix() +
|
190
|
+
ALPHABET_BASE_58[ timeBasedValue58.length ] +
|
191
|
+
timeBasedValue58 +
|
192
|
+
countBasedValue58;
|
193
|
+
|
194
|
+
// std.debug( id );
|
195
|
+
|
196
|
+
return id;
|
197
|
+
}
|
198
|
+
|
199
|
+
|
200
|
+
/**
|
201
|
+
* Returns a time based number that changes every 30 seconds
|
202
|
+
*
|
203
|
+
* @param {number} [timeMs=sinceMs()]
|
204
|
+
* Custom time value to be used instead of sinceMs()
|
205
|
+
*
|
206
|
+
* @returns {number} time based numerical that changes every 30 seconds
|
207
|
+
*/
|
208
|
+
export function getTimeBasedNumber30s( timeMs )
|
209
|
+
{
|
210
|
+
if( !timeMs )
|
211
|
+
{
|
212
|
+
timeMs = sinceMs();
|
213
|
+
}
|
214
|
+
|
215
|
+
// @note do not use bitwise shift since it only works on 32 bit numbers!
|
216
|
+
return Math.floor( timeMs / 30000 );
|
217
|
+
}
|
218
|
+
|
219
|
+
|
220
|
+
/**
|
221
|
+
* Returns two character base58 encoded string that changes every 10
|
222
|
+
* milliseconds
|
223
|
+
*
|
224
|
+
* - The function output changes every 9 milliseconds
|
225
|
+
* - Returns a two character string
|
226
|
+
* - The string is base58 encoded
|
227
|
+
* - After 58 * 58 * 10ms = 33,6 seconds, the function output repeats
|
228
|
+
*
|
229
|
+
* @param {number} [timeMs]
|
230
|
+
* Custom time value to be used instead of Date.now()
|
231
|
+
*
|
232
|
+
* @returns {string} time based value
|
233
|
+
*/
|
234
|
+
export function getTwoChar10ms( timeMs )
|
235
|
+
{
|
236
|
+
const now = timeMs || Date.now();
|
237
|
+
|
238
|
+
// @note
|
239
|
+
// do not use bitwise shift since it only works on 32 bit numbers
|
240
|
+
const num = Math.floor( now / 10 ) % 3364;
|
241
|
+
|
242
|
+
if( num >= 58 )
|
243
|
+
{
|
244
|
+
return base58fromNumber( num );
|
245
|
+
}
|
246
|
+
else {
|
247
|
+
return '1' + base58fromNumber( num );
|
248
|
+
}
|
249
|
+
}
|