@agimon-ai/doompi-session 0.0.1-alpha.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/LICENSE +21 -0
- package/README.md +44 -0
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/api-contracts.cjs +7 -0
- package/dist/api-contracts.d.cts +2 -0
- package/dist/api-contracts.d.mts +2 -0
- package/dist/api-contracts.mjs +2 -0
- package/dist/extensions/pi.cjs +20 -0
- package/dist/extensions/pi.cjs.map +1 -0
- package/dist/extensions/pi.d.cts +5 -0
- package/dist/extensions/pi.d.cts.map +1 -0
- package/dist/extensions/pi.d.mts +5 -0
- package/dist/extensions/pi.d.mts.map +1 -0
- package/dist/extensions/pi.mjs +15 -0
- package/dist/extensions/pi.mjs.map +1 -0
- package/dist/extensions/server.cjs +37 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.cts +5 -0
- package/dist/extensions/server.d.cts.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +32 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/index.cjs +32 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.mjs +10 -0
- package/dist/src/extensions/(backend)/api/session-peer/route.server.cjs +7 -0
- package/dist/src/extensions/(backend)/api/session-peer/route.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/api/session-peer/route.server.mjs +8 -0
- package/dist/src/extensions/(backend)/api/session-peer/route.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs +10 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs +11 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs +101 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs +99 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs.map +1 -0
- package/dist/src/schemas/apiContracts.cjs +33 -0
- package/dist/src/schemas/apiContracts.cjs.map +1 -0
- package/dist/src/schemas/apiContracts.d.cts +52 -0
- package/dist/src/schemas/apiContracts.d.cts.map +1 -0
- package/dist/src/schemas/apiContracts.d.mts +52 -0
- package/dist/src/schemas/apiContracts.d.mts.map +1 -0
- package/dist/src/schemas/apiContracts.mjs +32 -0
- package/dist/src/schemas/apiContracts.mjs.map +1 -0
- package/dist/src/services/backgroundWorkService/index.cjs +79 -0
- package/dist/src/services/backgroundWorkService/index.cjs.map +1 -0
- package/dist/src/services/backgroundWorkService/index.d.cts +9 -0
- package/dist/src/services/backgroundWorkService/index.d.cts.map +1 -0
- package/dist/src/services/backgroundWorkService/index.d.mts +9 -0
- package/dist/src/services/backgroundWorkService/index.d.mts.map +1 -0
- package/dist/src/services/backgroundWorkService/index.mjs +78 -0
- package/dist/src/services/backgroundWorkService/index.mjs.map +1 -0
- package/dist/src/services/peerInbox/index.cjs +18 -0
- package/dist/src/services/peerInbox/index.cjs.map +1 -0
- package/dist/src/services/peerInbox/index.mjs +17 -0
- package/dist/src/services/peerInbox/index.mjs.map +1 -0
- package/dist/src/services/peerInboxApi/index.cjs +48 -0
- package/dist/src/services/peerInboxApi/index.cjs.map +1 -0
- package/dist/src/services/peerInboxApi/index.mjs +48 -0
- package/dist/src/services/peerInboxApi/index.mjs.map +1 -0
- package/dist/src/services/peerTransport/index.cjs +206 -0
- package/dist/src/services/peerTransport/index.cjs.map +1 -0
- package/dist/src/services/peerTransport/index.d.cts +49 -0
- package/dist/src/services/peerTransport/index.d.cts.map +1 -0
- package/dist/src/services/peerTransport/index.d.mts +49 -0
- package/dist/src/services/peerTransport/index.d.mts.map +1 -0
- package/dist/src/services/peerTransport/index.mjs +195 -0
- package/dist/src/services/peerTransport/index.mjs.map +1 -0
- package/dist/src/services/sessionDelivery/index.cjs +277 -0
- package/dist/src/services/sessionDelivery/index.cjs.map +1 -0
- package/dist/src/services/sessionDelivery/index.d.cts +10 -0
- package/dist/src/services/sessionDelivery/index.d.cts.map +1 -0
- package/dist/src/services/sessionDelivery/index.d.mts +10 -0
- package/dist/src/services/sessionDelivery/index.d.mts.map +1 -0
- package/dist/src/services/sessionDelivery/index.mjs +274 -0
- package/dist/src/services/sessionDelivery/index.mjs.map +1 -0
- package/dist/src/services/sessionDelivery/type.cjs +11 -0
- package/dist/src/services/sessionDelivery/type.cjs.map +1 -0
- package/dist/src/services/sessionDelivery/type.d.cts +73 -0
- package/dist/src/services/sessionDelivery/type.d.cts.map +1 -0
- package/dist/src/services/sessionDelivery/type.d.mts +73 -0
- package/dist/src/services/sessionDelivery/type.d.mts.map +1 -0
- package/dist/src/services/sessionDelivery/type.mjs +10 -0
- package/dist/src/services/sessionDelivery/type.mjs.map +1 -0
- package/dist/src/services/sessionDirectory/index.cjs +120 -0
- package/dist/src/services/sessionDirectory/index.cjs.map +1 -0
- package/dist/src/services/sessionDirectory/index.d.cts +7 -0
- package/dist/src/services/sessionDirectory/index.d.cts.map +1 -0
- package/dist/src/services/sessionDirectory/index.d.mts +7 -0
- package/dist/src/services/sessionDirectory/index.d.mts.map +1 -0
- package/dist/src/services/sessionDirectory/index.mjs +120 -0
- package/dist/src/services/sessionDirectory/index.mjs.map +1 -0
- package/dist/src/services/sessionDirectory/type.d.cts +54 -0
- package/dist/src/services/sessionDirectory/type.d.cts.map +1 -0
- package/dist/src/services/sessionDirectory/type.d.mts +54 -0
- package/dist/src/services/sessionDirectory/type.d.mts.map +1 -0
- package/dist/src/services/sessionGroups/index.cjs +105 -0
- package/dist/src/services/sessionGroups/index.cjs.map +1 -0
- package/dist/src/services/sessionGroups/index.d.cts +7 -0
- package/dist/src/services/sessionGroups/index.d.cts.map +1 -0
- package/dist/src/services/sessionGroups/index.d.mts +7 -0
- package/dist/src/services/sessionGroups/index.d.mts.map +1 -0
- package/dist/src/services/sessionGroups/index.mjs +104 -0
- package/dist/src/services/sessionGroups/index.mjs.map +1 -0
- package/dist/src/services/sessionGroups/type.cjs +11 -0
- package/dist/src/services/sessionGroups/type.cjs.map +1 -0
- package/dist/src/services/sessionGroups/type.d.cts +32 -0
- package/dist/src/services/sessionGroups/type.d.cts.map +1 -0
- package/dist/src/services/sessionGroups/type.d.mts +32 -0
- package/dist/src/services/sessionGroups/type.d.mts.map +1 -0
- package/dist/src/services/sessionGroups/type.mjs +11 -0
- package/dist/src/services/sessionGroups/type.mjs.map +1 -0
- package/dist/src/services/sessionIntercom/index.cjs +89 -0
- package/dist/src/services/sessionIntercom/index.cjs.map +1 -0
- package/dist/src/services/sessionIntercom/index.d.cts +11 -0
- package/dist/src/services/sessionIntercom/index.d.cts.map +1 -0
- package/dist/src/services/sessionIntercom/index.d.mts +11 -0
- package/dist/src/services/sessionIntercom/index.d.mts.map +1 -0
- package/dist/src/services/sessionIntercom/index.mjs +85 -0
- package/dist/src/services/sessionIntercom/index.mjs.map +1 -0
- package/dist/src/services/sessionIntercom/type.cjs +16 -0
- package/dist/src/services/sessionIntercom/type.cjs.map +1 -0
- package/dist/src/services/sessionIntercom/type.d.cts +60 -0
- package/dist/src/services/sessionIntercom/type.d.cts.map +1 -0
- package/dist/src/services/sessionIntercom/type.d.mts +60 -0
- package/dist/src/services/sessionIntercom/type.d.mts.map +1 -0
- package/dist/src/services/sessionIntercom/type.mjs +14 -0
- package/dist/src/services/sessionIntercom/type.mjs.map +1 -0
- package/llms.txt +3 -0
- package/package.json +115 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { provideBackgroundWorkService } from "../../../../services/backgroundWorkService/index.mjs";
|
|
2
|
+
import { createPeerCommunication, parseRemoteSessionReference, peerSessionReference, readSessionPeerConfig } from "../../../../services/peerTransport/index.mjs";
|
|
3
|
+
import { createSessionDirectory } from "../../../../services/sessionDirectory/index.mjs";
|
|
4
|
+
import { createSessionGroupStore } from "../../../../services/sessionGroups/index.mjs";
|
|
5
|
+
import { DOOM_SESSION_INTERCOM_SERVICE } from "../../../../services/sessionIntercom/type.mjs";
|
|
6
|
+
import { createSessionGroupDeliveryAuthorizer, createSessionIntercom } from "../../../../services/sessionIntercom/index.mjs";
|
|
7
|
+
import { readDoomSessionDelivery } from "../../../../services/sessionDelivery/type.mjs";
|
|
8
|
+
import { provideSessionDeliveryService } from "../../../../services/sessionDelivery/index.mjs";
|
|
9
|
+
import { registerSessionPeerInbox } from "../../../../services/peerInbox/index.mjs";
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import { defineRoot } from "@agimon-ai/doompi-core/extension-file";
|
|
13
|
+
//#region src/extensions/workspaces/sessions/(backend)/root.server.ts
|
|
14
|
+
var root_server_default = defineRoot((pluginContext) => ({
|
|
15
|
+
value: void 0,
|
|
16
|
+
services: [provideBackgroundWorkService, (context) => {
|
|
17
|
+
const agent = pluginContext.agent;
|
|
18
|
+
const session = agent?.context.session;
|
|
19
|
+
const communication = pluginContext.host.context.sessionCommunication;
|
|
20
|
+
const homeDirectory = pluginContext.host.context.homeDirectory;
|
|
21
|
+
const sessionService = pluginContext.host.context.sessionService;
|
|
22
|
+
if (!agent || !session?.admitPrompt || !communication || !homeDirectory || !sessionService?.canCommunicate) throw new Error("Session delivery requires the headless agent, authenticated session communication, host home directory, and communication policy.");
|
|
23
|
+
const sessionDirectory = path.join(homeDirectory, ".pi", ".doom", "session");
|
|
24
|
+
const deliveryDirectory = path.join(sessionDirectory, "delivery");
|
|
25
|
+
fs.mkdirSync(deliveryDirectory, {
|
|
26
|
+
recursive: true,
|
|
27
|
+
mode: 448
|
|
28
|
+
});
|
|
29
|
+
const peerCommunication = createPeerCommunication({
|
|
30
|
+
local: communication,
|
|
31
|
+
homeDirectory
|
|
32
|
+
});
|
|
33
|
+
const peerConfig = readSessionPeerConfig(homeDirectory);
|
|
34
|
+
const remotePeerIsGranted = (peerKey) => {
|
|
35
|
+
const peer = parseRemoteSessionReference(peerKey);
|
|
36
|
+
return peer !== void 0 && peerConfig?.peers.some((candidate) => candidate.hostId === peer.hostId && candidate.allowedSessionIds.includes(agent.context.sessionId)) === true;
|
|
37
|
+
};
|
|
38
|
+
const fallbackAuthorization = (peerKey) => sessionService.canCommunicate?.(agent.context.sessionId, peerKey) === true || remotePeerIsGranted(peerKey);
|
|
39
|
+
const groups = peerConfig ? createSessionGroupStore({ databasePath: path.join(sessionDirectory, "groups.sqlite") }) : void 0;
|
|
40
|
+
const localHostId = peerConfig?.hostId;
|
|
41
|
+
const selfReference = localHostId ? peerSessionReference(localHostId, agent.context.sessionId) : void 0;
|
|
42
|
+
const groupAuthorization = groups && selfReference && localHostId ? createSessionGroupDeliveryAuthorizer({
|
|
43
|
+
selfReference,
|
|
44
|
+
groups,
|
|
45
|
+
peerReference: (peerKey) => parseRemoteSessionReference(peerKey) === void 0 ? peerSessionReference(localHostId, peerKey) : peerKey,
|
|
46
|
+
fallback: fallbackAuthorization
|
|
47
|
+
}) : void 0;
|
|
48
|
+
const closeDelivery = provideSessionDeliveryService(context, {
|
|
49
|
+
databasePath: path.join(deliveryDirectory, `${agent.context.sessionId}.sqlite`),
|
|
50
|
+
recipientKey: agent.context.sessionId,
|
|
51
|
+
communication: peerCommunication,
|
|
52
|
+
authorizePeer: (peerKey, metadata) => groupAuthorization?.(peerKey, metadata) ?? fallbackAuthorization(peerKey),
|
|
53
|
+
admitPrompt: (prompt, delivery) => session.admitPrompt(prompt, delivery)
|
|
54
|
+
});
|
|
55
|
+
const service = readDoomSessionDelivery(context);
|
|
56
|
+
if (!service?.receive) throw new Error("Session peer delivery receiver was not installed.");
|
|
57
|
+
const unprovide = [];
|
|
58
|
+
if (groups && selfReference && peerConfig) {
|
|
59
|
+
const directory = createSessionDirectory({ authorizeDiscovery: (caller, subject) => {
|
|
60
|
+
const reference = peerSessionReference(subject.hostId, subject.sessionId);
|
|
61
|
+
return groups.groupsFor(caller).some((group) => group.members.includes(reference)) ? { capabilities: ["message"] } : void 0;
|
|
62
|
+
} });
|
|
63
|
+
for (const peer of peerConfig.peers) for (const sessionId of peer.allowedSessionIds) directory.observe({
|
|
64
|
+
hostId: peer.hostId,
|
|
65
|
+
sessionId,
|
|
66
|
+
hostIncarnation: "unknown",
|
|
67
|
+
sessionIncarnation: "unknown",
|
|
68
|
+
sequence: 0,
|
|
69
|
+
observedAt: 0,
|
|
70
|
+
staleAfterMs: 0,
|
|
71
|
+
deliveryTarget: peerSessionReference(peer.hostId, sessionId),
|
|
72
|
+
reachability: "unknown",
|
|
73
|
+
runtime: "unknown",
|
|
74
|
+
activity: "unknown",
|
|
75
|
+
voice: {
|
|
76
|
+
eligible: "unknown",
|
|
77
|
+
readiness: "unknown"
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
unprovide.push(context.provide(DOOM_SESSION_INTERCOM_SERVICE, createSessionIntercom({
|
|
81
|
+
selfReference,
|
|
82
|
+
directory,
|
|
83
|
+
groups,
|
|
84
|
+
delivery: service
|
|
85
|
+
})));
|
|
86
|
+
}
|
|
87
|
+
const unregister = registerSessionPeerInbox(agent.context.sessionId, (sourceKey, kind, payload) => service.receive?.(sourceKey, kind, payload));
|
|
88
|
+
return async () => {
|
|
89
|
+
unregister();
|
|
90
|
+
for (const release of unprovide.reverse()) release();
|
|
91
|
+
await closeDelivery();
|
|
92
|
+
groups?.close();
|
|
93
|
+
};
|
|
94
|
+
}]
|
|
95
|
+
}));
|
|
96
|
+
//#endregion
|
|
97
|
+
export { root_server_default as default };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=root.server.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root.server.mjs","names":[],"sources":["../../../../../../src/extensions/workspaces/sessions/(backend)/root.server.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { defineRoot } from '@agimon-ai/doompi-core/extension-file';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/server-facet';\n\nimport { provideBackgroundWorkService } from '../../../../services/backgroundWorkService';\nimport { registerSessionPeerInbox } from '../../../../services/peerInbox';\nimport {\n createPeerCommunication,\n parseRemoteSessionReference,\n peerSessionReference,\n readSessionPeerConfig,\n} from '../../../../services/peerTransport';\nimport { provideSessionDeliveryService, readDoomSessionDelivery } from '../../../../services/sessionDelivery';\nimport { createSessionDirectory } from '../../../../services/sessionDirectory';\nimport { createSessionGroupStore } from '../../../../services/sessionGroups';\nimport {\n DOOM_SESSION_INTERCOM_SERVICE,\n createSessionGroupDeliveryAuthorizer,\n createSessionIntercom,\n} from '../../../../services/sessionIntercom';\n\nexport default defineRoot((pluginContext: DoomServerPluginContext) => ({\n value: undefined,\n services: [\n provideBackgroundWorkService,\n (context) => {\n const agent = pluginContext.agent;\n const session = agent?.context.session;\n const communication = pluginContext.host.context.sessionCommunication;\n const homeDirectory = pluginContext.host.context.homeDirectory;\n const sessionService = pluginContext.host.context.sessionService;\n if (!agent || !session?.admitPrompt || !communication || !homeDirectory || !sessionService?.canCommunicate) {\n throw new Error(\n 'Session delivery requires the headless agent, authenticated session communication, host home directory, and communication policy.',\n );\n }\n const sessionDirectory = path.join(homeDirectory, '.pi', '.doom', 'session');\n const deliveryDirectory = path.join(sessionDirectory, 'delivery');\n fs.mkdirSync(deliveryDirectory, { recursive: true, mode: 0o700 });\n const peerCommunication = createPeerCommunication({ local: communication, homeDirectory });\n const peerConfig = readSessionPeerConfig(homeDirectory);\n const remotePeerIsGranted = (peerKey: string): boolean => {\n const peer = parseRemoteSessionReference(peerKey);\n return (\n peer !== undefined &&\n peerConfig?.peers.some(\n (candidate) =>\n candidate.hostId === peer.hostId && candidate.allowedSessionIds.includes(agent.context.sessionId),\n ) === true\n );\n };\n const fallbackAuthorization = (peerKey: string): boolean =>\n sessionService.canCommunicate?.(agent.context.sessionId, peerKey) === true || remotePeerIsGranted(peerKey);\n const groups = peerConfig\n ? createSessionGroupStore({ databasePath: path.join(sessionDirectory, 'groups.sqlite') })\n : undefined;\n const localHostId = peerConfig?.hostId;\n const selfReference = localHostId ? peerSessionReference(localHostId, agent.context.sessionId) : undefined;\n const groupAuthorization =\n groups && selfReference && localHostId\n ? createSessionGroupDeliveryAuthorizer({\n selfReference,\n groups,\n peerReference: (peerKey) =>\n parseRemoteSessionReference(peerKey) === undefined\n ? peerSessionReference(localHostId, peerKey)\n : peerKey,\n fallback: fallbackAuthorization,\n })\n : undefined;\n const closeDelivery = provideSessionDeliveryService(context, {\n databasePath: path.join(deliveryDirectory, `${agent.context.sessionId}.sqlite`),\n recipientKey: agent.context.sessionId,\n communication: peerCommunication,\n authorizePeer: (peerKey, metadata) => groupAuthorization?.(peerKey, metadata) ?? fallbackAuthorization(peerKey),\n admitPrompt: (prompt, delivery) => session.admitPrompt!(prompt, delivery),\n });\n const service = readDoomSessionDelivery(context);\n if (!service?.receive) throw new Error('Session peer delivery receiver was not installed.');\n const unprovide: (() => void)[] = [];\n if (groups && selfReference && peerConfig) {\n const directory = createSessionDirectory({\n authorizeDiscovery: (caller, subject) => {\n const reference = peerSessionReference(subject.hostId, subject.sessionId);\n const permitted = groups.groupsFor(caller).some((group) => group.members.includes(reference));\n return permitted ? { capabilities: ['message'] } : undefined;\n },\n });\n for (const peer of peerConfig.peers)\n for (const sessionId of peer.allowedSessionIds)\n directory.observe({\n hostId: peer.hostId,\n sessionId,\n hostIncarnation: 'unknown',\n sessionIncarnation: 'unknown',\n sequence: 0,\n observedAt: 0,\n staleAfterMs: 0,\n deliveryTarget: peerSessionReference(peer.hostId, sessionId),\n reachability: 'unknown',\n runtime: 'unknown',\n activity: 'unknown',\n voice: { eligible: 'unknown', readiness: 'unknown' },\n });\n unprovide.push(\n context.provide(\n DOOM_SESSION_INTERCOM_SERVICE,\n createSessionIntercom({ selfReference, directory, groups, delivery: service }),\n ),\n );\n }\n const unregister = registerSessionPeerInbox(agent.context.sessionId, (sourceKey, kind, payload) =>\n service.receive?.(sourceKey, kind, payload),\n );\n return async () => {\n unregister();\n for (const release of unprovide.reverse()) release();\n await closeDelivery();\n groups?.close();\n };\n },\n ],\n}));\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAA,sBAAe,YAAY,mBAA4C;CACrE,OAAO,KAAA;CACP,UAAU,CACR,+BACC,YAAY;EACX,MAAM,QAAQ,cAAc;EAC5B,MAAM,UAAU,OAAO,QAAQ;EAC/B,MAAM,gBAAgB,cAAc,KAAK,QAAQ;EACjD,MAAM,gBAAgB,cAAc,KAAK,QAAQ;EACjD,MAAM,iBAAiB,cAAc,KAAK,QAAQ;EAClD,IAAI,CAAC,SAAS,CAAC,SAAS,eAAe,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,gBAAgB,gBAC1F,MAAM,IAAI,MACR,mIACF;EAEF,MAAM,mBAAmB,KAAK,KAAK,eAAe,OAAO,SAAS,SAAS;EAC3E,MAAM,oBAAoB,KAAK,KAAK,kBAAkB,UAAU;EAChE,GAAG,UAAU,mBAAmB;GAAE,WAAW;GAAM,MAAM;EAAM,CAAC;EAChE,MAAM,oBAAoB,wBAAwB;GAAE,OAAO;GAAe;EAAc,CAAC;EACzF,MAAM,aAAa,sBAAsB,aAAa;EACtD,MAAM,uBAAuB,YAA6B;GACxD,MAAM,OAAO,4BAA4B,OAAO;GAChD,OACE,SAAS,KAAA,KACT,YAAY,MAAM,MACf,cACC,UAAU,WAAW,KAAK,UAAU,UAAU,kBAAkB,SAAS,MAAM,QAAQ,SAAS,CACpG,MAAM;EAEV;EACA,MAAM,yBAAyB,YAC7B,eAAe,iBAAiB,MAAM,QAAQ,WAAW,OAAO,MAAM,QAAQ,oBAAoB,OAAO;EAC3G,MAAM,SAAS,aACX,wBAAwB,EAAE,cAAc,KAAK,KAAK,kBAAkB,eAAe,EAAE,CAAC,IACtF,KAAA;EACJ,MAAM,cAAc,YAAY;EAChC,MAAM,gBAAgB,cAAc,qBAAqB,aAAa,MAAM,QAAQ,SAAS,IAAI,KAAA;EACjG,MAAM,qBACJ,UAAU,iBAAiB,cACvB,qCAAqC;GACnC;GACA;GACA,gBAAgB,YACd,4BAA4B,OAAO,MAAM,KAAA,IACrC,qBAAqB,aAAa,OAAO,IACzC;GACN,UAAU;EACZ,CAAC,IACD,KAAA;EACN,MAAM,gBAAgB,8BAA8B,SAAS;GAC3D,cAAc,KAAK,KAAK,mBAAmB,GAAG,MAAM,QAAQ,UAAU,QAAQ;GAC9E,cAAc,MAAM,QAAQ;GAC5B,eAAe;GACf,gBAAgB,SAAS,aAAa,qBAAqB,SAAS,QAAQ,KAAK,sBAAsB,OAAO;GAC9G,cAAc,QAAQ,aAAa,QAAQ,YAAa,QAAQ,QAAQ;EAC1E,CAAC;EACD,MAAM,UAAU,wBAAwB,OAAO;EAC/C,IAAI,CAAC,SAAS,SAAS,MAAM,IAAI,MAAM,mDAAmD;EAC1F,MAAM,YAA4B,CAAC;EACnC,IAAI,UAAU,iBAAiB,YAAY;GACzC,MAAM,YAAY,uBAAuB,EACvC,qBAAqB,QAAQ,YAAY;IACvC,MAAM,YAAY,qBAAqB,QAAQ,QAAQ,QAAQ,SAAS;IAExE,OADkB,OAAO,UAAU,MAAM,CAAC,CAAC,MAAM,UAAU,MAAM,QAAQ,SAAS,SAAS,CAC5E,IAAI,EAAE,cAAc,CAAC,SAAS,EAAE,IAAI,KAAA;GACrD,EACF,CAAC;GACD,KAAK,MAAM,QAAQ,WAAW,OAC5B,KAAK,MAAM,aAAa,KAAK,mBAC3B,UAAU,QAAQ;IAChB,QAAQ,KAAK;IACb;IACA,iBAAiB;IACjB,oBAAoB;IACpB,UAAU;IACV,YAAY;IACZ,cAAc;IACd,gBAAgB,qBAAqB,KAAK,QAAQ,SAAS;IAC3D,cAAc;IACd,SAAS;IACT,UAAU;IACV,OAAO;KAAE,UAAU;KAAW,WAAW;IAAU;GACrD,CAAC;GACL,UAAU,KACR,QAAQ,QACN,+BACA,sBAAsB;IAAE;IAAe;IAAW;IAAQ,UAAU;GAAQ,CAAC,CAC/E,CACF;EACF;EACA,MAAM,aAAa,yBAAyB,MAAM,QAAQ,YAAY,WAAW,MAAM,YACrF,QAAQ,UAAU,WAAW,MAAM,OAAO,CAC5C;EACA,OAAO,YAAY;GACjB,WAAW;GACX,KAAK,MAAM,WAAW,UAAU,QAAQ,GAAG,QAAQ;GACnD,MAAM,cAAc;GACpB,QAAQ,MAAM;EAChB;CACF,CACF;AACF,EAAE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
let _agimon_ai_doompi_core_api_contracts = require("@agimon-ai/doompi-core/api-contracts");
|
|
2
|
+
let typebox = require("typebox");
|
|
3
|
+
//#region src/schemas/apiContracts.ts
|
|
4
|
+
/** The endpoint validates its own HMAC peer credential because tunnel device authentication is intentionally bypassed. */
|
|
5
|
+
const http = [{
|
|
6
|
+
id: "peer-inbox",
|
|
7
|
+
scope: "global",
|
|
8
|
+
basePath: "session-peer",
|
|
9
|
+
method: "POST",
|
|
10
|
+
path: "/inbox",
|
|
11
|
+
authentication: "none",
|
|
12
|
+
description: "Accept an HMAC-authenticated durable Session delivery envelope from an explicitly configured tunnel peer.",
|
|
13
|
+
body: {
|
|
14
|
+
contentType: "application/json",
|
|
15
|
+
required: true,
|
|
16
|
+
schema: typebox.Type.Unknown()
|
|
17
|
+
},
|
|
18
|
+
responses: (0, _agimon_ai_doompi_core_api_contracts.jsonApiResponses)(typebox.Type.Object({
|
|
19
|
+
accepted: typebox.Type.Boolean(),
|
|
20
|
+
state: typebox.Type.String()
|
|
21
|
+
}))
|
|
22
|
+
}];
|
|
23
|
+
const apiContracts = (0, _agimon_ai_doompi_core_api_contracts.defineApiContract)({
|
|
24
|
+
version: 1,
|
|
25
|
+
http,
|
|
26
|
+
sockets: [],
|
|
27
|
+
dynamic: []
|
|
28
|
+
});
|
|
29
|
+
//#endregion
|
|
30
|
+
exports.apiContracts = apiContracts;
|
|
31
|
+
exports.default = apiContracts;
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=apiContracts.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.cjs","names":["Type","jsonApiResponses","defineApiContract"],"sources":["../../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses, type DoomHttpContract } from '@agimon-ai/doompi-core/api-contracts';\nimport { Type } from 'typebox';\n\n/** The endpoint validates its own HMAC peer credential because tunnel device authentication is intentionally bypassed. */\nconst http: DoomHttpContract[] = [\n {\n id: 'peer-inbox',\n scope: 'global',\n basePath: 'session-peer',\n method: 'POST',\n path: '/inbox',\n authentication: 'none',\n description:\n 'Accept an HMAC-authenticated durable Session delivery envelope from an explicitly configured tunnel peer.',\n body: { contentType: 'application/json', required: true, schema: Type.Unknown() },\n responses: jsonApiResponses(Type.Object({ accepted: Type.Boolean(), state: Type.String() })),\n },\n];\n\nexport const apiContracts = defineApiContract({ version: 1, http, sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;;AAIA,MAAM,OAA2B,CAC/B;CACE,IAAI;CACJ,OAAO;CACP,UAAU;CACV,QAAQ;CACR,MAAM;CACN,gBAAgB;CAChB,aACE;CACF,MAAM;EAAE,aAAa;EAAoB,UAAU;EAAM,QAAQA,QAAAA,KAAK,QAAQ;CAAE;CAChF,YAAA,GAAWC,qCAAAA,iBAAAA,CAAiBD,QAAAA,KAAK,OAAO;EAAE,UAAUA,QAAAA,KAAK,QAAQ;EAAG,OAAOA,QAAAA,KAAK,OAAO;CAAE,CAAC,CAAC;AAC7F,CACF;AAEA,MAAa,gBAAA,GAAeE,qCAAAA,kBAAAA,CAAkB;CAAE,SAAS;CAAG;CAAM,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/schemas/apiContracts.d.ts
|
|
2
|
+
export declare const apiContracts: {
|
|
3
|
+
version: 1;
|
|
4
|
+
protocols?: Record<string, string> | undefined;
|
|
5
|
+
schemas?: Record<string, boolean | object> | undefined;
|
|
6
|
+
http: {
|
|
7
|
+
id: string;
|
|
8
|
+
scope: "global" | "session" | "workspace";
|
|
9
|
+
basePath?: string | undefined;
|
|
10
|
+
path: string;
|
|
11
|
+
method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
|
|
12
|
+
description: string;
|
|
13
|
+
availability?: string | undefined;
|
|
14
|
+
authentication: "device" | "none" | "owner";
|
|
15
|
+
parameters?: {
|
|
16
|
+
name: string;
|
|
17
|
+
in: "header" | "path" | "query";
|
|
18
|
+
required: boolean;
|
|
19
|
+
schema: boolean | object;
|
|
20
|
+
}[] | undefined;
|
|
21
|
+
body?: {
|
|
22
|
+
contentType: string;
|
|
23
|
+
contentTypes?: string[] | undefined;
|
|
24
|
+
required: boolean;
|
|
25
|
+
schema: boolean | object;
|
|
26
|
+
} | undefined;
|
|
27
|
+
responses: Record<string, {
|
|
28
|
+
description: string;
|
|
29
|
+
contentType?: string | undefined;
|
|
30
|
+
schema?: boolean | object | undefined;
|
|
31
|
+
events?: Record<string, boolean | object> | undefined;
|
|
32
|
+
}>;
|
|
33
|
+
}[];
|
|
34
|
+
sockets: {
|
|
35
|
+
id: string;
|
|
36
|
+
scope: "global" | "session" | "workspace";
|
|
37
|
+
description: string;
|
|
38
|
+
availability?: string | undefined;
|
|
39
|
+
service: string;
|
|
40
|
+
member: string;
|
|
41
|
+
direction: "client-to-server" | "server-to-client";
|
|
42
|
+
kind: "channel" | "method" | "state";
|
|
43
|
+
input: boolean | object;
|
|
44
|
+
output?: boolean | object | undefined;
|
|
45
|
+
errors?: boolean | object | undefined;
|
|
46
|
+
}[];
|
|
47
|
+
dynamic: string[];
|
|
48
|
+
gaps?: string[] | undefined;
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { apiContracts as default };
|
|
52
|
+
//# sourceMappingURL=apiContracts.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.d.cts","names":[],"sources":["../../../src/schemas/apiContracts.ts"],"mappings":";qBAmBa"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/schemas/apiContracts.d.ts
|
|
2
|
+
export declare const apiContracts: {
|
|
3
|
+
version: 1;
|
|
4
|
+
protocols?: Record<string, string> | undefined;
|
|
5
|
+
schemas?: Record<string, boolean | object> | undefined;
|
|
6
|
+
http: {
|
|
7
|
+
id: string;
|
|
8
|
+
scope: "global" | "session" | "workspace";
|
|
9
|
+
basePath?: string | undefined;
|
|
10
|
+
path: string;
|
|
11
|
+
method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
|
|
12
|
+
description: string;
|
|
13
|
+
availability?: string | undefined;
|
|
14
|
+
authentication: "device" | "none" | "owner";
|
|
15
|
+
parameters?: {
|
|
16
|
+
name: string;
|
|
17
|
+
in: "header" | "path" | "query";
|
|
18
|
+
required: boolean;
|
|
19
|
+
schema: boolean | object;
|
|
20
|
+
}[] | undefined;
|
|
21
|
+
body?: {
|
|
22
|
+
contentType: string;
|
|
23
|
+
contentTypes?: string[] | undefined;
|
|
24
|
+
required: boolean;
|
|
25
|
+
schema: boolean | object;
|
|
26
|
+
} | undefined;
|
|
27
|
+
responses: Record<string, {
|
|
28
|
+
description: string;
|
|
29
|
+
contentType?: string | undefined;
|
|
30
|
+
schema?: boolean | object | undefined;
|
|
31
|
+
events?: Record<string, boolean | object> | undefined;
|
|
32
|
+
}>;
|
|
33
|
+
}[];
|
|
34
|
+
sockets: {
|
|
35
|
+
id: string;
|
|
36
|
+
scope: "global" | "session" | "workspace";
|
|
37
|
+
description: string;
|
|
38
|
+
availability?: string | undefined;
|
|
39
|
+
service: string;
|
|
40
|
+
member: string;
|
|
41
|
+
direction: "client-to-server" | "server-to-client";
|
|
42
|
+
kind: "channel" | "method" | "state";
|
|
43
|
+
input: boolean | object;
|
|
44
|
+
output?: boolean | object | undefined;
|
|
45
|
+
errors?: boolean | object | undefined;
|
|
46
|
+
}[];
|
|
47
|
+
dynamic: string[];
|
|
48
|
+
gaps?: string[] | undefined;
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { apiContracts as default };
|
|
52
|
+
//# sourceMappingURL=apiContracts.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../../../src/schemas/apiContracts.ts"],"mappings":";qBAmBa"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineApiContract, jsonApiResponses } from "@agimon-ai/doompi-core/api-contracts";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
//#region src/schemas/apiContracts.ts
|
|
4
|
+
/** The endpoint validates its own HMAC peer credential because tunnel device authentication is intentionally bypassed. */
|
|
5
|
+
const http = [{
|
|
6
|
+
id: "peer-inbox",
|
|
7
|
+
scope: "global",
|
|
8
|
+
basePath: "session-peer",
|
|
9
|
+
method: "POST",
|
|
10
|
+
path: "/inbox",
|
|
11
|
+
authentication: "none",
|
|
12
|
+
description: "Accept an HMAC-authenticated durable Session delivery envelope from an explicitly configured tunnel peer.",
|
|
13
|
+
body: {
|
|
14
|
+
contentType: "application/json",
|
|
15
|
+
required: true,
|
|
16
|
+
schema: Type.Unknown()
|
|
17
|
+
},
|
|
18
|
+
responses: jsonApiResponses(Type.Object({
|
|
19
|
+
accepted: Type.Boolean(),
|
|
20
|
+
state: Type.String()
|
|
21
|
+
}))
|
|
22
|
+
}];
|
|
23
|
+
const apiContracts = defineApiContract({
|
|
24
|
+
version: 1,
|
|
25
|
+
http,
|
|
26
|
+
sockets: [],
|
|
27
|
+
dynamic: []
|
|
28
|
+
});
|
|
29
|
+
//#endregion
|
|
30
|
+
export { apiContracts, apiContracts as default };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=apiContracts.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.mjs","names":[],"sources":["../../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses, type DoomHttpContract } from '@agimon-ai/doompi-core/api-contracts';\nimport { Type } from 'typebox';\n\n/** The endpoint validates its own HMAC peer credential because tunnel device authentication is intentionally bypassed. */\nconst http: DoomHttpContract[] = [\n {\n id: 'peer-inbox',\n scope: 'global',\n basePath: 'session-peer',\n method: 'POST',\n path: '/inbox',\n authentication: 'none',\n description:\n 'Accept an HMAC-authenticated durable Session delivery envelope from an explicitly configured tunnel peer.',\n body: { contentType: 'application/json', required: true, schema: Type.Unknown() },\n responses: jsonApiResponses(Type.Object({ accepted: Type.Boolean(), state: Type.String() })),\n },\n];\n\nexport const apiContracts = defineApiContract({ version: 1, http, sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;;AAIA,MAAM,OAA2B,CAC/B;CACE,IAAI;CACJ,OAAO;CACP,UAAU;CACV,QAAQ;CACR,MAAM;CACN,gBAAgB;CAChB,aACE;CACF,MAAM;EAAE,aAAa;EAAoB,UAAU;EAAM,QAAQ,KAAK,QAAQ;CAAE;CAChF,WAAW,iBAAiB,KAAK,OAAO;EAAE,UAAU,KAAK,QAAQ;EAAG,OAAO,KAAK,OAAO;CAAE,CAAC,CAAC;AAC7F,CACF;AAEA,MAAa,eAAe,kBAAkB;CAAE,SAAS;CAAG;CAAM,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
let _agimon_ai_doompi_core_background_work = require("@agimon-ai/doompi-core/background-work");
|
|
2
|
+
let typebox_value = require("typebox/value");
|
|
3
|
+
//#region src/services/backgroundWorkService/index.ts
|
|
4
|
+
/** Creates the generation-bound, pull-based coordinator shared by session extensions. */
|
|
5
|
+
function createBackgroundWorkService(ctx) {
|
|
6
|
+
const registrations = /* @__PURE__ */ new Map();
|
|
7
|
+
const generation = `doom-background-work:${crypto.randomUUID()}`;
|
|
8
|
+
const changed = (provider, providerGeneration, kind) => {
|
|
9
|
+
ctx.emit(_agimon_ai_doompi_core_background_work.DOOM_BACKGROUND_WORK_CHANGED_EVENT, {
|
|
10
|
+
provider,
|
|
11
|
+
generation: providerGeneration,
|
|
12
|
+
kind
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
generation,
|
|
17
|
+
register(provider) {
|
|
18
|
+
if (!provider || typeof provider !== "object" || typeof provider.listActiveWork !== "function") throw new TypeError("A background-work provider must expose listActiveWork().");
|
|
19
|
+
const name = provider.provider.trim();
|
|
20
|
+
if (!name || name !== provider.provider) throw new TypeError("A background-work provider requires a trimmed, non-empty name.");
|
|
21
|
+
const token = Symbol(name);
|
|
22
|
+
const providerGeneration = `${name}:${crypto.randomUUID()}`;
|
|
23
|
+
registrations.set(name, {
|
|
24
|
+
token,
|
|
25
|
+
generation: providerGeneration,
|
|
26
|
+
provider
|
|
27
|
+
});
|
|
28
|
+
changed(name, providerGeneration, "registered");
|
|
29
|
+
let disposed = false;
|
|
30
|
+
return Object.freeze({
|
|
31
|
+
provider: name,
|
|
32
|
+
generation: providerGeneration,
|
|
33
|
+
update() {
|
|
34
|
+
if (!disposed && registrations.get(name)?.token === token) changed(name, providerGeneration, "updated");
|
|
35
|
+
},
|
|
36
|
+
dispose() {
|
|
37
|
+
if (disposed) return;
|
|
38
|
+
disposed = true;
|
|
39
|
+
if (registrations.get(name)?.token !== token) return;
|
|
40
|
+
registrations.delete(name);
|
|
41
|
+
changed(name, providerGeneration, "unregistered");
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
snapshot(sessionId) {
|
|
46
|
+
const items = [];
|
|
47
|
+
const errors = [];
|
|
48
|
+
for (const [provider, registration] of registrations) try {
|
|
49
|
+
const current = registration.provider.listActiveWork();
|
|
50
|
+
if (!Array.isArray(current)) throw new TypeError("listActiveWork() must return an array.");
|
|
51
|
+
for (const item of current) {
|
|
52
|
+
if (!(0, typebox_value.Check)(_agimon_ai_doompi_core_background_work.BackgroundProviderWorkItemSchema, item)) throw new TypeError("listActiveWork() returned an invalid item.");
|
|
53
|
+
if (sessionId === void 0 || item.sessionId === sessionId) items.push({
|
|
54
|
+
provider,
|
|
55
|
+
...item
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
errors.push({
|
|
60
|
+
provider,
|
|
61
|
+
message: error instanceof Error ? error.message : String(error)
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
items: Object.freeze(items),
|
|
66
|
+
errors: Object.freeze(errors)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Installs one coordinator in the current session service context. */
|
|
72
|
+
function provideBackgroundWorkService(context) {
|
|
73
|
+
context.provide(_agimon_ai_doompi_core_background_work.DOOM_BACKGROUND_WORK_SERVICE, createBackgroundWorkService(context));
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
exports.createBackgroundWorkService = createBackgroundWorkService;
|
|
77
|
+
exports.provideBackgroundWorkService = provideBackgroundWorkService;
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["DOOM_BACKGROUND_WORK_CHANGED_EVENT","Check","BackgroundProviderWorkItemSchema","DOOM_BACKGROUND_WORK_SERVICE"],"sources":["../../../../src/services/backgroundWorkService/index.ts"],"sourcesContent":["import {\n BackgroundProviderWorkItemSchema,\n DOOM_BACKGROUND_WORK_CHANGED_EVENT,\n DOOM_BACKGROUND_WORK_SERVICE,\n type BackgroundWorkProvider,\n type BackgroundWorkProviderHandle,\n type DoomBackgroundWorkService,\n type DoomBackgroundWorkSnapshot,\n} from '@agimon-ai/doompi-core/background-work';\nimport type { Context } from '@deepseek-ai/cordis';\nimport { Check } from 'typebox/value';\n\ninterface ProviderRegistration {\n readonly token: symbol;\n readonly generation: string;\n readonly provider: BackgroundWorkProvider;\n}\n\n/** Creates the generation-bound, pull-based coordinator shared by session extensions. */\nexport function createBackgroundWorkService(ctx: Context): DoomBackgroundWorkService {\n const registrations = new Map<string, ProviderRegistration>();\n const generation = `doom-background-work:${crypto.randomUUID()}`;\n\n const changed = (\n provider: string,\n providerGeneration: string,\n kind: 'registered' | 'updated' | 'unregistered',\n ): void => {\n ctx.emit(DOOM_BACKGROUND_WORK_CHANGED_EVENT, { provider, generation: providerGeneration, kind });\n };\n\n const service: DoomBackgroundWorkService = {\n generation,\n register(provider): BackgroundWorkProviderHandle {\n if (!provider || typeof provider !== 'object' || typeof provider.listActiveWork !== 'function') {\n throw new TypeError('A background-work provider must expose listActiveWork().');\n }\n const name = provider.provider.trim();\n if (!name || name !== provider.provider) {\n throw new TypeError('A background-work provider requires a trimmed, non-empty name.');\n }\n const token = Symbol(name);\n const providerGeneration = `${name}:${crypto.randomUUID()}`;\n registrations.set(name, { token, generation: providerGeneration, provider });\n changed(name, providerGeneration, 'registered');\n let disposed = false;\n return Object.freeze({\n provider: name,\n generation: providerGeneration,\n update(): void {\n if (!disposed && registrations.get(name)?.token === token) {\n changed(name, providerGeneration, 'updated');\n }\n },\n dispose(): void {\n if (disposed) return;\n disposed = true;\n if (registrations.get(name)?.token !== token) return;\n registrations.delete(name);\n changed(name, providerGeneration, 'unregistered');\n },\n });\n },\n snapshot(sessionId?: string): DoomBackgroundWorkSnapshot {\n const items: DoomBackgroundWorkSnapshot['items'][number][] = [];\n const errors: DoomBackgroundWorkSnapshot['errors'][number][] = [];\n for (const [provider, registration] of registrations) {\n try {\n const current = registration.provider.listActiveWork();\n if (!Array.isArray(current)) throw new TypeError('listActiveWork() must return an array.');\n for (const item of current) {\n if (!Check(BackgroundProviderWorkItemSchema, item)) {\n throw new TypeError('listActiveWork() returned an invalid item.');\n }\n if (sessionId === undefined || item.sessionId === sessionId) items.push({ provider, ...item });\n }\n } catch (error) {\n errors.push({ provider, message: error instanceof Error ? error.message : String(error) });\n }\n }\n return Object.freeze({ items: Object.freeze(items), errors: Object.freeze(errors) });\n },\n };\n return Object.freeze(service);\n}\n\n/** Installs one coordinator in the current session service context. */\nexport function provideBackgroundWorkService(context: Context): void {\n context.provide(DOOM_BACKGROUND_WORK_SERVICE, createBackgroundWorkService(context));\n}\n"],"mappings":";;;;AAmBA,SAAgB,4BAA4B,KAAyC;CACnF,MAAM,gCAAgB,IAAI,IAAkC;CAC5D,MAAM,aAAa,wBAAwB,OAAO,WAAW;CAE7D,MAAM,WACJ,UACA,oBACA,SACS;EACT,IAAI,KAAKA,uCAAAA,oCAAoC;GAAE;GAAU,YAAY;GAAoB;EAAK,CAAC;CACjG;CAsDA,OAAO,OAAO,OAAO;EAnDnB;EACA,SAAS,UAAwC;GAC/C,IAAI,CAAC,YAAY,OAAO,aAAa,YAAY,OAAO,SAAS,mBAAmB,YAClF,MAAM,IAAI,UAAU,0DAA0D;GAEhF,MAAM,OAAO,SAAS,SAAS,KAAK;GACpC,IAAI,CAAC,QAAQ,SAAS,SAAS,UAC7B,MAAM,IAAI,UAAU,gEAAgE;GAEtF,MAAM,QAAQ,OAAO,IAAI;GACzB,MAAM,qBAAqB,GAAG,KAAK,GAAG,OAAO,WAAW;GACxD,cAAc,IAAI,MAAM;IAAE;IAAO,YAAY;IAAoB;GAAS,CAAC;GAC3E,QAAQ,MAAM,oBAAoB,YAAY;GAC9C,IAAI,WAAW;GACf,OAAO,OAAO,OAAO;IACnB,UAAU;IACV,YAAY;IACZ,SAAe;KACb,IAAI,CAAC,YAAY,cAAc,IAAI,IAAI,CAAC,EAAE,UAAU,OAClD,QAAQ,MAAM,oBAAoB,SAAS;IAE/C;IACA,UAAgB;KACd,IAAI,UAAU;KACd,WAAW;KACX,IAAI,cAAc,IAAI,IAAI,CAAC,EAAE,UAAU,OAAO;KAC9C,cAAc,OAAO,IAAI;KACzB,QAAQ,MAAM,oBAAoB,cAAc;IAClD;GACF,CAAC;EACH;EACA,SAAS,WAAgD;GACvD,MAAM,QAAuD,CAAC;GAC9D,MAAM,SAAyD,CAAC;GAChE,KAAK,MAAM,CAAC,UAAU,iBAAiB,eACrC,IAAI;IACF,MAAM,UAAU,aAAa,SAAS,eAAe;IACrD,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,MAAM,IAAI,UAAU,wCAAwC;IACzF,KAAK,MAAM,QAAQ,SAAS;KAC1B,IAAI,EAAA,GAACC,cAAAA,MAAAA,CAAMC,uCAAAA,kCAAkC,IAAI,GAC/C,MAAM,IAAI,UAAU,4CAA4C;KAElE,IAAI,cAAc,KAAA,KAAa,KAAK,cAAc,WAAW,MAAM,KAAK;MAAE;MAAU,GAAG;KAAK,CAAC;IAC/F;GACF,SAAS,OAAO;IACd,OAAO,KAAK;KAAE;KAAU,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAAE,CAAC;GAC3F;GAEF,OAAO,OAAO,OAAO;IAAE,OAAO,OAAO,OAAO,KAAK;IAAG,QAAQ,OAAO,OAAO,MAAM;GAAE,CAAC;EACrF;CAEyB,CAAC;AAC9B;;AAGA,SAAgB,6BAA6B,SAAwB;CACnE,QAAQ,QAAQC,uCAAAA,8BAA8B,4BAA4B,OAAO,CAAC;AACpF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DoomBackgroundWorkService } from "@agimon-ai/doompi-core/background-work";
|
|
2
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
//#region src/services/backgroundWorkService/index.d.ts
|
|
4
|
+
/** Creates the generation-bound, pull-based coordinator shared by session extensions. */
|
|
5
|
+
export declare function createBackgroundWorkService(ctx: Context): DoomBackgroundWorkService;
|
|
6
|
+
/** Installs one coordinator in the current session service context. */
|
|
7
|
+
export declare function provideBackgroundWorkService(context: Context): void;
|
|
8
|
+
//#endregion
|
|
9
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../../src/services/backgroundWorkService/index.ts"],"mappings":";;;;wBAmBgB,4BAA4B,KAAK,UAAU;;wBAoE3C,6BAA6B,SAAS"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DoomBackgroundWorkService } from "@agimon-ai/doompi-core/background-work";
|
|
2
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
//#region src/services/backgroundWorkService/index.d.ts
|
|
4
|
+
/** Creates the generation-bound, pull-based coordinator shared by session extensions. */
|
|
5
|
+
export declare function createBackgroundWorkService(ctx: Context): DoomBackgroundWorkService;
|
|
6
|
+
/** Installs one coordinator in the current session service context. */
|
|
7
|
+
export declare function provideBackgroundWorkService(context: Context): void;
|
|
8
|
+
//#endregion
|
|
9
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/services/backgroundWorkService/index.ts"],"mappings":";;;;wBAmBgB,4BAA4B,KAAK,UAAU;;wBAoE3C,6BAA6B,SAAS"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { BackgroundProviderWorkItemSchema, DOOM_BACKGROUND_WORK_CHANGED_EVENT, DOOM_BACKGROUND_WORK_SERVICE } from "@agimon-ai/doompi-core/background-work";
|
|
2
|
+
import { Check } from "typebox/value";
|
|
3
|
+
//#region src/services/backgroundWorkService/index.ts
|
|
4
|
+
/** Creates the generation-bound, pull-based coordinator shared by session extensions. */
|
|
5
|
+
function createBackgroundWorkService(ctx) {
|
|
6
|
+
const registrations = /* @__PURE__ */ new Map();
|
|
7
|
+
const generation = `doom-background-work:${crypto.randomUUID()}`;
|
|
8
|
+
const changed = (provider, providerGeneration, kind) => {
|
|
9
|
+
ctx.emit(DOOM_BACKGROUND_WORK_CHANGED_EVENT, {
|
|
10
|
+
provider,
|
|
11
|
+
generation: providerGeneration,
|
|
12
|
+
kind
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
generation,
|
|
17
|
+
register(provider) {
|
|
18
|
+
if (!provider || typeof provider !== "object" || typeof provider.listActiveWork !== "function") throw new TypeError("A background-work provider must expose listActiveWork().");
|
|
19
|
+
const name = provider.provider.trim();
|
|
20
|
+
if (!name || name !== provider.provider) throw new TypeError("A background-work provider requires a trimmed, non-empty name.");
|
|
21
|
+
const token = Symbol(name);
|
|
22
|
+
const providerGeneration = `${name}:${crypto.randomUUID()}`;
|
|
23
|
+
registrations.set(name, {
|
|
24
|
+
token,
|
|
25
|
+
generation: providerGeneration,
|
|
26
|
+
provider
|
|
27
|
+
});
|
|
28
|
+
changed(name, providerGeneration, "registered");
|
|
29
|
+
let disposed = false;
|
|
30
|
+
return Object.freeze({
|
|
31
|
+
provider: name,
|
|
32
|
+
generation: providerGeneration,
|
|
33
|
+
update() {
|
|
34
|
+
if (!disposed && registrations.get(name)?.token === token) changed(name, providerGeneration, "updated");
|
|
35
|
+
},
|
|
36
|
+
dispose() {
|
|
37
|
+
if (disposed) return;
|
|
38
|
+
disposed = true;
|
|
39
|
+
if (registrations.get(name)?.token !== token) return;
|
|
40
|
+
registrations.delete(name);
|
|
41
|
+
changed(name, providerGeneration, "unregistered");
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
snapshot(sessionId) {
|
|
46
|
+
const items = [];
|
|
47
|
+
const errors = [];
|
|
48
|
+
for (const [provider, registration] of registrations) try {
|
|
49
|
+
const current = registration.provider.listActiveWork();
|
|
50
|
+
if (!Array.isArray(current)) throw new TypeError("listActiveWork() must return an array.");
|
|
51
|
+
for (const item of current) {
|
|
52
|
+
if (!Check(BackgroundProviderWorkItemSchema, item)) throw new TypeError("listActiveWork() returned an invalid item.");
|
|
53
|
+
if (sessionId === void 0 || item.sessionId === sessionId) items.push({
|
|
54
|
+
provider,
|
|
55
|
+
...item
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
errors.push({
|
|
60
|
+
provider,
|
|
61
|
+
message: error instanceof Error ? error.message : String(error)
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
items: Object.freeze(items),
|
|
66
|
+
errors: Object.freeze(errors)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Installs one coordinator in the current session service context. */
|
|
72
|
+
function provideBackgroundWorkService(context) {
|
|
73
|
+
context.provide(DOOM_BACKGROUND_WORK_SERVICE, createBackgroundWorkService(context));
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { createBackgroundWorkService, provideBackgroundWorkService };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/backgroundWorkService/index.ts"],"sourcesContent":["import {\n BackgroundProviderWorkItemSchema,\n DOOM_BACKGROUND_WORK_CHANGED_EVENT,\n DOOM_BACKGROUND_WORK_SERVICE,\n type BackgroundWorkProvider,\n type BackgroundWorkProviderHandle,\n type DoomBackgroundWorkService,\n type DoomBackgroundWorkSnapshot,\n} from '@agimon-ai/doompi-core/background-work';\nimport type { Context } from '@deepseek-ai/cordis';\nimport { Check } from 'typebox/value';\n\ninterface ProviderRegistration {\n readonly token: symbol;\n readonly generation: string;\n readonly provider: BackgroundWorkProvider;\n}\n\n/** Creates the generation-bound, pull-based coordinator shared by session extensions. */\nexport function createBackgroundWorkService(ctx: Context): DoomBackgroundWorkService {\n const registrations = new Map<string, ProviderRegistration>();\n const generation = `doom-background-work:${crypto.randomUUID()}`;\n\n const changed = (\n provider: string,\n providerGeneration: string,\n kind: 'registered' | 'updated' | 'unregistered',\n ): void => {\n ctx.emit(DOOM_BACKGROUND_WORK_CHANGED_EVENT, { provider, generation: providerGeneration, kind });\n };\n\n const service: DoomBackgroundWorkService = {\n generation,\n register(provider): BackgroundWorkProviderHandle {\n if (!provider || typeof provider !== 'object' || typeof provider.listActiveWork !== 'function') {\n throw new TypeError('A background-work provider must expose listActiveWork().');\n }\n const name = provider.provider.trim();\n if (!name || name !== provider.provider) {\n throw new TypeError('A background-work provider requires a trimmed, non-empty name.');\n }\n const token = Symbol(name);\n const providerGeneration = `${name}:${crypto.randomUUID()}`;\n registrations.set(name, { token, generation: providerGeneration, provider });\n changed(name, providerGeneration, 'registered');\n let disposed = false;\n return Object.freeze({\n provider: name,\n generation: providerGeneration,\n update(): void {\n if (!disposed && registrations.get(name)?.token === token) {\n changed(name, providerGeneration, 'updated');\n }\n },\n dispose(): void {\n if (disposed) return;\n disposed = true;\n if (registrations.get(name)?.token !== token) return;\n registrations.delete(name);\n changed(name, providerGeneration, 'unregistered');\n },\n });\n },\n snapshot(sessionId?: string): DoomBackgroundWorkSnapshot {\n const items: DoomBackgroundWorkSnapshot['items'][number][] = [];\n const errors: DoomBackgroundWorkSnapshot['errors'][number][] = [];\n for (const [provider, registration] of registrations) {\n try {\n const current = registration.provider.listActiveWork();\n if (!Array.isArray(current)) throw new TypeError('listActiveWork() must return an array.');\n for (const item of current) {\n if (!Check(BackgroundProviderWorkItemSchema, item)) {\n throw new TypeError('listActiveWork() returned an invalid item.');\n }\n if (sessionId === undefined || item.sessionId === sessionId) items.push({ provider, ...item });\n }\n } catch (error) {\n errors.push({ provider, message: error instanceof Error ? error.message : String(error) });\n }\n }\n return Object.freeze({ items: Object.freeze(items), errors: Object.freeze(errors) });\n },\n };\n return Object.freeze(service);\n}\n\n/** Installs one coordinator in the current session service context. */\nexport function provideBackgroundWorkService(context: Context): void {\n context.provide(DOOM_BACKGROUND_WORK_SERVICE, createBackgroundWorkService(context));\n}\n"],"mappings":";;;;AAmBA,SAAgB,4BAA4B,KAAyC;CACnF,MAAM,gCAAgB,IAAI,IAAkC;CAC5D,MAAM,aAAa,wBAAwB,OAAO,WAAW;CAE7D,MAAM,WACJ,UACA,oBACA,SACS;EACT,IAAI,KAAK,oCAAoC;GAAE;GAAU,YAAY;GAAoB;EAAK,CAAC;CACjG;CAsDA,OAAO,OAAO,OAAO;EAnDnB;EACA,SAAS,UAAwC;GAC/C,IAAI,CAAC,YAAY,OAAO,aAAa,YAAY,OAAO,SAAS,mBAAmB,YAClF,MAAM,IAAI,UAAU,0DAA0D;GAEhF,MAAM,OAAO,SAAS,SAAS,KAAK;GACpC,IAAI,CAAC,QAAQ,SAAS,SAAS,UAC7B,MAAM,IAAI,UAAU,gEAAgE;GAEtF,MAAM,QAAQ,OAAO,IAAI;GACzB,MAAM,qBAAqB,GAAG,KAAK,GAAG,OAAO,WAAW;GACxD,cAAc,IAAI,MAAM;IAAE;IAAO,YAAY;IAAoB;GAAS,CAAC;GAC3E,QAAQ,MAAM,oBAAoB,YAAY;GAC9C,IAAI,WAAW;GACf,OAAO,OAAO,OAAO;IACnB,UAAU;IACV,YAAY;IACZ,SAAe;KACb,IAAI,CAAC,YAAY,cAAc,IAAI,IAAI,CAAC,EAAE,UAAU,OAClD,QAAQ,MAAM,oBAAoB,SAAS;IAE/C;IACA,UAAgB;KACd,IAAI,UAAU;KACd,WAAW;KACX,IAAI,cAAc,IAAI,IAAI,CAAC,EAAE,UAAU,OAAO;KAC9C,cAAc,OAAO,IAAI;KACzB,QAAQ,MAAM,oBAAoB,cAAc;IAClD;GACF,CAAC;EACH;EACA,SAAS,WAAgD;GACvD,MAAM,QAAuD,CAAC;GAC9D,MAAM,SAAyD,CAAC;GAChE,KAAK,MAAM,CAAC,UAAU,iBAAiB,eACrC,IAAI;IACF,MAAM,UAAU,aAAa,SAAS,eAAe;IACrD,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,MAAM,IAAI,UAAU,wCAAwC;IACzF,KAAK,MAAM,QAAQ,SAAS;KAC1B,IAAI,CAAC,MAAM,kCAAkC,IAAI,GAC/C,MAAM,IAAI,UAAU,4CAA4C;KAElE,IAAI,cAAc,KAAA,KAAa,KAAK,cAAc,WAAW,MAAM,KAAK;MAAE;MAAU,GAAG;KAAK,CAAC;IAC/F;GACF,SAAS,OAAO;IACd,OAAO,KAAK;KAAE;KAAU,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAAE,CAAC;GAC3F;GAEF,OAAO,OAAO,OAAO;IAAE,OAAO,OAAO,OAAO,KAAK;IAAG,QAAQ,OAAO,OAAO,MAAM;GAAE,CAAC;EACrF;CAEyB,CAAC;AAC9B;;AAGA,SAAgB,6BAA6B,SAAwB;CACnE,QAAQ,QAAQ,8BAA8B,4BAA4B,OAAO,CAAC;AACpF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/services/peerInbox/index.ts
|
|
2
|
+
const inboxes = /* @__PURE__ */ new Map();
|
|
3
|
+
/** Registers one live session-owned peer inbox. This registry is reachable only by the Session route. */
|
|
4
|
+
function registerSessionPeerInbox(sessionId, inbox) {
|
|
5
|
+
if (inboxes.has(sessionId)) throw new Error(`Session peer inbox '${sessionId}' is already registered.`);
|
|
6
|
+
inboxes.set(sessionId, inbox);
|
|
7
|
+
return () => {
|
|
8
|
+
if (inboxes.get(sessionId) === inbox) inboxes.delete(sessionId);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function deliverSessionPeerEnvelope(targetSessionId, sourceKey, type, payload) {
|
|
12
|
+
return inboxes.get(targetSessionId)?.(sourceKey, type, payload);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
exports.deliverSessionPeerEnvelope = deliverSessionPeerEnvelope;
|
|
16
|
+
exports.registerSessionPeerInbox = registerSessionPeerInbox;
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/services/peerInbox/index.ts"],"sourcesContent":["import type { DoomSessionDeliveryInboxState } from '../sessionDelivery';\n\nexport type SessionPeerInbox = (\n sourceKey: string,\n type: string,\n payload: unknown,\n) => DoomSessionDeliveryInboxState | undefined;\n\nconst inboxes = new Map<string, SessionPeerInbox>();\n\n/** Registers one live session-owned peer inbox. This registry is reachable only by the Session route. */\nexport function registerSessionPeerInbox(sessionId: string, inbox: SessionPeerInbox): () => void {\n if (inboxes.has(sessionId)) throw new Error(`Session peer inbox '${sessionId}' is already registered.`);\n inboxes.set(sessionId, inbox);\n return () => {\n if (inboxes.get(sessionId) === inbox) inboxes.delete(sessionId);\n };\n}\n\nexport function deliverSessionPeerEnvelope(\n targetSessionId: string,\n sourceKey: string,\n type: string,\n payload: unknown,\n): DoomSessionDeliveryInboxState | undefined {\n return inboxes.get(targetSessionId)?.(sourceKey, type, payload);\n}\n"],"mappings":";AAQA,MAAM,0BAAU,IAAI,IAA8B;;AAGlD,SAAgB,yBAAyB,WAAmB,OAAqC;CAC/F,IAAI,QAAQ,IAAI,SAAS,GAAG,MAAM,IAAI,MAAM,uBAAuB,UAAU,yBAAyB;CACtG,QAAQ,IAAI,WAAW,KAAK;CAC5B,aAAa;EACX,IAAI,QAAQ,IAAI,SAAS,MAAM,OAAO,QAAQ,OAAO,SAAS;CAChE;AACF;AAEA,SAAgB,2BACd,iBACA,WACA,MACA,SAC2C;CAC3C,OAAO,QAAQ,IAAI,eAAe,CAAC,GAAG,WAAW,MAAM,OAAO;AAChE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/services/peerInbox/index.ts
|
|
2
|
+
const inboxes = /* @__PURE__ */ new Map();
|
|
3
|
+
/** Registers one live session-owned peer inbox. This registry is reachable only by the Session route. */
|
|
4
|
+
function registerSessionPeerInbox(sessionId, inbox) {
|
|
5
|
+
if (inboxes.has(sessionId)) throw new Error(`Session peer inbox '${sessionId}' is already registered.`);
|
|
6
|
+
inboxes.set(sessionId, inbox);
|
|
7
|
+
return () => {
|
|
8
|
+
if (inboxes.get(sessionId) === inbox) inboxes.delete(sessionId);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function deliverSessionPeerEnvelope(targetSessionId, sourceKey, type, payload) {
|
|
12
|
+
return inboxes.get(targetSessionId)?.(sourceKey, type, payload);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { deliverSessionPeerEnvelope, registerSessionPeerInbox };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/peerInbox/index.ts"],"sourcesContent":["import type { DoomSessionDeliveryInboxState } from '../sessionDelivery';\n\nexport type SessionPeerInbox = (\n sourceKey: string,\n type: string,\n payload: unknown,\n) => DoomSessionDeliveryInboxState | undefined;\n\nconst inboxes = new Map<string, SessionPeerInbox>();\n\n/** Registers one live session-owned peer inbox. This registry is reachable only by the Session route. */\nexport function registerSessionPeerInbox(sessionId: string, inbox: SessionPeerInbox): () => void {\n if (inboxes.has(sessionId)) throw new Error(`Session peer inbox '${sessionId}' is already registered.`);\n inboxes.set(sessionId, inbox);\n return () => {\n if (inboxes.get(sessionId) === inbox) inboxes.delete(sessionId);\n };\n}\n\nexport function deliverSessionPeerEnvelope(\n targetSessionId: string,\n sourceKey: string,\n type: string,\n payload: unknown,\n): DoomSessionDeliveryInboxState | undefined {\n return inboxes.get(targetSessionId)?.(sourceKey, type, payload);\n}\n"],"mappings":";AAQA,MAAM,0BAAU,IAAI,IAA8B;;AAGlD,SAAgB,yBAAyB,WAAmB,OAAqC;CAC/F,IAAI,QAAQ,IAAI,SAAS,GAAG,MAAM,IAAI,MAAM,uBAAuB,UAAU,yBAAyB;CACtG,QAAQ,IAAI,WAAW,KAAK;CAC5B,aAAa;EACX,IAAI,QAAQ,IAAI,SAAS,MAAM,OAAO,QAAQ,OAAO,SAAS;CAChE;AACF;AAEA,SAAgB,2BACd,iBACA,WACA,MACA,SAC2C;CAC3C,OAAO,QAAQ,IAAI,eAAe,CAAC,GAAG,WAAW,MAAM,OAAO;AAChE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const require_index = require("../peerTransport/index.cjs");
|
|
2
|
+
const require_index$1 = require("../peerInbox/index.cjs");
|
|
3
|
+
//#region src/services/peerInboxApi/index.ts
|
|
4
|
+
const MAX_BODY_BYTES = 65536;
|
|
5
|
+
const DELIVERY_TYPES = /* @__PURE__ */ new Set(["doom/session-delivery/envelope", "doom/session-delivery/ack"]);
|
|
6
|
+
function response(status, error) {
|
|
7
|
+
return Response.json({ error }, { status });
|
|
8
|
+
}
|
|
9
|
+
/** Narrow HMAC-authenticated endpoint that a trusted tunnel may forward without device authentication. */
|
|
10
|
+
const peerInboxApi = {
|
|
11
|
+
basePath: "session-peer",
|
|
12
|
+
start(context) {
|
|
13
|
+
const config = context.homeDirectory === void 0 ? void 0 : require_index.readSessionPeerConfig(context.homeDirectory);
|
|
14
|
+
const replay = context.homeDirectory === void 0 ? void 0 : require_index.createPeerReplayGuard(context.homeDirectory);
|
|
15
|
+
return {
|
|
16
|
+
async fetch(request) {
|
|
17
|
+
if (request.method !== "POST" || new URL(request.url).pathname !== "/inbox") return response(404, "Not found.");
|
|
18
|
+
if (!config) return response(503, "Paired Session delivery is not configured.");
|
|
19
|
+
const length = request.headers.get("content-length");
|
|
20
|
+
if (length !== null && (!/^\d+$/u.test(length) || Number(length) > MAX_BODY_BYTES)) return response(413, "Request body is too large.");
|
|
21
|
+
const body = await request.text();
|
|
22
|
+
if (Buffer.byteLength(body) > MAX_BODY_BYTES) return response(413, "Request body is too large.");
|
|
23
|
+
const peer = require_index.verifyPeerRequest(config, request, body);
|
|
24
|
+
if (!peer) return response(401, "Paired Session request is unauthorized.");
|
|
25
|
+
if (!replay?.admit(request)) return response(409, "Paired Session request was already received.");
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
parsed = JSON.parse(body);
|
|
29
|
+
} catch {
|
|
30
|
+
return response(400, "Paired Session request is malformed.");
|
|
31
|
+
}
|
|
32
|
+
const envelope = require_index.parseSessionPeerEnvelope(parsed);
|
|
33
|
+
if (!envelope || !DELIVERY_TYPES.has(envelope.type)) return response(400, "Paired Session envelope is invalid.");
|
|
34
|
+
if (!peer.allowedSessionIds.includes(envelope.targetSessionId)) return response(403, "Peer is not granted this session.");
|
|
35
|
+
const state = require_index$1.deliverSessionPeerEnvelope(envelope.targetSessionId, require_index.peerSessionReference(peer.hostId, envelope.sourceSessionId), envelope.type, envelope.payload);
|
|
36
|
+
return state === void 0 ? response(404, "Target Session is unavailable.") : Response.json({
|
|
37
|
+
accepted: true,
|
|
38
|
+
state
|
|
39
|
+
}, { status: 202 });
|
|
40
|
+
},
|
|
41
|
+
close: () => replay?.close()
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
exports.peerInboxApi = peerInboxApi;
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["readSessionPeerConfig","createPeerReplayGuard","verifyPeerRequest","parseSessionPeerEnvelope","deliverSessionPeerEnvelope","peerSessionReference"],"sources":["../../../../src/services/peerInboxApi/index.ts"],"sourcesContent":["import type { DoomApi, DoomApiHandler } from '@agimon-ai/doompi-core/package-api';\n\nimport { deliverSessionPeerEnvelope } from '../peerInbox';\nimport {\n createPeerReplayGuard,\n parseSessionPeerEnvelope,\n peerSessionReference,\n readSessionPeerConfig,\n verifyPeerRequest,\n} from '../peerTransport';\n\nconst MAX_BODY_BYTES = 64 * 1024;\nconst DELIVERY_TYPES = new Set(['doom/session-delivery/envelope', 'doom/session-delivery/ack']);\n\nfunction response(status: number, error: string): Response {\n return Response.json({ error }, { status });\n}\n\n/** Narrow HMAC-authenticated endpoint that a trusted tunnel may forward without device authentication. */\nexport const peerInboxApi: DoomApi = {\n basePath: 'session-peer',\n start(context): DoomApiHandler {\n const config = context.homeDirectory === undefined ? undefined : readSessionPeerConfig(context.homeDirectory);\n const replay = context.homeDirectory === undefined ? undefined : createPeerReplayGuard(context.homeDirectory);\n return {\n async fetch(request) {\n if (request.method !== 'POST' || new URL(request.url).pathname !== '/inbox') return response(404, 'Not found.');\n if (!config) return response(503, 'Paired Session delivery is not configured.');\n const length = request.headers.get('content-length');\n if (length !== null && (!/^\\d+$/u.test(length) || Number(length) > MAX_BODY_BYTES))\n return response(413, 'Request body is too large.');\n const body = await request.text();\n if (Buffer.byteLength(body) > MAX_BODY_BYTES) return response(413, 'Request body is too large.');\n const peer = verifyPeerRequest(config, request, body);\n if (!peer) return response(401, 'Paired Session request is unauthorized.');\n if (!replay?.admit(request)) return response(409, 'Paired Session request was already received.');\n let parsed: unknown;\n try {\n parsed = JSON.parse(body) as unknown;\n } catch {\n return response(400, 'Paired Session request is malformed.');\n }\n const envelope = parseSessionPeerEnvelope(parsed);\n if (!envelope || !DELIVERY_TYPES.has(envelope.type))\n return response(400, 'Paired Session envelope is invalid.');\n if (!peer.allowedSessionIds.includes(envelope.targetSessionId))\n return response(403, 'Peer is not granted this session.');\n const state = deliverSessionPeerEnvelope(\n envelope.targetSessionId,\n peerSessionReference(peer.hostId, envelope.sourceSessionId),\n envelope.type,\n envelope.payload,\n );\n return state === undefined\n ? response(404, 'Target Session is unavailable.')\n : Response.json({ accepted: true, state }, { status: 202 });\n },\n close: () => replay?.close(),\n };\n },\n};\n"],"mappings":";;;AAWA,MAAM,iBAAiB;AACvB,MAAM,iCAAiB,IAAI,IAAI,CAAC,kCAAkC,2BAA2B,CAAC;AAE9F,SAAS,SAAS,QAAgB,OAAyB;CACzD,OAAO,SAAS,KAAK,EAAE,MAAM,GAAG,EAAE,OAAO,CAAC;AAC5C;;AAGA,MAAa,eAAwB;CACnC,UAAU;CACV,MAAM,SAAyB;EAC7B,MAAM,SAAS,QAAQ,kBAAkB,KAAA,IAAY,KAAA,IAAYA,cAAAA,sBAAsB,QAAQ,aAAa;EAC5G,MAAM,SAAS,QAAQ,kBAAkB,KAAA,IAAY,KAAA,IAAYC,cAAAA,sBAAsB,QAAQ,aAAa;EAC5G,OAAO;GACL,MAAM,MAAM,SAAS;IACnB,IAAI,QAAQ,WAAW,UAAU,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,aAAa,UAAU,OAAO,SAAS,KAAK,YAAY;IAC9G,IAAI,CAAC,QAAQ,OAAO,SAAS,KAAK,4CAA4C;IAC9E,MAAM,SAAS,QAAQ,QAAQ,IAAI,gBAAgB;IACnD,IAAI,WAAW,SAAS,CAAC,SAAS,KAAK,MAAM,KAAK,OAAO,MAAM,IAAI,iBACjE,OAAO,SAAS,KAAK,4BAA4B;IACnD,MAAM,OAAO,MAAM,QAAQ,KAAK;IAChC,IAAI,OAAO,WAAW,IAAI,IAAI,gBAAgB,OAAO,SAAS,KAAK,4BAA4B;IAC/F,MAAM,OAAOC,cAAAA,kBAAkB,QAAQ,SAAS,IAAI;IACpD,IAAI,CAAC,MAAM,OAAO,SAAS,KAAK,yCAAyC;IACzE,IAAI,CAAC,QAAQ,MAAM,OAAO,GAAG,OAAO,SAAS,KAAK,8CAA8C;IAChG,IAAI;IACJ,IAAI;KACF,SAAS,KAAK,MAAM,IAAI;IAC1B,QAAQ;KACN,OAAO,SAAS,KAAK,sCAAsC;IAC7D;IACA,MAAM,WAAWC,cAAAA,yBAAyB,MAAM;IAChD,IAAI,CAAC,YAAY,CAAC,eAAe,IAAI,SAAS,IAAI,GAChD,OAAO,SAAS,KAAK,qCAAqC;IAC5D,IAAI,CAAC,KAAK,kBAAkB,SAAS,SAAS,eAAe,GAC3D,OAAO,SAAS,KAAK,mCAAmC;IAC1D,MAAM,QAAQC,gBAAAA,2BACZ,SAAS,iBACTC,cAAAA,qBAAqB,KAAK,QAAQ,SAAS,eAAe,GAC1D,SAAS,MACT,SAAS,OACX;IACA,OAAO,UAAU,KAAA,IACb,SAAS,KAAK,gCAAgC,IAC9C,SAAS,KAAK;KAAE,UAAU;KAAM;IAAM,GAAG,EAAE,QAAQ,IAAI,CAAC;GAC9D;GACA,aAAa,QAAQ,MAAM;EAC7B;CACF;AACF"}
|