@livequery/core 2.0.103 → 2.0.105

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.
Files changed (95) hide show
  1. package/README.md +569 -314
  2. package/build/src/ApiGatewayHandler.d.ts +56 -0
  3. package/build/src/ApiGatewayHandler.js +210 -0
  4. package/build/src/ApiGatewayHandler.js.map +1 -0
  5. package/build/src/ApiGatewayLinker.d.ts +61 -0
  6. package/build/src/ApiGatewayLinker.js +229 -0
  7. package/build/src/ApiGatewayLinker.js.map +1 -0
  8. package/build/src/ApiServiceLinker.d.ts +18 -0
  9. package/build/src/ApiServiceLinker.js +61 -0
  10. package/build/src/ApiServiceLinker.js.map +1 -0
  11. package/build/src/LivequeryContext.d.ts +43 -0
  12. package/build/src/LivequeryContext.js +2 -0
  13. package/build/src/LivequeryContext.js.map +1 -0
  14. package/build/src/LivequeryDatasource.d.ts +8 -0
  15. package/build/src/LivequeryDatasource.js +2 -0
  16. package/build/src/LivequeryDatasource.js.map +1 -0
  17. package/build/src/LivequeryRequestParser.d.ts +13 -0
  18. package/build/src/LivequeryRequestParser.js +34 -0
  19. package/build/src/LivequeryRequestParser.js.map +1 -0
  20. package/build/src/UdpDiscovery.d.ts +26 -0
  21. package/build/src/UdpDiscovery.js +238 -0
  22. package/build/src/UdpDiscovery.js.map +1 -0
  23. package/build/src/WebsocketGateway.d.ts +36 -0
  24. package/build/src/WebsocketGateway.js +353 -0
  25. package/build/src/WebsocketGateway.js.map +1 -0
  26. package/build/src/const.d.ts +8 -0
  27. package/build/src/const.js +10 -0
  28. package/build/src/const.js.map +1 -0
  29. package/build/src/headers.d.ts +9 -0
  30. package/build/src/headers.js +32 -0
  31. package/build/src/headers.js.map +1 -0
  32. package/build/src/helpers/PathHelper.d.ts +11 -0
  33. package/build/src/helpers/PathHelper.js +41 -0
  34. package/build/src/helpers/PathHelper.js.map +1 -0
  35. package/build/src/helpers/hidePrivateFields.d.ts +3 -0
  36. package/build/src/helpers/hidePrivateFields.js +29 -0
  37. package/build/src/helpers/hidePrivateFields.js.map +1 -0
  38. package/build/src/helpers/nodeRequestToWebRequest.d.ts +7 -0
  39. package/build/src/helpers/nodeRequestToWebRequest.js +17 -0
  40. package/build/src/helpers/nodeRequestToWebRequest.js.map +1 -0
  41. package/build/src/helpers/writeWebResponse.d.ts +2 -0
  42. package/build/src/helpers/writeWebResponse.js +9 -0
  43. package/build/src/helpers/writeWebResponse.js.map +1 -0
  44. package/build/src/index.d.ts +9 -0
  45. package/build/src/index.js +10 -0
  46. package/build/src/index.js.map +1 -0
  47. package/build/src/parseLivequeryRequest.d.ts +10 -0
  48. package/build/src/parseLivequeryRequest.js +17 -0
  49. package/build/src/parseLivequeryRequest.js.map +1 -0
  50. package/build/tsconfig.tsbuildinfo +1 -0
  51. package/package.json +39 -103
  52. package/dist/LivequeryCollection.d.ts +0 -182
  53. package/dist/LivequeryCollection.d.ts.map +0 -1
  54. package/dist/LivequeryCollection.js +0 -231
  55. package/dist/LivequeryCollection.js.map +0 -1
  56. package/dist/LivequeryCore.d.ts +0 -157
  57. package/dist/LivequeryCore.d.ts.map +0 -1
  58. package/dist/LivequeryCore.js +0 -343
  59. package/dist/LivequeryCore.js.map +0 -1
  60. package/dist/LivequeryDocument.d.ts +0 -15
  61. package/dist/LivequeryDocument.d.ts.map +0 -1
  62. package/dist/LivequeryDocument.js +0 -22
  63. package/dist/LivequeryDocument.js.map +0 -1
  64. package/dist/LivequeryMemoryStorage.d.ts +0 -14
  65. package/dist/LivequeryMemoryStorage.d.ts.map +0 -1
  66. package/dist/LivequeryMemoryStorage.js +0 -89
  67. package/dist/LivequeryMemoryStorage.js.map +0 -1
  68. package/dist/LivequeryStorge.d.ts +0 -12
  69. package/dist/LivequeryStorge.d.ts.map +0 -1
  70. package/dist/LivequeryStorge.js +0 -2
  71. package/dist/LivequeryStorge.js.map +0 -1
  72. package/dist/LivequeryTransporter.d.ts +0 -22
  73. package/dist/LivequeryTransporter.d.ts.map +0 -1
  74. package/dist/LivequeryTransporter.js +0 -2
  75. package/dist/LivequeryTransporter.js.map +0 -1
  76. package/dist/helpers/filterDocs.d.ts +0 -5
  77. package/dist/helpers/filterDocs.d.ts.map +0 -1
  78. package/dist/helpers/filterDocs.js +0 -80
  79. package/dist/helpers/filterDocs.js.map +0 -1
  80. package/dist/helpers/tryCatch.d.ts +0 -2
  81. package/dist/helpers/tryCatch.d.ts.map +0 -1
  82. package/dist/helpers/tryCatch.js +0 -10
  83. package/dist/helpers/tryCatch.js.map +0 -1
  84. package/dist/helpers/whenCompleted.d.ts +0 -3
  85. package/dist/helpers/whenCompleted.d.ts.map +0 -1
  86. package/dist/helpers/whenCompleted.js +0 -5
  87. package/dist/helpers/whenCompleted.js.map +0 -1
  88. package/dist/index.d.ts +0 -9
  89. package/dist/index.d.ts.map +0 -1
  90. package/dist/index.js +0 -9
  91. package/dist/index.js.map +0 -1
  92. package/dist/types.d.ts +0 -70
  93. package/dist/types.d.ts.map +0 -1
  94. package/dist/types.js +0 -2
  95. package/dist/types.js.map +0 -1
