@peers-app/peers-sdk 0.1.4
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 +1 -0
- package/dist/context/data-context.d.ts +31 -0
- package/dist/context/data-context.js +56 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.js +19 -0
- package/dist/context/user-context-singleton.d.ts +11 -0
- package/dist/context/user-context-singleton.js +121 -0
- package/dist/context/user-context.d.ts +55 -0
- package/dist/context/user-context.js +205 -0
- package/dist/data/assistants.d.ts +68 -0
- package/dist/data/assistants.js +64 -0
- package/dist/data/change-tracking.d.ts +219 -0
- package/dist/data/change-tracking.js +119 -0
- package/dist/data/channels.d.ts +29 -0
- package/dist/data/channels.js +25 -0
- package/dist/data/data-locks.d.ts +37 -0
- package/dist/data/data-locks.js +180 -0
- package/dist/data/data-locks.test.d.ts +1 -0
- package/dist/data/data-locks.test.js +456 -0
- package/dist/data/device-sync-info.d.ts +19 -0
- package/dist/data/device-sync-info.js +24 -0
- package/dist/data/devices.d.ts +51 -0
- package/dist/data/devices.js +36 -0
- package/dist/data/embeddings.d.ts +47 -0
- package/dist/data/embeddings.js +36 -0
- package/dist/data/files/file-read-stream.d.ts +27 -0
- package/dist/data/files/file-read-stream.js +195 -0
- package/dist/data/files/file-write-stream.d.ts +20 -0
- package/dist/data/files/file-write-stream.js +113 -0
- package/dist/data/files/file.types.d.ts +47 -0
- package/dist/data/files/file.types.js +55 -0
- package/dist/data/files/files.d.ts +28 -0
- package/dist/data/files/files.js +127 -0
- package/dist/data/files/files.test.d.ts +1 -0
- package/dist/data/files/files.test.js +728 -0
- package/dist/data/files/index.d.ts +4 -0
- package/dist/data/files/index.js +23 -0
- package/dist/data/group-member-roles.d.ts +9 -0
- package/dist/data/group-member-roles.js +25 -0
- package/dist/data/group-members.d.ts +39 -0
- package/dist/data/group-members.js +68 -0
- package/dist/data/group-members.test.d.ts +1 -0
- package/dist/data/group-members.test.js +287 -0
- package/dist/data/group-permissions.d.ts +8 -0
- package/dist/data/group-permissions.js +73 -0
- package/dist/data/group-share.d.ts +50 -0
- package/dist/data/group-share.js +196 -0
- package/dist/data/groups.d.ts +50 -0
- package/dist/data/groups.js +73 -0
- package/dist/data/groups.test.d.ts +1 -0
- package/dist/data/groups.test.js +153 -0
- package/dist/data/index.d.ts +31 -0
- package/dist/data/index.js +47 -0
- package/dist/data/knowledge/knowledge-frames.d.ts +34 -0
- package/dist/data/knowledge/knowledge-frames.js +34 -0
- package/dist/data/knowledge/knowledge-links.d.ts +30 -0
- package/dist/data/knowledge/knowledge-links.js +25 -0
- package/dist/data/knowledge/knowledge-values.d.ts +35 -0
- package/dist/data/knowledge/knowledge-values.js +35 -0
- package/dist/data/knowledge/peer-types.d.ts +112 -0
- package/dist/data/knowledge/peer-types.js +27 -0
- package/dist/data/knowledge/predicates.d.ts +34 -0
- package/dist/data/knowledge/predicates.js +27 -0
- package/dist/data/messages.d.ts +57 -0
- package/dist/data/messages.js +97 -0
- package/dist/data/orm/client-proxy.data-source.d.ts +27 -0
- package/dist/data/orm/client-proxy.data-source.js +65 -0
- package/dist/data/orm/cursor.d.ts +25 -0
- package/dist/data/orm/cursor.js +47 -0
- package/dist/data/orm/cursor.test.d.ts +1 -0
- package/dist/data/orm/cursor.test.js +315 -0
- package/dist/data/orm/data-query.d.ts +96 -0
- package/dist/data/orm/data-query.js +208 -0
- package/dist/data/orm/data-query.mongo.d.ts +17 -0
- package/dist/data/orm/data-query.mongo.js +267 -0
- package/dist/data/orm/data-query.mongo.test.d.ts +1 -0
- package/dist/data/orm/data-query.mongo.test.js +398 -0
- package/dist/data/orm/data-query.sqlite.d.ts +14 -0
- package/dist/data/orm/data-query.sqlite.js +297 -0
- package/dist/data/orm/data-query.sqlite.test.d.ts +1 -0
- package/dist/data/orm/data-query.sqlite.test.js +377 -0
- package/dist/data/orm/data-query.test.d.ts +1 -0
- package/dist/data/orm/data-query.test.js +553 -0
- package/dist/data/orm/decorators.d.ts +6 -0
- package/dist/data/orm/decorators.js +21 -0
- package/dist/data/orm/dependency-injection.test.d.ts +1 -0
- package/dist/data/orm/dependency-injection.test.js +171 -0
- package/dist/data/orm/doc.d.ts +26 -0
- package/dist/data/orm/doc.js +124 -0
- package/dist/data/orm/event-registry.d.ts +24 -0
- package/dist/data/orm/event-registry.js +40 -0
- package/dist/data/orm/event-registry.test.d.ts +1 -0
- package/dist/data/orm/event-registry.test.js +44 -0
- package/dist/data/orm/factory.d.ts +8 -0
- package/dist/data/orm/factory.js +147 -0
- package/dist/data/orm/index.d.ts +16 -0
- package/dist/data/orm/index.js +32 -0
- package/dist/data/orm/multi-cursors.d.ts +11 -0
- package/dist/data/orm/multi-cursors.js +146 -0
- package/dist/data/orm/multi-cursors.test.d.ts +1 -0
- package/dist/data/orm/multi-cursors.test.js +455 -0
- package/dist/data/orm/sql-db.d.ts +6 -0
- package/dist/data/orm/sql-db.js +2 -0
- package/dist/data/orm/sql.data-source.d.ts +38 -0
- package/dist/data/orm/sql.data-source.js +379 -0
- package/dist/data/orm/sql.data-source.test.d.ts +1 -0
- package/dist/data/orm/sql.data-source.test.js +406 -0
- package/dist/data/orm/subscribable.data-source.d.ts +25 -0
- package/dist/data/orm/subscribable.data-source.js +72 -0
- package/dist/data/orm/table-container-events.test.d.ts +1 -0
- package/dist/data/orm/table-container-events.test.js +93 -0
- package/dist/data/orm/table-container.d.ts +39 -0
- package/dist/data/orm/table-container.js +96 -0
- package/dist/data/orm/table-definitions.system.d.ts +9 -0
- package/dist/data/orm/table-definitions.system.js +29 -0
- package/dist/data/orm/table-definitions.type.d.ts +19 -0
- package/dist/data/orm/table-definitions.type.js +2 -0
- package/dist/data/orm/table-dependencies.d.ts +32 -0
- package/dist/data/orm/table-dependencies.js +2 -0
- package/dist/data/orm/table.d.ts +42 -0
- package/dist/data/orm/table.event-source.test.d.ts +1 -0
- package/dist/data/orm/table.event-source.test.js +341 -0
- package/dist/data/orm/table.js +244 -0
- package/dist/data/orm/types.d.ts +20 -0
- package/dist/data/orm/types.js +115 -0
- package/dist/data/orm/types.test.d.ts +1 -0
- package/dist/data/orm/types.test.js +71 -0
- package/dist/data/package-permissions.d.ts +7 -0
- package/dist/data/package-permissions.js +18 -0
- package/dist/data/packages.d.ts +92 -0
- package/dist/data/packages.js +90 -0
- package/dist/data/peer-events/peer-event-handlers.d.ts +21 -0
- package/dist/data/peer-events/peer-event-handlers.js +28 -0
- package/dist/data/peer-events/peer-event-types.d.ts +119 -0
- package/dist/data/peer-events/peer-event-types.js +29 -0
- package/dist/data/peer-events/peer-events.d.ts +41 -0
- package/dist/data/peer-events/peer-events.js +102 -0
- package/dist/data/persistent-vars.d.ts +87 -0
- package/dist/data/persistent-vars.js +230 -0
- package/dist/data/tool-tests.d.ts +37 -0
- package/dist/data/tool-tests.js +27 -0
- package/dist/data/tools.d.ts +358 -0
- package/dist/data/tools.js +48 -0
- package/dist/data/user-permissions.d.ts +15 -0
- package/dist/data/user-permissions.js +39 -0
- package/dist/data/user-permissions.test.d.ts +1 -0
- package/dist/data/user-permissions.test.js +252 -0
- package/dist/data/users.d.ts +38 -0
- package/dist/data/users.js +73 -0
- package/dist/data/workflow-logs.d.ts +106 -0
- package/dist/data/workflow-logs.js +67 -0
- package/dist/data/workflow-runs.d.ts +103 -0
- package/dist/data/workflow-runs.js +313 -0
- package/dist/data/workflows.d.ts +16 -0
- package/dist/data/workflows.js +21 -0
- package/dist/device/connection.d.ts +41 -0
- package/dist/device/connection.js +249 -0
- package/dist/device/connection.test.d.ts +1 -0
- package/dist/device/connection.test.js +292 -0
- package/dist/device/device-election.d.ts +36 -0
- package/dist/device/device-election.js +137 -0
- package/dist/device/device.d.ts +22 -0
- package/dist/device/device.js +110 -0
- package/dist/device/device.test.d.ts +1 -0
- package/dist/device/device.test.js +203 -0
- package/dist/device/get-trust-level.d.ts +3 -0
- package/dist/device/get-trust-level.js +87 -0
- package/dist/device/socket.type.d.ts +20 -0
- package/dist/device/socket.type.js +15 -0
- package/dist/device/streamed-socket.d.ts +27 -0
- package/dist/device/streamed-socket.js +154 -0
- package/dist/device/streamed-socket.test.d.ts +1 -0
- package/dist/device/streamed-socket.test.js +44 -0
- package/dist/events.d.ts +35 -0
- package/dist/events.js +128 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +50 -0
- package/dist/keys.d.ts +51 -0
- package/dist/keys.js +234 -0
- package/dist/keys.test.d.ts +1 -0
- package/dist/keys.test.js +215 -0
- package/dist/mentions.d.ts +9 -0
- package/dist/mentions.js +46 -0
- package/dist/observable.d.ts +19 -0
- package/dist/observable.js +112 -0
- package/dist/observable.test.d.ts +1 -0
- package/dist/observable.test.js +183 -0
- package/dist/package-loader/get-require.d.ts +10 -0
- package/dist/package-loader/get-require.js +31 -0
- package/dist/package-loader/index.d.ts +1 -0
- package/dist/package-loader/index.js +17 -0
- package/dist/package-loader/package-loader.d.ts +16 -0
- package/dist/package-loader/package-loader.js +102 -0
- package/dist/peers-ui/peers-ui.d.ts +15 -0
- package/dist/peers-ui/peers-ui.js +23 -0
- package/dist/peers-ui/peers-ui.types.d.ts +35 -0
- package/dist/peers-ui/peers-ui.types.js +3 -0
- package/dist/rpc-types.d.ts +45 -0
- package/dist/rpc-types.js +47 -0
- package/dist/serial-json.d.ts +5 -0
- package/dist/serial-json.js +186 -0
- package/dist/serial-json.test.d.ts +1 -0
- package/dist/serial-json.test.js +86 -0
- package/dist/system-ids.d.ts +6 -0
- package/dist/system-ids.js +10 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/tools-factory.d.ts +5 -0
- package/dist/tools/tools-factory.js +34 -0
- package/dist/types/app-nav.d.ts +18 -0
- package/dist/types/app-nav.js +10 -0
- package/dist/types/assistant-runner-args.d.ts +9 -0
- package/dist/types/assistant-runner-args.js +2 -0
- package/dist/types/field-type.d.ts +37 -0
- package/dist/types/field-type.js +26 -0
- package/dist/types/peer-device.d.ts +40 -0
- package/dist/types/peer-device.js +14 -0
- package/dist/types/peers-package.d.ts +23 -0
- package/dist/types/peers-package.js +2 -0
- package/dist/types/workflow-logger.d.ts +2 -0
- package/dist/types/workflow-logger.js +2 -0
- package/dist/types/workflow-run-context.d.ts +12 -0
- package/dist/types/workflow-run-context.js +2 -0
- package/dist/types/workflow.d.ts +72 -0
- package/dist/types/workflow.js +24 -0
- package/dist/types/zod-types.d.ts +7 -0
- package/dist/types/zod-types.js +12 -0
- package/dist/users.query.d.ts +13 -0
- package/dist/users.query.js +134 -0
- package/dist/utils.d.ts +39 -0
- package/dist/utils.js +240 -0
- package/dist/utils.test.d.ts +1 -0
- package/dist/utils.test.js +140 -0
- package/package.json +50 -0
package/dist/utils.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.moneyFormatter = exports.MAX_ID = exports.MIN_ID = void 0;
|
|
4
|
+
exports.cryptoRandomString = cryptoRandomString;
|
|
5
|
+
exports.newid = newid;
|
|
6
|
+
exports.isid = isid;
|
|
7
|
+
exports.idTime = idTime;
|
|
8
|
+
exports.idDate = idDate;
|
|
9
|
+
exports.idRandNums = idRandNums;
|
|
10
|
+
exports.simpleHash = simpleHash;
|
|
11
|
+
exports.simpleObjectHash = simpleObjectHash;
|
|
12
|
+
exports.sleep = sleep;
|
|
13
|
+
exports.camelCaseToSpaces = camelCaseToSpaces;
|
|
14
|
+
exports.camelCaseToHyphens = camelCaseToHyphens;
|
|
15
|
+
exports.formatMoney = formatMoney;
|
|
16
|
+
exports.memoizePromise = memoizePromise;
|
|
17
|
+
exports.debounceByArgs = debounceByArgs;
|
|
18
|
+
exports.getTimestamp = getTimestamp;
|
|
19
|
+
exports.retryOnErrorOrTimeout = retryOnErrorOrTimeout;
|
|
20
|
+
exports.getFullTableName = getFullTableName;
|
|
21
|
+
const _ = require("lodash");
|
|
22
|
+
const nacl = require("tweetnacl");
|
|
23
|
+
const peer_device_1 = require("./types/peer-device");
|
|
24
|
+
const stableStringify = require('fast-json-stable-stringify');
|
|
25
|
+
function cryptoRandomString(length) {
|
|
26
|
+
let s = '';
|
|
27
|
+
let r = nacl.randomBytes(length + 6);
|
|
28
|
+
let i = 0;
|
|
29
|
+
while (s.length < length) {
|
|
30
|
+
if (i >= r.length) {
|
|
31
|
+
r = nacl.randomBytes(length - s.length);
|
|
32
|
+
i = 0;
|
|
33
|
+
}
|
|
34
|
+
const n = r[i];
|
|
35
|
+
i++;
|
|
36
|
+
if (n >= 252) {
|
|
37
|
+
// we don't want to bias the characters generated so only consider the range of numbers that spread evenly between factors of 36
|
|
38
|
+
// we exclude 252, 253, 254, and 255 because it would bias towards '0', '1', '2', and '3' respectively
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
s += (n % 36).toString(36);
|
|
42
|
+
}
|
|
43
|
+
return s.substring(0, length);
|
|
44
|
+
}
|
|
45
|
+
function newid() {
|
|
46
|
+
// modeled after mongo ids, timestamp + counter + random but we're going to skip counter and have bigger random
|
|
47
|
+
// people can switch to using a counter + random later if they want (or do something else with the random part).
|
|
48
|
+
// This id is going to be a 128 bit number so it fits naturally into memory.
|
|
49
|
+
// 2 ** 128 ~= 3.4e38 is the maximum it can be
|
|
50
|
+
// For efficient transmission, storage, presentation, and usage we're going to represent this number with base 36 [0-9a-z]
|
|
51
|
+
// (3.4e38).toString(36) == "f55n5nmuuaw00000000000000", this is our max in base 36, 25 characters
|
|
52
|
+
// Date.now() =~ 1625282091498
|
|
53
|
+
// but we're dealing in base 36 not base 10
|
|
54
|
+
// (1625282091498).toString(36) == "kqn6zrvu" (length 8)
|
|
55
|
+
// Number.parseInt("zzzzzzzz", 36) == 2821109907455 == year 2059. Way too soon so going up to 9 characters
|
|
56
|
+
// Number.parseInt("zzzzzzzzz", 36) == 101559956668415 == year 5188.
|
|
57
|
+
// but the max size of 9 left most can only be "f55n5nmuu" == 42720753566838 == year 3323. That could still work but only ~ 1300 years
|
|
58
|
+
// that leaves 16 characters to represent a random number to prevent collisions each millisecond, 36 ** 16 ~= 8e24
|
|
59
|
+
// Allocating one more character to the time and one less to the random number to avoid hitting max time in any conceivable future
|
|
60
|
+
// now our max time is new Date(Number.parseInt('f55n5nmuua',36)) == +050705-08-09T23:40:06.178Z. 50k years from now.
|
|
61
|
+
// We still have 15 chars for our random number. 36 ** 15 ~= 2e23
|
|
62
|
+
// That is still a very large number and the chance of a collision should be so small as to be effectively unique in any single user's database
|
|
63
|
+
// I wish I knew the math to prove that out.
|
|
64
|
+
const time = Date.now().toString(36).padStart(10, '0'); // e.g: "00kq6xh45f", length == 10
|
|
65
|
+
//use nacl.randomBytes to be cryptographically secure
|
|
66
|
+
return time + cryptoRandomString(15);
|
|
67
|
+
}
|
|
68
|
+
exports.MIN_ID = '0'.repeat(25);
|
|
69
|
+
; // 1970
|
|
70
|
+
exports.MAX_ID = 'f55n5nmuua' + 'z'.repeat(15); // 50k years from now
|
|
71
|
+
function isid(id) {
|
|
72
|
+
id = String(id);
|
|
73
|
+
const idMatch = Boolean(/^[0-9a-z]{25}$/i.exec(id));
|
|
74
|
+
if (idMatch) {
|
|
75
|
+
// only consider ids valid if they are less than current time (with 5 min buffer)
|
|
76
|
+
// This is to prevent people from making ids with times in the future to get them to always show up as the "newest" item and/or prematurely claim ids
|
|
77
|
+
return idTime(id) < (Date.now() + 300000);
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
;
|
|
82
|
+
function idTime(id) {
|
|
83
|
+
const time36 = id.substr(0, 10);
|
|
84
|
+
return Number.parseInt(time36, 36);
|
|
85
|
+
}
|
|
86
|
+
function idDate(id) {
|
|
87
|
+
return new Date(idTime(id));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* This returns the random number as two parts to prevent loss of precision when converting to large numbers
|
|
91
|
+
*/
|
|
92
|
+
function idRandNums(id) {
|
|
93
|
+
const numPart1 = id.substr(10, 8);
|
|
94
|
+
const numPart2 = id.substr(18, 7);
|
|
95
|
+
return [Number.parseInt(numPart1, 36), Number.parseInt(numPart2, 36)];
|
|
96
|
+
}
|
|
97
|
+
function simpleHash(str) {
|
|
98
|
+
let hash = 0;
|
|
99
|
+
for (let i = 0; i < str.length; i++) {
|
|
100
|
+
const char = str.charCodeAt(i);
|
|
101
|
+
hash = (hash << 5) - hash + char;
|
|
102
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
103
|
+
}
|
|
104
|
+
return Math.abs(hash);
|
|
105
|
+
}
|
|
106
|
+
function simpleObjectHash(obj) {
|
|
107
|
+
return simpleHash(stableStringify(obj));
|
|
108
|
+
}
|
|
109
|
+
function sleep(ms = 0) {
|
|
110
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
111
|
+
}
|
|
112
|
+
function camelCaseToSpaces(s) {
|
|
113
|
+
s = s.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
114
|
+
// s = s.replace(/(GL)([A-Z])/g, '$1 $2'); // anything like GLAccounts, GLBatches, etc.
|
|
115
|
+
s = s.replace("_", " ");
|
|
116
|
+
s = s[0]?.toUpperCase() + s.substr(1);
|
|
117
|
+
return s;
|
|
118
|
+
}
|
|
119
|
+
function camelCaseToHyphens(s) {
|
|
120
|
+
s = camelCaseToSpaces(s);
|
|
121
|
+
return s.split(' ').join('-').toLowerCase();
|
|
122
|
+
}
|
|
123
|
+
exports.moneyFormatter = new Intl.NumberFormat('en-US', {
|
|
124
|
+
style: 'currency',
|
|
125
|
+
currency: 'USD',
|
|
126
|
+
minimumFractionDigits: 2,
|
|
127
|
+
maximumFractionDigits: 2,
|
|
128
|
+
});
|
|
129
|
+
function formatMoney(value, precision = 2) {
|
|
130
|
+
if (precision === 2) {
|
|
131
|
+
return exports.moneyFormatter.format(value);
|
|
132
|
+
}
|
|
133
|
+
const _moneyFormatter = new Intl.NumberFormat('en-US', {
|
|
134
|
+
style: 'currency',
|
|
135
|
+
currency: 'USD',
|
|
136
|
+
minimumFractionDigits: precision,
|
|
137
|
+
maximumFractionDigits: precision,
|
|
138
|
+
});
|
|
139
|
+
return _moneyFormatter.format(value);
|
|
140
|
+
}
|
|
141
|
+
function memoizePromise(fn, opts) {
|
|
142
|
+
const cache = new Map();
|
|
143
|
+
const memoized = (...args) => {
|
|
144
|
+
const key = JSON.stringify(args);
|
|
145
|
+
if (!cache.has(key)) {
|
|
146
|
+
const promise = fn(...args).finally(() => {
|
|
147
|
+
if (opts?.cacheTtl) {
|
|
148
|
+
setTimeout(() => {
|
|
149
|
+
cache.delete(key);
|
|
150
|
+
}, opts.cacheTtl);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
cache.delete(key);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
cache.set(key, promise);
|
|
157
|
+
}
|
|
158
|
+
return cache.get(key);
|
|
159
|
+
};
|
|
160
|
+
return memoized;
|
|
161
|
+
}
|
|
162
|
+
function debounceByArgs(fn, wait = 300) {
|
|
163
|
+
const debouncedFunctions = new Map();
|
|
164
|
+
const debounced = (...args) => {
|
|
165
|
+
const key = JSON.stringify(args);
|
|
166
|
+
if (!debouncedFunctions.has(key)) {
|
|
167
|
+
const debouncedFn = _.debounce(fn, wait);
|
|
168
|
+
debouncedFunctions.set(key, debouncedFn);
|
|
169
|
+
}
|
|
170
|
+
return debouncedFunctions.get(key)(...args);
|
|
171
|
+
};
|
|
172
|
+
return debounced;
|
|
173
|
+
}
|
|
174
|
+
function getTimestamp() {
|
|
175
|
+
// check if in node.js environment
|
|
176
|
+
if (typeof performance === 'undefined' || !performance.timeOrigin) {
|
|
177
|
+
// Fallback for environments without performance API
|
|
178
|
+
return Date.now();
|
|
179
|
+
}
|
|
180
|
+
return performance.timeOrigin + performance.now();
|
|
181
|
+
}
|
|
182
|
+
async function retryOnErrorOrTimeout({ fn, connection, opts = {}, }) {
|
|
183
|
+
const timeoutMin = opts.timeout ?? peer_device_1.PeerDeviceConsts.TIMEOUT_MIN;
|
|
184
|
+
const timeoutMax = opts.timeout ?? peer_device_1.PeerDeviceConsts.TIMEOUT_MAX;
|
|
185
|
+
const retriesOnError = opts.retriesOnError ?? peer_device_1.PeerDeviceConsts.RETRY_COUNT;
|
|
186
|
+
const retriesOnTimeout = opts.retriesOnTimeout ?? peer_device_1.PeerDeviceConsts.RETRY_COUNT;
|
|
187
|
+
const timeout = Math.round(_.clamp(connection.latencyMs * 10, timeoutMin, timeoutMax));
|
|
188
|
+
const startTime = Date.now();
|
|
189
|
+
let errorCount = 0;
|
|
190
|
+
let timeoutCount = 0;
|
|
191
|
+
let result;
|
|
192
|
+
let resultSet = false;
|
|
193
|
+
let finalError;
|
|
194
|
+
while (errorCount <= retriesOnError && timeoutCount <= retriesOnTimeout) {
|
|
195
|
+
try {
|
|
196
|
+
let sleepTimeout = null;
|
|
197
|
+
const sleepPromise = new Promise(resolve => {
|
|
198
|
+
sleepTimeout = setTimeout(() => {
|
|
199
|
+
resolve();
|
|
200
|
+
}, timeout);
|
|
201
|
+
});
|
|
202
|
+
await Promise.race([
|
|
203
|
+
fn().then(r => {
|
|
204
|
+
result = r;
|
|
205
|
+
resultSet = true;
|
|
206
|
+
}),
|
|
207
|
+
sleepPromise,
|
|
208
|
+
]);
|
|
209
|
+
clearTimeout(sleepTimeout);
|
|
210
|
+
if (resultSet) {
|
|
211
|
+
const totalTime = Date.now() - startTime;
|
|
212
|
+
connection.latencyMs = totalTime * 0.1 + connection.latencyMs * 0.9;
|
|
213
|
+
connection.errorRate = (connection.errorRate * 0.9);
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
// timeout *= 2; // double the timeout for the next attempt
|
|
217
|
+
timeoutCount++;
|
|
218
|
+
finalError = undefined;
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
finalError = error;
|
|
222
|
+
connection.errorRate = (connection.errorRate * 0.9) + 0.1;
|
|
223
|
+
errorCount++;
|
|
224
|
+
}
|
|
225
|
+
console.warn(`Call failed, retrying: timeout is ${timeout}ms, errorCount: ${errorCount} of ${retriesOnError}, timeoutCount: ${timeoutCount} of ${retriesOnTimeout + 1}. Last error:`, finalError);
|
|
226
|
+
}
|
|
227
|
+
if (finalError) {
|
|
228
|
+
console.error(`Retry failed after ${errorCount} errors and ${timeoutCount} timeouts. Last error:`, finalError);
|
|
229
|
+
throw finalError;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
throw new Error(`Timeout after ${timeoutCount} retries waiting for ${timeout}ms`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Table name is "name_id" if `id` is present, otherwise just "name"
|
|
237
|
+
*/
|
|
238
|
+
function getFullTableName(metaData) {
|
|
239
|
+
return [metaData.name, metaData.tableId].filter(v => v && v.length > 0).join('_');
|
|
240
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const lodash_1 = require("lodash");
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
describe("newid", () => {
|
|
6
|
+
it("should return a valid id", async () => {
|
|
7
|
+
const id = (0, utils_1.newid)();
|
|
8
|
+
expect((0, utils_1.isid)(id)).toBe(true);
|
|
9
|
+
const time = (0, utils_1.idTime)(id);
|
|
10
|
+
expect(time).toBeGreaterThan(Date.now() - 1000);
|
|
11
|
+
expect(time).toBeLessThan(Date.now() + 1000);
|
|
12
|
+
});
|
|
13
|
+
// NOTE: Make sure to run this if you change the random number generation
|
|
14
|
+
describe.skip("it should return ids with the random portion evenly distributed", () => {
|
|
15
|
+
it("random portion should have evenly distributed character values", async () => {
|
|
16
|
+
const buckets = {};
|
|
17
|
+
for (let i = 0; i < 1000000; i++) {
|
|
18
|
+
const randomPart = (0, utils_1.newid)().substring(10);
|
|
19
|
+
expect(randomPart.length).toBe(15);
|
|
20
|
+
for (const c of randomPart) {
|
|
21
|
+
buckets[c] = (buckets[c] || 0) + 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
console.log(buckets);
|
|
25
|
+
const counts = Object.values(buckets);
|
|
26
|
+
let average = 0;
|
|
27
|
+
let max = 0;
|
|
28
|
+
let min = Number.MAX_SAFE_INTEGER;
|
|
29
|
+
for (const c of counts) {
|
|
30
|
+
average += c;
|
|
31
|
+
max = Math.max(max, c);
|
|
32
|
+
min = Math.min(min, c);
|
|
33
|
+
}
|
|
34
|
+
average /= counts.length;
|
|
35
|
+
const maxDeviation = Math.max(max - average, average - min);
|
|
36
|
+
const maxDeviationPercent = maxDeviation / average * 100;
|
|
37
|
+
console.log({ average, max, min, maxDeviation, maxDeviationPercent });
|
|
38
|
+
// expect all values to be within 0.5% of the average
|
|
39
|
+
expect(maxDeviationPercent).toBeLessThan(0.5);
|
|
40
|
+
});
|
|
41
|
+
it("random portion should have evenly distributed character value positions", async () => {
|
|
42
|
+
const buckets = {};
|
|
43
|
+
for (let i = 0; i < 2000000; i++) {
|
|
44
|
+
const randomPart = (0, utils_1.newid)().substring(10);
|
|
45
|
+
expect(randomPart.length).toBe(15);
|
|
46
|
+
for (let j = 0; j < randomPart.length; j++) {
|
|
47
|
+
const c = randomPart[j];
|
|
48
|
+
const k = `${c},${String(j).padStart(2, '0')}`;
|
|
49
|
+
buckets[k] = (buckets[k] || 0) + 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const orderedKeys = {};
|
|
53
|
+
let keys = (0, lodash_1.sortBy)(Object.keys(buckets), key => Number(key.split(',')[1]));
|
|
54
|
+
keys = (0, lodash_1.sortBy)(keys, key => key.split(',')[0]);
|
|
55
|
+
keys.forEach(key => orderedKeys[key] = buckets[key]);
|
|
56
|
+
console.log(orderedKeys);
|
|
57
|
+
const orderedValues = {};
|
|
58
|
+
let values = (0, lodash_1.sortBy)(Object.entries(buckets), ([, value]) => value);
|
|
59
|
+
values.forEach(([key, value]) => orderedValues[key] = value);
|
|
60
|
+
console.log(orderedValues);
|
|
61
|
+
const counts = Object.values(buckets);
|
|
62
|
+
let average = 0;
|
|
63
|
+
let max = 0;
|
|
64
|
+
let min = Number.MAX_SAFE_INTEGER;
|
|
65
|
+
for (const c of counts) {
|
|
66
|
+
average += c;
|
|
67
|
+
max = Math.max(max, c);
|
|
68
|
+
min = Math.min(min, c);
|
|
69
|
+
}
|
|
70
|
+
average /= counts.length;
|
|
71
|
+
const maxDeviation = Math.max(max - average, average - min);
|
|
72
|
+
const maxDeviationPercent = maxDeviation / average * 100;
|
|
73
|
+
console.log({ average, max, min, maxDeviation, maxDeviationPercent });
|
|
74
|
+
// expect all values to be within 2% of the average
|
|
75
|
+
expect(maxDeviationPercent).toBeLessThan(2);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("debounceByArgs", () => {
|
|
80
|
+
beforeEach(() => {
|
|
81
|
+
jest.useFakeTimers();
|
|
82
|
+
});
|
|
83
|
+
afterEach(() => {
|
|
84
|
+
jest.useRealTimers();
|
|
85
|
+
});
|
|
86
|
+
it("should debounce function calls with different arguments independently", () => {
|
|
87
|
+
const mockFn = jest.fn();
|
|
88
|
+
const debouncedFn = (0, utils_1.debounceByArgs)(mockFn, 100);
|
|
89
|
+
debouncedFn(1);
|
|
90
|
+
debouncedFn(2);
|
|
91
|
+
debouncedFn(1);
|
|
92
|
+
expect(mockFn).not.toHaveBeenCalled();
|
|
93
|
+
jest.advanceTimersByTime(100);
|
|
94
|
+
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
95
|
+
expect(mockFn).toHaveBeenCalledWith(1);
|
|
96
|
+
expect(mockFn).toHaveBeenCalledWith(2);
|
|
97
|
+
});
|
|
98
|
+
it("should debounce multiple calls with same arguments", () => {
|
|
99
|
+
const mockFn = jest.fn();
|
|
100
|
+
const debouncedFn = (0, utils_1.debounceByArgs)(mockFn, 100);
|
|
101
|
+
debouncedFn(1);
|
|
102
|
+
debouncedFn(1);
|
|
103
|
+
debouncedFn(1);
|
|
104
|
+
expect(mockFn).not.toHaveBeenCalled();
|
|
105
|
+
jest.advanceTimersByTime(100);
|
|
106
|
+
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
107
|
+
expect(mockFn).toHaveBeenCalledWith(1);
|
|
108
|
+
});
|
|
109
|
+
it("should handle complex arguments", () => {
|
|
110
|
+
const mockFn = jest.fn();
|
|
111
|
+
const debouncedFn = (0, utils_1.debounceByArgs)(mockFn, 50);
|
|
112
|
+
const obj1 = { id: 1, name: "test" };
|
|
113
|
+
const obj2 = { id: 2, name: "test" };
|
|
114
|
+
debouncedFn(obj1, "extra");
|
|
115
|
+
debouncedFn(obj2, "extra");
|
|
116
|
+
debouncedFn(obj1, "extra");
|
|
117
|
+
jest.advanceTimersByTime(50);
|
|
118
|
+
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
119
|
+
expect(mockFn).toHaveBeenCalledWith(obj1, "extra");
|
|
120
|
+
expect(mockFn).toHaveBeenCalledWith(obj2, "extra");
|
|
121
|
+
});
|
|
122
|
+
it("should call the function with correct arguments after debounce", () => {
|
|
123
|
+
const mockFn = jest.fn().mockReturnValue("result");
|
|
124
|
+
const debouncedFn = (0, utils_1.debounceByArgs)(mockFn, 100);
|
|
125
|
+
debouncedFn(1, "test");
|
|
126
|
+
expect(mockFn).not.toHaveBeenCalled();
|
|
127
|
+
jest.advanceTimersByTime(100);
|
|
128
|
+
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
129
|
+
expect(mockFn).toHaveBeenCalledWith(1, "test");
|
|
130
|
+
});
|
|
131
|
+
it("should use default wait time of 300ms", () => {
|
|
132
|
+
const mockFn = jest.fn();
|
|
133
|
+
const debouncedFn = (0, utils_1.debounceByArgs)(mockFn);
|
|
134
|
+
debouncedFn(1);
|
|
135
|
+
jest.advanceTimersByTime(299);
|
|
136
|
+
expect(mockFn).not.toHaveBeenCalled();
|
|
137
|
+
jest.advanceTimersByTime(1);
|
|
138
|
+
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
139
|
+
});
|
|
140
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@peers-app/peers-sdk",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/peers-app/peers-sdk.git"
|
|
7
|
+
},
|
|
8
|
+
"author": "Mark Archer <mark_archer@live.com>",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"xexports": {
|
|
19
|
+
".": "./dist/index.js",
|
|
20
|
+
"./data": "./dist/data/index.js"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "rm -rf dist && tsc",
|
|
24
|
+
"dev": "tsc -w",
|
|
25
|
+
"test": "jest",
|
|
26
|
+
"deploy": "yarn build && npm version patch && npm publish && git push"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@noble/hashes": "^1.8.0",
|
|
30
|
+
"fast-json-stable-stringify": "^2.1.0",
|
|
31
|
+
"lodash": "^4.17.21",
|
|
32
|
+
"moment": "^2.30.1",
|
|
33
|
+
"moment-timezone": "^0.5.46",
|
|
34
|
+
"tweetnacl": "^1.0.3",
|
|
35
|
+
"tweetnacl-util": "^0.15.1",
|
|
36
|
+
"zod": "^3.23.8"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
40
|
+
"@types/jest": "^29.5.13",
|
|
41
|
+
"@types/lodash": "^4.17.7",
|
|
42
|
+
"@types/moment": "^2.13.0",
|
|
43
|
+
"@types/moment-timezone": "^0.5.30",
|
|
44
|
+
"@types/node": "^22.4.0",
|
|
45
|
+
"better-sqlite3": "^11.8.1",
|
|
46
|
+
"jest": "^29.7.0",
|
|
47
|
+
"ts-jest": "^29.2.5",
|
|
48
|
+
"typescript": "^5.4.5"
|
|
49
|
+
}
|
|
50
|
+
}
|