@peerbit/server 1.1.1 → 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 +34 -17
- package/lib/esm/config.js.map +1 -1
- package/lib/esm/peerbit.d.ts +2 -0
- package/lib/esm/peerbit.js +17 -3
- 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 +217 -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 +44 -21
- package/src/peerbit.ts +27 -4
- package/src/remotes.browser.ts +1 -0
- package/src/remotes.ts +65 -0
- package/src/routes.ts +2 -0
- package/src/server.ts +284 -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,
|
|
@@ -11,33 +11,64 @@ import { waitFor } from "@peerbit/time";
|
|
|
11
11
|
import { v4 as uuid } from "uuid";
|
|
12
12
|
import {
|
|
13
13
|
checkExistPath,
|
|
14
|
-
|
|
14
|
+
getHomeConfigDir,
|
|
15
15
|
getCredentialsPath,
|
|
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 {
|
|
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";
|
|
49
|
+
import { dirname } from "path";
|
|
50
|
+
import { fileURLToPath } from "url";
|
|
51
|
+
import { Level } from "level";
|
|
52
|
+
import { MemoryLevel } from "memory-level";
|
|
53
|
+
|
|
54
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
55
|
+
|
|
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
|
+
};
|
|
35
64
|
|
|
36
|
-
export const createPassword = async (
|
|
37
|
-
|
|
38
|
-
|
|
65
|
+
export const createPassword = async (
|
|
66
|
+
configDirectory: string,
|
|
67
|
+
password?: string
|
|
68
|
+
): Promise<string> => {
|
|
69
|
+
const configDir = configDirectory ?? (await getHomeConfigDir());
|
|
39
70
|
const credentialsPath = await getCredentialsPath(configDir);
|
|
40
|
-
if (await checkExistPath(credentialsPath)) {
|
|
71
|
+
if (!password && (await checkExistPath(credentialsPath))) {
|
|
41
72
|
throw new Error(
|
|
42
73
|
"Config path for credentials: " + credentialsPath + ", already exist"
|
|
43
74
|
);
|
|
@@ -49,46 +80,99 @@ export const createPassword = async (): Promise<string> => {
|
|
|
49
80
|
|
|
50
81
|
console.log(`Created config folder ${configDir}`);
|
|
51
82
|
|
|
52
|
-
|
|
83
|
+
password = password || uuid();
|
|
53
84
|
fs.writeFileSync(
|
|
54
85
|
credentialsPath,
|
|
55
86
|
JSON.stringify({ username: "admin", password })
|
|
56
87
|
);
|
|
57
88
|
console.log(`Created credentials at ${credentialsPath}`);
|
|
58
|
-
return password
|
|
89
|
+
return password!;
|
|
59
90
|
};
|
|
60
91
|
|
|
61
|
-
export const loadOrCreatePassword = async (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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;
|
|
67
104
|
}
|
|
68
|
-
|
|
105
|
+
} else {
|
|
106
|
+
return createPassword(configDirectory, password);
|
|
69
107
|
}
|
|
70
108
|
};
|
|
71
109
|
export const startServerWithNode = async (properties: {
|
|
72
110
|
directory?: string;
|
|
73
111
|
domain?: string;
|
|
74
112
|
bootstrap?: boolean;
|
|
113
|
+
newSession?: boolean;
|
|
114
|
+
password?: string;
|
|
115
|
+
ports?: {
|
|
116
|
+
node: number;
|
|
117
|
+
api: number;
|
|
118
|
+
};
|
|
119
|
+
restart?: () => void;
|
|
75
120
|
}) => {
|
|
76
121
|
const peer = await create({
|
|
77
|
-
directory:
|
|
122
|
+
directory:
|
|
123
|
+
properties.directory != null
|
|
124
|
+
? getNodePath(properties.directory)
|
|
125
|
+
: undefined,
|
|
78
126
|
domain: properties.domain,
|
|
127
|
+
listenPort: properties.ports?.node,
|
|
79
128
|
});
|
|
80
129
|
|
|
81
130
|
if (properties.bootstrap) {
|
|
82
131
|
await peer.bootstrap();
|
|
83
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
|
+
}
|
|
84
160
|
|
|
85
|
-
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
|
+
});
|
|
86
170
|
const printNodeInfo = async () => {
|
|
87
171
|
console.log("Starting node with address(es): ");
|
|
88
|
-
const id =
|
|
172
|
+
const id = peer.peerId.toString();
|
|
89
173
|
console.log("id: " + id);
|
|
90
174
|
console.log("Addresses: ");
|
|
91
|
-
for (const a of
|
|
175
|
+
for (const a of peer.getMultiaddrs()) {
|
|
92
176
|
console.log(a.toString());
|
|
93
177
|
}
|
|
94
178
|
};
|
|
@@ -96,16 +180,26 @@ export const startServerWithNode = async (properties: {
|
|
|
96
180
|
await printNodeInfo();
|
|
97
181
|
const shutDownHook = async (
|
|
98
182
|
controller: { stop: () => any },
|
|
99
|
-
server:
|
|
100
|
-
close: () => void;
|
|
101
|
-
}
|
|
183
|
+
server: http.Server
|
|
102
184
|
) => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
+
}
|
|
109
203
|
});
|
|
110
204
|
};
|
|
111
205
|
await shutDownHook(peer, server);
|
|
@@ -128,14 +222,78 @@ const getProgramFromPath = (
|
|
|
128
222
|
throw new Error("Invalid path");
|
|
129
223
|
}
|
|
130
224
|
const address = decodeURIComponent(path[pathIndex]);
|
|
131
|
-
return client.handler
|
|
225
|
+
return client.handler?.items.get(address);
|
|
132
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);
|
|
133
243
|
|
|
134
|
-
|
|
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 (
|
|
135
256
|
client: ProgramClient,
|
|
136
|
-
|
|
257
|
+
options: {
|
|
258
|
+
configDirectory: string;
|
|
259
|
+
session?: Session;
|
|
260
|
+
port?: number;
|
|
261
|
+
password?: string;
|
|
262
|
+
}
|
|
137
263
|
): Promise<http.Server> => {
|
|
138
|
-
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
|
+
};
|
|
139
297
|
|
|
140
298
|
const adminACL = (req: http.IncomingMessage): boolean => {
|
|
141
299
|
const auth = req.headers["authorization"];
|
|
@@ -198,9 +356,8 @@ export const startServer = async (
|
|
|
198
356
|
switch (req.method) {
|
|
199
357
|
case "GET":
|
|
200
358
|
try {
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
]);
|
|
359
|
+
const ref = (client as Peerbit).handler?.items?.keys() || [];
|
|
360
|
+
const keys = JSON.stringify([...ref]);
|
|
204
361
|
res.setHeader("Content-Type", "application/json");
|
|
205
362
|
res.writeHead(200);
|
|
206
363
|
res.end(keys);
|
|
@@ -244,11 +401,16 @@ export const startServer = async (
|
|
|
244
401
|
|
|
245
402
|
const program = getProgramFromPath(client as Peerbit, req, 1);
|
|
246
403
|
if (program) {
|
|
404
|
+
let closed = false;
|
|
247
405
|
if (queryData === "true") {
|
|
248
|
-
await program.drop();
|
|
406
|
+
closed = await program.drop();
|
|
249
407
|
} else {
|
|
250
|
-
await program.close();
|
|
408
|
+
closed = await program.close();
|
|
409
|
+
}
|
|
410
|
+
if (closed) {
|
|
411
|
+
await options?.session?.programs.remove(program.address);
|
|
251
412
|
}
|
|
413
|
+
|
|
252
414
|
res.writeHead(200);
|
|
253
415
|
res.end();
|
|
254
416
|
} else {
|
|
@@ -287,7 +449,18 @@ export const startServer = async (
|
|
|
287
449
|
}
|
|
288
450
|
client
|
|
289
451
|
.open(program) // TODO all users to pass args
|
|
290
|
-
.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
|
+
);
|
|
291
464
|
res.writeHead(200);
|
|
292
465
|
res.end(program.address.toString());
|
|
293
466
|
})
|
|
@@ -310,30 +483,60 @@ export const startServer = async (
|
|
|
310
483
|
switch (req.method) {
|
|
311
484
|
case "PUT":
|
|
312
485
|
getBody(req, async (body) => {
|
|
313
|
-
const
|
|
486
|
+
const installArgs: InstallDependency = JSON.parse(body);
|
|
314
487
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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;
|
|
318
504
|
}
|
|
319
505
|
|
|
320
|
-
if (!
|
|
506
|
+
if (!installName || installName.length === 0) {
|
|
321
507
|
res.writeHead(400);
|
|
322
|
-
res.end("Invalid package: " +
|
|
508
|
+
res.end("Invalid package: " + packageName);
|
|
323
509
|
} else {
|
|
324
|
-
const child_process = await import("child_process");
|
|
325
510
|
try {
|
|
326
|
-
|
|
327
|
-
|
|
511
|
+
// TODO do this without sudo. i.e. for servers provide arguments so that this app folder is writeable by default by the user
|
|
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`
|
|
328
530
|
); // TODO omit=dev ? but this makes breaks the tests after running once?
|
|
329
531
|
} catch (error: any) {
|
|
330
532
|
res.writeHead(400);
|
|
331
533
|
res.end(
|
|
332
|
-
"Failed
|
|
333
|
-
|
|
534
|
+
"Failed to install library: " +
|
|
535
|
+
packageName +
|
|
334
536
|
". " +
|
|
335
537
|
error.toString()
|
|
336
538
|
);
|
|
539
|
+
clear?.();
|
|
337
540
|
return;
|
|
338
541
|
}
|
|
339
542
|
|
|
@@ -347,6 +550,10 @@ export const startServer = async (
|
|
|
347
550
|
await import(
|
|
348
551
|
/* webpackIgnore: true */ /* @vite-ignore */ packageName
|
|
349
552
|
);
|
|
553
|
+
await options?.session?.imports.add(
|
|
554
|
+
packageName,
|
|
555
|
+
new Uint8Array()
|
|
556
|
+
);
|
|
350
557
|
const programsPost = getProgramFromVariants()?.map((x) =>
|
|
351
558
|
getSchema(x)
|
|
352
559
|
);
|
|
@@ -364,6 +571,7 @@ export const startServer = async (
|
|
|
364
571
|
} catch (e: any) {
|
|
365
572
|
res.writeHead(400);
|
|
366
573
|
res.end(e.message.toString?.());
|
|
574
|
+
clear?.();
|
|
367
575
|
}
|
|
368
576
|
}
|
|
369
577
|
});
|
|
@@ -386,6 +594,30 @@ export const startServer = async (
|
|
|
386
594
|
res.end();
|
|
387
595
|
break;
|
|
388
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
|
+
|
|
389
621
|
default:
|
|
390
622
|
r404();
|
|
391
623
|
break;
|
|
@@ -425,6 +657,7 @@ export const startServer = async (
|
|
|
425
657
|
});
|
|
426
658
|
});
|
|
427
659
|
});
|
|
660
|
+
await waitFor(() => server.listening);
|
|
428
661
|
console.log("API available at port", port);
|
|
429
662
|
return server;
|
|
430
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
|
-
|