@peers-app/peers-sdk 0.15.3 → 0.15.5
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/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/keys.d.ts +52 -1
- package/dist/keys.js +47 -1
- package/dist/serial-json.d.ts +11 -0
- package/dist/serial-json.js +11 -0
- package/dist/utils.d.ts +50 -2
- package/dist/utils.js +49 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from "./context";
|
|
2
2
|
export * from "./data";
|
|
3
|
-
export { WorkflowLogs, getLogger, workflowLogSchema, type IWorkflowLog, } from "./data/workflow-logs";
|
|
4
3
|
export * as data from "./data";
|
|
5
4
|
export * from "./data/orm";
|
|
6
5
|
export * as orm from "./data/orm";
|
|
6
|
+
export { getLogger, type IWorkflowLog, WorkflowLogs, workflowLogSchema, } from "./data/workflow-logs";
|
|
7
7
|
export * from "./device/binary-peer-connection-v2";
|
|
8
8
|
export * from "./device/connection";
|
|
9
9
|
export * from "./device/device";
|
package/dist/index.js
CHANGED
|
@@ -14,17 +14,17 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.tools = exports.
|
|
17
|
+
exports.tools = exports.workflowLogSchema = exports.WorkflowLogs = exports.getLogger = exports.orm = exports.data = void 0;
|
|
18
18
|
__exportStar(require("./context"), exports);
|
|
19
19
|
__exportStar(require("./data"), exports);
|
|
20
|
+
exports.data = require("./data");
|
|
21
|
+
__exportStar(require("./data/orm"), exports);
|
|
22
|
+
exports.orm = require("./data/orm");
|
|
20
23
|
// Root `.d.ts` lists these explicitly so IDEs see them (not only via `export *`).
|
|
21
24
|
var workflow_logs_1 = require("./data/workflow-logs");
|
|
22
|
-
Object.defineProperty(exports, "WorkflowLogs", { enumerable: true, get: function () { return workflow_logs_1.WorkflowLogs; } });
|
|
23
25
|
Object.defineProperty(exports, "getLogger", { enumerable: true, get: function () { return workflow_logs_1.getLogger; } });
|
|
26
|
+
Object.defineProperty(exports, "WorkflowLogs", { enumerable: true, get: function () { return workflow_logs_1.WorkflowLogs; } });
|
|
24
27
|
Object.defineProperty(exports, "workflowLogSchema", { enumerable: true, get: function () { return workflow_logs_1.workflowLogSchema; } });
|
|
25
|
-
exports.data = require("./data");
|
|
26
|
-
__exportStar(require("./data/orm"), exports);
|
|
27
|
-
exports.orm = require("./data/orm");
|
|
28
28
|
__exportStar(require("./device/binary-peer-connection-v2"), exports);
|
|
29
29
|
__exportStar(require("./device/connection"), exports);
|
|
30
30
|
__exportStar(require("./device/device"), exports);
|
package/dist/keys.d.ts
CHANGED
|
@@ -1,52 +1,103 @@
|
|
|
1
|
+
/** Replaces tweetnacl’s default PRNG (required on some runtimes, e.g. tests or constrained environments). */
|
|
1
2
|
export declare function setPRNG(fn: (x: Uint8Array, n: number) => void): void;
|
|
3
|
+
/** SHA-256 of UTF-8 `str`, returned as base64url (no padding). */
|
|
2
4
|
export declare function hashValue(str: string): string;
|
|
5
|
+
/** SHA-256 of raw bytes, returned as base64url (no padding). */
|
|
3
6
|
export declare function hashBytes(buffer: Uint8Array): string;
|
|
7
|
+
/** Deterministic JSON string via `fast-json-stable-stringify` (key order stable). */
|
|
4
8
|
export declare function stableStringify(obj: any): string;
|
|
9
|
+
/** {@link hashValue} of the stable JSON for `obj` (for content-addressing object payloads). */
|
|
5
10
|
export declare function hashObject(obj: {
|
|
6
11
|
[key: string]: any;
|
|
7
12
|
}): string;
|
|
13
|
+
/** Base64 with URL-safe alphabet and no `=` padding (used throughout keys and wire formats). */
|
|
8
14
|
export declare function encodeBase64(data: Uint8Array): string;
|
|
15
|
+
/**
|
|
16
|
+
* Inverse of {@link encodeBase64}; accepts standard or URL-safe base64 and repads as needed.
|
|
17
|
+
* @throws TypeError if `data` is not a string
|
|
18
|
+
*/
|
|
9
19
|
export declare function decodeBase64(data: string): Uint8Array;
|
|
20
|
+
/** Random token as base64url string (`size` raw bytes, default 32). */
|
|
10
21
|
export declare function newToken(size?: number): string;
|
|
22
|
+
/** Ed25519 signing key and derived X25519 box public key, both base64url. */
|
|
11
23
|
export interface IPublicKeys {
|
|
12
24
|
publicKey: string;
|
|
13
25
|
publicBoxKey: string;
|
|
14
26
|
}
|
|
27
|
+
/** {@link IPublicKeys} plus Ed25519 secret key material (64-byte encoding as stored by this module). */
|
|
15
28
|
export interface IPublicPrivateKeys extends IPublicKeys {
|
|
16
29
|
secretKey: string;
|
|
17
30
|
}
|
|
31
|
+
/** Detached Ed25519 signature over JSON-serialized `contents` with signer’s public key. */
|
|
18
32
|
export interface ISignedObject<T> {
|
|
19
33
|
contents: T;
|
|
20
34
|
signature: string;
|
|
21
35
|
publicKey: string;
|
|
22
36
|
}
|
|
37
|
+
/** NaCl box ciphertext + nonce + sender box public key (all base64url). */
|
|
23
38
|
export interface IDataBox {
|
|
24
39
|
contents: string;
|
|
25
40
|
nonce: string;
|
|
26
41
|
fromPublicKey: string;
|
|
27
42
|
}
|
|
43
|
+
/** Generates a new Ed25519 keypair and derived X25519 box keys; all keys are base64url. */
|
|
28
44
|
export declare function newKeys(): IPublicPrivateKeys;
|
|
45
|
+
/** Re-derives public and box keys from an Ed25519 `secretKey` (same encoding as {@link newKeys}). */
|
|
29
46
|
export declare function hydrateKeys(secretKey: string): IPublicPrivateKeys;
|
|
47
|
+
/** Signs a UTF-8 message with Ed25519; returns base64url signed message (NaCl `sign` combined format). */
|
|
30
48
|
export declare function signMessageWithSecretKey(msg: string, secretKey: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Verifies and strips an Ed25519 signed message; returns the original UTF-8 string.
|
|
51
|
+
* @throws If verification fails
|
|
52
|
+
*/
|
|
31
53
|
export declare function openMessageWithPublicKey(msg: string, publicKey: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Detached sign over stable JSON: `undefined` / `null` are encoded with sentinel fields for round-trip.
|
|
56
|
+
* @returns Payload with original `contents`, `signature`, and signer's Ed25519 public key (32-byte slice, base64url)
|
|
57
|
+
*/
|
|
32
58
|
export declare function signObjectWithSecretKey<T>(obj: T, secretKey: string): ISignedObject<T>;
|
|
59
|
+
/**
|
|
60
|
+
* Verifies a detached signature and returns `contents` after undoing the undefined/null sentinels.
|
|
61
|
+
* @throws If the signature is invalid
|
|
62
|
+
*/
|
|
33
63
|
export declare function openSignedObject<T>(signedObj: ISignedObject<T>): T;
|
|
64
|
+
/**
|
|
65
|
+
* X25519 box encrypts `data` (msgpack via {@link txEncode}) to `toPublicBoxKey` from keys derived from `mySecretKey`.
|
|
66
|
+
* @param toPublicBoxKey Recipient’s X25519 public key (base64url)
|
|
67
|
+
*/
|
|
34
68
|
export declare function boxDataWithKeys(data: any, toPublicBoxKey: string, mySecretKey: string): IDataBox;
|
|
69
|
+
/** Narrowing guard: value looks like an {@link IDataBox} envelope. */
|
|
35
70
|
export declare function isBoxedData(data: any): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Decrypts a box from {@link boxDataWithKeys} using the recipient’s Ed25519 secret (same format as {@link newKeys}).
|
|
73
|
+
* @throws If decryption or authentication fails
|
|
74
|
+
*/
|
|
36
75
|
export declare function openBoxWithSecretKey(box: IDataBox, mySecretKey: string): any;
|
|
76
|
+
/** JSON-serializes `data` then NaCl `secretbox` with a random nonce; returns base64 payload `~` base64 nonce. */
|
|
37
77
|
export declare function encryptData<T>(data: T, secretKey: string): string;
|
|
78
|
+
/** Inverse of {@link encryptData}. Returns `null` if secretbox open fails. */
|
|
38
79
|
export declare function decryptData<T>(encryptedData: string, secretKey: string): T | null;
|
|
80
|
+
/** Object plus a `signature` field in the `publicKey:detachedSig` form produced by this module. */
|
|
39
81
|
export type IObjectWithSignature<T> = T & {
|
|
40
82
|
signature: string;
|
|
41
83
|
};
|
|
42
84
|
type IMaybeSignature = {
|
|
43
85
|
signature?: string;
|
|
44
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Strips any existing `signature`, signs a shallow copy of `obj`, and sets `signature` to `publicKey:detachedSig`.
|
|
89
|
+
* @returns Same shape as `obj` with string `signature` suitable for {@link verifyObjectSignature}
|
|
90
|
+
*/
|
|
45
91
|
export declare function addSignatureToObject<T extends Record<string, any>>(obj: T, secretKey: string): IObjectWithSignature<T>;
|
|
46
92
|
/**
|
|
47
|
-
*
|
|
93
|
+
* Ensures `signature` matches the rest of the object via {@link openSignedObject}.
|
|
94
|
+
* @throws If there is no signature or verification fails
|
|
48
95
|
*/
|
|
49
96
|
export declare function verifyObjectSignature<T extends IMaybeSignature>(objectWithSignature: T): void;
|
|
97
|
+
/** True if {@link verifyObjectSignature} would succeed. */
|
|
50
98
|
export declare function isObjectSignatureValid<T extends IMaybeSignature>(objectWithSignature: T): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Parses the Ed25519 public key prefix from a `publicKey:signature` field, or `undefined` if malformed.
|
|
101
|
+
*/
|
|
51
102
|
export declare function getPublicKeyFromObjectSignature<T extends IMaybeSignature>(objectWithSignature: T): string | undefined;
|
|
52
103
|
export {};
|
package/dist/keys.js
CHANGED
|
@@ -33,9 +33,11 @@ const tx_encoding_1 = require("./device/tx-encoding");
|
|
|
33
33
|
const serial_json_1 = require("./serial-json");
|
|
34
34
|
globalThis.Buffer = buffer_1.Buffer; // shim for browsers/RN
|
|
35
35
|
const _stableStringify = require("fast-json-stable-stringify");
|
|
36
|
+
/** Replaces tweetnacl’s default PRNG (required on some runtimes, e.g. tests or constrained environments). */
|
|
36
37
|
function setPRNG(fn) {
|
|
37
38
|
nacl.setPRNG(fn);
|
|
38
39
|
}
|
|
40
|
+
/** SHA-256 of UTF-8 `str`, returned as base64url (no padding). */
|
|
39
41
|
function hashValue(str) {
|
|
40
42
|
// const full = nacl.hash(decodeUTF8(str));
|
|
41
43
|
// const half = full.slice(0, 32);
|
|
@@ -43,23 +45,31 @@ function hashValue(str) {
|
|
|
43
45
|
const hash = (0, sha2_1.sha256)(new TextEncoder().encode(str));
|
|
44
46
|
return encodeBase64(hash);
|
|
45
47
|
}
|
|
48
|
+
/** SHA-256 of raw bytes, returned as base64url (no padding). */
|
|
46
49
|
function hashBytes(buffer) {
|
|
47
50
|
const hash = (0, sha2_1.sha256)(buffer);
|
|
48
51
|
return encodeBase64(hash);
|
|
49
52
|
}
|
|
53
|
+
/** Deterministic JSON string via `fast-json-stable-stringify` (key order stable). */
|
|
50
54
|
function stableStringify(obj) {
|
|
51
55
|
return _stableStringify(obj);
|
|
52
56
|
}
|
|
57
|
+
/** {@link hashValue} of the stable JSON for `obj` (for content-addressing object payloads). */
|
|
53
58
|
function hashObject(obj) {
|
|
54
59
|
const stableJson = stableStringify(obj);
|
|
55
60
|
const hash = hashValue(stableJson);
|
|
56
61
|
return hash;
|
|
57
62
|
}
|
|
63
|
+
/** Base64 with URL-safe alphabet and no `=` padding (used throughout keys and wire formats). */
|
|
58
64
|
function encodeBase64(data) {
|
|
59
65
|
// return Buffer.from(data).toString("base64url"); // no padding by default
|
|
60
66
|
const str = utils.encodeBase64(data);
|
|
61
67
|
return str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
62
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Inverse of {@link encodeBase64}; accepts standard or URL-safe base64 and repads as needed.
|
|
71
|
+
* @throws TypeError if `data` is not a string
|
|
72
|
+
*/
|
|
63
73
|
function decodeBase64(data) {
|
|
64
74
|
if (typeof data !== "string") {
|
|
65
75
|
throw new TypeError(`decodeBase64 expected a string but received ${typeof data}`);
|
|
@@ -70,9 +80,11 @@ function decodeBase64(data) {
|
|
|
70
80
|
}
|
|
71
81
|
return utils.decodeBase64(data);
|
|
72
82
|
}
|
|
83
|
+
/** Random token as base64url string (`size` raw bytes, default 32). */
|
|
73
84
|
function newToken(size = 32) {
|
|
74
85
|
return encodeBase64(nacl.randomBytes(size));
|
|
75
86
|
}
|
|
87
|
+
/** Generates a new Ed25519 keypair and derived X25519 box keys; all keys are base64url. */
|
|
76
88
|
function newKeys() {
|
|
77
89
|
const sign = nacl.sign.keyPair(); // Ed25519
|
|
78
90
|
const curveSecret = ed2curve.convertSecretKey(sign.secretKey); // 32 bytes
|
|
@@ -83,6 +95,7 @@ function newKeys() {
|
|
|
83
95
|
publicBoxKey: encodeBase64(box.publicKey),
|
|
84
96
|
};
|
|
85
97
|
}
|
|
98
|
+
/** Re-derives public and box keys from an Ed25519 `secretKey` (same encoding as {@link newKeys}). */
|
|
86
99
|
function hydrateKeys(secretKey) {
|
|
87
100
|
const sk64 = decodeBase64(secretKey); // Ed25519 64-byte secretKey
|
|
88
101
|
const curveSecret = ed2curve.convertSecretKey(sk64);
|
|
@@ -93,12 +106,17 @@ function hydrateKeys(secretKey) {
|
|
|
93
106
|
publicBoxKey: encodeBase64(box.publicKey),
|
|
94
107
|
};
|
|
95
108
|
}
|
|
109
|
+
/** Signs a UTF-8 message with Ed25519; returns base64url signed message (NaCl `sign` combined format). */
|
|
96
110
|
function signMessageWithSecretKey(msg, secretKey) {
|
|
97
111
|
const _secretKey = decodeBase64(secretKey);
|
|
98
112
|
const msgDecoded = (0, tweetnacl_util_1.decodeUTF8)(msg);
|
|
99
113
|
const msgSigned = nacl.sign(msgDecoded, _secretKey);
|
|
100
114
|
return encodeBase64(msgSigned);
|
|
101
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Verifies and strips an Ed25519 signed message; returns the original UTF-8 string.
|
|
118
|
+
* @throws If verification fails
|
|
119
|
+
*/
|
|
102
120
|
function openMessageWithPublicKey(msg, publicKey) {
|
|
103
121
|
const _publicKey = decodeBase64(publicKey);
|
|
104
122
|
const msgDecoded = decodeBase64(msg);
|
|
@@ -108,6 +126,10 @@ function openMessageWithPublicKey(msg, publicKey) {
|
|
|
108
126
|
}
|
|
109
127
|
return (0, tweetnacl_util_1.encodeUTF8)(msgOpened);
|
|
110
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Detached sign over stable JSON: `undefined` / `null` are encoded with sentinel fields for round-trip.
|
|
131
|
+
* @returns Payload with original `contents`, `signature`, and signer's Ed25519 public key (32-byte slice, base64url)
|
|
132
|
+
*/
|
|
111
133
|
function signObjectWithSecretKey(obj, secretKey) {
|
|
112
134
|
const _secretKey = decodeBase64(secretKey);
|
|
113
135
|
if (obj === undefined) {
|
|
@@ -125,6 +147,10 @@ function signObjectWithSecretKey(obj, secretKey) {
|
|
|
125
147
|
publicKey: encodeBase64(_secretKey.slice(32)),
|
|
126
148
|
};
|
|
127
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Verifies a detached signature and returns `contents` after undoing the undefined/null sentinels.
|
|
152
|
+
* @throws If the signature is invalid
|
|
153
|
+
*/
|
|
128
154
|
function openSignedObject(signedObj) {
|
|
129
155
|
const _publicKey = decodeBase64(signedObj.publicKey);
|
|
130
156
|
const objStr = (0, serial_json_1.toJSONString)(signedObj.contents);
|
|
@@ -145,6 +171,10 @@ function openSignedObject(signedObj) {
|
|
|
145
171
|
}
|
|
146
172
|
return signedObj.contents;
|
|
147
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* X25519 box encrypts `data` (msgpack via {@link txEncode}) to `toPublicBoxKey` from keys derived from `mySecretKey`.
|
|
176
|
+
* @param toPublicBoxKey Recipient’s X25519 public key (base64url)
|
|
177
|
+
*/
|
|
148
178
|
function boxDataWithKeys(data, toPublicBoxKey, mySecretKey) {
|
|
149
179
|
const _secretKey = decodeBase64(mySecretKey);
|
|
150
180
|
const curveSecret = ed2curve.convertSecretKey(_secretKey);
|
|
@@ -159,12 +189,17 @@ function boxDataWithKeys(data, toPublicBoxKey, mySecretKey) {
|
|
|
159
189
|
fromPublicKey: encodeBase64(boxKeyPair.publicKey),
|
|
160
190
|
};
|
|
161
191
|
}
|
|
192
|
+
/** Narrowing guard: value looks like an {@link IDataBox} envelope. */
|
|
162
193
|
function isBoxedData(data) {
|
|
163
194
|
return (typeof data === "object" &&
|
|
164
195
|
typeof data.contents === "string" &&
|
|
165
196
|
typeof data.nonce === "string" &&
|
|
166
197
|
typeof data.fromPublicKey === "string");
|
|
167
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Decrypts a box from {@link boxDataWithKeys} using the recipient’s Ed25519 secret (same format as {@link newKeys}).
|
|
201
|
+
* @throws If decryption or authentication fails
|
|
202
|
+
*/
|
|
168
203
|
function openBoxWithSecretKey(box, mySecretKey) {
|
|
169
204
|
const _secretKey = decodeBase64(mySecretKey);
|
|
170
205
|
const curveSecret = ed2curve.convertSecretKey(_secretKey);
|
|
@@ -196,14 +231,20 @@ function decryptString(data, secretKey) {
|
|
|
196
231
|
}
|
|
197
232
|
return (0, tweetnacl_util_1.encodeUTF8)(decryptedData);
|
|
198
233
|
}
|
|
234
|
+
/** JSON-serializes `data` then NaCl `secretbox` with a random nonce; returns base64 payload `~` base64 nonce. */
|
|
199
235
|
function encryptData(data, secretKey) {
|
|
200
236
|
const _data = (0, serial_json_1.toJSONString)(data);
|
|
201
237
|
return encryptString(_data, secretKey);
|
|
202
238
|
}
|
|
239
|
+
/** Inverse of {@link encryptData}. Returns `null` if secretbox open fails. */
|
|
203
240
|
function decryptData(encryptedData, secretKey) {
|
|
204
241
|
const _data = decryptString(encryptedData, secretKey);
|
|
205
242
|
return (0, serial_json_1.fromJSONString)(_data);
|
|
206
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Strips any existing `signature`, signs a shallow copy of `obj`, and sets `signature` to `publicKey:detachedSig`.
|
|
246
|
+
* @returns Same shape as `obj` with string `signature` suitable for {@link verifyObjectSignature}
|
|
247
|
+
*/
|
|
207
248
|
function addSignatureToObject(obj, secretKey) {
|
|
208
249
|
obj = { ...obj };
|
|
209
250
|
delete obj.signature;
|
|
@@ -212,7 +253,8 @@ function addSignatureToObject(obj, secretKey) {
|
|
|
212
253
|
return { ...obj, signature: objSignature };
|
|
213
254
|
}
|
|
214
255
|
/**
|
|
215
|
-
*
|
|
256
|
+
* Ensures `signature` matches the rest of the object via {@link openSignedObject}.
|
|
257
|
+
* @throws If there is no signature or verification fails
|
|
216
258
|
*/
|
|
217
259
|
function verifyObjectSignature(objectWithSignature) {
|
|
218
260
|
if (!objectWithSignature.signature) {
|
|
@@ -228,6 +270,7 @@ function verifyObjectSignature(objectWithSignature) {
|
|
|
228
270
|
};
|
|
229
271
|
openSignedObject(signedObject); // will throw if invalid
|
|
230
272
|
}
|
|
273
|
+
/** True if {@link verifyObjectSignature} would succeed. */
|
|
231
274
|
function isObjectSignatureValid(objectWithSignature) {
|
|
232
275
|
try {
|
|
233
276
|
verifyObjectSignature(objectWithSignature);
|
|
@@ -237,6 +280,9 @@ function isObjectSignatureValid(objectWithSignature) {
|
|
|
237
280
|
}
|
|
238
281
|
return true;
|
|
239
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Parses the Ed25519 public key prefix from a `publicKey:signature` field, or `undefined` if malformed.
|
|
285
|
+
*/
|
|
240
286
|
function getPublicKeyFromObjectSignature(objectWithSignature) {
|
|
241
287
|
const parts = objectWithSignature.signature?.split(":");
|
|
242
288
|
if (!parts || parts.length !== 2) {
|
package/dist/serial-json.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
/** True for plain object literals (excludes array, Date, and null). */
|
|
1
2
|
export declare function isObject(x: any): x is Record<string, any>;
|
|
3
|
+
/**
|
|
4
|
+
* Clones a value into a JSON-serializable tree: Dates, Buffers, cycles, `undefined`, `NaN`, RegExp, etc. use sentinel strings.
|
|
5
|
+
* Shared references are preserved with `__duplicate_ref_*` and `__this_ref` markers for {@link fromJSON}.
|
|
6
|
+
*/
|
|
2
7
|
export declare function toJSON(obj: any): any;
|
|
8
|
+
/**
|
|
9
|
+
* Reverses {@link toJSON}: restores special values, shared references, and keys escaped with `__DOLLAR_`.
|
|
10
|
+
* @param _externalReferences Reserved for future use (function revival, etc.)
|
|
11
|
+
*/
|
|
3
12
|
export declare function fromJSON(obj: any, _externalReferences?: any): any;
|
|
13
|
+
/** `JSON.stringify` of {@link toJSON} (stable, extended types). */
|
|
4
14
|
export declare function toJSONString(obj: any): string;
|
|
15
|
+
/** `JSON.parse` then {@link fromJSON}. */
|
|
5
16
|
export declare function fromJSONString(str: string): any;
|
package/dist/serial-json.js
CHANGED
|
@@ -6,9 +6,14 @@ exports.fromJSON = fromJSON;
|
|
|
6
6
|
exports.toJSONString = toJSONString;
|
|
7
7
|
exports.fromJSONString = fromJSONString;
|
|
8
8
|
const _ = require("lodash");
|
|
9
|
+
/** True for plain object literals (excludes array, Date, and null). */
|
|
9
10
|
function isObject(x) {
|
|
10
11
|
return _.isObject(x) && !_.isArray(x) && !_.isDate(x) && x !== null;
|
|
11
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Clones a value into a JSON-serializable tree: Dates, Buffers, cycles, `undefined`, `NaN`, RegExp, etc. use sentinel strings.
|
|
15
|
+
* Shared references are preserved with `__duplicate_ref_*` and `__this_ref` markers for {@link fromJSON}.
|
|
16
|
+
*/
|
|
12
17
|
function toJSON(obj) {
|
|
13
18
|
if (!_.isObject(obj)) {
|
|
14
19
|
return obj;
|
|
@@ -95,6 +100,10 @@ function toJSON(obj) {
|
|
|
95
100
|
obj = recurse(obj);
|
|
96
101
|
return obj;
|
|
97
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Reverses {@link toJSON}: restores special values, shared references, and keys escaped with `__DOLLAR_`.
|
|
105
|
+
* @param _externalReferences Reserved for future use (function revival, etc.)
|
|
106
|
+
*/
|
|
98
107
|
function fromJSON(obj, _externalReferences) {
|
|
99
108
|
var dup_refs = {};
|
|
100
109
|
function recurse(obj) {
|
|
@@ -185,9 +194,11 @@ function fromJSON(obj, _externalReferences) {
|
|
|
185
194
|
obj = recurse(obj);
|
|
186
195
|
return obj;
|
|
187
196
|
}
|
|
197
|
+
/** `JSON.stringify` of {@link toJSON} (stable, extended types). */
|
|
188
198
|
function toJSONString(obj) {
|
|
189
199
|
return JSON.stringify(toJSON(obj));
|
|
190
200
|
}
|
|
201
|
+
/** `JSON.parse` then {@link fromJSON}. */
|
|
191
202
|
function fromJSONString(str) {
|
|
192
203
|
return fromJSON(JSON.parse(str));
|
|
193
204
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,29 +1,76 @@
|
|
|
1
1
|
import type { ITableMetaData } from "./data/orm";
|
|
2
2
|
import { type IDeviceConnection } from "./types/peer-device";
|
|
3
|
+
/** Builds a random string of base-36 characters with unbiased distribution (tweetnacl-backed). */
|
|
3
4
|
export declare function cryptoRandomString(length: number): string;
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new 25-character peer id: base-36 time prefix (10 chars) + random suffix (15 chars).
|
|
7
|
+
* Sort order correlates with creation time. Use {@link isid} to validate user-provided values.
|
|
8
|
+
*/
|
|
4
9
|
export declare function newid(): string;
|
|
10
|
+
/** Lexicographic lower bound for valid peer ids (epoch). */
|
|
5
11
|
export declare const MIN_ID: string;
|
|
12
|
+
/** Lexicographic upper bound for valid peer ids (far future). */
|
|
6
13
|
export declare const MAX_ID: string;
|
|
14
|
+
/**
|
|
15
|
+
* Returns whether `id` is a 25-char base-36 string whose embedded time is not in the future (5 min skew allowed).
|
|
16
|
+
* @param id Candidate id (coerced to string)
|
|
17
|
+
*/
|
|
7
18
|
export declare function isid(id: any): boolean;
|
|
19
|
+
/** Returns the `Date.now()`-compatible millisecond time encoded in the first 10 base-36 characters of a peer id. */
|
|
8
20
|
export declare function idTime(id: string): number;
|
|
21
|
+
/** Interprets a peer id’s time prefix as a `Date` (see {@link idTime}). */
|
|
9
22
|
export declare function idDate(id: string): Date;
|
|
10
23
|
/**
|
|
11
|
-
*
|
|
24
|
+
* Returns the 15-character random suffix of a peer id as two base-36 integers so large values stay exact in JS.
|
|
25
|
+
* @param id A 25-character peer id from {@link newid}
|
|
12
26
|
*/
|
|
13
27
|
export declare function idRandNums(id: string): [number, number];
|
|
28
|
+
/** Fast non-cryptographic 32-bit string hash (sign-insensitive) for display keys and bucketing. */
|
|
14
29
|
export declare function simpleHash(str: string): number;
|
|
30
|
+
/** Like TypeScript’s `Partial` for specific keys: required keys in `K` become optional. */
|
|
15
31
|
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
32
|
+
/** `simpleHash` of JSON-stable stringification of an object. */
|
|
16
33
|
export declare function simpleObjectHash(obj: any): number;
|
|
34
|
+
/** Resolves after `ms` milliseconds (0 yields a microtask-yield on most runtimes). */
|
|
17
35
|
export declare function sleep(ms?: number): Promise<void>;
|
|
36
|
+
/** Turns `fooBar` into `Foo Bar` for labels (also replaces `_` with space). */
|
|
18
37
|
export declare function camelCaseToSpaces(s?: string): string;
|
|
38
|
+
/** Like {@link camelCaseToSpaces} but lowercased and joined with hyphens (kebab-case). */
|
|
19
39
|
export declare function camelCaseToHyphens(s?: string): string;
|
|
40
|
+
/** USD currency formatter with two fraction digits. */
|
|
20
41
|
export declare const moneyFormatter: Intl.NumberFormat;
|
|
42
|
+
/**
|
|
43
|
+
* Formats a number as USD. Uses {@link moneyFormatter} when `precision` is 2; otherwise builds a custom `Intl` formatter.
|
|
44
|
+
* @param value Amount in major currency units
|
|
45
|
+
* @param precision Decimal places (default 2)
|
|
46
|
+
*/
|
|
21
47
|
export declare function formatMoney(value: number, precision?: number): string;
|
|
48
|
+
/**
|
|
49
|
+
* Caches the in-flight `Promise` per serialized argument tuple. Re-invoking with the same args returns the same promise.
|
|
50
|
+
* When `cacheTtl` is set, the cache entry is removed after that many ms after completion.
|
|
51
|
+
*/
|
|
22
52
|
export declare function memoizePromise<F extends (...args: any[]) => Promise<any>>(fn: F, opts?: {
|
|
23
53
|
cacheTtl?: number;
|
|
24
54
|
}): F;
|
|
55
|
+
/**
|
|
56
|
+
* Debounces per distinct argument list: each unique `JSON.stringify(args)` gets its own debounced function (lodash debounce).
|
|
57
|
+
* @param wait Debounce wait in ms (default 300)
|
|
58
|
+
* @throws If the internal map is missing an entry (should not happen)
|
|
59
|
+
*/
|
|
25
60
|
export declare function debounceByArgs<F extends (...args: any[]) => any>(fn: F, wait?: number): F;
|
|
61
|
+
/**
|
|
62
|
+
* Monotonic-ish high-resolution time when `performance` exists; otherwise `Date.now()`.
|
|
63
|
+
* Uses `timeOrigin + now()` in browsers; suitable for relative timing, not wall-clock.
|
|
64
|
+
*/
|
|
26
65
|
export declare function getTimestamp(): number;
|
|
66
|
+
/**
|
|
67
|
+
* Runs `fn` with adaptive timeout from {@link IDeviceConnection.latencyMs}, retrying on error or until the op finishes.
|
|
68
|
+
* Updates `connection` latency and error rate from outcomes.
|
|
69
|
+
* @param opts.timeout Clamped timeout; defaults to {@link PeerDeviceConsts} min/max
|
|
70
|
+
* @param opts.retriesOnError Max error retries
|
|
71
|
+
* @param opts.retriesOnTimeout Max “timed out” races before giving up
|
|
72
|
+
* @throws Last error, timeout exhaustion, or if the connection is closed
|
|
73
|
+
*/
|
|
27
74
|
export declare function retryOnErrorOrTimeout<T>({ fn, connection, opts, }: {
|
|
28
75
|
fn: () => Promise<T>;
|
|
29
76
|
connection: IDeviceConnection;
|
|
@@ -34,6 +81,7 @@ export declare function retryOnErrorOrTimeout<T>({ fn, connection, opts, }: {
|
|
|
34
81
|
};
|
|
35
82
|
}): Promise<T>;
|
|
36
83
|
/**
|
|
37
|
-
*
|
|
84
|
+
* Physical table name: `"name_id"` when `tableId` is set, else `name`.
|
|
85
|
+
* @param metaData Table metadata from the ORM layer
|
|
38
86
|
*/
|
|
39
87
|
export declare function getFullTableName(metaData: ITableMetaData): string;
|
package/dist/utils.js
CHANGED
|
@@ -22,6 +22,7 @@ const _ = require("lodash");
|
|
|
22
22
|
const nacl = require("tweetnacl");
|
|
23
23
|
const peer_device_1 = require("./types/peer-device");
|
|
24
24
|
const stableStringify = require("fast-json-stable-stringify");
|
|
25
|
+
/** Builds a random string of base-36 characters with unbiased distribution (tweetnacl-backed). */
|
|
25
26
|
function cryptoRandomString(length) {
|
|
26
27
|
let s = "";
|
|
27
28
|
let r = nacl.randomBytes(length + 6);
|
|
@@ -42,6 +43,10 @@ function cryptoRandomString(length) {
|
|
|
42
43
|
}
|
|
43
44
|
return s.substring(0, length);
|
|
44
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new 25-character peer id: base-36 time prefix (10 chars) + random suffix (15 chars).
|
|
48
|
+
* Sort order correlates with creation time. Use {@link isid} to validate user-provided values.
|
|
49
|
+
*/
|
|
45
50
|
function newid() {
|
|
46
51
|
// modeled after mongo ids, timestamp + counter + random but we're going to skip counter and have bigger random
|
|
47
52
|
// people can switch to using a counter + random later if they want (or do something else with the random part).
|
|
@@ -64,8 +69,14 @@ function newid() {
|
|
|
64
69
|
const time = Date.now().toString(36).padStart(10, "0"); // e.g: "00kq6xh45f", length == 10
|
|
65
70
|
return time + cryptoRandomString(15);
|
|
66
71
|
}
|
|
72
|
+
/** Lexicographic lower bound for valid peer ids (epoch). */
|
|
67
73
|
exports.MIN_ID = "0".repeat(25); // 1970
|
|
74
|
+
/** Lexicographic upper bound for valid peer ids (far future). */
|
|
68
75
|
exports.MAX_ID = `f55n5nmuua${"z".repeat(15)}`; // 50k years from now
|
|
76
|
+
/**
|
|
77
|
+
* Returns whether `id` is a 25-char base-36 string whose embedded time is not in the future (5 min skew allowed).
|
|
78
|
+
* @param id Candidate id (coerced to string)
|
|
79
|
+
*/
|
|
69
80
|
function isid(id) {
|
|
70
81
|
id = String(id);
|
|
71
82
|
const idMatch = Boolean(/^[0-9a-z]{25}$/i.exec(id));
|
|
@@ -76,21 +87,25 @@ function isid(id) {
|
|
|
76
87
|
}
|
|
77
88
|
return false;
|
|
78
89
|
}
|
|
90
|
+
/** Returns the `Date.now()`-compatible millisecond time encoded in the first 10 base-36 characters of a peer id. */
|
|
79
91
|
function idTime(id) {
|
|
80
92
|
const time36 = id.substr(0, 10);
|
|
81
93
|
return Number.parseInt(time36, 36);
|
|
82
94
|
}
|
|
95
|
+
/** Interprets a peer id’s time prefix as a `Date` (see {@link idTime}). */
|
|
83
96
|
function idDate(id) {
|
|
84
97
|
return new Date(idTime(id));
|
|
85
98
|
}
|
|
86
99
|
/**
|
|
87
|
-
*
|
|
100
|
+
* Returns the 15-character random suffix of a peer id as two base-36 integers so large values stay exact in JS.
|
|
101
|
+
* @param id A 25-character peer id from {@link newid}
|
|
88
102
|
*/
|
|
89
103
|
function idRandNums(id) {
|
|
90
104
|
const numPart1 = id.substr(10, 8);
|
|
91
105
|
const numPart2 = id.substr(18, 7);
|
|
92
106
|
return [Number.parseInt(numPart1, 36), Number.parseInt(numPart2, 36)];
|
|
93
107
|
}
|
|
108
|
+
/** Fast non-cryptographic 32-bit string hash (sign-insensitive) for display keys and bucketing. */
|
|
94
109
|
function simpleHash(str) {
|
|
95
110
|
let hash = 0;
|
|
96
111
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -100,12 +115,15 @@ function simpleHash(str) {
|
|
|
100
115
|
}
|
|
101
116
|
return Math.abs(hash);
|
|
102
117
|
}
|
|
118
|
+
/** `simpleHash` of JSON-stable stringification of an object. */
|
|
103
119
|
function simpleObjectHash(obj) {
|
|
104
120
|
return simpleHash(stableStringify(obj));
|
|
105
121
|
}
|
|
122
|
+
/** Resolves after `ms` milliseconds (0 yields a microtask-yield on most runtimes). */
|
|
106
123
|
function sleep(ms = 0) {
|
|
107
124
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
108
125
|
}
|
|
126
|
+
/** Turns `fooBar` into `Foo Bar` for labels (also replaces `_` with space). */
|
|
109
127
|
function camelCaseToSpaces(s = "") {
|
|
110
128
|
s = s.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
111
129
|
// s = s.replace(/(GL)([A-Z])/g, '$1 $2'); // anything like GLAccounts, GLBatches, etc.
|
|
@@ -113,16 +131,23 @@ function camelCaseToSpaces(s = "") {
|
|
|
113
131
|
s = s[0]?.toUpperCase() + s.substr(1);
|
|
114
132
|
return s;
|
|
115
133
|
}
|
|
134
|
+
/** Like {@link camelCaseToSpaces} but lowercased and joined with hyphens (kebab-case). */
|
|
116
135
|
function camelCaseToHyphens(s = "") {
|
|
117
136
|
s = camelCaseToSpaces(s);
|
|
118
137
|
return s.split(" ").join("-").toLowerCase();
|
|
119
138
|
}
|
|
139
|
+
/** USD currency formatter with two fraction digits. */
|
|
120
140
|
exports.moneyFormatter = new Intl.NumberFormat("en-US", {
|
|
121
141
|
style: "currency",
|
|
122
142
|
currency: "USD",
|
|
123
143
|
minimumFractionDigits: 2,
|
|
124
144
|
maximumFractionDigits: 2,
|
|
125
145
|
});
|
|
146
|
+
/**
|
|
147
|
+
* Formats a number as USD. Uses {@link moneyFormatter} when `precision` is 2; otherwise builds a custom `Intl` formatter.
|
|
148
|
+
* @param value Amount in major currency units
|
|
149
|
+
* @param precision Decimal places (default 2)
|
|
150
|
+
*/
|
|
126
151
|
function formatMoney(value, precision = 2) {
|
|
127
152
|
if (precision === 2) {
|
|
128
153
|
return exports.moneyFormatter.format(value);
|
|
@@ -135,6 +160,10 @@ function formatMoney(value, precision = 2) {
|
|
|
135
160
|
});
|
|
136
161
|
return _moneyFormatter.format(value);
|
|
137
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Caches the in-flight `Promise` per serialized argument tuple. Re-invoking with the same args returns the same promise.
|
|
165
|
+
* When `cacheTtl` is set, the cache entry is removed after that many ms after completion.
|
|
166
|
+
*/
|
|
138
167
|
function memoizePromise(fn, opts) {
|
|
139
168
|
const cache = new Map();
|
|
140
169
|
const memoized = (...args) => {
|
|
@@ -156,6 +185,11 @@ function memoizePromise(fn, opts) {
|
|
|
156
185
|
};
|
|
157
186
|
return memoized;
|
|
158
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Debounces per distinct argument list: each unique `JSON.stringify(args)` gets its own debounced function (lodash debounce).
|
|
190
|
+
* @param wait Debounce wait in ms (default 300)
|
|
191
|
+
* @throws If the internal map is missing an entry (should not happen)
|
|
192
|
+
*/
|
|
159
193
|
function debounceByArgs(fn, wait = 300) {
|
|
160
194
|
const debouncedFunctions = new Map();
|
|
161
195
|
const debounced = (...args) => {
|
|
@@ -172,6 +206,10 @@ function debounceByArgs(fn, wait = 300) {
|
|
|
172
206
|
};
|
|
173
207
|
return debounced;
|
|
174
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Monotonic-ish high-resolution time when `performance` exists; otherwise `Date.now()`.
|
|
211
|
+
* Uses `timeOrigin + now()` in browsers; suitable for relative timing, not wall-clock.
|
|
212
|
+
*/
|
|
175
213
|
function getTimestamp() {
|
|
176
214
|
// check if in node.js environment
|
|
177
215
|
if (typeof performance === "undefined" || !performance.timeOrigin) {
|
|
@@ -180,6 +218,14 @@ function getTimestamp() {
|
|
|
180
218
|
}
|
|
181
219
|
return performance.timeOrigin + performance.now();
|
|
182
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Runs `fn` with adaptive timeout from {@link IDeviceConnection.latencyMs}, retrying on error or until the op finishes.
|
|
223
|
+
* Updates `connection` latency and error rate from outcomes.
|
|
224
|
+
* @param opts.timeout Clamped timeout; defaults to {@link PeerDeviceConsts} min/max
|
|
225
|
+
* @param opts.retriesOnError Max error retries
|
|
226
|
+
* @param opts.retriesOnTimeout Max “timed out” races before giving up
|
|
227
|
+
* @throws Last error, timeout exhaustion, or if the connection is closed
|
|
228
|
+
*/
|
|
183
229
|
async function retryOnErrorOrTimeout({ fn, connection, opts = {}, }) {
|
|
184
230
|
const timeoutMin = opts.timeout ?? peer_device_1.PeerDeviceConsts.TIMEOUT_MIN;
|
|
185
231
|
const timeoutMax = opts.timeout ?? peer_device_1.PeerDeviceConsts.TIMEOUT_MAX;
|
|
@@ -244,7 +290,8 @@ async function retryOnErrorOrTimeout({ fn, connection, opts = {}, }) {
|
|
|
244
290
|
}
|
|
245
291
|
}
|
|
246
292
|
/**
|
|
247
|
-
*
|
|
293
|
+
* Physical table name: `"name_id"` when `tableId` is set, else `name`.
|
|
294
|
+
* @param metaData Table metadata from the ORM layer
|
|
248
295
|
*/
|
|
249
296
|
function getFullTableName(metaData) {
|
|
250
297
|
return [metaData.name, metaData.tableId].filter((v) => v && v.length > 0).join("_");
|