@bandeira-tech/b3nd-web 0.2.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/README.md +28 -0
- package/dist/apps/mod.d.ts +79 -0
- package/dist/apps/mod.js +7 -0
- package/dist/chunk-2D2RT2DW.js +277 -0
- package/dist/chunk-C2ZIFM22.js +272 -0
- package/dist/chunk-G6JDROB4.js +327 -0
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-PMBS2GFA.js +223 -0
- package/dist/chunk-QHDBFVLU.js +87 -0
- package/dist/chunk-XH4OLKBV.js +295 -0
- package/dist/clients/http/mod.d.ts +33 -0
- package/dist/clients/http/mod.js +7 -0
- package/dist/clients/local-storage/mod.d.ts +60 -0
- package/dist/clients/local-storage/mod.js +7 -0
- package/dist/clients/websocket/mod.d.ts +62 -0
- package/dist/clients/websocket/mod.js +7 -0
- package/dist/encrypt/mod.d.ts +1 -0
- package/dist/encrypt/mod.js +31 -0
- package/dist/mod-DHjjiF1o.d.ts +111 -0
- package/dist/src/mod.web.d.ts +7 -0
- package/dist/src/mod.web.js +27 -0
- package/dist/types-Bw0Boe0n.d.ts +219 -0
- package/dist/wallet/mod.d.ts +278 -0
- package/dist/wallet/mod.js +7 -0
- package/package.json +84 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__export
|
|
3
|
+
} from "./chunk-MLKGABMK.js";
|
|
4
|
+
|
|
5
|
+
// encrypt/mod.ts
|
|
6
|
+
var mod_exports = {};
|
|
7
|
+
__export(mod_exports, {
|
|
8
|
+
createAuthenticatedMessage: () => createAuthenticatedMessage,
|
|
9
|
+
createSignedEncryptedMessage: () => createSignedEncryptedMessage,
|
|
10
|
+
decrypt: () => decrypt,
|
|
11
|
+
decryptWithHex: () => decryptWithHex,
|
|
12
|
+
encrypt: () => encrypt,
|
|
13
|
+
generateEncryptionKeyPair: () => generateEncryptionKeyPair,
|
|
14
|
+
generateNonce: () => generateNonce,
|
|
15
|
+
generateRandomData: () => generateRandomData,
|
|
16
|
+
generateSigningKeyPair: () => generateSigningKeyPair,
|
|
17
|
+
sign: () => sign,
|
|
18
|
+
signWithHex: () => signWithHex,
|
|
19
|
+
verify: () => verify,
|
|
20
|
+
verifyAndDecrypt: () => verifyAndDecrypt
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// shared/encoding.ts
|
|
24
|
+
function encodeHex(bytes) {
|
|
25
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
26
|
+
}
|
|
27
|
+
function decodeHex(hex) {
|
|
28
|
+
if (hex.length % 2 !== 0) {
|
|
29
|
+
throw new Error("Invalid hex input");
|
|
30
|
+
}
|
|
31
|
+
const buffer = new ArrayBuffer(hex.length / 2);
|
|
32
|
+
const bytes = new Uint8Array(buffer);
|
|
33
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
34
|
+
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
|
35
|
+
}
|
|
36
|
+
return bytes;
|
|
37
|
+
}
|
|
38
|
+
function encodeBase64(bytes) {
|
|
39
|
+
if (typeof btoa === "function") {
|
|
40
|
+
let binary = "";
|
|
41
|
+
bytes.forEach((b) => binary += String.fromCharCode(b));
|
|
42
|
+
return btoa(binary);
|
|
43
|
+
}
|
|
44
|
+
return Buffer.from(bytes).toString("base64");
|
|
45
|
+
}
|
|
46
|
+
function decodeBase64(b64) {
|
|
47
|
+
if (typeof atob === "function") {
|
|
48
|
+
const binary = atob(b64);
|
|
49
|
+
const bytes = new Uint8Array(binary.length);
|
|
50
|
+
for (let i = 0; i < binary.length; i++) {
|
|
51
|
+
bytes[i] = binary.charCodeAt(i);
|
|
52
|
+
}
|
|
53
|
+
return bytes;
|
|
54
|
+
}
|
|
55
|
+
return new Uint8Array(Buffer.from(b64, "base64"));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// encrypt/mod.ts
|
|
59
|
+
async function generateSigningKeyPair() {
|
|
60
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
61
|
+
{
|
|
62
|
+
name: "Ed25519",
|
|
63
|
+
namedCurve: "Ed25519"
|
|
64
|
+
},
|
|
65
|
+
true,
|
|
66
|
+
["sign", "verify"]
|
|
67
|
+
);
|
|
68
|
+
const publicKeyBytes = await crypto.subtle.exportKey("raw", keyPair.publicKey);
|
|
69
|
+
const privateKeyBytes = await crypto.subtle.exportKey(
|
|
70
|
+
"pkcs8",
|
|
71
|
+
keyPair.privateKey
|
|
72
|
+
);
|
|
73
|
+
return {
|
|
74
|
+
publicKey: keyPair.publicKey,
|
|
75
|
+
privateKey: keyPair.privateKey,
|
|
76
|
+
publicKeyHex: encodeHex(new Uint8Array(publicKeyBytes)),
|
|
77
|
+
privateKeyHex: encodeHex(new Uint8Array(privateKeyBytes))
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function generateEncryptionKeyPair() {
|
|
81
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
82
|
+
{
|
|
83
|
+
name: "X25519",
|
|
84
|
+
namedCurve: "X25519"
|
|
85
|
+
},
|
|
86
|
+
true,
|
|
87
|
+
["deriveBits"]
|
|
88
|
+
);
|
|
89
|
+
const publicKeyBytes = await crypto.subtle.exportKey("raw", keyPair.publicKey);
|
|
90
|
+
return {
|
|
91
|
+
publicKey: keyPair.publicKey,
|
|
92
|
+
privateKey: keyPair.privateKey,
|
|
93
|
+
publicKeyHex: encodeHex(new Uint8Array(publicKeyBytes))
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function sign(privateKey, payload) {
|
|
97
|
+
const encoder = new TextEncoder();
|
|
98
|
+
const data = encoder.encode(JSON.stringify(payload));
|
|
99
|
+
const signature = await crypto.subtle.sign("Ed25519", privateKey, data);
|
|
100
|
+
return encodeHex(new Uint8Array(signature));
|
|
101
|
+
}
|
|
102
|
+
async function signWithHex(privateKeyHex, payload) {
|
|
103
|
+
const privateKeyBytes = decodeHex(privateKeyHex).buffer;
|
|
104
|
+
const privateKey = await crypto.subtle.importKey(
|
|
105
|
+
"pkcs8",
|
|
106
|
+
privateKeyBytes,
|
|
107
|
+
{
|
|
108
|
+
name: "Ed25519",
|
|
109
|
+
namedCurve: "Ed25519"
|
|
110
|
+
},
|
|
111
|
+
false,
|
|
112
|
+
["sign"]
|
|
113
|
+
);
|
|
114
|
+
return await sign(privateKey, payload);
|
|
115
|
+
}
|
|
116
|
+
async function verify(publicKeyHex, signatureHex, payload) {
|
|
117
|
+
try {
|
|
118
|
+
const publicKeyBytes = decodeHex(publicKeyHex).buffer;
|
|
119
|
+
const publicKey = await crypto.subtle.importKey(
|
|
120
|
+
"raw",
|
|
121
|
+
publicKeyBytes,
|
|
122
|
+
{
|
|
123
|
+
name: "Ed25519",
|
|
124
|
+
namedCurve: "Ed25519"
|
|
125
|
+
},
|
|
126
|
+
false,
|
|
127
|
+
["verify"]
|
|
128
|
+
);
|
|
129
|
+
const encoder = new TextEncoder();
|
|
130
|
+
const data = encoder.encode(JSON.stringify(payload));
|
|
131
|
+
const signatureBytes = decodeHex(signatureHex).buffer;
|
|
132
|
+
return await crypto.subtle.verify(
|
|
133
|
+
"Ed25519",
|
|
134
|
+
publicKey,
|
|
135
|
+
signatureBytes,
|
|
136
|
+
data
|
|
137
|
+
);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.error("Verification error:", error);
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function encrypt(data, recipientPublicKeyHex) {
|
|
144
|
+
const ephemeralKeyPair = await generateEncryptionKeyPair();
|
|
145
|
+
const recipientPublicKeyBytes = decodeHex(recipientPublicKeyHex).buffer;
|
|
146
|
+
const recipientPublicKey = await crypto.subtle.importKey(
|
|
147
|
+
"raw",
|
|
148
|
+
recipientPublicKeyBytes,
|
|
149
|
+
{
|
|
150
|
+
name: "X25519",
|
|
151
|
+
namedCurve: "X25519"
|
|
152
|
+
},
|
|
153
|
+
false,
|
|
154
|
+
[]
|
|
155
|
+
);
|
|
156
|
+
const sharedSecret = await crypto.subtle.deriveBits(
|
|
157
|
+
{
|
|
158
|
+
name: "X25519",
|
|
159
|
+
public: recipientPublicKey
|
|
160
|
+
},
|
|
161
|
+
ephemeralKeyPair.privateKey,
|
|
162
|
+
256
|
|
163
|
+
);
|
|
164
|
+
const aesKey = await crypto.subtle.importKey(
|
|
165
|
+
"raw",
|
|
166
|
+
sharedSecret,
|
|
167
|
+
{
|
|
168
|
+
name: "AES-GCM",
|
|
169
|
+
length: 256
|
|
170
|
+
},
|
|
171
|
+
false,
|
|
172
|
+
["encrypt"]
|
|
173
|
+
);
|
|
174
|
+
const nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
175
|
+
const encoder = new TextEncoder();
|
|
176
|
+
const plaintext = encoder.encode(JSON.stringify(data));
|
|
177
|
+
const ciphertext = await crypto.subtle.encrypt(
|
|
178
|
+
{
|
|
179
|
+
name: "AES-GCM",
|
|
180
|
+
iv: nonce
|
|
181
|
+
},
|
|
182
|
+
aesKey,
|
|
183
|
+
plaintext
|
|
184
|
+
);
|
|
185
|
+
return {
|
|
186
|
+
data: encodeBase64(new Uint8Array(ciphertext)),
|
|
187
|
+
nonce: encodeBase64(nonce),
|
|
188
|
+
ephemeralPublicKey: ephemeralKeyPair.publicKeyHex
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async function decrypt(encryptedPayload, recipientPrivateKey) {
|
|
192
|
+
if (!encryptedPayload.ephemeralPublicKey) {
|
|
193
|
+
throw new Error("Missing ephemeral public key");
|
|
194
|
+
}
|
|
195
|
+
const ephemeralPublicKeyBytes = decodeHex(
|
|
196
|
+
encryptedPayload.ephemeralPublicKey
|
|
197
|
+
).buffer;
|
|
198
|
+
const ephemeralPublicKey = await crypto.subtle.importKey(
|
|
199
|
+
"raw",
|
|
200
|
+
ephemeralPublicKeyBytes,
|
|
201
|
+
{
|
|
202
|
+
name: "X25519",
|
|
203
|
+
namedCurve: "X25519"
|
|
204
|
+
},
|
|
205
|
+
false,
|
|
206
|
+
[]
|
|
207
|
+
);
|
|
208
|
+
const sharedSecret = await crypto.subtle.deriveBits(
|
|
209
|
+
{
|
|
210
|
+
name: "X25519",
|
|
211
|
+
public: ephemeralPublicKey
|
|
212
|
+
},
|
|
213
|
+
recipientPrivateKey,
|
|
214
|
+
256
|
|
215
|
+
);
|
|
216
|
+
const aesKey = await crypto.subtle.importKey(
|
|
217
|
+
"raw",
|
|
218
|
+
sharedSecret,
|
|
219
|
+
{
|
|
220
|
+
name: "AES-GCM",
|
|
221
|
+
length: 256
|
|
222
|
+
},
|
|
223
|
+
false,
|
|
224
|
+
["decrypt"]
|
|
225
|
+
);
|
|
226
|
+
const ciphertext = new Uint8Array(decodeBase64(encryptedPayload.data));
|
|
227
|
+
const nonce = new Uint8Array(decodeBase64(encryptedPayload.nonce));
|
|
228
|
+
const plaintext = await crypto.subtle.decrypt(
|
|
229
|
+
{
|
|
230
|
+
name: "AES-GCM",
|
|
231
|
+
iv: nonce
|
|
232
|
+
},
|
|
233
|
+
aesKey,
|
|
234
|
+
ciphertext
|
|
235
|
+
);
|
|
236
|
+
const decoder = new TextDecoder();
|
|
237
|
+
const json = decoder.decode(plaintext);
|
|
238
|
+
return JSON.parse(json);
|
|
239
|
+
}
|
|
240
|
+
async function decryptWithHex(encryptedPayload, recipientPrivateKeyHex) {
|
|
241
|
+
const privateKeyBytes = decodeHex(recipientPrivateKeyHex).buffer;
|
|
242
|
+
const privateKey = await crypto.subtle.importKey(
|
|
243
|
+
"raw",
|
|
244
|
+
privateKeyBytes,
|
|
245
|
+
{
|
|
246
|
+
name: "X25519",
|
|
247
|
+
namedCurve: "X25519"
|
|
248
|
+
},
|
|
249
|
+
false,
|
|
250
|
+
["deriveBits"]
|
|
251
|
+
);
|
|
252
|
+
return await decrypt(encryptedPayload, privateKey);
|
|
253
|
+
}
|
|
254
|
+
async function createAuthenticatedMessage(payload, signers) {
|
|
255
|
+
const auth = await Promise.all(
|
|
256
|
+
signers.map(async (signer) => {
|
|
257
|
+
const signature = await sign(signer.privateKey, payload);
|
|
258
|
+
return {
|
|
259
|
+
pubkey: signer.publicKeyHex,
|
|
260
|
+
signature
|
|
261
|
+
};
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
return {
|
|
265
|
+
auth,
|
|
266
|
+
payload
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
async function createSignedEncryptedMessage(data, signers, recipientPublicKeyHex) {
|
|
270
|
+
const encrypted = await encrypt(data, recipientPublicKeyHex);
|
|
271
|
+
const auth = await Promise.all(
|
|
272
|
+
signers.map(async (signer) => {
|
|
273
|
+
const signature = await sign(signer.privateKey, encrypted);
|
|
274
|
+
return {
|
|
275
|
+
pubkey: signer.publicKeyHex,
|
|
276
|
+
signature
|
|
277
|
+
};
|
|
278
|
+
})
|
|
279
|
+
);
|
|
280
|
+
return {
|
|
281
|
+
auth,
|
|
282
|
+
payload: encrypted
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
async function verifyAndDecrypt(message, recipientPrivateKey) {
|
|
286
|
+
const verificationResults = await Promise.all(
|
|
287
|
+
message.auth.map(async (authEntry) => {
|
|
288
|
+
const verified2 = await verify(
|
|
289
|
+
authEntry.pubkey,
|
|
290
|
+
authEntry.signature,
|
|
291
|
+
message.payload
|
|
292
|
+
);
|
|
293
|
+
return { pubkey: authEntry.pubkey, verified: verified2 };
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
const verified = verificationResults.every((r) => r.verified);
|
|
297
|
+
const signers = verificationResults.filter((r) => r.verified).map((r) => r.pubkey);
|
|
298
|
+
const data = await decrypt(message.payload, recipientPrivateKey);
|
|
299
|
+
return {
|
|
300
|
+
data,
|
|
301
|
+
verified,
|
|
302
|
+
signers
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function generateNonce(length = 12) {
|
|
306
|
+
return crypto.getRandomValues(new Uint8Array(length));
|
|
307
|
+
}
|
|
308
|
+
function generateRandomData(size) {
|
|
309
|
+
return crypto.getRandomValues(new Uint8Array(size));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export {
|
|
313
|
+
generateSigningKeyPair,
|
|
314
|
+
generateEncryptionKeyPair,
|
|
315
|
+
sign,
|
|
316
|
+
signWithHex,
|
|
317
|
+
verify,
|
|
318
|
+
encrypt,
|
|
319
|
+
decrypt,
|
|
320
|
+
decryptWithHex,
|
|
321
|
+
createAuthenticatedMessage,
|
|
322
|
+
createSignedEncryptedMessage,
|
|
323
|
+
verifyAndDecrypt,
|
|
324
|
+
generateNonce,
|
|
325
|
+
generateRandomData,
|
|
326
|
+
mod_exports
|
|
327
|
+
};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// clients/http/mod.ts
|
|
2
|
+
var HttpClient = class {
|
|
3
|
+
baseUrl;
|
|
4
|
+
headers;
|
|
5
|
+
timeout;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.baseUrl = config.url.replace(/\/$/, "");
|
|
8
|
+
this.headers = config.headers || {};
|
|
9
|
+
this.timeout = config.timeout || 3e4;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Make an HTTP request with timeout
|
|
13
|
+
*/
|
|
14
|
+
async request(path, options = {}) {
|
|
15
|
+
const controller = new AbortController();
|
|
16
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
17
|
+
try {
|
|
18
|
+
const url = `${this.baseUrl}${path}`;
|
|
19
|
+
const response = await fetch(url, {
|
|
20
|
+
...options,
|
|
21
|
+
headers: {
|
|
22
|
+
"Content-Type": "application/json",
|
|
23
|
+
...this.headers,
|
|
24
|
+
...options.headers
|
|
25
|
+
},
|
|
26
|
+
signal: controller.signal
|
|
27
|
+
});
|
|
28
|
+
return response;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
31
|
+
throw new Error(`Request timeout after ${this.timeout}ms`);
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
} finally {
|
|
35
|
+
clearTimeout(timeoutId);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse URI into components
|
|
40
|
+
* Example: "users://alice/profile" -> { protocol: "users", domain: "alice", path: "/profile" }
|
|
41
|
+
*/
|
|
42
|
+
parseUri(uri) {
|
|
43
|
+
const url = new URL(uri);
|
|
44
|
+
return {
|
|
45
|
+
protocol: url.protocol.replace(":", ""),
|
|
46
|
+
domain: url.hostname,
|
|
47
|
+
path: url.pathname
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async write(uri, value) {
|
|
51
|
+
try {
|
|
52
|
+
const { protocol, domain, path } = this.parseUri(uri);
|
|
53
|
+
const requestPath = `/api/v1/write/${protocol}/${domain}${path}`;
|
|
54
|
+
const response = await this.request(requestPath, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
body: JSON.stringify({ value })
|
|
57
|
+
});
|
|
58
|
+
const result = await response.json();
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
return {
|
|
61
|
+
success: false,
|
|
62
|
+
error: `Write failed: ${result.error || response.statusText}`
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
success: true,
|
|
67
|
+
record: result.record
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return {
|
|
71
|
+
success: false,
|
|
72
|
+
error: error instanceof Error ? error.message : String(error)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async read(uri) {
|
|
77
|
+
try {
|
|
78
|
+
const { protocol, domain, path } = this.parseUri(uri);
|
|
79
|
+
const requestPath = `/api/v1/read/${protocol}/${domain}${path}`;
|
|
80
|
+
const response = await this.request(requestPath, {
|
|
81
|
+
method: "GET"
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
await response.text();
|
|
85
|
+
if (response.status === 404) {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: "Not found"
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
error: `Read failed: ${response.statusText}`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const result = await response.json();
|
|
97
|
+
return {
|
|
98
|
+
success: true,
|
|
99
|
+
record: result
|
|
100
|
+
};
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
error: error instanceof Error ? error.message : String(error)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async list(uri, options) {
|
|
109
|
+
try {
|
|
110
|
+
const { protocol, domain, path } = this.parseUri(uri);
|
|
111
|
+
const params = new URLSearchParams();
|
|
112
|
+
if (options == null ? void 0 : options.page) {
|
|
113
|
+
params.set("page", options.page.toString());
|
|
114
|
+
}
|
|
115
|
+
if (options == null ? void 0 : options.limit) {
|
|
116
|
+
params.set("limit", options.limit.toString());
|
|
117
|
+
}
|
|
118
|
+
if (options == null ? void 0 : options.pattern) {
|
|
119
|
+
params.set("pattern", options.pattern);
|
|
120
|
+
}
|
|
121
|
+
if (options == null ? void 0 : options.sortBy) {
|
|
122
|
+
params.set("sortBy", options.sortBy);
|
|
123
|
+
}
|
|
124
|
+
if (options == null ? void 0 : options.sortOrder) {
|
|
125
|
+
params.set("sortOrder", options.sortOrder);
|
|
126
|
+
}
|
|
127
|
+
const queryString = params.toString();
|
|
128
|
+
const pathPart = path === "/" ? "" : path;
|
|
129
|
+
const requestPath = `/api/v1/list/${protocol}/${domain}${pathPart}${queryString ? `?${queryString}` : ""}`;
|
|
130
|
+
const response = await this.request(requestPath, {
|
|
131
|
+
method: "GET"
|
|
132
|
+
});
|
|
133
|
+
if (!response.ok) {
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
data: [],
|
|
137
|
+
pagination: {
|
|
138
|
+
page: (options == null ? void 0 : options.page) || 1,
|
|
139
|
+
limit: (options == null ? void 0 : options.limit) || 50
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const result = await response.json();
|
|
144
|
+
return result;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
return {
|
|
147
|
+
success: true,
|
|
148
|
+
data: [],
|
|
149
|
+
pagination: {
|
|
150
|
+
page: (options == null ? void 0 : options.page) || 1,
|
|
151
|
+
limit: (options == null ? void 0 : options.limit) || 50
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async delete(uri) {
|
|
157
|
+
try {
|
|
158
|
+
const { protocol, domain, path } = this.parseUri(uri);
|
|
159
|
+
const requestPath = `/api/v1/delete/${protocol}/${domain}${path}`;
|
|
160
|
+
const response = await this.request(requestPath, {
|
|
161
|
+
method: "DELETE"
|
|
162
|
+
});
|
|
163
|
+
const result = response.ok ? await response.json() : { error: await response.text() };
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
return {
|
|
166
|
+
success: false,
|
|
167
|
+
error: `Delete failed: ${result.error}`
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
success: true
|
|
172
|
+
};
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
error: error instanceof Error ? error.message : String(error)
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async health() {
|
|
181
|
+
try {
|
|
182
|
+
const response = await this.request("/api/v1/health", {
|
|
183
|
+
method: "GET"
|
|
184
|
+
});
|
|
185
|
+
if (!response.ok) {
|
|
186
|
+
return {
|
|
187
|
+
status: "unhealthy",
|
|
188
|
+
message: "Health check failed"
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const result = await response.json();
|
|
192
|
+
return result;
|
|
193
|
+
} catch (error) {
|
|
194
|
+
return {
|
|
195
|
+
status: "unhealthy",
|
|
196
|
+
message: error instanceof Error ? error.message : String(error)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async getSchema() {
|
|
201
|
+
try {
|
|
202
|
+
const response = await this.request("/api/v1/schema", {
|
|
203
|
+
method: "GET"
|
|
204
|
+
});
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
const result = await response.json();
|
|
209
|
+
if (result.schema && Array.isArray(result.schema)) {
|
|
210
|
+
return result.schema;
|
|
211
|
+
}
|
|
212
|
+
return [];
|
|
213
|
+
} catch (error) {
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async cleanup() {
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export {
|
|
222
|
+
HttpClient
|
|
223
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// apps/mod.ts
|
|
2
|
+
var AppsClient = class {
|
|
3
|
+
base;
|
|
4
|
+
api;
|
|
5
|
+
f;
|
|
6
|
+
authToken;
|
|
7
|
+
constructor(cfg) {
|
|
8
|
+
if (!cfg.appServerUrl) throw new Error("appServerUrl is required");
|
|
9
|
+
if (!cfg.apiBasePath) throw new Error("apiBasePath is required");
|
|
10
|
+
this.base = cfg.appServerUrl.replace(/\/$/, "");
|
|
11
|
+
this.api = (cfg.apiBasePath.startsWith("/") ? cfg.apiBasePath : `/${cfg.apiBasePath}`).replace(/\/$/, "");
|
|
12
|
+
if (cfg.authToken) this.authToken = cfg.authToken;
|
|
13
|
+
if (cfg.fetch) {
|
|
14
|
+
this.f = cfg.fetch;
|
|
15
|
+
} else if (typeof window !== "undefined" && typeof window.fetch === "function") {
|
|
16
|
+
this.f = window.fetch.bind(window);
|
|
17
|
+
} else {
|
|
18
|
+
this.f = fetch;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
setAuthToken(token) {
|
|
22
|
+
this.authToken = token;
|
|
23
|
+
}
|
|
24
|
+
async health() {
|
|
25
|
+
const r = await this.f(`${this.base}${this.api}/health`);
|
|
26
|
+
if (!r.ok) throw new Error(`health failed: ${r.statusText}`);
|
|
27
|
+
return r.json();
|
|
28
|
+
}
|
|
29
|
+
async registerApp(reg) {
|
|
30
|
+
const r = await this.f(`${this.base}${this.api}/apps/register`, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: { "Content-Type": "application/json", ...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {} },
|
|
33
|
+
body: JSON.stringify(reg)
|
|
34
|
+
});
|
|
35
|
+
const j = await r.json();
|
|
36
|
+
if (!r.ok || !j.success) throw new Error(j.error || r.statusText);
|
|
37
|
+
return j;
|
|
38
|
+
}
|
|
39
|
+
async updateSchema(appKey, actions) {
|
|
40
|
+
const r = await this.f(`${this.base}${this.api}/apps/${encodeURIComponent(appKey)}/schema`, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: { "Content-Type": "application/json", ...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {} },
|
|
43
|
+
body: JSON.stringify(actions)
|
|
44
|
+
});
|
|
45
|
+
const j = await r.json();
|
|
46
|
+
if (!r.ok || !j.success) throw new Error(j.error || r.statusText);
|
|
47
|
+
return j;
|
|
48
|
+
}
|
|
49
|
+
async getSchema(appKey) {
|
|
50
|
+
const r = await this.f(`${this.base}${this.api}/apps/${encodeURIComponent(appKey)}/schema`, { headers: { ...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {} } });
|
|
51
|
+
const j = await r.json();
|
|
52
|
+
if (!r.ok || !j.success) throw new Error(j.error || r.statusText);
|
|
53
|
+
return j;
|
|
54
|
+
}
|
|
55
|
+
async createSession(appKey, token) {
|
|
56
|
+
const r = await this.f(`${this.base}${this.api}/app/${encodeURIComponent(appKey)}/session`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify({ token })
|
|
60
|
+
});
|
|
61
|
+
const j = await r.json();
|
|
62
|
+
if (!r.ok || !j.success) throw new Error(j.error || r.statusText);
|
|
63
|
+
return j;
|
|
64
|
+
}
|
|
65
|
+
async invokeAction(appKey, action, payload, origin) {
|
|
66
|
+
const r = await this.f(`${this.base}${this.api}/app/${encodeURIComponent(appKey)}/${encodeURIComponent(action)}`, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: { "Content-Type": "text/plain", ...origin ? { Origin: origin } : {} },
|
|
69
|
+
body: payload
|
|
70
|
+
});
|
|
71
|
+
const j = await r.json();
|
|
72
|
+
if (!r.ok || !j.success) throw new Error(j.error || r.statusText);
|
|
73
|
+
return j;
|
|
74
|
+
}
|
|
75
|
+
async read(appKey, uri) {
|
|
76
|
+
const u = new URL(`${this.base}${this.api}/app/${encodeURIComponent(appKey)}/read`);
|
|
77
|
+
u.searchParams.set("uri", uri);
|
|
78
|
+
const r = await this.f(u.toString());
|
|
79
|
+
const j = await r.json();
|
|
80
|
+
if (!r.ok || !j.success) throw new Error(j.error || r.statusText);
|
|
81
|
+
return j;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
AppsClient
|
|
87
|
+
};
|