@peerbit/server 1.0.20 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/lib/esm/cli.js +107 -36
  2. package/lib/esm/cli.js.map +1 -1
  3. package/lib/esm/client.d.ts +25 -2
  4. package/lib/esm/client.js +105 -16
  5. package/lib/esm/client.js.map +1 -1
  6. package/lib/esm/config.browser.d.ts +0 -0
  7. package/lib/esm/config.browser.js +3 -0
  8. package/lib/esm/config.browser.js.map +1 -0
  9. package/lib/esm/config.d.ts +3 -0
  10. package/lib/esm/config.js +71 -0
  11. package/lib/esm/config.js.map +1 -1
  12. package/lib/esm/index.d.ts +3 -1
  13. package/lib/esm/index.js +3 -1
  14. package/lib/esm/index.js.map +1 -1
  15. package/lib/esm/peerbit.d.ts +5 -0
  16. package/lib/esm/peerbit.js +26 -0
  17. package/lib/esm/peerbit.js.map +1 -0
  18. package/lib/esm/routes.d.ts +9 -0
  19. package/lib/esm/routes.js +18 -0
  20. package/lib/esm/routes.js.map +1 -0
  21. package/lib/esm/server.browser.d.ts +0 -0
  22. package/lib/esm/server.browser.js +3 -0
  23. package/lib/esm/server.browser.js.map +1 -0
  24. package/lib/esm/server.d.ts +15 -0
  25. package/lib/esm/server.js +356 -0
  26. package/lib/esm/server.js.map +1 -0
  27. package/lib/esm/types.d.ts +7 -0
  28. package/lib/esm/types.js +2 -0
  29. package/lib/esm/types.js.map +1 -0
  30. package/lib/ui/assets/config.browser-4ed993c7.js +1 -0
  31. package/lib/ui/assets/index-a8188422.js +53 -0
  32. package/lib/ui/index.html +1 -1
  33. package/package.json +16 -7
  34. package/src/cli.ts +118 -43
  35. package/src/client.ts +157 -16
  36. package/src/config.browser.ts +1 -0
  37. package/src/config.ts +80 -0
  38. package/src/index.ts +3 -1
  39. package/src/peerbit.ts +26 -0
  40. package/src/routes.ts +20 -0
  41. package/src/server.browser.ts +1 -0
  42. package/src/server.ts +430 -0
  43. package/src/types.ts +7 -0
  44. package/lib/esm/api.d.ts +0 -33
  45. package/lib/esm/api.js +0 -370
  46. package/lib/esm/api.js.map +0 -1
  47. package/lib/esm/package.json +0 -3
  48. package/lib/ui/assets/index-40169014.js +0 -80
  49. package/src/api.ts +0 -436
package/lib/ui/index.html CHANGED
@@ -23,7 +23,7 @@
23
23
  Learn how to configure a non-root public URL by running `npm run build`.
24
24
  -->
25
25
  <title>Peerbit</title>
26
- <script type="module" crossorigin src="/assets/index-40169014.js"></script>
26
+ <script type="module" crossorigin src="/assets/index-a8188422.js"></script>
27
27
  <link rel="stylesheet" href="/assets/index-5265c558.css">
28
28
  </head>
29
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/server",
3
- "version": "1.0.20",
3
+ "version": "1.1.0",
4
4
  "author": "dao.xyz",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,6 +17,12 @@
17
17
  "exports": {
18
18
  "import": "./lib/esm/index.js"
19
19
  },
20
+ "browser": {
21
+ "./lib/esm/server.js": "./lib/esm/server.browser.js",
22
+ "./server.js": "./lib/esm/server.browser.js",
23
+ "./lib/esm/config.js": "./lib/esm/config.browser.js",
24
+ "./config.js": "./lib/esm/config.browser.js"
25
+ },
20
26
  "files": [
21
27
  "lib",
22
28
  "src",
@@ -30,21 +36,21 @@
30
36
  "access": "public"
31
37
  },
32
38
  "engines": {
33
- "node": ">=16.15.1"
39
+ "node": ">=18"
34
40
  },
