@portel/photon 1.11.0 → 1.12.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.
Files changed (56) hide show
  1. package/README.md +81 -72
  2. package/dist/auto-ui/beam/photon-management.d.ts.map +1 -1
  3. package/dist/auto-ui/beam/photon-management.js +5 -0
  4. package/dist/auto-ui/beam/photon-management.js.map +1 -1
  5. package/dist/auto-ui/beam/routes/api-browse.d.ts +1 -2
  6. package/dist/auto-ui/beam/routes/api-browse.d.ts.map +1 -1
  7. package/dist/auto-ui/beam/routes/api-browse.js +140 -191
  8. package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
  9. package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
  10. package/dist/auto-ui/beam/routes/api-config.js +44 -1
  11. package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
  12. package/dist/auto-ui/beam.d.ts.map +1 -1
  13. package/dist/auto-ui/beam.js +874 -20
  14. package/dist/auto-ui/beam.js.map +1 -1
  15. package/dist/auto-ui/frontend/index.html +83 -60
  16. package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
  17. package/dist/auto-ui/streamable-http-transport.js +16 -2
  18. package/dist/auto-ui/streamable-http-transport.js.map +1 -1
  19. package/dist/auto-ui/types.d.ts +1 -1
  20. package/dist/auto-ui/types.d.ts.map +1 -1
  21. package/dist/auto-ui/types.js.map +1 -1
  22. package/dist/beam.bundle.js +2794 -322
  23. package/dist/beam.bundle.js.map +4 -4
  24. package/dist/cli/commands/package-app.d.ts.map +1 -1
  25. package/dist/cli/commands/package-app.js +116 -35
  26. package/dist/cli/commands/package-app.js.map +1 -1
  27. package/dist/context-store.d.ts +5 -0
  28. package/dist/context-store.d.ts.map +1 -1
  29. package/dist/context-store.js +9 -0
  30. package/dist/context-store.js.map +1 -1
  31. package/dist/daemon/server.js +303 -6
  32. package/dist/daemon/server.js.map +1 -1
  33. package/dist/loader.d.ts +4 -0
  34. package/dist/loader.d.ts.map +1 -1
  35. package/dist/loader.js +186 -1
  36. package/dist/loader.js.map +1 -1
  37. package/dist/photon-cli-runner.d.ts.map +1 -1
  38. package/dist/photon-cli-runner.js +21 -1
  39. package/dist/photon-cli-runner.js.map +1 -1
  40. package/dist/photon-doc-extractor.d.ts +6 -0
  41. package/dist/photon-doc-extractor.d.ts.map +1 -1
  42. package/dist/photon-doc-extractor.js +22 -0
  43. package/dist/photon-doc-extractor.js.map +1 -1
  44. package/dist/photons/tunnel.photon.d.ts +5 -9
  45. package/dist/photons/tunnel.photon.d.ts.map +1 -1
  46. package/dist/photons/tunnel.photon.js +36 -96
  47. package/dist/photons/tunnel.photon.js.map +1 -1
  48. package/dist/photons/tunnel.photon.ts +40 -112
  49. package/dist/server.d.ts.map +1 -1
  50. package/dist/server.js +27 -2
  51. package/dist/server.js.map +1 -1
  52. package/dist/test-runner.d.ts +13 -1
  53. package/dist/test-runner.d.ts.map +1 -1
  54. package/dist/test-runner.js +529 -122
  55. package/dist/test-runner.js.map +1 -1
  56. package/package.json +22 -6
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Tunnel - Expose local servers to the internet
3
3
  * @description Multi-provider tunneling for remote access to Beam and local services
4
- * @internal
4
+ * @icon 🌐
5
5
  */
6
- import { spawn, spawnSync, execSync } from 'child_process';
6
+ import { spawn, spawnSync } from 'child_process';
7
7
  // Track active tunnels
8
8
  const activeTunnels = new Map();
