@bandeira-tech/b3nd-save 0.8.1

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.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/esm/_dnt.shims.d.ts +2 -0
  3. package/esm/_dnt.shims.d.ts.map +1 -0
  4. package/esm/_dnt.shims.js +57 -0
  5. package/esm/byte-entity-shim.d.ts +47 -0
  6. package/esm/byte-entity-shim.d.ts.map +1 -0
  7. package/esm/byte-entity-shim.js +138 -0
  8. package/esm/clients/mod.d.ts +15 -0
  9. package/esm/clients/mod.d.ts.map +1 -0
  10. package/esm/clients/mod.js +14 -0
  11. package/esm/clients/save-client.d.ts +87 -0
  12. package/esm/clients/save-client.d.ts.map +1 -0
  13. package/esm/clients/save-client.js +174 -0
  14. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts +40 -0
  15. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts.map +1 -0
  16. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.js +31 -0
  17. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.d.ts +30 -0
  18. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.d.ts.map +1 -0
  19. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.js +70 -0
  20. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.d.ts +16 -0
  21. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.d.ts.map +1 -0
  22. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.js +50 -0
  23. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts +235 -0
  24. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts.map +1 -0
  25. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.js +619 -0
  26. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.d.ts +43 -0
  27. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.d.ts.map +1 -0
  28. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.js +54 -0
  29. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts +47 -0
  30. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts.map +1 -0
  31. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.js +134 -0
  32. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.d.ts +20 -0
  33. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.d.ts.map +1 -0
  34. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.js +34 -0
  35. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.d.ts +46 -0
  36. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.d.ts.map +1 -0
  37. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.js +131 -0
  38. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.d.ts +27 -0
  39. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.d.ts.map +1 -0
  40. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.js +25 -0
  41. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.d.ts +59 -0
  42. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.d.ts.map +1 -0
  43. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.js +188 -0
  44. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts +35 -0
  45. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts.map +1 -0
  46. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.js +57 -0
  47. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.d.ts +117 -0
  48. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.d.ts.map +1 -0
  49. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.js +125 -0
  50. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.d.ts +112 -0
  51. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.d.ts.map +1 -0
  52. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.js +21 -0
  53. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.d.ts +35 -0
  54. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.d.ts.map +1 -0
  55. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.js +106 -0
  56. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts +88 -0
  57. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts.map +1 -0
  58. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.js +86 -0
  59. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.d.ts +83 -0
  60. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.d.ts.map +1 -0
  61. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.js +115 -0
  62. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.d.ts +164 -0
  63. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.d.ts.map +1 -0
  64. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.js +67 -0
  65. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.d.ts +99 -0
  66. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.d.ts.map +1 -0
  67. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.js +190 -0
  68. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.d.ts +185 -0
  69. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.d.ts.map +1 -0
  70. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.js +103 -0
  71. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.d.ts +58 -0
  72. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.d.ts.map +1 -0
  73. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.js +64 -0
  74. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts +295 -0
  75. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts.map +1 -0
  76. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.js +898 -0
  77. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts +167 -0
  78. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts.map +1 -0
  79. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.js +5 -0
  80. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts +278 -0
  81. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts.map +1 -0
  82. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.js +89 -0
  83. package/esm/dispatch.d.ts +35 -0
  84. package/esm/dispatch.d.ts.map +1 -0
  85. package/esm/dispatch.js +40 -0
  86. package/esm/elasticsearch/mod.d.ts +31 -0
  87. package/esm/elasticsearch/mod.d.ts.map +1 -0
  88. package/esm/elasticsearch/mod.js +8 -0
  89. package/esm/elasticsearch/store.d.ts +44 -0
  90. package/esm/elasticsearch/store.d.ts.map +1 -0
  91. package/esm/elasticsearch/store.js +213 -0
  92. package/esm/entity-store.d.ts +106 -0
  93. package/esm/entity-store.d.ts.map +1 -0
  94. package/esm/entity-store.js +46 -0
  95. package/esm/entity.d.ts +125 -0
  96. package/esm/entity.d.ts.map +1 -0
  97. package/esm/entity.js +66 -0
  98. package/esm/errors.d.ts +23 -0
  99. package/esm/errors.d.ts.map +1 -0
  100. package/esm/errors.js +25 -0
  101. package/esm/fs/mod.d.ts +28 -0
  102. package/esm/fs/mod.d.ts.map +1 -0
  103. package/esm/fs/mod.js +13 -0
  104. package/esm/fs/store.d.ts +45 -0
  105. package/esm/fs/store.d.ts.map +1 -0
  106. package/esm/fs/store.js +194 -0
  107. package/esm/indexeddb/mod.d.ts +9 -0
  108. package/esm/indexeddb/mod.d.ts.map +1 -0
  109. package/esm/indexeddb/mod.js +8 -0
  110. package/esm/indexeddb/store.d.ts +47 -0
  111. package/esm/indexeddb/store.d.ts.map +1 -0
  112. package/esm/indexeddb/store.js +299 -0
  113. package/esm/ipfs/mod.d.ts +24 -0
  114. package/esm/ipfs/mod.d.ts.map +1 -0
  115. package/esm/ipfs/mod.js +13 -0
  116. package/esm/ipfs/store.d.ts +42 -0
  117. package/esm/ipfs/store.d.ts.map +1 -0
  118. package/esm/ipfs/store.js +197 -0
  119. package/esm/localstorage/mod.d.ts +9 -0
  120. package/esm/localstorage/mod.d.ts.map +1 -0
  121. package/esm/localstorage/mod.js +8 -0
  122. package/esm/localstorage/store.d.ts +45 -0
  123. package/esm/localstorage/store.d.ts.map +1 -0
  124. package/esm/localstorage/store.js +147 -0
  125. package/esm/memory/mod.d.ts +12 -0
  126. package/esm/memory/mod.d.ts.map +1 -0
  127. package/esm/memory/mod.js +11 -0
  128. package/esm/memory/store.d.ts +73 -0
  129. package/esm/memory/store.d.ts.map +1 -0
  130. package/esm/memory/store.js +300 -0
  131. package/esm/mod.d.ts +36 -0
  132. package/esm/mod.d.ts.map +1 -0
  133. package/esm/mod.js +31 -0
  134. package/esm/mongo/mod.d.ts +35 -0
  135. package/esm/mongo/mod.d.ts.map +1 -0
  136. package/esm/mongo/mod.js +8 -0
  137. package/esm/mongo/store.d.ts +42 -0
  138. package/esm/mongo/store.d.ts.map +1 -0
  139. package/esm/mongo/store.js +185 -0
  140. package/esm/package.json +3 -0
  141. package/esm/payload.d.ts +24 -0
  142. package/esm/payload.d.ts.map +1 -0
  143. package/esm/payload.js +30 -0
  144. package/esm/postgres/columns.d.ts +33 -0
  145. package/esm/postgres/columns.d.ts.map +1 -0
  146. package/esm/postgres/columns.js +51 -0
  147. package/esm/postgres/mod.d.ts +19 -0
  148. package/esm/postgres/mod.d.ts.map +1 -0
  149. package/esm/postgres/mod.js +9 -0
  150. package/esm/postgres/store.d.ts +75 -0
  151. package/esm/postgres/store.d.ts.map +1 -0
  152. package/esm/postgres/store.js +364 -0
  153. package/esm/read.d.ts +40 -0
  154. package/esm/read.d.ts.map +1 -0
  155. package/esm/read.js +67 -0
  156. package/esm/s3/mod.d.ts +23 -0
  157. package/esm/s3/mod.d.ts.map +1 -0
  158. package/esm/s3/mod.js +13 -0
  159. package/esm/s3/store.d.ts +46 -0
  160. package/esm/s3/store.d.ts.map +1 -0
  161. package/esm/s3/store.js +183 -0
  162. package/esm/sqlite/mod.d.ts +18 -0
  163. package/esm/sqlite/mod.d.ts.map +1 -0
  164. package/esm/sqlite/mod.js +8 -0
  165. package/esm/sqlite/schema.d.ts +10 -0
  166. package/esm/sqlite/schema.d.ts.map +1 -0
  167. package/esm/sqlite/schema.js +26 -0
  168. package/esm/sqlite/store.d.ts +42 -0
  169. package/esm/sqlite/store.d.ts.map +1 -0
  170. package/esm/sqlite/store.js +184 -0
  171. package/esm/types.d.ts +101 -0
  172. package/esm/types.d.ts.map +1 -0
  173. package/esm/types.js +21 -0
  174. package/esm/url.d.ts +108 -0
  175. package/esm/url.d.ts.map +1 -0
  176. package/esm/url.js +151 -0
  177. package/package.json +93 -0
