uuid-cbr 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -15
- package/index.d.ts +55 -0
- package/index.js +155 -81
- package/index.mjs +17 -0
- package/package.json +41 -18
- package/test.js +0 -21
package/README.md
CHANGED
|
@@ -1,33 +1,160 @@
|
|
|
1
1
|
# UUID-CBR
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Генератор уникальных идентификаторов (УИд) по требованиям Банка России (Указание 5251-У, Положение 758-П)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Реализация алгоритма формирования УИд на основе UUID v1 с контрольным символом, полностью соответствующая официальному примеру ЦБ на C.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### Установка
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install uuid-cbr
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Форматы модуля
|
|
14
|
+
|
|
15
|
+
Пакет публикуется сразу в двух вариантах:
|
|
16
|
+
|
|
17
|
+
- `require("uuid-cbr")` для CommonJS
|
|
18
|
+
- `import { generate } from "uuid-cbr"` для ESM
|
|
19
|
+
- встроенные декларации `index.d.ts` для TypeScript
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
const { generate } = require("uuid-cbr");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
import { generate } from "uuid-cbr";
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### API
|
|
30
|
+
|
|
31
|
+
#### `generate(datetime?)`
|
|
32
|
+
|
|
33
|
+
Формирует УИд — строку из 38 символов в формате `8-4-4-4-12-1`, где последний символ — контрольный.
|
|
8
34
|
|
|
9
35
|
```JavaScript
|
|
10
36
|
const { generate } = require("uuid-cbr");
|
|
11
|
-
const nowDatetime = new Date("2021-09-24T09:55:09.332Z")
|
|
12
|
-
const uuidByDate = generate(nowDatetime)
|
|
13
|
-
console.log(uuidByDate); // 80c57a90-1d1d-11ec-adda-26dbb65f1526-0
|
|
14
37
|
|
|
15
|
-
const
|
|
16
|
-
|
|
38
|
+
const uid = generate(new Date("2021-09-24T09:55:09.332Z"));
|
|
39
|
+
// 80c57a90-1d1d-11ec-adda-26dbb65f1526-0
|
|
40
|
+
|
|
41
|
+
const uidNow = generate();
|
|
42
|
+
// генерация для текущего момента
|
|
17
43
|
```
|
|
18
44
|
|
|
19
|
-
|
|
45
|
+
#### `isValid(uuid)`
|
|
46
|
+
|
|
47
|
+
Проверяет строку: формат UUID v1, variant-биты, контрольный символ.
|
|
20
48
|
|
|
21
49
|
```JavaScript
|
|
22
50
|
const { isValid } = require("uuid-cbr");
|
|
23
|
-
|
|
24
|
-
|
|
51
|
+
|
|
52
|
+
isValid("80c57a90-1d1d-11ec-adda-26dbb65f1526-0"); // true
|
|
53
|
+
isValid("not-a-uuid"); // false
|
|
25
54
|
```
|
|
26
55
|
|
|
27
|
-
|
|
56
|
+
#### `toDate(uuid)`
|
|
57
|
+
|
|
58
|
+
Извлекает дату из UUID-части идентификатора.
|
|
28
59
|
|
|
29
60
|
```JavaScript
|
|
30
61
|
const { toDate } = require("uuid-cbr");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
62
|
+
|
|
63
|
+
toDate("80c57a90-1d1d-11ec-adda-26dbb65f1526-0");
|
|
64
|
+
// 2021-09-24T09:55:09.332Z
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### `info(uuid)`
|
|
68
|
+
|
|
69
|
+
Метаданные идентификатора: длина, валидность, контрольный символ, clock sequence, дата.
|
|
70
|
+
|
|
71
|
+
```JavaScript
|
|
72
|
+
const { info } = require("uuid-cbr");
|
|
73
|
+
|
|
74
|
+
info("80c57a90-1d1d-11ec-adda-26dbb65f1526-0");
|
|
75
|
+
// { len: 38, valid: true, controlNum: '0', gClockSeq: ..., datetime: 2021-09-24T09:55:09.332Z }
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### `getTime(datetime?)`
|
|
79
|
+
|
|
80
|
+
Возвращает метку времени в 100-наносекундных интервалах (Number) — то же значение, которое кодируется в UUID.
|
|
81
|
+
|
|
82
|
+
```JavaScript
|
|
83
|
+
const { getTime } = require("uuid-cbr");
|
|
84
|
+
|
|
85
|
+
getTime(new Date("2021-09-24T09:55:09.332Z"));
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### `uid_init(options?)` / `uid_deinit()`
|
|
89
|
+
|
|
90
|
+
Lifecycle-управление генератором, аналог `uid_init` и `uid_deinit` из официального C-примера ЦБ.
|
|
91
|
+
|
|
92
|
+
```JavaScript
|
|
93
|
+
const { uid_init, uid_deinit, uid_create } = require("uuid-cbr");
|
|
94
|
+
|
|
95
|
+
uid_init({
|
|
96
|
+
node: [0x10, 0x20, 0x30, 0x40, 0x50, 0x60],
|
|
97
|
+
clockSeq: 0x1234,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const uid = uid_create(new Date("2021-09-24T09:55:09.332Z"));
|
|
101
|
+
uid_deinit();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`options`:
|
|
105
|
+
|
|
106
|
+
- `node` — 6 байт (Buffer, Array или hex-строка). По умолчанию — случайные.
|
|
107
|
+
- `clockSeq` — 13-битное значение clock sequence. По умолчанию — случайное.
|
|
108
|
+
|
|
109
|
+
#### `uid_create(datetime?)` / `uuid_create(datetime?)`
|
|
110
|
+
|
|
111
|
+
- `uid_create` — формирует УИд-строку (аналог `generate`).
|
|
112
|
+
- `uuid_create` — возвращает структуру полей UUID: `time_low`, `time_mid`, `time_hi_and_version`, `clock_seq_hi_and_reserved`, `clock_seq_low`, `node`.
|
|
113
|
+
|
|
114
|
+
`uuid_init` / `uuid_deinit` — алиасы для `uid_init` / `uid_deinit`.
|
|
115
|
+
|
|
116
|
+
### Тесты
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npm test
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Тесты запускаются через встроенный раннер Node.js `node:test` и покрывают поведение публичного API как unit-тесты.
|
|
123
|
+
|
|
124
|
+
### Сверка с официальным алгоритмом
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
npm run compare:official
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Скрипт собирает УИд при детерминированных входных данных и побайтово сравнивает результат с эталонной реализацией, эквивалентной официальному C-коду ЦБ.
|
|
131
|
+
|
|
132
|
+
### Проверка перед публикацией
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npm run verify:publish
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Эта команда последовательно выполняет:
|
|
139
|
+
|
|
140
|
+
- unit-тесты;
|
|
141
|
+
- сверку с официальным алгоритмом;
|
|
142
|
+
- `npm pack --dry-run`, чтобы проверить состав публикуемого пакета.
|
|
143
|
+
|
|
144
|
+
При `npm publish` эта проверка запускается автоматически через `prepublishOnly`.
|
|
145
|
+
|
|
146
|
+
### Что попадает в npm
|
|
147
|
+
|
|
148
|
+
В опубликованный пакет входят только файлы рантайма:
|
|
149
|
+
|
|
150
|
+
- `index.js`
|
|
151
|
+
- `index.mjs`
|
|
152
|
+
- `index.d.ts`
|
|
153
|
+
- `README.md`
|
|
154
|
+
|
|
155
|
+
Тесты, служебные скрипты, локальные временные файлы и официальный reference-архив остаются в репозитории, но не публикуются в npm.
|
|
156
|
+
|
|
157
|
+
### Официальные материалы
|
|
158
|
+
|
|
159
|
+
- [docs/official/README.md](docs/official/README.md) — описание сохранённых документов
|
|
160
|
+
- [docs/official/cbr-algorithm-findings.md](docs/official/cbr-algorithm-findings.md) — результаты сверки с официальным примером
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
|
|
3
|
+
export interface GeneratorOptions {
|
|
4
|
+
node?: Buffer | number[] | string;
|
|
5
|
+
clockSeq?: number;
|
|
6
|
+
lastTime?: bigint | number | string;
|
|
7
|
+
lastUSNS?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface UuidStruct {
|
|
11
|
+
time_low: number;
|
|
12
|
+
time_mid: number;
|
|
13
|
+
time_hi_and_version: number;
|
|
14
|
+
clock_seq_hi_and_reserved: number;
|
|
15
|
+
clock_seq_low: number;
|
|
16
|
+
node: number[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UidInfo {
|
|
20
|
+
len: number;
|
|
21
|
+
valid: boolean;
|
|
22
|
+
controlNum: string | undefined;
|
|
23
|
+
gClockSeq: number;
|
|
24
|
+
datetime: Date;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type DatetimeInput = Date | number | string;
|
|
28
|
+
|
|
29
|
+
export function generate(datetime?: DatetimeInput): string;
|
|
30
|
+
export function uid_init(options?: GeneratorOptions): boolean;
|
|
31
|
+
export function uid_deinit(): void;
|
|
32
|
+
export function uid_create(datetime?: DatetimeInput): string;
|
|
33
|
+
export function uuid_init(options?: GeneratorOptions): boolean;
|
|
34
|
+
export function uuid_deinit(): void;
|
|
35
|
+
export function uuid_create(datetime?: DatetimeInput): UuidStruct;
|
|
36
|
+
export function isValid(data: string): boolean;
|
|
37
|
+
export function getTime(datetime?: DatetimeInput): number;
|
|
38
|
+
export function toDate(uuid: string): Date;
|
|
39
|
+
export function info(uuid: string): UidInfo;
|
|
40
|
+
|
|
41
|
+
declare const api: {
|
|
42
|
+
generate: typeof generate;
|
|
43
|
+
uid_init: typeof uid_init;
|
|
44
|
+
uid_deinit: typeof uid_deinit;
|
|
45
|
+
uid_create: typeof uid_create;
|
|
46
|
+
uuid_init: typeof uuid_init;
|
|
47
|
+
uuid_deinit: typeof uuid_deinit;
|
|
48
|
+
uuid_create: typeof uuid_create;
|
|
49
|
+
isValid: typeof isValid;
|
|
50
|
+
getTime: typeof getTime;
|
|
51
|
+
toDate: typeof toDate;
|
|
52
|
+
info: typeof info;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default api;
|
package/index.js
CHANGED
|
@@ -1,32 +1,89 @@
|
|
|
1
1
|
const crypto = require("crypto");
|
|
2
|
-
const
|
|
2
|
+
const WIN_EPOCH_MS = BigInt(Date.UTC(1601, 0, 1));
|
|
3
|
+
const UUID_TIME_OFFSET = 5748192000000000n;
|
|
4
|
+
const HUNDRED_NS_PER_MS = 10000n;
|
|
3
5
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
+
const UUID_WITH_CHECKSUM_REGEX =
|
|
7
|
+
/^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})(?:-([0-9a-f]{1}))?$/i;
|
|
8
|
+
|
|
9
|
+
const formatHex = (value, length) => value.toString(16).padStart(length, "0");
|
|
10
|
+
|
|
11
|
+
const normalizeNode = (node) => {
|
|
12
|
+
if (Buffer.isBuffer(node)) {
|
|
13
|
+
return Buffer.from(node);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (Array.isArray(node)) {
|
|
17
|
+
return Buffer.from(node);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (typeof node === "string") {
|
|
21
|
+
return Buffer.from(node, "hex");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
throw new TypeError("Invalid node");
|
|
6
25
|
};
|
|
7
26
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
27
|
+
const createState = (options = {}) => {
|
|
28
|
+
const node =
|
|
29
|
+
options.node === undefined
|
|
30
|
+
? crypto.randomBytes(6)
|
|
31
|
+
: normalizeNode(options.node);
|
|
32
|
+
if (node.length !== 6) {
|
|
33
|
+
throw new RangeError("Node must be 6 bytes long");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
node[5] |= 0x01;
|
|
11
37
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
38
|
+
const clockSeq =
|
|
39
|
+
options.clockSeq === undefined
|
|
40
|
+
? crypto.randomBytes(2).readUInt16LE(0) & 0x1fff
|
|
41
|
+
: Number(options.clockSeq) & 0x1fff;
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
lastUSNS: options.lastUSNS === undefined ? 0 : Number(options.lastUSNS),
|
|
45
|
+
lastTime: options.lastTime === undefined ? 0n : BigInt(options.lastTime),
|
|
46
|
+
node,
|
|
47
|
+
nodeHex: Buffer.from(node).reverse().toString("hex"),
|
|
48
|
+
clockSeq,
|
|
49
|
+
clockSeqLow: clockSeq & 0xff,
|
|
50
|
+
clockSeqHiAndReserved: ((clockSeq & 0x3f00) >> 8) | 0x80,
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
let state = createState();
|
|
55
|
+
|
|
56
|
+
const ensureState = () => {
|
|
57
|
+
if (!state) {
|
|
58
|
+
state = createState();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return state;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const getTimestamp100ns = (datetime) => {
|
|
65
|
+
const currentState = ensureState();
|
|
66
|
+
const date = new Date(datetime);
|
|
67
|
+
if (Number.isNaN(date.getTime())) {
|
|
68
|
+
throw new TypeError("Invalid datetime");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const currentTime =
|
|
72
|
+
(BigInt(date.getTime()) - WIN_EPOCH_MS) * HUNDRED_NS_PER_MS +
|
|
73
|
+
UUID_TIME_OFFSET;
|
|
74
|
+
|
|
75
|
+
if (currentTime === currentState.lastTime) {
|
|
76
|
+
currentState.lastUSNS++;
|
|
22
77
|
} else {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// и запомним значение времени
|
|
26
|
-
gLastTime = time;
|
|
78
|
+
currentState.lastUSNS = 0;
|
|
79
|
+
currentState.lastTime = currentTime;
|
|
27
80
|
}
|
|
28
|
-
|
|
29
|
-
return
|
|
81
|
+
|
|
82
|
+
return currentTime + BigInt(currentState.lastUSNS);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const getTime = (datetime) => {
|
|
86
|
+
return Number(getTimestamp100ns(datetime));
|
|
30
87
|
};
|
|
31
88
|
|
|
32
89
|
const calcCtrl = (uuid) => {
|
|
@@ -34,114 +91,131 @@ const calcCtrl = (uuid) => {
|
|
|
34
91
|
let index = 1;
|
|
35
92
|
let sum = 0;
|
|
36
93
|
while (uuid[pos]) {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
94
|
+
const code = uuid.charCodeAt(pos++);
|
|
95
|
+
|
|
96
|
+
if (code >= 48 && code <= 57) {
|
|
97
|
+
sum += (code - 48) * index++;
|
|
98
|
+
} else {
|
|
99
|
+
const lowerCode = code | 32;
|
|
100
|
+
if (lowerCode >= 97 && lowerCode <= 102) {
|
|
101
|
+
sum += (lowerCode - 87) * index++;
|
|
102
|
+
}
|
|
42
103
|
}
|
|
43
104
|
|
|
44
|
-
// если символ - шестнадцатеричная цифра
|
|
45
|
-
if (/[a-f]/i.test(c)) {
|
|
46
|
-
sum += parseInt(c, 16) * index++;
|
|
47
|
-
}
|
|
48
105
|
// если значение индекса превысило 10, сбрасываем индекс в 1
|
|
49
106
|
if (index > 10) index = 1;
|
|
50
107
|
}
|
|
51
108
|
|
|
52
109
|
const r = sum % 16;
|
|
53
|
-
// возврат результата в виде контрольного символа
|
|
54
|
-
if (r < 10) {
|
|
55
|
-
return r;
|
|
56
|
-
}
|
|
57
110
|
return r.toString(16);
|
|
58
111
|
};
|
|
59
112
|
|
|
60
113
|
const isValid = (data) => {
|
|
61
|
-
|
|
114
|
+
if (typeof data !== "string") {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const res = data.match(
|
|
119
|
+
/^([0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})-([0-9a-f]{1})$/,
|
|
120
|
+
);
|
|
62
121
|
if (!res) return false;
|
|
63
122
|
const [, uuid, cs] = res;
|
|
64
123
|
if (!uuid && !cs) {
|
|
65
124
|
return false;
|
|
66
125
|
}
|
|
67
|
-
return calcCtrl(uuid)
|
|
126
|
+
return calcCtrl(uuid) === cs;
|
|
68
127
|
};
|
|
69
128
|
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
129
|
+
const uuid_create = (datetime = new Date()) => {
|
|
130
|
+
const currentState = ensureState();
|
|
131
|
+
const timeValue = getTimestamp100ns(datetime);
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
time_low: Number(timeValue & 0xffffffffn),
|
|
135
|
+
time_mid: Number((timeValue >> 32n) & 0xffffn),
|
|
136
|
+
time_hi_and_version: Number((timeValue >> 48n) & 0x0fffn) | (1 << 12),
|
|
137
|
+
clock_seq_hi_and_reserved: currentState.clockSeqHiAndReserved,
|
|
138
|
+
clock_seq_low: currentState.clockSeqLow,
|
|
139
|
+
node: Array.from(currentState.node),
|
|
140
|
+
};
|
|
74
141
|
};
|
|
75
142
|
|
|
76
|
-
const gClockSeq = Buffer.alloc(14, crypto.randomBytes(14).readUInt32BE(0, true).toString(2));
|
|
77
143
|
const generate = (datetime = new Date()) => {
|
|
78
|
-
const
|
|
144
|
+
const currentState = ensureState();
|
|
145
|
+
const uuid = uuid_create(datetime);
|
|
79
146
|
|
|
80
|
-
const
|
|
147
|
+
const result =
|
|
148
|
+
`${formatHex(uuid.time_low, 8)}-` +
|
|
149
|
+
`${formatHex(uuid.time_mid, 4)}-` +
|
|
150
|
+
`${formatHex(uuid.time_hi_and_version, 4)}-` +
|
|
151
|
+
`${formatHex(uuid.clock_seq_hi_and_reserved, 2)}${formatHex(uuid.clock_seq_low, 2)}-` +
|
|
152
|
+
currentState.nodeHex;
|
|
81
153
|
|
|
82
|
-
|
|
154
|
+
return result + "-" + calcCtrl(result);
|
|
155
|
+
};
|
|
83
156
|
|
|
84
|
-
|
|
85
|
-
const variant_clockseq_high = Buffer.from(gClockSeq.buffer, 0, 6);
|
|
157
|
+
const uid_create = (datetime = new Date()) => generate(datetime);
|
|
86
158
|
|
|
87
|
-
|
|
159
|
+
const uid_init = (options = {}) => {
|
|
160
|
+
state = createState(options);
|
|
161
|
+
return true;
|
|
162
|
+
};
|
|
88
163
|
|
|
89
|
-
|
|
164
|
+
const uid_deinit = () => {
|
|
165
|
+
state = null;
|
|
166
|
+
};
|
|
90
167
|
|
|
91
|
-
|
|
92
|
-
time_bin: buff + "",
|
|
93
|
-
time_low: time_low + "",
|
|
94
|
-
time_mid: (time_mid + "").padStart(16, "0"),
|
|
95
|
-
version_time_hide: "0001000" + version_time_hide,
|
|
96
|
-
clockseq_low: `10${variant_clockseq_high.toString("binary")}${clockseq_low.toString("binary")}`,
|
|
97
|
-
};
|
|
168
|
+
const uuid_init = (options = {}) => uid_init(options);
|
|
98
169
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
node[1] = crypto.randomBytes(4).readUInt32BE(0, true);
|
|
102
|
-
node[2] = crypto.randomBytes(4).readUInt32BE(0, true);
|
|
103
|
-
node[3] = crypto.randomBytes(4).readUInt32BE(0, true);
|
|
104
|
-
node[4] = crypto.randomBytes(4).readUInt32BE(0, true);
|
|
105
|
-
node[5] = crypto.randomBytes(4).readUInt32BE(0, true);
|
|
106
|
-
const result = [
|
|
107
|
-
bin2Hex(time.time_low).padStart(8, "0"),
|
|
108
|
-
bin2Hex(time.time_mid),
|
|
109
|
-
bin2Hex(time.version_time_hide),
|
|
110
|
-
bin2Hex(time.clockseq_low),
|
|
111
|
-
node.toString("hex"),
|
|
112
|
-
].join("-");
|
|
113
|
-
return result + "-" + calcCtrl(result);
|
|
170
|
+
const uuid_deinit = () => {
|
|
171
|
+
uid_deinit();
|
|
114
172
|
};
|
|
115
173
|
|
|
116
174
|
const toDate = (uuid) => {
|
|
117
|
-
|
|
175
|
+
if (typeof uuid !== "string") {
|
|
176
|
+
throw new TypeError("Invalid UUID");
|
|
177
|
+
}
|
|
118
178
|
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const bin_time_low = parseInt(time_low, 16).toString(2).padStart(32, "0");
|
|
179
|
+
const match = uuid.match(UUID_WITH_CHECKSUM_REGEX);
|
|
180
|
+
if (!match) {
|
|
181
|
+
throw new TypeError("Invalid UUID");
|
|
182
|
+
}
|
|
124
183
|
|
|
125
|
-
const
|
|
184
|
+
const [, timeLow, timeMid, timeHiAndVersion] = match;
|
|
185
|
+
const timestamp =
|
|
186
|
+
((BigInt(`0x${timeHiAndVersion}`) & 0x0fffn) << 48n) |
|
|
187
|
+
(BigInt(`0x${timeMid}`) << 32n) |
|
|
188
|
+
BigInt(`0x${timeLow}`);
|
|
189
|
+
const dateMs =
|
|
190
|
+
(timestamp - UUID_TIME_OFFSET) / HUNDRED_NS_PER_MS + WIN_EPOCH_MS;
|
|
126
191
|
|
|
127
|
-
|
|
128
|
-
return new Date(nSec / 10000 + winEpoch);
|
|
192
|
+
return new Date(Number(dateMs));
|
|
129
193
|
};
|
|
130
194
|
|
|
131
195
|
const info = (uuid) => {
|
|
196
|
+
if (typeof uuid !== "string") {
|
|
197
|
+
throw new TypeError("Invalid UUID");
|
|
198
|
+
}
|
|
199
|
+
|
|
132
200
|
const controlNum = uuid.split("-")[5];
|
|
133
201
|
|
|
134
202
|
return {
|
|
135
203
|
len: uuid.length,
|
|
136
204
|
valid: isValid(uuid),
|
|
137
205
|
controlNum,
|
|
138
|
-
gClockSeq:
|
|
206
|
+
gClockSeq: ensureState().clockSeq,
|
|
139
207
|
datetime: toDate(uuid),
|
|
140
208
|
};
|
|
141
209
|
};
|
|
142
210
|
|
|
143
211
|
module.exports = {
|
|
144
212
|
generate,
|
|
213
|
+
uid_init,
|
|
214
|
+
uid_deinit,
|
|
215
|
+
uid_create,
|
|
216
|
+
uuid_init,
|
|
217
|
+
uuid_deinit,
|
|
218
|
+
uuid_create,
|
|
145
219
|
isValid,
|
|
146
220
|
getTime,
|
|
147
221
|
toDate,
|
package/index.mjs
ADDED
package/package.json
CHANGED
|
@@ -1,18 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "uuid-cbr",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
5
|
-
"keywords": [
|
|
6
|
-
"uuid",
|
|
7
|
-
"ЦБ",
|
|
8
|
-
"cb",
|
|
9
|
-
"cbr"
|
|
10
|
-
],
|
|
11
|
-
"main": "index.js",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "uuid-cbr",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Генератор уникальных идентификаторов (УИд) по требованиям Банка России",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"uuid",
|
|
7
|
+
"ЦБ",
|
|
8
|
+
"cb",
|
|
9
|
+
"cbr"
|
|
10
|
+
],
|
|
11
|
+
"main": "index.js",
|
|
12
|
+
"module": "index.mjs",
|
|
13
|
+
"types": "index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./index.d.ts",
|
|
17
|
+
"import": "./index.mjs",
|
|
18
|
+
"require": "./index.js",
|
|
19
|
+
"default": "./index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"index.js",
|
|
24
|
+
"index.mjs",
|
|
25
|
+
"index.d.ts",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"author": "kdinisv",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/kdinisv/uuid-cbr"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "node --test test.js",
|
|
37
|
+
"compare:official": "node scripts/compare-official.js",
|
|
38
|
+
"verify:publish": "npm test && npm run compare:official && npm pack --dry-run",
|
|
39
|
+
"prepublishOnly": "npm run verify:publish"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/test.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const { generate, isValid, info, toDate } = require("./index.js");
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const nowDatetime = new Date("2021-09-24T09:55:09.332Z")
|
|
5
|
-
|
|
6
|
-
const uuid = generate(nowDatetime)
|
|
7
|
-
console.log(uuid)
|
|
8
|
-
|
|
9
|
-
const isValidUUID = isValid(uuid)
|
|
10
|
-
|
|
11
|
-
console.log(isValidUUID)
|
|
12
|
-
|
|
13
|
-
const infoUUID = info(uuid)
|
|
14
|
-
|
|
15
|
-
console.log(nowDatetime.toISOString(), infoUUID.datetime.toISOString())
|
|
16
|
-
console.assert(nowDatetime.toISOString() === infoUUID.datetime.toISOString())
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const datetime = toDate('80c57a90-1d1d-11ec-adda-26dbb65f1526-0')
|
|
20
|
-
|
|
21
|
-
console.log(datetime)
|