35
41
  "scripts": {
36
42
  "clean": "shx rm -rf lib/*",
37
43
  "build": "yarn clean && yarn build-lib && yarn build-ui",
38
44
  "build-lib": "tsc -p tsconfig.json",
39
45
  "build-ui": "cd ../frontend && yarn build && cd ../node",
40
- "postbuild": "cp src/nginx-template.conf lib/esm/ && echo '{\"type\":\"module\"} ' | node ../../../../node_modules/.bin/json > lib/esm/package.json && cp -r ../frontend/dist lib/ui",
46
+ "postbuild": "cp src/nginx-template.conf lib/esm/ && cp -r ../frontend/dist lib/ui",
41
47
  "test": "node ../../../node_modules/.bin/jest test -c ../../../jest.config.ts --runInBand --forceExit",
42
48
  "test:unit": "node ../../../node_modules/.bin/jest test -c ../../../jest.config.unit.ts --runInBand --forceExit",
43
49
  "test:integration": "node ../node_modules/.bin/jest test -c ../../../jest.config.integration.ts --runInBand --forceExit"
44
50
  },
45
51
  "devDependencies": {
46
52
  "@peerbit/test-lib": "^0.0.1",
47
- "@peerbit/test-utils": "1.0.14",
53
+ "@peerbit/test-utils": "1.0.15",
48
54
  "@types/yargs": "^17.0.24",
49
55
  "aws-sdk": "^2.1259.0",
50
56
  "dotenv": "^16.1.4"
@@ -53,8 +59,11 @@
53
59
  "@aws-sdk/client-route-53": "^3.345.0",
54
60
  "@dao-xyz/libp2p-noise": "^12.0.1",
55
61
  "axios": "^1.4.0",
56
- "peerbit": "1.1.7",
57
- "yargs": "^17.7.2"
62
+ "chalk": "^5.3.0",
63
+ "peerbit": "1.2.0",
64
+ "tar-stream": "^3.1.6",
65
+ "yargs": "^17.7.2",
66
+ "zlib": "^1.0.5"
58
67
  },
59
- "gitHead": "7983b5ca2b1c8b25e2f210de5cf67dcb866a9b7d"
68
+ "gitHead": "4752c301fb49b2f937b4039533ff5bc3537da3e0"
60
69
  }
package/src/cli.ts CHANGED
@@ -4,11 +4,12 @@ import {
4
4
  loadConfig,
5
5
  startCertbot,
6
6
  } from "./domain.js";
7
- import { serialize } from "@dao-xyz/borsh";
8
- import { client, startServerWithNode } from "./api.js";
7
+ import { startServerWithNode } from "./server.js";
9
8
  import { createRecord } from "./aws.js";
10
- import { toBase64 } from "@peerbit/crypto";
11
9
  import { getConfigDir } from "./config.js";
10
+ import chalk from "chalk";
11
+ import { client } from "./client.js";
12
+ import { StartProgram } from "./types.js";
12
13
 
13
14
  export const cli = async (args?: string[]) => {
14
15
  const yargs = await import("yargs");
@@ -30,14 +31,21 @@ export const cli = async (args?: string[]) => {
30
31
  type: "string",
31
32
  default: await getConfigDir(),
32
33
  },
34
+
35
+ bootstrap: {
36
+ describe: "Whether to connect to bootstap nodes on startup",
37
+ type: "boolean",
38
+ default: false,
39
+ },
33
40
  },
34
41
  handler: async (args) => {
35
- await startServerWithNode(
36
- args.directory,
37
- await loadConfig().then((config) =>
42
+ await startServerWithNode({
43
+ directory: args.directory,
44
+ domain: await loadConfig().then((config) =>
38
45
  config ? getDomainFromConfig(config) : undefined
39
- )
40
- );
46
+ ),
47
+ bootstrap: args.bootstrap,
48
+ });
41
49
  },
42
50
  })
