@kumiai/hub-server 0.13.0 → 0.13.1
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 +18 -2
- package/lib/handlers.d.ts +5 -1
- package/lib/handlers.js +9 -0
- package/lib/hub.d.ts +5 -2
- package/lib/hub.js +2 -0
- package/lib/memoryStore.js +9 -3
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -5,8 +5,8 @@ client registry for push fan-out, and an in-memory `HubStore` for development an
|
|
|
5
5
|
|
|
6
6
|
## Exports
|
|
7
7
|
|
|
8
|
-
- `createHub({ transport, store, identity, ... })`
|
|
9
|
-
|
|
8
|
+
- `createHub({ transport, store, identity, ... })` -- handlers, registry, access rules, rate limits and an optional scheduled purge.
|
|
9
|
+
Returns `{ registry, server, dispose }`.
|
|
10
10
|
- `createHandlers({ registry, store, ... })` — the handlers alone, for a host assembling its own
|
|
11
11
|
server.
|
|
12
12
|
- `createMemoryStore({ maxDepth?, retention? })` — an in-memory `HubStore`. For testing and
|
|
@@ -160,3 +160,19 @@ rather than passing silently. Pass an empty handler to silence it deliberately.
|
|
|
160
160
|
There is no throttling: a permanently broken store reports per request. logtape ships
|
|
161
161
|
`getThrottlingFilter`, so rate control belongs in the app's sink configuration where an operator
|
|
162
162
|
can tune it.
|
|
163
|
+
|
|
164
|
+
## Invocation hooks and attribution
|
|
165
|
+
|
|
166
|
+
`createHub` accepts optional `onInvocation`, forwarded to the Enkaku server for authenticated invocation context and delegation verification.
|
|
167
|
+
`createHub` and `createHandlers` accept optional `resolveAttribution({ message, senderDID })`.
|
|
168
|
+
The resolver can return `HubAttribution`, `undefined`, or a promise of either.
|
|
169
|
+
|
|
170
|
+
Without a resolver result, publishes use `{ account: senderDID, actor: senderDID, via: 'direct' }`.
|
|
171
|
+
The sender DID still comes from the verified signature.
|
|
172
|
+
A resolver supplies host accounting metadata rather than changing the authenticated sender or authorisation rules.
|
|
173
|
+
Only a verified delegation yields `via: 'delegated'`. A claimed subject alone does not prove delegation.
|
|
174
|
+
Hosts can use `onInvocation` to verify delegation before resolving attribution.
|
|
175
|
+
|
|
176
|
+
The store receives the resolved attribution with the publish.
|
|
177
|
+
The SQL stores persist it. The development memory store reports publish outcomes but does not implement occupancy sampling.
|
|
178
|
+
Unconfigured hooks preserve existing routing, retention and delivery behaviour.
|
package/lib/handlers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ProcedureHandlers } from '@enkaku/server';
|
|
2
|
-
import type { HubProtocol, HubStore, WakeRegistry } from '@kumiai/hub-protocol';
|
|
2
|
+
import type { HubAttribution, HubProtocol, HubStore, WakeRegistry } from '@kumiai/hub-protocol';
|
|
3
3
|
import { type RateLimitConfig } from './rateLimit.js';
|
|
4
4
|
import type { HubClientRegistry } from './registry.js';
|
|
5
5
|
import type { WakeDispatcher } from './wake.js';
|
|
@@ -198,6 +198,10 @@ export type CreateHandlersParams = {
|
|
|
198
198
|
registry: HubClientRegistry;
|
|
199
199
|
store: HubStore;
|
|
200
200
|
authorize?: AuthorizeHook;
|
|
201
|
+
resolveAttribution?: (params: {
|
|
202
|
+
message: unknown;
|
|
203
|
+
senderDID: string;
|
|
204
|
+
}) => HubAttribution | undefined | Promise<HubAttribution | undefined>;
|
|
201
205
|
rateLimits?: Partial<HubRateLimits>;
|
|
202
206
|
keyPackageFetchLimits?: Partial<KeyPackageFetchLimits>;
|
|
203
207
|
/** Max frames queued-but-unflushed on a receive channel. See {@link DEFAULT_RECEIVE_BUFFER_LIMIT}
|
package/lib/handlers.js
CHANGED
|
@@ -287,8 +287,17 @@ export function createHandlers(params) {
|
|
|
287
287
|
let sequenceID;
|
|
288
288
|
let deduped;
|
|
289
289
|
try {
|
|
290
|
+
const attribution = await params.resolveAttribution?.({
|
|
291
|
+
message: ctx.message,
|
|
292
|
+
senderDID
|
|
293
|
+
}) ?? {
|
|
294
|
+
account: senderDID,
|
|
295
|
+
actor: senderDID,
|
|
296
|
+
via: 'direct'
|
|
297
|
+
};
|
|
290
298
|
const result = await store.publish({
|
|
291
299
|
senderDID,
|
|
300
|
+
attribution,
|
|
292
301
|
topicID,
|
|
293
302
|
payload: payloadBytes,
|
|
294
303
|
retain: ctx.param.retain,
|
package/lib/hub.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ServerTransportOf } from '@enkaku/protocol';
|
|
2
|
-
import type { AccessRules, ReplayOptions, ResourceLimits, Server } from '@enkaku/server';
|
|
2
|
+
import type { AccessRules, InvocationHook, ReplayOptions, ResourceLimits, Server } from '@enkaku/server';
|
|
3
3
|
import type { VerifyTokenHook } from '@kokuin/capability';
|
|
4
4
|
import type { CryptoOptions, Identity } from '@kokuin/token';
|
|
5
5
|
import type { HubProtocol, HubStore, WakeRegistry, WakeSender } from '@kumiai/hub-protocol';
|
|
6
|
-
import {
|
|
6
|
+
import type { AuthorizeHook, CreateHandlersParams, HubRateLimits, HubStoreErrorHook, KeyPackageFetchLimits } from './handlers.js';
|
|
7
7
|
import { HubClientRegistry } from './registry.js';
|
|
8
8
|
/**
|
|
9
9
|
* Default access rules: any authenticated DID may call hub procedures.
|
|
@@ -53,6 +53,9 @@ export type CreateHubParams = CryptoOptions & {
|
|
|
53
53
|
* delegated capabilities.
|
|
54
54
|
*/
|
|
55
55
|
verifyToken?: VerifyTokenHook;
|
|
56
|
+
onInvocation?: InvocationHook;
|
|
57
|
+
/** An absent result attributes directly to the sender. */
|
|
58
|
+
resolveAttribution?: CreateHandlersParams['resolveAttribution'];
|
|
56
59
|
/** Publish rate limits. Merged over {@link DEFAULT_RATE_LIMITS}. */
|
|
57
60
|
rateLimits?: Partial<HubRateLimits>;
|
|
58
61
|
/**
|
package/lib/hub.js
CHANGED
|
@@ -32,6 +32,7 @@ export function createHub(params) {
|
|
|
32
32
|
registry,
|
|
33
33
|
store: params.store,
|
|
34
34
|
authorize: params.authorize,
|
|
35
|
+
resolveAttribution: params.resolveAttribution,
|
|
35
36
|
rateLimits: params.rateLimits,
|
|
36
37
|
keyPackageFetchLimits: params.keyPackageFetchLimits,
|
|
37
38
|
receiveAuthCacheTTL: params.receiveAuthCacheTTL,
|
|
@@ -58,6 +59,7 @@ export function createHub(params) {
|
|
|
58
59
|
crypto: params.crypto,
|
|
59
60
|
accessRules: params.accessRules ?? DEFAULT_HUB_ACCESS_RULES,
|
|
60
61
|
verifyToken: params.verifyToken,
|
|
62
|
+
onInvocation: params.onInvocation,
|
|
61
63
|
replay: {
|
|
62
64
|
...params.replay,
|
|
63
65
|
enabled: true,
|
package/lib/memoryStore.js
CHANGED
|
@@ -137,7 +137,9 @@ function isLive(entry, nowSeconds) {
|
|
|
137
137
|
if (accepted !== undefined) {
|
|
138
138
|
return {
|
|
139
139
|
sequenceID: accepted,
|
|
140
|
-
deduped: true
|
|
140
|
+
deduped: true,
|
|
141
|
+
outcome: 'deduplicated',
|
|
142
|
+
storedBytes: 0
|
|
141
143
|
};
|
|
142
144
|
}
|
|
143
145
|
}
|
|
@@ -174,7 +176,9 @@ function isLive(entry, nowSeconds) {
|
|
|
174
176
|
if (retain === 'mailbox' && recipients.size === 0) {
|
|
175
177
|
return {
|
|
176
178
|
sequenceID,
|
|
177
|
-
deduped: false
|
|
179
|
+
deduped: false,
|
|
180
|
+
outcome: 'no-recipients',
|
|
181
|
+
storedBytes: 0
|
|
178
182
|
};
|
|
179
183
|
}
|
|
180
184
|
const entry = {
|
|
@@ -219,7 +223,9 @@ function isLive(entry, nowSeconds) {
|
|
|
219
223
|
}
|
|
220
224
|
return {
|
|
221
225
|
sequenceID,
|
|
222
|
-
deduped: false
|
|
226
|
+
deduped: false,
|
|
227
|
+
outcome: 'inserted',
|
|
228
|
+
storedBytes: params.payload.byteLength
|
|
223
229
|
};
|
|
224
230
|
},
|
|
225
231
|
async fetch (params) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kumiai/hub-server",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Hub server for Enkaku E2EE group message routing",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hub",
|
|
@@ -25,19 +25,19 @@
|
|
|
25
25
|
"lib/*"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@enkaku/protocol": "^0.23.
|
|
29
|
-
"@enkaku/server": "^0.23.
|
|
28
|
+
"@enkaku/protocol": "^0.23.1",
|
|
29
|
+
"@enkaku/server": "^0.23.1",
|
|
30
30
|
"@kokuin/capability": "^0.7.0",
|
|
31
31
|
"@kokuin/token": "^0.7.0",
|
|
32
|
-
"@kumiai/hub-protocol": "^0.13.
|
|
32
|
+
"@kumiai/hub-protocol": "^0.13.1",
|
|
33
33
|
"@sozai/codec": "^0.4.4",
|
|
34
34
|
"@sozai/event": "^0.1.6",
|
|
35
35
|
"@sozai/log": "^0.4.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@enkaku/client": "^0.23.
|
|
39
|
-
"@enkaku/transport": "^0.23.
|
|
40
|
-
"@kokuin/crypto": "^0.7.
|
|
38
|
+
"@enkaku/client": "^0.23.1",
|
|
39
|
+
"@enkaku/transport": "^0.23.1",
|
|
40
|
+
"@kokuin/crypto": "^0.7.1",
|
|
41
41
|
"@kumiai/hub-conformance": "^0.13.0",
|
|
42
42
|
"@kumiai/hub-wake": "^0.13.0"
|
|
43
43
|
},
|