@portel/photon-core 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -0
- package/dist/base.d.ts +41 -1
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +63 -1
- package/dist/base.js.map +1 -1
- package/dist/channels/daemon-broker.d.ts +35 -0
- package/dist/channels/daemon-broker.d.ts.map +1 -0
- package/dist/channels/daemon-broker.js +229 -0
- package/dist/channels/daemon-broker.js.map +1 -0
- package/dist/channels/http-broker.d.ts +45 -0
- package/dist/channels/http-broker.d.ts.map +1 -0
- package/dist/channels/http-broker.js +182 -0
- package/dist/channels/http-broker.js.map +1 -0
- package/dist/channels/index.d.ts +53 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +67 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/noop-broker.d.ts +21 -0
- package/dist/channels/noop-broker.d.ts.map +1 -0
- package/dist/channels/noop-broker.js +38 -0
- package/dist/channels/noop-broker.js.map +1 -0
- package/dist/channels/redis-broker.d.ts +45 -0
- package/dist/channels/redis-broker.d.ts.map +1 -0
- package/dist/channels/redis-broker.js +214 -0
- package/dist/channels/redis-broker.js.map +1 -0
- package/dist/channels/registry.d.ts +49 -0
- package/dist/channels/registry.d.ts.map +1 -0
- package/dist/channels/registry.js +150 -0
- package/dist/channels/registry.js.map +1 -0
- package/dist/channels/types.d.ts +85 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +8 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/decorators.d.ts +48 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +64 -0
- package/dist/decorators.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/schema-extractor.d.ts +23 -2
- package/dist/schema-extractor.d.ts.map +1 -1
- package/dist/schema-extractor.js +88 -3
- package/dist/schema-extractor.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +5 -3
- package/src/base.ts +70 -1
- package/src/channels/daemon-broker.ts +271 -0
- package/src/channels/http-broker.ts +221 -0
- package/src/channels/index.ts +96 -0
- package/src/channels/noop-broker.ts +47 -0
- package/src/channels/redis-broker.ts +252 -0
- package/src/channels/registry.ts +170 -0
- package/src/channels/types.ts +95 -0
- package/src/decorators.ts +87 -0
- package/src/index.ts +13 -0
- package/src/schema-extractor.ts +100 -3
- package/src/types.ts +23 -0
package/README.md
CHANGED
|
@@ -449,6 +449,67 @@ const resumed = await maybeStatefulExecute(
|
|
|
449
449
|
|
|
450
450
|
---
|
|
451
451
|
|
|
452
|
+
### Channel-Based Pub/Sub
|
|
453
|
+
|
|
454
|
+
Photon Core provides a pluggable channel broker architecture for cross-process messaging. This enables real-time updates between MCP processes, Beam UI, and other services.
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
import { PhotonMCP } from '@portel/photon-core';
|
|
458
|
+
|
|
459
|
+
export default class KanbanBoard extends PhotonMCP {
|
|
460
|
+
async moveTask(params: { taskId: string; column: string }) {
|
|
461
|
+
const task = await this.updateTask(params);
|
|
462
|
+
|
|
463
|
+
// Emit to local output handler (current caller)
|
|
464
|
+
this.emit({ emit: 'board-update', board: 'default' });
|
|
465
|
+
|
|
466
|
+
// Also publish to channel for cross-process subscribers
|
|
467
|
+
this.emit({
|
|
468
|
+
channel: 'kanban:default', // Format: photonName:subChannel
|
|
469
|
+
event: 'task-moved',
|
|
470
|
+
data: { task }
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
return task;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
**Broker Types:**
|
|
479
|
+
|
|
480
|
+
| Broker | Use Case | Configuration |
|
|
481
|
+
|--------|----------|---------------|
|
|
482
|
+
| `daemon` | Local dev, single-server | Default (uses Unix sockets) |
|
|
483
|
+
| `redis` | Multi-server, production | `PHOTON_REDIS_URL` |
|
|
484
|
+
| `http` | Webhook integrations | `PHOTON_CHANNEL_HTTP_URL` |
|
|
485
|
+
| `noop` | Testing, disabled | `PHOTON_CHANNEL_BROKER=noop` |
|
|
486
|
+
|
|
487
|
+
**Subscribing to channels:**
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
import { getBroker } from '@portel/photon-core';
|
|
491
|
+
|
|
492
|
+
const broker = getBroker();
|
|
493
|
+
|
|
494
|
+
// Subscribe
|
|
495
|
+
const sub = await broker.subscribe('kanban:default', (message) => {
|
|
496
|
+
console.log('Received:', message.event, message.data);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
// Later: unsubscribe
|
|
500
|
+
sub.unsubscribe();
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**Environment Variables:**
|
|
504
|
+
- `PHOTON_CHANNEL_BROKER` - Explicit broker type (`daemon`, `redis`, `http`, `noop`)
|
|
505
|
+
- `PHOTON_NAME` - Photon name for daemon socket path
|
|
506
|
+
- `PHOTON_REDIS_URL` - Redis connection URL (auto-enables redis broker)
|
|
507
|
+
- `PHOTON_CHANNEL_HTTP_URL` - HTTP webhook URL (auto-enables http broker)
|
|
508
|
+
|
|
509
|
+
See [CHANNELS.md](./CHANNELS.md) for full architecture documentation.
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
452
513
|
## 🏗️ Building Custom Runtimes
|
|
453
514
|
|
|
454
515
|
Photon Core is designed to be the foundation for custom runtimes. Here are examples:
|
package/dist/base.d.ts
CHANGED
|
@@ -49,7 +49,24 @@ import { MCPClient, MCPClientFactory } from '@portel/mcp';
|
|
|
49
49
|
export declare class PhotonMCP {
|
|
50
50
|
/**
|
|
51
51
|
* Emit an event/progress update
|
|
52
|
-
*
|
|
52
|
+
*
|
|
53
|
+
* If data includes a `channel` property, the message is also published
|
|
54
|
+
* to the channel broker for cross-process notification.
|
|
55
|
+
*
|
|
56
|
+
* @param data Data to emit (can include channel, event, data properties for pub/sub)
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* // Simple emit (local only)
|
|
61
|
+
* this.emit({ status: 'processing', progress: 50 });
|
|
62
|
+
*
|
|
63
|
+
* // Emit with channel (broadcasts to subscribers)
|
|
64
|
+
* this.emit({
|
|
65
|
+
* channel: 'board:my-board',
|
|
66
|
+
* event: 'task-moved',
|
|
67
|
+
* data: { taskId: '123', newColumn: 'Done' }
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
53
70
|
*/
|
|
54
71
|
protected emit(data: any): void;
|
|
55
72
|
/**
|
|
@@ -128,5 +145,28 @@ export declare class PhotonMCP {
|
|
|
128
145
|
* Requires MCP factory to be set
|
|
129
146
|
*/
|
|
130
147
|
listMCPServers(): Promise<string[]>;
|
|
148
|
+
/**
|
|
149
|
+
* Execute a function with a distributed lock
|
|
150
|
+
*
|
|
151
|
+
* Acquires the lock before executing, releases after (even on error).
|
|
152
|
+
* If the lock cannot be acquired, throws an error.
|
|
153
|
+
*
|
|
154
|
+
* @param lockName Name of the lock to acquire
|
|
155
|
+
* @param fn Function to execute while holding the lock
|
|
156
|
+
* @param timeout Optional lock timeout in ms (default 30000)
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* async moveTask(params: { taskId: string; column: string }) {
|
|
161
|
+
* return this.withLock('board:write', async () => {
|
|
162
|
+
* const task = await this.loadTask(params.taskId);
|
|
163
|
+
* task.column = params.column;
|
|
164
|
+
* await this.saveTask(task);
|
|
165
|
+
* return task;
|
|
166
|
+
* });
|
|
167
|
+
* }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
protected withLock<T>(lockName: string, fn: () => Promise<T>, timeout?: number): Promise<T>;
|
|
131
171
|
}
|
|
132
172
|
//# sourceMappingURL=base.d.ts.map
|
package/dist/base.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAkB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAkB,MAAM,aAAa,CAAC;AAK1E;;;;;;GAMG;AACH,qBAAa,SAAS;IACpB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI;IA0B/B;;;OAGG;IACH,SAAS,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAEzC;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAsF;IAEzG;;;OAGG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM;IAQ3B;;;OAGG;IACH,MAAM,CAAC,cAAc,IAAI,MAAM,EAAE;IA0BjC;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAkBrH;;OAEG;IACG,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;IAC9B,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;IAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAoBhF;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAM9C;;OAEG;IACH,YAAY,IAAI,OAAO;IAIvB;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAOzC;;;;;;;;;;;;;;;;;;;;;OAqBG;cACa,QAAQ,CAAC,CAAC,EACxB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,CAAC;CAGd"}
|
package/dist/base.js
CHANGED
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
*/
|
|
41
41
|
import { createMCPProxy } from '@portel/mcp';
|
|
42
42
|
import { executionContext } from '@portel/cli';
|
|
43
|
+
import { getBroker } from './channels/index.js';
|
|
44
|
+
import { withLock as withLockHelper } from './decorators.js';
|
|
43
45
|
/**
|
|
44
46
|
* Simple base class for creating Photon MCPs
|
|
45
47
|
*
|
|
@@ -50,13 +52,48 @@ import { executionContext } from '@portel/cli';
|
|
|
50
52
|
export class PhotonMCP {
|
|
51
53
|
/**
|
|
52
54
|
* Emit an event/progress update
|
|
53
|
-
*
|
|
55
|
+
*
|
|
56
|
+
* If data includes a `channel` property, the message is also published
|
|
57
|
+
* to the channel broker for cross-process notification.
|
|
58
|
+
*
|
|
59
|
+
* @param data Data to emit (can include channel, event, data properties for pub/sub)
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* // Simple emit (local only)
|
|
64
|
+
* this.emit({ status: 'processing', progress: 50 });
|
|
65
|
+
*
|
|
66
|
+
* // Emit with channel (broadcasts to subscribers)
|
|
67
|
+
* this.emit({
|
|
68
|
+
* channel: 'board:my-board',
|
|
69
|
+
* event: 'task-moved',
|
|
70
|
+
* data: { taskId: '123', newColumn: 'Done' }
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
54
73
|
*/
|
|
55
74
|
emit(data) {
|
|
56
75
|
const store = executionContext.getStore();
|
|
76
|
+
// Send to local output handler (current caller)
|
|
57
77
|
if (store?.outputHandler) {
|
|
58
78
|
store.outputHandler(data);
|
|
59
79
|
}
|
|
80
|
+
// If channel is specified, also publish to broker for cross-process notification
|
|
81
|
+
if (data && typeof data.channel === 'string') {
|
|
82
|
+
const broker = getBroker();
|
|
83
|
+
broker.publish({
|
|
84
|
+
channel: data.channel,
|
|
85
|
+
event: data.event || 'message',
|
|
86
|
+
data: data.data !== undefined ? data.data : data,
|
|
87
|
+
timestamp: Date.now(),
|
|
88
|
+
source: this.constructor.name,
|
|
89
|
+
}).catch((err) => {
|
|
90
|
+
// Silent fail - channel pub is best-effort
|
|
91
|
+
// Log only in debug mode
|
|
92
|
+
if (process.env.PHOTON_DEBUG) {
|
|
93
|
+
console.error('Channel publish error:', err);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
60
97
|
}
|
|
61
98
|
/**
|
|
62
99
|
* MCP client factory - injected by runtime
|
|
@@ -193,5 +230,30 @@ export class PhotonMCP {
|
|
|
193
230
|
}
|
|
194
231
|
return this._mcpFactory.listServers();
|
|
195
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Execute a function with a distributed lock
|
|
235
|
+
*
|
|
236
|
+
* Acquires the lock before executing, releases after (even on error).
|
|
237
|
+
* If the lock cannot be acquired, throws an error.
|
|
238
|
+
*
|
|
239
|
+
* @param lockName Name of the lock to acquire
|
|
240
|
+
* @param fn Function to execute while holding the lock
|
|
241
|
+
* @param timeout Optional lock timeout in ms (default 30000)
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* async moveTask(params: { taskId: string; column: string }) {
|
|
246
|
+
* return this.withLock('board:write', async () => {
|
|
247
|
+
* const task = await this.loadTask(params.taskId);
|
|
248
|
+
* task.column = params.column;
|
|
249
|
+
* await this.saveTask(task);
|
|
250
|
+
* return task;
|
|
251
|
+
* });
|
|
252
|
+
* }
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
async withLock(lockName, fn, timeout) {
|
|
256
|
+
return withLockHelper(lockName, fn, timeout);
|
|
257
|
+
}
|
|
196
258
|
}
|
|
197
259
|
//# sourceMappingURL=base.js.map
|
package/dist/base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAA+B,cAAc,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon Channel Broker
|
|
3
|
+
*
|
|
4
|
+
* Uses Unix sockets (or named pipes on Windows) to communicate with
|
|
5
|
+
* the local photon daemon for pub/sub messaging.
|
|
6
|
+
*
|
|
7
|
+
* Best for:
|
|
8
|
+
* - Local development
|
|
9
|
+
* - Single-server deployments
|
|
10
|
+
* - Scenarios where BEAM and MCP share the same filesystem
|
|
11
|
+
*/
|
|
12
|
+
import type { ChannelBroker, ChannelMessage, ChannelHandler, Subscription } from './types.js';
|
|
13
|
+
export interface DaemonBrokerOptions {
|
|
14
|
+
/** Photon name (for socket path) */
|
|
15
|
+
photonName?: string;
|
|
16
|
+
/** Custom socket directory */
|
|
17
|
+
socketDir?: string;
|
|
18
|
+
/** Connection timeout in ms */
|
|
19
|
+
timeout?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare class DaemonBroker implements ChannelBroker {
|
|
22
|
+
readonly type = "daemon";
|
|
23
|
+
private photonName;
|
|
24
|
+
private socketDir?;
|
|
25
|
+
private timeout;
|
|
26
|
+
private subscriptions;
|
|
27
|
+
constructor(options?: DaemonBrokerOptions);
|
|
28
|
+
publish(message: ChannelMessage): Promise<void>;
|
|
29
|
+
subscribe(channel: string, handler: ChannelHandler): Promise<Subscription>;
|
|
30
|
+
isConnected(): boolean;
|
|
31
|
+
connect(): Promise<void>;
|
|
32
|
+
disconnect(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export default DaemonBroker;
|
|
35
|
+
//# sourceMappingURL=daemon-broker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-broker.d.ts","sourceRoot":"","sources":["../../src/channels/daemon-broker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9F,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAaD,qBAAa,YAAa,YAAW,aAAa;IAChD,QAAQ,CAAC,IAAI,YAAY;IAEzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAA4E;gBAErF,OAAO,GAAE,mBAAwB;IAMvC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAmE/C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IA+HhF,WAAW,IAAI,OAAO;IAKhB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CASlC;AAKD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon Channel Broker
|
|
3
|
+
*
|
|
4
|
+
* Uses Unix sockets (or named pipes on Windows) to communicate with
|
|
5
|
+
* the local photon daemon for pub/sub messaging.
|
|
6
|
+
*
|
|
7
|
+
* Best for:
|
|
8
|
+
* - Local development
|
|
9
|
+
* - Single-server deployments
|
|
10
|
+
* - Scenarios where BEAM and MCP share the same filesystem
|
|
11
|
+
*/
|
|
12
|
+
import * as net from 'net';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import * as os from 'os';
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import { registerBroker } from './registry.js';
|
|
17
|
+
/**
|
|
18
|
+
* Get the socket path for a photon daemon
|
|
19
|
+
*/
|
|
20
|
+
function getSocketPath(photonName, socketDir) {
|
|
21
|
+
const dir = socketDir || path.join(os.homedir(), '.photon', 'daemons');
|
|
22
|
+
if (process.platform === 'win32') {
|
|
23
|
+
return `\\\\.\\pipe\\photon-${photonName}`;
|
|
24
|
+
}
|
|
25
|
+
return path.join(dir, `${photonName}.sock`);
|
|
26
|
+
}
|
|
27
|
+
export class DaemonBroker {
|
|
28
|
+
type = 'daemon';
|
|
29
|
+
photonName;
|
|
30
|
+
socketDir;
|
|
31
|
+
timeout;
|
|
32
|
+
subscriptions = new Map();
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
this.photonName = options.photonName || process.env.PHOTON_NAME || 'unknown';
|
|
35
|
+
this.socketDir = options.socketDir;
|
|
36
|
+
this.timeout = options.timeout || 5000;
|
|
37
|
+
}
|
|
38
|
+
async publish(message) {
|
|
39
|
+
// Determine photon name: use configured name, or extract from channel format "photonName:subChannel"
|
|
40
|
+
let targetPhoton = this.photonName;
|
|
41
|
+
if (targetPhoton === 'unknown' && message.channel?.includes(':')) {
|
|
42
|
+
// Extract photon name from channel (e.g., "kanban:default" -> "kanban")
|
|
43
|
+
const colonIndex = message.channel.indexOf(':');
|
|
44
|
+
targetPhoton = message.channel.slice(0, colonIndex);
|
|
45
|
+
}
|
|
46
|
+
const socketPath = getSocketPath(targetPhoton, this.socketDir);
|
|
47
|
+
// Check if socket exists
|
|
48
|
+
if (process.platform !== 'win32' && !fs.existsSync(socketPath)) {
|
|
49
|
+
// Daemon not running, silently ignore
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const client = net.createConnection(socketPath);
|
|
54
|
+
const requestId = `pub_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
55
|
+
const timeout = setTimeout(() => {
|
|
56
|
+
client.destroy();
|
|
57
|
+
// Don't reject on timeout - publish is best-effort
|
|
58
|
+
resolve();
|
|
59
|
+
}, this.timeout);
|
|
60
|
+
client.on('connect', () => {
|
|
61
|
+
const request = {
|
|
62
|
+
type: 'publish',
|
|
63
|
+
id: requestId,
|
|
64
|
+
channel: message.channel,
|
|
65
|
+
message: {
|
|
66
|
+
...message,
|
|
67
|
+
timestamp: message.timestamp || Date.now(),
|
|
68
|
+
source: message.source || this.photonName,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
client.write(JSON.stringify(request) + '\n');
|
|
72
|
+
});
|
|
73
|
+
client.on('data', (chunk) => {
|
|
74
|
+
try {
|
|
75
|
+
const response = JSON.parse(chunk.toString().trim());
|
|
76
|
+
if (response.id === requestId) {
|
|
77
|
+
clearTimeout(timeout);
|
|
78
|
+
client.destroy();
|
|
79
|
+
resolve();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Ignore parse errors
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
client.on('error', () => {
|
|
87
|
+
clearTimeout(timeout);
|
|
88
|
+
client.destroy();
|
|
89
|
+
// Don't reject - publish is best-effort
|
|
90
|
+
resolve();
|
|
91
|
+
});
|
|
92
|
+
client.on('end', () => {
|
|
93
|
+
clearTimeout(timeout);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async subscribe(channel, handler) {
|
|
98
|
+
const socketPath = getSocketPath(this.photonName, this.socketDir);
|
|
99
|
+
const subscribeId = `sub_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const client = net.createConnection(socketPath);
|
|
102
|
+
let subscribed = false;
|
|
103
|
+
let buffer = '';
|
|
104
|
+
const timeout = setTimeout(() => {
|
|
105
|
+
if (!subscribed) {
|
|
106
|
+
client.destroy();
|
|
107
|
+
reject(new Error('Subscription timeout'));
|
|
108
|
+
}
|
|
109
|
+
}, this.timeout);
|
|
110
|
+
client.on('connect', () => {
|
|
111
|
+
const request = {
|
|
112
|
+
type: 'subscribe',
|
|
113
|
+
id: subscribeId,
|
|
114
|
+
channel,
|
|
115
|
+
clientType: 'photon',
|
|
116
|
+
};
|
|
117
|
+
client.write(JSON.stringify(request) + '\n');
|
|
118
|
+
});
|
|
119
|
+
client.on('data', (chunk) => {
|
|
120
|
+
buffer += chunk.toString();
|
|
121
|
+
// Process complete JSON messages (newline-delimited)
|
|
122
|
+
const lines = buffer.split('\n');
|
|
123
|
+
buffer = lines.pop() || '';
|
|
124
|
+
for (const line of lines) {
|
|
125
|
+
if (!line.trim())
|
|
126
|
+
continue;
|
|
127
|
+
try {
|
|
128
|
+
const response = JSON.parse(line);
|
|
129
|
+
// Handle subscription confirmation
|
|
130
|
+
if (response.id === subscribeId && response.type === 'result') {
|
|
131
|
+
clearTimeout(timeout);
|
|
132
|
+
subscribed = true;
|
|
133
|
+
// Track subscription
|
|
134
|
+
if (!this.subscriptions.has(channel)) {
|
|
135
|
+
this.subscriptions.set(channel, { socket: client, handlers: new Set() });
|
|
136
|
+
}
|
|
137
|
+
this.subscriptions.get(channel).handlers.add(handler);
|
|
138
|
+
// Return subscription handle
|
|
139
|
+
const subscription = {
|
|
140
|
+
channel,
|
|
141
|
+
active: true,
|
|
142
|
+
unsubscribe: () => {
|
|
143
|
+
subscription.active = false;
|
|
144
|
+
const sub = this.subscriptions.get(channel);
|
|
145
|
+
if (sub) {
|
|
146
|
+
sub.handlers.delete(handler);
|
|
147
|
+
if (sub.handlers.size === 0) {
|
|
148
|
+
// Send unsubscribe and close
|
|
149
|
+
const unsubRequest = {
|
|
150
|
+
type: 'unsubscribe',
|
|
151
|
+
id: `unsub_${Date.now()}`,
|
|
152
|
+
channel,
|
|
153
|
+
};
|
|
154
|
+
if (!client.destroyed) {
|
|
155
|
+
client.write(JSON.stringify(unsubRequest) + '\n');
|
|
156
|
+
client.end();
|
|
157
|
+
}
|
|
158
|
+
this.subscriptions.delete(channel);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
resolve(subscription);
|
|
164
|
+
}
|
|
165
|
+
// Handle channel messages
|
|
166
|
+
if (response.type === 'channel_message' && response.channel === channel) {
|
|
167
|
+
const msg = {
|
|
168
|
+
channel: response.channel,
|
|
169
|
+
event: response.message?.event || 'message',
|
|
170
|
+
data: response.message?.data || response.message,
|
|
171
|
+
timestamp: response.message?.timestamp || Date.now(),
|
|
172
|
+
source: response.message?.source,
|
|
173
|
+
};
|
|
174
|
+
handler(msg);
|
|
175
|
+
}
|
|
176
|
+
// Handle errors
|
|
177
|
+
if (response.type === 'error' && response.id === subscribeId) {
|
|
178
|
+
clearTimeout(timeout);
|
|
179
|
+
reject(new Error(response.error || 'Subscription failed'));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Ignore parse errors for partial messages
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
client.on('error', (error) => {
|
|
188
|
+
if (!subscribed) {
|
|
189
|
+
clearTimeout(timeout);
|
|
190
|
+
reject(new Error(`Connection error: ${error.message}`));
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
client.on('end', () => {
|
|
194
|
+
if (!subscribed) {
|
|
195
|
+
clearTimeout(timeout);
|
|
196
|
+
reject(new Error('Connection closed before subscription confirmed'));
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
client.on('close', () => {
|
|
200
|
+
// Mark all subscriptions on this socket as inactive
|
|
201
|
+
for (const [ch, sub] of this.subscriptions) {
|
|
202
|
+
if (sub.socket === client) {
|
|
203
|
+
this.subscriptions.delete(ch);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
isConnected() {
|
|
210
|
+
// Check if any subscriptions are active
|
|
211
|
+
return this.subscriptions.size > 0;
|
|
212
|
+
}
|
|
213
|
+
async connect() {
|
|
214
|
+
// Connection happens lazily on first publish/subscribe
|
|
215
|
+
}
|
|
216
|
+
async disconnect() {
|
|
217
|
+
// Close all subscription sockets
|
|
218
|
+
for (const [, sub] of this.subscriptions) {
|
|
219
|
+
if (!sub.socket.destroyed) {
|
|
220
|
+
sub.socket.end();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
this.subscriptions.clear();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Register the broker
|
|
227
|
+
registerBroker('daemon', (options) => new DaemonBroker(options));
|
|
228
|
+
export default DaemonBroker;
|
|
229
|
+
//# sourceMappingURL=daemon-broker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-broker.js","sourceRoot":"","sources":["../../src/channels/daemon-broker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Channel Broker
|
|
3
|
+
*
|
|
4
|
+
* Uses HTTP webhooks for publishing and Server-Sent Events (SSE) for subscribing.
|
|
5
|
+
* Works with any HTTP-based pub/sub system.
|
|
6
|
+
*
|
|
7
|
+
* Best for:
|
|
8
|
+
* - Serverless environments (AWS Lambda, Vercel, etc.)
|
|
9
|
+
* - Cloud functions that can't maintain long-lived connections
|
|
10
|
+
* - Integration with existing webhook infrastructure
|
|
11
|
+
*
|
|
12
|
+
* Publishing: POST to publishUrl with JSON body
|
|
13
|
+
* Subscribing: SSE connection to subscribeUrl
|
|
14
|
+
*/
|
|
15
|
+
import type { ChannelBroker, ChannelMessage, ChannelHandler, Subscription } from './types.js';
|
|
16
|
+
export interface HttpBrokerOptions {
|
|
17
|
+
/** URL for publishing messages (POST requests) */
|
|
18
|
+
publishUrl?: string;
|
|
19
|
+
/** URL for SSE subscriptions */
|
|
20
|
+
subscribeUrl?: string;
|
|
21
|
+
/** Authentication token (sent as Bearer token) */
|
|
22
|
+
authToken?: string;
|
|
23
|
+
/** Custom headers for requests */
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
/** Request timeout in ms */
|
|
26
|
+
timeout?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare class HttpBroker implements ChannelBroker {
|
|
29
|
+
readonly type = "http";
|
|
30
|
+
private publishUrl?;
|
|
31
|
+
private subscribeUrl?;
|
|
32
|
+
private authToken?;
|
|
33
|
+
private headers;
|
|
34
|
+
private timeout;
|
|
35
|
+
private subscriptions;
|
|
36
|
+
constructor(options?: HttpBrokerOptions);
|
|
37
|
+
private getHeaders;
|
|
38
|
+
publish(message: ChannelMessage): Promise<void>;
|
|
39
|
+
subscribe(channel: string, handler: ChannelHandler): Promise<Subscription>;
|
|
40
|
+
isConnected(): boolean;
|
|
41
|
+
connect(): Promise<void>;
|
|
42
|
+
disconnect(): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export default HttpBroker;
|
|
45
|
+
//# sourceMappingURL=http-broker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-broker.d.ts","sourceRoot":"","sources":["../../src/channels/http-broker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9F,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,UAAW,YAAW,aAAa;IAC9C,QAAQ,CAAC,IAAI,UAAU;IAEvB,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAqF;gBAE9F,OAAO,GAAE,iBAAsB;IAQ3C,OAAO,CAAC,UAAU;IAaZ,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B/C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IA4GhF,WAAW,IAAI,OAAO;IAIhB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAOlC;AAKD,eAAe,UAAU,CAAC"}
|