@portel/photon 1.9.0 → 1.10.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 +163 -210
- package/dist/async/dedup-map.d.ts +40 -0
- package/dist/async/dedup-map.d.ts.map +1 -0
- package/dist/async/dedup-map.js +80 -0
- package/dist/async/dedup-map.js.map +1 -0
- package/dist/async/index.d.ts +11 -0
- package/dist/async/index.d.ts.map +1 -0
- package/dist/async/index.js +11 -0
- package/dist/async/index.js.map +1 -0
- package/dist/async/loading-gate.d.ts +27 -0
- package/dist/async/loading-gate.d.ts.map +1 -0
- package/dist/async/loading-gate.js +48 -0
- package/dist/async/loading-gate.js.map +1 -0
- package/dist/async/with-timeout.d.ts +6 -0
- package/dist/async/with-timeout.d.ts.map +1 -0
- package/dist/async/with-timeout.js +17 -0
- package/dist/async/with-timeout.js.map +1 -0
- package/dist/auto-ui/beam/class-metadata.d.ts +52 -0
- package/dist/auto-ui/beam/class-metadata.d.ts.map +1 -0
- package/dist/auto-ui/beam/class-metadata.js +133 -0
- package/dist/auto-ui/beam/class-metadata.js.map +1 -0
- package/dist/auto-ui/beam/config.d.ts +13 -0
- package/dist/auto-ui/beam/config.d.ts.map +1 -0
- package/dist/auto-ui/beam/config.js +52 -0
- package/dist/auto-ui/beam/config.js.map +1 -0
- package/dist/auto-ui/beam/external-mcp.d.ts +37 -0
- package/dist/auto-ui/beam/external-mcp.d.ts.map +1 -0
- package/dist/auto-ui/beam/external-mcp.js +311 -0
- package/dist/auto-ui/beam/external-mcp.js.map +1 -0
- package/dist/auto-ui/beam/photon-management.d.ts +51 -0
- package/dist/auto-ui/beam/photon-management.d.ts.map +1 -0
- package/dist/auto-ui/beam/photon-management.js +310 -0
- package/dist/auto-ui/beam/photon-management.js.map +1 -0
- package/dist/auto-ui/beam/routes/api-browse.d.ts +17 -0
- package/dist/auto-ui/beam/routes/api-browse.d.ts.map +1 -0
- package/dist/auto-ui/beam/routes/api-browse.js +531 -0
- package/dist/auto-ui/beam/routes/api-browse.js.map +1 -0
- package/dist/auto-ui/beam/routes/api-config.d.ts +9 -0
- package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -0
- package/dist/auto-ui/beam/routes/api-config.js +494 -0
- package/dist/auto-ui/beam/routes/api-config.js.map +1 -0
- package/dist/auto-ui/beam/routes/api-marketplace.d.ts +8 -0
- package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -0
- package/dist/auto-ui/beam/routes/api-marketplace.js +490 -0
- package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -0
- package/dist/auto-ui/beam/startup.d.ts +41 -0
- package/dist/auto-ui/beam/startup.d.ts.map +1 -0
- package/dist/auto-ui/beam/startup.js +98 -0
- package/dist/auto-ui/beam/startup.js.map +1 -0
- package/dist/auto-ui/beam/subscription.d.ts +35 -0
- package/dist/auto-ui/beam/subscription.d.ts.map +1 -0
- package/dist/auto-ui/beam/subscription.js +151 -0
- package/dist/auto-ui/beam/subscription.js.map +1 -0
- package/dist/auto-ui/beam/types.d.ts +103 -0
- package/dist/auto-ui/beam/types.d.ts.map +1 -0
- package/dist/auto-ui/beam/types.js +8 -0
- package/dist/auto-ui/beam/types.js.map +1 -0
- package/dist/auto-ui/beam.d.ts +2 -0
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +729 -2596
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/bridge/index.d.ts.map +1 -1
- package/dist/auto-ui/bridge/index.js +10 -2
- package/dist/auto-ui/bridge/index.js.map +1 -1
- package/dist/auto-ui/components/card.d.ts.map +1 -1
- package/dist/auto-ui/components/card.js +3 -1
- package/dist/auto-ui/components/card.js.map +1 -1
- package/dist/auto-ui/components/progress.d.ts.map +1 -1
- package/dist/auto-ui/components/progress.js.map +1 -1
- package/dist/auto-ui/daemon-tools.d.ts +1 -1
- package/dist/auto-ui/daemon-tools.d.ts.map +1 -1
- package/dist/auto-ui/daemon-tools.js +4 -3
- package/dist/auto-ui/daemon-tools.js.map +1 -1
- package/dist/auto-ui/photon-bridge.d.ts +6 -2
- package/dist/auto-ui/photon-bridge.d.ts.map +1 -1
- package/dist/auto-ui/photon-bridge.js +20 -8
- package/dist/auto-ui/photon-bridge.js.map +1 -1
- package/dist/auto-ui/platform-compat.d.ts.map +1 -1
- package/dist/auto-ui/platform-compat.js +4 -0
- package/dist/auto-ui/platform-compat.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts +4 -2
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +120 -30
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/auto-ui/types.d.ts +4 -2
- package/dist/auto-ui/types.d.ts.map +1 -1
- package/dist/auto-ui/types.js.map +1 -1
- package/dist/beam.bundle.js +8225 -3999
- package/dist/beam.bundle.js.map +4 -4
- package/dist/cli/commands/alias.d.ts +14 -0
- package/dist/cli/commands/alias.d.ts.map +1 -0
- package/dist/cli/commands/alias.js +41 -0
- package/dist/cli/commands/alias.js.map +1 -0
- package/dist/cli/commands/audit.d.ts +9 -0
- package/dist/cli/commands/audit.d.ts.map +1 -0
- package/dist/cli/commands/audit.js +377 -0
- package/dist/cli/commands/audit.js.map +1 -0
- package/dist/cli/commands/beam.d.ts +20 -0
- package/dist/cli/commands/beam.d.ts.map +1 -0
- package/dist/cli/commands/beam.js +256 -0
- package/dist/cli/commands/beam.js.map +1 -0
- package/dist/cli/commands/config.d.ts +14 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +165 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +11 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -0
- package/dist/cli/commands/daemon.js +108 -0
- package/dist/cli/commands/daemon.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +14 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +257 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/host.d.ts +11 -0
- package/dist/cli/commands/host.d.ts.map +1 -0
- package/dist/cli/commands/host.js +96 -0
- package/dist/cli/commands/host.js.map +1 -0
- package/dist/cli/commands/info.d.ts +1 -1
- package/dist/cli/commands/info.d.ts.map +1 -1
- package/dist/cli/commands/info.js +16 -15
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/init.d.ts +20 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +774 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/maker.d.ts +12 -0
- package/dist/cli/commands/maker.d.ts.map +1 -0
- package/dist/cli/commands/maker.js +605 -0
- package/dist/cli/commands/maker.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +27 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +390 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/package-app.d.ts +1 -1
- package/dist/cli/commands/package-app.d.ts.map +1 -1
- package/dist/cli/commands/package-app.js +5 -4
- package/dist/cli/commands/package-app.js.map +1 -1
- package/dist/cli/commands/package.d.ts +1 -1
- package/dist/cli/commands/package.d.ts.map +1 -1
- package/dist/cli/commands/package.js +134 -32
- package/dist/cli/commands/package.js.map +1 -1
- package/dist/cli/commands/run.d.ts +34 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +334 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/search.d.ts +11 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/search.js +60 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +11 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +138 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/test.d.ts +14 -0
- package/dist/cli/commands/test.d.ts.map +1 -0
- package/dist/cli/commands/test.js +51 -0
- package/dist/cli/commands/test.js.map +1 -0
- package/dist/cli/commands/update.d.ts +11 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +72 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +139 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli-alias.js +2 -2
- package/dist/cli-alias.js.map +1 -1
- package/dist/cli.d.ts +3 -16
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -2725
- package/dist/cli.js.map +1 -1
- package/dist/context-store.d.ts +13 -12
- package/dist/context-store.d.ts.map +1 -1
- package/dist/context-store.js +47 -23
- package/dist/context-store.js.map +1 -1
- package/dist/context.d.ts +35 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +38 -0
- package/dist/context.js.map +1 -0
- package/dist/daemon/client.d.ts +25 -13
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +183 -135
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.d.ts +58 -26
- package/dist/daemon/manager.d.ts.map +1 -1
- package/dist/daemon/manager.js +348 -157
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/protocol.d.ts +9 -3
- package/dist/daemon/protocol.d.ts.map +1 -1
- package/dist/daemon/protocol.js +2 -0
- package/dist/daemon/protocol.js.map +1 -1
- package/dist/daemon/server.js +850 -200
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/session-manager.d.ts +16 -2
- package/dist/daemon/session-manager.d.ts.map +1 -1
- package/dist/daemon/session-manager.js +65 -7
- package/dist/daemon/session-manager.js.map +1 -1
- package/dist/daemon/state-machine.d.ts +22 -0
- package/dist/daemon/state-machine.d.ts.map +1 -0
- package/dist/daemon/state-machine.js +48 -0
- package/dist/daemon/state-machine.js.map +1 -0
- package/dist/deploy/cloudflare.d.ts.map +1 -1
- package/dist/deploy/cloudflare.js +5 -5
- package/dist/deploy/cloudflare.js.map +1 -1
- package/dist/loader.d.ts +65 -7
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +587 -63
- package/dist/loader.js.map +1 -1
- package/dist/marketplace-manager.d.ts +84 -12
- package/dist/marketplace-manager.d.ts.map +1 -1
- package/dist/marketplace-manager.js +470 -26
- package/dist/marketplace-manager.js.map +1 -1
- package/dist/path-resolver.d.ts +3 -1
- package/dist/path-resolver.d.ts.map +1 -1
- package/dist/path-resolver.js +4 -3
- package/dist/path-resolver.js.map +1 -1
- package/dist/photon-cli-runner.d.ts +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +34 -44
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/photon-doc-extractor.d.ts +1 -0
- package/dist/photon-doc-extractor.d.ts.map +1 -1
- package/dist/photon-doc-extractor.js +33 -12
- package/dist/photon-doc-extractor.js.map +1 -1
- package/dist/photons/maker.photon.d.ts.map +1 -1
- package/dist/photons/maker.photon.js +4 -4
- package/dist/photons/maker.photon.js.map +1 -1
- package/dist/photons/maker.photon.ts +4 -3
- package/dist/photons/marketplace.photon.d.ts.map +1 -1
- package/dist/photons/marketplace.photon.js +10 -27
- package/dist/photons/marketplace.photon.js.map +1 -1
- package/dist/photons/marketplace.photon.ts +14 -33
- package/dist/photons/tunnel.photon.d.ts.map +1 -1
- package/dist/photons/tunnel.photon.js +4 -8
- package/dist/photons/tunnel.photon.js.map +1 -1
- package/dist/photons/tunnel.photon.ts +4 -7
- package/dist/serv/session/kv-store.d.ts +1 -1
- package/dist/serv/session/kv-store.d.ts.map +1 -1
- package/dist/serv/session/store.d.ts.map +1 -1
- package/dist/serv/session/store.js +16 -14
- package/dist/serv/session/store.js.map +1 -1
- package/dist/serv/vault/token-vault.js +1 -1
- package/dist/serv/vault/token-vault.js.map +1 -1
- package/dist/server.d.ts +34 -12
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +364 -313
- package/dist/server.js.map +1 -1
- package/dist/shared/audit.d.ts +30 -0
- package/dist/shared/audit.d.ts.map +1 -0
- package/dist/shared/audit.js +89 -0
- package/dist/shared/audit.js.map +1 -0
- package/dist/shared/cli-sections.d.ts +0 -4
- package/dist/shared/cli-sections.d.ts.map +1 -1
- package/dist/shared/cli-sections.js +0 -6
- package/dist/shared/cli-sections.js.map +1 -1
- package/dist/shared/cli-utils.d.ts +2 -56
- package/dist/shared/cli-utils.d.ts.map +1 -1
- package/dist/shared/cli-utils.js +1 -87
- package/dist/shared/cli-utils.js.map +1 -1
- package/dist/shared/error-handler.d.ts +6 -72
- package/dist/shared/error-handler.d.ts.map +1 -1
- package/dist/shared/error-handler.js +22 -213
- package/dist/shared/error-handler.js.map +1 -1
- package/dist/shared/security.d.ts +0 -9
- package/dist/shared/security.d.ts.map +1 -1
- package/dist/shared/security.js +0 -30
- package/dist/shared/security.js.map +1 -1
- package/dist/shared-utils.d.ts +0 -26
- package/dist/shared-utils.d.ts.map +1 -1
- package/dist/shared-utils.js +0 -44
- package/dist/shared-utils.js.map +1 -1
- package/dist/shell-completions.d.ts +1 -1
- package/dist/shell-completions.d.ts.map +1 -1
- package/dist/shell-completions.js +5 -5
- package/dist/shell-completions.js.map +1 -1
- package/dist/template-manager.d.ts.map +1 -1
- package/dist/template-manager.js +14 -1
- package/dist/template-manager.js.map +1 -1
- package/dist/test-runner.d.ts +0 -12
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +4 -39
- package/dist/test-runner.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +2 -2
- package/dist/testing.js.map +1 -1
- package/dist/version-checker.d.ts +4 -4
- package/dist/version-checker.d.ts.map +1 -1
- package/dist/version-checker.js +33 -4
- package/dist/version-checker.js.map +1 -1
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +14 -12
- package/dist/watcher.js.map +1 -1
- package/package.json +24 -17
package/dist/daemon/client.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import * as net from 'net';
|
|
9
9
|
import * as crypto from 'crypto';
|
|
10
10
|
import * as readline from 'readline';
|
|
11
|
-
import { getGlobalSocketPath,
|
|
11
|
+
import { getGlobalSocketPath, ensureDaemon } from './manager.js';
|
|
12
12
|
import { createLogger } from '../shared/logger.js';
|
|
13
13
|
import { getErrorMessage } from '../shared/error-handler.js';
|
|
14
14
|
// Generate session ID for this process
|
|
@@ -46,12 +46,12 @@ export async function sendCommand(photonName, method, args, options) {
|
|
|
46
46
|
const maxRetries = options?.maxRetries ?? 1;
|
|
47
47
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
48
48
|
try {
|
|
49
|
-
return await sendCommandDirect(photonName, method, args, options?.photonPath, options?.sessionId, options?.instanceName);
|
|
49
|
+
return await sendCommandDirect(photonName, method, args, options?.photonPath, options?.sessionId, options?.instanceName, options?.workingDir, options?.targetInstance, options?.clientType);
|
|
50
50
|
}
|
|
51
51
|
catch (error) {
|
|
52
52
|
if (isDaemonConnectionError(error) && attempt < maxRetries) {
|
|
53
|
-
logger.info(
|
|
54
|
-
await
|
|
53
|
+
logger.info(`Daemon unreachable (${photonName}/${method}), retrying...`);
|
|
54
|
+
await ensureDaemon();
|
|
55
55
|
continue;
|
|
56
56
|
}
|
|
57
57
|
throw error;
|
|
@@ -61,14 +61,14 @@ export async function sendCommand(photonName, method, args, options) {
|
|
|
61
61
|
/**
|
|
62
62
|
* Send command directly to daemon (no retry logic)
|
|
63
63
|
*/
|
|
64
|
-
async function sendCommandDirect(photonName, method, args, photonPath, sessionId, instanceName) {
|
|
64
|
+
async function sendCommandDirect(photonName, method, args, photonPath, sessionId, instanceName, workingDir, targetInstance, clientType) {
|
|
65
65
|
const socketPath = getGlobalSocketPath();
|
|
66
66
|
const requestId = `req_${Date.now()}_${Math.random()}`;
|
|
67
67
|
return new Promise((resolve, reject) => {
|
|
68
68
|
const client = net.createConnection(socketPath);
|
|
69
69
|
let buffer = '';
|
|
70
70
|
let responseReceived = false;
|
|
71
|
-
|
|
71
|
+
let currentTimeout = setTimeout(() => {
|
|
72
72
|
if (!responseReceived) {
|
|
73
73
|
client.destroy();
|
|
74
74
|
reject(new Error('Request timeout'));
|
|
@@ -81,73 +81,77 @@ async function sendCommandDirect(photonName, method, args, photonPath, sessionId
|
|
|
81
81
|
photonName,
|
|
82
82
|
photonPath,
|
|
83
83
|
sessionId: sessionId || SESSION_ID,
|
|
84
|
-
clientType: 'cli',
|
|
84
|
+
clientType: clientType || 'cli',
|
|
85
85
|
method,
|
|
86
86
|
args,
|
|
87
87
|
instanceName,
|
|
88
|
+
targetInstance,
|
|
89
|
+
workingDir,
|
|
88
90
|
};
|
|
89
91
|
client.write(JSON.stringify(request) + '\n');
|
|
90
92
|
});
|
|
91
|
-
client.on('data',
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
93
|
+
client.on('data', (chunk) => {
|
|
94
|
+
void (async () => {
|
|
95
|
+
buffer += chunk.toString();
|
|
96
|
+
// Process complete JSON messages (newline-delimited)
|
|
97
|
+
const lines = buffer.split('\n');
|
|
98
|
+
buffer = lines.pop() || '';
|
|
99
|
+
for (const line of lines) {
|
|
100
|
+
if (!line.trim())
|
|
101
|
+
continue;
|
|
102
|
+
try {
|
|
103
|
+
const response = JSON.parse(line);
|
|
104
|
+
if (response.id === requestId) {
|
|
105
|
+
// Handle prompt request from daemon
|
|
106
|
+
if (response.type === 'prompt' && response.prompt) {
|
|
107
|
+
// Reset timeout while waiting for user input
|
|
108
|
+
clearTimeout(currentTimeout);
|
|
109
|
+
// Get user input via readline
|
|
110
|
+
const userInput = await promptUser(response.prompt.message, response.prompt.default);
|
|
111
|
+
// Send prompt response back to daemon
|
|
112
|
+
const promptResponse = {
|
|
113
|
+
type: 'prompt_response',
|
|
114
|
+
id: requestId,
|
|
115
|
+
promptValue: userInput,
|
|
116
|
+
};
|
|
117
|
+
client.write(JSON.stringify(promptResponse) + '\n');
|
|
118
|
+
// Restart timeout for next response — store handle so it can be cleared
|
|
119
|
+
currentTimeout = setTimeout(() => {
|
|
120
|
+
if (!responseReceived) {
|
|
121
|
+
client.destroy();
|
|
122
|
+
reject(new Error('Request timeout'));
|
|
123
|
+
}
|
|
124
|
+
}, 120000);
|
|
125
|
+
}
|
|
126
|
+
// Handle final result
|
|
127
|
+
else if (response.type === 'result') {
|
|
128
|
+
responseReceived = true;
|
|
129
|
+
clearTimeout(currentTimeout);
|
|
130
|
+
client.destroy();
|
|
131
|
+
resolve(response.data);
|
|
132
|
+
}
|
|
133
|
+
// Handle error
|
|
134
|
+
else if (response.type === 'error') {
|
|
135
|
+
responseReceived = true;
|
|
136
|
+
clearTimeout(currentTimeout);
|
|
137
|
+
client.destroy();
|
|
138
|
+
reject(new Error(response.error || 'Unknown error'));
|
|
139
|
+
}
|
|
136
140
|
}
|
|
137
141
|
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(error) });
|
|
144
|
+
}
|
|
138
145
|
}
|
|
139
|
-
|
|
140
|
-
logger.warn('Failed to parse daemon response', { error: getErrorMessage(error) });
|
|
141
|
-
}
|
|
142
|
-
}
|
|
146
|
+
})();
|
|
143
147
|
});
|
|
144
148
|
client.on('error', (error) => {
|
|
145
|
-
clearTimeout(
|
|
149
|
+
clearTimeout(currentTimeout);
|
|
146
150
|
client.destroy();
|
|
147
151
|
reject(new Error(`Connection error: ${getErrorMessage(error)}`));
|
|
148
152
|
});
|
|
149
153
|
client.on('end', () => {
|
|
150
|
-
clearTimeout(
|
|
154
|
+
clearTimeout(currentTimeout);
|
|
151
155
|
client.destroy();
|
|
152
156
|
if (!responseReceived) {
|
|
153
157
|
reject(new Error('Connection closed before receiving response'));
|
|
@@ -179,6 +183,7 @@ export async function subscribeChannel(photonName, channel, handler, options) {
|
|
|
179
183
|
channel,
|
|
180
184
|
clientType: 'beam',
|
|
181
185
|
lastEventId: lastSeenEventId,
|
|
186
|
+
workingDir: options?.workingDir,
|
|
182
187
|
};
|
|
183
188
|
client.write(JSON.stringify(request) + '\n');
|
|
184
189
|
});
|
|
@@ -228,8 +233,10 @@ export async function subscribeChannel(photonName, channel, handler, options) {
|
|
|
228
233
|
reject(new Error(response.error || 'Subscription failed'));
|
|
229
234
|
}
|
|
230
235
|
}
|
|
231
|
-
catch {
|
|
232
|
-
//
|
|
236
|
+
catch (e) {
|
|
237
|
+
// Lines are fully buffered (split on '\n'), so a parse error here
|
|
238
|
+
// indicates actual protocol corruption — log it.
|
|
239
|
+
logger.warn('Failed to parse daemon channel message', { error: getErrorMessage(e) });
|
|
233
240
|
}
|
|
234
241
|
}
|
|
235
242
|
});
|
|
@@ -237,9 +244,9 @@ export async function subscribeChannel(photonName, channel, handler, options) {
|
|
|
237
244
|
if (!subscribed) {
|
|
238
245
|
if (options?.reconnect && !cancelled) {
|
|
239
246
|
// Initial connection failed — retry (e.g. daemon not running yet)
|
|
240
|
-
resolve((
|
|
247
|
+
resolve(() => {
|
|
241
248
|
cancelled = true;
|
|
242
|
-
})
|
|
249
|
+
});
|
|
243
250
|
scheduleReconnect();
|
|
244
251
|
}
|
|
245
252
|
else {
|
|
@@ -253,9 +260,9 @@ export async function subscribeChannel(photonName, channel, handler, options) {
|
|
|
253
260
|
client.on('end', () => {
|
|
254
261
|
if (!subscribed) {
|
|
255
262
|
if (options?.reconnect && !cancelled) {
|
|
256
|
-
resolve((
|
|
263
|
+
resolve(() => {
|
|
257
264
|
cancelled = true;
|
|
258
|
-
})
|
|
265
|
+
});
|
|
259
266
|
scheduleReconnect();
|
|
260
267
|
}
|
|
261
268
|
else {
|
|
@@ -276,27 +283,31 @@ export async function subscribeChannel(photonName, channel, handler, options) {
|
|
|
276
283
|
reconnectAttempts++;
|
|
277
284
|
const delay = Math.min(1000 * Math.pow(2, reconnectAttempts - 1), 30000);
|
|
278
285
|
if (reconnectAttempts === 1) {
|
|
279
|
-
logger.
|
|
286
|
+
logger.debug(`Subscription lost for ${channel}, reconnecting...`);
|
|
280
287
|
}
|
|
281
288
|
else {
|
|
282
289
|
logger.debug(`Reconnecting ${channel} in ${delay}ms (attempt ${reconnectAttempts})`);
|
|
283
290
|
}
|
|
284
|
-
setTimeout(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
291
|
+
setTimeout(() => {
|
|
292
|
+
void (async () => {
|
|
293
|
+
if (cancelled)
|
|
294
|
+
return;
|
|
295
|
+
try {
|
|
296
|
+
// Try reconnecting to existing daemon first; only start if it's down
|
|
297
|
+
await ensureDaemon();
|
|
298
|
+
await connect();
|
|
299
|
+
reconnectAttempts = 0;
|
|
300
|
+
logger.debug(`Reconnected subscription for ${channel}`);
|
|
301
|
+
options?.onReconnect?.();
|
|
302
|
+
}
|
|
303
|
+
catch (e) {
|
|
304
|
+
logger.debug(`Reconnect attempt ${reconnectAttempts} failed for ${channel}`, {
|
|
305
|
+
error: getErrorMessage(e),
|
|
306
|
+
});
|
|
307
|
+
if (!cancelled)
|
|
308
|
+
scheduleReconnect();
|
|
309
|
+
}
|
|
310
|
+
})();
|
|
300
311
|
}, delay);
|
|
301
312
|
};
|
|
302
313
|
return connect();
|
|
@@ -304,7 +315,7 @@ export async function subscribeChannel(photonName, channel, handler, options) {
|
|
|
304
315
|
/**
|
|
305
316
|
* Publish a message to a channel on a daemon
|
|
306
317
|
*/
|
|
307
|
-
export async function publishToChannel(photonName, channel, message) {
|
|
318
|
+
export async function publishToChannel(photonName, channel, message, workingDir) {
|
|
308
319
|
const socketPath = getGlobalSocketPath();
|
|
309
320
|
const requestId = `pub_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
310
321
|
return new Promise((resolve, reject) => {
|
|
@@ -320,6 +331,7 @@ export async function publishToChannel(photonName, channel, message) {
|
|
|
320
331
|
photonName,
|
|
321
332
|
channel,
|
|
322
333
|
message,
|
|
334
|
+
workingDir,
|
|
323
335
|
};
|
|
324
336
|
client.write(JSON.stringify(request) + '\n');
|
|
325
337
|
});
|
|
@@ -337,8 +349,8 @@ export async function publishToChannel(photonName, channel, message) {
|
|
|
337
349
|
}
|
|
338
350
|
}
|
|
339
351
|
}
|
|
340
|
-
catch {
|
|
341
|
-
|
|
352
|
+
catch (e) {
|
|
353
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
342
354
|
}
|
|
343
355
|
});
|
|
344
356
|
client.on('error', (error) => {
|
|
@@ -352,7 +364,7 @@ export async function publishToChannel(photonName, channel, message) {
|
|
|
352
364
|
* Acquire a distributed lock
|
|
353
365
|
* Returns true if lock acquired, false if already held
|
|
354
366
|
*/
|
|
355
|
-
export async function acquireLock(photonName, lockName, timeout) {
|
|
367
|
+
export async function acquireLock(photonName, lockName, timeout, workingDir) {
|
|
356
368
|
const socketPath = getGlobalSocketPath();
|
|
357
369
|
const requestId = `lock_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
358
370
|
return new Promise((resolve, reject) => {
|
|
@@ -369,6 +381,7 @@ export async function acquireLock(photonName, lockName, timeout) {
|
|
|
369
381
|
sessionId: SESSION_ID,
|
|
370
382
|
lockName,
|
|
371
383
|
lockTimeout: timeout,
|
|
384
|
+
workingDir,
|
|
372
385
|
};
|
|
373
386
|
client.write(JSON.stringify(request) + '\n');
|
|
374
387
|
});
|
|
@@ -386,8 +399,8 @@ export async function acquireLock(photonName, lockName, timeout) {
|
|
|
386
399
|
}
|
|
387
400
|
}
|
|
388
401
|
}
|
|
389
|
-
catch {
|
|
390
|
-
|
|
402
|
+
catch (e) {
|
|
403
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
391
404
|
}
|
|
392
405
|
});
|
|
393
406
|
client.on('error', (error) => {
|
|
@@ -401,7 +414,7 @@ export async function acquireLock(photonName, lockName, timeout) {
|
|
|
401
414
|
* Release a distributed lock
|
|
402
415
|
* Returns true if lock released, false if not held by this session
|
|
403
416
|
*/
|
|
404
|
-
export async function releaseLock(photonName, lockName) {
|
|
417
|
+
export async function releaseLock(photonName, lockName, workingDir) {
|
|
405
418
|
const socketPath = getGlobalSocketPath();
|
|
406
419
|
const requestId = `unlock_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
407
420
|
return new Promise((resolve, reject) => {
|
|
@@ -417,6 +430,7 @@ export async function releaseLock(photonName, lockName) {
|
|
|
417
430
|
photonName,
|
|
418
431
|
sessionId: SESSION_ID,
|
|
419
432
|
lockName,
|
|
433
|
+
workingDir,
|
|
420
434
|
};
|
|
421
435
|
client.write(JSON.stringify(request) + '\n');
|
|
422
436
|
});
|
|
@@ -434,8 +448,8 @@ export async function releaseLock(photonName, lockName) {
|
|
|
434
448
|
}
|
|
435
449
|
}
|
|
436
450
|
}
|
|
437
|
-
catch {
|
|
438
|
-
|
|
451
|
+
catch (e) {
|
|
452
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
439
453
|
}
|
|
440
454
|
});
|
|
441
455
|
client.on('error', (error) => {
|
|
@@ -479,8 +493,8 @@ export async function listLocks(photonName) {
|
|
|
479
493
|
}
|
|
480
494
|
}
|
|
481
495
|
}
|
|
482
|
-
catch {
|
|
483
|
-
|
|
496
|
+
catch (e) {
|
|
497
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
484
498
|
}
|
|
485
499
|
});
|
|
486
500
|
client.on('error', (error) => {
|
|
@@ -529,8 +543,8 @@ export async function scheduleJob(photonName, jobId, method, cron, args) {
|
|
|
529
543
|
}
|
|
530
544
|
}
|
|
531
545
|
}
|
|
532
|
-
catch {
|
|
533
|
-
|
|
546
|
+
catch (e) {
|
|
547
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
534
548
|
}
|
|
535
549
|
});
|
|
536
550
|
client.on('error', (error) => {
|
|
@@ -575,8 +589,8 @@ export async function unscheduleJob(photonName, jobId) {
|
|
|
575
589
|
}
|
|
576
590
|
}
|
|
577
591
|
}
|
|
578
|
-
catch {
|
|
579
|
-
|
|
592
|
+
catch (e) {
|
|
593
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
580
594
|
}
|
|
581
595
|
});
|
|
582
596
|
client.on('error', (error) => {
|
|
@@ -620,8 +634,8 @@ export async function listJobs(photonName) {
|
|
|
620
634
|
}
|
|
621
635
|
}
|
|
622
636
|
}
|
|
623
|
-
catch {
|
|
624
|
-
|
|
637
|
+
catch (e) {
|
|
638
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
625
639
|
}
|
|
626
640
|
});
|
|
627
641
|
client.on('error', (error) => {
|
|
@@ -632,99 +646,91 @@ export async function listJobs(photonName) {
|
|
|
632
646
|
});
|
|
633
647
|
}
|
|
634
648
|
/**
|
|
635
|
-
*
|
|
636
|
-
* Called by dev server after hot-reload to sync daemon
|
|
649
|
+
* Ping daemon to check if it's responsive
|
|
637
650
|
*/
|
|
638
|
-
export async function
|
|
651
|
+
export async function pingDaemon(photonName) {
|
|
639
652
|
const socketPath = getGlobalSocketPath();
|
|
640
|
-
const requestId = `
|
|
641
|
-
return new Promise((resolve
|
|
653
|
+
const requestId = `ping_${Date.now()}`;
|
|
654
|
+
return new Promise((resolve) => {
|
|
642
655
|
const client = net.createConnection(socketPath);
|
|
643
656
|
const timeout = setTimeout(() => {
|
|
644
657
|
client.destroy();
|
|
645
|
-
|
|
646
|
-
},
|
|
658
|
+
resolve(false);
|
|
659
|
+
}, 5000);
|
|
647
660
|
client.on('connect', () => {
|
|
648
661
|
const request = {
|
|
649
|
-
type: '
|
|
662
|
+
type: 'ping',
|
|
650
663
|
id: requestId,
|
|
651
664
|
photonName,
|
|
652
|
-
photonPath,
|
|
653
665
|
};
|
|
654
666
|
client.write(JSON.stringify(request) + '\n');
|
|
655
667
|
});
|
|
656
668
|
client.on('data', (chunk) => {
|
|
657
669
|
try {
|
|
658
670
|
const response = JSON.parse(chunk.toString().trim());
|
|
659
|
-
if (response.id === requestId) {
|
|
671
|
+
if (response.id === requestId && response.type === 'pong') {
|
|
660
672
|
clearTimeout(timeout);
|
|
661
673
|
client.destroy();
|
|
662
|
-
|
|
663
|
-
const data = response.data;
|
|
664
|
-
resolve({
|
|
665
|
-
success: response.success ?? true,
|
|
666
|
-
error: data?.error,
|
|
667
|
-
sessionsUpdated: data?.sessionsUpdated,
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
else {
|
|
671
|
-
resolve({ success: false, error: response.error || 'Reload failed' });
|
|
672
|
-
}
|
|
674
|
+
resolve(true);
|
|
673
675
|
}
|
|
674
676
|
}
|
|
675
|
-
catch {
|
|
677
|
+
catch (error) {
|
|
676
678
|
// Ignore parse errors
|
|
677
679
|
}
|
|
678
680
|
});
|
|
679
|
-
client.on('error', (
|
|
681
|
+
client.on('error', () => {
|
|
680
682
|
clearTimeout(timeout);
|
|
681
683
|
client.destroy();
|
|
682
|
-
|
|
684
|
+
resolve(false);
|
|
685
|
+
});
|
|
686
|
+
client.on('end', () => {
|
|
687
|
+
clearTimeout(timeout);
|
|
688
|
+
client.destroy();
|
|
689
|
+
resolve(false);
|
|
683
690
|
});
|
|
684
691
|
});
|
|
685
692
|
}
|
|
686
693
|
/**
|
|
687
|
-
*
|
|
694
|
+
* Query daemon health status (uptime, memory, sessions, etc.)
|
|
688
695
|
*/
|
|
689
|
-
export async function
|
|
696
|
+
export async function queryDaemonStatus() {
|
|
690
697
|
const socketPath = getGlobalSocketPath();
|
|
691
|
-
const requestId = `
|
|
698
|
+
const requestId = `status_${Date.now()}`;
|
|
692
699
|
return new Promise((resolve) => {
|
|
693
700
|
const client = net.createConnection(socketPath);
|
|
694
701
|
const timeout = setTimeout(() => {
|
|
695
702
|
client.destroy();
|
|
696
|
-
resolve(
|
|
703
|
+
resolve(null);
|
|
697
704
|
}, 5000);
|
|
698
705
|
client.on('connect', () => {
|
|
699
706
|
const request = {
|
|
700
|
-
type: '
|
|
707
|
+
type: 'status',
|
|
701
708
|
id: requestId,
|
|
702
|
-
photonName,
|
|
703
709
|
};
|
|
704
710
|
client.write(JSON.stringify(request) + '\n');
|
|
705
711
|
});
|
|
706
712
|
client.on('data', (chunk) => {
|
|
707
713
|
try {
|
|
708
714
|
const response = JSON.parse(chunk.toString().trim());
|
|
709
|
-
if (response.id === requestId && response.type === '
|
|
715
|
+
if (response.id === requestId && response.type === 'result' && response.data) {
|
|
710
716
|
clearTimeout(timeout);
|
|
711
717
|
client.destroy();
|
|
712
|
-
resolve(
|
|
718
|
+
resolve(response.data);
|
|
713
719
|
}
|
|
714
720
|
}
|
|
715
|
-
catch
|
|
721
|
+
catch {
|
|
716
722
|
// Ignore parse errors
|
|
717
723
|
}
|
|
718
724
|
});
|
|
719
725
|
client.on('error', () => {
|
|
720
726
|
clearTimeout(timeout);
|
|
721
727
|
client.destroy();
|
|
722
|
-
resolve(
|
|
728
|
+
resolve(null);
|
|
723
729
|
});
|
|
724
730
|
client.on('end', () => {
|
|
725
731
|
clearTimeout(timeout);
|
|
726
732
|
client.destroy();
|
|
727
|
-
resolve(
|
|
733
|
+
resolve(null);
|
|
728
734
|
});
|
|
729
735
|
});
|
|
730
736
|
}
|
|
@@ -732,6 +738,48 @@ export async function pingDaemon(photonName) {
|
|
|
732
738
|
* Get events since a specific timestamp for a channel
|
|
733
739
|
* Used for explicit delta sync when client has missed events
|
|
734
740
|
*/
|
|
741
|
+
/**
|
|
742
|
+
* Clear cached instances for a photon in a given workingDir.
|
|
743
|
+
* Called by Beam when starting with a fresh workingDir to avoid stale in-memory state.
|
|
744
|
+
*/
|
|
745
|
+
export async function clearInstances(photonName, workingDir) {
|
|
746
|
+
const socketPath = getGlobalSocketPath();
|
|
747
|
+
const requestId = `clearinst_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
748
|
+
return new Promise((resolve) => {
|
|
749
|
+
const client = net.createConnection(socketPath);
|
|
750
|
+
const timeout = setTimeout(() => {
|
|
751
|
+
client.destroy();
|
|
752
|
+
resolve(false);
|
|
753
|
+
}, 5000);
|
|
754
|
+
client.on('connect', () => {
|
|
755
|
+
const request = {
|
|
756
|
+
type: 'clear_instances',
|
|
757
|
+
id: requestId,
|
|
758
|
+
photonName,
|
|
759
|
+
workingDir,
|
|
760
|
+
};
|
|
761
|
+
client.write(JSON.stringify(request) + '\n');
|
|
762
|
+
});
|
|
763
|
+
client.on('data', (chunk) => {
|
|
764
|
+
try {
|
|
765
|
+
const response = JSON.parse(chunk.toString().trim());
|
|
766
|
+
if (response.id === requestId) {
|
|
767
|
+
clearTimeout(timeout);
|
|
768
|
+
client.destroy();
|
|
769
|
+
resolve(response.success ?? true);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
catch (e) {
|
|
773
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
client.on('error', () => {
|
|
777
|
+
clearTimeout(timeout);
|
|
778
|
+
client.destroy();
|
|
779
|
+
resolve(false); // Daemon not running — nothing to clear
|
|
780
|
+
});
|
|
781
|
+
});
|
|
782
|
+
}
|
|
735
783
|
export async function getEventsSince(photonName, channel, lastEventId) {
|
|
736
784
|
const socketPath = getGlobalSocketPath();
|
|
737
785
|
const requestId = `getevents_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
@@ -769,8 +817,8 @@ export async function getEventsSince(photonName, channel, lastEventId) {
|
|
|
769
817
|
}
|
|
770
818
|
}
|
|
771
819
|
}
|
|
772
|
-
catch {
|
|
773
|
-
|
|
820
|
+
catch (e) {
|
|
821
|
+
logger.warn('Failed to parse daemon response', { error: getErrorMessage(e) });
|
|
774
822
|
}
|
|
775
823
|
});
|
|
776
824
|
client.on('error', (error) => {
|