@openchambery/web 1.17.1-beta.7 → 1.17.1-beta.9

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 (140) hide show
  1. package/README.md +3 -39
  2. package/bin/cli-output.js +0 -16
  3. package/bin/cli.js +3 -66
  4. package/bin/cli.test.js +4 -81
  5. package/bin/lib/DOCUMENTATION.md +5 -19
  6. package/bin/lib/cli-args.js +3 -327
  7. package/bin/lib/cli-http.js +0 -16
  8. package/bin/lib/cli-lifecycle.js +2 -111
  9. package/bin/lib/cli-paths.js +0 -57
  10. package/dist/assets/{AgentAvatar-htFrIvQx.js → AgentAvatar-C6Hxu5_o.js} +1 -1
  11. package/dist/assets/{AssistantView-BZiJsNuI.js → AssistantView-BKg8KK5a.js} +1 -1
  12. package/dist/assets/{ChatContainer-CdmcMnL3.js → ChatContainer-CuxynsBz.js} +5 -5
  13. package/dist/assets/{DiagramView-B7sq74V-.js → DiagramView-CjMblW4W.js} +1 -1
  14. package/dist/assets/{FadeInOnReveal-8fY7XL23.js → FadeInOnReveal-CvNA_aGD.js} +1 -1
  15. package/dist/assets/{Icon-B7eLbnyj.js → Icon-BPJ_quEe.js} +1 -1
  16. package/dist/assets/{MarkdownRendererImpl-DICju9ve.js → MarkdownRendererImpl--oy9PEaq.js} +1 -1
  17. package/dist/assets/{MobileDetailNavigation-CuxWU1yf.js → MobileDetailNavigation-j5XTy0wI.js} +1 -1
  18. package/dist/assets/{MobileShareBridge-CPg9Eyro.js → MobileShareBridge-BnF86wui.js} +1 -1
  19. package/dist/assets/{MobileSurface-D7sDH_tx.js → MobileSurface-D0LTFt1w.js} +1 -1
  20. package/dist/assets/{MultiRunWindow-MSO0Equt.js → MultiRunWindow-BTTFYUzI.js} +1 -1
  21. package/dist/assets/{OnboardingScreen-C87u_MLg.js → OnboardingScreen-CdvaEBtt.js} +1 -1
  22. package/dist/assets/{OverlayScrollbar-Kmmybw-z.js → OverlayScrollbar-DyP73J3X.js} +1 -1
  23. package/dist/assets/SettingsView-JQxnmG9X.js +25 -0
  24. package/dist/assets/{SettingsWindow-Bl25cfXX.js → SettingsWindow-Ddr1B6Hc.js} +1 -1
  25. package/dist/assets/{TerminalView-jR5jP1b0.js → TerminalView-bHOuUIxH.js} +1 -1
  26. package/dist/assets/{ToolOutputDialog-DCEZb2DZ.js → ToolOutputDialog-CbGv7HQ5.js} +1 -1
  27. package/dist/assets/{appThemeRegistry-aiRF-s3c.js → appThemeRegistry-DIDGDdQq.js} +2 -2
  28. package/dist/assets/{button-bYWkDtDI.js → button-BmNJBT13.js} +1 -1
  29. package/dist/assets/{clipboard-CzpzN4Um.js → clipboard-CXWbHCAk.js} +1 -1
  30. package/dist/assets/{collapsible-A1PFvMRp.js → collapsible-68IqWBM1.js} +1 -1
  31. package/dist/assets/{context-menu-CkpHn-Bm.js → context-menu-B-8pAqjS.js} +1 -1
  32. package/dist/assets/desktopHosts-BpjUSDz4.js +1 -0
  33. package/dist/assets/{desktopRelayRestore-C5vYnSTd.js → desktopRelayRestore-BzUEk1i7.js} +1 -1
  34. package/dist/assets/{diagram-BkwKWaTO.js → diagram-YN0GZ1Q0.js} +1 -1
  35. package/dist/assets/{dialog-DW7-_iqo.js → dialog-BV1ENlLf.js} +1 -1
  36. package/dist/assets/es-EXZUX1sB.js +15 -0
  37. package/dist/assets/{fileQueries-P9SX4YwC.js → fileQueries-i4oziMnC.js} +1 -1
  38. package/dist/assets/fr-jWNPO91J.js +13 -0
  39. package/dist/assets/{gitApi-CMsZ2v08.js → gitApi-BuTpcy5P.js} +1 -1
  40. package/dist/assets/{gitApiHttp-DvIIcDAO.js → gitApiHttp-C1DaEMKR.js} +1 -1
  41. package/dist/assets/{input-B9aNttqV.js → input-BLVhPvhN.js} +1 -1
  42. package/dist/assets/{insertionBoundaries-Di3rCXgN.js → insertionBoundaries-D8FUCksc.js} +1 -1
  43. package/dist/assets/ja-Dcb0VtDE.js +15 -0
  44. package/dist/assets/ko-CX71xNDX.js +15 -0
  45. package/dist/assets/{main-DY27kMV5.js → main-Bz2igSmw.js} +2 -2
  46. package/dist/assets/{main-Chtf300b.js → main-C3JiVxSp.js} +5 -5
  47. package/dist/assets/{markdown-worker-BoB1_DPo.js → markdown-worker-Cq3Twp1A.js} +1 -1
  48. package/dist/assets/{markdownTheme-om5XcPqq.js → markdownTheme-CCnvI6L0.js} +1 -1
  49. package/dist/assets/{miniChat-BWbpl5SN.js → miniChat-6EMGKhlG.js} +2 -2
  50. package/dist/assets/mobile-DP5GfqmN.js +2 -0
  51. package/dist/assets/{multirun-BfPcVktg.js → multirun-9f6WZ3Jd.js} +1 -1
  52. package/dist/assets/persistence-C_KCiMcY.js +3 -0
  53. package/dist/assets/{pl-BSjLn4dm.js → pl-mR_3Sqr8.js} +2 -2
  54. package/dist/assets/{projectMeta-CiAR7MRG.js → projectMeta-Dsa2wr8n.js} +1 -1
  55. package/dist/assets/pt-BR-D1RpVOvC.js +15 -0
  56. package/dist/assets/radio-CrWrJ2b-.js +1 -0
  57. package/dist/assets/{renderElectronMiniChatApp-CiEXAVSt.js → renderElectronMiniChatApp-4adD-9dD.js} +2 -2
  58. package/dist/assets/{renderMobileApp-BHvgSVPk.js → renderMobileApp-bSjLTDsy.js} +3 -3
  59. package/dist/assets/{runtimeConfig-49YbZaqI.js → runtimeConfig-JSaYFA5x.js} +1 -1
  60. package/dist/assets/{runtimeEndpointReset-CdhtjuPe.js → runtimeEndpointReset-DW-MKG59.js} +1 -1
  61. package/dist/assets/{sortable-tabs-strip-XeYica3j.js → sortable-tabs-strip-NTPx-T_l.js} +1 -1
  62. package/dist/assets/src-B8mzksNL.css +2 -0
  63. package/dist/assets/store-oojlrF4d.js +15 -0
  64. package/dist/assets/{terminalApi-DAu7xKli.js → terminalApi-BYTA045F.js} +1 -1
  65. package/dist/assets/{tooltip-BSlxaNrR.js → tooltip-BYGBBTc2.js} +1 -1
  66. package/dist/assets/uk-UvnVqWv-.js +15 -0
  67. package/dist/assets/{url-DjkTDrad.js → url-CGHw6D-E.js} +1 -1
  68. package/dist/assets/useAppFontEffects-BIO3lPVM.js +7 -0
  69. package/dist/assets/{useDesktopWindowControlsLayout-BwYnhrEy.js → useDesktopWindowControlsLayout-Df2h_cM_.js} +1 -1
  70. package/dist/assets/{useEffectiveDirectory-CEmsrrEs.js → useEffectiveDirectory-D0vaM832.js} +1 -1
  71. package/dist/assets/{useFontPreferences-BxMT_kty.js → useFontPreferences-Bu4ME5hk.js} +1 -1
  72. package/dist/assets/useMobileNavigationStore-7HNp5YHY.js +475 -0
  73. package/dist/assets/useSessionAutoCleanup-BPNLtDRJ.js +1 -0
  74. package/dist/assets/{useWorkerHighlightedLines-CFW2AoPL.js → useWorkerHighlightedLines-DYfBlGb-.js} +1 -1
  75. package/dist/assets/{utils-RUACCsOs.js → utils-DyUyiLje.js} +1 -1
  76. package/dist/assets/zh-CN-9v-RC966.js +15 -0
  77. package/dist/assets/zh-TW-BZ_wZdC-.js +15 -0
  78. package/dist/index.html +8 -8
  79. package/dist/mini-chat.html +8 -8
  80. package/dist/mobile.html +8 -8
  81. package/package.json +1 -1
  82. package/server/index.d.ts +0 -6
  83. package/server/index.js +5 -153
  84. package/server/lib/opencode/DOCUMENTATION.md +6 -10
  85. package/server/lib/opencode/cli-entry-runtime.js +0 -10
  86. package/server/lib/opencode/cli-options.js +0 -65
  87. package/server/lib/opencode/core-routes.js +2 -4
  88. package/server/lib/opencode/routes.test.js +0 -1
  89. package/server/lib/opencode/server-startup-runtime.js +0 -55
  90. package/server/lib/opencode/settings-helpers.js +0 -55
  91. package/server/lib/opencode/settings-helpers.test.js +0 -20
  92. package/server/lib/opencode/settings-normalization-runtime.js +0 -87
  93. package/server/lib/opencode/settings-normalization-runtime.test.js +0 -3
  94. package/server/lib/opencode/settings-runtime.js +9 -102
  95. package/server/lib/opencode/settings-runtime.test.js +0 -10
  96. package/server/lib/opencode/shutdown-runtime.js +1 -9
  97. package/server/lib/opencode/shutdown-runtime.test.js +0 -2
  98. package/server/lib/opencode/startup-pipeline-runtime.js +0 -20
  99. package/server/lib/opencode/startup-pipeline-runtime.test.js +2 -3
  100. package/server/lib/opencode/tunnel-wiring-runtime.js +2 -80
  101. package/server/lib/relay/DOCUMENTATION.md +1 -1
  102. package/bin/lib/cli-tunnel-capabilities.js +0 -9
  103. package/bin/lib/cli-tunnel-profiles.js +0 -366
  104. package/bin/lib/cli-tunnel-utils.js +0 -300
  105. package/bin/lib/commands-tunnel.js +0 -1761
  106. package/dist/assets/SettingsView-5YNu54KI.js +0 -25
  107. package/dist/assets/desktopHosts-D5m_ggY1.js +0 -1
  108. package/dist/assets/es-Cei_75Jt.js +0 -15
  109. package/dist/assets/fr-Dn7WSHh2.js +0 -13
  110. package/dist/assets/ja-DFARVqVj.js +0 -15
  111. package/dist/assets/ko-pyLnIyDY.js +0 -15
  112. package/dist/assets/mobile-DEQeGskq.js +0 -2
  113. package/dist/assets/persistence-CHA81Od7.js +0 -3
  114. package/dist/assets/pt-BR-DaWvr_0A.js +0 -15
  115. package/dist/assets/radio-BnF4XhCC.js +0 -1
  116. package/dist/assets/src-BtkWqMFu.css +0 -2
  117. package/dist/assets/store-DIpqFVjs.js +0 -15
  118. package/dist/assets/uk-CHCRqRKf.js +0 -15
  119. package/dist/assets/useAppFontEffects-BRNICZS2.js +0 -7
  120. package/dist/assets/useMobileNavigationStore-DryW-QdG.js +0 -475
  121. package/dist/assets/useSessionAutoCleanup-DMJ1LiW_.js +0 -1
  122. package/dist/assets/zh-CN-BWEQZKXk.js +0 -15
  123. package/dist/assets/zh-TW-BbO-gJq3.js +0 -15
  124. package/server/lib/cloudflare-tunnel.js +0 -618
  125. package/server/lib/ngrok-tunnel.js +0 -343
  126. package/server/lib/ngrok-tunnel.test.js +0 -50
  127. package/server/lib/tunnels/DOCUMENTATION.md +0 -21
  128. package/server/lib/tunnels/executable-search.js +0 -140
  129. package/server/lib/tunnels/executable-search.test.js +0 -96
  130. package/server/lib/tunnels/index.js +0 -179
  131. package/server/lib/tunnels/index.test.js +0 -93
  132. package/server/lib/tunnels/install-help.js +0 -56
  133. package/server/lib/tunnels/install-help.test.js +0 -31
  134. package/server/lib/tunnels/managed-config.js +0 -201
  135. package/server/lib/tunnels/providers/cloudflare.js +0 -266
  136. package/server/lib/tunnels/providers/ngrok.js +0 -123
  137. package/server/lib/tunnels/registry.js +0 -51
  138. package/server/lib/tunnels/routes.js +0 -610
  139. package/server/lib/tunnels/types.js +0 -245
  140. package/server/lib/tunnels/types.test.js +0 -34