@@ -0,0 +1,619 @@
1
+ import { decodeBase64, decodeHex, encodeBase64, encodeHex, } from "../encoding/encoding.js";
2
+ import _canonicalize from "canonicalize";
3
+ // CJS/ESM interop: cast to callable
4
+ const canonicalize = _canonicalize;
5
+ export class IdentityKey {
6
+ privateKey;
7
+ publicKeyHex;
8
+ constructor(privateKey, publicKeyHex) {
9
+ this.privateKey = privateKey;
10
+ this.publicKeyHex = publicKeyHex;
11
+ }
12
+ static async generate() {
13
+ const pair = await generateSigningKeyPair();
14
+ const privateKeyPem = await exportPrivateKeyPem(pair.privateKey, "PRIVATE KEY");
15
+ return {
16
+ key: new IdentityKey(pair.privateKey, pair.publicKeyHex),
17
+ privateKeyPem,
18
+ publicKeyHex: pair.publicKeyHex,
19
+ };
20
+ }
21
+ static async fromPem(pem, publicKeyHex) {
22
+ const privateKey = await pemToCryptoKey(pem, "Ed25519");
23
+ return new IdentityKey(privateKey, publicKeyHex);
24
+ }
25
+ static async fromHex(params) {
26
+ const privateKeyBytes = decodeHex(params.privateKeyHex).buffer;
27
+ const privateKey = await crypto.subtle.importKey("pkcs8", privateKeyBytes, { name: "Ed25519", namedCurve: "Ed25519" }, false, ["sign"]);
28
+ return new IdentityKey(privateKey, params.publicKeyHex);
29
+ }
30
+ async sign(payload) {
31
+ return await sign(this.privateKey, payload);
32
+ }
33
+ }
34
+ export class PublicEncryptionKey {
35
+ publicKeyHex;
36
+ publicKey;
37
+ constructor(publicKeyHex, publicKey) {
38
+ this.publicKeyHex = publicKeyHex;
39
+ this.publicKey = publicKey;
40
+ }
41
+ static async fromHex(publicKeyHex) {
42
+ const publicKeyBytes = decodeHex(publicKeyHex).buffer;
43
+ const publicKey = await crypto.subtle.importKey("raw", publicKeyBytes, { name: "X25519", namedCurve: "X25519" }, false, []);
44
+ return new PublicEncryptionKey(publicKeyHex, publicKey);
45
+ }
46
+ static async generatePair() {
47
+ const pair = await generateEncryptionKeyPair();
48
+ const privateKeyBytes = new Uint8Array(await crypto.subtle.exportKey("pkcs8", pair.privateKey));
49
+ return {
50
+ publicKey: new PublicEncryptionKey(pair.publicKeyHex, pair.publicKey),
51
+ privateKeyHex: encodeHex(privateKeyBytes),
52
+ };
53
+ }
54
+ async encrypt(data) {
55
+ return await encrypt(data, this.publicKeyHex);
56
+ }
57
+ toHex() {
58
+ return this.publicKeyHex;
59
+ }
60
+ }
61
+ export class SecretEncryptionKey {
62
+ keyHex;
63
+ constructor(keyHex) {
64
+ this.keyHex = keyHex;
65
+ }
66
+ static async fromSecret(params) {
67
+ const keyHex = await deriveKeyFromSeed(params.secret, params.salt, params.iterations ?? 600000);
68
+ return new SecretEncryptionKey(keyHex);
69
+ }
70
+ static fromHex(keyHex) {
71
+ return new SecretEncryptionKey(keyHex);
72
+ }
73
+ async encrypt(data) {
74
+ return await encryptSymmetric(data, this.keyHex);
75
+ }
76
+ async decrypt(payload) {
77
+ return await decryptSymmetric(payload, this.keyHex);
78
+ }
79
+ }
80
+ export class PrivateEncryptionKey {
81
+ privateKey;
82
+ privateKeyHex;
83
+ publicKeyHex;
84
+ constructor(privateKey, privateKeyHex, publicKeyHex) {
85
+ this.privateKey = privateKey;
86
+ this.privateKeyHex = privateKeyHex;
87
+ this.publicKeyHex = publicKeyHex;
88
+ }
89
+ static async fromHex(params) {
90
+ const { privateKeyHex, publicKeyHex } = params;
91
+ const privateKeyBytes = decodeHex(privateKeyHex).buffer;
92
+ const privateKey = await crypto.subtle.importKey("pkcs8", privateKeyBytes, { name: "X25519", namedCurve: "X25519" }, true, // extractable — needed for HKDF salt derivation in decrypt()
93
+ ["deriveBits"]);
94
+ return new PrivateEncryptionKey(privateKey, privateKeyHex, publicKeyHex);
95
+ }
96
+ static async generatePair() {
97
+ const pair = await generateEncryptionKeyPair();
98
+ const privateKeyBytes = new Uint8Array(await crypto.subtle.exportKey("pkcs8", pair.privateKey));
99
+ const privateKeyHex = encodeHex(privateKeyBytes);
100
+ const publicKey = new PublicEncryptionKey(pair.publicKeyHex, pair.publicKey);
101
+ return {
102
+ privateKey: new PrivateEncryptionKey(pair.privateKey, privateKeyHex, pair.publicKeyHex),
103
+ publicKey,
104
+ };
105
+ }
106
+ toPublic() {
107
+ return new PublicEncryptionKey(this.publicKeyHex, null);
108
+ }
109
+ async decrypt(payload) {
110
+ return await decrypt(payload, this.privateKey, this.publicKeyHex);
111
+ }
112
+ toHex() {
113
+ return this.privateKeyHex;
114
+ }
115
+ }
116
+ /**
117
+ * Convert a PEM-encoded private key to a CryptoKey
118
+ */
119
+ export async function pemToCryptoKey(pem, algorithm, extractable = false) {
120
+ const lines = pem
121
+ .split("\n")
122
+ .map((l) => l.trim())
123
+ .filter((l) => l.length > 0 && !l.startsWith("---"));
124
+ if (lines.length === 0) {
125
+ throw new Error("Invalid PEM: no key data");
126
+ }
127
+ const base64 = lines.join("");
128
+ const binary = atob(base64);
129
+ const bytes = new Uint8Array(binary.length);
130
+ for (let i = 0; i < binary.length; i++)
131
+ bytes[i] = binary.charCodeAt(i);
132
+ const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
133
+ if (algorithm === "Ed25519") {
134
+ return await crypto.subtle.importKey("pkcs8", buffer, { name: "Ed25519", namedCurve: "Ed25519" }, extractable, ["sign"]);
135
+ }
136
+ return await crypto.subtle.importKey("pkcs8", buffer, { name: "X25519", namedCurve: "X25519" }, extractable, ["deriveBits"]);
137
+ }
138
+ /**
139
+ * Generate an Ed25519 keypair for signing
140
+ */
141
+ export async function generateSigningKeyPair() {
142
+ const keyPair = await crypto.subtle.generateKey({
143
+ name: "Ed25519",
144
+ namedCurve: "Ed25519",
145
+ }, true, ["sign", "verify"]);
146
+ const publicKeyBytes = await crypto.subtle.exportKey("raw", keyPair.publicKey);
147
+ const privateKeyBytes = await crypto.subtle.exportKey("pkcs8", keyPair.privateKey);
148
+ return {
149
+ publicKey: keyPair.publicKey,
150
+ privateKey: keyPair.privateKey,
151
+ publicKeyHex: encodeHex(new Uint8Array(publicKeyBytes)),
152
+ privateKeyHex: encodeHex(new Uint8Array(privateKeyBytes)),
153
+ };
154
+ }
155
+ /**
156
+ * Generate an X25519 keypair for encryption (ECDH)
157
+ */
158
+ export async function generateEncryptionKeyPair() {
159
+ const keyPair = await crypto.subtle.generateKey({
160
+ name: "X25519",
161
+ namedCurve: "X25519",
162
+ }, true, ["deriveBits"]);
163
+ const publicKeyBytes = await crypto.subtle.exportKey("raw", keyPair.publicKey);
164
+ return {
165
+ publicKey: keyPair.publicKey,
166
+ privateKey: keyPair.privateKey,
167
+ publicKeyHex: encodeHex(new Uint8Array(publicKeyBytes)),
168
+ };
169
+ }
170
+ /**
171
+ * Sign a payload with an Ed25519 private key
172
+ */
173
+ export async function sign(privateKey, payload) {
174
+ const encoder = new TextEncoder();
175
+ const canonical = canonicalize(payload);
176
+ if (canonical === undefined) {
177
+ throw new Error("Payload is not canonicalizable (contains non-JSON-serializable values)");
178
+ }
179
+ const data = encoder.encode(canonical);
180
+ const signature = await crypto.subtle.sign("Ed25519", privateKey, data);
181
+ return encodeHex(new Uint8Array(signature));
182
+ }
183
+ /**
184
+ * Sign a payload with an Ed25519 private key from hex
185
+ */
186
+ export async function signWithHex(privateKeyHex, payload) {
187
+ const privateKeyBytes = decodeHex(privateKeyHex).buffer;
188
+ const privateKey = await crypto.subtle.importKey("pkcs8", privateKeyBytes, {
189
+ name: "Ed25519",
190
+ namedCurve: "Ed25519",
191
+ }, false, ["sign"]);
192
+ return await sign(privateKey, payload);
193
+ }
194
+ /**
195
+ * Verify a signature using Ed25519 public key
196
+ */
197
+ export async function verify(publicKeyHex, signatureHex, payload) {
198
+ try {
199
+ const publicKeyBytes = decodeHex(publicKeyHex).buffer;
200
+ const publicKey = await crypto.subtle.importKey("raw", publicKeyBytes, {
201
+ name: "Ed25519",
202
+ namedCurve: "Ed25519",
203
+ }, false, ["verify"]);
204
+ const encoder = new TextEncoder();
205
+ const canonical = canonicalize(payload);
206
+ if (canonical === undefined) {
207
+ return false;
208
+ }
209
+ const data = encoder.encode(canonical);
210
+ const signatureBytes = decodeHex(signatureHex).buffer;
211
+ return await crypto.subtle.verify("Ed25519", publicKey, signatureBytes, data);
212
+ }
213
+ catch (error) {
214
+ console.error("Verification error:", error);
215
+ return false;
216
+ }
217
+ }
218
+ /**
219
+ * Derive an AES-GCM key from ECDH shared secret using HKDF-SHA256 (RFC 5869).
220
+ * Provides domain separation and defense-in-depth per NIST SP 800-56C.
221
+ *
222
+ * @param sharedSecret - Raw ECDH shared secret (ArrayBuffer)
223
+ * @param pubkey1Hex - First public key hex (sorted deterministically for salt)
224
+ * @param pubkey2Hex - Second public key hex
225
+ * @param usage - "encrypt" or "decrypt"
226
+ */
227
+ async function deriveAesKeyFromEcdh(sharedSecret, pubkey1Hex, pubkey2Hex, usage) {
228
+ const encoder = new TextEncoder();
229
+ // Deterministic salt from sorted public keys, hashed to 32 bytes
230
+ // (raw concatenation exceeds HKDF salt length limits in some implementations)
231
+ const [sortedA, sortedB] = [pubkey1Hex, pubkey2Hex].sort();
232
+ const saltInput = encoder.encode(sortedA + sortedB);
233
+ const salt = new Uint8Array(await crypto.subtle.digest("SHA-256", saltInput));
234
+ const info = encoder.encode("b3nd-aes-gcm-key-v1");
235
+ // Import shared secret as HKDF key material
236
+ const hkdfKey = await crypto.subtle.importKey("raw", sharedSecret, "HKDF", false, ["deriveKey"]);
237
+ // Derive AES-256-GCM key via HKDF-SHA256
238
+ return await crypto.subtle.deriveKey({
239
+ name: "HKDF",
240
+ hash: "SHA-256",
241
+ salt,
242
+ info,
243
+ }, hkdfKey, { name: "AES-GCM", length: 256 }, false, [usage]);
244
+ }
245
+ /**
246
+ * Encrypt data using X25519 ECDH + HKDF + AES-GCM
247
+ * Uses ephemeral keypair for forward secrecy.
248
+ * HKDF provides domain separation per NIST SP 800-56C / RFC 5869.
249
+ */
250
+ export async function encrypt(data, recipientPublicKeyHex) {
251
+ // Generate ephemeral keypair for ECDH
252
+ const ephemeralKeyPair = await generateEncryptionKeyPair();
253
+ // Import recipient's public key
254
+ const recipientPublicKeyBytes = decodeHex(recipientPublicKeyHex).buffer;
255
+ const recipientPublicKey = await crypto.subtle.importKey("raw", recipientPublicKeyBytes, {
256
+ name: "X25519",
257
+ namedCurve: "X25519",
258
+ }, false, []);
259
+ // Derive shared secret using ECDH
260
+ const sharedSecret = await crypto.subtle.deriveBits({
261
+ name: "X25519",
262
+ public: recipientPublicKey,
263
+ }, ephemeralKeyPair.privateKey, 256);
264
+ // Derive AES key via HKDF (not raw ECDH output)
265
+ const aesKey = await deriveAesKeyFromEcdh(sharedSecret, ephemeralKeyPair.publicKeyHex, recipientPublicKeyHex, "encrypt");
266
+ // Generate nonce
267
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
268
+ // Encrypt data
269
+ const ciphertext = await crypto.subtle.encrypt({
270
+ name: "AES-GCM",
271
+ iv: nonce,
272
+ }, aesKey, data);
273
+ return {
274
+ data: encodeBase64(new Uint8Array(ciphertext)),
275
+ nonce: encodeBase64(nonce),
276
+ ephemeralPublicKey: ephemeralKeyPair.publicKeyHex,
277
+ };
278
+ }
279
+ /**
280
+ * Decrypt data using X25519 ECDH + HKDF + AES-GCM
281
+ */
282
+ export async function decrypt(encryptedPayload, recipientPrivateKey, recipientPublicKeyHex) {
283
+ if (!encryptedPayload.ephemeralPublicKey) {
284
+ throw new Error("Missing ephemeral public key");
285
+ }
286
+ // We need the recipient's public key hex for HKDF salt.
287
+ // If caller provided it, use it directly; otherwise extract via JWK round-trip
288
+ // (requires the key to have been imported with extractable: true).
289
+ if (!recipientPublicKeyHex) {
290
+ const jwk = await crypto.subtle.exportKey("jwk", recipientPrivateKey);
291
+ const recipientPub = await crypto.subtle.importKey("jwk", { kty: jwk.kty, crv: jwk.crv, x: jwk.x, key_ops: [] }, { name: "X25519", namedCurve: "X25519" }, true, []);
292
+ const recipientPubBytes = new Uint8Array(await crypto.subtle.exportKey("raw", recipientPub));
293
+ recipientPublicKeyHex = encodeHex(recipientPubBytes);
294
+ }
295
+ // Import ephemeral public key
296
+ const ephemeralPublicKeyBytes = decodeHex(encryptedPayload.ephemeralPublicKey).buffer;
297
+ const ephemeralPublicKey = await crypto.subtle.importKey("raw", ephemeralPublicKeyBytes, {
298
+ name: "X25519",
299
+ namedCurve: "X25519",
300
+ }, false, []);
301
+ // Derive shared secret using ECDH
302
+ const sharedSecret = await crypto.subtle.deriveBits({
303
+ name: "X25519",
304
+ public: ephemeralPublicKey,
305
+ }, recipientPrivateKey, 256);
306
+ // Derive AES key via HKDF (not raw ECDH output)
307
+ const aesKey = await deriveAesKeyFromEcdh(sharedSecret, encryptedPayload.ephemeralPublicKey, recipientPublicKeyHex, "decrypt");
308
+ // Decrypt data
309
+ const ciphertext = new Uint8Array(decodeBase64(encryptedPayload.data));
310
+ const nonce = new Uint8Array(decodeBase64(encryptedPayload.nonce));
311
+ const plaintext = await crypto.subtle.decrypt({
312
+ name: "AES-GCM",
313
+ iv: nonce,
314
+ }, aesKey, ciphertext);
315
+ return new Uint8Array(plaintext);
316
+ }
317
+ /**
318
+ * Decrypt data using private key from hex
319
+ */
320
+ export async function decryptWithHex(encryptedPayload, recipientPrivateKeyHex) {
321
+ const privateKeyBytes = decodeHex(recipientPrivateKeyHex).buffer;
322
+ const privateKey = await crypto.subtle.importKey("pkcs8", privateKeyBytes, {
323
+ name: "X25519",
324
+ namedCurve: "X25519",
325
+ }, true, // extractable — needed for HKDF salt derivation in decrypt()
326
+ ["deriveBits"]);
327
+ return await decrypt(encryptedPayload, privateKey);
328
+ }
329
+ /**
330
+ * Create an authenticated message (signed but not encrypted)
331
+ */
332
+ export async function createAuthenticatedMessage(payload, signers) {
333
+ const auth = await Promise.all(signers.map(async (signer) => {
334
+ const signature = await sign(signer.privateKey, payload);
335
+ return {
336
+ pubkey: signer.publicKeyHex,
337
+ signature,
338
+ };
339
+ }));
340
+ return {
341
+ auth,
342
+ payload,
343
+ };
344
+ }
345
+ /**
346
+ * Create an authenticated message with hex-encoded keys (convenience wrapper)
347
+ */
348
+ export async function createAuthenticatedMessageWithHex(payload, pubkeyHex, privateKeyHex) {
349
+ const signature = await signWithHex(privateKeyHex, payload);
350
+ return {
351
+ auth: [{ pubkey: pubkeyHex, signature }],
352
+ payload,
353
+ };
354
+ }
355
+ /**
356
+ * Derive an encryption key from seed and salt using PBKDF2
357
+ * Returns hex-encoded key suitable for encrypt/decrypt functions
358
+ */
359
+ export async function deriveKeyFromSeed(seed, salt, iterations = 600000) {
360
+ const encoder = new TextEncoder();
361
+ // Import seed as key material
362
+ const keyMaterial = await crypto.subtle.importKey("raw", encoder.encode(seed), "PBKDF2", false, ["deriveBits"]);
363
+ // Derive 256-bit key
364
+ const derivedBits = await crypto.subtle.deriveBits({
365
+ name: "PBKDF2",
366
+ salt: encoder.encode(salt),
367
+ iterations,
368
+ hash: "SHA-256",
369
+ }, keyMaterial, 256);
370
+ return encodeHex(new Uint8Array(derivedBits));
371
+ }
372
+ // Utility functions
373
+ export function generateNonce(length = 12) {
374
+ return crypto.getRandomValues(new Uint8Array(length));
375
+ }
376
+ export function generateRandomData(size) {
377
+ return crypto.getRandomValues(new Uint8Array(size));
378
+ }
379
+ export async function exportPrivateKeyPem(privateKey, label) {
380
+ const der = new Uint8Array(await crypto.subtle.exportKey("pkcs8", privateKey));
381
+ return toPem(der, label);
382
+ }
383
+ function toPem(der, label) {
384
+ const base64 = encodeBase64(der);
385
+ const formatted = base64.match(/.{1,64}/g)?.join("\n") ?? base64;
386
+ return `-----BEGIN ${label}-----\n${formatted}\n-----END ${label}-----`;
387
+ }
388
+ export async function signPayload(params) {
389
+ const { payload, identity } = params;
390
+ const signature = await identity.sign(payload);
391
+ return [{ pubkey: identity.publicKeyHex, signature }];
392
+ }
393
+ export async function verifyPayload(params) {
394
+ const { payload, auth } = params;
395
+ const results = await Promise.all(auth.map(async (entry) => {
396
+ const ok = await verify(entry.pubkey, entry.signature, payload);
397
+ return { pubkey: entry.pubkey, ok };
398
+ }));
399
+ const verified = results.every((r) => r.ok);
400
+ const signers = results.filter((r) => r.ok).map((r) => r.pubkey);
401
+ return { verified, signers };
402
+ }
403
+ export async function createSignedEncryptedMessage(paramsOrData, signers, recipientPublicKeyHex) {
404
+ if (typeof paramsOrData === "object" && paramsOrData !== null &&
405
+ !(paramsOrData instanceof Uint8Array) &&
406
+ "encryptionKey" in paramsOrData) {
407
+ const { data, identity, encryptionKey } = paramsOrData;
408
+ const payload = await encryptionKey.encrypt(data);
409
+ const auth = await signPayload({ payload, identity });
410
+ return { auth, payload };
411
+ }
412
+ if (!signers || !recipientPublicKeyHex) {
413
+ throw new Error("Invalid arguments for legacy createSignedEncryptedMessage");
414
+ }
415
+ const encrypted = await encrypt(paramsOrData, recipientPublicKeyHex);
416
+ const auth = await Promise.all(signers.map(async (signer) => {
417
+ const signature = await sign(signer.privateKey, encrypted);
418
+ return { pubkey: signer.publicKeyHex, signature };
419
+ }));
420
+ return { auth, payload: encrypted };
421
+ }
422
+ export async function verifyAndDecryptMessage(params) {
423
+ const { message, encryptionKey } = params;
424
+ const { verified, signers } = await verifyPayload({
425
+ payload: message.payload,
426
+ auth: message.auth,
427
+ });
428
+ const data = encryptionKey instanceof SecretEncryptionKey
429
+ ? await encryptionKey.decrypt(message.payload)
430
+ : await encryptionKey.decrypt(message.payload);
431
+ return { data, verified, signers };
432
+ }
433
+ /**
434
+ * Encrypt data using a symmetric key (AES-GCM) provided as hex
435
+ */
436
+ export async function encryptSymmetric(data, keyHex) {
437
+ const keyBytes = decodeHex(keyHex).buffer;
438
+ const aesKey = await crypto.subtle.importKey("raw", keyBytes, { name: "AES-GCM" }, false, ["encrypt"]);
439
+ const nonce = generateNonce();
440
+ const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, aesKey, data);
441
+ return {
442
+ data: encodeBase64(new Uint8Array(ciphertext)),
443
+ nonce: encodeBase64(nonce),
444
+ };
445
+ }
446
+ /**
447
+ * Decrypt data using a symmetric key (AES-GCM) provided as hex
448
+ */
449
+ export async function decryptSymmetric(payload, keyHex) {
450
+ const keyBytes = decodeHex(keyHex).buffer;
451
+ const aesKey = await crypto.subtle.importKey("raw", keyBytes, { name: "AES-GCM" }, false, ["decrypt"]);
452
+ const ciphertext = new Uint8Array(decodeBase64(payload.data));
453
+ const nonce = new Uint8Array(decodeBase64(payload.nonce));
454
+ const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv: nonce }, aesKey, ciphertext);
455
+ return new Uint8Array(plaintext);
456
+ }
457
+ /**
458
+ * Create a signed symmetric message (signs encrypted payload)
459
+ */
460
+ export async function createSignedSymmetricMessage(data, signers, keyHex) {
461
+ const encryptedPayload = await encryptSymmetric(data, keyHex);
462
+ const auth = await Promise.all(signers.map(async (signer) => {
463
+ const signature = await sign(signer.privateKey, encryptedPayload);
464
+ return {
465
+ pubkey: signer.publicKeyHex,
466
+ signature,
467
+ };
468
+ }));
469
+ return {
470
+ auth,
471
+ payload: encryptedPayload,
472
+ };
473
+ }
474
+ /**
475
+ * Compute HMAC-SHA256 of data with a key
476
+ * Returns hex-encoded 32-byte result
477
+ */
478
+ export async function hmac(key, data) {
479
+ const encoder = new TextEncoder();
480
+ const cryptoKey = await crypto.subtle.importKey("raw", encoder.encode(key), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
481
+ const signature = await crypto.subtle.sign("HMAC", cryptoKey, encoder.encode(data));
482
+ return encodeHex(new Uint8Array(signature));
483
+ }
484
+ /**
485
+ * Derive a deterministic Ed25519 signing keypair from a seed string.
486
+ * Uses HKDF to expand the seed into key material suitable for Ed25519.
487
+ *
488
+ * The same seed always produces the same keypair.
489
+ */
490
+ export async function deriveSigningKeyPairFromSeed(seed) {
491
+ const encoder = new TextEncoder();
492
+ // Import seed as HKDF key material
493
+ const keyMaterial = await crypto.subtle.importKey("raw", encoder.encode(seed), "HKDF", false, ["deriveBits"]);
494
+ // Derive 32 bytes for Ed25519 private key seed
495
+ const derivedBits = await crypto.subtle.deriveBits({
496
+ name: "HKDF",
497
+ hash: "SHA-256",
498
+ salt: encoder.encode("b3nd-signing-key"),
499
+ info: encoder.encode("Ed25519"),
500
+ }, keyMaterial, 256);
501
+ const privateKeyBytes = new Uint8Array(derivedBits);
502
+ // Ed25519 PKCS8 wrapper: ASN.1 prefix for a 32-byte Ed25519 private key
503
+ const pkcs8Prefix = new Uint8Array([
504
+ 0x30,
505
+ 0x2e,
506
+ 0x02,
507
+ 0x01,
508
+ 0x00,
509
+ 0x30,
510
+ 0x05,
511
+ 0x06,
512
+ 0x03,
513
+ 0x2b,
514
+ 0x65,
515
+ 0x70,
516
+ 0x04,
517
+ 0x22,
518
+ 0x04,
519
+ 0x20,
520
+ ]);
521
+ const pkcs8Key = new Uint8Array(pkcs8Prefix.length + privateKeyBytes.length);
522
+ pkcs8Key.set(pkcs8Prefix);
523
+ pkcs8Key.set(privateKeyBytes, pkcs8Prefix.length);
524
+ const privateKey = await crypto.subtle.importKey("pkcs8", pkcs8Key.buffer, { name: "Ed25519", namedCurve: "Ed25519" }, true, ["sign"]);
525
+ // Extract public key from the JWK representation
526
+ const jwk = await crypto.subtle.exportKey("jwk", privateKey);
527
+ // Import just the public part (x only, no d) as a verify key
528
+ const publicKey = await crypto.subtle.importKey("jwk", { kty: jwk.kty, crv: jwk.crv, x: jwk.x }, { name: "Ed25519", namedCurve: "Ed25519" }, true, ["verify"]);
529
+ const publicKeyBytes = await crypto.subtle.exportKey("raw", publicKey);
530
+ const exportedPrivateKey = await crypto.subtle.exportKey("pkcs8", privateKey);
531
+ return {
532
+ publicKey,
533
+ privateKey,
534
+ publicKeyHex: encodeHex(new Uint8Array(publicKeyBytes)),
535
+ privateKeyHex: encodeHex(new Uint8Array(exportedPrivateKey)),
536
+ };
537
+ }
538
+ /**
539
+ * Derive a deterministic X25519 encryption keypair from a seed string.
540
+ * Uses HKDF to expand the seed into key material suitable for X25519.
541
+ *
542
+ * The same seed always produces the same keypair.
543
+ */
544
+ export async function deriveEncryptionKeyPairFromSeed(seed) {
545
+ const encoder = new TextEncoder();
546
+ // Import seed as HKDF key material
547
+ const keyMaterial = await crypto.subtle.importKey("raw", encoder.encode(seed), "HKDF", false, ["deriveBits"]);
548
+ // Derive 32 bytes for X25519 private key
549
+ // Use different info than signing to get a different key from the same seed
550
+ const derivedBits = await crypto.subtle.deriveBits({
551
+ name: "HKDF",
552
+ hash: "SHA-256",
553
+ salt: encoder.encode("b3nd-encryption-key"),
554
+ info: encoder.encode("X25519"),
555
+ }, keyMaterial, 256);
556
+ const privateKeyBytes = new Uint8Array(derivedBits);
557
+ // X25519 PKCS8 wrapper: ASN.1 prefix for a 32-byte X25519 private key
558
+ const pkcs8Prefix = new Uint8Array([
559
+ 0x30,
560
+ 0x2e,
561
+ 0x02,
562
+ 0x01,
563
+ 0x00,
564
+ 0x30,
565
+ 0x05,
566
+ 0x06,
567
+ 0x03,
568
+ 0x2b,
569
+ 0x65,
570
+ 0x6e,
571
+ 0x04,
572
+ 0x22,
573
+ 0x04,
574
+ 0x20,
575
+ ]);
576
+ const pkcs8Key = new Uint8Array(pkcs8Prefix.length + privateKeyBytes.length);
577
+ pkcs8Key.set(pkcs8Prefix);
578
+ pkcs8Key.set(privateKeyBytes, pkcs8Prefix.length);
579
+ const privateKey = await crypto.subtle.importKey("pkcs8", pkcs8Key.buffer, { name: "X25519", namedCurve: "X25519" }, true, ["deriveBits"]);
580
+ // Get public key via JWK round-trip
581
+ const jwk = await crypto.subtle.exportKey("jwk", privateKey);
582
+ const publicKey = await crypto.subtle.importKey("jwk", { kty: jwk.kty, crv: jwk.crv, x: jwk.x, key_ops: [] }, { name: "X25519", namedCurve: "X25519" }, true, []);
583
+ const publicKeyBytes = await crypto.subtle.exportKey("raw", publicKey);
584
+ return {
585
+ publicKey,
586
+ privateKey,
587
+ publicKeyHex: encodeHex(new Uint8Array(publicKeyBytes)),
588
+ };
589
+ }
590
+ /**
591
+ * Extract the Ed25519 public key hex from an Ed25519 private CryptoKey.
592
+ * Useful for deriving a node ID from a PEM-imported private key.
593
+ */
594
+ export async function extractPublicKeyHex(privateKey) {
595
+ const jwk = await crypto.subtle.exportKey("jwk", privateKey);
596
+ const pub = await crypto.subtle.importKey("jwk", { kty: jwk.kty, crv: jwk.crv, x: jwk.x }, { name: "Ed25519", namedCurve: "Ed25519" }, true, ["verify"]);
597
+ const raw = await crypto.subtle.exportKey("raw", pub);
598
+ return encodeHex(new Uint8Array(raw));
599
+ }
600
+ /**
601
+ * Generate a PKCE code verifier (RFC 7636)
602
+ * 32 random bytes, base64url-encoded (43 characters)
603
+ */
604
+ export function generateCodeVerifier() {
605
+ const bytes = crypto.getRandomValues(new Uint8Array(32));
606
+ const base64 = encodeBase64(bytes);
607
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
608
+ }
609
+ /**
610
+ * Generate a PKCE code challenge from a verifier (RFC 7636, S256 method)
611
+ * SHA-256 hash of verifier, base64url-encoded (43 characters)
612
+ */
613
+ export async function generateCodeChallenge(verifier) {
614
+ const encoder = new TextEncoder();
615
+ const hash = await crypto.subtle.digest("SHA-256", encoder.encode(verifier));
616
+ const hashArray = new Uint8Array(hash);
617
+ const base64 = encodeBase64(hashArray);
618
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
619
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @module
3
+ * FunctionalClient - A client that takes functions as config.
4
+ *
5
+ * Replaces createNode() for cases where you want to wire up
6
+ * custom behavior without class inheritance.
7
+ */
8
+ import type { Output, ProtocolInterfaceNode, ReceiveResult, StatusResult } from "../types/types.js";
9
+ /**
10
+ * Configuration for FunctionalClient.
11
+ * Each method is optional — missing methods return sensible defaults.
12
+ */
13
+ export interface FunctionalClientConfig {
14
+ receive?: (msgs: Output[]) => Promise<ReceiveResult[]>;
15
+ read?: <T = unknown>(urls: string[]) => Promise<Output<T>[]>;
16
+ observe?: (urls: string[], signal: AbortSignal) => AsyncIterable<readonly string[]>;
17
+ status?: () => Promise<StatusResult>;
18
+ }
19
+ /**
20
+ * A client that delegates each method to a config function.
21
+ *
22
+ * If a method is not provided, it returns a sensible default:
23
+ * - receive → { accepted: false, error: "not implemented" }
24
+ * - read → [{ success: false, error: "not implemented" }] per URI
25
+ * - status → { status: "healthy" }
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const client = new FunctionalClient({
30
+ * receive: async (msg) => backend.receive(msg),
31
+ * read: async (urls) => backend.read(urls),
32
+ * });
33
+ * ```
34
+ */
35
+ export declare class FunctionalClient implements ProtocolInterfaceNode {
36
+ private config;
37
+ constructor(config: FunctionalClientConfig);
38
+ receive(msgs: Output[]): Promise<ReceiveResult[]>;
39
+ read<T = unknown>(urls: string[]): Promise<Output<T>[]>;
40
+ observe(urls: string[], signal: AbortSignal): AsyncIterable<readonly string[]>;
41
+ status(): Promise<StatusResult>;
42
+ }
43
+ //# sourceMappingURL=functional-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functional-client.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,MAAM,EACN,qBAAqB,EACrB,aAAa,EACb,YAAY,EACb,MAAM,mBAAmB,CAAC;AAE3B;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,EAAE,CACR,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,WAAW,KAChB,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;CACtC;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,gBAAiB,YAAW,qBAAqB;IAC5D,OAAO,CAAC,MAAM,CAAyB;gBAE3B,MAAM,EAAE,sBAAsB;IAI1C,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IASjD,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAQhD,OAAO,CACZ,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,WAAW,GAClB,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC;IAOnC,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;CAMhC"}