@peerbit/server 1.1.2 → 2.0.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/lib/esm/cli.js +471 -144
- package/lib/esm/cli.js.map +1 -1
- package/lib/esm/client.d.ts +5 -3
- package/lib/esm/client.js +25 -8
- package/lib/esm/client.js.map +1 -1
- package/lib/esm/config.d.ts +7 -4
- package/lib/esm/config.js +31 -8
- package/lib/esm/config.js.map +1 -1
- package/lib/esm/peerbit.d.ts +2 -0
- package/lib/esm/peerbit.js +14 -2
- package/lib/esm/peerbit.js.map +1 -1
- package/lib/esm/remotes.browser.d.ts +0 -0
- package/lib/esm/remotes.browser.js +3 -0
- package/lib/esm/remotes.browser.js.map +1 -0
- package/lib/esm/remotes.d.ts +17 -0
- package/lib/esm/remotes.js +52 -0
- package/lib/esm/remotes.js.map +1 -0
- package/lib/esm/routes.d.ts +2 -0
- package/lib/esm/routes.js +2 -0
- package/lib/esm/routes.js.map +1 -1
- package/lib/esm/server.d.ts +17 -3
- package/lib/esm/server.js +213 -45
- package/lib/esm/server.js.map +1 -1
- package/lib/esm/session.d.ts +19 -0
- package/lib/esm/session.js +49 -0
- package/lib/esm/session.js.map +1 -0
- package/lib/esm/types.d.ts +10 -0
- package/lib/ui/assets/{index-a8188422.js → index-73eaa3bc.js} +10 -10
- package/lib/ui/index.html +1 -1
- package/package.json +7 -3
- package/src/cli.ts +649 -271
- package/src/client.ts +43 -10
- package/src/config.ts +40 -11
- package/src/peerbit.ts +24 -3
- package/src/remotes.browser.ts +1 -0
- package/src/remotes.ts +65 -0
- package/src/routes.ts +2 -0
- package/src/server.ts +278 -51
- package/src/session.ts +69 -0
- package/src/types.ts +13 -0
- package/lib/ui/assets/config.browser-4ed993c7.js +0 -1
package/src/server.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import http from "http";
|
|
2
|
-
import { fromBase64 } from "@peerbit/crypto";
|
|
2
|
+
import { fromBase64, sha256Base64Sync } from "@peerbit/crypto";
|
|
3
3
|
import { deserialize } from "@dao-xyz/borsh";
|
|
4
4
|
import {
|
|
5
5
|
Program,
|
|
@@ -16,33 +16,59 @@ import {
|
|
|
16
16
|
getPackageName,
|
|
17
17
|
loadPassword,
|
|
18
18
|
NotFoundError,
|
|
19
|
+
getNodePath,
|
|
19
20
|
} from "./config.js";
|
|
20
21
|
import { setMaxListeners } from "events";
|
|
21
22
|
import { create } from "./peerbit.js";
|
|
22
23
|
import { Peerbit } from "peerbit";
|
|
23
24
|
import { getSchema } from "@dao-xyz/borsh";
|
|
24
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
InstallDependency,
|
|
27
|
+
StartByBase64,
|
|
28
|
+
StartByVariant,
|
|
29
|
+
StartProgram,
|
|
30
|
+
} from "./types.js";
|
|
25
31
|
import {
|
|
26
32
|
ADDRESS_PATH,
|
|
27
33
|
BOOTSTRAP_PATH,
|
|
34
|
+
TERMINATE_PATH,
|
|
28
35
|
INSTALL_PATH,
|
|
29
36
|
LOCAL_PORT,
|
|
30
37
|
PEER_ID_PATH,
|
|
31
38
|
PROGRAMS_PATH,
|
|
32
39
|
PROGRAM_PATH,
|
|
40
|
+
RESTART_PATH,
|
|
33
41
|
} from "./routes.js";
|
|
34
|
-
import {
|
|
35
|
-
|
|
42
|
+
import { Session } from "./session.js";
|
|
43
|
+
import fs from "fs";
|
|
44
|
+
import { exit } from "process";
|
|
45
|
+
import { spawn, fork, execSync } from "child_process";
|
|
46
|
+
import tmp from "tmp";
|
|
47
|
+
import path from "path";
|
|
48
|
+
import { base58btc } from "multiformats/bases/base58";
|
|
36
49
|
import { dirname } from "path";
|
|
37
50
|
import { fileURLToPath } from "url";
|
|
51
|
+
import { Level } from "level";
|
|
52
|
+
import { MemoryLevel } from "memory-level";
|
|
38
53
|
|
|
39
54
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
40
55
|
|
|
41
|
-
export const
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
export const stopAndWait = (server: http.Server) => {
|
|
57
|
+
let closed = false;
|
|
58
|
+
server.on("close", () => {
|
|
59
|
+
closed = true;
|
|
60
|
+
});
|
|
61
|
+
server.close();
|
|
62
|
+
return waitFor(() => closed);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const createPassword = async (
|
|
66
|
+
configDirectory: string,
|
|
67
|
+
password?: string
|
|
68
|
+
): Promise<string> => {
|
|
69
|
+
const configDir = configDirectory ?? (await getHomeConfigDir());
|
|
44
70
|
const credentialsPath = await getCredentialsPath(configDir);
|
|
45
|
-
if (await checkExistPath(credentialsPath)) {
|
|
71
|
+
if (!password && (await checkExistPath(credentialsPath))) {
|
|
46
72
|
throw new Error(
|
|
47
73
|
"Config path for credentials: " + credentialsPath + ", already exist"
|
|
48
74
|
);
|
|
@@ -54,46 +80,99 @@ export const createPassword = async (): Promise<string> => {
|
|
|
54
80
|
|
|
55
81
|
console.log(`Created config folder ${configDir}`);
|
|
56
82
|
|
|
57
|
-
|
|
83
|
+
password = password || uuid();
|
|
58
84
|
fs.writeFileSync(
|
|
59
85
|
credentialsPath,
|
|
60
86
|
JSON.stringify({ username: "admin", password })
|
|
61
87
|
);
|
|
62
88
|
console.log(`Created credentials at ${credentialsPath}`);
|
|
63
|
-
return password
|
|
89
|
+
return password!;
|
|
64
90
|
};
|
|
65
91
|
|
|
66
|
-
export const loadOrCreatePassword = async (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
export const loadOrCreatePassword = async (
|
|
93
|
+
configDirectory: string,
|
|
94
|
+
password?: string
|
|
95
|
+
): Promise<string> => {
|
|
96
|
+
if (!password) {
|
|
97
|
+
try {
|
|
98
|
+
return await loadPassword(configDirectory);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (error instanceof NotFoundError) {
|
|
101
|
+
return createPassword(configDirectory, password);
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
72
104
|
}
|
|
73
|
-
|
|
105
|
+
} else {
|
|
106
|
+
return createPassword(configDirectory, password);
|
|
74
107
|
}
|
|
75
108
|
};
|
|
76
109
|
export const startServerWithNode = async (properties: {
|
|
77
110
|
directory?: string;
|
|
78
111
|
domain?: string;
|
|
79
112
|
bootstrap?: boolean;
|
|
113
|
+
newSession?: boolean;
|
|
114
|
+
password?: string;
|
|
115
|
+
ports?: {
|
|
116
|
+
node: number;
|
|
117
|
+
api: number;
|
|
118
|
+
};
|
|
119
|
+
restart?: () => void;
|
|
80
120
|
}) => {
|
|
81
121
|
const peer = await create({
|
|
82
|
-
directory:
|
|
122
|
+
directory:
|
|
123
|
+
properties.directory != null
|
|
124
|
+
? getNodePath(properties.directory)
|
|
125
|
+
: undefined,
|
|
83
126
|
domain: properties.domain,
|
|
127
|
+
listenPort: properties.ports?.node,
|
|
84
128
|
});
|
|
85
129
|
|
|
86
130
|
if (properties.bootstrap) {
|
|
87
131
|
await peer.bootstrap();
|
|
88
132
|
}
|
|
133
|
+
const sessionDirectory =
|
|
134
|
+
properties.directory != null
|
|
135
|
+
? path.join(properties.directory, "session")
|
|
136
|
+
: undefined;
|
|
137
|
+
const session = new Session(
|
|
138
|
+
sessionDirectory
|
|
139
|
+
? new Level<string, Uint8Array>(sessionDirectory, {
|
|
140
|
+
valueEncoding: "view",
|
|
141
|
+
keyEncoding: "utf-8",
|
|
142
|
+
})
|
|
143
|
+
: new MemoryLevel({ valueEncoding: "view", keyEncoding: "utf-8" })
|
|
144
|
+
);
|
|
145
|
+
if (!properties.newSession) {
|
|
146
|
+
for (const [string] of await session.imports.all()) {
|
|
147
|
+
await import(string);
|
|
148
|
+
}
|
|
149
|
+
for (const [address] of await session.programs.all()) {
|
|
150
|
+
// TODO args
|
|
151
|
+
try {
|
|
152
|
+
await peer.open(address, { timeout: 3000 });
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error(error);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
await session.clear();
|
|
159
|
+
}
|
|
89
160
|
|
|
90
|
-
const server = await
|
|
161
|
+
const server = await startApiServer(peer, {
|
|
162
|
+
port: properties.ports?.api,
|
|
163
|
+
configDirectory:
|
|
164
|
+
properties.directory != null
|
|
165
|
+
? path.join(properties.directory, "server")
|
|
166
|
+
: undefined || getHomeConfigDir(),
|
|
167
|
+
session,
|
|
168
|
+
password: properties.password,
|
|
169
|
+
});
|
|
91
170
|
const printNodeInfo = async () => {
|
|
92
171
|
console.log("Starting node with address(es): ");
|
|
93
|
-
const id =
|
|
172
|
+
const id = peer.peerId.toString();
|
|
94
173
|
console.log("id: " + id);
|
|
95
174
|
console.log("Addresses: ");
|
|
96
|
-
for (const a of
|
|
175
|
+
for (const a of peer.getMultiaddrs()) {
|
|
97
176
|
console.log(a.toString());
|
|
98
177
|
}
|
|
99
178
|
};
|
|
@@ -101,16 +180,26 @@ export const startServerWithNode = async (properties: {
|
|
|
101
180
|
await printNodeInfo();
|
|
102
181
|
const shutDownHook = async (
|
|
103
182
|
controller: { stop: () => any },
|
|
104
|
-
server:
|
|
105
|
-
close: () => void;
|
|
106
|
-
}
|
|
183
|
+
server: http.Server
|
|
107
184
|
) => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
185
|
+
["SIGTERM", "SIGINT", "SIGUSR1", "SIGUSR2"].forEach((code) => {
|
|
186
|
+
process.on(code, async () => {
|
|
187
|
+
if (server.listening) {
|
|
188
|
+
console.log("Shutting down node");
|
|
189
|
+
await stopAndWait(server);
|
|
190
|
+
await waitFor(() => closed);
|
|
191
|
+
await controller.stop();
|
|
192
|
+
}
|
|
193
|
+
exit();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
process.on("exit", async () => {
|
|
197
|
+
if (server.listening) {
|
|
198
|
+
console.log("Shutting down node");
|
|
199
|
+
await stopAndWait(server);
|
|
200
|
+
await waitFor(() => closed);
|
|
201
|
+
await controller.stop();
|
|
202
|
+
}
|
|
114
203
|
});
|
|
115
204
|
};
|
|
116
205
|
await shutDownHook(peer, server);
|
|
@@ -133,14 +222,78 @@ const getProgramFromPath = (
|
|
|
133
222
|
throw new Error("Invalid path");
|
|
134
223
|
}
|
|
135
224
|
const address = decodeURIComponent(path[pathIndex]);
|
|
136
|
-
return client.handler
|
|
225
|
+
return client.handler?.items.get(address);
|
|
137
226
|
};
|
|
227
|
+
function findPeerbitProgramFolder(inputDirectory: string): string | null {
|
|
228
|
+
let currentDir = path.resolve(inputDirectory);
|
|
229
|
+
|
|
230
|
+
while (currentDir !== "/") {
|
|
231
|
+
// Stop at the root directory
|
|
232
|
+
const nodeModulesPath = path.join(currentDir, "node_modules");
|
|
233
|
+
const packageJsonPath = path.join(
|
|
234
|
+
nodeModulesPath,
|
|
235
|
+
"@peerbit",
|
|
236
|
+
"program",
|
|
237
|
+
"package.json"
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
241
|
+
const packageJsonContent = fs.readFileSync(packageJsonPath, "utf-8");
|
|
242
|
+
const packageData = JSON.parse(packageJsonContent);
|
|
138
243
|
|
|
139
|
-
|
|
244
|
+
if (packageData.name === "@peerbit/program") {
|
|
245
|
+
return currentDir;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
currentDir = path.dirname(currentDir);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export const startApiServer = async (
|
|
140
256
|
client: ProgramClient,
|
|
141
|
-
|
|
257
|
+
options: {
|
|
258
|
+
configDirectory: string;
|
|
259
|
+
session?: Session;
|
|
260
|
+
port?: number;
|
|
261
|
+
password?: string;
|
|
262
|
+
}
|
|
142
263
|
): Promise<http.Server> => {
|
|
143
|
-
const
|
|
264
|
+
const port = options?.port ?? LOCAL_PORT;
|
|
265
|
+
const password = await loadOrCreatePassword(
|
|
266
|
+
options.configDirectory,
|
|
267
|
+
options?.password
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const restart = async () => {
|
|
271
|
+
await client.stop();
|
|
272
|
+
await stopAndWait(server);
|
|
273
|
+
|
|
274
|
+
// We filter out the reset command, since restarting means that we want to resume something
|
|
275
|
+
spawn(
|
|
276
|
+
process.argv.shift()!,
|
|
277
|
+
[
|
|
278
|
+
...process.execArgv,
|
|
279
|
+
...process.argv.filter((x) => x !== "--reset" && x !== "-r"),
|
|
280
|
+
],
|
|
281
|
+
{
|
|
282
|
+
cwd: process.cwd(),
|
|
283
|
+
detached: true,
|
|
284
|
+
stdio: "inherit",
|
|
285
|
+
gid: process.getgid!(),
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
/* process.on("exit", async () => {
|
|
290
|
+
child.kill("SIGINT")
|
|
291
|
+
});
|
|
292
|
+
process.on("SIGINT", async () => {
|
|
293
|
+
child.kill("SIGINT")
|
|
294
|
+
}); */
|
|
295
|
+
process.exit(0);
|
|
296
|
+
};
|
|
144
297
|
|
|
145
298
|
const adminACL = (req: http.IncomingMessage): boolean => {
|
|
146
299
|
const auth = req.headers["authorization"];
|
|
@@ -203,9 +356,8 @@ export const startServer = async (
|
|
|
203
356
|
switch (req.method) {
|
|
204
357
|
case "GET":
|
|
205
358
|
try {
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
]);
|
|
359
|
+
const ref = (client as Peerbit).handler?.items?.keys() || [];
|
|
360
|
+
const keys = JSON.stringify([...ref]);
|
|
209
361
|
res.setHeader("Content-Type", "application/json");
|
|
210
362
|
res.writeHead(200);
|
|
211
363
|
res.end(keys);
|
|
@@ -249,11 +401,16 @@ export const startServer = async (
|
|
|
249
401
|
|
|
250
402
|
const program = getProgramFromPath(client as Peerbit, req, 1);
|
|
251
403
|
if (program) {
|
|
404
|
+
let closed = false;
|
|
252
405
|
if (queryData === "true") {
|
|
253
|
-
await program.drop();
|
|
406
|
+
closed = await program.drop();
|
|
254
407
|
} else {
|
|
255
|
-
await program.close();
|
|
408
|
+
closed = await program.close();
|
|
409
|
+
}
|
|
410
|
+
if (closed) {
|
|
411
|
+
await options?.session?.programs.remove(program.address);
|
|
256
412
|
}
|
|
413
|
+
|
|
257
414
|
res.writeHead(200);
|
|
258
415
|
res.end();
|
|
259
416
|
} else {
|
|
@@ -292,7 +449,18 @@ export const startServer = async (
|
|
|
292
449
|
}
|
|
293
450
|
client
|
|
294
451
|
.open(program) // TODO all users to pass args
|
|
295
|
-
.then((program) => {
|
|
452
|
+
.then(async (program) => {
|
|
453
|
+
// TODO what if this is a reopen?
|
|
454
|
+
console.log(
|
|
455
|
+
"OPEN ADDRESS",
|
|
456
|
+
program.address,
|
|
457
|
+
(client as Peerbit).directory,
|
|
458
|
+
await client.services.blocks.has(program.address)
|
|
459
|
+
);
|
|
460
|
+
await options?.session?.programs.add(
|
|
461
|
+
program.address,
|
|
462
|
+
new Uint8Array()
|
|
463
|
+
);
|
|
296
464
|
res.writeHead(200);
|
|
297
465
|
res.end(program.address.toString());
|
|
298
466
|
})
|
|
@@ -315,31 +483,60 @@ export const startServer = async (
|
|
|
315
483
|
switch (req.method) {
|
|
316
484
|
case "PUT":
|
|
317
485
|
getBody(req, async (body) => {
|
|
318
|
-
const
|
|
486
|
+
const installArgs: InstallDependency = JSON.parse(body);
|
|
319
487
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
488
|
+
const packageName = installArgs.name; // @abc/123
|
|
489
|
+
let installName = installArgs.name; // abc123.tgz or @abc/123 (npm package name)
|
|
490
|
+
let clear: (() => void) | undefined;
|
|
491
|
+
if (installArgs.type === "tgz") {
|
|
492
|
+
const binary = fromBase64(installArgs.base64);
|
|
493
|
+
const tempFile = tmp.fileSync({
|
|
494
|
+
name:
|
|
495
|
+
base58btc.encode(Buffer.from(installName)) +
|
|
496
|
+
uuid() +
|
|
497
|
+
".tgz",
|
|
498
|
+
});
|
|
499
|
+
fs.writeFileSync(tempFile.fd, binary);
|
|
500
|
+
clear = () => tempFile.removeCallback();
|
|
501
|
+
installName = tempFile.name;
|
|
502
|
+
} else {
|
|
503
|
+
clear = undefined;
|
|
323
504
|
}
|
|
324
505
|
|
|
325
|
-
if (!
|
|
506
|
+
if (!installName || installName.length === 0) {
|
|
326
507
|
res.writeHead(400);
|
|
327
|
-
res.end("Invalid package: " +
|
|
508
|
+
res.end("Invalid package: " + packageName);
|
|
328
509
|
} else {
|
|
329
|
-
const child_process = await import("child_process");
|
|
330
510
|
try {
|
|
331
511
|
// TODO do this without sudo. i.e. for servers provide arguments so that this app folder is writeable by default by the user
|
|
332
|
-
|
|
333
|
-
|
|
512
|
+
const installDir =
|
|
513
|
+
process.env.PEERBIT_MODULES_PATH ||
|
|
514
|
+
findPeerbitProgramFolder(__dirname);
|
|
515
|
+
let permission = "";
|
|
516
|
+
if (!installDir) {
|
|
517
|
+
res.writeHead(400);
|
|
518
|
+
res.end("Missing installation directory");
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
try {
|
|
522
|
+
fs.accessSync(installDir, fs.constants.W_OK);
|
|
523
|
+
} catch (error) {
|
|
524
|
+
permission = "sudo";
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
console.log("Installing package: " + installName);
|
|
528
|
+
execSync(
|
|
529
|
+
`${permission} npm install ${installName} --prefix ${installDir} --no-save --no-package-lock`
|
|
334
530
|
); // TODO omit=dev ? but this makes breaks the tests after running once?
|
|
335
531
|
} catch (error: any) {
|
|
336
532
|
res.writeHead(400);
|
|
337
533
|
res.end(
|
|
338
|
-
"Failed
|
|
339
|
-
|
|
534
|
+
"Failed to install library: " +
|
|
535
|
+
packageName +
|
|
340
536
|
". " +
|
|
341
537
|
error.toString()
|
|
342
538
|
);
|
|
539
|
+
clear?.();
|
|
343
540
|
return;
|
|
344
541
|
}
|
|
345
542
|
|
|
@@ -353,6 +550,10 @@ export const startServer = async (
|
|
|
353
550
|
await import(
|
|
354
551
|
/* webpackIgnore: true */ /* @vite-ignore */ packageName
|
|
355
552
|
);
|
|
553
|
+
await options?.session?.imports.add(
|
|
554
|
+
packageName,
|
|
555
|
+
new Uint8Array()
|
|
556
|
+
);
|
|
356
557
|
const programsPost = getProgramFromVariants()?.map((x) =>
|
|
357
558
|
getSchema(x)
|
|
358
559
|
);
|
|
@@ -370,6 +571,7 @@ export const startServer = async (
|
|
|
370
571
|
} catch (e: any) {
|
|
371
572
|
res.writeHead(400);
|
|
372
573
|
res.end(e.message.toString?.());
|
|
574
|
+
clear?.();
|
|
373
575
|
}
|
|
374
576
|
}
|
|
375
577
|
});
|
|
@@ -392,6 +594,30 @@ export const startServer = async (
|
|
|
392
594
|
res.end();
|
|
393
595
|
break;
|
|
394
596
|
|
|
597
|
+
default:
|
|
598
|
+
r404();
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
} else if (req.url.startsWith(RESTART_PATH)) {
|
|
602
|
+
switch (req.method) {
|
|
603
|
+
case "POST":
|
|
604
|
+
res.writeHead(200);
|
|
605
|
+
res.end();
|
|
606
|
+
restart();
|
|
607
|
+
break;
|
|
608
|
+
|
|
609
|
+
default:
|
|
610
|
+
r404();
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
} else if (req.url.startsWith(TERMINATE_PATH)) {
|
|
614
|
+
switch (req.method) {
|
|
615
|
+
case "POST":
|
|
616
|
+
res.writeHead(200);
|
|
617
|
+
res.end();
|
|
618
|
+
process.exit(0);
|
|
619
|
+
break;
|
|
620
|
+
|
|
395
621
|
default:
|
|
396
622
|
r404();
|
|
397
623
|
break;
|
|
@@ -431,6 +657,7 @@ export const startServer = async (
|
|
|
431
657
|
});
|
|
432
658
|
});
|
|
433
659
|
});
|
|
660
|
+
await waitFor(() => server.listening);
|
|
434
661
|
console.log("API available at port", port);
|
|
435
662
|
return server;
|
|
436
663
|
};
|
package/src/session.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AbstractLevel } from "abstract-level";
|
|
2
|
+
|
|
3
|
+
export class Session {
|
|
4
|
+
programs: KV;
|
|
5
|
+
imports: KV;
|
|
6
|
+
constructor(
|
|
7
|
+
readonly level: AbstractLevel<
|
|
8
|
+
string | Buffer | Uint8Array,
|
|
9
|
+
string,
|
|
10
|
+
Uint8Array
|
|
11
|
+
>
|
|
12
|
+
) {
|
|
13
|
+
this.imports = new KV(
|
|
14
|
+
this.level.sublevel<string, Uint8Array>("imports", {
|
|
15
|
+
keyEncoding: "utf8",
|
|
16
|
+
valueEncoding: "view",
|
|
17
|
+
})
|
|
18
|
+
);
|
|
19
|
+
this.programs = new KV(
|
|
20
|
+
this.level.sublevel<string, Uint8Array>("programs", {
|
|
21
|
+
keyEncoding: "utf8",
|
|
22
|
+
valueEncoding: "view",
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async clear() {
|
|
28
|
+
await this.imports.clear();
|
|
29
|
+
await this.programs.clear();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class KV {
|
|
34
|
+
constructor(
|
|
35
|
+
readonly level: AbstractLevel<
|
|
36
|
+
string | Buffer | Uint8Array,
|
|
37
|
+
string,
|
|
38
|
+
Uint8Array
|
|
39
|
+
>
|
|
40
|
+
) {}
|
|
41
|
+
|
|
42
|
+
add(key: string, arg: Uint8Array) {
|
|
43
|
+
return this.level.put(key, arg);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
remove(key: string) {
|
|
47
|
+
return this.level.del(key);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async all(): Promise<[string, Uint8Array][]> {
|
|
51
|
+
const res: [string, Uint8Array][] = [];
|
|
52
|
+
for await (const [key, value] of this.level.iterator()) {
|
|
53
|
+
res.push([key, value]);
|
|
54
|
+
}
|
|
55
|
+
return res;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async open() {
|
|
59
|
+
await this.level.open();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async close() {
|
|
63
|
+
await this.level.close();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async clear() {
|
|
67
|
+
await this.level.clear();
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -5,3 +5,16 @@ export interface StartByBase64 {
|
|
|
5
5
|
base64: string;
|
|
6
6
|
}
|
|
7
7
|
export type StartProgram = StartByVariant | StartByBase64;
|
|
8
|
+
|
|
9
|
+
export interface InstallWithTGZ {
|
|
10
|
+
type: "tgz";
|
|
11
|
+
name: string;
|
|
12
|
+
base64: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface InstallWithNPM {
|
|
16
|
+
type: "npm";
|
|
17
|
+
name: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type InstallDependency = InstallWithTGZ | InstallWithNPM;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|