43
51
  .command("domain", "Setup a domain and certificate", (yargs) => {
@@ -148,6 +156,20 @@ export const cli = async (args?: string[]) => {
148
156
  .strict()
149
157
  .demandCommand();
150
158
  })
159
+ .command("network", "Manage network", (yargs) => {
160
+ yargs
161
+ .command({
162
+ command: "bootstrap",
163
+ describe: "Connect to bootstrap nodes",
164
+ handler: async () => {
165
+ const c = await client();
166
+ await c.network.bootstrap();
167
+ },
168
+ })
169
+ .strict()
170
+ .demandCommand();
171
+ })
172
+
151
173
  .command("topic", "Manage topics the node is listening to", (yargs) => {
152
174
  yargs
153
175
  .command({
@@ -184,8 +206,8 @@ export const cli = async (args?: string[]) => {
184
206
  .command("program", "Manage programs", (yargs) => {
185
207
  yargs
186
208
  .command({
187
- command: "get <address>",
188
- describe: "Get program manifest/serialized in base64",
209
+ command: "status <address>",
210
+ describe: "Is a program open",
189
211
  builder: (yargs: any) => {
190
212
  yargs.positional("address", {
191
213
  type: "string",
@@ -197,79 +219,132 @@ export const cli = async (args?: string[]) => {
197
219
 
198
220
  handler: async (args) => {
199
221
  const c = await client();
200
- const program = await c.program.get(args.address);
222
+ const program = await c.program.has(args.address);
201
223
  if (!program) {
202
- console.log("Program does not exist");
224
+ console.log(chalk.red("Closed"));
203
225
  } else {
204
- console.log(toBase64(serialize(program)));
226
+ console.log(chalk.green("Open"));
205
227
  }
206
228
  },
207
229
  })
208
230
  .command({
209
- command: "add <program>",
210
- describe: "Add program",
231
+ command: "drop <address>",
232
+ describe: "Drop a program",
211
233
  builder: (yargs: any) => {
212
- yargs.positional("program", {
234
+ yargs.positional("address", {
213
235
  type: "string",
214
- describe: "base64 serialized",
236
+ describe: "Program address",
215
237
  demandOption: true,
216
238
  });
217
239
  return yargs;
218
240
  },
241
+
219
242
  handler: async (args) => {
220
243
  const c = await client();
221
- const address = await c.program.put(args.program);
222
- console.log(address.toString());
244
+ await c.program.drop(args.address);
223
245
  },
224
246
  })
225
247
  .command({
226
- command: "import <library>",
227
- describe: "import a library that contains programs",
248
+ command: "close <address>",
249
+ describe: "Close a program",
228
250
  builder: (yargs: any) => {
229
- yargs.positional("library", {
230
- type: "array",
231
- describe:
232
- "Library name (will be loaded with js import(...)). Onlu libraries that are globally installed and can be imported",
251
+ yargs.positional("address", {
252
+ type: "string",
253
+ describe: "Program address",
233
254
  demandOption: true,
234
255
  });
235
256
  return yargs;
236
257
  },
258
+
237
259
  handler: async (args) => {
238
- for (const lib of args.library) {
239
- const importedLib = await import(
240
- /* webpackIgnore: true */ /* @vite-ignore */ lib
241
- );
242
- console.log("imported lib:", importedLib);
243
- }
260
+ const c = await client();
261
+ await c.program.close(args.address);
244
262
  },
245
263
  })
246
- .strict()
247
- .demandCommand();
248
- return yargs;
249
- })
250
- .command("library", "Manage libraries", (yargs) => {
251
- yargs
252
264
  .command({
253
- command: "add <library>",
254
- describe: "add a library that contains programs",
265
+ command: "list",
266
+ describe: "List all runniing programs",
267
+ aliases: "ls",
268
+ handler: async (args) => {
269
+ const c = await client();
270
+ const list = await c.program.list();
271
+
272
+ console.log(`Running programs (${list.length}):`);
273
+ list.forEach((p) => {
274
+ console.log(chalk.green(p));
275
+ });
276
+ },
277
+ })
278
+
279
+ .command({
280
+ command: "open [program]",
281
+ describe: "Open program",
255
282
  builder: (yargs: any) => {
256
- yargs.positional("library", {
283
+ yargs.positional("program", {
257
284
  type: "string",
258
- describe:
259
- "Library name (will be loaded with js import(...)). Onlu libraries that are globally installed and can be imported",
285
+ describe: "Identifier",
260
286
  demandOption: true,
261
287
  });
288
+ yargs.option("base64", {
289
+ type: "string",
290
+ describe: "Base64 encoded serialized",
291
+ alias: "b",
292
+ });
293
+ yargs.option("variant", {
294
+ type: "string",
295
+ describe: "Variant name",
296
+ alias: "v",
297
+ });
262
298
  return yargs;
263
299
  },
264
300
  handler: async (args) => {
265
301
  const c = await client();
266
- await c.library.put(args.library);
302
+ if (!args.base64 && !args.variant) {
303
+ throw new Error(
304
+ "Either base64 or variant argument needs to be provided"
305
+ );
306
+ }
307
+ let startArg: StartProgram;
308
+ if (args.base64) {
309
+ startArg = {
310
+ base64: args.base64,
311
+ };
312
+ } else {
313
+ startArg = {
314
+ variant: args.variant,
315
+ };
316
+ }
317
+ const address = await c.program.open(startArg);
318
+ console.log("Started program with address: ");
319
+ console.log(chalk.green(address.toString()));
267
320
  },
268
321
  })
269
322
  .strict()
270
323
  .demandCommand();
271
324
  return yargs;
272
325
  })
326
+ .command({
327
+ command: "install <package-spec>",
328
+ describe: "install and import a dependency",
329
+ builder: (yargs: any) => {
330
+ yargs.positional("package-spec", {
331
+ type: "string",
332
+ describe: "Installed dependency will be loaded with js import(...)",
333
+ demandOption: true,
334
+ });
335
+
336
+ return yargs;
337
+ },
338
+ handler: async (args) => {
339
+ const c = await client();
340
+ const newPrograms = await c.dependency.install(args["package-spec"]);
341
+
342
+ console.log(`New programs available (${newPrograms.length}):`);
343
+ newPrograms.forEach((p) => {
344
+ console.log(chalk.green(p));
345
+ });
346
+ },
347
+ })
273
348
  .help()
274
349
  .strict()
275
350
  .demandCommand().argv;
package/src/client.ts CHANGED
@@ -1,23 +1,164 @@
1
- import { DirectSub } from "@peerbit/pubsub";
2
- import { Peerbit } from "peerbit";
1
+ import { StartByBase64, StartByVariant, StartProgram } from "./types.js";
2
+ import {
3
+ ADDRESS_PATH,
4
+ BOOTSTRAP_PATH,
5
+ INSTALL_PATH,
6
+ LOCAL_PORT,
7
+ PEER_ID_PATH,
8
+ PROGRAMS_PATH,
9
+ PROGRAM_PATH,
10
+ } from "./routes.js";
11
+ import { Address } from "@peerbit/program";
12
+ import { multiaddr } from "@multiformats/multiaddr";
3
13
 
4
- export const create = (directory: string, domain?: string) => {
5
- return Peerbit.create({
6
- libp2p: {
14
+ export const client = async (
15
+ endpoint: string = "http://localhost:" + LOCAL_PORT
16
+ ) => {
17
+ const { default: axios } = await import("axios");
18
+
19
+ const validateStatus = (status: number) => {
20
+ return (status >= 200 && status < 300) || status == 404;
21
+ };
22
+
23
+ const throwIfNot200 = (resp: { status: number; data: any }) => {
24
+ if (resp.status !== 200) {
25
+ throw new Error(resp.data);
26
+ }
27
+ return resp;
28
+ };
29
+ const getBodyByStatus = <
30
+ D extends { toString(): string },
31
+ T extends { status: number; data: D }
32
+ >(
33
+ resp: T
34
+ ): D | undefined => {
35
+ if (resp.status === 404) {
36
+ return;
37
+ }
38
+ if (resp.status == 200) {
39
+ return resp.data;
40
+ }
41
+ throw new Error(
42
+ typeof resp.data === "string" ? resp.data : resp.data.toString()
43
+ );
44
+ };
45
+ const getId = async () =>
46
+ throwIfNot200(await axios.get(endpoint + PEER_ID_PATH, { validateStatus }))
47
+ .data;
48
+
49
+ const getHeaders = async () => {
50
+ const config = await import("./config.js");
51
+ const headers = {
52
+ authorization: "Basic admin:" + (await config.loadPassword()),
53
+ };
54
+ return headers;
55
+ };
56
+ return {
57
+ peer: {
58
+ id: {
59
+ get: getId,
60
+ },
7
61
  addresses: {
8
- announce: domain
9
- ? [`/dns4/${domain}/tcp/8001`, `/dns4/${domain}/tcp/8002/ws`]
10
- : undefined,
11
- listen: ["/ip4/127.0.0.1/tcp/8001", "/ip4/127.0.0.1/tcp/8002/ws"],
62
+ get: async () => {
63
+ return (
64
+ throwIfNot200(
65
+ await axios.get(endpoint + ADDRESS_PATH, {
66
+ validateStatus,
67
+ })
68
+ ).data as string[]
69
+ ).map((x) => multiaddr(x));
70
+ },
71
+ },
72
+ },
73
+ program: {
74
+ has: async (address: Address | string): Promise<boolean> => {
75
+ const result = await axios.head(
76
+ endpoint +
77
+ PROGRAM_PATH +
78
+ "/" +
79
+ encodeURIComponent(address.toString()),
80
+ { validateStatus, headers: await getHeaders() }
81
+ );
82
+ if (result.status !== 200 && result.status !== 404) {
83
+ throw new Error(result.data);
84
+ }
85
+ return result.status === 200 ? true : false;
86
+ },
87
+
88
+ open: async (program: StartProgram): Promise<Address> => {
89
+ const resp = throwIfNot200(
90
+ await axios.put(endpoint + PROGRAM_PATH, JSON.stringify(program), {
91
+ validateStatus,
92
+ headers: await getHeaders(),
93
+ })
94
+ );
95
+ return resp.data as string;
12
96
  },
13
- connectionManager: {
14
- maxConnections: Infinity,
15
- minConnections: 0,
97
+
98
+ close: async (address: string): Promise<void> => {
99
+ throwIfNot200(
100
+ await axios.delete(
101
+ endpoint +
102
+ PROGRAM_PATH +
103
+ "/" +
104
+ encodeURIComponent(address.toString()),
105
+ {
106
+ validateStatus,
107
+ headers: await getHeaders(),
108
+ }
109
+ )
110
+ );
111
+ },
112
+
113
+ drop: async (address: string): Promise<void> => {
114
+ throwIfNot200(
115
+ await axios.delete(
116
+ endpoint +
117
+ PROGRAM_PATH +
118
+ "/" +
119
+ encodeURIComponent(address.toString()) +
120
+ "?delete=true",
121
+ {
122
+ validateStatus,
123
+ headers: await getHeaders(),
124
+ }
125
+ )
126
+ );
127
+ },
128
+
129
+ list: async (): Promise<string[]> => {
130
+ const resp = throwIfNot200(
131
+ await axios.get(endpoint + PROGRAMS_PATH, {
132
+ validateStatus,
133
+ headers: await getHeaders(),
134
+ })
135
+ );
136
+ return resp.data as string[];
137
+ },
138
+ },
139
+ dependency: {
140
+ install: async (name: string): Promise<string[]> => {
141
+ const resp = await axios.put(endpoint + INSTALL_PATH, name, {
142
+ validateStatus,
143
+ headers: await getHeaders(),
144
+ });
145
+ if (resp.status !== 200) {
146
+ throw new Error(
147
+ typeof resp.data === "string" ? resp.data : resp.data.toString()
148
+ );
149
+ }
150
+ return resp.data;
16
151
  },
17
- services: {
18
- pubsub: (c) => new DirectSub(c, { canRelayMessage: true }),
152
+ },
153
+ network: {
154
+ bootstrap: async (): Promise<void> => {
155
+ throwIfNot200(
156
+ await axios.post(endpoint + BOOTSTRAP_PATH, undefined, {
157
+ validateStatus,
158
+ headers: await getHeaders(),
159
+ })
160
+ );
19
161
  },
20
162
  },
21
- directory,
22
- });
163
+ };
23
164
  };
@@ -0,0 +1 @@
1
+ /// Not supported
package/src/config.ts CHANGED
@@ -17,4 +17,84 @@ export const getKeysPath = async (configDir: string): Promise<string> => {
17
17
  return path.join(configDir, "keys");
18
18
  };
19
19
 
20
+ export const checkExistPath = async (path: string) => {
21
+ const fs = await import("fs");
22
+
23
+ try {
24
+ if (!fs.existsSync(path)) {
25
+ fs.accessSync(path, fs.constants.W_OK); // will throw if fails
26
+ return false;
27
+ }
28
+ return true;
29
+ } catch (err: any) {
30
+ if (err.message.indexOf("no such file")) {
31
+ return false;
32
+ }
33
+ throw new Error("Can not access path");
34
+ }
35
+ };
36
+
37
+ export const loadPassword = async (): Promise<string> => {
38
+ const fs = await import("fs");
39
+ const configDir = await getConfigDir();
40
+ const credentialsPath = await getCredentialsPath(configDir);
41
+ if (!(await checkExistPath(credentialsPath))) {
42
+ throw new NotFoundError("Credentials file does not exist");
43
+ }
44
+ const password = JSON.parse(
45
+ fs.readFileSync(credentialsPath, "utf-8")
46
+ ).password;
47
+ if (!password || password.length === 0) {
48
+ throw new NotFoundError("Password not found");
49
+ }
50
+ return password;
51
+ };
52
+
53
+ export const getPackageName = async (path: string): Promise<string> => {
54
+ const pathLib = await import("path");
55
+ const tar = await import("tar-stream");
56
+ const zlib = await import("zlib");
57
+ const urlLib = await import("url");
58
+ const fs = await import("fs");
59
+
60
+ if (!fs.existsSync(path)) {
61
+ throw new Error("File does not exist");
62
+ }
63
+ return new Promise((resolve, reject) => {
64
+ try {
65
+ const extract = tar.extract();
66
+ let data = "";
67
+
68
+ extract.on("entry", function (header, stream, cb) {
69
+ stream.on("data", function (chunk) {
70
+ if (header.name == "package/package.json") data += chunk;
71
+ });
72
+
73
+ stream.on("end", function () {
74
+ cb();
75
+ });
76
+
77
+ stream.resume();
78
+ });
79
+
80
+ extract.on("finish", function () {
81
+ const name = JSON.parse(data)?.name;
82
+ if (!name) {
83
+ reject(new Error("Could not find name from package.json file"));
84
+ } else {
85
+ resolve(name);
86
+ }
87
+ });
88
+
89
+ extract.on("error", (e) => {
90
+ reject(e);
91
+ });
92
+
93
+ fs.createReadStream(path).pipe(zlib.createGunzip()).pipe(extract);
94
+ } catch (error) {
95
+ reject(error);
96
+ }
97
+ });
98
+ };
99
+
20
100
  export class NotFoundError extends Error {}
package/src/index.ts CHANGED
@@ -1 +1,3 @@
1
- export * from "./api.js";
1
+ export * from "./server.js";
2
+ export * from "./routes.js";
3
+ export * from "./client.js";
package/src/peerbit.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { DirectSub } from "@peerbit/pubsub";
2
+ import { Peerbit } from "peerbit";
3
+
4
+ export const create = (properties: { directory?: string; domain?: string }) => {
5
+ return Peerbit.create({
6
+ libp2p: {
7
+ addresses: {
8
+ announce: properties.domain
9
+ ? [
10
+ `/dns4/${properties.domain}/tcp/8001`,
11
+ `/dns4/${properties.domain}/tcp/8002/ws`,
12
+ ]
13
+ : undefined,
14
+ listen: ["/ip4/127.0.0.1/tcp/8001", "/ip4/127.0.0.1/tcp/8002/ws"],
15
+ },
16
+ connectionManager: {
17
+ maxConnections: Infinity,
18
+ minConnections: 0,
19
+ },
20
+ services: {
21
+ pubsub: (c) => new DirectSub(c, { canRelayMessage: true }),
22
+ },
23
+ },
24
+ directory: properties.directory,
25
+ });
26
+ };
package/src/routes.ts ADDED
@@ -0,0 +1,20 @@
1
+ export const getPort = (protocol: string) => {
2
+ if (protocol === "https:") {
3
+ return SSL_PORT;
4
+ }
5
+
6
+ if (protocol === "http:") {
7
+ return LOCAL_PORT;
8
+ }
9
+
10
+ throw new Error("Unsupported protocol: " + protocol);
11
+ };
12
+ export const SSL_PORT = 9002;
13
+ export const LOCAL_PORT = 8082;
14
+
15
+ export const PEER_ID_PATH = "/peer/id";
16
+ export const ADDRESS_PATH = "/peer/address";
17
+ export const PROGRAM_PATH = "/program";
18
+ export const PROGRAMS_PATH = "/programs";
19
+ export const INSTALL_PATH = "/install";
20
+ export const BOOTSTRAP_PATH = "/network/bootstrap";
@@ -0,0 +1 @@
1
+ // Not supported