@undefineds.co/xpod 0.3.66 → 0.3.68
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/config/components-ignore.json +1 -0
- package/dist/api/ApiServer.d.ts +9 -1
- package/dist/api/ApiServer.js +22 -1
- package/dist/api/ApiServer.js.map +1 -1
- package/dist/api/container/routes.js +13 -0
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/handlers/DeviceNotificationRuntime.d.ts +26 -0
- package/dist/api/handlers/DeviceNotificationRuntime.js +77 -0
- package/dist/api/handlers/DeviceNotificationRuntime.js.map +1 -0
- package/dist/api/handlers/DeviceNotificationTicketHandler.d.ts +50 -0
- package/dist/api/handlers/DeviceNotificationTicketHandler.js +130 -0
- package/dist/api/handlers/DeviceNotificationTicketHandler.js.map +1 -0
- package/dist/api/handlers/DeviceNotificationTicketHandler.jsonld +117 -0
- package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
- package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
- package/dist/components/components.jsonld +6 -1
- package/dist/components/context.jsonld +122 -0
- package/dist/http/DeviceNotificationWebSocketServer.d.ts +29 -0
- package/dist/http/DeviceNotificationWebSocketServer.js +138 -0
- package/dist/http/DeviceNotificationWebSocketServer.js.map +1 -0
- package/dist/http/DeviceNotificationWebSocketServer.jsonld +148 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/notifications/DeviceNotificationHub.d.ts +74 -0
- package/dist/notifications/DeviceNotificationHub.js +313 -0
- package/dist/notifications/DeviceNotificationHub.js.map +1 -0
- package/dist/notifications/DeviceNotificationHub.jsonld +258 -0
- package/dist/notifications/DeviceNotificationResourceListener.d.ts +21 -0
- package/dist/notifications/DeviceNotificationResourceListener.js +38 -0
- package/dist/notifications/DeviceNotificationResourceListener.js.map +1 -0
- package/dist/notifications/DeviceNotificationResourceListener.jsonld +98 -0
- package/dist/notifications/device-notification-protocol.d.ts +56 -0
- package/dist/notifications/device-notification-protocol.js +127 -0
- package/dist/notifications/device-notification-protocol.js.map +1 -0
- package/dist/notifications/device-notification-protocol.jsonld +29 -0
- package/dist/notifications/index.d.ts +3 -0
- package/dist/notifications/index.js +20 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/storage/ObservableResourceStore.d.ts +3 -0
- package/dist/storage/ObservableResourceStore.js +17 -1
- package/dist/storage/ObservableResourceStore.js.map +1 -1
- package/package.json +1 -1
package/dist/api/ApiServer.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { type Server, type ServerResponse } from 'node:http';
|
|
1
|
+
import { type Server, type IncomingMessage, type ServerResponse } from 'node:http';
|
|
2
2
|
import type { AddressInfo } from 'node:net';
|
|
3
|
+
import type { Duplex } from 'node:stream';
|
|
3
4
|
import type { AuthMiddleware, AuthenticatedRequest } from './middleware/AuthMiddleware';
|
|
4
5
|
import type { RuntimeHost, RuntimeListenEndpoint } from '../runtime/host/types';
|
|
5
6
|
/**
|
|
@@ -30,6 +31,7 @@ export interface ApiServerOptions {
|
|
|
30
31
|
authMiddleware: AuthMiddleware;
|
|
31
32
|
corsOrigins?: string[];
|
|
32
33
|
}
|
|
34
|
+
export type UpgradeHandler = (request: IncomingMessage, socket: Duplex, head: Buffer) => void;
|
|
33
35
|
/**
|
|
34
36
|
* Standalone API Server
|
|
35
37
|
*/
|
|
@@ -40,6 +42,9 @@ export declare class ApiServer {
|
|
|
40
42
|
private readonly authMiddleware;
|
|
41
43
|
private readonly corsOrigins;
|
|
42
44
|
private readonly routes;
|
|
45
|
+
private readonly upgradeHandlers;
|
|
46
|
+
private readonly shutdownHandlers;
|
|
47
|
+
private responseHeaders;
|
|
43
48
|
private server?;
|
|
44
49
|
constructor(options: ApiServerOptions);
|
|
45
50
|
/**
|
|
@@ -80,6 +85,9 @@ export declare class ApiServer {
|
|
|
80
85
|
public?: boolean;
|
|
81
86
|
optionalAuth?: boolean;
|
|
82
87
|
}): void;
|
|
88
|
+
addUpgradeHandler(handler: UpgradeHandler): void;
|
|
89
|
+
addShutdownHandler(handler: () => void | Promise<void>): void;
|
|
90
|
+
addResponseHeaders(headers: Record<string, string>): void;
|
|
83
91
|
/**
|
|
84
92
|
* Start the server
|
|
85
93
|
*/
|
package/dist/api/ApiServer.js
CHANGED
|
@@ -11,6 +11,9 @@ class ApiServer {
|
|
|
11
11
|
constructor(options) {
|
|
12
12
|
this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
|
|
13
13
|
this.routes = [];
|
|
14
|
+
this.upgradeHandlers = [];
|
|
15
|
+
this.shutdownHandlers = [];
|
|
16
|
+
this.responseHeaders = {};
|
|
14
17
|
this.runtimeHost = options.runtimeHost ?? NodeRuntimeHost_1.nodeRuntimeHost;
|
|
15
18
|
this.listenEndpoint = options.listenEndpoint ?? this.runtimeHost.createListenEndpoint({
|
|
16
19
|
port: options.port,
|
|
@@ -57,6 +60,18 @@ class ApiServer {
|
|
|
57
60
|
all(path, handler, options) {
|
|
58
61
|
this.route('ALL', path, handler, { ...options, allMethods: true });
|
|
59
62
|
}
|
|
63
|
+
addUpgradeHandler(handler) {
|
|
64
|
+
this.upgradeHandlers.push(handler);
|
|
65
|
+
if (this.server) {
|
|
66
|
+
this.server.on('upgrade', handler);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
addShutdownHandler(handler) {
|
|
70
|
+
this.shutdownHandlers.push(handler);
|
|
71
|
+
}
|
|
72
|
+
addResponseHeaders(headers) {
|
|
73
|
+
this.responseHeaders = { ...this.responseHeaders, ...headers };
|
|
74
|
+
}
|
|
60
75
|
/**
|
|
61
76
|
* Start the server
|
|
62
77
|
*/
|
|
@@ -72,6 +87,9 @@ class ApiServer {
|
|
|
72
87
|
}
|
|
73
88
|
});
|
|
74
89
|
});
|
|
90
|
+
for (const handler of this.upgradeHandlers) {
|
|
91
|
+
this.server.on('upgrade', handler);
|
|
92
|
+
}
|
|
75
93
|
this.runtimeHost.listen(this.server, this.listenEndpoint).then(() => {
|
|
76
94
|
this.logger.info(`API Server listening on ${this.runtimeHost.formatListenEndpoint(this.listenEndpoint)}`);
|
|
77
95
|
resolve();
|
|
@@ -87,7 +105,7 @@ class ApiServer {
|
|
|
87
105
|
resolve();
|
|
88
106
|
return;
|
|
89
107
|
}
|
|
90
|
-
this.runtimeHost.close(this.server, this.listenEndpoint).then(() => {
|
|
108
|
+
Promise.all(this.shutdownHandlers.map(async (handler) => handler())).then(() => this.runtimeHost.close(this.server, this.listenEndpoint)).then(() => {
|
|
91
109
|
this.logger.info('API Server stopped');
|
|
92
110
|
resolve();
|
|
93
111
|
}, reject);
|
|
@@ -115,6 +133,9 @@ class ApiServer {
|
|
|
115
133
|
}
|
|
116
134
|
// Add CORS headers
|
|
117
135
|
this.handleCors(request, response);
|
|
136
|
+
for (const [name, value] of Object.entries(this.responseHeaders)) {
|
|
137
|
+
response.setHeader(name, value);
|
|
138
|
+
}
|
|
118
139
|
// Find matching route
|
|
119
140
|
const match = this.findRoute(method, path);
|
|
120
141
|
if (!match) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiServer.js","sourceRoot":"","sources":["../../src/api/ApiServer.ts"],"names":[],"mappings":";;;AAAA,yCAAiG;AAEjG,iEAAqD;AAErD,0EAAuE;AAsCvE;;GAEG;AACH,MAAa,SAAS;IASpB,YAAmB,OAAyB;QAR3B,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAK5B,WAAM,GAAY,EAAE,CAAC;QAIpC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,iCAAe,CAAC;QAC1D,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC;YACpF,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACI,KAAK,CACV,MAAc,EACd,IAAY,EACZ,OAAqB,EACrB,OAOC;QAED,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YACf,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE;YAC5B,OAAO;YACP,UAAU;YACV,OAAO;YACP,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,YAAY,EAAE,OAAO,EAAE,YAAY;YACnC,UAAU,EAAE,OAAO,EAAE,UAAU;SAChC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChK,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,IAAY,EAAE,OAAqB,EAAE,OAAsD;QACpG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAEM,IAAI,CAAC,IAAY,EAAE,OAAqB,EAAE,OAAsD;QACrG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAEM,GAAG,CAAC,IAAY,EAAE,OAAqB,EAAE,OAAsD;QACpG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAEM,MAAM,CAAC,IAAY,EAAE,OAAqB,EAAE,OAAsD;QACvG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAEM,KAAK,CAAC,IAAY,EAAE,OAAqB,EAAE,OAAsD;QACtG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAEM,GAAG,CAAC,IAAY,EAAE,OAAqB,EAAE,OAAsD;QACpG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,KAAK;QAChB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,MAAM,GAAG,IAAA,wBAAY,EAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;gBACtC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBAC3C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,KAAK,EAAE,CAAC,CAAC;oBAC/C,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;wBACrB,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;wBACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;wBAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC;oBAC9D,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBAClE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;gBAC1G,OAAO,EAAE,CAAC;YACZ,CAAC,EAAE,MAAM,CAAC,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,IAAI;QACf,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,OAAO,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC/D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;gBACvC,OAAO,EAAE,CAAC;YACd,CAAC,EAAE,MAAM,CAAC,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACI,aAAa;QAClB,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC;IACxC,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,OAAwB,EAAE,QAAwB;QAC5E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,KAAK,CAAC;QACtD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC,CAAC;QACzF,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;QAE1B,wBAAwB;QACxB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACnC,QAAQ,CAAC,UAAU,GAAG,GAAG,CAAC;YAC1B,QAAQ,CAAC,GAAG,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,mBAAmB;QACnB,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEnC,sBAAsB;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,QAAQ,CAAC,UAAU,GAAG,GAAG,CAAC;YAC1B,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;YACvD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;QAChC,MAAM,WAAW,GAAG,OAA+B,CAAC;QAEpD,0EAA0E;QAC1E,2EAA2E;QAC3E,IAAI,KAAK,CAAC,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YACxE,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YACxE,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;QACH,CAAC;QAED,kBAAkB;QAClB,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC;YACnD,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;gBAC1B,QAAQ,CAAC,UAAU,GAAG,GAAG,CAAC;gBAC1B,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;gBACvD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,MAAc,EAAE,IAAY;QAC5C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBACjD,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,MAAM,GAA2B,EAAE,CAAC;gBAC1C,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;oBACvC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;gBAClC,CAAC,CAAC,CAAC;gBACH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,WAAW,CAAC,IAAY;QAC9B,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,IAAI,QAAQ,GAAG,IAAI;YACjB,8BAA8B;aAC7B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;YACzC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,UAAU,CAAC,CAAC;YACpC,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;YACF,yBAAyB;aACxB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;YACxC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC;aACD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACzB,OAAO;YACL,OAAO,EAAE,IAAI,MAAM,CAAC,IAAI,QAAQ,GAAG,CAAC;YACpC,UAAU;SACX,CAAC;IACJ,CAAC;IAEO,UAAU,CAAC,OAAwB,EAAE,QAAwB;QACnE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;QAEtC,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,QAAQ,CAAC,SAAS,CAAC,6BAA6B,EAAE,MAAM,IAAI,GAAG,CAAC,CAAC;YACjE,IAAI,MAAM,EAAE,CAAC;gBACX,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACvD,QAAQ,CAAC,SAAS,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YAC1D,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;QAED,QAAQ,CAAC,SAAS,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAC;QAC/D,QAAQ,CAAC,SAAS,CAAC,8BAA8B,EAAE,wCAAwC,CAAC,CAAC;QAC7F,QAAQ,CAAC,SAAS,CAChB,8BAA8B,EAC9B;YACE,eAAe;YACf,cAAc;YACd,QAAQ;YACR,MAAM;YACN,QAAQ;YACR,kBAAkB;YAClB,UAAU;YACV,eAAe;YACf,MAAM;YACN,MAAM;SACP,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,QAAQ,CAAC,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;CACF;AA5PD,8BA4PC","sourcesContent":["import { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { AuthMiddleware, AuthenticatedRequest } from './middleware/AuthMiddleware';\nimport { nodeRuntimeHost } from '../runtime/host/node/NodeRuntimeHost';\nimport type { RuntimeHost, RuntimeListenEndpoint } from '../runtime/host/types';\n\n/**\n * Route handler function\n */\nexport type RouteHandler = (\n request: AuthenticatedRequest,\n response: ServerResponse,\n params: Record<string, string>,\n) => Promise<void>;\n\n/**\n * Route definition\n */\nexport interface Route {\n method: string;\n pattern: RegExp;\n paramNames: string[];\n handler: RouteHandler;\n /** If true, skip authentication */\n public?: boolean;\n /** If true, authenticate when credentials are present, otherwise continue unauthenticated */\n optionalAuth?: boolean;\n /** If true, match all methods instead of one method. */\n allMethods?: boolean;\n}\n\nexport interface ApiServerOptions {\n port?: number;\n host?: string;\n socketPath?: string;\n listenEndpoint?: RuntimeListenEndpoint;\n runtimeHost?: RuntimeHost;\n authMiddleware: AuthMiddleware;\n corsOrigins?: string[];\n}\n\n/**\n * Standalone API Server\n */\nexport class ApiServer {\n private readonly logger = getLoggerFor(this);\n private readonly runtimeHost: RuntimeHost;\n private readonly listenEndpoint: RuntimeListenEndpoint;\n private readonly authMiddleware: AuthMiddleware;\n private readonly corsOrigins: string[];\n private readonly routes: Route[] = [];\n private server?: Server;\n\n public constructor(options: ApiServerOptions) {\n this.runtimeHost = options.runtimeHost ?? nodeRuntimeHost;\n this.listenEndpoint = options.listenEndpoint ?? this.runtimeHost.createListenEndpoint({\n port: options.port,\n host: options.host,\n socketPath: options.socketPath,\n });\n this.authMiddleware = options.authMiddleware;\n this.corsOrigins = options.corsOrigins ?? ['*'];\n }\n\n /**\n * Register a route\n */\n public route(\n method: string,\n path: string,\n handler: RouteHandler,\n options?: {\n /** If true, skip authentication for this route */\n public?: boolean;\n /** If true, authenticate when credentials are present, otherwise continue unauthenticated */\n optionalAuth?: boolean;\n /** If true, match all methods instead of one method */\n allMethods?: boolean;\n },\n ): void {\n const { pattern, paramNames } = this.pathToRegex(path);\n this.routes.push({\n method: method.toUpperCase(),\n pattern,\n paramNames,\n handler,\n public: options?.public,\n optionalAuth: options?.optionalAuth,\n allMethods: options?.allMethods,\n });\n this.logger.debug(`Registered route: ${method.toUpperCase()} ${path}${options?.public ? ' (public)' : ''}${options?.optionalAuth ? ' (optional auth)' : ''}`);\n }\n\n /**\n * Convenience methods for common HTTP methods\n */\n public get(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('GET', path, handler, options);\n }\n\n public post(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('POST', path, handler, options);\n }\n\n public put(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('PUT', path, handler, options);\n }\n\n public delete(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('DELETE', path, handler, options);\n }\n\n public patch(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('PATCH', path, handler, options);\n }\n\n public all(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('ALL', path, handler, { ...options, allMethods: true });\n }\n\n /**\n * Start the server\n */\n public async start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.server = createServer((req, res) => {\n this.handleRequest(req, res).catch((error) => {\n this.logger.error(`Unhandled error: ${error}`);\n if (!res.headersSent) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Internal Server Error' }));\n }\n });\n });\n\n this.runtimeHost.listen(this.server, this.listenEndpoint).then(() => {\n this.logger.info(`API Server listening on ${this.runtimeHost.formatListenEndpoint(this.listenEndpoint)}`);\n resolve();\n }, reject);\n });\n }\n\n /**\n * Stop the server\n */\n public async stop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.server) {\n resolve();\n return;\n }\n\n this.runtimeHost.close(this.server, this.listenEndpoint).then(() => {\n this.logger.info('API Server stopped');\n resolve();\n }, reject);\n });\n }\n\n /**\n * Get the underlying HTTP server (for WebSocket upgrade)\n */\n public getHttpServer(): Server | undefined {\n return this.server;\n }\n\n public address(): AddressInfo | string | null {\n return this.server?.address() ?? null;\n }\n\n private async handleRequest(request: IncomingMessage, response: ServerResponse): Promise<void> {\n const method = request.method?.toUpperCase() ?? 'GET';\n const url = new URL(request.url ?? '/', `http://${request.headers.host ?? 'localhost'}`);\n const path = url.pathname;\n\n // Handle CORS preflight\n if (method === 'OPTIONS') {\n this.handleCors(request, response);\n response.statusCode = 204;\n response.end();\n return;\n }\n\n // Add CORS headers\n this.handleCors(request, response);\n\n // Find matching route\n const match = this.findRoute(method, path);\n if (!match) {\n response.statusCode = 404;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify({ error: 'Not Found' }));\n return;\n }\n\n const { route, params } = match;\n const authRequest = request as AuthenticatedRequest;\n\n // Run auth middleware unless route is public. Optional-auth routes accept\n // anonymous callers but still hydrate request.auth when credentials exist.\n if (route.optionalAuth && request.headers.authorization) {\n const authOk = await this.authMiddleware.process(authRequest, response);\n if (!authOk) {\n return;\n }\n } else if (!route.public && !route.optionalAuth) {\n const authOk = await this.authMiddleware.process(authRequest, response);\n if (!authOk) {\n return;\n }\n }\n\n // Execute handler\n try {\n await route.handler(authRequest, response, params);\n } catch (error) {\n this.logger.error(`Route handler error: ${error}`);\n if (!response.headersSent) {\n response.statusCode = 500;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify({ error: 'Internal Server Error' }));\n }\n }\n }\n\n private findRoute(method: string, path: string): { route: Route; params: Record<string, string> } | undefined {\n for (const route of this.routes) {\n if (!route.allMethods && route.method !== method) {\n continue;\n }\n\n const match = route.pattern.exec(path);\n if (match) {\n const params: Record<string, string> = {};\n route.paramNames.forEach((name, index) => {\n params[name] = match[index + 1];\n });\n return { route, params };\n }\n }\n return undefined;\n }\n\n private pathToRegex(path: string): { pattern: RegExp; paramNames: string[] } {\n const paramNames: string[] = [];\n let regexStr = path\n // 先处理通配符 *path 或 * (匹配剩余所有路径)\n .replace(/\\*([a-zA-Z0-9_]*)/g, (_, name) => {\n paramNames.push(name || 'wildcard');\n return '(.*)';\n })\n // 再处理普通参数 :param (只匹配单段)\n .replace(/:([a-zA-Z0-9_]+)/g, (_, name) => {\n paramNames.push(name);\n return '([^/]+)';\n })\n .replace(/\\//g, '\\\\/');\n return {\n pattern: new RegExp(`^${regexStr}$`),\n paramNames,\n };\n }\n\n private handleCors(request: IncomingMessage, response: ServerResponse): void {\n const origin = request.headers.origin;\n\n if (this.corsOrigins.includes('*')) {\n response.setHeader('Access-Control-Allow-Origin', origin ?? '*');\n if (origin) {\n response.setHeader('Vary', 'Origin');\n }\n } else if (origin && this.corsOrigins.includes(origin)) {\n response.setHeader('Access-Control-Allow-Origin', origin);\n response.setHeader('Vary', 'Origin');\n }\n\n response.setHeader('Access-Control-Allow-Credentials', 'true');\n response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');\n response.setHeader(\n 'Access-Control-Allow-Headers',\n [\n 'Authorization',\n 'Content-Type',\n 'Accept',\n 'DPoP',\n 'Origin',\n 'X-Requested-With',\n 'If-Match',\n 'If-None-Match',\n 'Slug',\n 'Link',\n ].join(', '),\n );\n response.setHeader('Access-Control-Max-Age', '86400');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ApiServer.js","sourceRoot":"","sources":["../../src/api/ApiServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport type { Duplex } from 'node:stream';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { AuthMiddleware, AuthenticatedRequest } from './middleware/AuthMiddleware';\nimport { nodeRuntimeHost } from '../runtime/host/node/NodeRuntimeHost';\nimport type { RuntimeHost, RuntimeListenEndpoint } from '../runtime/host/types';\n\n/**\n * Route handler function\n */\nexport type RouteHandler = (\n request: AuthenticatedRequest,\n response: ServerResponse,\n params: Record<string, string>,\n) => Promise<void>;\n\n/**\n * Route definition\n */\nexport interface Route {\n method: string;\n pattern: RegExp;\n paramNames: string[];\n handler: RouteHandler;\n /** If true, skip authentication */\n public?: boolean;\n /** If true, authenticate when credentials are present, otherwise continue unauthenticated */\n optionalAuth?: boolean;\n /** If true, match all methods instead of one method. */\n allMethods?: boolean;\n}\n\nexport interface ApiServerOptions {\n port?: number;\n host?: string;\n socketPath?: string;\n listenEndpoint?: RuntimeListenEndpoint;\n runtimeHost?: RuntimeHost;\n authMiddleware: AuthMiddleware;\n corsOrigins?: string[];\n}\n\nexport type UpgradeHandler = (request: IncomingMessage, socket: Duplex, head: Buffer) => void;\n\n/**\n * Standalone API Server\n */\nexport class ApiServer {\n private readonly logger = getLoggerFor(this);\n private readonly runtimeHost: RuntimeHost;\n private readonly listenEndpoint: RuntimeListenEndpoint;\n private readonly authMiddleware: AuthMiddleware;\n private readonly corsOrigins: string[];\n private readonly routes: Route[] = [];\n private readonly upgradeHandlers: UpgradeHandler[] = [];\n private readonly shutdownHandlers: Array<() => void | Promise<void>> = [];\n private responseHeaders: Record<string, string> = {};\n private server?: Server;\n\n public constructor(options: ApiServerOptions) {\n this.runtimeHost = options.runtimeHost ?? nodeRuntimeHost;\n this.listenEndpoint = options.listenEndpoint ?? this.runtimeHost.createListenEndpoint({\n port: options.port,\n host: options.host,\n socketPath: options.socketPath,\n });\n this.authMiddleware = options.authMiddleware;\n this.corsOrigins = options.corsOrigins ?? ['*'];\n }\n\n /**\n * Register a route\n */\n public route(\n method: string,\n path: string,\n handler: RouteHandler,\n options?: {\n /** If true, skip authentication for this route */\n public?: boolean;\n /** If true, authenticate when credentials are present, otherwise continue unauthenticated */\n optionalAuth?: boolean;\n /** If true, match all methods instead of one method */\n allMethods?: boolean;\n },\n ): void {\n const { pattern, paramNames } = this.pathToRegex(path);\n this.routes.push({\n method: method.toUpperCase(),\n pattern,\n paramNames,\n handler,\n public: options?.public,\n optionalAuth: options?.optionalAuth,\n allMethods: options?.allMethods,\n });\n this.logger.debug(`Registered route: ${method.toUpperCase()} ${path}${options?.public ? ' (public)' : ''}${options?.optionalAuth ? ' (optional auth)' : ''}`);\n }\n\n /**\n * Convenience methods for common HTTP methods\n */\n public get(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('GET', path, handler, options);\n }\n\n public post(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('POST', path, handler, options);\n }\n\n public put(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('PUT', path, handler, options);\n }\n\n public delete(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('DELETE', path, handler, options);\n }\n\n public patch(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('PATCH', path, handler, options);\n }\n\n public all(path: string, handler: RouteHandler, options?: { public?: boolean; optionalAuth?: boolean }): void {\n this.route('ALL', path, handler, { ...options, allMethods: true });\n }\n\n public addUpgradeHandler(handler: UpgradeHandler): void {\n this.upgradeHandlers.push(handler);\n if (this.server) {\n this.server.on('upgrade', handler);\n }\n }\n\n public addShutdownHandler(handler: () => void | Promise<void>): void {\n this.shutdownHandlers.push(handler);\n }\n\n public addResponseHeaders(headers: Record<string, string>): void {\n this.responseHeaders = { ...this.responseHeaders, ...headers };\n }\n\n /**\n * Start the server\n */\n public async start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.server = createServer((req, res) => {\n this.handleRequest(req, res).catch((error) => {\n this.logger.error(`Unhandled error: ${error}`);\n if (!res.headersSent) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Internal Server Error' }));\n }\n });\n });\n for (const handler of this.upgradeHandlers) {\n this.server.on('upgrade', handler);\n }\n\n this.runtimeHost.listen(this.server, this.listenEndpoint).then(() => {\n this.logger.info(`API Server listening on ${this.runtimeHost.formatListenEndpoint(this.listenEndpoint)}`);\n resolve();\n }, reject);\n });\n }\n\n /**\n * Stop the server\n */\n public async stop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.server) {\n resolve();\n return;\n }\n\n Promise.all(this.shutdownHandlers.map(async (handler) => handler())).then(() =>\n this.runtimeHost.close(this.server!, this.listenEndpoint)).then(() => {\n this.logger.info('API Server stopped');\n resolve();\n }, reject);\n });\n }\n\n /**\n * Get the underlying HTTP server (for WebSocket upgrade)\n */\n public getHttpServer(): Server | undefined {\n return this.server;\n }\n\n public address(): AddressInfo | string | null {\n return this.server?.address() ?? null;\n }\n\n private async handleRequest(request: IncomingMessage, response: ServerResponse): Promise<void> {\n const method = request.method?.toUpperCase() ?? 'GET';\n const url = new URL(request.url ?? '/', `http://${request.headers.host ?? 'localhost'}`);\n const path = url.pathname;\n\n // Handle CORS preflight\n if (method === 'OPTIONS') {\n this.handleCors(request, response);\n response.statusCode = 204;\n response.end();\n return;\n }\n\n // Add CORS headers\n this.handleCors(request, response);\n for (const [name, value] of Object.entries(this.responseHeaders)) {\n response.setHeader(name, value);\n }\n\n // Find matching route\n const match = this.findRoute(method, path);\n if (!match) {\n response.statusCode = 404;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify({ error: 'Not Found' }));\n return;\n }\n\n const { route, params } = match;\n const authRequest = request as AuthenticatedRequest;\n\n // Run auth middleware unless route is public. Optional-auth routes accept\n // anonymous callers but still hydrate request.auth when credentials exist.\n if (route.optionalAuth && request.headers.authorization) {\n const authOk = await this.authMiddleware.process(authRequest, response);\n if (!authOk) {\n return;\n }\n } else if (!route.public && !route.optionalAuth) {\n const authOk = await this.authMiddleware.process(authRequest, response);\n if (!authOk) {\n return;\n }\n }\n\n // Execute handler\n try {\n await route.handler(authRequest, response, params);\n } catch (error) {\n this.logger.error(`Route handler error: ${error}`);\n if (!response.headersSent) {\n response.statusCode = 500;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify({ error: 'Internal Server Error' }));\n }\n }\n }\n\n private findRoute(method: string, path: string): { route: Route; params: Record<string, string> } | undefined {\n for (const route of this.routes) {\n if (!route.allMethods && route.method !== method) {\n continue;\n }\n\n const match = route.pattern.exec(path);\n if (match) {\n const params: Record<string, string> = {};\n route.paramNames.forEach((name, index) => {\n params[name] = match[index + 1];\n });\n return { route, params };\n }\n }\n return undefined;\n }\n\n private pathToRegex(path: string): { pattern: RegExp; paramNames: string[] } {\n const paramNames: string[] = [];\n let regexStr = path\n // 先处理通配符 *path 或 * (匹配剩余所有路径)\n .replace(/\\*([a-zA-Z0-9_]*)/g, (_, name) => {\n paramNames.push(name || 'wildcard');\n return '(.*)';\n })\n // 再处理普通参数 :param (只匹配单段)\n .replace(/:([a-zA-Z0-9_]+)/g, (_, name) => {\n paramNames.push(name);\n return '([^/]+)';\n })\n .replace(/\\//g, '\\\\/');\n return {\n pattern: new RegExp(`^${regexStr}$`),\n paramNames,\n };\n }\n\n private handleCors(request: IncomingMessage, response: ServerResponse): void {\n const origin = request.headers.origin;\n\n if (this.corsOrigins.includes('*')) {\n response.setHeader('Access-Control-Allow-Origin', origin ?? '*');\n if (origin) {\n response.setHeader('Vary', 'Origin');\n }\n } else if (origin && this.corsOrigins.includes(origin)) {\n response.setHeader('Access-Control-Allow-Origin', origin);\n response.setHeader('Vary', 'Origin');\n }\n\n response.setHeader('Access-Control-Allow-Credentials', 'true');\n response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');\n response.setHeader(\n 'Access-Control-Allow-Headers',\n [\n 'Authorization',\n 'Content-Type',\n 'Accept',\n 'DPoP',\n 'Origin',\n 'X-Requested-With',\n 'If-Match',\n 'If-None-Match',\n 'Slug',\n 'Link',\n ].join(', '),\n );\n response.setHeader('Access-Control-Max-Age', '86400');\n }\n}\n"]}
|
|
@@ -56,6 +56,7 @@ const UsageHandler_1 = require("../handlers/UsageHandler");
|
|
|
56
56
|
const RdfStatsHandler_1 = require("../handlers/RdfStatsHandler");
|
|
57
57
|
const AiGatewayManagementHandler_1 = require("../handlers/AiGatewayManagementHandler");
|
|
58
58
|
const AiClientConfigurationHandler_1 = require("../handlers/AiClientConfigurationHandler");
|
|
59
|
+
const DeviceNotificationRuntime_1 = require("../handlers/DeviceNotificationRuntime");
|
|
59
60
|
const AiClientConfigurationService_1 = require("../service/AiClientConfigurationService");
|
|
60
61
|
const UsageRepository_1 = require("../../storage/quota/UsageRepository");
|
|
61
62
|
const DrizzleQuotaService_1 = require("../../quota/DrizzleQuotaService");
|
|
@@ -178,6 +179,11 @@ function registerSharedRoutes(container, server) {
|
|
|
178
179
|
(0, AiClientConfigurationHandler_1.registerAiClientConfigurationRoutes)(server, {
|
|
179
180
|
service: aiClientConfigurationService,
|
|
180
181
|
});
|
|
182
|
+
const notificationOrigin = config.publicUrl ?? config.solidBaseUrl ?? process.env.CSS_BASE_URL ?? `http://${config.host === '0.0.0.0' ? '127.0.0.1' : config.host}:${config.port}`;
|
|
183
|
+
(0, DeviceNotificationRuntime_1.registerDeviceNotificationRuntime)(server, {
|
|
184
|
+
origin: notificationOrigin,
|
|
185
|
+
authorizeTopic: createOwnerOnlyNotificationTopicAuthorizer(notificationOrigin),
|
|
186
|
+
});
|
|
181
187
|
(0, PodSettingsHandler_1.registerPodSettingsRoutes)(server, {
|
|
182
188
|
podLookupRepository,
|
|
183
189
|
usageRepo: new UsageRepository_1.UsageRepository(container.resolve('db')),
|
|
@@ -222,6 +228,13 @@ function registerSharedRoutes(container, server) {
|
|
|
222
228
|
console.log(`[Shared] Quota & Usage routes not registered: ${error}`);
|
|
223
229
|
}
|
|
224
230
|
}
|
|
231
|
+
function createOwnerOnlyNotificationTopicAuthorizer(origin) {
|
|
232
|
+
return async ({ identity, topic }) => {
|
|
233
|
+
// Owner-only fallback until a shared Solid Read permission reader is available for runtime injection.
|
|
234
|
+
// This is not a full WebACL/ACP authorization decision.
|
|
235
|
+
return topic.startsWith(new URL(`/${identity.localPart}/`, origin).toString());
|
|
236
|
+
};
|
|
237
|
+
}
|
|
225
238
|
function resolveAiClientConfigurationService(container, config) {
|
|
226
239
|
const injected = container.resolve('aiClientConfigurationService', { allowUnregistered: true });
|
|
227
240
|
if (injected)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/api/container/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 路由注册\n *\n * 根据容器中的服务注册 API 路由\n */\n\nimport type { AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\nimport type { ApiServer } from '../ApiServer';\n\nimport { registerEdgeNodeSignalRoutes } from '../handlers/EdgeNodeSignalHandler';\nimport { registerReachabilityRoutes } from '../handlers/ReachabilityHandler';\nimport { registerNodeRoutes } from '../handlers/NodeHandler';\nimport { registerChatRoutes } from '../handlers/ChatHandler';\nimport { registerSubdomainRoutes } from '../handlers/SubdomainHandler';\nimport { registerSubdomainClientRoutes } from '../handlers/SubdomainClientHandler';\nimport { registerDdnsRoutes } from '../handlers/DdnsHandler';\nimport { registerChatKitRoutes } from '../handlers/ChatKitHandler';\nimport { registerChatKitV1Routes } from '../handlers/ChatKitV1Handler';\nimport { registerInngestRoutes } from '../handlers/InngestHandler';\nimport { registerRunRoutes } from '../handlers/RunHandler';\nimport { registerMatrixRoutes } from '../handlers/MatrixHandler';\nimport { registerCoordinationRoutes } from '../handlers/CoordinationHandler';\nimport { registerDashboardRoutes } from '../handlers/DashboardHandler';\nimport { registerSettingsRoutes } from '../handlers/SettingsHandler';\nimport { registerAdminRoutes } from '../handlers/AdminHandler';\nimport { registerAdminDdnsRoutes } from '../handlers/AdminDdnsHandler';\nimport { registerLinxCapabilitiesRoutes } from '../handlers/LinxCapabilitiesHandler';\nimport { createLocalSetupProvisionStateWriter, registerProvisionRoutes, registerProvisionStatusRoute } from '../handlers/ProvisionHandler';\nimport { registerPodManagementRoutes } from '../handlers/PodManagementHandler';\nimport { DrizzlePodAiConnectionStatusReader, registerPodSettingsRoutes } from '../handlers/PodSettingsHandler';\nimport {\n createAddressReaders,\n createCertificateCapability,\n createDeploymentNetworkSettingsAuthorizer,\n createDnsStatusReader,\n createPublicAddressReader,\n createTunnelStatusReader,\n registerNetworkSettingsRoutes,\n} from '../handlers/NetworkSettingsHandler';\nimport { registerQuotaRoutes } from '../handlers/QuotaHandler';\nimport { registerUsageRoutes } from '../handlers/UsageHandler';\nimport { registerRdfStatsRoutes } from '../handlers/RdfStatsHandler';\nimport { registerAiGatewayManagementRoutes } from '../handlers/AiGatewayManagementHandler';\nimport { registerAiClientConfigurationRoutes } from '../handlers/AiClientConfigurationHandler';\nimport { AiClientConfigurationService } from '../service/AiClientConfigurationService';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { DrizzleQuotaService } from '../../quota/DrizzleQuotaService';\nimport { LocalPodProvisioningService } from '../../provision/LocalPodProvisioningService';\nimport { verifyServiceAccessToken } from '../../provision/ServiceAccessTokenCodec';\nimport {\n findEdgeNodeCertificateCapabilityBridge,\n resolveEdgeNodeCertificateCapabilityBridgeId,\n} from '../../edge/EdgeNodeCertificateCapabilityBridge';\nimport * as path from 'node:path';\nimport { PACKAGE_ROOT } from '../../runtime';\n\n/**\n * 注册所有 API 路由\n */\nexport function registerRoutes(container: AwilixContainer<ApiContainerCradle>): void {\n const server = container.resolve('apiServer') as ApiServer;\n const config = container.resolve('config') as ApiContainerConfig;\n\n // 公共健康检查端点\n registerHealthRoutes(server);\n\n // 共享路由\n registerSharedRoutes(container, server);\n\n // 根据 edition 注册专属路由\n if (config.edition === 'cloud') {\n registerCloudRoutes(container, server);\n } else {\n registerLocalRoutes(container, server);\n }\n}\n\n/**\n * 健康检查路由\n */\nfunction registerHealthRoutes(server: ApiServer): void {\n server.get('/health', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ok' }));\n }, { public: true });\n\n server.get('/ready', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ready' }));\n }, { public: true });\n\n // Dashboard 静态资源\n const staticDir = path.resolve(PACKAGE_ROOT, 'static/dashboard');\n registerDashboardRoutes(server, { staticDir });\n const settingsStaticDir = path.resolve(PACKAGE_ROOT, 'static/settings');\n registerSettingsRoutes(server, { staticDir: settingsStaticDir });\n}\n\n/**\n * 共享路由 (cloud 和 local 都有)\n */\nfunction registerSharedRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const chatService = container.resolve('chatService');\n const chatKitService = container.resolve('chatKitService');\n const chatKitStore = container.resolve('chatKitStore');\n const runExecutionBackend = container.resolve('runExecutionBackend');\n const matrixStore = container.resolve('matrixStore');\n const clientReconcilerCoordinator = container.resolve('clientReconcilerCoordinator');\n const inngestTaskScheduler = container.resolve('inngestTaskScheduler');\n const inngestRuntimeConfig = container.resolve('inngestRuntimeConfig');\n const rdfStorageStatsService = container.resolve('rdfStorageStatsService');\n const gatewayAccessKeyRepository = container.resolve('gatewayAccessKeyRepository');\n const gatewayInternalPodAccess = container.resolve('gatewayInternalPodAccess');\n const aiConnectionInvocationKeyIssuer = container.resolve('aiConnectionInvocationKeyIssuer');\n const providerConnectService = container.resolve('providerConnectService');\n const providerQuotaService = container.resolve('providerQuotaService', { allowUnregistered: true });\n const config = container.resolve('config') as ApiContainerConfig;\n const aiClientConfigurationService = resolveAiClientConfigurationService(container, config);\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true });\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });\n const dnsCoordinator = container.resolve('dnsCoordinator', { allowUnregistered: true });\n const localTunnelProvider = container.resolve('localTunnelProvider', { allowUnregistered: true });\n const cloudTunnelProvider = container.resolve('tunnelProvider', { allowUnregistered: true });\n const tunnelProvider = localTunnelProvider ?? cloudTunnelProvider;\n const edgeCertificateBridge = createDynamicEdgeCertificateBridge(config);\n const certificateCapability = createCertificateCapability(\n container.resolve('certificateManager', { allowUnregistered: true }),\n container.resolve('acmeCertificateManager', { allowUnregistered: true }),\n container.resolve('clusterCertificateManager', { allowUnregistered: true }),\n edgeCertificateBridge,\n );\n const podLookupRepository = container.resolve('podLookupRepo');\n const accountRoleRepository = container.resolve('accountRoleRepo', { allowUnregistered: true });\n if (!podLookupRepository) {\n throw new Error('Pod settings route requires podLookupRepo');\n }\n\n registerEdgeNodeSignalRoutes(server, {\n repository: nodeRepo,\n dnsCoordinator: container.resolve('dnsCoordinator', { allowUnregistered: true }) as any,\n healthProbeService: container.resolve('healthProbeService', { allowUnregistered: true }) as any,\n });\n registerReachabilityRoutes(server, {\n repository: nodeRepo,\n baseStorageDomain: config.subdomain?.baseStorageDomain,\n apiBaseUrl: config.cloudApiEndpoint ?? process.env.XPOD_CLOUD_API_ENDPOINT ?? process.env.CSS_BASE_URL,\n });\n registerNodeRoutes(server, { repository: nodeRepo });\n const aiGatewayService = container.resolve('aiGatewayService');\n registerChatRoutes(server, {\n chatService,\n aiGatewayService,\n acceptanceEndpointsEnabled: process.env.XPOD_ACCEPTANCE_ENDPOINTS_ENABLED === 'true',\n });\n registerChatKitRoutes(server, { chatKitService });\n registerChatKitV1Routes(server, { store: chatKitStore });\n registerRunRoutes(server, { runStore: chatKitStore });\n registerMatrixRoutes(server, { store: matrixStore });\n registerCoordinationRoutes(server, { clientReconcilerCoordinator });\n registerInngestRoutes(server, {\n backend: runExecutionBackend,\n taskScheduler: inngestTaskScheduler,\n runtimeConfig: inngestRuntimeConfig,\n });\n registerRdfStatsRoutes(server, {\n rdfStorageStatsService,\n });\n registerAiGatewayManagementRoutes(server, {\n repository: gatewayAccessKeyRepository,\n deployment: config.edition,\n connectService: providerConnectService,\n quotaService: providerQuotaService,\n servicePrincipal: gatewayInternalPodAccess,\n aiClientConfiguration: aiClientConfigurationService?.capability(),\n aiConnectionInvocationKeyIssuer,\n });\n registerAiClientConfigurationRoutes(server, {\n service: aiClientConfigurationService,\n });\n registerPodSettingsRoutes(server, {\n podLookupRepository,\n usageRepo: new UsageRepository(container.resolve('db')),\n aiConnectionStatusReader: new DrizzlePodAiConnectionStatusReader(gatewayInternalPodAccess),\n });\n registerNetworkSettingsRoutes(server, {\n endpoint: () => resolveNetworkEndpoint(config),\n ...createAddressReaders({\n endpoint: () => resolveNetworkEndpoint(config),\n port: config.port,\n publicUrls: [\n config.publicUrl,\n config.activeTunnelProfile?.publicUrl,\n ],\n }),\n publicAddresses: createPublicAddressReader({\n configuredUrls: [\n config.publicUrl,\n config.activeTunnelProfile?.publicUrl,\n ],\n ddnsManager,\n tunnelProvider,\n }),\n dnsStatusReader: createDnsStatusReader({ ddnsManager, dnsProvider, dnsCoordinator }),\n tunnelStatusReader: createTunnelStatusReader(tunnelProvider),\n tlsStatusReader: certificateCapability?.tlsStatusReader,\n certificateRenewer: certificateCapability?.certificateRenewer,\n authorizer: createDeploymentNetworkSettingsAuthorizer({\n deployment: config.edition,\n accountRoleRepository,\n }),\n });\n\n // Quota & Usage API (Business 对接)\n try {\n const quotaService = new DrizzleQuotaService({ identityDbUrl: config.databaseUrl });\n const usageRepo = new UsageRepository(container.resolve('db'));\n registerQuotaRoutes(server, { quotaService, usageRepo });\n registerUsageRoutes(server, { usageRepo });\n console.log('[Shared] Quota & Usage routes registered');\n } catch (error) {\n console.log(`[Shared] Quota & Usage routes not registered: ${error}`);\n }\n}\n\nfunction resolveAiClientConfigurationService(\n container: AwilixContainer<ApiContainerCradle>,\n config: ApiContainerConfig,\n): AiClientConfigurationService | undefined {\n const injected = container.resolve('aiClientConfigurationService', { allowUnregistered: true });\n if (injected) return injected;\n const capability = config.aiClientConfiguration;\n if (!capability?.enabled || capability.authority !== 'local-filesystem') {\n return undefined;\n }\n return new AiClientConfigurationService({\n homeDir: capability.homeDir,\n backupRoot: capability.backupRoot,\n });\n}\n\nfunction createDynamicEdgeCertificateBridge(config: ApiContainerConfig): unknown {\n const bridgeId = resolveEdgeNodeCertificateCapabilityBridgeId({\n nodeId: config.nodeId,\n baseUrl: config.solidBaseUrl ?? config.publicUrl,\n });\n if (!bridgeId) {\n return undefined;\n }\n return {\n readCertificateStatus: async () => {\n return await findEdgeNodeCertificateCapabilityBridge(bridgeId)?.readCertificateStatus()\n ?? { supported: false, status: 'unsupported' };\n },\n renewCertificate: async () => {\n const bridge = findEdgeNodeCertificateCapabilityBridge(bridgeId);\n if (!bridge) {\n throw Object.assign(new Error('Certificate runtime is not available.'), {\n statusCode: 503,\n code: 'certificate_renewal_unavailable',\n });\n }\n return await bridge.renewCertificate();\n },\n isAvailable: async () => {\n return Boolean(await findEdgeNodeCertificateCapabilityBridge(bridgeId)?.isAvailable());\n },\n };\n}\n\n/**\n * Cloud 模式专属路由\n */\nfunction registerCloudRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // 子域名管理 API (需要 SubdomainService)\n try {\n const subdomainService = container.resolve('subdomainService') as ApiContainerCradle['subdomainService'];\n if (subdomainService) {\n registerSubdomainRoutes(server, { subdomainService });\n console.log('[Cloud] Subdomain routes registered');\n }\n } catch {\n console.log('[Cloud] Subdomain routes not registered (service not available)');\n }\n\n // DDNS 服务\n try {\n const ddnsRepo = container.resolve('ddnsRepo', { allowUnregistered: true });\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });\n const config = container.resolve('config') as ApiContainerConfig;\n\n if (ddnsRepo) {\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n if (baseStorageDomain) {\n registerDdnsRoutes(server, {\n ddnsRepo: ddnsRepo as any,\n dnsProvider: dnsProvider as any,\n defaultDomain: baseStorageDomain,\n });\n console.log(`[Cloud] DDNS routes registered (domain: ${baseStorageDomain})`);\n } else {\n console.log('[Cloud] DDNS routes not registered (no CSS_BASE_STORAGE_DOMAIN)');\n }\n }\n } catch {\n console.log('[Cloud] DDNS routes not registered (repo not available)');\n }\n\n // SP Provision API (SP 注册)\n try {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const config = container.resolve('config') as ApiContainerConfig;\n const baseUrl = process.env.CSS_BASE_URL || 'http://localhost:3000/';\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n const ddnsRepo = container.resolve('ddnsRepo', { allowUnregistered: true }) as any;\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true }) as any;\n const tunnelProvider = container.resolve('tunnelProvider', { allowUnregistered: true }) as any;\n registerProvisionRoutes(server, {\n repository: nodeRepo,\n ddnsRepo,\n dnsProvider,\n tunnelProvider,\n baseUrl,\n baseStorageDomain,\n });\n console.log(`[Cloud] Provision routes registered${baseStorageDomain ? ` (baseStorageDomain: ${baseStorageDomain})` : ''}`);\n } catch {\n console.log('[Cloud] Provision routes not registered (dependencies not available)');\n }\n}\n\n/**\n * Local 模式专属路由\n */\nfunction registerLocalRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n const config = container.resolve('config') as ApiContainerConfig;\n registerLinxCapabilitiesRoutes(server);\n\n // Admin API (配置管理、重启)\n registerAdminRoutes(server, {\n internalAdminAuthSecret: config.gatewayAdminProxyAuthSecret,\n });\n // DDNS status (托管式 Local 模式)\n try {\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true }) as any;\n registerAdminDdnsRoutes(server, { ddnsManager });\n } catch {\n // ignore\n }\n\n // 子域名客户端 API (通过 SubdomainClient 调用 Cloud)\n try {\n const subdomainClient = container.resolve('subdomainClient') as ApiContainerCradle['subdomainClient'];\n if (subdomainClient) {\n registerSubdomainClientRoutes(server, { subdomainClient });\n console.log('[Local] Subdomain client routes registered');\n }\n } catch {\n console.log('[Local] Subdomain client routes not registered (client not available)');\n }\n\n // Pod Provision API (SP 端,供 Cloud 回调创建 Pod)\n try {\n const config = container.resolve('config') as ApiContainerConfig;\n // rootDir: CSS 数据目录,默认 ./data\n const rootDir = process.env.CSS_ROOT_FILE_PATH || './data';\n // serviceToken 验证:从 SP 配置中读取\n const expectedServiceToken = config.serviceToken;\n\n if (expectedServiceToken) {\n const baseUrl = process.env.CSS_BASE_URL || 'http://localhost:3000/';\n const sparqlEndpoint = process.env.CSS_SPARQL_ENDPOINT || process.env.SPARQL_ENDPOINT;\n const identityDbUrl = process.env.CSS_IDENTITY_DB_URL || process.env.DATABASE_URL;\n const provisioningService = sparqlEndpoint && identityDbUrl\n ? new LocalPodProvisioningService({\n baseUrl,\n rootDir,\n sparqlEndpoint,\n identityDbUrl,\n rdfIndexPath: config.rdfIndexPath,\n oidcIssuer: process.env.oidcIssuer ?? config.oidcIssuer,\n authMode: config.authMode,\n })\n : undefined;\n\n registerPodManagementRoutes(server, {\n rootDir,\n verifyServiceToken: async (token: string) => (\n token === expectedServiceToken\n || verifyServiceAccessToken(token, { serviceToken: expectedServiceToken }).valid\n ),\n provisioningService,\n podLookupRepository: container.resolve('podLookupRepo', { allowUnregistered: true }),\n storageProviderBaseUrl: baseUrl,\n });\n console.log(`[Local] Pod provision routes registered (/provision/pods, /provision/webids, ${provisioningService ? 'css-compatible' : 'directory-only'})`);\n } else {\n console.log('[Local] Pod provision routes not registered (serviceToken not configured)');\n }\n } catch (error) {\n console.log(`[Local] Pod provision routes not registered: ${error}`);\n }\n\n // SP 状态查询 (供 Linx 查询 SP 配置状态)\n try {\n const config = container.resolve('config') as ApiContainerConfig;\n registerProvisionStatusRoute(server, {\n cloudUrl: config.cloudApiEndpoint,\n nodeId: config.nodeId,\n nodeToken: config.nodeToken,\n serviceToken: config.serviceToken,\n publicUrl: process.env.XPOD_PUBLIC_URL ?? config.publicUrl ?? process.env.CSS_BASE_URL,\n spDomain: process.env.XPOD_SP_DOMAIN ?? config.spDomain,\n localPort: readPositiveInteger(process.env.CSS_PORT ?? process.env.XPOD_PORT ?? process.env.PORT),\n tunnelToken: process.env.CLOUDFLARE_TUNNEL_TOKEN ?? process.env.SAKURA_TUNNEL_TOKEN ?? process.env.SAKURA_TOKEN,\n cloudBaseUrl: config.oidcIssuer || config.cloudApiEndpoint,\n provisionCode: process.env.XPOD_PROVISION_CODE ?? config.provisionCode,\n persistState: createLocalSetupProvisionStateWriter(\n config.localSetupPath,\n config.localSetupProviderId,\n ),\n });\n console.log('[Local] Provision status route registered (/provision/status)');\n } catch (error) {\n console.log(`[Local] Provision status route not registered: ${error}`);\n }\n}\n\nfunction readPositiveInteger(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const parsed = Number.parseInt(value, 10);\n return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;\n}\n\nfunction resolveNetworkEndpoint(config: ApiContainerConfig): string {\n const configured = config.publicUrl\n ?? config.activeTunnelProfile?.publicUrl\n ?? config.solidBaseUrl\n ?? `http://${config.host === '0.0.0.0' ? '127.0.0.1' : config.host}:${config.port}/`;\n try {\n return new URL(configured).toString().replace(/\\/+$/u, '') + '/';\n } catch {\n return `http://127.0.0.1:${config.port}/`;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/api/container/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 路由注册\n *\n * 根据容器中的服务注册 API 路由\n */\n\nimport type { AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\nimport type { ApiServer } from '../ApiServer';\n\nimport { registerEdgeNodeSignalRoutes } from '../handlers/EdgeNodeSignalHandler';\nimport { registerReachabilityRoutes } from '../handlers/ReachabilityHandler';\nimport { registerNodeRoutes } from '../handlers/NodeHandler';\nimport { registerChatRoutes } from '../handlers/ChatHandler';\nimport { registerSubdomainRoutes } from '../handlers/SubdomainHandler';\nimport { registerSubdomainClientRoutes } from '../handlers/SubdomainClientHandler';\nimport { registerDdnsRoutes } from '../handlers/DdnsHandler';\nimport { registerChatKitRoutes } from '../handlers/ChatKitHandler';\nimport { registerChatKitV1Routes } from '../handlers/ChatKitV1Handler';\nimport { registerInngestRoutes } from '../handlers/InngestHandler';\nimport { registerRunRoutes } from '../handlers/RunHandler';\nimport { registerMatrixRoutes } from '../handlers/MatrixHandler';\nimport { registerCoordinationRoutes } from '../handlers/CoordinationHandler';\nimport { registerDashboardRoutes } from '../handlers/DashboardHandler';\nimport { registerSettingsRoutes } from '../handlers/SettingsHandler';\nimport { registerAdminRoutes } from '../handlers/AdminHandler';\nimport { registerAdminDdnsRoutes } from '../handlers/AdminDdnsHandler';\nimport { registerLinxCapabilitiesRoutes } from '../handlers/LinxCapabilitiesHandler';\nimport { createLocalSetupProvisionStateWriter, registerProvisionRoutes, registerProvisionStatusRoute } from '../handlers/ProvisionHandler';\nimport { registerPodManagementRoutes } from '../handlers/PodManagementHandler';\nimport { DrizzlePodAiConnectionStatusReader, registerPodSettingsRoutes } from '../handlers/PodSettingsHandler';\nimport {\n createAddressReaders,\n createCertificateCapability,\n createDeploymentNetworkSettingsAuthorizer,\n createDnsStatusReader,\n createPublicAddressReader,\n createTunnelStatusReader,\n registerNetworkSettingsRoutes,\n} from '../handlers/NetworkSettingsHandler';\nimport { registerQuotaRoutes } from '../handlers/QuotaHandler';\nimport { registerUsageRoutes } from '../handlers/UsageHandler';\nimport { registerRdfStatsRoutes } from '../handlers/RdfStatsHandler';\nimport { registerAiGatewayManagementRoutes } from '../handlers/AiGatewayManagementHandler';\nimport { registerAiClientConfigurationRoutes } from '../handlers/AiClientConfigurationHandler';\nimport { registerDeviceNotificationRuntime, type DeviceNotificationRuntimeOptions } from '../handlers/DeviceNotificationRuntime';\nimport { AiClientConfigurationService } from '../service/AiClientConfigurationService';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { DrizzleQuotaService } from '../../quota/DrizzleQuotaService';\nimport { LocalPodProvisioningService } from '../../provision/LocalPodProvisioningService';\nimport { verifyServiceAccessToken } from '../../provision/ServiceAccessTokenCodec';\nimport {\n findEdgeNodeCertificateCapabilityBridge,\n resolveEdgeNodeCertificateCapabilityBridgeId,\n} from '../../edge/EdgeNodeCertificateCapabilityBridge';\nimport * as path from 'node:path';\nimport { PACKAGE_ROOT } from '../../runtime';\n\n/**\n * 注册所有 API 路由\n */\nexport function registerRoutes(container: AwilixContainer<ApiContainerCradle>): void {\n const server = container.resolve('apiServer') as ApiServer;\n const config = container.resolve('config') as ApiContainerConfig;\n\n // 公共健康检查端点\n registerHealthRoutes(server);\n\n // 共享路由\n registerSharedRoutes(container, server);\n\n // 根据 edition 注册专属路由\n if (config.edition === 'cloud') {\n registerCloudRoutes(container, server);\n } else {\n registerLocalRoutes(container, server);\n }\n}\n\n/**\n * 健康检查路由\n */\nfunction registerHealthRoutes(server: ApiServer): void {\n server.get('/health', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ok' }));\n }, { public: true });\n\n server.get('/ready', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ready' }));\n }, { public: true });\n\n // Dashboard 静态资源\n const staticDir = path.resolve(PACKAGE_ROOT, 'static/dashboard');\n registerDashboardRoutes(server, { staticDir });\n const settingsStaticDir = path.resolve(PACKAGE_ROOT, 'static/settings');\n registerSettingsRoutes(server, { staticDir: settingsStaticDir });\n}\n\n/**\n * 共享路由 (cloud 和 local 都有)\n */\nfunction registerSharedRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const chatService = container.resolve('chatService');\n const chatKitService = container.resolve('chatKitService');\n const chatKitStore = container.resolve('chatKitStore');\n const runExecutionBackend = container.resolve('runExecutionBackend');\n const matrixStore = container.resolve('matrixStore');\n const clientReconcilerCoordinator = container.resolve('clientReconcilerCoordinator');\n const inngestTaskScheduler = container.resolve('inngestTaskScheduler');\n const inngestRuntimeConfig = container.resolve('inngestRuntimeConfig');\n const rdfStorageStatsService = container.resolve('rdfStorageStatsService');\n const gatewayAccessKeyRepository = container.resolve('gatewayAccessKeyRepository');\n const gatewayInternalPodAccess = container.resolve('gatewayInternalPodAccess');\n const aiConnectionInvocationKeyIssuer = container.resolve('aiConnectionInvocationKeyIssuer');\n const providerConnectService = container.resolve('providerConnectService');\n const providerQuotaService = container.resolve('providerQuotaService', { allowUnregistered: true });\n const config = container.resolve('config') as ApiContainerConfig;\n const aiClientConfigurationService = resolveAiClientConfigurationService(container, config);\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true });\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });\n const dnsCoordinator = container.resolve('dnsCoordinator', { allowUnregistered: true });\n const localTunnelProvider = container.resolve('localTunnelProvider', { allowUnregistered: true });\n const cloudTunnelProvider = container.resolve('tunnelProvider', { allowUnregistered: true });\n const tunnelProvider = localTunnelProvider ?? cloudTunnelProvider;\n const edgeCertificateBridge = createDynamicEdgeCertificateBridge(config);\n const certificateCapability = createCertificateCapability(\n container.resolve('certificateManager', { allowUnregistered: true }),\n container.resolve('acmeCertificateManager', { allowUnregistered: true }),\n container.resolve('clusterCertificateManager', { allowUnregistered: true }),\n edgeCertificateBridge,\n );\n const podLookupRepository = container.resolve('podLookupRepo');\n const accountRoleRepository = container.resolve('accountRoleRepo', { allowUnregistered: true });\n if (!podLookupRepository) {\n throw new Error('Pod settings route requires podLookupRepo');\n }\n\n registerEdgeNodeSignalRoutes(server, {\n repository: nodeRepo,\n dnsCoordinator: container.resolve('dnsCoordinator', { allowUnregistered: true }) as any,\n healthProbeService: container.resolve('healthProbeService', { allowUnregistered: true }) as any,\n });\n registerReachabilityRoutes(server, {\n repository: nodeRepo,\n baseStorageDomain: config.subdomain?.baseStorageDomain,\n apiBaseUrl: config.cloudApiEndpoint ?? process.env.XPOD_CLOUD_API_ENDPOINT ?? process.env.CSS_BASE_URL,\n });\n registerNodeRoutes(server, { repository: nodeRepo });\n const aiGatewayService = container.resolve('aiGatewayService');\n registerChatRoutes(server, {\n chatService,\n aiGatewayService,\n acceptanceEndpointsEnabled: process.env.XPOD_ACCEPTANCE_ENDPOINTS_ENABLED === 'true',\n });\n registerChatKitRoutes(server, { chatKitService });\n registerChatKitV1Routes(server, { store: chatKitStore });\n registerRunRoutes(server, { runStore: chatKitStore });\n registerMatrixRoutes(server, { store: matrixStore });\n registerCoordinationRoutes(server, { clientReconcilerCoordinator });\n registerInngestRoutes(server, {\n backend: runExecutionBackend,\n taskScheduler: inngestTaskScheduler,\n runtimeConfig: inngestRuntimeConfig,\n });\n registerRdfStatsRoutes(server, {\n rdfStorageStatsService,\n });\n registerAiGatewayManagementRoutes(server, {\n repository: gatewayAccessKeyRepository,\n deployment: config.edition,\n connectService: providerConnectService,\n quotaService: providerQuotaService,\n servicePrincipal: gatewayInternalPodAccess,\n aiClientConfiguration: aiClientConfigurationService?.capability(),\n aiConnectionInvocationKeyIssuer,\n });\n registerAiClientConfigurationRoutes(server, {\n service: aiClientConfigurationService,\n });\n const notificationOrigin = config.publicUrl ?? config.solidBaseUrl ?? process.env.CSS_BASE_URL ?? `http://${config.host === '0.0.0.0' ? '127.0.0.1' : config.host}:${config.port}`;\n registerDeviceNotificationRuntime(server, {\n origin: notificationOrigin,\n authorizeTopic: createOwnerOnlyNotificationTopicAuthorizer(notificationOrigin),\n });\n registerPodSettingsRoutes(server, {\n podLookupRepository,\n usageRepo: new UsageRepository(container.resolve('db')),\n aiConnectionStatusReader: new DrizzlePodAiConnectionStatusReader(gatewayInternalPodAccess),\n });\n registerNetworkSettingsRoutes(server, {\n endpoint: () => resolveNetworkEndpoint(config),\n ...createAddressReaders({\n endpoint: () => resolveNetworkEndpoint(config),\n port: config.port,\n publicUrls: [\n config.publicUrl,\n config.activeTunnelProfile?.publicUrl,\n ],\n }),\n publicAddresses: createPublicAddressReader({\n configuredUrls: [\n config.publicUrl,\n config.activeTunnelProfile?.publicUrl,\n ],\n ddnsManager,\n tunnelProvider,\n }),\n dnsStatusReader: createDnsStatusReader({ ddnsManager, dnsProvider, dnsCoordinator }),\n tunnelStatusReader: createTunnelStatusReader(tunnelProvider),\n tlsStatusReader: certificateCapability?.tlsStatusReader,\n certificateRenewer: certificateCapability?.certificateRenewer,\n authorizer: createDeploymentNetworkSettingsAuthorizer({\n deployment: config.edition,\n accountRoleRepository,\n }),\n });\n\n // Quota & Usage API (Business 对接)\n try {\n const quotaService = new DrizzleQuotaService({ identityDbUrl: config.databaseUrl });\n const usageRepo = new UsageRepository(container.resolve('db'));\n registerQuotaRoutes(server, { quotaService, usageRepo });\n registerUsageRoutes(server, { usageRepo });\n console.log('[Shared] Quota & Usage routes registered');\n } catch (error) {\n console.log(`[Shared] Quota & Usage routes not registered: ${error}`);\n }\n}\n\ntype DeviceNotificationTopicAuthorizer = NonNullable<DeviceNotificationRuntimeOptions['authorizeTopic']>;\n\nfunction createOwnerOnlyNotificationTopicAuthorizer(origin: string): DeviceNotificationTopicAuthorizer {\n return async ({ identity, topic }) => {\n // Owner-only fallback until a shared Solid Read permission reader is available for runtime injection.\n // This is not a full WebACL/ACP authorization decision.\n return topic.startsWith(new URL(`/${identity.localPart}/`, origin).toString());\n };\n}\n\nfunction resolveAiClientConfigurationService(\n container: AwilixContainer<ApiContainerCradle>,\n config: ApiContainerConfig,\n): AiClientConfigurationService | undefined {\n const injected = container.resolve('aiClientConfigurationService', { allowUnregistered: true });\n if (injected) return injected;\n const capability = config.aiClientConfiguration;\n if (!capability?.enabled || capability.authority !== 'local-filesystem') {\n return undefined;\n }\n return new AiClientConfigurationService({\n homeDir: capability.homeDir,\n backupRoot: capability.backupRoot,\n });\n}\n\nfunction createDynamicEdgeCertificateBridge(config: ApiContainerConfig): unknown {\n const bridgeId = resolveEdgeNodeCertificateCapabilityBridgeId({\n nodeId: config.nodeId,\n baseUrl: config.solidBaseUrl ?? config.publicUrl,\n });\n if (!bridgeId) {\n return undefined;\n }\n return {\n readCertificateStatus: async () => {\n return await findEdgeNodeCertificateCapabilityBridge(bridgeId)?.readCertificateStatus()\n ?? { supported: false, status: 'unsupported' };\n },\n renewCertificate: async () => {\n const bridge = findEdgeNodeCertificateCapabilityBridge(bridgeId);\n if (!bridge) {\n throw Object.assign(new Error('Certificate runtime is not available.'), {\n statusCode: 503,\n code: 'certificate_renewal_unavailable',\n });\n }\n return await bridge.renewCertificate();\n },\n isAvailable: async () => {\n return Boolean(await findEdgeNodeCertificateCapabilityBridge(bridgeId)?.isAvailable());\n },\n };\n}\n\n/**\n * Cloud 模式专属路由\n */\nfunction registerCloudRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // 子域名管理 API (需要 SubdomainService)\n try {\n const subdomainService = container.resolve('subdomainService') as ApiContainerCradle['subdomainService'];\n if (subdomainService) {\n registerSubdomainRoutes(server, { subdomainService });\n console.log('[Cloud] Subdomain routes registered');\n }\n } catch {\n console.log('[Cloud] Subdomain routes not registered (service not available)');\n }\n\n // DDNS 服务\n try {\n const ddnsRepo = container.resolve('ddnsRepo', { allowUnregistered: true });\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });\n const config = container.resolve('config') as ApiContainerConfig;\n\n if (ddnsRepo) {\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n if (baseStorageDomain) {\n registerDdnsRoutes(server, {\n ddnsRepo: ddnsRepo as any,\n dnsProvider: dnsProvider as any,\n defaultDomain: baseStorageDomain,\n });\n console.log(`[Cloud] DDNS routes registered (domain: ${baseStorageDomain})`);\n } else {\n console.log('[Cloud] DDNS routes not registered (no CSS_BASE_STORAGE_DOMAIN)');\n }\n }\n } catch {\n console.log('[Cloud] DDNS routes not registered (repo not available)');\n }\n\n // SP Provision API (SP 注册)\n try {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const config = container.resolve('config') as ApiContainerConfig;\n const baseUrl = process.env.CSS_BASE_URL || 'http://localhost:3000/';\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n const ddnsRepo = container.resolve('ddnsRepo', { allowUnregistered: true }) as any;\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true }) as any;\n const tunnelProvider = container.resolve('tunnelProvider', { allowUnregistered: true }) as any;\n registerProvisionRoutes(server, {\n repository: nodeRepo,\n ddnsRepo,\n dnsProvider,\n tunnelProvider,\n baseUrl,\n baseStorageDomain,\n });\n console.log(`[Cloud] Provision routes registered${baseStorageDomain ? ` (baseStorageDomain: ${baseStorageDomain})` : ''}`);\n } catch {\n console.log('[Cloud] Provision routes not registered (dependencies not available)');\n }\n}\n\n/**\n * Local 模式专属路由\n */\nfunction registerLocalRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n const config = container.resolve('config') as ApiContainerConfig;\n registerLinxCapabilitiesRoutes(server);\n\n // Admin API (配置管理、重启)\n registerAdminRoutes(server, {\n internalAdminAuthSecret: config.gatewayAdminProxyAuthSecret,\n });\n // DDNS status (托管式 Local 模式)\n try {\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true }) as any;\n registerAdminDdnsRoutes(server, { ddnsManager });\n } catch {\n // ignore\n }\n\n // 子域名客户端 API (通过 SubdomainClient 调用 Cloud)\n try {\n const subdomainClient = container.resolve('subdomainClient') as ApiContainerCradle['subdomainClient'];\n if (subdomainClient) {\n registerSubdomainClientRoutes(server, { subdomainClient });\n console.log('[Local] Subdomain client routes registered');\n }\n } catch {\n console.log('[Local] Subdomain client routes not registered (client not available)');\n }\n\n // Pod Provision API (SP 端,供 Cloud 回调创建 Pod)\n try {\n const config = container.resolve('config') as ApiContainerConfig;\n // rootDir: CSS 数据目录,默认 ./data\n const rootDir = process.env.CSS_ROOT_FILE_PATH || './data';\n // serviceToken 验证:从 SP 配置中读取\n const expectedServiceToken = config.serviceToken;\n\n if (expectedServiceToken) {\n const baseUrl = process.env.CSS_BASE_URL || 'http://localhost:3000/';\n const sparqlEndpoint = process.env.CSS_SPARQL_ENDPOINT || process.env.SPARQL_ENDPOINT;\n const identityDbUrl = process.env.CSS_IDENTITY_DB_URL || process.env.DATABASE_URL;\n const provisioningService = sparqlEndpoint && identityDbUrl\n ? new LocalPodProvisioningService({\n baseUrl,\n rootDir,\n sparqlEndpoint,\n identityDbUrl,\n rdfIndexPath: config.rdfIndexPath,\n oidcIssuer: process.env.oidcIssuer ?? config.oidcIssuer,\n authMode: config.authMode,\n })\n : undefined;\n\n registerPodManagementRoutes(server, {\n rootDir,\n verifyServiceToken: async (token: string) => (\n token === expectedServiceToken\n || verifyServiceAccessToken(token, { serviceToken: expectedServiceToken }).valid\n ),\n provisioningService,\n podLookupRepository: container.resolve('podLookupRepo', { allowUnregistered: true }),\n storageProviderBaseUrl: baseUrl,\n });\n console.log(`[Local] Pod provision routes registered (/provision/pods, /provision/webids, ${provisioningService ? 'css-compatible' : 'directory-only'})`);\n } else {\n console.log('[Local] Pod provision routes not registered (serviceToken not configured)');\n }\n } catch (error) {\n console.log(`[Local] Pod provision routes not registered: ${error}`);\n }\n\n // SP 状态查询 (供 Linx 查询 SP 配置状态)\n try {\n const config = container.resolve('config') as ApiContainerConfig;\n registerProvisionStatusRoute(server, {\n cloudUrl: config.cloudApiEndpoint,\n nodeId: config.nodeId,\n nodeToken: config.nodeToken,\n serviceToken: config.serviceToken,\n publicUrl: process.env.XPOD_PUBLIC_URL ?? config.publicUrl ?? process.env.CSS_BASE_URL,\n spDomain: process.env.XPOD_SP_DOMAIN ?? config.spDomain,\n localPort: readPositiveInteger(process.env.CSS_PORT ?? process.env.XPOD_PORT ?? process.env.PORT),\n tunnelToken: process.env.CLOUDFLARE_TUNNEL_TOKEN ?? process.env.SAKURA_TUNNEL_TOKEN ?? process.env.SAKURA_TOKEN,\n cloudBaseUrl: config.oidcIssuer || config.cloudApiEndpoint,\n provisionCode: process.env.XPOD_PROVISION_CODE ?? config.provisionCode,\n persistState: createLocalSetupProvisionStateWriter(\n config.localSetupPath,\n config.localSetupProviderId,\n ),\n });\n console.log('[Local] Provision status route registered (/provision/status)');\n } catch (error) {\n console.log(`[Local] Provision status route not registered: ${error}`);\n }\n}\n\nfunction readPositiveInteger(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const parsed = Number.parseInt(value, 10);\n return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;\n}\n\nfunction resolveNetworkEndpoint(config: ApiContainerConfig): string {\n const configured = config.publicUrl\n ?? config.activeTunnelProfile?.publicUrl\n ?? config.solidBaseUrl\n ?? `http://${config.host === '0.0.0.0' ? '127.0.0.1' : config.host}:${config.port}/`;\n try {\n return new URL(configured).toString().replace(/\\/+$/u, '') + '/';\n } catch {\n return `http://127.0.0.1:${config.port}/`;\n }\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ApiServer } from '../ApiServer';
|
|
2
|
+
import { DeviceNotificationTicketHandler } from './DeviceNotificationTicketHandler';
|
|
3
|
+
import { DeviceNotificationWebSocketServer } from '../../http/DeviceNotificationWebSocketServer';
|
|
4
|
+
import { DeviceNotificationHub } from '../../notifications/DeviceNotificationHub';
|
|
5
|
+
import { DeviceNotificationResourceListener } from '../../notifications/DeviceNotificationResourceListener';
|
|
6
|
+
import { XPOD_NOTIFICATIONS_PROTOCOL } from '../../notifications/device-notification-protocol';
|
|
7
|
+
export interface DeviceNotificationRuntimeOptions {
|
|
8
|
+
origin: string;
|
|
9
|
+
ticketEndpoint?: string;
|
|
10
|
+
webSocketEndpoint?: string;
|
|
11
|
+
ticketTtlMs?: number;
|
|
12
|
+
authorizeTopic?: ConstructorParameters<typeof DeviceNotificationHub>[0]['authorizeTopic'];
|
|
13
|
+
}
|
|
14
|
+
export interface DeviceNotificationRuntimeHandle {
|
|
15
|
+
hub: DeviceNotificationHub;
|
|
16
|
+
ticketHandler: DeviceNotificationTicketHandler;
|
|
17
|
+
webSocketServer: DeviceNotificationWebSocketServer;
|
|
18
|
+
resourceListener: DeviceNotificationResourceListener;
|
|
19
|
+
descriptor: {
|
|
20
|
+
protocol: typeof XPOD_NOTIFICATIONS_PROTOCOL;
|
|
21
|
+
ticketEndpoint: string;
|
|
22
|
+
webSocketEndpoint: string;
|
|
23
|
+
};
|
|
24
|
+
stop(): void;
|
|
25
|
+
}
|
|
26
|
+
export declare function registerDeviceNotificationRuntime(server: ApiServer, options: DeviceNotificationRuntimeOptions): DeviceNotificationRuntimeHandle;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDeviceNotificationRuntime = registerDeviceNotificationRuntime;
|
|
4
|
+
const DeviceNotificationTicketHandler_1 = require("./DeviceNotificationTicketHandler");
|
|
5
|
+
const DeviceNotificationWebSocketServer_1 = require("../../http/DeviceNotificationWebSocketServer");
|
|
6
|
+
const DeviceNotificationHub_1 = require("../../notifications/DeviceNotificationHub");
|
|
7
|
+
const DeviceNotificationResourceListener_1 = require("../../notifications/DeviceNotificationResourceListener");
|
|
8
|
+
const ObservableResourceStore_1 = require("../../storage/ObservableResourceStore");
|
|
9
|
+
const device_notification_protocol_1 = require("../../notifications/device-notification-protocol");
|
|
10
|
+
function registerDeviceNotificationRuntime(server, options) {
|
|
11
|
+
const ticketEndpoint = options.ticketEndpoint ?? '/v1/notifications/tickets';
|
|
12
|
+
const webSocketEndpoint = options.webSocketEndpoint ?? '/v1/notifications/ws';
|
|
13
|
+
const descriptor = {
|
|
14
|
+
protocol: device_notification_protocol_1.XPOD_NOTIFICATIONS_PROTOCOL,
|
|
15
|
+
ticketEndpoint,
|
|
16
|
+
webSocketEndpoint,
|
|
17
|
+
};
|
|
18
|
+
const hub = new DeviceNotificationHub_1.DeviceNotificationHub({
|
|
19
|
+
origin: options.origin,
|
|
20
|
+
authorizeTopic: options.authorizeTopic,
|
|
21
|
+
});
|
|
22
|
+
const ticketStore = new DeviceNotificationTicketHandler_1.DeviceNotificationTicketStore();
|
|
23
|
+
const ticketHandler = new DeviceNotificationTicketHandler_1.DeviceNotificationTicketHandler({
|
|
24
|
+
origin: options.origin,
|
|
25
|
+
webSocketEndpoint,
|
|
26
|
+
ticketTtlMs: options.ticketTtlMs,
|
|
27
|
+
ticketStore,
|
|
28
|
+
});
|
|
29
|
+
const webSocketServer = new DeviceNotificationWebSocketServer_1.DeviceNotificationWebSocketServer({
|
|
30
|
+
hub,
|
|
31
|
+
ticketStore,
|
|
32
|
+
path: webSocketEndpoint,
|
|
33
|
+
});
|
|
34
|
+
const resourceListener = new DeviceNotificationResourceListener_1.DeviceNotificationResourceListener({
|
|
35
|
+
origin: options.origin,
|
|
36
|
+
hub,
|
|
37
|
+
});
|
|
38
|
+
server.addResponseHeaders({
|
|
39
|
+
'X-Xpod-Notifications': JSON.stringify(descriptor),
|
|
40
|
+
});
|
|
41
|
+
server.post(ticketEndpoint, async (request, response) => {
|
|
42
|
+
await ticketHandler.handle(request, response);
|
|
43
|
+
});
|
|
44
|
+
server.get('/.well-known/xpod-notifications', async (_request, response) => {
|
|
45
|
+
sendJson(response, 200, descriptor);
|
|
46
|
+
}, { public: true });
|
|
47
|
+
server.addUpgradeHandler((request, socket, head) => {
|
|
48
|
+
webSocketServer.handleUpgrade(request, socket, head);
|
|
49
|
+
});
|
|
50
|
+
ObservableResourceStore_1.ObservableResourceStore.addGlobalListener(resourceListener);
|
|
51
|
+
server.addShutdownHandler(() => {
|
|
52
|
+
webSocketServer.stop();
|
|
53
|
+
ticketStore.clear();
|
|
54
|
+
ObservableResourceStore_1.ObservableResourceStore.removeGlobalListener(resourceListener);
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
hub,
|
|
58
|
+
ticketHandler,
|
|
59
|
+
webSocketServer,
|
|
60
|
+
resourceListener,
|
|
61
|
+
descriptor,
|
|
62
|
+
stop: () => {
|
|
63
|
+
webSocketServer.stop();
|
|
64
|
+
ticketStore.clear();
|
|
65
|
+
ObservableResourceStore_1.ObservableResourceStore.removeGlobalListener(resourceListener);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function sendJson(response, status, body) {
|
|
70
|
+
const encoded = JSON.stringify(body);
|
|
71
|
+
response.writeHead(status, {
|
|
72
|
+
'Content-Type': 'application/json',
|
|
73
|
+
'Content-Length': Buffer.byteLength(encoded),
|
|
74
|
+
});
|
|
75
|
+
response.end(encoded);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=DeviceNotificationRuntime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeviceNotificationRuntime.js","sourceRoot":"","sources":["../../../src/api/handlers/DeviceNotificationRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse } from 'node:http';\nimport type { ApiServer } from '../ApiServer';\nimport { DeviceNotificationTicketHandler, DeviceNotificationTicketStore } from './DeviceNotificationTicketHandler';\nimport { DeviceNotificationWebSocketServer } from '../../http/DeviceNotificationWebSocketServer';\nimport { DeviceNotificationHub } from '../../notifications/DeviceNotificationHub';\nimport { DeviceNotificationResourceListener } from '../../notifications/DeviceNotificationResourceListener';\nimport { ObservableResourceStore } from '../../storage/ObservableResourceStore';\nimport { XPOD_NOTIFICATIONS_PROTOCOL } from '../../notifications/device-notification-protocol';\nimport type { AuthenticatedRequest } from '../middleware/AuthMiddleware';\n\nexport interface DeviceNotificationRuntimeOptions {\n origin: string;\n ticketEndpoint?: string;\n webSocketEndpoint?: string;\n ticketTtlMs?: number;\n authorizeTopic?: ConstructorParameters<typeof DeviceNotificationHub>[0]['authorizeTopic'];\n}\n\nexport interface DeviceNotificationRuntimeHandle {\n hub: DeviceNotificationHub;\n ticketHandler: DeviceNotificationTicketHandler;\n webSocketServer: DeviceNotificationWebSocketServer;\n resourceListener: DeviceNotificationResourceListener;\n descriptor: {\n protocol: typeof XPOD_NOTIFICATIONS_PROTOCOL;\n ticketEndpoint: string;\n webSocketEndpoint: string;\n };\n stop(): void;\n}\n\nexport function registerDeviceNotificationRuntime(\n server: ApiServer,\n options: DeviceNotificationRuntimeOptions,\n): DeviceNotificationRuntimeHandle {\n const ticketEndpoint = options.ticketEndpoint ?? '/v1/notifications/tickets';\n const webSocketEndpoint = options.webSocketEndpoint ?? '/v1/notifications/ws';\n const descriptor: DeviceNotificationRuntimeHandle['descriptor'] = {\n protocol: XPOD_NOTIFICATIONS_PROTOCOL,\n ticketEndpoint,\n webSocketEndpoint,\n };\n const hub = new DeviceNotificationHub({\n origin: options.origin,\n authorizeTopic: options.authorizeTopic,\n });\n const ticketStore = new DeviceNotificationTicketStore();\n const ticketHandler = new DeviceNotificationTicketHandler({\n origin: options.origin,\n webSocketEndpoint,\n ticketTtlMs: options.ticketTtlMs,\n ticketStore,\n });\n const webSocketServer = new DeviceNotificationWebSocketServer({\n hub,\n ticketStore,\n path: webSocketEndpoint,\n });\n const resourceListener = new DeviceNotificationResourceListener({\n origin: options.origin,\n hub,\n });\n\n server.addResponseHeaders({\n 'X-Xpod-Notifications': JSON.stringify(descriptor),\n });\n server.post(ticketEndpoint, async (request, response) => {\n await ticketHandler.handle(request as AuthenticatedRequest, response);\n });\n server.get('/.well-known/xpod-notifications', async (_request, response) => {\n sendJson(response, 200, descriptor);\n }, { public: true });\n server.addUpgradeHandler((request, socket, head) => {\n webSocketServer.handleUpgrade(request, socket, head);\n });\n ObservableResourceStore.addGlobalListener(resourceListener);\n server.addShutdownHandler(() => {\n webSocketServer.stop();\n ticketStore.clear();\n ObservableResourceStore.removeGlobalListener(resourceListener);\n });\n\n return {\n hub,\n ticketHandler,\n webSocketServer,\n resourceListener,\n descriptor,\n stop: () => {\n webSocketServer.stop();\n ticketStore.clear();\n ObservableResourceStore.removeGlobalListener(resourceListener);\n },\n };\n}\n\nfunction sendJson(response: ServerResponse, status: number, body: unknown): void {\n const encoded = JSON.stringify(body);\n response.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(encoded),\n });\n response.end(encoded);\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { AuthContext } from '../auth/AuthContext';
|
|
3
|
+
export interface DeviceNotificationIdentity {
|
|
4
|
+
webId: string;
|
|
5
|
+
localPart: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DeviceNotificationTicketRecord {
|
|
8
|
+
digest: string;
|
|
9
|
+
identity: DeviceNotificationIdentity;
|
|
10
|
+
deviceSessionId: string;
|
|
11
|
+
origin: string;
|
|
12
|
+
expiresAt: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class DeviceNotificationTicketStore {
|
|
15
|
+
private readonly records;
|
|
16
|
+
mint(input: {
|
|
17
|
+
identity: DeviceNotificationIdentity;
|
|
18
|
+
deviceSessionId: string;
|
|
19
|
+
origin: string;
|
|
20
|
+
ttlMs: number;
|
|
21
|
+
}): string;
|
|
22
|
+
consume(ticket: string): DeviceNotificationTicketRecord | undefined;
|
|
23
|
+
size(): number;
|
|
24
|
+
clear(): void;
|
|
25
|
+
private digest;
|
|
26
|
+
}
|
|
27
|
+
export interface DeviceNotificationTicketHandlerOptions {
|
|
28
|
+
webSocketEndpoint: string;
|
|
29
|
+
origin: string;
|
|
30
|
+
ticketTtlMs?: number;
|
|
31
|
+
ticketStore?: DeviceNotificationTicketStore;
|
|
32
|
+
}
|
|
33
|
+
type TicketRequest = IncomingMessage & {
|
|
34
|
+
auth?: AuthContext | {
|
|
35
|
+
webId?: string;
|
|
36
|
+
localPart?: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export declare class DeviceNotificationTicketHandler {
|
|
40
|
+
readonly ticketStore: DeviceNotificationTicketStore;
|
|
41
|
+
private readonly webSocketEndpoint;
|
|
42
|
+
private readonly origin;
|
|
43
|
+
private readonly ticketTtlMs;
|
|
44
|
+
constructor(options: DeviceNotificationTicketHandlerOptions);
|
|
45
|
+
handle(request: TicketRequest, response: ServerResponse): Promise<void>;
|
|
46
|
+
private extractIdentity;
|
|
47
|
+
private readJson;
|
|
48
|
+
private sendJson;
|
|
49
|
+
}
|
|
50
|
+
export {};
|