@@ -0,0 +1,56 @@
1
+ import type { IncomingMessage, OutgoingHttpHeaders, ServerResponse } from 'http';
2
+ import { UdpDiscovery, type UdpDiscoveryNode } from './UdpDiscovery.js';
3
+ import { WebsocketGateway } from './WebsocketGateway.js';
4
+ export type RegisterOptions = {
5
+ node_id: string;
6
+ hostname: string;
7
+ port: number;
8
+ paths: Array<{
9
+ method: string;
10
+ path: string;
11
+ }>;
12
+ };
13
+ export type ServiceApiMetadata = UdpDiscoveryNode & {
14
+ role: 'service' | 'gateway';
15
+ name: string;
16
+ port: number;
17
+ paths: Array<{
18
+ method: string;
19
+ path: string;
20
+ }>;
21
+ linked: string[];
22
+ target?: string;
23
+ ws?: {
24
+ path: string;
25
+ auth: string;
26
+ };
27
+ };
28
+ export type ServiceApiStatus = {
29
+ id: string;
30
+ online: boolean;
31
+ metadata?: ServiceApiMetadata;
32
+ } | {
33
+ id: string;
34
+ online: false;
35
+ };
36
+ export type ApiGatewayOptions = {
37
+ ws?: WebsocketGateway;
38
+ discovery?: UdpDiscovery<ServiceApiMetadata>;
39
+ node_id?: string;
40
+ };
41
+ export declare class ApiGatewayHandler {
42
+ #private;
43
+ private options;
44
+ readonly restGateway: this;
45
+ constructor(options: ApiGatewayOptions);
46
+ register({ node_id, hostname, port, paths }: RegisterOptions): void;
47
+ deregister(node_id: string): void;
48
+ fetch(request: Request): Promise<Response>;
49
+ fetch(req: IncomingMessage & {
50
+ url: string;
51
+ method: string;
52
+ rawBody?: Buffer;
53
+ }, res: ServerResponse, extraHeaders?: OutgoingHttpHeaders): Promise<void>;
54
+ fetchRequest(request: Request): Promise<Response>;
55
+ close(): void;
56
+ }
@@ -0,0 +1,210 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { API_GATEWAY_NAMESPACE, LIVEQUERY_API_GATEWAY_DEBUG, LIVEQUERY_MAGIC_KEY, WEBSOCKET_PATH, } from './const.js';
3
+ import { UdpDiscovery } from './UdpDiscovery.js';
4
+ import { nodeRequestToWebRequest } from './helpers/nodeRequestToWebRequest.js';
5
+ import { writeWebResponse } from './helpers/writeWebResponse.js';
6
+ function createNode() {
7
+ return { children: {}, paramPrefixes: [], methods: {} };
8
+ }
9
+ function normalizeSegment(seg) {
10
+ return seg.includes(':') ? seg.split(':')[0] + ':' : seg;
11
+ }
12
+ function isSameServiceDefinition(a, b) {
13
+ return a.port === b.port
14
+ && JSON.stringify(a.paths) === JSON.stringify(b.paths)
15
+ && a.ws?.path === b.ws?.path
16
+ && a.ws?.auth === b.ws?.auth;
17
+ }
18
+ export class ApiGatewayHandler {
19
+ options;
20
+ restGateway = this;
21
+ #root = createNode();
22
+ #nodeId;
23
+ #lws;
24
+ #discovery;
25
+ #discoverySubscription;
26
+ #services = new Map();
27
+ constructor(options) {
28
+ this.options = options;
29
+ this.#nodeId = options.node_id ?? randomUUID();
30
+ this.#lws = options.ws;
31
+ this.#discovery = options.discovery ?? new UdpDiscovery({ key: LIVEQUERY_MAGIC_KEY });
32
+ this.#discoverySubscription = this.#discovery.subscribe(metadata => {
33
+ if (metadata.role !== 'service')
34
+ return;
35
+ if (metadata.namespace !== API_GATEWAY_NAMESPACE)
36
+ return;
37
+ if (metadata.node_id === this.#nodeId)
38
+ return;
39
+ const existing = this.#services.get(metadata.node_id);
40
+ if (existing) {
41
+ if (metadata.version <= existing.metadata.version)
42
+ return;
43
+ if (isSameServiceDefinition(existing.metadata, metadata)) {
44
+ existing.metadata = { ...metadata, host: existing.host };
45
+ return;
46
+ }
47
+ this.#removeService(metadata.node_id, false);
48
+ }
49
+ this.#join(metadata);
50
+ });
51
+ this.#discovery.broadcast(this.#metadata()).catch(e => console.error(e));
52
+ }
53
+ register({ node_id, hostname, port, paths }) {
54
+ const uri = `${hostname}:${port}`;
55
+ for (const { method, path } of paths) {
56
+ const segments = path.split('/').filter(Boolean).map(normalizeSegment);
57
+ let node = this.#root;
58
+ for (const seg of segments) {
59
+ if (!node.children[seg])
60
+ node.children[seg] = createNode();
61
+ if (seg !== ':' && seg.endsWith(':')) {
62
+ const prefix = seg.slice(0, -1);
63
+ if (!node.paramPrefixes.includes(prefix))
64
+ node.paramPrefixes.push(prefix);
65
+ }
66
+ node = node.children[seg];
67
+ }
68
+ const METHOD = method.toUpperCase();
69
+ if (!node.methods[METHOD])
70
+ node.methods[METHOD] = { hosts: [], rr_index: 0 };
71
+ const exists = node.methods[METHOD].hosts.some(host => host.node_id === node_id && host.uri === uri);
72
+ if (!exists)
73
+ node.methods[METHOD].hosts.push({ node_id, uri });
74
+ }
75
+ }
76
+ deregister(node_id) {
77
+ const queue = [this.#root];
78
+ while (queue.length > 0) {
79
+ const node = queue.shift();
80
+ for (const entry of Object.values(node.methods)) {
81
+ entry.hosts = entry.hosts.filter(host => host.node_id !== node_id);
82
+ }
83
+ queue.push(...Object.values(node.children));
84
+ }
85
+ }
86
+ async fetch(requestOrReq, res, extraHeaders) {
87
+ if (requestOrReq instanceof Request) {
88
+ const client_id = requestOrReq.headers.get('x-lcid') ?? requestOrReq.headers.get('socket_id');
89
+ const extraHeaders = client_id && this.options.ws ? {
90
+ 'x-lcid': client_id,
91
+ 'x-lgid': requestOrReq.headers.get('x-lgid') || this.options.ws?.id || this.#nodeId,
92
+ } : {};
93
+ return this.#fetchRequest(requestOrReq, extraHeaders);
94
+ }
95
+ if (!res)
96
+ throw new Error('ServerResponse is required for Node.js requests');
97
+ const response = await this.#fetchRequest(nodeRequestToWebRequest(requestOrReq, extraHeaders), extraHeaders);
98
+ await writeWebResponse(res, response);
99
+ }
100
+ fetchRequest(request) {
101
+ return this.fetch(request);
102
+ }
103
+ close() {
104
+ this.#discoverySubscription.unsubscribe();
105
+ for (const { subscription } of this.#services.values()) {
106
+ subscription?.unsubscribe();
107
+ }
108
+ this.#services.clear();
109
+ this.#discovery.close();
110
+ }
111
+ async #fetchRequest(request, extraHeaders) {
112
+ const url = new URL(request.url);
113
+ const target = this.#resolve(url.pathname, request.method);
114
+ if (target === undefined) {
115
+ return Response.json({ error: { status: 404, code: 'API_NOT_FOUND' } }, { status: 404 });
116
+ }
117
+ if (target === null) {
118
+ return Response.json({ error: { status: 503, code: 'API_OFFLINE' } }, { status: 503 });
119
+ }
120
+ const headers = new Headers(request.headers);
121
+ headers.delete('content-length');
122
+ headers.delete('host');
123
+ if (extraHeaders) {
124
+ new Headers(extraHeaders).forEach((value, key) => headers.set(key, value));
125
+ }
126
+ const body = request.method === 'GET' || request.method === 'HEAD' ? undefined : request.body;
127
+ try {
128
+ return await globalThis.fetch(`http://${target.uri}${url.pathname}${url.search}`, {
129
+ method: request.method,
130
+ headers,
131
+ body,
132
+ duplex: 'half',
133
+ });
134
+ }
135
+ catch {
136
+ this.deregister(target.node_id);
137
+ return Response.json({ error: { status: 502, code: 'SERVICE_API_OFFLINE' } }, { status: 502 });
138
+ }
139
+ }
140
+ #matchChild(node, segment) {
141
+ if (node.children[segment])
142
+ return node.children[segment];
143
+ for (const prefix of node.paramPrefixes) {
144
+ if (segment.startsWith(prefix))
145
+ return node.children[prefix + ':'];
146
+ }
147
+ return node.children[':'];
148
+ }
149
+ #resolve(path, method) {
150
+ const segments = path.split('?')[0].split('/').filter(Boolean);
151
+ let node = this.#root;
152
+ for (const segment of segments) {
153
+ node = this.#matchChild(node, segment);
154
+ if (!node)
155
+ return undefined;
156
+ }
157
+ const entry = node.methods[method.toUpperCase()];
158
+ if (!entry)
159
+ return undefined;
160
+ if (entry.hosts.length === 0)
161
+ return null;
162
+ const host = entry.hosts[entry.rr_index % entry.hosts.length];
163
+ entry.rr_index++;
164
+ return host;
165
+ }
166
+ #join(metadata) {
167
+ const { port, node_id, name, paths, ws } = metadata;
168
+ const host = metadata.host ?? '';
169
+ const subscription = ws
170
+ ? this.#lws?.connect(`ws://${host}:${port}${ws.path}`, ws.auth, () => this.#disconnect(node_id))
171
+ : undefined;
172
+ this.#services.set(node_id, { metadata, subscription, host });
173
+ this.register({ node_id, hostname: host, port, paths: paths ?? [] });
174
+ LIVEQUERY_API_GATEWAY_DEBUG && console.info(`[${new Date().toLocaleString()}] Service API online: ${name} at ${host}:${port}`);
175
+ }
176
+ #disconnect(id) {
177
+ this.#removeService(id, true);
178
+ }
179
+ #removeService(id, logOffline) {
180
+ const service = this.#services.get(id);
181
+ if (!service)
182
+ return;
183
+ const { metadata: { name, port }, subscription, host } = service;
184
+ subscription?.unsubscribe();
185
+ this.#services.delete(id);
186
+ this.deregister(id);
187
+ logOffline && LIVEQUERY_API_GATEWAY_DEBUG && console.error(`[${new Date().toLocaleString()}] Service API OFFLINE: ${name} at ${host}:${port}`);
188
+ }
189
+ #metadata() {
190
+ const metadata = {
191
+ name: 'API gateway',
192
+ paths: [],
193
+ port: 0,
194
+ role: 'gateway',
195
+ linked: [...this.#services.keys()],
196
+ host: '',
197
+ node_id: this.#nodeId,
198
+ namespace: API_GATEWAY_NAMESPACE,
199
+ version: Date.now(),
200
+ };
201
+ if (this.#lws) {
202
+ metadata.ws = {
203
+ auth: this.#lws.auth,
204
+ path: WEBSOCKET_PATH,
205
+ };
206
+ }
207
+ return metadata;
208
+ }
209
+ }
210
+ //# sourceMappingURL=ApiGatewayHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiGatewayHandler.js","sourceRoot":"","sources":["../../src/ApiGatewayHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { IncomingMessage, OutgoingHttpHeaders, ServerResponse } from 'http';
2
+ import type { LivequeryHandler } from './LivequeryContext.js';
3
+ import { UdpDiscovery, type UdpDiscoveryNode } from './UdpDiscovery.js';
4
+ import { WebsocketGateway } from './WebsocketGateway.js';
5
+ export type RegisterOptions = {
6
+ node_id: string;
7
+ hostname: string;
8
+ port: number;
9
+ paths: Array<{
10
+ method: string;
11
+ path: string;
12
+ }>;
13
+ };
14
+ export type ServiceApiMetadata = UdpDiscoveryNode & {
15
+ role: 'service' | 'gateway';
16
+ name: string;
17
+ port: number;
18
+ paths: Array<{
19
+ method: string;
20
+ path: string;
21
+ }>;
22
+ linked: string[];
23
+ target?: string;
24
+ ws?: {
25
+ path: string;
26
+ auth: string;
27
+ };
28
+ };
29
+ export type ServiceApiStatus = {
30
+ id: string;
31
+ online: boolean;
32
+ metadata?: ServiceApiMetadata;
33
+ } | {
34
+ id: string;
35
+ online: false;
36
+ };
37
+ export type ApiGatewayOptions<Handler extends LivequeryHandler = LivequeryHandler> = {
38
+ websocketGateway?: WebsocketGateway;
39
+ discovery?: UdpDiscovery<ServiceApiMetadata>;
40
+ nodeId?: string;
41
+ restGateway?: Handler;
42
+ };
43
+ export declare class ApiGateway<Handler extends LivequeryHandler = LivequeryHandler> {
44
+ #private;
45
+ readonly restGateway: this;
46
+ constructor(options?: ApiGatewayOptions<Handler>);
47
+ register({ node_id, hostname, port, paths }: RegisterOptions): void;
48
+ deregister(node_id: string): void;
49
+ fetch(request: Request): Promise<Response>;
50
+ fetch(req: IncomingMessage & {
51
+ url: string;
52
+ method: string;
53
+ rawBody?: Buffer;
54
+ }, res: ServerResponse, extraHeaders?: OutgoingHttpHeaders): Promise<void>;
55
+ fetchRequest(request: Request): Promise<Response>;
56
+ close(): void;
57
+ }
58
+ export { ApiGateway as ApiGatewayLinker };
59
+ export { ApiGateway as FetchApiGateway };
60
+ export { ApiGateway as SimpleApiGateway };
61
+ export type ApiGatewayLinkerOptions<Handler extends LivequeryHandler = LivequeryHandler> = ApiGatewayOptions<Handler>;
@@ -0,0 +1,229 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { API_GATEWAY_NAMESPACE, LIVEQUERY_API_GATEWAY_DEBUG, LIVEQUERY_MAGIC_KEY, WEBSOCKET_PATH, } from './const.js';
3
+ import { createRealtimeForwardHeaders } from './headers.js';
4
+ import { UdpDiscovery } from './UdpDiscovery.js';
5
+ function createNode() {
6
+ return { children: {}, paramPrefixes: [], methods: {} };
7
+ }
8
+ function normalizeSegment(seg) {
9
+ return seg.includes(':') ? seg.split(':')[0] + ':' : seg;
10
+ }
11
+ function isSameServiceDefinition(a, b) {
12
+ return a.port === b.port
13
+ && JSON.stringify(a.paths) === JSON.stringify(b.paths)
14
+ && a.ws?.path === b.ws?.path
15
+ && a.ws?.auth === b.ws?.auth;
16
+ }
17
+ export class ApiGateway {
18
+ restGateway = this;
19
+ #root = createNode();
20
+ #nodeId;
21
+ #lws;
22
+ #discovery;
23
+ #discoverySubscription;
24
+ #services = new Map();
25
+ constructor(options = {}) {
26
+ this.#nodeId = options.nodeId ?? randomUUID();
27
+ this.#lws = options.websocketGateway;
28
+ this.#discovery = options.discovery ?? new UdpDiscovery({ key: LIVEQUERY_MAGIC_KEY });
29
+ this.#discoverySubscription = this.#discovery.subscribe(metadata => {
30
+ if (metadata.role !== 'service')
31
+ return;
32
+ if (metadata.namespace !== API_GATEWAY_NAMESPACE)
33
+ return;
34
+ if (metadata.node_id === this.#nodeId)
35
+ return;
36
+ const existing = this.#services.get(metadata.node_id);
37
+ if (existing) {
38
+ if (metadata.version <= existing.metadata.version)
39
+ return;
40
+ if (isSameServiceDefinition(existing.metadata, metadata)) {
41
+ existing.metadata = { ...metadata, host: existing.host };
42
+ return;
43
+ }
44
+ this.#removeService(metadata.node_id, false);
45
+ }
46
+ this.#join(metadata);
47
+ });
48
+ this.#discovery.broadcast(this.#metadata()).catch(e => console.error(e));
49
+ }
50
+ register({ node_id, hostname, port, paths }) {
51
+ const uri = `${hostname}:${port}`;
52
+ for (const { method, path } of paths) {
53
+ const segments = path.split('/').filter(Boolean).map(normalizeSegment);
54
+ let node = this.#root;
55
+ for (const seg of segments) {
56
+ if (!node.children[seg])
57
+ node.children[seg] = createNode();
58
+ if (seg !== ':' && seg.endsWith(':')) {
59
+ const prefix = seg.slice(0, -1);
60
+ if (!node.paramPrefixes.includes(prefix))
61
+ node.paramPrefixes.push(prefix);
62
+ }
63
+ node = node.children[seg];
64
+ }
65
+ const METHOD = method.toUpperCase();
66
+ if (!node.methods[METHOD])
67
+ node.methods[METHOD] = { hosts: [], rr_index: 0 };
68
+ const exists = node.methods[METHOD].hosts.some(host => host.node_id === node_id && host.uri === uri);
69
+ if (!exists)
70
+ node.methods[METHOD].hosts.push({ node_id, uri });
71
+ }
72
+ }
73
+ deregister(node_id) {
74
+ const queue = [this.#root];
75
+ while (queue.length > 0) {
76
+ const node = queue.shift();
77
+ for (const entry of Object.values(node.methods)) {
78
+ entry.hosts = entry.hosts.filter(host => host.node_id !== node_id);
79
+ }
80
+ queue.push(...Object.values(node.children));
81
+ }
82
+ }
83
+ async fetch(requestOrReq, res, extraHeaders) {
84
+ if (requestOrReq instanceof Request) {
85
+ return this.#fetchRequest(requestOrReq, createRealtimeForwardHeaders(requestOrReq, this.#lws?.id));
86
+ }
87
+ if (!res)
88
+ throw new Error('ServerResponse is required for Node.js requests');
89
+ const response = await this.#fetchRequest(nodeRequestToWebRequest(requestOrReq, extraHeaders), extraHeaders);
90
+ await writeWebResponse(res, response);
91
+ }
92
+ fetchRequest(request) {
93
+ return this.fetch(request);
94
+ }
95
+ close() {
96
+ this.#discoverySubscription.unsubscribe();
97
+ for (const { subscription } of this.#services.values()) {
98
+ subscription?.unsubscribe();
99
+ }
100
+ this.#services.clear();
101
+ this.#discovery.close();
102
+ }
103
+ async #fetchRequest(request, extraHeaders) {
104
+ const url = new URL(request.url);
105
+ const target = this.#resolve(url.pathname, request.method);
106
+ if (target === undefined) {
107
+ return Response.json({ error: { status: 404, code: 'API_NOT_FOUND' } }, { status: 404 });
108
+ }
109
+ if (target === null) {
110
+ return Response.json({ error: { status: 503, code: 'API_OFFLINE' } }, { status: 503 });
111
+ }
112
+ const headers = new Headers(request.headers);
113
+ headers.delete('content-length');
114
+ headers.delete('host');
115
+ if (extraHeaders) {
116
+ new Headers(extraHeaders).forEach((value, key) => headers.set(key, value));
117
+ }
118
+ const body = request.method === 'GET' || request.method === 'HEAD' ? undefined : request.body;
119
+ try {
120
+ return await globalThis.fetch(`http://${target.uri}${url.pathname}${url.search}`, {
121
+ method: request.method,
122
+ headers,
123
+ body,
124
+ duplex: 'half',
125
+ });
126
+ }
127
+ catch {
128
+ this.deregister(target.node_id);
129
+ return Response.json({ error: { status: 502, code: 'SERVICE_API_OFFLINE' } }, { status: 502 });
130
+ }
131
+ }
132
+ #matchChild(node, segment) {
133
+ if (node.children[segment])
134
+ return node.children[segment];
135
+ for (const prefix of node.paramPrefixes) {
136
+ if (segment.startsWith(prefix))
137
+ return node.children[prefix + ':'];
138
+ }
139
+ return node.children[':'];
140
+ }
141
+ #resolve(path, method) {
142
+ const segments = path.split('?')[0].split('/').filter(Boolean);
143
+ let node = this.#root;
144
+ for (const segment of segments) {
145
+ node = this.#matchChild(node, segment);
146
+ if (!node)
147
+ return undefined;
148
+ }
149
+ const entry = node.methods[method.toUpperCase()];
150
+ if (!entry)
151
+ return undefined;
152
+ if (entry.hosts.length === 0)
153
+ return null;
154
+ const host = entry.hosts[entry.rr_index % entry.hosts.length];
155
+ entry.rr_index++;
156
+ return host;
157
+ }
158
+ #join(metadata) {
159
+ const { port, node_id, name, paths, ws } = metadata;
160
+ const host = metadata.host ?? '';
161
+ const subscription = ws
162
+ ? this.#lws?.connect(`ws://${host}:${port}${ws.path}`, ws.auth, () => this.#disconnect(node_id))
163
+ : undefined;
164
+ this.#services.set(node_id, { metadata, subscription, host });
165
+ this.register({ node_id, hostname: host, port, paths: paths ?? [] });
166
+ LIVEQUERY_API_GATEWAY_DEBUG && console.info(`[${new Date().toLocaleString()}] Service API online: ${name} at ${host}:${port}`);
167
+ }
168
+ #disconnect(id) {
169
+ this.#removeService(id, true);
170
+ }
171
+ #removeService(id, logOffline) {
172
+ const service = this.#services.get(id);
173
+ if (!service)
174
+ return;
175
+ const { metadata: { name, port }, subscription, host } = service;
176
+ subscription?.unsubscribe();
177
+ this.#services.delete(id);
178
+ this.deregister(id);
179
+ logOffline && LIVEQUERY_API_GATEWAY_DEBUG && console.error(`[${new Date().toLocaleString()}] Service API OFFLINE: ${name} at ${host}:${port}`);
180
+ }
181
+ #metadata() {
182
+ const metadata = {
183
+ name: 'API gateway',
184
+ paths: [],
185
+ port: 0,
186
+ role: 'gateway',
187
+ linked: [...this.#services.keys()],
188
+ host: '',
189
+ node_id: this.#nodeId,
190
+ namespace: API_GATEWAY_NAMESPACE,
191
+ version: Date.now(),
192
+ };
193
+ if (this.#lws) {
194
+ metadata.ws = {
195
+ auth: this.#lws.auth,
196
+ path: WEBSOCKET_PATH,
197
+ };
198
+ }
199
+ return metadata;
200
+ }
201
+ }
202
+ function nodeRequestToWebRequest(req, extraHeaders) {
203
+ const host = req.headers.host ?? '127.0.0.1';
204
+ const headers = new Headers(req.headers);
205
+ if (extraHeaders) {
206
+ new Headers(extraHeaders).forEach((value, key) => headers.set(key, value));
207
+ }
208
+ const body = req.method === 'GET' || req.method === 'HEAD'
209
+ ? undefined
210
+ : req.rawBody ? new Uint8Array(req.rawBody) : undefined;
211
+ return new Request(`http://${host}${req.url}`, {
212
+ method: req.method,
213
+ headers,
214
+ body,
215
+ duplex: body ? 'half' : undefined,
216
+ });
217
+ }
218
+ async function writeWebResponse(res, response) {
219
+ const headers = {};
220
+ response.headers.forEach((value, key) => {
221
+ headers[key] = value;
222
+ });
223
+ res.writeHead(response.status, headers);
224
+ res.end(Buffer.from(await response.arrayBuffer()));
225
+ }
226
+ export { ApiGateway as ApiGatewayLinker };
227
+ export { ApiGateway as FetchApiGateway };
228
+ export { ApiGateway as SimpleApiGateway };
229
+ //# sourceMappingURL=ApiGatewayLinker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiGatewayLinker.js","sourceRoot":"","sources":["../../src/ApiGatewayLinker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { UdpDiscovery } from './UdpDiscovery.js';
2
+ import { WebsocketGateway } from './WebsocketGateway.js';
3
+ import { ServiceApiMetadata } from './ApiGatewayHandler.js';
4
+ export type ApiServiceLinkerOptions = {
5
+ paths: Array<{
6
+ method: string;
7
+ path: string;
8
+ }>;
9
+ ws?: WebsocketGateway;
10
+ discovery?: UdpDiscovery<ServiceApiMetadata>;
11
+ node_id?: string;
12
+ };
13
+ export declare class ApiServiceLinker {
14
+ #private;
15
+ constructor(options: ApiServiceLinkerOptions);
16
+ start(name: string, port: number): void;
17
+ close(): void;
18
+ }
@@ -0,0 +1,61 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { API_GATEWAY_NAMESPACE, LIVEQUERY_MAGIC_KEY, WEBSOCKET_PATH, } from './const.js';
3
+ import { UdpDiscovery } from './UdpDiscovery.js';
4
+ export class ApiServiceLinker {
5
+ #paths;
6
+ #nodeId;
7
+ #lws;
8
+ #discovery;
9
+ #subscription;
10
+ #metadata;
11
+ constructor(options) {
12
+ this.#paths = options.paths;
13
+ this.#nodeId = options.node_id ?? randomUUID();
14
+ this.#lws = options.ws;
15
+ this.#discovery = options.discovery ?? new UdpDiscovery({ key: LIVEQUERY_MAGIC_KEY });
16
+ }
17
+ start(name, port) {
18
+ this.#metadata = this.#createMetadata(name, port);
19
+ this.#subscription?.unsubscribe();
20
+ this.#subscription = this.#discovery.subscribe(node => {
21
+ if (node.role !== 'gateway')
22
+ return;
23
+ if (node.namespace !== API_GATEWAY_NAMESPACE)
24
+ return;
25
+ if (node.node_id === this.#nodeId)
26
+ return;
27
+ const metadata = this.#metadata;
28
+ if (metadata)
29
+ this.#discovery.broadcast(this.#bump(metadata)).catch(e => console.error(e));
30
+ });
31
+ this.#discovery.broadcast(this.#metadata).catch(e => console.error(e));
32
+ }
33
+ close() {
34
+ this.#subscription?.unsubscribe();
35
+ this.#discovery.close();
36
+ }
37
+ #createMetadata(name, port) {
38
+ return {
39
+ node_id: this.#nodeId,
40
+ host: '',
41
+ namespace: API_GATEWAY_NAMESPACE,
42
+ version: Date.now(),
43
+ name,
44
+ port,
45
+ role: 'service',
46
+ paths: this.#paths,
47
+ linked: [],
48
+ ws: this.#lws ? {
49
+ auth: this.#lws.auth,
50
+ path: WEBSOCKET_PATH,
51
+ } : undefined,
52
+ };
53
+ }
54
+ #bump(metadata) {
55
+ return {
56
+ ...metadata,
57
+ version: Date.now(),
58
+ };
59
+ }
60
+ }
61
+ //# sourceMappingURL=ApiServiceLinker.js.map