@toon-protocol/relay 2.0.1 → 2.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.
- package/README.md +118 -64
- package/dist/chunk-IZOSPMWV.js +1799 -0
- package/dist/chunk-IZOSPMWV.js.map +1 -0
- package/dist/chunk-SMT6G3XD.js +92 -0
- package/dist/chunk-SMT6G3XD.js.map +1 -0
- package/dist/cli.js +181 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1073 -57
- package/dist/index.js +53 -100
- package/dist/index.js.map +1 -1
- package/dist/verify-worker.d.ts +2 -0
- package/dist/verify-worker.js +17 -0
- package/dist/verify-worker.js.map +1 -0
- package/package.json +9 -5
- package/dist/chunk-FXQSNOCG.js +0 -939
- package/dist/chunk-FXQSNOCG.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,126 +1,79 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ConnectionHandler,
|
|
3
|
+
DEFAULT_EPHEMERAL_MAX_BODY_BYTES,
|
|
4
|
+
DEFAULT_EPHEMERAL_RATE_LIMIT,
|
|
3
5
|
DEFAULT_RELAY_CONFIG,
|
|
6
|
+
DELETION_KIND,
|
|
7
|
+
EXPIRATION_TAG,
|
|
4
8
|
InMemoryEventStore,
|
|
5
9
|
NostrRelayServer,
|
|
6
10
|
RelayError,
|
|
7
11
|
RelaySubscriber,
|
|
8
12
|
SqliteEventStore,
|
|
9
13
|
VERSION,
|
|
14
|
+
createEphemeralWriteHandler,
|
|
10
15
|
createHealthResponse,
|
|
16
|
+
createMetricsRegistry,
|
|
17
|
+
createRateLimiter,
|
|
18
|
+
createVerifyPool,
|
|
11
19
|
createWriteHandler,
|
|
20
|
+
defaultVerifyWorkers,
|
|
21
|
+
getExpiration,
|
|
22
|
+
isDeletableBy,
|
|
23
|
+
isDeletionKind,
|
|
24
|
+
isExpired,
|
|
25
|
+
isInternalBindHost,
|
|
12
26
|
matchFilter,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
constructor(message, cause) {
|
|
28
|
-
super(message, { cause });
|
|
29
|
-
this.name = "ToonDecodeError";
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
function encodeEventToToon(event) {
|
|
33
|
-
return new TextEncoder().encode(encodeEventToToonString(event));
|
|
34
|
-
}
|
|
35
|
-
function encodeEventToToonString(event) {
|
|
36
|
-
try {
|
|
37
|
-
return encode(event);
|
|
38
|
-
} catch (error) {
|
|
39
|
-
throw new ToonEncodeError(
|
|
40
|
-
`Failed to encode event to TOON: ${error instanceof Error ? error.message : String(error)}`,
|
|
41
|
-
error instanceof Error ? error : void 0
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function isValidHex(value, length) {
|
|
46
|
-
return typeof value === "string" && value.length === length && /^[0-9a-f]+$/i.test(value);
|
|
47
|
-
}
|
|
48
|
-
function validateNostrEvent(obj) {
|
|
49
|
-
if (typeof obj !== "object" || obj === null) {
|
|
50
|
-
throw new ToonDecodeError("Decoded value is not an object");
|
|
51
|
-
}
|
|
52
|
-
const event = obj;
|
|
53
|
-
if (!isValidHex(event["id"], 64)) {
|
|
54
|
-
throw new ToonDecodeError(
|
|
55
|
-
"Invalid event id: must be a 64-character hex string"
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
if (!isValidHex(event["pubkey"], 64)) {
|
|
59
|
-
throw new ToonDecodeError(
|
|
60
|
-
"Invalid event pubkey: must be a 64-character hex string"
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
if (typeof event["kind"] !== "number" || !Number.isInteger(event["kind"])) {
|
|
64
|
-
throw new ToonDecodeError("Invalid event kind: must be an integer");
|
|
65
|
-
}
|
|
66
|
-
if (typeof event["content"] !== "string") {
|
|
67
|
-
throw new ToonDecodeError("Invalid event content: must be a string");
|
|
68
|
-
}
|
|
69
|
-
const tags = event["tags"];
|
|
70
|
-
if (!Array.isArray(tags)) {
|
|
71
|
-
throw new ToonDecodeError("Invalid event tags: must be an array");
|
|
72
|
-
}
|
|
73
|
-
for (let i = 0; i < tags.length; i++) {
|
|
74
|
-
const tag = tags[i];
|
|
75
|
-
if (!Array.isArray(tag)) {
|
|
76
|
-
throw new ToonDecodeError(`Invalid event tags[${i}]: must be an array`);
|
|
77
|
-
}
|
|
78
|
-
for (let j = 0; j < tag.length; j++) {
|
|
79
|
-
if (typeof tag[j] !== "string") {
|
|
80
|
-
throw new ToonDecodeError(
|
|
81
|
-
`Invalid event tags[${i}][${j}]: must be a string`
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (typeof event["created_at"] !== "number" || !Number.isInteger(event["created_at"])) {
|
|
87
|
-
throw new ToonDecodeError("Invalid event created_at: must be an integer");
|
|
88
|
-
}
|
|
89
|
-
if (!isValidHex(event["sig"], 128)) {
|
|
90
|
-
throw new ToonDecodeError(
|
|
91
|
-
"Invalid event sig: must be a 128-character hex string"
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function decodeEventFromToon(data) {
|
|
96
|
-
let decoded;
|
|
97
|
-
try {
|
|
98
|
-
decoded = decode(new TextDecoder().decode(data));
|
|
99
|
-
} catch (error) {
|
|
100
|
-
throw new ToonDecodeError(
|
|
101
|
-
`Failed to decode TOON data: ${error instanceof Error ? error.message : String(error)}`,
|
|
102
|
-
error instanceof Error ? error : void 0
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
validateNostrEvent(decoded);
|
|
106
|
-
return decoded;
|
|
107
|
-
}
|
|
27
|
+
parseAddressCoordinate,
|
|
28
|
+
parseBlockedEventIds,
|
|
29
|
+
parseDeletionTargets,
|
|
30
|
+
readOpenFilesSoftLimit,
|
|
31
|
+
readPaymentAttribution,
|
|
32
|
+
serializeEventFrame,
|
|
33
|
+
startRelay,
|
|
34
|
+
warnIfWritePortExposed
|
|
35
|
+
} from "./chunk-IZOSPMWV.js";
|
|
36
|
+
import {
|
|
37
|
+
verifyEventId,
|
|
38
|
+
verifyEventSignature,
|
|
39
|
+
verifyImplementation
|
|
40
|
+
} from "./chunk-SMT6G3XD.js";
|
|
108
41
|
export {
|
|
109
42
|
ConnectionHandler,
|
|
43
|
+
DEFAULT_EPHEMERAL_MAX_BODY_BYTES,
|
|
44
|
+
DEFAULT_EPHEMERAL_RATE_LIMIT,
|
|
110
45
|
DEFAULT_RELAY_CONFIG,
|
|
46
|
+
DELETION_KIND,
|
|
47
|
+
EXPIRATION_TAG,
|
|
111
48
|
InMemoryEventStore,
|
|
112
49
|
NostrRelayServer,
|
|
113
50
|
RelayError,
|
|
114
51
|
RelaySubscriber,
|
|
115
52
|
SqliteEventStore,
|
|
116
|
-
ToonDecodeError,
|
|
117
|
-
ToonEncodeError,
|
|
118
53
|
VERSION,
|
|
54
|
+
createEphemeralWriteHandler,
|
|
119
55
|
createHealthResponse,
|
|
56
|
+
createMetricsRegistry,
|
|
57
|
+
createRateLimiter,
|
|
58
|
+
createVerifyPool,
|
|
120
59
|
createWriteHandler,
|
|
121
|
-
|
|
122
|
-
|
|
60
|
+
defaultVerifyWorkers,
|
|
61
|
+
getExpiration,
|
|
62
|
+
isDeletableBy,
|
|
63
|
+
isDeletionKind,
|
|
64
|
+
isExpired,
|
|
65
|
+
isInternalBindHost,
|
|
123
66
|
matchFilter,
|
|
124
|
-
|
|
67
|
+
parseAddressCoordinate,
|
|
68
|
+
parseBlockedEventIds,
|
|
69
|
+
parseDeletionTargets,
|
|
70
|
+
readOpenFilesSoftLimit,
|
|
71
|
+
readPaymentAttribution,
|
|
72
|
+
serializeEventFrame,
|
|
73
|
+
startRelay,
|
|
74
|
+
verifyEventId,
|
|
75
|
+
verifyEventSignature,
|
|
76
|
+
verifyImplementation,
|
|
77
|
+
warnIfWritePortExposed
|
|
125
78
|
};
|
|
126
79
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
verifyEventSignature
|
|
3
|
+
} from "./chunk-SMT6G3XD.js";
|
|
4
|
+
|
|
5
|
+
// src/crypto/verify-worker.ts
|
|
6
|
+
import { parentPort } from "worker_threads";
|
|
7
|
+
if (!parentPort) {
|
|
8
|
+
throw new Error("verify-worker must be started as a worker thread");
|
|
9
|
+
}
|
|
10
|
+
var port = parentPort;
|
|
11
|
+
port.on("message", (message) => {
|
|
12
|
+
port.postMessage({
|
|
13
|
+
seq: message.seq,
|
|
14
|
+
ok: verifyEventSignature(message.event)
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=verify-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/crypto/verify-worker.ts"],"sourcesContent":["/**\n * Worker-thread entrypoint for the verify pool (relay#85).\n *\n * Each worker imports `verify-event.ts` in its own thread, so each worker\n * instantiates its OWN WASM libsecp256k1 module (with the same load-time\n * self-test and transparent noble fallback as the inline path -- WASM\n * instances are not shareable across threads anyway).\n *\n * Protocol: the parent posts `{ seq, event }`; the worker replies\n * `{ seq, ok }`. `verifyEventSignature` never throws, so every request gets\n * exactly one reply.\n *\n * Built as its own tsup entry (`dist/verify-worker.js`) because\n * `worker_threads` needs a real JS file on disk, not a bundled import.\n *\n * @module\n */\n\nimport { parentPort } from 'node:worker_threads';\nimport type { NostrEvent } from 'nostr-tools/pure';\nimport { verifyEventSignature } from './verify-event.js';\n\nif (!parentPort) {\n throw new Error('verify-worker must be started as a worker thread');\n}\n\nconst port = parentPort;\nport.on('message', (message: { seq: number; event: NostrEvent }) => {\n port.postMessage({\n seq: message.seq,\n ok: verifyEventSignature(message.event),\n });\n});\n"],"mappings":";;;;;AAkBA,SAAS,kBAAkB;AAI3B,IAAI,CAAC,YAAY;AACf,QAAM,IAAI,MAAM,kDAAkD;AACpE;AAEA,IAAM,OAAO;AACb,KAAK,GAAG,WAAW,CAAC,YAAgD;AAClE,OAAK,YAAY;AAAA,IACf,KAAK,QAAQ;AAAA,IACb,IAAI,qBAAqB,QAAQ,KAAK;AAAA,EACxC,CAAC;AACH,CAAC;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toon-protocol/relay",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "Nostr relay app: free NIP-01 reads + HTTP POST /write",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Nostr relay app: free NIP-01 WebSocket reads + an HTTP POST /write surface",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -24,8 +24,12 @@
|
|
|
24
24
|
"keywords": [
|
|
25
25
|
"nostr",
|
|
26
26
|
"relay",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
27
|
+
"toon",
|
|
28
|
+
"nip-01",
|
|
29
|
+
"nip-09",
|
|
30
|
+
"nip-16",
|
|
31
|
+
"nip-40",
|
|
32
|
+
"websocket"
|
|
29
33
|
],
|
|
30
34
|
"license": "MIT",
|
|
31
35
|
"repository": {
|
|
@@ -39,10 +43,10 @@
|
|
|
39
43
|
},
|
|
40
44
|
"dependencies": {
|
|
41
45
|
"@hono/node-server": "^1.0.0",
|
|
42
|
-
"@toon-format/toon": "^1.0.0",
|
|
43
46
|
"better-sqlite3": "^11.0.0",
|
|
44
47
|
"hono": "^4.11.10",
|
|
45
48
|
"nostr-tools": "^2.20.0",
|
|
49
|
+
"tiny-secp256k1": "^2.2.4",
|
|
46
50
|
"ws": "^8.0.0"
|
|
47
51
|
},
|
|
48
52
|
"devDependencies": {
|