9
9
  export default class Tunnel {
@@ -12,21 +12,23 @@ export default class Tunnel {
12
12
  * @icon 🔍
13
13
  */
14
14
  async status() {
15
+ // Check which tunnels are still alive
16
+ for (const [port, tunnel] of activeTunnels) {
17
+ if (tunnel.process.killed || tunnel.process.exitCode !== null) {
18
+ tunnel.info.active = false;
19
+ activeTunnels.delete(port);
20
+ }
21
+ }
15
22
  const providers = [
16
23
  {
17
- name: 'localtunnel',
18
- available: true, // Always available via npx
19
- note: 'Ready (uses npx, no install needed)',
24
+ name: 'cloudflared',
25
+ available: this._checkCommand('cloudflared'),
26
+ install: 'brew install cloudflared',
20
27
  },
21
28
  {
22
29
  name: 'ngrok',
23
30
  available: this._checkCommand('ngrok'),
24
- install: 'brew install ngrok OR https://ngrok.com/download',
25
- },
26
- {
27
- name: 'cloudflared',
28
- available: this._checkCommand('cloudflared'),
29
- install: 'brew install cloudflared OR https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation',
31
+ install: 'brew install ngrok',
30
32
  },
31
33
  ];
32
34
  return {
@@ -37,67 +39,62 @@ export default class Tunnel {
37
39
  /**
38
40
  * Start a tunnel to expose Beam to the internet
39
41
  * @icon 🚀
42
+ * @format qr
40
43
  * @param provider Tunnel provider to use
41
44
  */
42
- async *start({ provider = 'localtunnel', } = {}) {
45
+ async *start({ provider = 'cloudflared', } = {}) {
43
46
  // Auto-detect Beam port from environment
44
47
  const port = parseInt(process.env.BEAM_PORT || '3117', 10);
45
48
  // Check if tunnel already exists for this port
46
- if (activeTunnels.has(port)) {
47
- const existing = activeTunnels.get(port);
48
- const publicIp = await this._getPublicIp();
49
- return {
50
- message: `Tunnel already active on port ${port}`,
51
- url: existing.info.url,
52
- link: existing.info.url,
53
- password: existing.info.provider === 'localtunnel' ? publicIp : undefined,
54
- provider: existing.info.provider,
55
- port,
56
- };
49
+ const existing = activeTunnels.get(port);
50
+ if (existing) {
51
+ // Verify the process is still alive
52
+ if (!existing.process.killed && existing.process.exitCode === null) {
53
+ return {
54
+ message: `Tunnel already running via ${existing.info.provider}`,
55
+ url: existing.info.url,
56
+ link: existing.info.url,
57
+ };
58
+ }
59
+ // Process died — clean up and start fresh
60
+ activeTunnels.delete(port);
57
61
  }
58
62
  yield {
59
63
  emit: 'status',
60
64
  value: { step: 'starting' },
61
- message: `Starting ${provider} tunnel for Beam (port ${port})...`,
65
+ message: `Starting ${provider} tunnel on port ${port}...`,
62
66
  };
63
67
  try {
64
68
  let url;
65
- let process;
69
+ let tunnelProcess;
66
70
  switch (provider) {
67
71
  case 'ngrok':
68
72
  if (!this._checkCommand('ngrok')) {
69
73
  throw new Error('ngrok not installed. Run: brew install ngrok');
70
74
  }
71
- ({ url, process } = await this._startNgrok(port));
75
+ ({ url, process: tunnelProcess } = await this._startNgrok(port));
72
76
  break;
73
77
  case 'cloudflared':
78
+ default:
74
79
  if (!this._checkCommand('cloudflared')) {
75
80
  throw new Error('cloudflared not installed. Run: brew install cloudflared');
76
81
  }
77
- ({ url, process } = await this._startCloudflared(port));
78
- break;
79
- case 'localtunnel':
80
- default:
81
- ({ url, process } = await this._startLocaltunnel(port));
82
+ ({ url, process: tunnelProcess } = await this._startCloudflared(port));
82
83
  break;
83
84
  }
84
- // Fetch public IP (needed for localtunnel password)
85
- const publicIp = await this._getPublicIp();
86
85
  const info = {
87
86
  provider,
88
87
  port,
89
88
  url,
90
- pid: process.pid,
89
+ pid: tunnelProcess.pid,
91
90
  startedAt: new Date(),
91
+ active: true,
92
92
  };
93
- activeTunnels.set(port, { process, info });
93
+ activeTunnels.set(port, { process: tunnelProcess, info });
94
94
  return {
95
- message: `Tunnel started successfully`,
95
+ message: `Tunnel started via ${provider}`,
96
96
  url,
97
97
  link: url,
98
- password: provider === 'localtunnel' ? publicIp : undefined,
99
- provider,
100
- port,
101
98
  };
102
99
  }
103
100
  catch (error) {
@@ -153,63 +150,6 @@ export default class Tunnel {
153
150
  const result = spawnSync(which, [cmd], { stdio: 'ignore' });
154
151
  return result.status === 0;
155
152
  }
156
- async _getPublicIp() {
157
- // Try multiple services in order
158
- const services = ['https://api.ipify.org', 'https://ifconfig.me/ip', 'https://icanhazip.com'];
159
- for (const service of services) {
160
- try {
161
- const result = execSync(`curl -s --max-time 3 ${service}`, {
162
- encoding: 'utf-8',
163
- timeout: 5000,
164
- });
165
- const ip = result.trim();
166
- if (ip && /^\d+\.\d+\.\d+\.\d+$/.test(ip)) {
167
- return ip;
168
- }
169
- }
170
- catch {
171
- continue;
172
- }
173
- }
174
- return 'unknown';
175
- }
176
- async _startLocaltunnel(port) {
177
- return new Promise((resolve, reject) => {
178
- const proc = spawn('npx', ['localtunnel', '--port', String(port)], {
179
- stdio: ['ignore', 'pipe', 'pipe'],
180
- });
181
- let output = '';
182
- const timeout = setTimeout(() => {
183
- reject(new Error('Timeout waiting for localtunnel URL'));
184
- }, 30000);
185
- proc.stdout?.on('data', (data) => {
186
- output += data.toString();
187
- // localtunnel outputs: "your url is: https://xxx.loca.lt"
188
- const match = output.match(/your url is: (https?:\/\/[^\s]+)/i);
189
- if (match) {
190
- clearTimeout(timeout);
191
- resolve({ url: match[1], process: proc });
192
- }
193
- });
194
- proc.stderr?.on('data', (data) => {
195
- const err = data.toString();
196
- if (err.includes('error')) {
197
- clearTimeout(timeout);
198
- reject(new Error(err));
199
- }
200
- });
201
- proc.on('error', (err) => {
202
- clearTimeout(timeout);
203
- reject(err);
204
- });
205
- proc.on('close', (code) => {
206
- if (code !== 0 && !output.includes('your url is')) {
207
- clearTimeout(timeout);
208
- reject(new Error(`localtunnel exited with code ${code}`));
209
- }
210
- });
211
- });
212
- }
213
153
  async _startNgrok(port) {
214
154
  return new Promise((resolve, reject) => {
215
155
  const proc = spawn('ngrok', ['http', String(port), '--log', 'stdout'], {
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel.photon.js","sourceRoot":"","sources":["../../src/photons/tunnel.photon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAgB,MAAM,eAAe,CAAC;AAUzE,uBAAuB;AACvB,MAAM,aAAa,GAA6D,IAAI,GAAG,EAAE,CAAC;AAE1F,MAAM,CAAC,OAAO,OAAO,MAAM;IACzB;;;OAGG;IACH,KAAK,CAAC,MAAM;QASV,MAAM,SAAS,GAAG;YAChB;gBACE,IAAI,EAAE,aAAa;gBACnB,SAAS,EAAE,IAAI,EAAE,2BAA2B;gBAC5C,IAAI,EAAE,qCAAqC;aAC5C;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;gBACtC,OAAO,EAAE,oDAAoD;aAC9D;YACD;gBACE,IAAI,EAAE,aAAa;gBACnB,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC;gBAC5C,OAAO,EACL,wIAAwI;aAC3I;SACF,CAAC;QAEF,OAAO;YACL,SAAS;YACT,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACrE,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,CAAC,KAAK,CAAC,EACX,QAAQ,GAAG,aAAa,MAItB,EAAE;QAWJ,yCAAyC;QACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;QAE3D,+CAA+C;QAC/C,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;YAC1C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;YAC3C,OAAO;gBACL,OAAO,EAAE,iCAAiC,IAAI,EAAE;gBAChD,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG;gBACtB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG;gBACvB,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;gBACzE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ;gBAChC,IAAI;aACL,CAAC;QACJ,CAAC;QAED,MAAM;YACJ,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;YAC3B,OAAO,EAAE,YAAY,QAAQ,0BAA0B,IAAI,MAAM;SAClE,CAAC;QAEF,IAAI,CAAC;YACH,IAAI,GAAW,CAAC;YAChB,IAAI,OAAqB,CAAC;YAE1B,QAAQ,QAAQ,EAAE,CAAC;gBACjB,KAAK,OAAO;oBACV,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;wBACjC,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;oBAClE,CAAC;oBACD,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;oBAClD,MAAM;gBAER,KAAK,aAAa;oBAChB,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,EAAE,CAAC;wBACvC,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;oBAC9E,CAAC;oBACD,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;oBACxD,MAAM;gBAER,KAAK,aAAa,CAAC;gBACnB;oBACE,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;oBACxD,MAAM;YACV,CAAC;YAED,oDAAoD;YACpD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;YAE3C,MAAM,IAAI,GAAe;gBACvB,QAAQ;gBACR,IAAI;gBACJ,GAAG;gBACH,GAAG,EAAE,OAAO,CAAC,GAAI;gBACjB,SAAS,EAAE,IAAI,IAAI,EAAE;aACtB,CAAC;YAEF,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAE3C,OAAO;gBACL,OAAO,EAAE,6BAA6B;gBACtC,GAAG;gBACH,IAAI,EAAE,GAAG;gBACT,QAAQ,EAAE,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;gBAC3D,QAAQ;gBACR,IAAI;aACL,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,CAAC,EACT,IAAI,GAIL;QACC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,4BAA4B,IAAI,EAAE,EAAE,CAAC;QACzE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACtB,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAE3B,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,WAAW,MAAM,CAAC,IAAI,CAAC,QAAQ,mBAAmB,IAAI,EAAE;SAClE,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC;QAEjC,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC3C,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACtB,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,YAAY,CAAC,CAAC,CAAC,mBAAmB;SACxE,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI;QACR,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAC/D,CAAC;IACJ,CAAC;IAED,+CAA+C;IAC/C,2BAA2B;IAC3B,+CAA+C;IAEvC,aAAa,CAAC,GAAW;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/D,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5D,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;IAC7B,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,iCAAiC;QACjC,MAAM,QAAQ,GAAG,CAAC,uBAAuB,EAAE,wBAAwB,EAAE,uBAAuB,CAAC,CAAC;QAE9F,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,QAAQ,CAAC,wBAAwB,OAAO,EAAE,EAAE;oBACzD,QAAQ,EAAE,OAAO;oBACjB,OAAO,EAAE,IAAI;iBACd,CAAC,CAAC;gBACH,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;gBACzB,IAAI,EAAE,IAAI,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;oBAC1C,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,IAAY;QAC1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE;gBACjE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAC;YAEH,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;YAC3D,CAAC,EAAE,KAAK,CAAC,CAAC;YAEV,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC/B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC1B,0DAA0D;gBAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBAChE,IAAI,KAAK,EAAE,CAAC;oBACV,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC5B,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC1B,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACvB,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACxB,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;oBAClD,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,IAAY;QACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE;gBACrE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAC;YAEH,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;YACrD,CAAC,EAAE,KAAK,CAAC,CAAC;YAEV,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC/B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC1B,4CAA4C;gBAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;gBACtE,IAAI,KAAK,EAAE,CAAC;oBACV,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC/B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5B,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACvB,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,IAAY;QAC1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,oBAAoB,IAAI,EAAE,CAAC,EAAE;gBACjF,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAC;YAEH,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;YAC3D,CAAC,EAAE,KAAK,CAAC,CAAC;YAEV,gCAAgC;YAChC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC/B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC1B,qCAAqC;gBACrC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;gBACvE,IAAI,KAAK,EAAE,CAAC;oBACV,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC/B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5B,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACvB,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
1
+ {"version":3,"file":"tunnel.photon.js","sourceRoot":"","sources":["../../src/photons/tunnel.photon.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Tunnel - Expose local servers to the internet
3
3
  * @description Multi-provider tunneling for remote access to Beam and local services
4
- * @internal
4
+ * @icon 🌐
5
5
  */
6
6
 
7
- import { spawn, spawnSync, execSync, ChildProcess } from 'child_process';
7
+ import { spawn, spawnSync, ChildProcess } from 'child_process';
8
8
 
9
9
  interface TunnelInfo {
10
10
  provider: string;
@@ -12,6 +12,7 @@ interface TunnelInfo {
12
12
  url: string;
13
13
  pid: number;
14
14
  startedAt: Date;
15
+ active: boolean;
15
16
  }
16
17
 
17
18
  // Track active tunnels
@@ -27,26 +28,27 @@ export default class Tunnel {
27
28
  name: string;
28
29
  available: boolean;
29
30
  install?: string;
30
- note?: string;
31
31
  }>;
32
32
  activeTunnels: TunnelInfo[];
33
33
  }> {
34
+ // Check which tunnels are still alive
35
+ for (const [port, tunnel] of activeTunnels) {
36
+ if (tunnel.process.killed || tunnel.process.exitCode !== null) {
37
+ tunnel.info.active = false;
38
+ activeTunnels.delete(port);
39
+ }
40
+ }
41
+
34
42
  const providers = [
35
43
  {
36
- name: 'localtunnel',
37
- available: true, // Always available via npx
38
- note: 'Ready (uses npx, no install needed)',
44
+ name: 'cloudflared',
45
+ available: this._checkCommand('cloudflared'),
46
+ install: 'brew install cloudflared',
39
47
  },
40
48
  {
41
49
  name: 'ngrok',
42
50
  available: this._checkCommand('ngrok'),
43
- install: 'brew install ngrok OR https://ngrok.com/download',
44
- },
45
- {
46
- name: 'cloudflared',
47
- available: this._checkCommand('cloudflared'),
48
- install:
49
- 'brew install cloudflared OR https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation',
51
+ install: 'brew install ngrok',
50
52
  },
51
53
  ];
52
54
 
@@ -59,92 +61,82 @@ export default class Tunnel {
59
61
  /**
60
62
  * Start a tunnel to expose Beam to the internet
61
63
  * @icon 🚀
64
+ * @format qr
62
65
  * @param provider Tunnel provider to use
63
66
  */
64
67
  async *start({
65
- provider = 'localtunnel',
68
+ provider = 'cloudflared',
66
69
  }: {
67
- /** Provider: localtunnel, ngrok, or cloudflared */
68
- provider?: 'localtunnel' | 'ngrok' | 'cloudflared';
70
+ /** Provider: cloudflared or ngrok */
71
+ provider?: 'cloudflared' | 'ngrok';
69
72
  } = {}): AsyncGenerator<
70
73
  { emit: string; value?: any; message: string },
71
74
  {
72
75
  message: string;
73
76
  url: string;
74
77
  link: string;
75
- provider: string;
76
- port: number;
77
- password?: string;
78
78
  }
79
79
  > {
80
80
  // Auto-detect Beam port from environment
81
81
  const port = parseInt(process.env.BEAM_PORT || '3117', 10);
82
82
 
83
83
  // Check if tunnel already exists for this port
84
- if (activeTunnels.has(port)) {
85
- const existing = activeTunnels.get(port)!;
86
- const publicIp = await this._getPublicIp();
87
- return {
88
- message: `Tunnel already active on port ${port}`,
89
- url: existing.info.url,
90
- link: existing.info.url,
91
- password: existing.info.provider === 'localtunnel' ? publicIp : undefined,
92
- provider: existing.info.provider,
93
- port,
94
- };
84
+ const existing = activeTunnels.get(port);
85
+ if (existing) {
86
+ // Verify the process is still alive
87
+ if (!existing.process.killed && existing.process.exitCode === null) {
88
+ return {
89
+ message: `Tunnel already running via ${existing.info.provider}`,
90
+ url: existing.info.url,
91
+ link: existing.info.url,
92
+ };
93
+ }
94
+ // Process died — clean up and start fresh
95
+ activeTunnels.delete(port);
95
96
  }
96
97
 
97
98
  yield {
98
99
  emit: 'status',
99
100
  value: { step: 'starting' },
100
- message: `Starting ${provider} tunnel for Beam (port ${port})...`,
101
+ message: `Starting ${provider} tunnel on port ${port}...`,
101
102
  };
102
103
 
103
104
  try {
104
105
  let url: string;
105
- let process: ChildProcess;
106
+ let tunnelProcess: ChildProcess;
106
107
 
107
108
  switch (provider) {
108
109
  case 'ngrok':
109
110
  if (!this._checkCommand('ngrok')) {
110
111
  throw new Error('ngrok not installed. Run: brew install ngrok');
111
112
  }
112
- ({ url, process } = await this._startNgrok(port));
113
+ ({ url, process: tunnelProcess } = await this._startNgrok(port));
113
114
  break;
114
115
 
115
116
  case 'cloudflared':
117
+ default:
116
118
  if (!this._checkCommand('cloudflared')) {
117
119
  throw new Error('cloudflared not installed. Run: brew install cloudflared');
118
120
  }
119
- ({ url, process } = await this._startCloudflared(port));
120
- break;
121
-
122
- case 'localtunnel':
123
- default:
124
- ({ url, process } = await this._startLocaltunnel(port));
121
+ ({ url, process: tunnelProcess } = await this._startCloudflared(port));
125
122
  break;
126
123
  }
127
124
 
128
- // Fetch public IP (needed for localtunnel password)
129
- const publicIp = await this._getPublicIp();
130
-
131
125
  const info: TunnelInfo = {
132
126
  provider,
133
127
  port,
134
128
  url,
135
- pid: process.pid!,
129
+ pid: tunnelProcess.pid!,
136
130
  startedAt: new Date(),
131
+ active: true,
137
132
  };
138
133
 
139
- activeTunnels.set(port, { process, info });
134
+ activeTunnels.set(port, { process: tunnelProcess, info });
140
135
 
141
136
  return {
142
- message: `Tunnel started successfully`,
137
+ message: `Tunnel started via ${provider}`,
143
138
  url,
144
139
  link: url,
145
- password: provider === 'localtunnel' ? publicIp : undefined,
146
- provider,
147
- port,
148
140
  };
149
141
  } catch (error: any) {
150
142
  throw new Error(error.message);
@@ -215,70 +207,6 @@ export default class Tunnel {
215
207
  return result.status === 0;
216
208
  }
217
209
 
218
- private async _getPublicIp(): Promise<string> {
219
- // Try multiple services in order
220
- const services = ['https://api.ipify.org', 'https://ifconfig.me/ip', 'https://icanhazip.com'];
221
-
222
- for (const service of services) {
223
- try {
224
- const result = execSync(`curl -s --max-time 3 ${service}`, {
225
- encoding: 'utf-8',
226
- timeout: 5000,
227
- });
228
- const ip = result.trim();
229
- if (ip && /^\d+\.\d+\.\d+\.\d+$/.test(ip)) {
230
- return ip;
231
- }
232
- } catch {
233
- continue;
234
- }
235
- }
236
- return 'unknown';
237
- }
238
-
239
- private async _startLocaltunnel(port: number): Promise<{ url: string; process: ChildProcess }> {
240
- return new Promise((resolve, reject) => {
241
- const proc = spawn('npx', ['localtunnel', '--port', String(port)], {
242
- stdio: ['ignore', 'pipe', 'pipe'],
243
- });
244
-
245
- let output = '';
246
- const timeout = setTimeout(() => {
247
- reject(new Error('Timeout waiting for localtunnel URL'));
248
- }, 30000);
249
-
250
- proc.stdout?.on('data', (data) => {
251
- output += data.toString();
252
- // localtunnel outputs: "your url is: https://xxx.loca.lt"
253
- const match = output.match(/your url is: (https?:\/\/[^\s]+)/i);
254
- if (match) {
255
- clearTimeout(timeout);
256
- resolve({ url: match[1], process: proc });
257
- }
258
- });
259
-
260
- proc.stderr?.on('data', (data) => {
261
- const err = data.toString();
262
- if (err.includes('error')) {
263
- clearTimeout(timeout);
264
- reject(new Error(err));
265
- }
266
- });
267
-
268
- proc.on('error', (err) => {
269
- clearTimeout(timeout);
270
- reject(err);
271
- });
272
-
273
- proc.on('close', (code) => {
274
- if (code !== 0 && !output.includes('your url is')) {
275
- clearTimeout(timeout);
276
- reject(new Error(`localtunnel exited with code ${code}`));
277
- }
278
- });
279
- });
280
- }
281
-
282
210
  private async _startNgrok(port: number): Promise<{ url: string; process: ChildProcess }> {
283
211
  return new Promise((resolve, reject) => {
284
212
  const proc = spawn('ngrok', ['http', String(port), '--log', 'stdout'], {
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -464,6 +464,16 @@ export class PhotonServer {
464
464
  description: `List all available instances.`,
465
465
  inputSchema: { type: 'object', properties: {} },
466
466
  });
467
+ tools.push({
468
+ name: '_undo',
469
+ description: `Undo the last state mutation. Reverts the most recent tool call's changes.`,
470
+ inputSchema: { type: 'object', properties: {} },
471
+ });
472
+ tools.push({
473
+ name: '_redo',
474
+ description: `Redo the last undone mutation. Re-applies a previously undone change.`,
475
+ inputSchema: { type: 'object', properties: {} },
476
+ });
467
477
  }
468
478
  return { tools };
469
479
  }
@@ -472,8 +482,12 @@ export class PhotonServer {
472
482
  throw new Error('MCP not loaded');
473
483
  }
474
484
  const { name: toolName, arguments: args } = request.params;
475
- // Route _use and _instances through daemon for stateful photons
476
- if (this.daemonName && (toolName === '_use' || toolName === '_instances')) {
485
+ // Route _use, _instances, _undo, _redo through daemon for stateful photons
486
+ if (this.daemonName &&
487
+ (toolName === '_use' ||
488
+ toolName === '_instances' ||
489
+ toolName === '_undo' ||
490
+ toolName === '_redo')) {
477
491
  const { sendCommand } = await import('./daemon/client.js');
478
492
  const sendOpts = {
479
493
  photonPath: this.options.filePath,
@@ -1290,6 +1304,10 @@ export class PhotonServer {
1290
1304
  if (!message || typeof message !== 'object')
1291
1305
  return;
1292
1306
  const msg = message;
1307
+ // Debug logging for cross-client event transmission
1308
+ if (process.env.PHOTON_DEBUG_EVENTS === '1') {
1309
+ console.error(`[PHOTON-SERVER] Received daemon message on ${String(msg.channel)}: event=${String(msg.event)}`);
1310
+ }
1293
1311
  // Use STANDARD notification with embedded photon data
1294
1312
  // Claude Desktop will forward this (it's a standard notification)
1295
1313
  // Our bridge extracts _photon and routes to the appropriate event handler
@@ -1306,9 +1324,16 @@ export class PhotonServer {
1306
1324
  },
1307
1325
  };
1308
1326
  try {
1327
+ if (process.env.PHOTON_DEBUG_EVENTS === '1') {
1328
+ console.error(`[PHOTON-SERVER] Sending notification to MCP clients...`);
1329
+ }
1309
1330
  await this.server.notification(payload);
1331
+ if (process.env.PHOTON_DEBUG_EVENTS === '1') {
1332
+ console.error(`[PHOTON-SERVER] Notification sent successfully`);
1333
+ }
1310
1334
  }
1311
1335
  catch (e) {
1336
+ console.error(`[PHOTON-SERVER-ERROR] Notification send failed: ${getErrorMessage(e)}`);
1312
1337
  this.log('debug', 'Notification send failed', { error: getErrorMessage(e) });
1313
1338
  }
1314
1339
  // Also send to SSE sessions — snapshot to avoid live-iterator + await issues