@fluxpointstudios/orynq-sdk-flight-recorder 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/crypto/compression.d.ts +37 -0
- package/dist/crypto/compression.d.ts.map +1 -0
- package/dist/crypto/compression.js +84 -0
- package/dist/crypto/compression.js.map +1 -0
- package/dist/crypto/encryption.d.ts +44 -0
- package/dist/crypto/encryption.d.ts.map +1 -0
- package/dist/crypto/encryption.js +129 -0
- package/dist/crypto/encryption.js.map +1 -0
- package/dist/crypto/hashing.d.ts +63 -0
- package/dist/crypto/hashing.d.ts.map +1 -0
- package/dist/crypto/hashing.js +182 -0
- package/dist/crypto/hashing.js.map +1 -0
- package/dist/crypto/index.d.ts +4 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +4 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/integration/index.d.ts +2 -0
- package/dist/integration/index.d.ts.map +1 -0
- package/dist/integration/index.js +2 -0
- package/dist/integration/index.js.map +1 -0
- package/dist/integration/openclaw-adapter.d.ts +64 -0
- package/dist/integration/openclaw-adapter.d.ts.map +1 -0
- package/dist/integration/openclaw-adapter.js +137 -0
- package/dist/integration/openclaw-adapter.js.map +1 -0
- package/dist/manifest/index.d.ts +2 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +2 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/manifest-builder.d.ts +72 -0
- package/dist/manifest/manifest-builder.d.ts.map +1 -0
- package/dist/manifest/manifest-builder.js +84 -0
- package/dist/manifest/manifest-builder.js.map +1 -0
- package/dist/recorder/chunk-manager.d.ts +56 -0
- package/dist/recorder/chunk-manager.d.ts.map +1 -0
- package/dist/recorder/chunk-manager.js +172 -0
- package/dist/recorder/chunk-manager.js.map +1 -0
- package/dist/recorder/event-buffer.d.ts +61 -0
- package/dist/recorder/event-buffer.d.ts.map +1 -0
- package/dist/recorder/event-buffer.js +101 -0
- package/dist/recorder/event-buffer.js.map +1 -0
- package/dist/recorder/index.d.ts +4 -0
- package/dist/recorder/index.d.ts.map +1 -0
- package/dist/recorder/index.js +4 -0
- package/dist/recorder/index.js.map +1 -0
- package/dist/recorder/stream-recorder.d.ts +66 -0
- package/dist/recorder/stream-recorder.d.ts.map +1 -0
- package/dist/recorder/stream-recorder.js +329 -0
- package/dist/recorder/stream-recorder.js.map +1 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/local-adapter.d.ts +65 -0
- package/dist/storage/local-adapter.d.ts.map +1 -0
- package/dist/storage/local-adapter.js +152 -0
- package/dist/storage/local-adapter.js.map +1 -0
- package/dist/types.d.ts +284 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +28 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
- package/src/__tests__/flight-recorder.test.ts +211 -0
- package/src/crypto/compression.ts +105 -0
- package/src/crypto/encryption.ts +210 -0
- package/src/crypto/hashing.ts +225 -0
- package/src/crypto/index.ts +3 -0
- package/src/index.ts +96 -0
- package/src/integration/index.ts +1 -0
- package/src/integration/openclaw-adapter.ts +206 -0
- package/src/manifest/index.ts +1 -0
- package/src/manifest/manifest-builder.ts +152 -0
- package/src/recorder/chunk-manager.ts +224 -0
- package/src/recorder/event-buffer.ts +124 -0
- package/src/recorder/index.ts +3 -0
- package/src/recorder/stream-recorder.ts +427 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/local-adapter.ts +181 -0
- package/src/types.ts +347 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Flux Point Studios
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compression utilities for flight recorder chunks.
|
|
3
|
+
* Uses fflate for zstd-like compression (actually gzip/deflate, but fast).
|
|
4
|
+
*
|
|
5
|
+
* Note: True zstd would require native bindings. fflate provides
|
|
6
|
+
* excellent pure-JS compression that works everywhere.
|
|
7
|
+
*/
|
|
8
|
+
export type CompressionType = "gzip" | "none";
|
|
9
|
+
export interface CompressionResult {
|
|
10
|
+
data: Uint8Array;
|
|
11
|
+
originalSize: number;
|
|
12
|
+
compressedSize: number;
|
|
13
|
+
ratio: number;
|
|
14
|
+
algorithm: CompressionType;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Compress data using gzip.
|
|
18
|
+
*/
|
|
19
|
+
export declare function compress(data: Uint8Array, algorithm?: CompressionType): Promise<CompressionResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Decompress gzip data.
|
|
22
|
+
*/
|
|
23
|
+
export declare function decompress(data: Uint8Array, algorithm?: CompressionType): Promise<Uint8Array>;
|
|
24
|
+
/**
|
|
25
|
+
* Compress a string to bytes.
|
|
26
|
+
*/
|
|
27
|
+
export declare function compressString(str: string, algorithm?: CompressionType): Promise<CompressionResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Decompress bytes to a string.
|
|
30
|
+
*/
|
|
31
|
+
export declare function decompressString(data: Uint8Array, algorithm?: CompressionType): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Estimate if compression is worthwhile for the given data.
|
|
34
|
+
* Returns true if data is likely compressible (text, JSON, etc).
|
|
35
|
+
*/
|
|
36
|
+
export declare function isCompressible(data: Uint8Array, sampleSize?: number): boolean;
|
|
37
|
+
//# sourceMappingURL=compression.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compression.d.ts","sourceRoot":"","sources":["../../src/crypto/compression.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,UAAU,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,eAAe,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,GAAE,eAAwB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4B1G;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,GAAE,eAAwB,GAAG,OAAO,CAAC,UAAU,CAAC,CAgBrG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,eAAwB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAG3G;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,GAAE,eAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7G;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,SAAO,GAAG,OAAO,CAU3E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compression utilities for flight recorder chunks.
|
|
3
|
+
* Uses fflate for zstd-like compression (actually gzip/deflate, but fast).
|
|
4
|
+
*
|
|
5
|
+
* Note: True zstd would require native bindings. fflate provides
|
|
6
|
+
* excellent pure-JS compression that works everywhere.
|
|
7
|
+
*/
|
|
8
|
+
import { gzip, gunzip, strToU8, strFromU8 } from "fflate";
|
|
9
|
+
/**
|
|
10
|
+
* Compress data using gzip.
|
|
11
|
+
*/
|
|
12
|
+
export function compress(data, algorithm = "gzip") {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
if (algorithm === "none") {
|
|
15
|
+
resolve({
|
|
16
|
+
data,
|
|
17
|
+
originalSize: data.length,
|
|
18
|
+
compressedSize: data.length,
|
|
19
|
+
ratio: 1,
|
|
20
|
+
algorithm: "none",
|
|
21
|
+
});
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
gzip(data, { level: 6 }, (err, compressed) => {
|
|
25
|
+
if (err) {
|
|
26
|
+
reject(err);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
resolve({
|
|
30
|
+
data: compressed,
|
|
31
|
+
originalSize: data.length,
|
|
32
|
+
compressedSize: compressed.length,
|
|
33
|
+
ratio: compressed.length / data.length,
|
|
34
|
+
algorithm: "gzip",
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Decompress gzip data.
|
|
41
|
+
*/
|
|
42
|
+
export function decompress(data, algorithm = "gzip") {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
if (algorithm === "none") {
|
|
45
|
+
resolve(data);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
gunzip(data, (err, decompressed) => {
|
|
49
|
+
if (err) {
|
|
50
|
+
reject(err);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
resolve(decompressed);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Compress a string to bytes.
|
|
59
|
+
*/
|
|
60
|
+
export function compressString(str, algorithm = "gzip") {
|
|
61
|
+
const data = strToU8(str);
|
|
62
|
+
return compress(data, algorithm);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Decompress bytes to a string.
|
|
66
|
+
*/
|
|
67
|
+
export async function decompressString(data, algorithm = "gzip") {
|
|
68
|
+
const decompressed = await decompress(data, algorithm);
|
|
69
|
+
return strFromU8(decompressed);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Estimate if compression is worthwhile for the given data.
|
|
73
|
+
* Returns true if data is likely compressible (text, JSON, etc).
|
|
74
|
+
*/
|
|
75
|
+
export function isCompressible(data, sampleSize = 1024) {
|
|
76
|
+
// Sample the beginning of the data
|
|
77
|
+
const sample = data.slice(0, Math.min(sampleSize, data.length));
|
|
78
|
+
// Count unique bytes - highly compressible data has fewer unique values
|
|
79
|
+
const uniqueBytes = new Set(sample);
|
|
80
|
+
const uniqueRatio = uniqueBytes.size / sample.length;
|
|
81
|
+
// If less than 60% unique bytes, likely compressible
|
|
82
|
+
return uniqueRatio < 0.6;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=compression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compression.js","sourceRoot":"","sources":["../../src/crypto/compression.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAY1D;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAgB,EAAE,YAA6B,MAAM;IAC5E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACzB,OAAO,CAAC;gBACN,IAAI;gBACJ,YAAY,EAAE,IAAI,CAAC,MAAM;gBACzB,cAAc,EAAE,IAAI,CAAC,MAAM;gBAC3B,KAAK,EAAE,CAAC;gBACR,SAAS,EAAE,MAAM;aAClB,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE;YAC3C,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,CAAC,GAAG,CAAC,CAAC;gBACZ,OAAO;YACT,CAAC;YAED,OAAO,CAAC;gBACN,IAAI,EAAE,UAAU;gBAChB,YAAY,EAAE,IAAI,CAAC,MAAM;gBACzB,cAAc,EAAE,UAAU,CAAC,MAAM;gBACjC,KAAK,EAAE,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;gBACtC,SAAS,EAAE,MAAM;aAClB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAgB,EAAE,YAA6B,MAAM;IAC9E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;QACT,CAAC;QAED,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE;YACjC,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,CAAC,GAAG,CAAC,CAAC;gBACZ,OAAO;YACT,CAAC;YAED,OAAO,CAAC,YAAY,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,YAA6B,MAAM;IAC7E,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAgB,EAAE,YAA6B,MAAM;IAC1F,MAAM,YAAY,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACvD,OAAO,SAAS,CAAC,YAAY,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAgB,EAAE,UAAU,GAAG,IAAI;IAChE,mCAAmC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAEhE,wEAAwE;IACxE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;IAErD,qDAAqD;IACrD,OAAO,WAAW,GAAG,GAAG,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encryption utilities for flight recorder chunks.
|
|
3
|
+
* Uses Web Crypto API for AES-256-GCM encryption.
|
|
4
|
+
*/
|
|
5
|
+
export interface EncryptedData {
|
|
6
|
+
ciphertext: Uint8Array;
|
|
7
|
+
nonce: Uint8Array;
|
|
8
|
+
tag: Uint8Array;
|
|
9
|
+
}
|
|
10
|
+
export interface EncryptionKey {
|
|
11
|
+
keyId: string;
|
|
12
|
+
key: CryptoKey;
|
|
13
|
+
algorithm: "aes-256-gcm" | "chacha20-poly1305";
|
|
14
|
+
createdAt: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate a new AES-256-GCM encryption key.
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateKey(algorithm?: "aes-256-gcm" | "chacha20-poly1305"): Promise<EncryptionKey>;
|
|
20
|
+
/**
|
|
21
|
+
* Generate a random nonce/IV for AES-GCM (12 bytes recommended).
|
|
22
|
+
*/
|
|
23
|
+
export declare function generateNonce(): Uint8Array;
|
|
24
|
+
/**
|
|
25
|
+
* Encrypt data using AES-256-GCM.
|
|
26
|
+
*/
|
|
27
|
+
export declare function encrypt(data: Uint8Array, key: EncryptionKey, additionalData?: Uint8Array): Promise<EncryptedData>;
|
|
28
|
+
/**
|
|
29
|
+
* Decrypt data using AES-256-GCM.
|
|
30
|
+
*/
|
|
31
|
+
export declare function decrypt(encrypted: EncryptedData, key: EncryptionKey, additionalData?: Uint8Array): Promise<Uint8Array>;
|
|
32
|
+
/**
|
|
33
|
+
* Export key as raw bytes (for sealing/wrapping).
|
|
34
|
+
*/
|
|
35
|
+
export declare function exportKey(key: EncryptionKey): Promise<Uint8Array>;
|
|
36
|
+
/**
|
|
37
|
+
* Import key from raw bytes.
|
|
38
|
+
*/
|
|
39
|
+
export declare function importKey(rawKey: Uint8Array, keyId: string, algorithm?: "aes-256-gcm" | "chacha20-poly1305"): Promise<EncryptionKey>;
|
|
40
|
+
/**
|
|
41
|
+
* Derive a key from a master key using HKDF-SHA256.
|
|
42
|
+
*/
|
|
43
|
+
export declare function deriveKey(masterKey: Uint8Array, info: string, salt?: Uint8Array): Promise<EncryptionKey>;
|
|
44
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/crypto/encryption.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,UAAU,CAAC;IAClB,GAAG,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,SAAS,CAAC;IACf,SAAS,EAAE,aAAa,GAAG,mBAAmB,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,SAAS,GAAE,aAAa,GAAG,mBAAmC,GAAG,OAAO,CAAC,aAAa,CAAC,CAsBxH;AAaD;;GAEG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAI1C;AAED;;GAEG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,aAAa,EAClB,cAAc,CAAC,EAAE,UAAU,GAC1B,OAAO,CAAC,aAAa,CAAC,CA+BxB;AAED;;GAEG;AACH,wBAAsB,OAAO,CAC3B,SAAS,EAAE,aAAa,EACxB,GAAG,EAAE,aAAa,EAClB,cAAc,CAAC,EAAE,UAAU,GAC1B,OAAO,CAAC,UAAU,CAAC,CAsBrB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAGvE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,aAAa,GAAG,mBAAmC,GAC7D,OAAO,CAAC,aAAa,CAAC,CAexB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,UAAU,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,UAAU,GAChB,OAAO,CAAC,aAAa,CAAC,CA8BxB"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encryption utilities for flight recorder chunks.
|
|
3
|
+
* Uses Web Crypto API for AES-256-GCM encryption.
|
|
4
|
+
*/
|
|
5
|
+
import { webcrypto } from "node:crypto";
|
|
6
|
+
const crypto = webcrypto;
|
|
7
|
+
/**
|
|
8
|
+
* Generate a new AES-256-GCM encryption key.
|
|
9
|
+
*/
|
|
10
|
+
export async function generateKey(algorithm = "aes-256-gcm") {
|
|
11
|
+
if (algorithm === "chacha20-poly1305") {
|
|
12
|
+
// ChaCha20-Poly1305 not directly supported in Web Crypto
|
|
13
|
+
// Fall back to AES-GCM for now, can add libsodium later
|
|
14
|
+
console.warn("ChaCha20-Poly1305 not supported, using AES-256-GCM");
|
|
15
|
+
algorithm = "aes-256-gcm";
|
|
16
|
+
}
|
|
17
|
+
const key = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, // extractable for export/wrapping
|
|
18
|
+
["encrypt", "decrypt"]);
|
|
19
|
+
const keyId = generateKeyId();
|
|
20
|
+
return {
|
|
21
|
+
keyId,
|
|
22
|
+
key,
|
|
23
|
+
algorithm,
|
|
24
|
+
createdAt: new Date().toISOString(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Generate a random key ID.
|
|
29
|
+
*/
|
|
30
|
+
function generateKeyId() {
|
|
31
|
+
const bytes = new Uint8Array(16);
|
|
32
|
+
crypto.getRandomValues(bytes);
|
|
33
|
+
return Array.from(bytes)
|
|
34
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
35
|
+
.join("");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate a random nonce/IV for AES-GCM (12 bytes recommended).
|
|
39
|
+
*/
|
|
40
|
+
export function generateNonce() {
|
|
41
|
+
const nonce = new Uint8Array(12);
|
|
42
|
+
crypto.getRandomValues(nonce);
|
|
43
|
+
return nonce;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Encrypt data using AES-256-GCM.
|
|
47
|
+
*/
|
|
48
|
+
export async function encrypt(data, key, additionalData) {
|
|
49
|
+
const nonce = generateNonce();
|
|
50
|
+
const params = {
|
|
51
|
+
name: "AES-GCM",
|
|
52
|
+
iv: nonce,
|
|
53
|
+
tagLength: 128, // 16 bytes
|
|
54
|
+
};
|
|
55
|
+
if (additionalData) {
|
|
56
|
+
params.additionalData = additionalData;
|
|
57
|
+
}
|
|
58
|
+
const ciphertextWithTag = await crypto.subtle.encrypt(params, key.key, data);
|
|
59
|
+
const ciphertextWithTagArray = new Uint8Array(ciphertextWithTag);
|
|
60
|
+
// AES-GCM appends the tag to the ciphertext
|
|
61
|
+
// Split them for clarity in our data structure
|
|
62
|
+
const tagStart = ciphertextWithTagArray.length - 16;
|
|
63
|
+
const ciphertext = ciphertextWithTagArray.slice(0, tagStart);
|
|
64
|
+
const tag = ciphertextWithTagArray.slice(tagStart);
|
|
65
|
+
return {
|
|
66
|
+
ciphertext,
|
|
67
|
+
nonce,
|
|
68
|
+
tag,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Decrypt data using AES-256-GCM.
|
|
73
|
+
*/
|
|
74
|
+
export async function decrypt(encrypted, key, additionalData) {
|
|
75
|
+
// Reconstruct ciphertext with tag appended
|
|
76
|
+
const ciphertextWithTag = new Uint8Array(encrypted.ciphertext.length + encrypted.tag.length);
|
|
77
|
+
ciphertextWithTag.set(encrypted.ciphertext, 0);
|
|
78
|
+
ciphertextWithTag.set(encrypted.tag, encrypted.ciphertext.length);
|
|
79
|
+
const decryptParams = {
|
|
80
|
+
name: "AES-GCM",
|
|
81
|
+
iv: encrypted.nonce,
|
|
82
|
+
tagLength: 128,
|
|
83
|
+
};
|
|
84
|
+
if (additionalData) {
|
|
85
|
+
decryptParams.additionalData = additionalData;
|
|
86
|
+
}
|
|
87
|
+
const plaintext = await crypto.subtle.decrypt(decryptParams, key.key, ciphertextWithTag);
|
|
88
|
+
return new Uint8Array(plaintext);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Export key as raw bytes (for sealing/wrapping).
|
|
92
|
+
*/
|
|
93
|
+
export async function exportKey(key) {
|
|
94
|
+
const rawKey = await crypto.subtle.exportKey("raw", key.key);
|
|
95
|
+
return new Uint8Array(rawKey);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Import key from raw bytes.
|
|
99
|
+
*/
|
|
100
|
+
export async function importKey(rawKey, keyId, algorithm = "aes-256-gcm") {
|
|
101
|
+
const key = await crypto.subtle.importKey("raw", rawKey, { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]);
|
|
102
|
+
return {
|
|
103
|
+
keyId,
|
|
104
|
+
key,
|
|
105
|
+
algorithm,
|
|
106
|
+
createdAt: new Date().toISOString(),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Derive a key from a master key using HKDF-SHA256.
|
|
111
|
+
*/
|
|
112
|
+
export async function deriveKey(masterKey, info, salt) {
|
|
113
|
+
const baseKey = await crypto.subtle.importKey("raw", masterKey, "HKDF", false, ["deriveKey"]);
|
|
114
|
+
const saltBuffer = salt ?? new Uint8Array(32);
|
|
115
|
+
const infoBuffer = new TextEncoder().encode(info);
|
|
116
|
+
const derivedKey = await crypto.subtle.deriveKey({
|
|
117
|
+
name: "HKDF",
|
|
118
|
+
hash: "SHA-256",
|
|
119
|
+
salt: saltBuffer,
|
|
120
|
+
info: infoBuffer,
|
|
121
|
+
}, baseKey, { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]);
|
|
122
|
+
return {
|
|
123
|
+
keyId: generateKeyId(),
|
|
124
|
+
key: derivedKey,
|
|
125
|
+
algorithm: "aes-256-gcm",
|
|
126
|
+
createdAt: new Date().toISOString(),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=encryption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/crypto/encryption.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hashing utilities for flight recorder.
|
|
3
|
+
* Provides consistent SHA-256 hashing with domain separation.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Hash domain prefixes for different data types.
|
|
7
|
+
*/
|
|
8
|
+
export declare const HASH_DOMAINS: {
|
|
9
|
+
readonly event: "poi-flight:event:v2|";
|
|
10
|
+
readonly chunk: "poi-flight:chunk:v2|";
|
|
11
|
+
readonly manifest: "poi-flight:manifest:v2|";
|
|
12
|
+
readonly roll: "poi-flight:roll:v2|";
|
|
13
|
+
readonly merkleLeaf: "poi-flight:leaf:v2|";
|
|
14
|
+
readonly merkleNode: "poi-flight:node:v2|";
|
|
15
|
+
readonly encryptedChunk: "poi-flight:encrypted:v2|";
|
|
16
|
+
};
|
|
17
|
+
export type HashDomain = keyof typeof HASH_DOMAINS;
|
|
18
|
+
/**
|
|
19
|
+
* Compute SHA-256 hash of data with domain separation.
|
|
20
|
+
*/
|
|
21
|
+
export declare function sha256(data: Uint8Array, domain?: HashDomain): Promise<string>;
|
|
22
|
+
/**
|
|
23
|
+
* Compute SHA-256 hash of a string.
|
|
24
|
+
*/
|
|
25
|
+
export declare function sha256String(str: string, domain?: HashDomain): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Compute SHA-256 hash of JSON-serializable data.
|
|
28
|
+
*/
|
|
29
|
+
export declare function sha256Json(obj: unknown, domain?: HashDomain): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Compute rolling hash by combining previous hash with new data.
|
|
32
|
+
*/
|
|
33
|
+
export declare function rollingHash(prevHash: string, newData: Uint8Array): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Compute Merkle tree leaf hash.
|
|
36
|
+
*/
|
|
37
|
+
export declare function merkleLeaf(data: Uint8Array): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Compute Merkle tree internal node hash.
|
|
40
|
+
*/
|
|
41
|
+
export declare function merkleNode(left: string, right: string): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Build a Merkle tree from leaf hashes and return the root.
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildMerkleRoot(leafHashes: string[]): Promise<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Generate a Merkle proof for a leaf at the given index.
|
|
48
|
+
*/
|
|
49
|
+
export interface MerkleProof {
|
|
50
|
+
leafIndex: number;
|
|
51
|
+
leafHash: string;
|
|
52
|
+
siblings: Array<{
|
|
53
|
+
hash: string;
|
|
54
|
+
position: "left" | "right";
|
|
55
|
+
}>;
|
|
56
|
+
root: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function generateMerkleProof(leafHashes: string[], leafIndex: number): Promise<MerkleProof>;
|
|
59
|
+
/**
|
|
60
|
+
* Verify a Merkle proof.
|
|
61
|
+
*/
|
|
62
|
+
export declare function verifyMerkleProof(proof: MerkleProof): Promise<boolean>;
|
|
63
|
+
//# sourceMappingURL=hashing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashing.d.ts","sourceRoot":"","sources":["../../src/crypto/hashing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;CAQf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,YAAY,CAAC;AAEnD;;GAEG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAanF;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAGpF;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAMxF;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAElE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO7E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC3E;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAkDtB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAY5E"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hashing utilities for flight recorder.
|
|
3
|
+
* Provides consistent SHA-256 hashing with domain separation.
|
|
4
|
+
*/
|
|
5
|
+
import { webcrypto } from "node:crypto";
|
|
6
|
+
const crypto = webcrypto;
|
|
7
|
+
/**
|
|
8
|
+
* Hash domain prefixes for different data types.
|
|
9
|
+
*/
|
|
10
|
+
export const HASH_DOMAINS = {
|
|
11
|
+
event: "poi-flight:event:v2|",
|
|
12
|
+
chunk: "poi-flight:chunk:v2|",
|
|
13
|
+
manifest: "poi-flight:manifest:v2|",
|
|
14
|
+
roll: "poi-flight:roll:v2|",
|
|
15
|
+
merkleLeaf: "poi-flight:leaf:v2|",
|
|
16
|
+
merkleNode: "poi-flight:node:v2|",
|
|
17
|
+
encryptedChunk: "poi-flight:encrypted:v2|",
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Compute SHA-256 hash of data with domain separation.
|
|
21
|
+
*/
|
|
22
|
+
export async function sha256(data, domain) {
|
|
23
|
+
let input = data;
|
|
24
|
+
if (domain) {
|
|
25
|
+
const prefix = new TextEncoder().encode(HASH_DOMAINS[domain]);
|
|
26
|
+
const combined = new Uint8Array(prefix.length + data.length);
|
|
27
|
+
combined.set(prefix, 0);
|
|
28
|
+
combined.set(data, prefix.length);
|
|
29
|
+
input = combined;
|
|
30
|
+
}
|
|
31
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", input);
|
|
32
|
+
return bufferToHex(new Uint8Array(hashBuffer));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Compute SHA-256 hash of a string.
|
|
36
|
+
*/
|
|
37
|
+
export async function sha256String(str, domain) {
|
|
38
|
+
const data = new TextEncoder().encode(str);
|
|
39
|
+
return sha256(data, domain);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Compute SHA-256 hash of JSON-serializable data.
|
|
43
|
+
*/
|
|
44
|
+
export async function sha256Json(obj, domain) {
|
|
45
|
+
const json = JSON.stringify(obj, null, 0);
|
|
46
|
+
return sha256String(json, domain);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Compute rolling hash by combining previous hash with new data.
|
|
50
|
+
*/
|
|
51
|
+
export async function rollingHash(prevHash, newData) {
|
|
52
|
+
const prevBytes = hexToBuffer(prevHash);
|
|
53
|
+
const combined = new Uint8Array(prevBytes.length + newData.length);
|
|
54
|
+
combined.set(prevBytes, 0);
|
|
55
|
+
combined.set(newData, prevBytes.length);
|
|
56
|
+
return sha256(combined, "roll");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Compute Merkle tree leaf hash.
|
|
60
|
+
*/
|
|
61
|
+
export async function merkleLeaf(data) {
|
|
62
|
+
return sha256(data, "merkleLeaf");
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compute Merkle tree internal node hash.
|
|
66
|
+
*/
|
|
67
|
+
export async function merkleNode(left, right) {
|
|
68
|
+
const leftBytes = hexToBuffer(left);
|
|
69
|
+
const rightBytes = hexToBuffer(right);
|
|
70
|
+
const combined = new Uint8Array(leftBytes.length + rightBytes.length);
|
|
71
|
+
combined.set(leftBytes, 0);
|
|
72
|
+
combined.set(rightBytes, leftBytes.length);
|
|
73
|
+
return sha256(combined, "merkleNode");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Build a Merkle tree from leaf hashes and return the root.
|
|
77
|
+
*/
|
|
78
|
+
export async function buildMerkleRoot(leafHashes) {
|
|
79
|
+
if (leafHashes.length === 0) {
|
|
80
|
+
// Empty tree - hash of empty string
|
|
81
|
+
return sha256(new Uint8Array(0), "merkleNode");
|
|
82
|
+
}
|
|
83
|
+
if (leafHashes.length === 1) {
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
85
|
+
return leafHashes[0];
|
|
86
|
+
}
|
|
87
|
+
// Build tree level by level
|
|
88
|
+
let currentLevel = leafHashes;
|
|
89
|
+
while (currentLevel.length > 1) {
|
|
90
|
+
const nextLevel = [];
|
|
91
|
+
for (let i = 0; i < currentLevel.length; i += 2) {
|
|
92
|
+
const left = currentLevel[i];
|
|
93
|
+
const right = currentLevel[i + 1];
|
|
94
|
+
if (left !== undefined && right !== undefined) {
|
|
95
|
+
// Pair exists
|
|
96
|
+
const nodeHash = await merkleNode(left, right);
|
|
97
|
+
nextLevel.push(nodeHash);
|
|
98
|
+
}
|
|
99
|
+
else if (left !== undefined) {
|
|
100
|
+
// Odd element - promote to next level
|
|
101
|
+
nextLevel.push(left);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
currentLevel = nextLevel;
|
|
105
|
+
}
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
107
|
+
return currentLevel[0];
|
|
108
|
+
}
|
|
109
|
+
export async function generateMerkleProof(leafHashes, leafIndex) {
|
|
110
|
+
if (leafIndex < 0 || leafIndex >= leafHashes.length) {
|
|
111
|
+
throw new Error(`Invalid leaf index: ${leafIndex}`);
|
|
112
|
+
}
|
|
113
|
+
const siblings = [];
|
|
114
|
+
let currentLevel = leafHashes;
|
|
115
|
+
let currentIndex = leafIndex;
|
|
116
|
+
while (currentLevel.length > 1) {
|
|
117
|
+
const isLeft = currentIndex % 2 === 0;
|
|
118
|
+
const siblingIndex = isLeft ? currentIndex + 1 : currentIndex - 1;
|
|
119
|
+
const siblingHash = currentLevel[siblingIndex];
|
|
120
|
+
if (siblingIndex < currentLevel.length && siblingHash !== undefined) {
|
|
121
|
+
siblings.push({
|
|
122
|
+
hash: siblingHash,
|
|
123
|
+
position: isLeft ? "right" : "left",
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Build next level
|
|
127
|
+
const nextLevel = [];
|
|
128
|
+
for (let i = 0; i < currentLevel.length; i += 2) {
|
|
129
|
+
const left = currentLevel[i];
|
|
130
|
+
const right = currentLevel[i + 1];
|
|
131
|
+
if (left !== undefined && right !== undefined) {
|
|
132
|
+
const nodeHash = await merkleNode(left, right);
|
|
133
|
+
nextLevel.push(nodeHash);
|
|
134
|
+
}
|
|
135
|
+
else if (left !== undefined) {
|
|
136
|
+
nextLevel.push(left);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
currentLevel = nextLevel;
|
|
140
|
+
currentIndex = Math.floor(currentIndex / 2);
|
|
141
|
+
}
|
|
142
|
+
const leafHash = leafHashes[leafIndex];
|
|
143
|
+
const root = currentLevel[0];
|
|
144
|
+
if (leafHash === undefined || root === undefined) {
|
|
145
|
+
throw new Error("Invalid merkle tree state");
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
leafIndex,
|
|
149
|
+
leafHash,
|
|
150
|
+
siblings,
|
|
151
|
+
root,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Verify a Merkle proof.
|
|
156
|
+
*/
|
|
157
|
+
export async function verifyMerkleProof(proof) {
|
|
158
|
+
let currentHash = proof.leafHash;
|
|
159
|
+
for (const sibling of proof.siblings) {
|
|
160
|
+
if (sibling.position === "left") {
|
|
161
|
+
currentHash = await merkleNode(sibling.hash, currentHash);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
currentHash = await merkleNode(currentHash, sibling.hash);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return currentHash === proof.root;
|
|
168
|
+
}
|
|
169
|
+
// === Utility functions ===
|
|
170
|
+
function bufferToHex(buffer) {
|
|
171
|
+
return Array.from(buffer)
|
|
172
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
173
|
+
.join("");
|
|
174
|
+
}
|
|
175
|
+
function hexToBuffer(hex) {
|
|
176
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
177
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
178
|
+
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
179
|
+
}
|
|
180
|
+
return bytes;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=hashing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashing.js","sourceRoot":"","sources":["../../src/crypto/hashing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC"}
|