@@ -1,266 +0,0 @@
1
- import {
2
- checkCloudflareApiReachability,
3
- checkCloudflaredAvailable,
4
- inspectManagedLocalCloudflareConfig,
5
- normalizeCloudflareTunnelHostname,
6
- startCloudflareManagedLocalTunnel,
7
- startCloudflareManagedRemoteTunnel,
8
- startCloudflareQuickTunnel,
9
- } from '../../cloudflare-tunnel.js';
10
-
11
- import {
12
- TUNNEL_INTENT_EPHEMERAL_PUBLIC,
13
- TUNNEL_INTENT_PERSISTENT_PUBLIC,
14
- TUNNEL_MODE_MANAGED_LOCAL,
15
- TUNNEL_MODE_MANAGED_REMOTE,
16
- TUNNEL_MODE_QUICK,
17
- TUNNEL_PROVIDER_CLOUDFLARE,
18
- TunnelServiceError,
19
- } from '../types.js';
20
- import { getTunnelDependencyInstallInfo } from '../install-help.js';
21
-
22
- export const cloudflareTunnelProviderCapabilities = {
23
- provider: TUNNEL_PROVIDER_CLOUDFLARE,
24
- defaults: {
25
- mode: TUNNEL_MODE_QUICK,
26
- optionDefaults: {},
27
- },
28
- modes: [
29
- {
30
- key: TUNNEL_MODE_QUICK,
31
- label: 'Quick Tunnel',
32
- intent: TUNNEL_INTENT_EPHEMERAL_PUBLIC,
33
- requires: [],
34
- supports: ['sessionTTL'],
35
- stability: 'ga',
36
- },
37
- {
38
- key: TUNNEL_MODE_MANAGED_REMOTE,
39
- label: 'Managed Remote Tunnel',
40
- intent: TUNNEL_INTENT_PERSISTENT_PUBLIC,
41
- requires: ['token', 'hostname'],
42
- supports: ['customDomain', 'sessionTTL'],
43
- stability: 'ga',
44
- },
45
- {
46
- key: TUNNEL_MODE_MANAGED_LOCAL,
47
- label: 'Managed Local Tunnel',
48
- intent: TUNNEL_INTENT_PERSISTENT_PUBLIC,
49
- requires: [],
50
- supports: ['configFile', 'customDomain', 'sessionTTL'],
51
- stability: 'ga',
52
- },
53
- ],
54
- };
55
-
56
- export function createCloudflareTunnelProvider() {
57
- const validateTokenShape = (value) => {
58
- if (typeof value !== 'string') {
59
- return { ok: false, detail: 'Managed remote token is missing.' };
60
- }
61
- const trimmed = value.trim();
62
- if (!trimmed) {
63
- return { ok: false, detail: 'Managed remote token is missing.' };
64
- }
65
- if (/\s/.test(trimmed)) {
66
- return { ok: false, detail: 'Managed remote token has whitespace; provide the raw token value.' };
67
- }
68
- return { ok: true, detail: 'Managed remote token looks valid.' };
69
- };
70
-
71
- const createModeSummary = (checks) => {
72
- const failures = checks.filter((entry) => entry.status === 'fail').length;
73
- const warnings = checks.filter((entry) => entry.status === 'warn').length;
74
- return {
75
- ready: failures === 0,
76
- failures,
77
- warnings,
78
- };
79
- };
80
-
81
- const describeMode = ({ mode, checks }) => {
82
- const summary = createModeSummary(checks);
83
- const blockers = checks
84
- .filter((entry) => entry.status === 'fail' && entry.id !== 'startup_readiness')
85
- .map((entry) => entry.detail || entry.label || entry.id);
86
- return {
87
- mode,
88
- checks,
89
- summary,
90
- ready: summary.ready,
91
- blockers,
92
- };
93
- };
94
-
95
- return {
96
- id: TUNNEL_PROVIDER_CLOUDFLARE,
97
- capabilities: cloudflareTunnelProviderCapabilities,
98
- checkAvailability: async () => {
99
- const result = await checkCloudflaredAvailable();
100
- if (result.available) {
101
- return {
102
- ...result,
103
- ...getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_CLOUDFLARE),
104
- };
105
- }
106
- const installInfo = getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_CLOUDFLARE);
107
- return {
108
- ...result,
109
- ...installInfo,
110
- };
111
- },
112
- diagnose: async (request = {}) => {
113
- const dependency = await checkCloudflaredAvailable();
114
- const network = await checkCloudflareApiReachability();
115
- const installInfo = getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_CLOUDFLARE);
116
-
117
- const providerChecks = [
118
- {
119
- id: 'dependency',
120
- label: 'cloudflared installed',
121
- status: dependency.available ? 'pass' : 'fail',
122
- detail: dependency.available
123
- ? (dependency.version || dependency.path || 'cloudflared available')
124
- : installInfo.message,
125
- },
126
- {
127
- id: 'network',
128
- label: 'Cloudflare API reachable',
129
- status: network.reachable ? 'pass' : 'fail',
130
- detail: network.reachable
131
- ? (network.status ? `HTTP ${network.status}` : 'Reachable')
132
- : (network.error || 'Could not reach api.trycloudflare.com'),
133
- },
134
- ];
135
-
136
- const startupReady = dependency.available && network.reachable;
137
- const startupDetail = startupReady
138
- ? 'Provider dependency and network checks passed.'
139
- : 'Resolve provider checks before starting tunnels.';
140
-
141
- const quickChecks = [
142
- {
143
- id: 'startup_readiness',
144
- label: 'Provider startup readiness',
145
- status: startupReady ? 'pass' : 'fail',
146
- detail: startupDetail,
147
- },
148
- {
149
- id: 'quick_mode_prerequisites',
150
- label: 'Quick tunnel prerequisites',
151
- status: network.reachable ? 'pass' : 'fail',
152
- detail: network.reachable
153
- ? 'Cloudflare edge is reachable for quick tunnels.'
154
- : 'Cloudflare edge is not reachable for quick tunnels.',
155
- },
156
- ];
157
-
158
- const managedLocalInspection = inspectManagedLocalCloudflareConfig({
159
- configPath: request.configPath,
160
- hostname: request.hostname,
161
- });
162
- const managedLocalChecks = [
163
- {
164
- id: 'startup_readiness',
165
- label: 'Provider startup readiness',
166
- status: startupReady ? 'pass' : 'fail',
167
- detail: startupDetail,
168
- },
169
- {
170
- id: 'managed_local_config',
171
- label: 'Managed local config',
172
- status: managedLocalInspection.ok ? 'pass' : 'fail',
173
- detail: managedLocalInspection.ok
174
- ? `${managedLocalInspection.effectiveConfigPath}${managedLocalInspection.resolvedHostname ? ` (${managedLocalInspection.resolvedHostname})` : ''}`
175
- : managedLocalInspection.error,
176
- },
177
- ];
178
-
179
- const normalizedHost = normalizeCloudflareTunnelHostname(request.hostname);
180
- const hostnameMissing = !normalizedHost;
181
- const remoteTokenValidation = validateTokenShape(request.token);
182
- const tokenMissing = typeof request.token !== 'string' || request.token.trim().length === 0;
183
- const hasSavedManagedRemoteProfile = request.hasSavedManagedRemoteProfile === true;
184
- const tokenProvided = request.tokenProvided === true;
185
- const hostnameProvided = request.hostnameProvided === true;
186
- const hasExplicitManagedRemoteInput = tokenProvided || hostnameProvided;
187
- const canUseSavedProfileForHostname = !hasExplicitManagedRemoteInput && hostnameMissing && hasSavedManagedRemoteProfile;
188
- const canUseSavedProfileForToken = !hasExplicitManagedRemoteInput && tokenMissing && hasSavedManagedRemoteProfile;
189
- const savedProfileReadyDetail = 'at least one saved profile present';
190
- const managedRemoteChecks = [
191
- {
192
- id: 'startup_readiness',
193
- label: 'Provider startup readiness',
194
- status: startupReady ? 'pass' : 'fail',
195
- detail: startupDetail,
196
- },
197
- {
198
- id: 'managed_remote_hostname',
199
- label: 'Managed remote hostname',
200
- status: normalizedHost || canUseSavedProfileForHostname ? 'pass' : 'fail',
201
- detail: normalizedHost
202
- ? normalizedHost
203
- : canUseSavedProfileForHostname
204
- ? savedProfileReadyDetail
205
- : 'Managed remote hostname is required (use --hostname).',
206
- },
207
- {
208
- id: 'managed_remote_token',
209
- label: 'Managed remote token',
210
- status: remoteTokenValidation.ok || canUseSavedProfileForToken ? 'pass' : 'fail',
211
- detail: canUseSavedProfileForToken
212
- ? savedProfileReadyDetail
213
- : remoteTokenValidation.detail,
214
- },
215
- ];
216
-
217
- const allModes = [
218
- describeMode({ mode: TUNNEL_MODE_QUICK, checks: quickChecks }),
219
- describeMode({ mode: TUNNEL_MODE_MANAGED_REMOTE, checks: managedRemoteChecks }),
220
- describeMode({ mode: TUNNEL_MODE_MANAGED_LOCAL, checks: managedLocalChecks }),
221
- ];
222
-
223
- const modeFilter = typeof request.mode === 'string' && request.mode.trim().length > 0
224
- ? request.mode.trim().toLowerCase()
225
- : null;
226
- const modes = modeFilter ? allModes.filter((entry) => entry.mode === modeFilter) : allModes;
227
-
228
- return {
229
- providerChecks,
230
- modes,
231
- };
232
- },
233
- start: async (request, context = {}) => {
234
- if (request.mode === TUNNEL_MODE_MANAGED_REMOTE) {
235
- return startCloudflareManagedRemoteTunnel({
236
- token: request.token,
237
- hostname: request.hostname,
238
- });
239
- }
240
-
241
- if (request.mode === TUNNEL_MODE_MANAGED_LOCAL) {
242
- return startCloudflareManagedLocalTunnel({
243
- configPath: request.configPath,
244
- hostname: request.hostname,
245
- });
246
- }
247
-
248
- if (!context.originUrl) {
249
- throw new TunnelServiceError('validation_error', 'originUrl is required for quick tunnel mode');
250
- }
251
-
252
- return startCloudflareQuickTunnel({
253
- originUrl: context.originUrl,
254
- port: context.activePort,
255
- });
256
- },
257
- stop: (controller) => {
258
- controller?.stop?.();
259
- },
260
- resolvePublicUrl: (controller) => controller?.getPublicUrl?.() ?? null,
261
- getMetadata: (controller) => ({
262
- configPath: controller?.getEffectiveConfigPath?.() ?? null,
263
- resolvedHostname: controller?.getResolvedHostname?.() ?? null,
264
- }),
265
- };
266
- }
@@ -1,123 +0,0 @@
1
- import {
2
- checkNgrokApiReachability,
3
- checkNgrokAuthtokenConfigured,
4
- checkNgrokAvailable,
5
- startNgrokQuickTunnel,
6
- } from '../../ngrok-tunnel.js';
7
-
8
- import {
9
- TUNNEL_INTENT_EPHEMERAL_PUBLIC,
10
- TUNNEL_MODE_QUICK,
11
- TUNNEL_PROVIDER_NGROK,
12
- TunnelServiceError,
13
- } from '../types.js';
14
- import { getTunnelDependencyInstallInfo } from '../install-help.js';
15
-
16
- export const ngrokTunnelProviderCapabilities = {
17
- provider: TUNNEL_PROVIDER_NGROK,
18
- defaults: {
19
- mode: TUNNEL_MODE_QUICK,
20
- optionDefaults: {},
21
- },
22
- modes: [
23
- {
24
- key: TUNNEL_MODE_QUICK,
25
- label: 'Quick Tunnel',
26
- intent: TUNNEL_INTENT_EPHEMERAL_PUBLIC,
27
- requires: [],
28
- supports: ['sessionTTL'],
29
- stability: 'beta',
30
- },
31
- ],
32
- };
33
-
34
- export function createNgrokTunnelProvider() {
35
- return {
36
- id: TUNNEL_PROVIDER_NGROK,
37
- capabilities: ngrokTunnelProviderCapabilities,
38
- checkAvailability: async () => {
39
- const result = await checkNgrokAvailable();
40
- if (result.available) {
41
- return {
42
- ...result,
43
- ...getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_NGROK),
44
- };
45
- }
46
- const installInfo = getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_NGROK);
47
- return {
48
- ...result,
49
- ...installInfo,
50
- };
51
- },
52
- diagnose: async () => {
53
- const dependency = await checkNgrokAvailable();
54
- const authtoken = await checkNgrokAuthtokenConfigured(dependency.path);
55
- const network = await checkNgrokApiReachability();
56
- const installInfo = getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_NGROK);
57
- const startupReady = dependency.available && authtoken.configured && network.reachable;
58
- const providerChecks = [
59
- {
60
- id: 'dependency',
61
- label: 'ngrok installed',
62
- status: dependency.available ? 'pass' : 'fail',
63
- detail: dependency.available
64
- ? (dependency.version || dependency.path || 'ngrok available')
65
- : installInfo.message,
66
- },
67
- {
68
- id: 'authtoken',
69
- label: 'ngrok authtoken configured',
70
- status: authtoken.configured ? 'pass' : 'fail',
71
- detail: authtoken.configured
72
- ? authtoken.detail
73
- : (authtoken.detail || 'Run: ngrok config add-authtoken <your-ngrok-token>'),
74
- },
75
- {
76
- id: 'network',
77
- label: 'ngrok API reachable',
78
- status: network.reachable ? 'pass' : 'fail',
79
- detail: network.reachable
80
- ? (network.status ? `HTTP ${network.status}` : 'Reachable')
81
- : (network.error || 'Could not reach api.ngrok.com'),
82
- },
83
- ];
84
-
85
- return {
86
- providerChecks,
87
- modes: [
88
- {
89
- mode: TUNNEL_MODE_QUICK,
90
- checks: [
91
- {
92
- id: 'startup_readiness',
93
- label: 'Provider startup readiness',
94
- status: startupReady ? 'pass' : 'fail',
95
- detail: startupReady
96
- ? 'Provider dependency, auth, and network checks passed.'
97
- : 'Resolve provider checks before starting tunnels.',
98
- },
99
- ],
100
- summary: {
101
- ready: startupReady,
102
- failures: startupReady ? 0 : 1,
103
- warnings: 0,
104
- },
105
- ready: startupReady,
106
- blockers: startupReady ? [] : ['Resolve provider checks before starting tunnels.'],
107
- },
108
- ],
109
- };
110
- },
111
- start: async (request, context = {}) => {
112
- if (request.mode !== TUNNEL_MODE_QUICK) {
113
- throw new TunnelServiceError('mode_unsupported', `Ngrok only supports '${TUNNEL_MODE_QUICK}' mode right now`);
114
- }
115
- return startNgrokQuickTunnel({ port: context.activePort });
116
- },
117
- stop: (controller) => {
118
- controller?.stop?.();
119
- },
120
- resolvePublicUrl: (controller) => controller?.getPublicUrl?.() ?? null,
121
- getMetadata: () => null,
122
- };
123
- }
@@ -1,51 +0,0 @@
1
- const REQUIRED_PROVIDER_METHODS = ['start', 'stop', 'checkAvailability', 'resolvePublicUrl'];
2
-
3
- export function createTunnelProviderRegistry(initialProviders = []) {
4
- const providers = new Map();
5
- let sealed = false;
6
-
7
- const register = (provider) => {
8
- if (sealed) {
9
- throw new Error('Tunnel provider registry is sealed; no further registrations allowed');
10
- }
11
- if (!provider || typeof provider.id !== 'string' || provider.id.trim().length === 0) {
12
- throw new Error('Tunnel provider must define a non-empty id');
13
- }
14
- for (const method of REQUIRED_PROVIDER_METHODS) {
15
- if (typeof provider[method] !== 'function') {
16
- throw new Error(`Tunnel provider '${provider.id}' must implement ${method}()`);
17
- }
18
- }
19
- const key = provider.id.trim().toLowerCase();
20
- if (providers.has(key)) {
21
- throw new Error(`Tunnel provider '${key}' is already registered`);
22
- }
23
- providers.set(key, provider);
24
- return provider;
25
- };
26
-
27
- const get = (providerId) => {
28
- if (typeof providerId !== 'string' || providerId.trim().length === 0) {
29
- return null;
30
- }
31
- return providers.get(providerId.trim().toLowerCase()) ?? null;
32
- };
33
-
34
- const list = () => Array.from(providers.values());
35
-
36
- const listCapabilities = () => list().map((provider) => ({ ...provider.capabilities }));
37
-
38
- for (const provider of initialProviders) {
39
- register(provider);
40
- }
41
-
42
- const seal = () => { sealed = true; };
43
-
44
- return {
45
- register,
46
- get,
47
- list,
48
- listCapabilities,
49
- seal,
50
- };
51
- }