spasm.js 1.0.2 → 2.0.0-alpha
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 +454 -113
- package/lib.commonjs/convert/convertToEventForSpasmid.d.ts +4 -0
- package/lib.commonjs/convert/convertToEventForSpasmid.d.ts.map +1 -0
- package/lib.commonjs/convert/convertToEventForSpasmid.js +171 -0
- package/lib.commonjs/convert/convertToEventForSpasmid.js.map +1 -0
- package/lib.commonjs/convert/convertToSpasm.d.ts +17 -15
- package/lib.commonjs/convert/convertToSpasm.d.ts.map +1 -1
- package/lib.commonjs/convert/convertToSpasm.js +772 -265
- package/lib.commonjs/convert/convertToSpasm.js.map +1 -1
- package/lib.commonjs/convert/convertToSpasmEventDatabase.d.ts +4 -0
- package/lib.commonjs/convert/convertToSpasmEventDatabase.d.ts.map +1 -0
- package/lib.commonjs/convert/convertToSpasmEventDatabase.js +130 -0
- package/lib.commonjs/convert/convertToSpasmEventDatabase.js.map +1 -0
- package/lib.commonjs/convert/index.d.ts +2 -0
- package/lib.commonjs/convert/index.d.ts.map +1 -1
- package/lib.commonjs/convert/index.js +5 -1
- package/lib.commonjs/convert/index.js.map +1 -1
- package/lib.commonjs/id/getSpasmId.d.ts +4 -0
- package/lib.commonjs/id/getSpasmId.d.ts.map +1 -0
- package/lib.commonjs/id/getSpasmId.js +31 -0
- package/lib.commonjs/id/getSpasmId.js.map +1 -0
- package/lib.commonjs/id/index.d.ts +2 -0
- package/lib.commonjs/id/index.d.ts.map +1 -0
- package/lib.commonjs/id/index.js +6 -0
- package/lib.commonjs/id/index.js.map +1 -0
- package/lib.commonjs/identify/identifyEvent.d.ts.map +1 -1
- package/lib.commonjs/identify/identifyEvent.js +13 -5
- package/lib.commonjs/identify/identifyEvent.js.map +1 -1
- package/lib.commonjs/sort/index.d.ts +2 -0
- package/lib.commonjs/sort/index.d.ts.map +1 -0
- package/lib.commonjs/sort/index.js +6 -0
- package/lib.commonjs/sort/index.js.map +1 -0
- package/lib.commonjs/sort/sortEventForSpasmid.d.ts +3 -0
- package/lib.commonjs/sort/sortEventForSpasmid.d.ts.map +1 -0
- package/lib.commonjs/sort/sortEventForSpasmid.js +15 -0
- package/lib.commonjs/sort/sortEventForSpasmid.js.map +1 -0
- package/lib.commonjs/spasm.d.ts +5 -3
- package/lib.commonjs/spasm.d.ts.map +1 -1
- package/lib.commonjs/spasm.js +4 -5
- package/lib.commonjs/spasm.js.map +1 -1
- package/lib.commonjs/types/index.d.ts +1 -1
- package/lib.commonjs/types/index.d.ts.map +1 -1
- package/lib.commonjs/types/interfaces.d.ts +468 -90
- package/lib.commonjs/types/interfaces.d.ts.map +1 -1
- package/lib.commonjs/types/interfaces.js +2 -0
- package/lib.commonjs/types/interfaces.js.map +1 -1
- package/lib.commonjs/utils/nostrUtils.d.ts +10 -2
- package/lib.commonjs/utils/nostrUtils.d.ts.map +1 -1
- package/lib.commonjs/utils/nostrUtils.js +122 -22
- package/lib.commonjs/utils/nostrUtils.js.map +1 -1
- package/lib.commonjs/utils/utils.d.ts +26 -1
- package/lib.commonjs/utils/utils.d.ts.map +1 -1
- package/lib.commonjs/utils/utils.js +723 -3
- package/lib.commonjs/utils/utils.js.map +1 -1
- package/lib.esm/convert/convertToEventForSpasmid.d.ts +4 -0
- package/lib.esm/convert/convertToEventForSpasmid.d.ts.map +1 -0
- package/lib.esm/convert/convertToEventForSpasmid.js +168 -0
- package/lib.esm/convert/convertToEventForSpasmid.js.map +1 -0
- package/lib.esm/convert/convertToSpasm.d.ts +17 -15
- package/lib.esm/convert/convertToSpasm.d.ts.map +1 -1
- package/lib.esm/convert/convertToSpasm.js +759 -251
- package/lib.esm/convert/convertToSpasm.js.map +1 -1
- package/lib.esm/convert/convertToSpasmEventDatabase.d.ts +4 -0
- package/lib.esm/convert/convertToSpasmEventDatabase.d.ts.map +1 -0
- package/lib.esm/convert/convertToSpasmEventDatabase.js +137 -0
- package/lib.esm/convert/convertToSpasmEventDatabase.js.map +1 -0
- package/lib.esm/convert/index.d.ts +2 -0
- package/lib.esm/convert/index.d.ts.map +1 -1
- package/lib.esm/convert/index.js +2 -0
- package/lib.esm/convert/index.js.map +1 -1
- package/lib.esm/id/getSpasmId.d.ts +4 -0
- package/lib.esm/id/getSpasmId.d.ts.map +1 -0
- package/lib.esm/id/getSpasmId.js +31 -0
- package/lib.esm/id/getSpasmId.js.map +1 -0
- package/lib.esm/id/index.d.ts +2 -0
- package/lib.esm/id/index.d.ts.map +1 -0
- package/lib.esm/id/index.js +2 -0
- package/lib.esm/id/index.js.map +1 -0
- package/lib.esm/identify/identifyEvent.d.ts.map +1 -1
- package/lib.esm/identify/identifyEvent.js +13 -5
- package/lib.esm/identify/identifyEvent.js.map +1 -1
- package/lib.esm/sort/index.d.ts +2 -0
- package/lib.esm/sort/index.d.ts.map +1 -0
- package/lib.esm/sort/index.js +2 -0
- package/lib.esm/sort/index.js.map +1 -0
- package/lib.esm/sort/sortEventForSpasmid.d.ts +3 -0
- package/lib.esm/sort/sortEventForSpasmid.d.ts.map +1 -0
- package/lib.esm/sort/sortEventForSpasmid.js +17 -0
- package/lib.esm/sort/sortEventForSpasmid.js.map +1 -0
- package/lib.esm/spasm.d.ts +5 -3
- package/lib.esm/spasm.d.ts.map +1 -1
- package/lib.esm/spasm.js +4 -2
- package/lib.esm/spasm.js.map +1 -1
- package/lib.esm/types/index.d.ts +1 -1
- package/lib.esm/types/index.d.ts.map +1 -1
- package/lib.esm/types/interfaces.d.ts +468 -90
- package/lib.esm/types/interfaces.d.ts.map +1 -1
- package/lib.esm/types/interfaces.js +2 -0
- package/lib.esm/types/interfaces.js.map +1 -1
- package/lib.esm/utils/nostrUtils.d.ts +10 -2
- package/lib.esm/utils/nostrUtils.d.ts.map +1 -1
- package/lib.esm/utils/nostrUtils.js +119 -21
- package/lib.esm/utils/nostrUtils.js.map +1 -1
- package/lib.esm/utils/utils.d.ts +26 -1
- package/lib.esm/utils/utils.d.ts.map +1 -1
- package/lib.esm/utils/utils.js +701 -2
- package/lib.esm/utils/utils.js.map +1 -1
- package/package.json +9 -2
- package/src.ts/convert/convertToEventForSpasmid.ts +289 -0
- package/src.ts/convert/convertToSpasm.ts +962 -292
- package/src.ts/convert/convertToSpasmEventDatabase.ts +204 -0
- package/src.ts/convert/index.ts +2 -0
- package/src.ts/docs/architecture.md +413 -0
- package/src.ts/id/getSpasmId.ts +56 -0
- package/src.ts/id/index.ts +1 -0
- package/src.ts/identify/identifyEvent.ts +12 -5
- package/src.ts/sort/index.ts +1 -0
- package/src.ts/sort/sortEventForSpasmid.ts +30 -0
- package/src.ts/spasm.ts +5 -3
- package/src.ts/types/index.ts +1 -1
- package/src.ts/types/interfaces.ts +729 -125
- package/src.ts/utils/nostrUtils.ts +150 -22
- package/src.ts/utils/utils.ts +1005 -4
package/lib.esm/utils/utils.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Using sha256 from 'js-sha256' npm package, because
|
|
3
|
+
* built-in 'crypto' module works only in a server-side
|
|
4
|
+
* Node.js environment, not on the client-side (browser).
|
|
5
|
+
*/
|
|
6
|
+
import { sha256 } from "js-sha256";
|
|
7
|
+
import { ethers } from "ethers";
|
|
1
8
|
// Filter out undefined, null, 0, '', false, NaN, {}, []
|
|
2
9
|
// Keep {a: null}, {b: undefined}
|
|
3
10
|
// Examples:
|
|
@@ -78,12 +85,17 @@ export const extractSealedEvent = (unknownPostOrEvent) => {
|
|
|
78
85
|
if (!isObjectWithValues(unknownPostOrEvent))
|
|
79
86
|
return false;
|
|
80
87
|
let signedObject = false;
|
|
81
|
-
if (
|
|
88
|
+
if (unknownPostOrEvent &&
|
|
89
|
+
typeof (unknownPostOrEvent) === "object" &&
|
|
90
|
+
'signed_message' in unknownPostOrEvent &&
|
|
82
91
|
unknownPostOrEvent['signed_message'] &&
|
|
83
92
|
typeof (unknownPostOrEvent['signed_message'] === "string")) {
|
|
84
93
|
signedObject = JSON.parse(unknownPostOrEvent['signed_message']);
|
|
85
94
|
}
|
|
86
|
-
else if (
|
|
95
|
+
else if (unknownPostOrEvent &&
|
|
96
|
+
typeof (unknownPostOrEvent) === "object" &&
|
|
97
|
+
'signedString' in unknownPostOrEvent &&
|
|
98
|
+
unknownPostOrEvent['signedString'] &&
|
|
87
99
|
typeof (unknownPostOrEvent['signedString'] === "string")) {
|
|
88
100
|
signedObject = JSON.parse(unknownPostOrEvent['signedString']);
|
|
89
101
|
}
|
|
@@ -96,6 +108,12 @@ export const toBeTimestamp = (time) => {
|
|
|
96
108
|
if (Number.isNaN(timestamp)) {
|
|
97
109
|
return undefined;
|
|
98
110
|
}
|
|
111
|
+
// Optional
|
|
112
|
+
// Standardize the timestamp to 10 characters (seconds)
|
|
113
|
+
// by rounding down the timestamp to the nearest second.
|
|
114
|
+
// if (timestamp.toString().length > 10) {
|
|
115
|
+
// timestamp = Math.floor(timestamp / 1000) * 1000;
|
|
116
|
+
// }
|
|
99
117
|
return timestamp;
|
|
100
118
|
};
|
|
101
119
|
export const getNostrSpasmVersion = (event) => {
|
|
@@ -112,4 +130,685 @@ export const getNostrSpasmVersion = (event) => {
|
|
|
112
130
|
}
|
|
113
131
|
return nostrSpasmVersion;
|
|
114
132
|
};
|
|
133
|
+
// Example usage
|
|
134
|
+
// getSchemeFromUrl('https://example.com/news') // return 'https'
|
|
135
|
+
// getSchemeFromUrl('http://example.com') // return 'http'
|
|
136
|
+
// getSchemeFromUrl('ftp://example.com') // return 'ftp'
|
|
137
|
+
// getSchemeFromUrl('mailto://...') // return 'mailto'
|
|
138
|
+
// getSchemeFromUrl('ipfs://123abc') // return 'ipfs'
|
|
139
|
+
// export const getSchemeFromUrl = (url: any) => {
|
|
140
|
+
// if (!url || typeof(url) !== "string") return ""
|
|
141
|
+
// try {
|
|
142
|
+
// const urlObject = new URL(url);
|
|
143
|
+
// return urlObject.protocol.slice(0, -1); // Remove the trailing colon
|
|
144
|
+
// } catch (error) {
|
|
145
|
+
// console.log('Invalid URL:', url);
|
|
146
|
+
// return "";
|
|
147
|
+
// }
|
|
148
|
+
// }
|
|
149
|
+
export const isValidUrl = (value) => {
|
|
150
|
+
if (!value)
|
|
151
|
+
return false;
|
|
152
|
+
try {
|
|
153
|
+
// new URL() constructor is less vulnerable to ReDoS attacks
|
|
154
|
+
// because it's a built-it JS function that doesn't use regex
|
|
155
|
+
new URL(value);
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
export const createLinkObjectFromUrl = (url, key) => {
|
|
163
|
+
if (!url || typeof (url) !== "string")
|
|
164
|
+
return null;
|
|
165
|
+
try {
|
|
166
|
+
const urlObject = new URL(url);
|
|
167
|
+
const linkObject = {
|
|
168
|
+
value: url,
|
|
169
|
+
// protocol: urlObject.protocol.slice(0, -1),
|
|
170
|
+
// host: urlObject.host,
|
|
171
|
+
// path: urlObject.pathname,
|
|
172
|
+
// search: urlObject.search,
|
|
173
|
+
};
|
|
174
|
+
if (urlObject.protocol) {
|
|
175
|
+
linkObject.protocol = urlObject.protocol.slice(0, -1);
|
|
176
|
+
}
|
|
177
|
+
if (urlObject.origin) {
|
|
178
|
+
linkObject.origin = urlObject.origin;
|
|
179
|
+
}
|
|
180
|
+
if (urlObject.host) {
|
|
181
|
+
linkObject.host = urlObject.host;
|
|
182
|
+
}
|
|
183
|
+
if (urlObject.pathname &&
|
|
184
|
+
typeof (urlObject.pathname) === "string" // &&
|
|
185
|
+
// urlObject.pathname.length > 1
|
|
186
|
+
) {
|
|
187
|
+
linkObject.pathname = urlObject.pathname;
|
|
188
|
+
}
|
|
189
|
+
if (urlObject.search &&
|
|
190
|
+
typeof (urlObject.search) === "string" // &&
|
|
191
|
+
// urlObject.search.length > 1
|
|
192
|
+
) {
|
|
193
|
+
linkObject.search = urlObject.search;
|
|
194
|
+
}
|
|
195
|
+
if (urlObject.port) {
|
|
196
|
+
linkObject.port = urlObject.port;
|
|
197
|
+
}
|
|
198
|
+
if (urlObject.hash) {
|
|
199
|
+
linkObject.hash = urlObject.hash;
|
|
200
|
+
}
|
|
201
|
+
if (key &&
|
|
202
|
+
(typeof (key) === "string" || typeof (key) === "number")) {
|
|
203
|
+
linkObject.originalProtocolKey = key;
|
|
204
|
+
}
|
|
205
|
+
return linkObject;
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
console.log('Invalid URL:', url);
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
export const getFormatFromValue = (value) => {
|
|
213
|
+
let format = undefined;
|
|
214
|
+
if (!value)
|
|
215
|
+
return format;
|
|
216
|
+
if (typeof (value) !== "string" && typeof (value) !== "number") {
|
|
217
|
+
return format;
|
|
218
|
+
}
|
|
219
|
+
if (typeof (value) === "number") {
|
|
220
|
+
return format = { name: "number" };
|
|
221
|
+
}
|
|
222
|
+
if (value && typeof (value) === "string") {
|
|
223
|
+
// Spasm ID
|
|
224
|
+
if (value.length === 64 + 9 && value.startsWith("spasmid")) {
|
|
225
|
+
const version = value.slice(7, 9);
|
|
226
|
+
format = { name: "spasmid", version: version };
|
|
227
|
+
return format;
|
|
228
|
+
}
|
|
229
|
+
// Dmp ID (signature)
|
|
230
|
+
if (value.length === 132 && value.startsWith("0x")) {
|
|
231
|
+
format = { name: "ethereum-sig" };
|
|
232
|
+
return format;
|
|
233
|
+
}
|
|
234
|
+
// Nostr ID
|
|
235
|
+
if (value.length === 63 && value.startsWith("note")) {
|
|
236
|
+
format = { name: "nostr-note" };
|
|
237
|
+
return format;
|
|
238
|
+
}
|
|
239
|
+
if (value.length === 68 && value.startsWith("nevent")) {
|
|
240
|
+
format = { name: "nostr-nevent" };
|
|
241
|
+
return format;
|
|
242
|
+
}
|
|
243
|
+
// Spasm signer
|
|
244
|
+
// if (address.length === 64 + 9 && address.startsWith("spasmer")) {
|
|
245
|
+
// const version = address.slice(7,9)
|
|
246
|
+
// format = { name: "spasmer", version: version }
|
|
247
|
+
// return format
|
|
248
|
+
// }
|
|
249
|
+
// Ethereum signer
|
|
250
|
+
if (value.length === 42 && value.startsWith("0x")) {
|
|
251
|
+
format = { name: "ethereum-pubkey" };
|
|
252
|
+
return format;
|
|
253
|
+
}
|
|
254
|
+
// Nostr signer
|
|
255
|
+
if (value.length === 63 && value.startsWith("npub")) {
|
|
256
|
+
format = { name: "nostr-npub" };
|
|
257
|
+
return format;
|
|
258
|
+
}
|
|
259
|
+
// url
|
|
260
|
+
if (isValidUrl(value)) {
|
|
261
|
+
format = { name: "url" };
|
|
262
|
+
return format;
|
|
263
|
+
}
|
|
264
|
+
if (value.length === 64 &&
|
|
265
|
+
!value.startsWith("note") &&
|
|
266
|
+
!value.startsWith("nevent") &&
|
|
267
|
+
!value.startsWith("npub")) {
|
|
268
|
+
format = { name: "nostr-hex" };
|
|
269
|
+
return format;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (typeof (value) === "string") {
|
|
273
|
+
return format = { name: "string" };
|
|
274
|
+
}
|
|
275
|
+
return format;
|
|
276
|
+
};
|
|
277
|
+
export const getFormatFromId = (id) => {
|
|
278
|
+
return getFormatFromValue(id);
|
|
279
|
+
};
|
|
280
|
+
export const getFormatFromAddress = (address) => {
|
|
281
|
+
return getFormatFromValue(address);
|
|
282
|
+
};
|
|
283
|
+
export const getFormatFromSignature = (address) => {
|
|
284
|
+
return getFormatFromValue(address);
|
|
285
|
+
};
|
|
286
|
+
export const getHashOfString = (string, algorithm = "sha256") => {
|
|
287
|
+
if (typeof (string) !== "string")
|
|
288
|
+
return "";
|
|
289
|
+
if (algorithm === "sha256") {
|
|
290
|
+
return sha256(string);
|
|
291
|
+
}
|
|
292
|
+
return "";
|
|
293
|
+
};
|
|
294
|
+
// Keep only specified keys in an object.
|
|
295
|
+
export const keepTheseKeysInObject = (obj, keys) => {
|
|
296
|
+
return keys.reduce((acc, key) => {
|
|
297
|
+
if (obj.hasOwnProperty(key)) {
|
|
298
|
+
acc[key] = obj[key];
|
|
299
|
+
}
|
|
300
|
+
return acc;
|
|
301
|
+
}, {});
|
|
302
|
+
};
|
|
303
|
+
// Keep only specified keys in each object of an array.
|
|
304
|
+
export const keepTheseKeysInObjectsInArray = (array, keys) => {
|
|
305
|
+
return array.map(obj => keepTheseKeysInObject(obj, keys));
|
|
306
|
+
};
|
|
307
|
+
// This function only sorts string and number values.
|
|
308
|
+
export const sortArrayOfStringsAndNumbers = (array) => {
|
|
309
|
+
// Separate values into valid and invalid categories.
|
|
310
|
+
const { validValues, invalidValues } = array.reduce((acc, value) => {
|
|
311
|
+
if (typeof value === 'string' ||
|
|
312
|
+
typeof value === 'number') {
|
|
313
|
+
acc.validValues.push(value);
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
acc.invalidValues.push(value);
|
|
317
|
+
}
|
|
318
|
+
return acc;
|
|
319
|
+
}, { validValues: [], invalidValues: [] });
|
|
320
|
+
// Sort the valid values
|
|
321
|
+
const sortedValidValues = validValues.sort((a, b) => String(a).localeCompare(String(b)));
|
|
322
|
+
// Combine sorted valid values with invalid values
|
|
323
|
+
const result = [...sortedValidValues, ...invalidValues];
|
|
324
|
+
return result;
|
|
325
|
+
};
|
|
326
|
+
export const sortArrayOfObjects = (objects, sortBy = ["id"]) => {
|
|
327
|
+
if (!objects ||
|
|
328
|
+
!Array.isArray(objects) ||
|
|
329
|
+
!objects[0]) {
|
|
330
|
+
return [];
|
|
331
|
+
}
|
|
332
|
+
// Ensure sortBy is always treated as an array
|
|
333
|
+
const sortedBy = Array.isArray(sortBy) ? sortBy : [sortBy];
|
|
334
|
+
// Separate objects into valid and invalid categories based
|
|
335
|
+
// on the existence of the specified property(ies)
|
|
336
|
+
const { validObjects, invalidValues } = objects.reduce((acc, item) => {
|
|
337
|
+
let isValid = false;
|
|
338
|
+
// Only one prop should exist in item in order
|
|
339
|
+
// to make it a valid item.
|
|
340
|
+
sortedBy.forEach((key) => {
|
|
341
|
+
if (typeof (item) === 'object' && item &&
|
|
342
|
+
key in item && item[key] &&
|
|
343
|
+
(typeof (item[key]) === "string" ||
|
|
344
|
+
typeof (item[key]) === "number")) {
|
|
345
|
+
isValid = true;
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
if (isValid) {
|
|
349
|
+
acc.validObjects.push(item);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
acc.invalidValues.push(item);
|
|
353
|
+
}
|
|
354
|
+
return acc;
|
|
355
|
+
}, { validObjects: [], invalidValues: [] });
|
|
356
|
+
// Sort the valid objects by the specified property(ies)
|
|
357
|
+
const sortedValidObjects = validObjects.sort((a, b) => {
|
|
358
|
+
for (const key of sortedBy) {
|
|
359
|
+
const aValue = typeof a[key] === 'string' ? a[key] : String(a[key]);
|
|
360
|
+
const bValue = typeof b[key] === 'string' ? b[key] : String(b[key]);
|
|
361
|
+
const compareResult = aValue.localeCompare(bValue);
|
|
362
|
+
if (compareResult !== 0) {
|
|
363
|
+
return compareResult;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return 0; // Equal
|
|
367
|
+
});
|
|
368
|
+
const sortedInvalidValues = sortArrayOfStringsAndNumbers(invalidValues);
|
|
369
|
+
// Combine sorted valid objects with invalid objects
|
|
370
|
+
const result = [...sortedValidObjects, ...sortedInvalidValues];
|
|
371
|
+
return result;
|
|
372
|
+
};
|
|
373
|
+
export const sortAuthorsForSpasmEventV2 = (authors) => {
|
|
374
|
+
// Clean and sort addresses
|
|
375
|
+
authors.forEach(author => {
|
|
376
|
+
if (author && typeof (author) === "object" &&
|
|
377
|
+
'addresses' in author && author.addresses &&
|
|
378
|
+
Array.isArray(author.addresses) &&
|
|
379
|
+
author.addresses[0]) {
|
|
380
|
+
// Clean addresses to keep only 'value' and 'format' keys
|
|
381
|
+
// and remove 'verified' and 'hosts' keys.
|
|
382
|
+
author.addresses = keepTheseKeysInObjectsInArray(author.addresses, ["value", "format"]);
|
|
383
|
+
// Sort addresses
|
|
384
|
+
author.addresses = sortArrayOfObjects(author.addresses, "value");
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
// Clean and sort usernames
|
|
388
|
+
authors.forEach(author => {
|
|
389
|
+
if (author && typeof (author) === "object" &&
|
|
390
|
+
'usernames' in author && author.usernames &&
|
|
391
|
+
Array.isArray(author.usernames) &&
|
|
392
|
+
author.usernames[0]) {
|
|
393
|
+
// There is no need to clean usernames because all fields
|
|
394
|
+
// should be calculated for the Spasm ID 01.
|
|
395
|
+
// Sort usernames
|
|
396
|
+
author.usernames = sortArrayOfObjects(author.usernames, "value");
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
let authorsWithAddress = [];
|
|
400
|
+
// Authors without address are used temporary until we split
|
|
401
|
+
// them further depending on whether they have usernames.
|
|
402
|
+
let authorsWithoutAddress = [];
|
|
403
|
+
let authorsWithoutAddressWithUsername = [];
|
|
404
|
+
let authorsWithoutAddressWithoutUsername = [];
|
|
405
|
+
authors.forEach(author => {
|
|
406
|
+
if (author && typeof (author) === "object" &&
|
|
407
|
+
'addresses' in author && author.addresses &&
|
|
408
|
+
Array.isArray(author.addresses) && author.addresses[0] &&
|
|
409
|
+
author.addresses[0].value &&
|
|
410
|
+
(typeof (author.addresses[0].value) === "string" ||
|
|
411
|
+
typeof (author.addresses[0].value) === "number")) {
|
|
412
|
+
authorsWithAddress.push(author);
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
authorsWithoutAddress.push(author);
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
authorsWithoutAddress.forEach(author => {
|
|
419
|
+
if (author && typeof (author) === "object" &&
|
|
420
|
+
'usernames' in author && author.usernames &&
|
|
421
|
+
Array.isArray(author.usernames) && author.usernames[0] &&
|
|
422
|
+
author.usernames[0].value &&
|
|
423
|
+
(typeof (author.usernames[0].value) === "string" ||
|
|
424
|
+
typeof (author.usernames[0].value) === "number")) {
|
|
425
|
+
authorsWithoutAddressWithUsername.push(author);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
authorsWithoutAddressWithoutUsername.push(author);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
// Sort all 3 arrays
|
|
432
|
+
const sortedAuthorsWithAddress = sortArrayOfObjectsByKeyValue(authorsWithAddress, "addresses");
|
|
433
|
+
const sortedAuthorsWithoutAddressWithUsername = sortArrayOfObjectsByKeyValue(authorsWithoutAddressWithUsername, "usernames");
|
|
434
|
+
const sortedAuthorsWithoutAddressWithoutUsername = sortArrayOfObjects(authorsWithoutAddressWithoutUsername, ["id"]);
|
|
435
|
+
const result = [
|
|
436
|
+
...sortedAuthorsWithAddress,
|
|
437
|
+
...sortedAuthorsWithoutAddressWithUsername,
|
|
438
|
+
...sortedAuthorsWithoutAddressWithoutUsername
|
|
439
|
+
];
|
|
440
|
+
return result;
|
|
441
|
+
};
|
|
442
|
+
export const sortAuthorsForSpasmid01 = sortAuthorsForSpasmEventV2;
|
|
443
|
+
export const sortArrayOfObjectsByKeyValue = (objects, key) => {
|
|
444
|
+
const sortedObjects = objects.sort((a, b) => {
|
|
445
|
+
let aValue = "";
|
|
446
|
+
let bValue = "";
|
|
447
|
+
if (a[key] && a[key][0] &&
|
|
448
|
+
a[key][0].value) {
|
|
449
|
+
if (typeof (a[key][0].value) === 'string') {
|
|
450
|
+
aValue = a[key][0].value;
|
|
451
|
+
}
|
|
452
|
+
else if (typeof (a[key][0].value) === 'number') {
|
|
453
|
+
aValue = String(a[key][0].value);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (b[key] && b[key][0] &&
|
|
457
|
+
b[key][0].value) {
|
|
458
|
+
if (typeof (b[key][0].value) === 'string') {
|
|
459
|
+
bValue = b[key][0].value;
|
|
460
|
+
}
|
|
461
|
+
else if (typeof (b[key][0].value) === 'number') {
|
|
462
|
+
bValue = String(b[key][0].value);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
const compareResult = aValue.localeCompare(bValue);
|
|
466
|
+
if (compareResult !== 0) {
|
|
467
|
+
return compareResult;
|
|
468
|
+
}
|
|
469
|
+
return 0; // Equal
|
|
470
|
+
});
|
|
471
|
+
return sortedObjects;
|
|
472
|
+
};
|
|
473
|
+
export const sortHostsForSpasmEventV2 = (hosts) => {
|
|
474
|
+
if (!hosts ||
|
|
475
|
+
!Array.isArray(hosts) ||
|
|
476
|
+
!hosts[0]) {
|
|
477
|
+
return hosts;
|
|
478
|
+
}
|
|
479
|
+
const sortedHosts = sortArrayOfObjects(hosts, "value");
|
|
480
|
+
return sortedHosts;
|
|
481
|
+
};
|
|
482
|
+
export const sortHostsForSpasmid01 = sortHostsForSpasmEventV2;
|
|
483
|
+
export const sortLinksForSpasmEventV2 = sortHostsForSpasmEventV2;
|
|
484
|
+
export const sortLinksForSpasmid01 = sortLinksForSpasmEventV2;
|
|
485
|
+
export const sortMediasForSpasmid01 = (medias) => {
|
|
486
|
+
if (!medias || !Array.isArray(medias))
|
|
487
|
+
return [];
|
|
488
|
+
// Clean and sort IDs
|
|
489
|
+
medias.forEach(media => {
|
|
490
|
+
if (media && typeof (media) === "object" &&
|
|
491
|
+
'ids' in media && media.ids &&
|
|
492
|
+
Array.isArray(media.ids) &&
|
|
493
|
+
media.ids[0]) {
|
|
494
|
+
// Clean ids to keep only 'value' key
|
|
495
|
+
media.ids = keepTheseKeysInObjectsInArray(media.ids, ["value"]);
|
|
496
|
+
// Sort ids
|
|
497
|
+
media.ids = sortArrayOfObjects(media.ids, "value");
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
// Clean and sort hashes
|
|
501
|
+
medias.forEach(media => {
|
|
502
|
+
if (media && typeof (media) === "object" &&
|
|
503
|
+
'hashes' in media && media.hashes &&
|
|
504
|
+
Array.isArray(media.hashes) &&
|
|
505
|
+
media.hashes[0]) {
|
|
506
|
+
// Clean hashes to keep only 'value' key
|
|
507
|
+
media.hashes = keepTheseKeysInObjectsInArray(media.hashes, ["value"]);
|
|
508
|
+
// Sort hashes
|
|
509
|
+
media.hashes = sortArrayOfObjects(media.hashes, "value");
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
// Clean and sort links
|
|
513
|
+
medias.forEach(media => {
|
|
514
|
+
if (media && typeof (media) === "object" &&
|
|
515
|
+
'links' in media && media.links &&
|
|
516
|
+
Array.isArray(media.links) &&
|
|
517
|
+
media.links[0]) {
|
|
518
|
+
// Clean links to keep only 'value' key
|
|
519
|
+
media.links = keepTheseKeysInObjectsInArray(media.links, ["value"]);
|
|
520
|
+
// Sort links
|
|
521
|
+
media.links = sortArrayOfObjects(media.links, "value");
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
// mediasWithIds might also have hashes and links
|
|
525
|
+
let mediasWithIds = [];
|
|
526
|
+
let mediasWithoutIds = [];
|
|
527
|
+
// mediasWithHashes might also have links, but no ids
|
|
528
|
+
let mediasWithHashes = [];
|
|
529
|
+
let mediasWithoutIdsHashes = [];
|
|
530
|
+
// mediasWithLinks only has links, but no ids and hashes
|
|
531
|
+
let mediasWithLinks = [];
|
|
532
|
+
let mediasWithoutIdsHashesLinks = [];
|
|
533
|
+
// Sort medias by ids
|
|
534
|
+
medias.forEach(media => {
|
|
535
|
+
if (media && typeof (media) === "object" &&
|
|
536
|
+
'ids' in media && media.ids &&
|
|
537
|
+
Array.isArray(media.ids) && media.ids[0] &&
|
|
538
|
+
media.ids[0].value &&
|
|
539
|
+
(typeof (media.ids[0].value) === "string" ||
|
|
540
|
+
typeof (media.ids[0].value) === "number")) {
|
|
541
|
+
mediasWithIds.push(media);
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
mediasWithoutIds.push(media);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
// Sort medias by hashes
|
|
548
|
+
mediasWithoutIds.forEach(media => {
|
|
549
|
+
if (media && typeof (media) === "object" &&
|
|
550
|
+
'hashes' in media && media.hashes &&
|
|
551
|
+
Array.isArray(media.hashes) && media.hashes[0] &&
|
|
552
|
+
media.hashes[0].value &&
|
|
553
|
+
(typeof (media.hashes[0].value) === "string" ||
|
|
554
|
+
typeof (media.hashes[0].value) === "number")) {
|
|
555
|
+
mediasWithHashes.push(media);
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
mediasWithoutIdsHashes.push(media);
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
// Sort medias by links
|
|
562
|
+
mediasWithoutIdsHashes.forEach(media => {
|
|
563
|
+
if (media && typeof (media) === "object" &&
|
|
564
|
+
'links' in media && media.links &&
|
|
565
|
+
Array.isArray(media.links) && media.links[0] &&
|
|
566
|
+
media.links[0].value &&
|
|
567
|
+
(typeof (media.links[0].value) === "string" ||
|
|
568
|
+
typeof (media.links[0].value) === "number")) {
|
|
569
|
+
mediasWithLinks.push(media);
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
mediasWithoutIdsHashesLinks.push(media);
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
const mediasOther = mediasWithoutIdsHashesLinks;
|
|
576
|
+
// Sort all 3 arrays
|
|
577
|
+
const sortedMediasWithIds = sortArrayOfObjectsByKeyValue(mediasWithIds, "ids");
|
|
578
|
+
const sortedMediasWithHashes = sortArrayOfObjectsByKeyValue(mediasWithHashes, "hashes");
|
|
579
|
+
const sortedMediasWithLinks = sortArrayOfObjectsByKeyValue(mediasWithLinks, "links");
|
|
580
|
+
const sortedMediasOther = sortArrayOfObjects(mediasOther, ["id"]);
|
|
581
|
+
const result = [
|
|
582
|
+
...sortedMediasWithIds,
|
|
583
|
+
...sortedMediasWithHashes,
|
|
584
|
+
...sortedMediasWithLinks,
|
|
585
|
+
...sortedMediasOther
|
|
586
|
+
];
|
|
587
|
+
return result;
|
|
588
|
+
};
|
|
589
|
+
// Deprecated sortMediasForSpasmEventV2 because we only keep
|
|
590
|
+
// a 'value' key to calculate Spasm ID 01.
|
|
591
|
+
// export const sortMediasForSpasmid01 = sortMediasforSpasmEventV2
|
|
592
|
+
export const sortReferencesForSpasmid01 = (references) => {
|
|
593
|
+
if (!references || !Array.isArray(references))
|
|
594
|
+
return [];
|
|
595
|
+
// Clean and sort IDs
|
|
596
|
+
references.forEach(reference => {
|
|
597
|
+
if (reference && typeof (reference) === "object" &&
|
|
598
|
+
'ids' in reference && reference.ids &&
|
|
599
|
+
Array.isArray(reference.ids) &&
|
|
600
|
+
reference.ids[0]) {
|
|
601
|
+
// Clean ids to keep only 'value' key
|
|
602
|
+
reference.ids = keepTheseKeysInObjectsInArray(reference.ids, ["value"]);
|
|
603
|
+
// Sort ids
|
|
604
|
+
reference.ids = sortArrayOfObjects(reference.ids, "value");
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
// Sort references based on IDs
|
|
608
|
+
const sortedReferences = sortArrayOfObjectsByKeyValue(references, "ids");
|
|
609
|
+
return sortedReferences;
|
|
610
|
+
};
|
|
611
|
+
export const sortParentForSpasmid01 = (parent) => {
|
|
612
|
+
if (!parent || typeof (parent) !== "object")
|
|
613
|
+
return parent;
|
|
614
|
+
// Clean and sort IDs
|
|
615
|
+
if (parent && typeof (parent) === "object" &&
|
|
616
|
+
'ids' in parent && parent.ids &&
|
|
617
|
+
Array.isArray(parent.ids) &&
|
|
618
|
+
parent.ids[0]) {
|
|
619
|
+
// Clean ids to keep only 'value' key
|
|
620
|
+
parent.ids = keepTheseKeysInObjectsInArray(parent.ids, ["value"]);
|
|
621
|
+
// Sort ids
|
|
622
|
+
parent.ids = sortArrayOfObjects(parent.ids, "value");
|
|
623
|
+
}
|
|
624
|
+
return parent;
|
|
625
|
+
};
|
|
626
|
+
export const sortTagsForSpasmid01 = (tags) => {
|
|
627
|
+
if (!tags || !Array.isArray(tags))
|
|
628
|
+
return [[]];
|
|
629
|
+
/**
|
|
630
|
+
* Tags are an array of arrays (e.g., Nostr tags).
|
|
631
|
+
* Each tag is an array with any number of elements.
|
|
632
|
+
* Some tags will have the same one-letter first element,
|
|
633
|
+
* so sorting by the first element is not a good approach.
|
|
634
|
+
* Instead, the current sorting logic for spasmid01 is
|
|
635
|
+
* to find the length of the longest tag array (e.g., 10),
|
|
636
|
+
* and start sorting tags by the 10th element, then
|
|
637
|
+
* by the 9th element, and continue until sorting is
|
|
638
|
+
* done by the first element.
|
|
639
|
+
*
|
|
640
|
+
* Each tag is an array of values. However, values inside
|
|
641
|
+
* each tag should not be sorted as it can affect the
|
|
642
|
+
* intention of the event. For example, the order of an
|
|
643
|
+
* element in a Nostr tag array has a meaning.
|
|
644
|
+
*/
|
|
645
|
+
const sortTagsByElementNumber = (elementNumber = 0) => {
|
|
646
|
+
tags = tags.sort((a, b) => {
|
|
647
|
+
const key = elementNumber;
|
|
648
|
+
let aValue = "";
|
|
649
|
+
let bValue = "";
|
|
650
|
+
if (a[key]) {
|
|
651
|
+
if (typeof (a[key]) === 'string') {
|
|
652
|
+
aValue = a[key];
|
|
653
|
+
}
|
|
654
|
+
else if (typeof (a[key]) === 'number') {
|
|
655
|
+
aValue = String(a[key]);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (b[key]) {
|
|
659
|
+
if (typeof (b[key]) === 'string') {
|
|
660
|
+
bValue = b[key];
|
|
661
|
+
}
|
|
662
|
+
else if (typeof (b[key]) === 'number') {
|
|
663
|
+
bValue = String(b[key]);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
const compareResult = aValue.localeCompare(bValue);
|
|
667
|
+
if (compareResult !== 0) {
|
|
668
|
+
return compareResult;
|
|
669
|
+
}
|
|
670
|
+
return 0; // Equal
|
|
671
|
+
});
|
|
672
|
+
};
|
|
673
|
+
let longestTagArrayLength = 1;
|
|
674
|
+
// Find the longest array (tag) to be used for sorting.
|
|
675
|
+
tags.forEach(tag => {
|
|
676
|
+
if (tag && Array.isArray(tag) &&
|
|
677
|
+
tag.length > longestTagArrayLength) {
|
|
678
|
+
longestTagArrayLength = tag.length;
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
for (let i = longestTagArrayLength; i >= 0; i--) {
|
|
682
|
+
sortTagsByElementNumber(i);
|
|
683
|
+
}
|
|
684
|
+
return tags;
|
|
685
|
+
};
|
|
686
|
+
export const markSpasmEventAddressAsVerified = (spasmEvent, verifiedAddress, version = "2.0.0") => {
|
|
687
|
+
if (version === "2.0.0") {
|
|
688
|
+
if (spasmEvent.authors) {
|
|
689
|
+
spasmEvent.authors.forEach(author => {
|
|
690
|
+
if (author.addresses) {
|
|
691
|
+
author.addresses.forEach(address => {
|
|
692
|
+
if (address.value === verifiedAddress) {
|
|
693
|
+
address.verified = true;
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
export const verifyEthereumSignature = (messageString, signature, signerAddress) => {
|
|
702
|
+
try {
|
|
703
|
+
if (signature && typeof (signature) === 'string') {
|
|
704
|
+
const recoveredAddress = ethers.verifyMessage(messageString, signature);
|
|
705
|
+
return recoveredAddress.toLowerCase() ===
|
|
706
|
+
signerAddress.toLowerCase();
|
|
707
|
+
}
|
|
708
|
+
return false;
|
|
709
|
+
}
|
|
710
|
+
catch (error) {
|
|
711
|
+
return false;
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
export const utilsStatus = () => {
|
|
715
|
+
console.log("spasm.js utils status: success");
|
|
716
|
+
};
|
|
717
|
+
// var sha256pure = function sha256(ascii) {
|
|
718
|
+
// function rightRotate(value, amount) {
|
|
719
|
+
// return (value>>>amount) | (value<<(32 - amount));
|
|
720
|
+
// };
|
|
721
|
+
//
|
|
722
|
+
// var mathPow = Math.pow;
|
|
723
|
+
// var maxWord = mathPow(2, 32);
|
|
724
|
+
// var lengthProperty = 'length'
|
|
725
|
+
// var i, j; // Used as a counter across the whole file
|
|
726
|
+
// var result = ''
|
|
727
|
+
//
|
|
728
|
+
// var words = [];
|
|
729
|
+
// var asciiBitLength = ascii[lengthProperty]*8;
|
|
730
|
+
//
|
|
731
|
+
// /[> caching results is optional - remove/add slash from front of this line to toggle
|
|
732
|
+
// // Initial hash value: first 32 bits of the fractional parts of the square roots of the first 8 primes
|
|
733
|
+
// // (we actually calculate the first 64, but extra values are just ignored)
|
|
734
|
+
// var hash = sha256.h = sha256.h || [];
|
|
735
|
+
// // Round constants: first 32 bits of the fractional parts of the cube roots of the first 64 primes
|
|
736
|
+
// var k = sha256.k = sha256.k || [];
|
|
737
|
+
// var primeCounter = k[lengthProperty];
|
|
738
|
+
// [>/
|
|
739
|
+
// var hash = [], k = [];
|
|
740
|
+
// var primeCounter = 0;
|
|
741
|
+
// /[>/
|
|
742
|
+
//
|
|
743
|
+
// var isComposite = {};
|
|
744
|
+
// for (var candidate = 2; primeCounter < 64; candidate++) {
|
|
745
|
+
// if (!isComposite[candidate]) {
|
|
746
|
+
// for (i = 0; i < 313; i += candidate) {
|
|
747
|
+
// isComposite[i] = candidate;
|
|
748
|
+
// }
|
|
749
|
+
// hash[primeCounter] = (mathPow(candidate, .5)*maxWord)|0;
|
|
750
|
+
// k[primeCounter++] = (mathPow(candidate, 1/3)*maxWord)|0;
|
|
751
|
+
// }
|
|
752
|
+
// }
|
|
753
|
+
//
|
|
754
|
+
// ascii += '\x80' // Append Ƈ' bit (plus zero padding)
|
|
755
|
+
// while (ascii[lengthProperty]%64 - 56) ascii += '\x00' // More zero padding
|
|
756
|
+
// for (i = 0; i < ascii[lengthProperty]; i++) {
|
|
757
|
+
// j = ascii.charCodeAt(i);
|
|
758
|
+
// if (j>>8) return; // ASCII check: only accept characters in range 0-255
|
|
759
|
+
// words[i>>2] |= j << ((3 - i)%4)*8;
|
|
760
|
+
// }
|
|
761
|
+
// words[words[lengthProperty]] = ((asciiBitLength/maxWord)|0);
|
|
762
|
+
// words[words[lengthProperty]] = (asciiBitLength)
|
|
763
|
+
//
|
|
764
|
+
// // process each chunk
|
|
765
|
+
// for (j = 0; j < words[lengthProperty];) {
|
|
766
|
+
// var w = words.slice(j, j += 16); // The message is expanded into 64 words as part of the iteration
|
|
767
|
+
// var oldHash = hash;
|
|
768
|
+
// // This is now the undefinedworking hash", often labelled as variables a...g
|
|
769
|
+
// // (we have to truncate as well, otherwise extra entries at the end accumulate
|
|
770
|
+
// hash = hash.slice(0, 8);
|
|
771
|
+
//
|
|
772
|
+
// for (i = 0; i < 64; i++) {
|
|
773
|
+
// // Typescript error: i2 value is never read
|
|
774
|
+
// var i2 = i + j;
|
|
775
|
+
// // Expand the message into 64 words
|
|
776
|
+
// // Used below if
|
|
777
|
+
// var w15 = w[i - 15], w2 = w[i - 2];
|
|
778
|
+
//
|
|
779
|
+
// // Iterate
|
|
780
|
+
// var a = hash[0], e = hash[4];
|
|
781
|
+
// var temp1 = hash[7]
|
|
782
|
+
// + (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) // S1
|
|
783
|
+
// + ((e&hash[5])^((~e)&hash[6])) // ch
|
|
784
|
+
// + k[i]
|
|
785
|
+
// // Expand the message schedule if needed
|
|
786
|
+
// + (w[i] = (i < 16) ? w[i] : (
|
|
787
|
+
// w[i - 16]
|
|
788
|
+
// + (rightRotate(w15, 7) ^ rightRotate(w15, 18) ^ (w15>>>3)) // s0
|
|
789
|
+
// + w[i - 7]
|
|
790
|
+
// + (rightRotate(w2, 17) ^ rightRotate(w2, 19) ^ (w2>>>10)) // s1
|
|
791
|
+
// )|0
|
|
792
|
+
// );
|
|
793
|
+
// // This is only used once, so *could* be moved below, but it only saves 4 bytes and makes things unreadble
|
|
794
|
+
// var temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) // S0
|
|
795
|
+
// + ((a&hash[1])^(a&hash[2])^(hash[1]&hash[2])); // maj
|
|
796
|
+
//
|
|
797
|
+
// hash = [(temp1 + temp2)|0].concat(hash); // We don't bother trimming off the extra ones, they're harmless as long as we're truncating when we do the slice()
|
|
798
|
+
// hash[4] = (hash[4] + temp1)|0;
|
|
799
|
+
// }
|
|
800
|
+
//
|
|
801
|
+
// for (i = 0; i < 8; i++) {
|
|
802
|
+
// hash[i] = (hash[i] + oldHash[i])|0;
|
|
803
|
+
// }
|
|
804
|
+
// }
|
|
805
|
+
//
|
|
806
|
+
// for (i = 0; i < 8; i++) {
|
|
807
|
+
// for (j = 3; j + 1; j--) {
|
|
808
|
+
// var b = (hash[i]>>(j*8))&255;
|
|
809
|
+
// result += ((b < 16) ? 0 : '') + b.toString(16);
|
|
810
|
+
// }
|
|
811
|
+
// }
|
|
812
|
+
// return result;
|
|
813
|
+
// };
|
|
115
814
|
//# sourceMappingURL=utils.js.map
|