@enbox/dwn-server 0.0.2 → 0.0.3
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/README.md +13 -13
- package/dist/esm/src/config.d.ts +2 -6
- package/dist/esm/src/config.d.ts.map +1 -1
- package/dist/esm/src/config.js +4 -8
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/connection/connection-manager.d.ts +9 -9
- package/dist/esm/src/connection/connection-manager.d.ts.map +1 -1
- package/dist/esm/src/connection/connection-manager.js +5 -3
- package/dist/esm/src/connection/connection-manager.js.map +1 -1
- package/dist/esm/src/connection/socket-connection.d.ts +18 -17
- package/dist/esm/src/connection/socket-connection.d.ts.map +1 -1
- package/dist/esm/src/connection/socket-connection.js +26 -35
- package/dist/esm/src/connection/socket-connection.js.map +1 -1
- package/dist/esm/src/dwn-error.js.map +1 -1
- package/dist/esm/src/dwn-server.d.ts +5 -6
- package/dist/esm/src/dwn-server.d.ts.map +1 -1
- package/dist/esm/src/dwn-server.js +3 -14
- package/dist/esm/src/dwn-server.js.map +1 -1
- package/dist/esm/src/http-api.d.ts +9 -11
- package/dist/esm/src/http-api.d.ts.map +1 -1
- package/dist/esm/src/http-api.js +450 -375
- package/dist/esm/src/http-api.js.map +1 -1
- package/dist/esm/src/json-rpc-handlers/dwn/process-message.d.ts.map +1 -1
- package/dist/esm/src/json-rpc-handlers/dwn/process-message.js +3 -3
- package/dist/esm/src/json-rpc-handlers/dwn/process-message.js.map +1 -1
- package/dist/esm/src/json-rpc-handlers/subscription/close.d.ts.map +1 -1
- package/dist/esm/src/json-rpc-handlers/subscription/close.js.map +1 -1
- package/dist/esm/src/json-rpc-socket.d.ts +1 -1
- package/dist/esm/src/json-rpc-socket.d.ts.map +1 -1
- package/dist/esm/src/json-rpc-socket.js +1 -1
- package/dist/esm/src/json-rpc-socket.js.map +1 -1
- package/dist/esm/src/lib/json-rpc-router.d.ts +3 -4
- package/dist/esm/src/lib/json-rpc-router.d.ts.map +1 -1
- package/dist/esm/src/lib/json-rpc-router.js.map +1 -1
- package/dist/esm/src/lib/json-rpc.d.ts.map +1 -1
- package/dist/esm/src/lib/json-rpc.js.map +1 -1
- package/dist/esm/src/main.js +0 -0
- package/dist/esm/src/metrics.d.ts +1 -1
- package/dist/esm/src/metrics.js.map +1 -1
- package/dist/esm/src/registration/proof-of-work-manager.d.ts +1 -1
- package/dist/esm/src/registration/proof-of-work-manager.d.ts.map +1 -1
- package/dist/esm/src/registration/proof-of-work-manager.js +3 -3
- package/dist/esm/src/registration/proof-of-work-manager.js.map +1 -1
- package/dist/esm/src/registration/registration-manager.d.ts +3 -3
- package/dist/esm/src/registration/registration-manager.d.ts.map +1 -1
- package/dist/esm/src/registration/registration-manager.js +6 -6
- package/dist/esm/src/registration/registration-manager.js.map +1 -1
- package/dist/esm/src/registration/registration-store.d.ts +1 -1
- package/dist/esm/src/registration/registration-store.d.ts.map +1 -1
- package/dist/esm/src/registration/registration-store.js.map +1 -1
- package/dist/esm/src/storage.d.ts +2 -2
- package/dist/esm/src/storage.d.ts.map +1 -1
- package/dist/esm/src/storage.js +5 -4
- package/dist/esm/src/storage.js.map +1 -1
- package/dist/esm/src/web5-connect/sql-ttl-cache.d.ts.map +1 -1
- package/dist/esm/src/web5-connect/sql-ttl-cache.js +3 -2
- package/dist/esm/src/web5-connect/sql-ttl-cache.js.map +1 -1
- package/dist/esm/src/web5-connect/web5-connect-server.d.ts.map +1 -1
- package/dist/esm/src/web5-connect/web5-connect-server.js +2 -2
- package/dist/esm/src/web5-connect/web5-connect-server.js.map +1 -1
- package/dist/esm/src/ws-api.d.ts +2 -4
- package/dist/esm/src/ws-api.d.ts.map +1 -1
- package/dist/esm/src/ws-api.js +6 -17
- package/dist/esm/src/ws-api.js.map +1 -1
- package/dist/esm/tests/common-scenario-validator.d.ts.map +1 -1
- package/dist/esm/tests/common-scenario-validator.js +2 -3
- package/dist/esm/tests/common-scenario-validator.js.map +1 -1
- package/dist/esm/tests/connection/connection-manager.spec.js +11 -9
- package/dist/esm/tests/connection/connection-manager.spec.js.map +1 -1
- package/dist/esm/tests/connection/socket-connection.spec.js +40 -18
- package/dist/esm/tests/connection/socket-connection.spec.js.map +1 -1
- package/dist/esm/tests/cors/http-api.browser.js +1 -1
- package/dist/esm/tests/cors/http-api.browser.js.map +1 -1
- package/dist/esm/tests/dwn-process-message.spec.js +4 -4
- package/dist/esm/tests/dwn-process-message.spec.js.map +1 -1
- package/dist/esm/tests/dwn-server.spec.js +8 -9
- package/dist/esm/tests/dwn-server.spec.js.map +1 -1
- package/dist/esm/tests/http-api.spec.js +92 -85
- package/dist/esm/tests/http-api.spec.js.map +1 -1
- package/dist/esm/tests/json-rpc-socket.spec.js +11 -9
- package/dist/esm/tests/json-rpc-socket.spec.js.map +1 -1
- package/dist/esm/tests/plugins/data-store-sqlite.d.ts +2 -2
- package/dist/esm/tests/plugins/data-store-sqlite.js +2 -2
- package/dist/esm/tests/plugins/event-log-sqlite.d.ts +2 -2
- package/dist/esm/tests/plugins/event-log-sqlite.js +2 -2
- package/dist/esm/tests/plugins/event-stream-in-memory.d.ts +2 -2
- package/dist/esm/tests/plugins/event-stream-in-memory.d.ts.map +1 -1
- package/dist/esm/tests/plugins/event-stream-in-memory.js +1 -1
- package/dist/esm/tests/plugins/event-stream-in-memory.js.map +1 -1
- package/dist/esm/tests/plugins/message-store-sqlite.d.ts +2 -2
- package/dist/esm/tests/plugins/message-store-sqlite.d.ts.map +1 -1
- package/dist/esm/tests/plugins/message-store-sqlite.js +2 -2
- package/dist/esm/tests/plugins/message-store-sqlite.js.map +1 -1
- package/dist/esm/tests/plugins/resumable-task-store-sqlite.d.ts +2 -2
- package/dist/esm/tests/plugins/resumable-task-store-sqlite.d.ts.map +1 -1
- package/dist/esm/tests/plugins/resumable-task-store-sqlite.js +2 -2
- package/dist/esm/tests/plugins/resumable-task-store-sqlite.js.map +1 -1
- package/dist/esm/tests/process-handler.spec.js +6 -6
- package/dist/esm/tests/process-handler.spec.js.map +1 -1
- package/dist/esm/tests/registration/proof-of-work-manager.spec.js +3 -4
- package/dist/esm/tests/registration/proof-of-work-manager.spec.js.map +1 -1
- package/dist/esm/tests/rpc-subscribe-close.spec.js +1 -1
- package/dist/esm/tests/rpc-subscribe-close.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/dynamic-plugin-loading.spec.js +11 -10
- package/dist/esm/tests/scenarios/dynamic-plugin-loading.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/registration.spec.js +16 -12
- package/dist/esm/tests/scenarios/registration.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/web5-connect.spec.js +12 -8
- package/dist/esm/tests/scenarios/web5-connect.spec.js.map +1 -1
- package/dist/esm/tests/test-dwn.d.ts.map +1 -1
- package/dist/esm/tests/test-dwn.js +9 -15
- package/dist/esm/tests/test-dwn.js.map +1 -1
- package/dist/esm/tests/utils.d.ts +3 -6
- package/dist/esm/tests/utils.d.ts.map +1 -1
- package/dist/esm/tests/utils.js +9 -18
- package/dist/esm/tests/utils.js.map +1 -1
- package/dist/esm/tests/ws-api.spec.js +28 -23
- package/dist/esm/tests/ws-api.spec.js.map +1 -1
- package/package.json +25 -44
- package/src/config.ts +15 -19
- package/src/connection/connection-manager.ts +18 -12
- package/src/connection/socket-connection.ts +52 -57
- package/src/dwn-error.ts +2 -2
- package/src/dwn-server.ts +17 -30
- package/src/http-api.ts +499 -396
- package/src/json-rpc-handlers/dwn/process-message.ts +9 -10
- package/src/json-rpc-handlers/subscription/close.ts +4 -4
- package/src/json-rpc-socket.ts +3 -2
- package/src/lib/json-rpc-router.ts +5 -6
- package/src/lib/json-rpc.ts +6 -6
- package/src/metrics.ts +7 -7
- package/src/process-handlers.ts +5 -5
- package/src/registration/proof-of-work-manager.ts +11 -10
- package/src/registration/registration-manager.ts +23 -21
- package/src/registration/registration-store.ts +8 -7
- package/src/storage.ts +15 -13
- package/src/web5-connect/sql-ttl-cache.ts +5 -4
- package/src/web5-connect/web5-connect-server.ts +9 -8
- package/src/ws-api.ts +11 -26
- package/dist/cjs/index.js +0 -6811
- package/dist/cjs/package.json +0 -1
- package/dist/esm/src/lib/http-server-shutdown-handler.d.ts +0 -10
- package/dist/esm/src/lib/http-server-shutdown-handler.d.ts.map +0 -1
- package/dist/esm/src/lib/http-server-shutdown-handler.js +0 -65
- package/dist/esm/src/lib/http-server-shutdown-handler.js.map +0 -1
- package/src/lib/http-server-shutdown-handler.ts +0 -79
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { GenericMessage } from '@enbox/dwn-sdk-js';
|
|
2
2
|
import { DwnInterfaceName, DwnMethodName } from '@enbox/dwn-sdk-js';
|
|
3
3
|
|
|
4
|
-
import type { Readable as IsomorphicReadable } from 'readable-stream';
|
|
5
4
|
import log from 'loglevel';
|
|
6
5
|
import { v4 as uuidv4 } from 'uuid';
|
|
7
6
|
|
|
@@ -28,7 +27,7 @@ export const handleDwnProcessMessage: JsonRpcHandler = async (
|
|
|
28
27
|
|
|
29
28
|
try {
|
|
30
29
|
// RecordsWrite is only supported on 'http' to support data stream for large data
|
|
31
|
-
// TODO: https://github.com/
|
|
30
|
+
// TODO: https://github.com/enboxorg/enbox/issues/108
|
|
32
31
|
if (
|
|
33
32
|
transport !== 'http' &&
|
|
34
33
|
message.descriptor.interface === DwnInterfaceName.Records &&
|
|
@@ -38,11 +37,11 @@ export const handleDwnProcessMessage: JsonRpcHandler = async (
|
|
|
38
37
|
requestId,
|
|
39
38
|
JsonRpcErrorCodes.InvalidParams,
|
|
40
39
|
`RecordsWrite is not supported via ${context.transport}`
|
|
41
|
-
)
|
|
40
|
+
);
|
|
42
41
|
return { jsonRpcResponse };
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
// subscribe methods must come with a subscriptionRequest context
|
|
44
|
+
// subscribe methods must come with a subscriptionRequest context
|
|
46
45
|
if (message.descriptor.method === DwnMethodName.Subscribe && subscriptionRequest === undefined) {
|
|
47
46
|
const jsonRpcResponse = createJsonRpcErrorResponse(
|
|
48
47
|
requestId,
|
|
@@ -58,7 +57,7 @@ export const handleDwnProcessMessage: JsonRpcHandler = async (
|
|
|
58
57
|
requestId,
|
|
59
58
|
JsonRpcErrorCodes.InvalidParams,
|
|
60
59
|
`subscriptions are not supported via ${context.transport}`
|
|
61
|
-
)
|
|
60
|
+
);
|
|
62
61
|
return { jsonRpcResponse };
|
|
63
62
|
}
|
|
64
63
|
|
|
@@ -70,12 +69,12 @@ export const handleDwnProcessMessage: JsonRpcHandler = async (
|
|
|
70
69
|
requestId,
|
|
71
70
|
JsonRpcErrorCodes.InvalidParams,
|
|
72
71
|
`the subscribe id: ${subscriptionRequest.id} is in use by an active subscription`
|
|
73
|
-
)
|
|
72
|
+
);
|
|
74
73
|
return { jsonRpcResponse };
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
const reply = await dwn.processMessage(target, message, {
|
|
78
|
-
dataStream
|
|
77
|
+
dataStream,
|
|
79
78
|
subscriptionHandler: subscriptionRequest?.subscriptionHandler,
|
|
80
79
|
});
|
|
81
80
|
|
|
@@ -83,7 +82,7 @@ export const handleDwnProcessMessage: JsonRpcHandler = async (
|
|
|
83
82
|
const { entry } = reply;
|
|
84
83
|
// RecordsRead or MessagesRead messages optionally return data as a stream to accommodate large amounts of data
|
|
85
84
|
// we remove the data stream from the reply that will be serialized and return it as a separate property in the response payload.
|
|
86
|
-
let recordDataStream:
|
|
85
|
+
let recordDataStream: ReadableStream<Uint8Array>;
|
|
87
86
|
if (entry !== undefined && entry.data !== undefined) {
|
|
88
87
|
recordDataStream = entry.data;
|
|
89
88
|
delete reply.entry.data; // not serializable via JSON
|
|
@@ -97,9 +96,9 @@ export const handleDwnProcessMessage: JsonRpcHandler = async (
|
|
|
97
96
|
const subscriptionReply: JsonRpcSubscription = {
|
|
98
97
|
id: subscriptionRequest.id,
|
|
99
98
|
close,
|
|
100
|
-
}
|
|
99
|
+
};
|
|
101
100
|
await socketConnection.addSubscription(subscriptionReply);
|
|
102
|
-
delete reply.subscription.close // delete the close method from the reply as it's not JSON serializable and has a held reference.
|
|
101
|
+
delete reply.subscription.close; // delete the close method from the reply as it's not JSON serializable and has a held reference.
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
const jsonRpcResponse = createJsonRpcSuccessResponse(requestId, { reply });
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { v4 as uuidv4 } from 'uuid';
|
|
2
2
|
|
|
3
|
-
import { DwnServerErrorCode } from '../../dwn-error.js';
|
|
4
3
|
import type {
|
|
5
4
|
HandlerResponse,
|
|
6
5
|
JsonRpcHandler,
|
|
7
6
|
} from '../../lib/json-rpc-router.js';
|
|
8
|
-
|
|
9
7
|
import type { JsonRpcId, JsonRpcResponse } from '../../lib/json-rpc.js';
|
|
8
|
+
|
|
9
|
+
import { DwnServerErrorCode } from '../../dwn-error.js';
|
|
10
10
|
import {
|
|
11
11
|
createJsonRpcErrorResponse,
|
|
12
12
|
createJsonRpcSuccessResponse,
|
|
@@ -43,7 +43,7 @@ export const handleSubscriptionsClose: JsonRpcHandler = async (
|
|
|
43
43
|
// closing the subscription and cleaning up the reference within the given connection.
|
|
44
44
|
await socketConnection.closeSubscription(id);
|
|
45
45
|
jsonRpcResponse = createJsonRpcSuccessResponse(requestId, { reply: { status: 200, detail: 'Accepted' } });
|
|
46
|
-
} catch(error) {
|
|
46
|
+
} catch (error) {
|
|
47
47
|
if (error.code === DwnServerErrorCode.ConnectionSubscriptionJsonRpcIdNotFound) {
|
|
48
48
|
jsonRpcResponse = createJsonRpcErrorResponse(requestId, JsonRpcErrorCodes.InvalidParams, `subscription ${id} does not exist.`);
|
|
49
49
|
} else {
|
|
@@ -56,4 +56,4 @@ export const handleSubscriptionsClose: JsonRpcHandler = async (
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
return { jsonRpcResponse } as HandlerResponse;
|
|
59
|
-
}
|
|
59
|
+
};
|
package/src/json-rpc-socket.ts
CHANGED
|
@@ -2,8 +2,9 @@ import log from 'loglevel';
|
|
|
2
2
|
import { v4 as uuidv4 } from 'uuid';
|
|
3
3
|
import WebSocket from 'ws';
|
|
4
4
|
|
|
5
|
-
import type { JsonRpcId, JsonRpcRequest, JsonRpcResponse } from
|
|
6
|
-
|
|
5
|
+
import type { JsonRpcId, JsonRpcRequest, JsonRpcResponse } from './lib/json-rpc.js';
|
|
6
|
+
|
|
7
|
+
import { createJsonRpcSubscriptionRequest } from './lib/json-rpc.js';
|
|
7
8
|
|
|
8
9
|
// These were arbitrarily chosen, but can be modified via connect options
|
|
9
10
|
const CONNECT_TIMEOUT = 3_000;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { Dwn, MessageSubscriptionHandler } from '@enbox/dwn-sdk-js';
|
|
2
2
|
|
|
3
|
-
import type { Readable } from 'node:stream';
|
|
4
|
-
|
|
5
3
|
import type { JsonRpcId, JsonRpcRequest, JsonRpcResponse } from './json-rpc.js';
|
|
4
|
+
|
|
6
5
|
import type { SocketConnection } from '../connection/socket-connection.js';
|
|
7
6
|
|
|
8
7
|
export type RequestContext = {
|
|
@@ -12,17 +11,17 @@ export type RequestContext = {
|
|
|
12
11
|
socketConnection?: SocketConnection;
|
|
13
12
|
subscriptionRequest?: {
|
|
14
13
|
/** The JsonRpcId of the subscription handler */
|
|
15
|
-
id: JsonRpcId;
|
|
14
|
+
id: JsonRpcId;
|
|
16
15
|
/** The `MessageEvent` handler associated with a subscription request, only used in `ws` requests */
|
|
17
16
|
subscriptionHandler: MessageSubscriptionHandler;
|
|
18
17
|
}
|
|
19
|
-
/** The `
|
|
20
|
-
dataStream?:
|
|
18
|
+
/** The `ReadableStream` associated with a `RecordsWrite` request only used in `http` requests */
|
|
19
|
+
dataStream?: ReadableStream<Uint8Array>;
|
|
21
20
|
};
|
|
22
21
|
|
|
23
22
|
export type HandlerResponse = {
|
|
24
23
|
jsonRpcResponse: JsonRpcResponse;
|
|
25
|
-
dataStream?:
|
|
24
|
+
dataStream?: ReadableStream<Uint8Array>;
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
export type JsonRpcHandler = (
|
package/src/lib/json-rpc.ts
CHANGED
|
@@ -91,15 +91,15 @@ export const createJsonRpcSubscriptionRequest = (
|
|
|
91
91
|
subscriptionId?: JsonRpcId
|
|
92
92
|
): JsonRpcRequest => {
|
|
93
93
|
return {
|
|
94
|
-
jsonrpc: '2.0',
|
|
94
|
+
jsonrpc : '2.0',
|
|
95
95
|
id,
|
|
96
96
|
method,
|
|
97
97
|
params,
|
|
98
|
-
subscription: {
|
|
98
|
+
subscription : {
|
|
99
99
|
id: subscriptionId,
|
|
100
100
|
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
103
|
|
|
104
104
|
export const createJsonRpcRequest = (
|
|
105
105
|
id: JsonRpcId,
|
|
@@ -119,8 +119,8 @@ export const createJsonRpcSuccessResponse = (
|
|
|
119
119
|
result?: any,
|
|
120
120
|
): JsonRpcSuccessResponse => {
|
|
121
121
|
return {
|
|
122
|
-
jsonrpc: '2.0',
|
|
122
|
+
jsonrpc : '2.0',
|
|
123
123
|
id,
|
|
124
|
-
result: result ?? null,
|
|
124
|
+
result : result ?? null,
|
|
125
125
|
};
|
|
126
126
|
};
|
package/src/metrics.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Counter, Histogram } from 'prom-client';
|
|
2
2
|
|
|
3
3
|
export const requestCounter = new Counter({
|
|
4
|
-
name: 'dwn_requests_total',
|
|
5
|
-
help: 'all dwn requests processed',
|
|
6
|
-
labelNames: ['method', 'status', 'error'],
|
|
4
|
+
name : 'dwn_requests_total',
|
|
5
|
+
help : 'all dwn requests processed',
|
|
6
|
+
labelNames : ['method', 'status', 'error'],
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
export const responseHistogram = new Histogram({
|
|
10
|
-
name: 'http_response',
|
|
11
|
-
help: 'response histogram',
|
|
12
|
-
buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
13
|
-
labelNames: ['route', 'code'],
|
|
10
|
+
name : 'http_response',
|
|
11
|
+
help : 'response histogram',
|
|
12
|
+
buckets : [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
13
|
+
labelNames : ['route', 'code'],
|
|
14
14
|
});
|
package/src/process-handlers.ts
CHANGED
|
@@ -51,11 +51,11 @@ export const setProcessHandlers = (dwnServer: DwnServer): ProcessHandlers => {
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
export const removeProcessHandlers = (handlers: ProcessHandlers): void => {
|
|
54
|
-
const {
|
|
55
|
-
unhandledRejectionHandler,
|
|
56
|
-
uncaughtExceptionHandler,
|
|
57
|
-
sigintHandler,
|
|
58
|
-
sigtermHandler
|
|
54
|
+
const {
|
|
55
|
+
unhandledRejectionHandler,
|
|
56
|
+
uncaughtExceptionHandler,
|
|
57
|
+
sigintHandler,
|
|
58
|
+
sigtermHandler
|
|
59
59
|
} = handlers;
|
|
60
60
|
|
|
61
61
|
process.removeListener('unhandledRejection', unhandledRejectionHandler);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { ProofOfWork } from
|
|
1
|
+
import type { ProofOfWorkChallengeModel } from './proof-of-work-types.js';
|
|
2
|
+
|
|
3
|
+
import { ProofOfWork } from './proof-of-work.js';
|
|
4
|
+
import { DwnServerError, DwnServerErrorCode } from '../dwn-error.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Manages proof-of-work challenge difficulty and lifecycle based on solve rate.
|
|
@@ -18,7 +19,7 @@ export class ProofOfWorkManager {
|
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
// There is opportunity to improve implementation here.
|
|
21
|
-
// TODO: https://github.com/
|
|
22
|
+
// TODO: https://github.com/enboxorg/enbox/issues/101
|
|
22
23
|
private proofOfWorkOfLastMinute: Map<string, number> = new Map(); // proofOfWorkId -> timestamp of proof-of-work
|
|
23
24
|
|
|
24
25
|
// Seed to generate the challenge nonce from, this allows all DWN instances in a cluster to generate the same challenge.
|
|
@@ -122,8 +123,8 @@ export class ProofOfWorkManager {
|
|
|
122
123
|
|
|
123
124
|
public getProofOfWorkChallenge(): ProofOfWorkChallengeModel {
|
|
124
125
|
return {
|
|
125
|
-
challengeNonce: this.challengeNonces.currentChallengeNonce,
|
|
126
|
-
maximumAllowedHashValue: ProofOfWorkManager.bigIntToHexString(this.currentMaximumAllowedHashValue),
|
|
126
|
+
challengeNonce : this.challengeNonces.currentChallengeNonce,
|
|
127
|
+
maximumAllowedHashValue : ProofOfWorkManager.bigIntToHexString(this.currentMaximumAllowedHashValue),
|
|
127
128
|
};
|
|
128
129
|
}
|
|
129
130
|
|
|
@@ -228,7 +229,7 @@ export class ProofOfWorkManager {
|
|
|
228
229
|
/**
|
|
229
230
|
* Refreshes the difficulty by changing the max hash value.
|
|
230
231
|
* The higher the number, the easier. Scale 1 (hardest) to 2^256 (easiest), represented in HEX.
|
|
231
|
-
*
|
|
232
|
+
*
|
|
232
233
|
* If solve rate rate is higher than expected, the difficulty will increase rapidly.
|
|
233
234
|
* If solve rate is lower than expected, the difficulty will decrease gradually.
|
|
234
235
|
* The difficulty will never be lower than the initial difficulty.
|
|
@@ -247,16 +248,16 @@ export class ProofOfWorkManager {
|
|
|
247
248
|
// and harder difficulty is represented by a smaller max allowed hash value.
|
|
248
249
|
if (latestSolveCountPerMinute > this.desiredSolveCountPerMinute) {
|
|
249
250
|
// if solve rate is higher than desired, make difficulty harder by making the max allowed hash value smaller
|
|
250
|
-
|
|
251
|
+
|
|
251
252
|
const currentSolveRateInFractionOfDesiredSolveRate = latestSolveCountPerMinute / this.desiredSolveCountPerMinute;
|
|
252
253
|
const newMaximumAllowedHashValueAsBigIntPriorToMultiplierAdjustment
|
|
253
|
-
= (this.currentMaximumAllowedHashValueAsBigInt * BigInt(scaleFactor)) /
|
|
254
|
+
= (this.currentMaximumAllowedHashValueAsBigInt * BigInt(scaleFactor)) /
|
|
254
255
|
(BigInt(Math.floor(currentSolveRateInFractionOfDesiredSolveRate * this.difficultyIncreaseMultiplier * scaleFactor)));
|
|
255
256
|
|
|
256
257
|
const hashValueDecreaseAmountPriorToEvaluationFrequencyAdjustment
|
|
257
258
|
= (this.currentMaximumAllowedHashValueAsBigInt - newMaximumAllowedHashValueAsBigIntPriorToMultiplierAdjustment) *
|
|
258
259
|
(BigInt(Math.floor(this.difficultyIncreaseMultiplier * scaleFactor)) / BigInt(scaleFactor));
|
|
259
|
-
|
|
260
|
+
|
|
260
261
|
// Adjustment based on the reevaluation frequency to provide more-or-less consistent behavior regardless of the reevaluation frequency.
|
|
261
262
|
const hashValueDecreaseAmount = hashValueDecreaseAmountPriorToEvaluationFrequencyAdjustment / BigInt(difficultyEvaluationsPerMinute);
|
|
262
263
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
1
|
+
import type { ProofOfWorkChallengeModel } from './proof-of-work-types.js';
|
|
2
|
+
import type { ActiveTenantCheckResult, TenantGate } from '@enbox/dwn-sdk-js';
|
|
3
|
+
import type { RegistrationData, RegistrationRequest } from './registration-types.js';
|
|
4
|
+
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
|
|
7
|
+
import { getDialectFromUrl } from '../storage.js';
|
|
8
|
+
import { ProofOfWork } from './proof-of-work.js';
|
|
9
|
+
import { ProofOfWorkManager } from './proof-of-work-manager.js';
|
|
10
|
+
import { RegistrationStore } from './registration-store.js';
|
|
11
|
+
import { DwnServerError, DwnServerErrorCode } from '../dwn-error.js';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* The RegistrationManager is responsible for managing the registration of tenants.
|
|
@@ -27,7 +29,7 @@ export class RegistrationManager implements TenantGate {
|
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
|
-
* The terms-of-service hash.
|
|
32
|
+
* The terms-of-service hash.
|
|
31
33
|
*/
|
|
32
34
|
public getTermsOfServiceHash(): string | undefined {
|
|
33
35
|
return this.termsOfServiceHash;
|
|
@@ -45,7 +47,7 @@ export class RegistrationManager implements TenantGate {
|
|
|
45
47
|
* Creates a new RegistrationManager instance.
|
|
46
48
|
* @param input.registrationStoreUrl - The URL of the registration store.
|
|
47
49
|
* Set to `undefined` or empty string if tenant registration is not required (ie. DWN is open for all).
|
|
48
|
-
*
|
|
50
|
+
*
|
|
49
51
|
*/
|
|
50
52
|
public static async create(input: {
|
|
51
53
|
registrationStoreUrl?: string,
|
|
@@ -70,17 +72,17 @@ export class RegistrationManager implements TenantGate {
|
|
|
70
72
|
|
|
71
73
|
// Initialize and start ProofOfWorkManager.
|
|
72
74
|
registrationManager.proofOfWorkManager = await ProofOfWorkManager.create({
|
|
73
|
-
autoStart: true,
|
|
74
|
-
desiredSolveCountPerMinute: 10,
|
|
75
|
-
initialMaximumAllowedHashValue: input.proofOfWorkInitialMaximumAllowedHash,
|
|
76
|
-
challengeSeed: input.proofOfWorkChallengeNonceSeed,
|
|
75
|
+
autoStart : true,
|
|
76
|
+
desiredSolveCountPerMinute : 10,
|
|
77
|
+
initialMaximumAllowedHashValue : input.proofOfWorkInitialMaximumAllowedHash,
|
|
78
|
+
challengeSeed : input.proofOfWorkChallengeNonceSeed,
|
|
77
79
|
});
|
|
78
80
|
|
|
79
81
|
// Initialize RegistrationStore.
|
|
80
82
|
const sqlDialect = getDialectFromUrl(new URL(registrationStoreUrl));
|
|
81
83
|
const registrationStore = await RegistrationStore.create(sqlDialect);
|
|
82
84
|
registrationManager.registrationStore = registrationStore;
|
|
83
|
-
|
|
85
|
+
|
|
84
86
|
return registrationManager;
|
|
85
87
|
}
|
|
86
88
|
|
|
@@ -136,18 +138,18 @@ export class RegistrationManager implements TenantGate {
|
|
|
136
138
|
|
|
137
139
|
if (tenantRegistration === undefined) {
|
|
138
140
|
return {
|
|
139
|
-
isActiveTenant: false,
|
|
140
|
-
detail: 'Not a registered tenant.'
|
|
141
|
+
isActiveTenant : false,
|
|
142
|
+
detail : 'Not a registered tenant.'
|
|
141
143
|
};
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
if (tenantRegistration.termsOfServiceHash !== this.termsOfServiceHash) {
|
|
145
147
|
return {
|
|
146
|
-
isActiveTenant: false,
|
|
147
|
-
detail: 'Agreed terms-of-service is outdated.'
|
|
148
|
+
isActiveTenant : false,
|
|
149
|
+
detail : 'Agreed terms-of-service is outdated.'
|
|
148
150
|
};
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
return { isActiveTenant: true }
|
|
153
|
+
return { isActiveTenant: true };
|
|
152
154
|
}
|
|
153
155
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Kysely } from 'kysely';
|
|
2
|
-
import type { RegistrationData } from './registration-types.js';
|
|
3
1
|
import type { Dialect } from '@enbox/dwn-sql-store';
|
|
2
|
+
import type { RegistrationData } from './registration-types.js';
|
|
3
|
+
|
|
4
|
+
import { Kysely } from 'kysely';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The RegistrationStore is responsible for storing and retrieving tenant registration information.
|
|
@@ -27,11 +28,11 @@ export class RegistrationStore {
|
|
|
27
28
|
|
|
28
29
|
private async initialize(): Promise<void> {
|
|
29
30
|
await this.db.schema
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
.createTable(RegistrationStore.registeredTenantTableName)
|
|
32
|
+
.ifNotExists()
|
|
33
|
+
.addColumn('did', 'text', (column) => column.primaryKey())
|
|
34
|
+
.addColumn('termsOfServiceHash', 'text')
|
|
35
|
+
.execute();
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/**
|
package/src/storage.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { Dialect } from '@enbox/dwn-sql-store';
|
|
1
2
|
import type { DidResolver } from '@enbox/dids';
|
|
3
|
+
import type { DwnServerConfig } from './config.js';
|
|
2
4
|
import type {
|
|
3
5
|
DataStore,
|
|
4
6
|
DwnConfig,
|
|
@@ -8,14 +10,13 @@ import type {
|
|
|
8
10
|
ResumableTaskStore,
|
|
9
11
|
TenantGate,
|
|
10
12
|
} from '@enbox/dwn-sdk-js';
|
|
11
|
-
import type { Dialect } from '@enbox/dwn-sql-store';
|
|
12
|
-
import type { DwnServerConfig } from './config.js';
|
|
13
13
|
|
|
14
14
|
import * as fs from 'fs';
|
|
15
15
|
import Cursor from 'pg-cursor';
|
|
16
|
-
import Database from 'better-sqlite3';
|
|
17
|
-
import pg from 'pg';
|
|
18
16
|
import { createPool as MySQLCreatePool } from 'mysql2';
|
|
17
|
+
import pg from 'pg';
|
|
18
|
+
|
|
19
|
+
import { createBunSqliteDatabase } from '@enbox/dwn-sql-store';
|
|
19
20
|
import { PluginLoader } from './plugin-loader.js';
|
|
20
21
|
|
|
21
22
|
import {
|
|
@@ -51,10 +52,10 @@ export enum BackendTypes {
|
|
|
51
52
|
export type DwnStore = DataStore | EventLog | MessageStore | ResumableTaskStore;
|
|
52
53
|
|
|
53
54
|
export async function getDwnConfig(
|
|
54
|
-
config
|
|
55
|
+
config : DwnServerConfig,
|
|
55
56
|
options : {
|
|
56
57
|
didResolver? : DidResolver,
|
|
57
|
-
tenantGate?
|
|
58
|
+
tenantGate? : TenantGate,
|
|
58
59
|
eventStream? : EventStream,
|
|
59
60
|
}
|
|
60
61
|
): Promise<DwnConfig> {
|
|
@@ -78,8 +79,8 @@ function getLevelStore(
|
|
|
78
79
|
});
|
|
79
80
|
case StoreType.MessageStore:
|
|
80
81
|
return new MessageStoreLevel({
|
|
81
|
-
blockstoreLocation: storeURI.host + storeURI.pathname + '/MESSAGESTORE',
|
|
82
|
-
indexLocation: storeURI.host + storeURI.pathname + '/INDEX',
|
|
82
|
+
blockstoreLocation : storeURI.host + storeURI.pathname + '/MESSAGESTORE',
|
|
83
|
+
indexLocation : storeURI.host + storeURI.pathname + '/INDEX',
|
|
83
84
|
});
|
|
84
85
|
case StoreType.EventLog:
|
|
85
86
|
return new EventLogLevel({
|
|
@@ -131,7 +132,7 @@ async function getStore(storeConfigString: string, storeType: StoreType): Promis
|
|
|
131
132
|
return await loadStoreFromFilePath(storeConfigString, storeType);
|
|
132
133
|
}
|
|
133
134
|
// else treat the `storeConfigString` as a connection string
|
|
134
|
-
|
|
135
|
+
|
|
135
136
|
const storeURI = new URL(storeConfigString);
|
|
136
137
|
|
|
137
138
|
switch (storeURI.protocol.slice(0, -1)) {
|
|
@@ -171,7 +172,7 @@ async function loadStoreFromFilePath(
|
|
|
171
172
|
|
|
172
173
|
export function getDialectFromUrl(connectionUrl: URL): Dialect {
|
|
173
174
|
switch (connectionUrl.protocol.slice(0, -1)) {
|
|
174
|
-
case BackendTypes.SQLITE:
|
|
175
|
+
case BackendTypes.SQLITE: {
|
|
175
176
|
const path = connectionUrl.host + connectionUrl.pathname;
|
|
176
177
|
console.log('SQL-lite relative path:', path ? path : undefined); // NOTE, using ? for lose equality comparison
|
|
177
178
|
|
|
@@ -184,16 +185,17 @@ export function getDialectFromUrl(connectionUrl: URL): Dialect {
|
|
|
184
185
|
const dbPath = path || ':memory:';
|
|
185
186
|
|
|
186
187
|
return new SqliteDialect({
|
|
187
|
-
database: async () =>
|
|
188
|
+
database: async () => createBunSqliteDatabase(dbPath),
|
|
188
189
|
});
|
|
190
|
+
}
|
|
189
191
|
case BackendTypes.MYSQL:
|
|
190
192
|
return new MysqlDialect({
|
|
191
193
|
pool: async () => MySQLCreatePool(connectionUrl.toString()),
|
|
192
194
|
});
|
|
193
195
|
case BackendTypes.POSTGRES:
|
|
194
196
|
return new PostgresDialect({
|
|
195
|
-
pool: async () => new pg.Pool({ connectionString: connectionUrl.toString() }),
|
|
196
|
-
cursor: Cursor,
|
|
197
|
+
pool : async () => new pg.Pool({ connectionString: connectionUrl.toString() }),
|
|
198
|
+
cursor : Cursor,
|
|
197
199
|
});
|
|
198
200
|
}
|
|
199
201
|
}
|
|
@@ -39,9 +39,9 @@ export class SqlTtlCache {
|
|
|
39
39
|
// 512 chars to accommodate potentially large `state` in Web5 Connect flow
|
|
40
40
|
.addColumn('key', 'varchar(512)', (column) => column.primaryKey())
|
|
41
41
|
.addColumn('value', 'text', (column) => column.notNull())
|
|
42
|
-
.addColumn('expiry', '
|
|
42
|
+
.addColumn('expiry', 'bigint', (column) => column.notNull())
|
|
43
43
|
.execute();
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
await this.db.schema
|
|
46
46
|
.createIndex('index_expiry')
|
|
47
47
|
// .ifNotExists() // intentionally kept commented out code to show that it is not supported by all dialects (ie. MySQL)
|
|
@@ -97,7 +97,8 @@ export class SqlTtlCache {
|
|
|
97
97
|
const entry = result[0];
|
|
98
98
|
|
|
99
99
|
// if the entry is expired, don't return it and delete it
|
|
100
|
-
|
|
100
|
+
const expiry = typeof entry.expiry === 'string' ? parseInt(entry.expiry, 10) : entry.expiry;
|
|
101
|
+
if (Date.now() >= expiry) {
|
|
101
102
|
this.delete(key); // no need to await
|
|
102
103
|
return undefined;
|
|
103
104
|
}
|
|
@@ -129,7 +130,7 @@ export class SqlTtlCache {
|
|
|
129
130
|
interface CacheEntry {
|
|
130
131
|
key: string;
|
|
131
132
|
value: string;
|
|
132
|
-
expiry: number;
|
|
133
|
+
expiry: number | string; // bigint is returned as string by PostgreSQL driver
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
interface CacheDatabase {
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { getDialectFromUrl } from "../storage.js";
|
|
2
1
|
import { CryptoUtils } from '@enbox/crypto';
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
import { getDialectFromUrl } from '../storage.js';
|
|
4
|
+
import { SqlTtlCache } from './sql-ttl-cache.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The Web5 Connect Request object.
|
|
7
8
|
*/
|
|
8
|
-
export type Web5ConnectRequest = any; // TODO: define type in common repo for reuse (https://github.com/
|
|
9
|
+
export type Web5ConnectRequest = any; // TODO: define type in common repo for reuse (https://github.com/enboxorg/enbox/issues/138)
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* The Web5 Connect Response object, which is also an OIDC ID token
|
|
12
13
|
*/
|
|
13
|
-
export type Web5ConnectResponse = any; // TODO: define type in common repo for reuse (https://github.com/
|
|
14
|
+
export type Web5ConnectResponse = any; // TODO: define type in common repo for reuse (https://github.com/enboxorg/enbox/issues/138)
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* The result of the setWeb5ConnectRequest() method.
|
|
@@ -25,7 +26,7 @@ export type SetWeb5ConnectRequestResult = {
|
|
|
25
26
|
* The time in seconds that the Request URI is valid for.
|
|
26
27
|
*/
|
|
27
28
|
expires_in: number;
|
|
28
|
-
}
|
|
29
|
+
};
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* The Web5 Connect Server is responsible for handling the Web5 Connect flow.
|
|
@@ -69,13 +70,13 @@ export class Web5ConnectServer {
|
|
|
69
70
|
// Generate a request URI
|
|
70
71
|
const requestId = CryptoUtils.randomUuid();
|
|
71
72
|
const request_uri = `${this.baseUrl}/connect/authorize/${requestId}.jwt`;
|
|
72
|
-
|
|
73
|
+
|
|
73
74
|
// Store the Request Object.
|
|
74
75
|
this.cache.insert(`request:${requestId}`, request, Web5ConnectServer.ttlInSeconds);
|
|
75
|
-
|
|
76
|
+
|
|
76
77
|
return {
|
|
77
78
|
request_uri,
|
|
78
|
-
expires_in
|
|
79
|
+
expires_in: Web5ConnectServer.ttlInSeconds,
|
|
79
80
|
};
|
|
80
81
|
}
|
|
81
82
|
|
package/src/ws-api.ts
CHANGED
|
@@ -1,45 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
import type {
|
|
3
|
-
Dwn,
|
|
4
|
-
} from '@enbox/dwn-sdk-js';
|
|
5
|
-
|
|
6
|
-
import type { Server } from 'http';
|
|
7
|
-
|
|
8
|
-
import { WebSocketServer } from 'ws';
|
|
1
|
+
import type { Dwn } from '@enbox/dwn-sdk-js';
|
|
2
|
+
import type { ServerWebSocket } from 'bun';
|
|
9
3
|
|
|
10
4
|
import type { ConnectionManager } from './connection/connection-manager.js';
|
|
5
|
+
import type { HttpApi, WsData } from './http-api.js';
|
|
6
|
+
|
|
11
7
|
import { InMemoryConnectionManager } from './connection/connection-manager.js';
|
|
12
8
|
|
|
13
9
|
export class WsApi {
|
|
14
|
-
#wsServer: WebSocketServer;
|
|
15
10
|
dwn: Dwn;
|
|
16
|
-
#connectionManager: ConnectionManager
|
|
11
|
+
#connectionManager: ConnectionManager;
|
|
17
12
|
|
|
18
|
-
constructor(
|
|
13
|
+
constructor(httpApi: HttpApi, dwn: Dwn, connectionManager?: ConnectionManager) {
|
|
19
14
|
this.dwn = dwn;
|
|
20
15
|
this.#connectionManager = connectionManager || new InMemoryConnectionManager(dwn);
|
|
21
|
-
this.#wsServer = new WebSocketServer({ server });
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get server(): WebSocketServer {
|
|
25
|
-
return this.#wsServer;
|
|
26
|
-
}
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
#setupWebSocket(): void {
|
|
33
|
-
this.#wsServer.on('connection', (socket, request) => this.#connectionManager.connect(socket, request));
|
|
34
|
-
this.#wsServer.on('close', () => this.#connectionManager.closeAll());
|
|
17
|
+
// Wire up the WebSocket open event from Bun.serve() to the connection manager.
|
|
18
|
+
httpApi.onWebSocketConnection = (ws: ServerWebSocket<WsData>): void => {
|
|
19
|
+
this.#connectionManager.connect(ws);
|
|
20
|
+
};
|
|
35
21
|
}
|
|
36
22
|
|
|
37
23
|
start(): void {
|
|
38
|
-
|
|
24
|
+
// No additional setup needed — Bun.serve() handles WebSocket lifecycle.
|
|
39
25
|
}
|
|
40
26
|
|
|
41
27
|
async close(): Promise<void> {
|
|
42
|
-
this.#wsServer.close();
|
|
43
28
|
await this.#connectionManager.closeAll();
|
|
44
29
|
}
|
|
45
30
|
}
|