@camstack/addon-cloudflare-tunnel 0.1.13 → 0.1.14

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.
@@ -0,0 +1,55 @@
1
+ // src/cloudflare-tunnel.addon.ts
2
+ import { BaseAddon, networkAccessCapability } from "@camstack/types";
3
+ var CloudflareTunnelAddon = class extends BaseAddon {
4
+ constructor() {
5
+ super({ mode: "quick", namedTunnelToken: "", localPort: 3e3 });
6
+ }
7
+ async onInitialize() {
8
+ this.ctx.logger.info("Cloudflare Tunnel addon initialized");
9
+ return [{ capability: networkAccessCapability, provider: this }];
10
+ }
11
+ globalSettingsSchema() {
12
+ return this.schema({
13
+ sections: [{
14
+ id: "tunnel",
15
+ title: "Tunnel Settings",
16
+ fields: [
17
+ this.field({
18
+ type: "select",
19
+ key: "mode",
20
+ label: "Tunnel Mode",
21
+ description: "Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel.",
22
+ default: "quick",
23
+ options: [
24
+ { value: "quick", label: "Quick Tunnel", description: "Temporary public URL, no Cloudflare account required" },
25
+ { value: "named", label: "Named Tunnel", description: "Persistent tunnel using a Cloudflare tunnel token" }
26
+ ]
27
+ }),
28
+ this.field({
29
+ type: "password",
30
+ key: "namedTunnelToken",
31
+ label: "Tunnel Token",
32
+ description: "Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)",
33
+ showToggle: true,
34
+ showWhen: { field: "mode", equals: "named" }
35
+ }),
36
+ this.field({
37
+ type: "number",
38
+ key: "localPort",
39
+ label: "Local Port",
40
+ description: "The local port that the tunnel will expose publicly",
41
+ min: 1,
42
+ max: 65535,
43
+ step: 1,
44
+ default: 3e3
45
+ })
46
+ ]
47
+ }]
48
+ });
49
+ }
50
+ };
51
+
52
+ export {
53
+ CloudflareTunnelAddon
54
+ };
55
+ //# sourceMappingURL=chunk-VHOC5TFB.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cloudflare-tunnel.addon.ts"],"sourcesContent":["import type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, networkAccessCapability } from '@camstack/types'\n\ninterface TunnelConfig {\n readonly mode: 'quick' | 'named'\n readonly namedTunnelToken: string\n readonly localPort: number\n}\n\n/**\n * Cloudflare Tunnel — exposes CamStack via Cloudflare's network.\n * Settings appear under Cluster → NodeDetail → Settings.\n */\nexport class CloudflareTunnelAddon extends BaseAddon<TunnelConfig> {\n constructor() {\n super({ mode: 'quick', namedTunnelToken: '', localPort: 3000 })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n this.ctx.logger.info('Cloudflare Tunnel addon initialized')\n return [{ capability: networkAccessCapability, provider: this }]\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'tunnel',\n title: 'Tunnel Settings',\n fields: [\n this.field({\n type: 'select',\n key: 'mode',\n label: 'Tunnel Mode',\n description: 'Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel.',\n default: 'quick',\n options: [\n { value: 'quick', label: 'Quick Tunnel', description: 'Temporary public URL, no Cloudflare account required' },\n { value: 'named', label: 'Named Tunnel', description: 'Persistent tunnel using a Cloudflare tunnel token' },\n ],\n }),\n this.field({\n type: 'password',\n key: 'namedTunnelToken',\n label: 'Tunnel Token',\n description: 'Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)',\n showToggle: true,\n showWhen: { field: 'mode', equals: 'named' },\n }),\n this.field({\n type: 'number',\n key: 'localPort',\n label: 'Local Port',\n description: 'The local port that the tunnel will expose publicly',\n min: 1, max: 65535, step: 1, default: 3000,\n }),\n ],\n }],\n })\n }\n}\n"],"mappings":";AACA,SAAS,WAAW,+BAA+B;AAY5C,IAAM,wBAAN,cAAoC,UAAwB;AAAA,EACjE,cAAc;AACZ,UAAM,EAAE,MAAM,SAAS,kBAAkB,IAAI,WAAW,IAAK,CAAC;AAAA,EAChE;AAAA,EAEA,MAAgB,eAAgD;AAC9D,SAAK,IAAI,OAAO,KAAK,qCAAqC;AAC1D,WAAO,CAAC,EAAE,YAAY,yBAAyB,UAAU,KAAK,CAAC;AAAA,EACjE;AAAA,EAEU,uBAAuB;AAC/B,WAAO,KAAK,OAAO;AAAA,MACjB,UAAU,CAAC;AAAA,QACT,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ;AAAA,UACN,KAAK,MAAM;AAAA,YACT,MAAM;AAAA,YACN,KAAK;AAAA,YACL,OAAO;AAAA,YACP,aAAa;AAAA,YACb,SAAS;AAAA,YACT,SAAS;AAAA,cACP,EAAE,OAAO,SAAS,OAAO,gBAAgB,aAAa,uDAAuD;AAAA,cAC7G,EAAE,OAAO,SAAS,OAAO,gBAAgB,aAAa,oDAAoD;AAAA,YAC5G;AAAA,UACF,CAAC;AAAA,UACD,KAAK,MAAM;AAAA,YACT,MAAM;AAAA,YACN,KAAK;AAAA,YACL,OAAO;AAAA,YACP,aAAa;AAAA,YACb,YAAY;AAAA,YACZ,UAAU,EAAE,OAAO,QAAQ,QAAQ,QAAQ;AAAA,UAC7C,CAAC;AAAA,UACD,KAAK,MAAM;AAAA,YACT,MAAM;AAAA,YACN,KAAK;AAAA,YACL,OAAO;AAAA,YACP,aAAa;AAAA,YACb,KAAK;AAAA,YAAG,KAAK;AAAA,YAAO,MAAM;AAAA,YAAG,SAAS;AAAA,UACxC,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;","names":[]}
@@ -1,39 +1,19 @@
1
- import { INetworkAccessProvider, IScopedLogger, IEventBus, IProcessManager, INetworkEndpoint, NetworkAccessStatus, ICamstackAddon, IConfigurable, AddonManifest, AddonContext, CapabilityProviderMap, ConfigUISchema } from '@camstack/types';
1
+ import * as _camstack_types from '@camstack/types';
2
+ import { BaseAddon, ProviderRegistration } from '@camstack/types';
2
3
 
3
- interface CloudflareTunnelConfig {
4
+ interface TunnelConfig {
4
5
  readonly mode: 'quick' | 'named';
5
- readonly namedTunnelToken?: string;
6
+ readonly namedTunnelToken: string;
6
7
  readonly localPort: number;
7
8
  }
8
- declare class CloudflareTunnelService implements INetworkAccessProvider {
9
- private readonly config;
10
- private readonly logger;
11
- private readonly eventBus;
12
- private readonly processManager;
13
- readonly id = "cloudflare-tunnel";
14
- readonly type = "cloudflare";
15
- private endpoint;
16
- private processId;
17
- constructor(config: CloudflareTunnelConfig, logger: IScopedLogger, eventBus: IEventBus, processManager: IProcessManager);
18
- start(): Promise<INetworkEndpoint>;
19
- stop(): Promise<void>;
20
- getEndpoint(): INetworkEndpoint | null;
21
- getStatus(): NetworkAccessStatus;
9
+ /**
10
+ * Cloudflare Tunnel — exposes CamStack via Cloudflare's network.
11
+ * Settings appear under Cluster → NodeDetail → Settings.
12
+ */
13
+ declare class CloudflareTunnelAddon extends BaseAddon<TunnelConfig> {
14
+ constructor();
15
+ protected onInitialize(): Promise<ProviderRegistration[]>;
16
+ protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
22
17
  }
23
18
 
24
- declare class CloudflareTunnelAddon implements ICamstackAddon, IConfigurable {
25
- readonly manifest: AddonManifest;
26
- private service;
27
- private currentConfig;
28
- initialize(context: AddonContext): Promise<void>;
29
- shutdown(): Promise<void>;
30
- /** Provide the ProcessManagerService to enable tunnel management */
31
- setProcessManager(processManager: IProcessManager, config: CloudflareTunnelConfig, context: AddonContext): void;
32
- getService(): CloudflareTunnelService;
33
- getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
34
- getConfigSchema(): ConfigUISchema;
35
- getConfig(): Record<string, unknown>;
36
- onConfigChange(config: Record<string, unknown>): Promise<void>;
37
- }
38
-
39
- export { type CloudflareTunnelConfig as C, CloudflareTunnelAddon, CloudflareTunnelService as a };
19
+ export { CloudflareTunnelAddon };
@@ -1,39 +1,19 @@
1
- import { INetworkAccessProvider, IScopedLogger, IEventBus, IProcessManager, INetworkEndpoint, NetworkAccessStatus, ICamstackAddon, IConfigurable, AddonManifest, AddonContext, CapabilityProviderMap, ConfigUISchema } from '@camstack/types';
1
+ import * as _camstack_types from '@camstack/types';
2
+ import { BaseAddon, ProviderRegistration } from '@camstack/types';
2
3
 
3
- interface CloudflareTunnelConfig {
4
+ interface TunnelConfig {
4
5
  readonly mode: 'quick' | 'named';
5
- readonly namedTunnelToken?: string;
6
+ readonly namedTunnelToken: string;
6
7
  readonly localPort: number;
7
8
  }
8
- declare class CloudflareTunnelService implements INetworkAccessProvider {
9
- private readonly config;
10
- private readonly logger;
11
- private readonly eventBus;
12
- private readonly processManager;
13
- readonly id = "cloudflare-tunnel";
14
- readonly type = "cloudflare";
15
- private endpoint;
16
- private processId;
17
- constructor(config: CloudflareTunnelConfig, logger: IScopedLogger, eventBus: IEventBus, processManager: IProcessManager);
18
- start(): Promise<INetworkEndpoint>;
19
- stop(): Promise<void>;
20
- getEndpoint(): INetworkEndpoint | null;
21
- getStatus(): NetworkAccessStatus;
9
+ /**
10
+ * Cloudflare Tunnel — exposes CamStack via Cloudflare's network.
11
+ * Settings appear under Cluster → NodeDetail → Settings.
12
+ */
13
+ declare class CloudflareTunnelAddon extends BaseAddon<TunnelConfig> {
14
+ constructor();
15
+ protected onInitialize(): Promise<ProviderRegistration[]>;
16
+ protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
22
17
  }
23
18
 
24
- declare class CloudflareTunnelAddon implements ICamstackAddon, IConfigurable {
25
- readonly manifest: AddonManifest;
26
- private service;
27
- private currentConfig;
28
- initialize(context: AddonContext): Promise<void>;
29
- shutdown(): Promise<void>;
30
- /** Provide the ProcessManagerService to enable tunnel management */
31
- setProcessManager(processManager: IProcessManager, config: CloudflareTunnelConfig, context: AddonContext): void;
32
- getService(): CloudflareTunnelService;
33
- getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
34
- getConfigSchema(): ConfigUISchema;
35
- getConfig(): Record<string, unknown>;
36
- onConfigChange(config: Record<string, unknown>): Promise<void>;
37
- }
38
-
39
- export { type CloudflareTunnelConfig as C, CloudflareTunnelAddon, CloudflareTunnelService as a };
19
+ export { CloudflareTunnelAddon };
@@ -23,174 +23,54 @@ __export(cloudflare_tunnel_addon_exports, {
23
23
  CloudflareTunnelAddon: () => CloudflareTunnelAddon
24
24
  });
25
25
  module.exports = __toCommonJS(cloudflare_tunnel_addon_exports);
26
-
27
- // src/cloudflare-tunnel.ts
28
- var import_node_crypto = require("crypto");
29
- var CloudflareTunnelService = class {
30
- constructor(config, logger, eventBus, processManager) {
31
- this.config = config;
32
- this.logger = logger;
33
- this.eventBus = eventBus;
34
- this.processManager = processManager;
26
+ var import_types = require("@camstack/types");
27
+ var CloudflareTunnelAddon = class extends import_types.BaseAddon {
28
+ constructor() {
29
+ super({ mode: "quick", namedTunnelToken: "", localPort: 3e3 });
35
30
  }
36
- id = "cloudflare-tunnel";
37
- type = "cloudflare";
38
- endpoint = null;
39
- processId = null;
40
- async start() {
41
- this.logger.info(`Starting Cloudflare tunnel (${this.config.mode})`);
42
- const processConfig = {
43
- id: "cloudflared-tunnel",
44
- label: "Cloudflare Tunnel",
45
- command: "cloudflared",
46
- args: this.config.mode === "quick" ? ["tunnel", "--url", `http://localhost:${this.config.localPort}`] : ["tunnel", "run", "--token", this.config.namedTunnelToken],
47
- autoRestart: true,
48
- maxRestarts: 5
49
- };
50
- this.processManager.register(processConfig);
51
- await this.processManager.start("cloudflared-tunnel");
52
- this.processId = "cloudflared-tunnel";
53
- const publicUrl = this.config.mode === "named" ? "https://tunnel.example.com" : "https://pending.trycloudflare.com";
54
- this.endpoint = {
55
- id: "cloudflare-tunnel",
56
- type: "tunnel",
57
- provider: "cloudflare",
58
- url: publicUrl,
59
- internal: false,
60
- capabilities: {
61
- supportsWebRTC: false,
62
- supportsWebSocket: true,
63
- supportsSSE: true
64
- },
65
- priority: 50,
66
- status: "online"
67
- };
68
- this.eventBus.emit({
69
- id: (0, import_node_crypto.randomUUID)(),
70
- timestamp: /* @__PURE__ */ new Date(),
71
- source: { type: "addon", id: "cloudflare-tunnel" },
72
- category: "network.tunnel.started",
73
- data: { url: publicUrl }
74
- });
75
- return this.endpoint;
31
+ async onInitialize() {
32
+ this.ctx.logger.info("Cloudflare Tunnel addon initialized");
33
+ return [{ capability: import_types.networkAccessCapability, provider: this }];
76
34
  }
77
- async stop() {
78
- if (this.processId) {
79
- await this.processManager.stop(this.processId);
80
- }
81
- this.endpoint = null;
82
- this.eventBus.emit({
83
- id: (0, import_node_crypto.randomUUID)(),
84
- timestamp: /* @__PURE__ */ new Date(),
85
- source: { type: "addon", id: "cloudflare-tunnel" },
86
- category: "network.tunnel.stopped",
87
- data: {}
35
+ globalSettingsSchema() {
36
+ return this.schema({
37
+ sections: [{
38
+ id: "tunnel",
39
+ title: "Tunnel Settings",
40
+ fields: [
41
+ this.field({
42
+ type: "select",
43
+ key: "mode",
44
+ label: "Tunnel Mode",
45
+ description: "Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel.",
46
+ default: "quick",
47
+ options: [
48
+ { value: "quick", label: "Quick Tunnel", description: "Temporary public URL, no Cloudflare account required" },
49
+ { value: "named", label: "Named Tunnel", description: "Persistent tunnel using a Cloudflare tunnel token" }
50
+ ]
51
+ }),
52
+ this.field({
53
+ type: "password",
54
+ key: "namedTunnelToken",
55
+ label: "Tunnel Token",
56
+ description: "Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)",
57
+ showToggle: true,
58
+ showWhen: { field: "mode", equals: "named" }
59
+ }),
60
+ this.field({
61
+ type: "number",
62
+ key: "localPort",
63
+ label: "Local Port",
64
+ description: "The local port that the tunnel will expose publicly",
65
+ min: 1,
66
+ max: 65535,
67
+ step: 1,
68
+ default: 3e3
69
+ })
70
+ ]
71
+ }]
88
72
  });
89
73
  }
90
- getEndpoint() {
91
- return this.endpoint;
92
- }
93
- getStatus() {
94
- return {
95
- connected: this.endpoint !== null,
96
- publicUrl: this.endpoint?.url
97
- };
98
- }
99
- };
100
-
101
- // src/cloudflare-tunnel.addon.ts
102
- var CloudflareTunnelAddon = class {
103
- manifest = {
104
- id: "cloudflare-tunnel",
105
- name: "Cloudflare Tunnel",
106
- version: "1.0.0",
107
- capabilities: ["network-access"]
108
- };
109
- service = null;
110
- currentConfig = {
111
- mode: "quick",
112
- localPort: 3e3
113
- };
114
- async initialize(context) {
115
- this.currentConfig = {
116
- mode: context.addonConfig.mode ?? this.currentConfig.mode,
117
- namedTunnelToken: context.addonConfig.namedTunnelToken ?? this.currentConfig.namedTunnelToken,
118
- localPort: context.addonConfig.localPort ?? this.currentConfig.localPort
119
- };
120
- context.logger.info("Cloudflare Tunnel addon initialized");
121
- }
122
- async shutdown() {
123
- await this.service?.stop();
124
- this.service = null;
125
- }
126
- /** Provide the ProcessManagerService to enable tunnel management */
127
- setProcessManager(processManager, config, context) {
128
- this.service = new CloudflareTunnelService(
129
- config,
130
- context.logger,
131
- context.eventBus,
132
- processManager
133
- );
134
- }
135
- getService() {
136
- if (!this.service) throw new Error("Cloudflare Tunnel not initialized");
137
- return this.service;
138
- }
139
- getCapabilityProvider(name) {
140
- if (name === "network-access" && this.service) {
141
- return this.service;
142
- }
143
- return null;
144
- }
145
- getConfigSchema() {
146
- return {
147
- sections: [
148
- {
149
- id: "tunnel",
150
- title: "Tunnel Settings",
151
- fields: [
152
- {
153
- type: "select",
154
- key: "mode",
155
- label: "Tunnel Mode",
156
- description: "Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel with your Cloudflare account.",
157
- options: [
158
- { value: "quick", label: "Quick Tunnel", description: "Temporary public URL, no Cloudflare account required" },
159
- { value: "named", label: "Named Tunnel", description: "Persistent tunnel using a Cloudflare tunnel token" }
160
- ]
161
- },
162
- {
163
- type: "password",
164
- key: "namedTunnelToken",
165
- label: "Tunnel Token",
166
- description: "Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)",
167
- showToggle: true,
168
- showWhen: { field: "mode", equals: "named" }
169
- },
170
- {
171
- type: "number",
172
- key: "localPort",
173
- label: "Local Port",
174
- description: "The local port that the tunnel will expose publicly",
175
- min: 1,
176
- max: 65535,
177
- step: 1
178
- }
179
- ]
180
- }
181
- ]
182
- };
183
- }
184
- getConfig() {
185
- return { ...this.currentConfig };
186
- }
187
- async onConfigChange(config) {
188
- this.currentConfig = {
189
- mode: config.mode ?? this.currentConfig.mode,
190
- namedTunnelToken: config.namedTunnelToken ?? this.currentConfig.namedTunnelToken,
191
- localPort: config.localPort ?? this.currentConfig.localPort
192
- };
193
- }
194
74
  };
195
75
  // Annotate the CommonJS export names for ESM import in node:
196
76
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cloudflare-tunnel.addon.ts","../src/cloudflare-tunnel.ts"],"sourcesContent":["import type {\n ICamstackAddon, AddonManifest, AddonContext,\n IConfigurable, ConfigUISchema, CapabilityProviderMap,\n IProcessManager,\n} from '@camstack/types'\nimport { CloudflareTunnelService } from './cloudflare-tunnel'\nimport type { CloudflareTunnelConfig } from './cloudflare-tunnel'\n\nexport class CloudflareTunnelAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'cloudflare-tunnel',\n name: 'Cloudflare Tunnel',\n version: '1.0.0',\n capabilities: ['network-access'],\n }\n\n private service: CloudflareTunnelService | null = null\n private currentConfig: Partial<CloudflareTunnelConfig> = {\n mode: 'quick',\n localPort: 3000,\n }\n\n async initialize(context: AddonContext): Promise<void> {\n this.currentConfig = {\n mode: (context.addonConfig.mode as CloudflareTunnelConfig['mode']) ?? this.currentConfig.mode,\n namedTunnelToken: (context.addonConfig.namedTunnelToken as string | undefined) ?? this.currentConfig.namedTunnelToken,\n localPort: (context.addonConfig.localPort as number) ?? this.currentConfig.localPort,\n }\n // Service creation is deferred until processManager is provided via setProcessManager\n context.logger.info('Cloudflare Tunnel addon initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.service?.stop()\n this.service = null\n }\n\n /** Provide the ProcessManagerService to enable tunnel management */\n setProcessManager(\n processManager: IProcessManager,\n config: CloudflareTunnelConfig,\n context: AddonContext,\n ): void {\n this.service = new CloudflareTunnelService(\n config,\n context.logger,\n context.eventBus,\n processManager,\n )\n }\n\n getService(): CloudflareTunnelService {\n if (!this.service) throw new Error('Cloudflare Tunnel not initialized')\n return this.service\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'network-access' && this.service) {\n return this.service as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'tunnel',\n title: 'Tunnel Settings',\n fields: [\n {\n type: 'select',\n key: 'mode',\n label: 'Tunnel Mode',\n description: 'Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel with your Cloudflare account.',\n options: [\n { value: 'quick', label: 'Quick Tunnel', description: 'Temporary public URL, no Cloudflare account required' },\n { value: 'named', label: 'Named Tunnel', description: 'Persistent tunnel using a Cloudflare tunnel token' },\n ],\n },\n {\n type: 'password',\n key: 'namedTunnelToken',\n label: 'Tunnel Token',\n description: 'Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)',\n showToggle: true,\n showWhen: { field: 'mode', equals: 'named' },\n },\n {\n type: 'number',\n key: 'localPort',\n label: 'Local Port',\n description: 'The local port that the tunnel will expose publicly',\n min: 1,\n max: 65535,\n step: 1,\n },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig = {\n mode: (config.mode as CloudflareTunnelConfig['mode']) ?? this.currentConfig.mode,\n namedTunnelToken: (config.namedTunnelToken as string | undefined) ?? this.currentConfig.namedTunnelToken,\n localPort: (config.localPort as number) ?? this.currentConfig.localPort,\n }\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type {\n IScopedLogger, IEventBus,\n INetworkAccessProvider, INetworkEndpoint, NetworkAccessStatus,\n IProcessManager, ProcessConfig,\n} from '@camstack/types'\n\nexport interface CloudflareTunnelConfig {\n readonly mode: 'quick' | 'named'\n readonly namedTunnelToken?: string\n readonly localPort: number\n}\n\nexport class CloudflareTunnelService implements INetworkAccessProvider {\n readonly id = 'cloudflare-tunnel'\n readonly type = 'cloudflare'\n\n private endpoint: INetworkEndpoint | null = null\n private processId: string | null = null\n\n constructor(\n private readonly config: CloudflareTunnelConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n private readonly processManager: IProcessManager,\n ) {}\n\n async start(): Promise<INetworkEndpoint> {\n this.logger.info(`Starting Cloudflare tunnel (${this.config.mode})`)\n\n const processConfig: ProcessConfig = {\n id: 'cloudflared-tunnel',\n label: 'Cloudflare Tunnel',\n command: 'cloudflared',\n args:\n this.config.mode === 'quick'\n ? ['tunnel', '--url', `http://localhost:${this.config.localPort}`]\n : ['tunnel', 'run', '--token', this.config.namedTunnelToken!],\n autoRestart: true,\n maxRestarts: 5,\n }\n\n this.processManager.register(processConfig)\n await this.processManager.start('cloudflared-tunnel')\n this.processId = 'cloudflared-tunnel'\n\n const publicUrl =\n this.config.mode === 'named'\n ? 'https://tunnel.example.com'\n : 'https://pending.trycloudflare.com'\n\n this.endpoint = {\n id: 'cloudflare-tunnel',\n type: 'tunnel',\n provider: 'cloudflare',\n url: publicUrl,\n internal: false,\n capabilities: {\n supportsWebRTC: false,\n supportsWebSocket: true,\n supportsSSE: true,\n },\n priority: 50,\n status: 'online',\n }\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: 'network.tunnel.started',\n data: { url: publicUrl },\n })\n\n return this.endpoint\n }\n\n async stop(): Promise<void> {\n if (this.processId) {\n await this.processManager.stop(this.processId)\n }\n this.endpoint = null\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: 'network.tunnel.stopped',\n data: {},\n })\n }\n\n getEndpoint(): INetworkEndpoint | null {\n return this.endpoint\n }\n\n getStatus(): NetworkAccessStatus {\n return {\n connected: this.endpoint !== null,\n publicUrl: this.endpoint?.url,\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cloudflare-tunnel.addon.ts"],"sourcesContent":["import type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, networkAccessCapability } from '@camstack/types'\n\ninterface TunnelConfig {\n readonly mode: 'quick' | 'named'\n readonly namedTunnelToken: string\n readonly localPort: number\n}\n\n/**\n * Cloudflare Tunnel — exposes CamStack via Cloudflare's network.\n * Settings appear under Cluster → NodeDetail → Settings.\n */\nexport class CloudflareTunnelAddon extends BaseAddon<TunnelConfig> {\n constructor() {\n super({ mode: 'quick', namedTunnelToken: '', localPort: 3000 })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n this.ctx.logger.info('Cloudflare Tunnel addon initialized')\n return [{ capability: networkAccessCapability, provider: this }]\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'tunnel',\n title: 'Tunnel Settings',\n fields: [\n this.field({\n type: 'select',\n key: 'mode',\n label: 'Tunnel Mode',\n description: 'Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel.',\n default: 'quick',\n options: [\n { value: 'quick', label: 'Quick Tunnel', description: 'Temporary public URL, no Cloudflare account required' },\n { value: 'named', label: 'Named Tunnel', description: 'Persistent tunnel using a Cloudflare tunnel token' },\n ],\n }),\n this.field({\n type: 'password',\n key: 'namedTunnelToken',\n label: 'Tunnel Token',\n description: 'Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)',\n showToggle: true,\n showWhen: { field: 'mode', equals: 'named' },\n }),\n this.field({\n type: 'number',\n key: 'localPort',\n label: 'Local Port',\n description: 'The local port that the tunnel will expose publicly',\n min: 1, max: 65535, step: 1, default: 3000,\n }),\n ],\n }],\n })\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAmD;AAY5C,IAAM,wBAAN,cAAoC,uBAAwB;AAAA,EACjE,cAAc;AACZ,UAAM,EAAE,MAAM,SAAS,kBAAkB,IAAI,WAAW,IAAK,CAAC;AAAA,EAChE;AAAA,EAEA,MAAgB,eAAgD;AAC9D,SAAK,IAAI,OAAO,KAAK,qCAAqC;AAC1D,WAAO,CAAC,EAAE,YAAY,sCAAyB,UAAU,KAAK,CAAC;AAAA,EACjE;AAAA,EAEU,uBAAuB;AAC/B,WAAO,KAAK,OAAO;AAAA,MACjB,UAAU,CAAC;AAAA,QACT,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ;AAAA,UACN,KAAK,MAAM;AAAA,YACT,MAAM;AAAA,YACN,KAAK;AAAA,YACL,OAAO;AAAA,YACP,aAAa;AAAA,YACb,SAAS;AAAA,YACT,SAAS;AAAA,cACP,EAAE,OAAO,SAAS,OAAO,gBAAgB,aAAa,uDAAuD;AAAA,cAC7G,EAAE,OAAO,SAAS,OAAO,gBAAgB,aAAa,oDAAoD;AAAA,YAC5G;AAAA,UACF,CAAC;AAAA,UACD,KAAK,MAAM;AAAA,YACT,MAAM;AAAA,YACN,KAAK;AAAA,YACL,OAAO;AAAA,YACP,aAAa;AAAA,YACb,YAAY;AAAA,YACZ,UAAU,EAAE,OAAO,QAAQ,QAAQ,QAAQ;AAAA,UAC7C,CAAC;AAAA,UACD,KAAK,MAAM;AAAA,YACT,MAAM;AAAA,YACN,KAAK;AAAA,YACL,OAAO;AAAA,YACP,aAAa;AAAA,YACb,KAAK;AAAA,YAAG,KAAK;AAAA,YAAO,MAAM;AAAA,YAAG,SAAS;AAAA,UACxC,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CloudflareTunnelAddon
3
- } from "./chunk-HHH5U2SN.mjs";
3
+ } from "./chunk-VHOC5TFB.mjs";
4
4
  export {
5
5
  CloudflareTunnelAddon
6
6
  };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,25 @@
1
- export { CloudflareTunnelAddon, C as CloudflareTunnelConfig, a as CloudflareTunnelService } from './cloudflare-tunnel.addon.mjs';
2
- import '@camstack/types';
1
+ import { INetworkAccessProvider, IScopedLogger, IEventBus, IProcessManager, INetworkEndpoint, NetworkAccessStatus } from '@camstack/types';
2
+ export { CloudflareTunnelAddon } from './cloudflare-tunnel.addon.mjs';
3
+
4
+ interface CloudflareTunnelConfig {
5
+ readonly mode: 'quick' | 'named';
6
+ readonly namedTunnelToken?: string;
7
+ readonly localPort: number;
8
+ }
9
+ declare class CloudflareTunnelService implements INetworkAccessProvider {
10
+ private readonly config;
11
+ private readonly logger;
12
+ private readonly eventBus;
13
+ private readonly processManager;
14
+ readonly id = "cloudflare-tunnel";
15
+ readonly type = "cloudflare";
16
+ private endpoint;
17
+ private processId;
18
+ constructor(config: CloudflareTunnelConfig, logger: IScopedLogger, eventBus: IEventBus, processManager: IProcessManager);
19
+ start(): Promise<INetworkEndpoint>;
20
+ stop(): Promise<void>;
21
+ getEndpoint(): INetworkEndpoint | null;
22
+ getStatus(): NetworkAccessStatus;
23
+ }
24
+
25
+ export { type CloudflareTunnelConfig, CloudflareTunnelService };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,25 @@
1
- export { CloudflareTunnelAddon, C as CloudflareTunnelConfig, a as CloudflareTunnelService } from './cloudflare-tunnel.addon.js';
2
- import '@camstack/types';
1
+ import { INetworkAccessProvider, IScopedLogger, IEventBus, IProcessManager, INetworkEndpoint, NetworkAccessStatus } from '@camstack/types';
2
+ export { CloudflareTunnelAddon } from './cloudflare-tunnel.addon.js';
3
+
4
+ interface CloudflareTunnelConfig {
5
+ readonly mode: 'quick' | 'named';
6
+ readonly namedTunnelToken?: string;
7
+ readonly localPort: number;
8
+ }
9
+ declare class CloudflareTunnelService implements INetworkAccessProvider {
10
+ private readonly config;
11
+ private readonly logger;
12
+ private readonly eventBus;
13
+ private readonly processManager;
14
+ readonly id = "cloudflare-tunnel";
15
+ readonly type = "cloudflare";
16
+ private endpoint;
17
+ private processId;
18
+ constructor(config: CloudflareTunnelConfig, logger: IScopedLogger, eventBus: IEventBus, processManager: IProcessManager);
19
+ start(): Promise<INetworkEndpoint>;
20
+ stop(): Promise<void>;
21
+ getEndpoint(): INetworkEndpoint | null;
22
+ getStatus(): NetworkAccessStatus;
23
+ }
24
+
25
+ export { type CloudflareTunnelConfig, CloudflareTunnelService };
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ module.exports = __toCommonJS(index_exports);
27
27
 
28
28
  // src/cloudflare-tunnel.ts
29
29
  var import_node_crypto = require("crypto");
30
+ var import_types = require("@camstack/types");
30
31
  var CloudflareTunnelService = class {
31
32
  constructor(config, logger, eventBus, processManager) {
32
33
  this.config = config;
@@ -34,12 +35,16 @@ var CloudflareTunnelService = class {
34
35
  this.eventBus = eventBus;
35
36
  this.processManager = processManager;
36
37
  }
38
+ config;
39
+ logger;
40
+ eventBus;
41
+ processManager;
37
42
  id = "cloudflare-tunnel";
38
43
  type = "cloudflare";
39
44
  endpoint = null;
40
45
  processId = null;
41
46
  async start() {
42
- this.logger.info(`Starting Cloudflare tunnel (${this.config.mode})`);
47
+ this.logger.info("Starting Cloudflare tunnel", { meta: { mode: this.config.mode } });
43
48
  const processConfig = {
44
49
  id: "cloudflared-tunnel",
45
50
  label: "Cloudflare Tunnel",
@@ -70,7 +75,7 @@ var CloudflareTunnelService = class {
70
75
  id: (0, import_node_crypto.randomUUID)(),
71
76
  timestamp: /* @__PURE__ */ new Date(),
72
77
  source: { type: "addon", id: "cloudflare-tunnel" },
73
- category: "network.tunnel.started",
78
+ category: import_types.EventCategory.NetworkTunnelStarted,
74
79
  data: { url: publicUrl }
75
80
  });
76
81
  return this.endpoint;
@@ -84,7 +89,7 @@ var CloudflareTunnelService = class {
84
89
  id: (0, import_node_crypto.randomUUID)(),
85
90
  timestamp: /* @__PURE__ */ new Date(),
86
91
  source: { type: "addon", id: "cloudflare-tunnel" },
87
- category: "network.tunnel.stopped",
92
+ category: import_types.EventCategory.NetworkTunnelStopped,
88
93
  data: {}
89
94
  });
90
95
  }
@@ -100,97 +105,53 @@ var CloudflareTunnelService = class {
100
105
  };
101
106
 
102
107
  // src/cloudflare-tunnel.addon.ts
103
- var CloudflareTunnelAddon = class {
104
- manifest = {
105
- id: "cloudflare-tunnel",
106
- name: "Cloudflare Tunnel",
107
- version: "1.0.0",
108
- capabilities: ["network-access"]
109
- };
110
- service = null;
111
- currentConfig = {
112
- mode: "quick",
113
- localPort: 3e3
114
- };
115
- async initialize(context) {
116
- this.currentConfig = {
117
- mode: context.addonConfig.mode ?? this.currentConfig.mode,
118
- namedTunnelToken: context.addonConfig.namedTunnelToken ?? this.currentConfig.namedTunnelToken,
119
- localPort: context.addonConfig.localPort ?? this.currentConfig.localPort
120
- };
121
- context.logger.info("Cloudflare Tunnel addon initialized");
122
- }
123
- async shutdown() {
124
- await this.service?.stop();
125
- this.service = null;
126
- }
127
- /** Provide the ProcessManagerService to enable tunnel management */
128
- setProcessManager(processManager, config, context) {
129
- this.service = new CloudflareTunnelService(
130
- config,
131
- context.logger,
132
- context.eventBus,
133
- processManager
134
- );
108
+ var import_types2 = require("@camstack/types");
109
+ var CloudflareTunnelAddon = class extends import_types2.BaseAddon {
110
+ constructor() {
111
+ super({ mode: "quick", namedTunnelToken: "", localPort: 3e3 });
135
112
  }
136
- getService() {
137
- if (!this.service) throw new Error("Cloudflare Tunnel not initialized");
138
- return this.service;
113
+ async onInitialize() {
114
+ this.ctx.logger.info("Cloudflare Tunnel addon initialized");
115
+ return [{ capability: import_types2.networkAccessCapability, provider: this }];
139
116
  }
140
- getCapabilityProvider(name) {
141
- if (name === "network-access" && this.service) {
142
- return this.service;
143
- }
144
- return null;
145
- }
146
- getConfigSchema() {
147
- return {
148
- sections: [
149
- {
150
- id: "tunnel",
151
- title: "Tunnel Settings",
152
- fields: [
153
- {
154
- type: "select",
155
- key: "mode",
156
- label: "Tunnel Mode",
157
- description: "Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel with your Cloudflare account.",
158
- options: [
159
- { value: "quick", label: "Quick Tunnel", description: "Temporary public URL, no Cloudflare account required" },
160
- { value: "named", label: "Named Tunnel", description: "Persistent tunnel using a Cloudflare tunnel token" }
161
- ]
162
- },
163
- {
164
- type: "password",
165
- key: "namedTunnelToken",
166
- label: "Tunnel Token",
167
- description: "Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)",
168
- showToggle: true,
169
- showWhen: { field: "mode", equals: "named" }
170
- },
171
- {
172
- type: "number",
173
- key: "localPort",
174
- label: "Local Port",
175
- description: "The local port that the tunnel will expose publicly",
176
- min: 1,
177
- max: 65535,
178
- step: 1
179
- }
180
- ]
181
- }
182
- ]
183
- };
184
- }
185
- getConfig() {
186
- return { ...this.currentConfig };
187
- }
188
- async onConfigChange(config) {
189
- this.currentConfig = {
190
- mode: config.mode ?? this.currentConfig.mode,
191
- namedTunnelToken: config.namedTunnelToken ?? this.currentConfig.namedTunnelToken,
192
- localPort: config.localPort ?? this.currentConfig.localPort
193
- };
117
+ globalSettingsSchema() {
118
+ return this.schema({
119
+ sections: [{
120
+ id: "tunnel",
121
+ title: "Tunnel Settings",
122
+ fields: [
123
+ this.field({
124
+ type: "select",
125
+ key: "mode",
126
+ label: "Tunnel Mode",
127
+ description: "Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel.",
128
+ default: "quick",
129
+ options: [
130
+ { value: "quick", label: "Quick Tunnel", description: "Temporary public URL, no Cloudflare account required" },
131
+ { value: "named", label: "Named Tunnel", description: "Persistent tunnel using a Cloudflare tunnel token" }
132
+ ]
133
+ }),
134
+ this.field({
135
+ type: "password",
136
+ key: "namedTunnelToken",
137
+ label: "Tunnel Token",
138
+ description: "Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)",
139
+ showToggle: true,
140
+ showWhen: { field: "mode", equals: "named" }
141
+ }),
142
+ this.field({
143
+ type: "number",
144
+ key: "localPort",
145
+ label: "Local Port",
146
+ description: "The local port that the tunnel will expose publicly",
147
+ min: 1,
148
+ max: 65535,
149
+ step: 1,
150
+ default: 3e3
151
+ })
152
+ ]
153
+ }]
154
+ });
194
155
  }
195
156
  };
196
157
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cloudflare-tunnel.ts","../src/cloudflare-tunnel.addon.ts"],"sourcesContent":["export { CloudflareTunnelService } from './cloudflare-tunnel'\nexport type { CloudflareTunnelConfig } from './cloudflare-tunnel'\nexport { CloudflareTunnelAddon } from './cloudflare-tunnel.addon'\n","import { randomUUID } from 'node:crypto'\nimport type {\n IScopedLogger, IEventBus,\n INetworkAccessProvider, INetworkEndpoint, NetworkAccessStatus,\n IProcessManager, ProcessConfig,\n} from '@camstack/types'\n\nexport interface CloudflareTunnelConfig {\n readonly mode: 'quick' | 'named'\n readonly namedTunnelToken?: string\n readonly localPort: number\n}\n\nexport class CloudflareTunnelService implements INetworkAccessProvider {\n readonly id = 'cloudflare-tunnel'\n readonly type = 'cloudflare'\n\n private endpoint: INetworkEndpoint | null = null\n private processId: string | null = null\n\n constructor(\n private readonly config: CloudflareTunnelConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n private readonly processManager: IProcessManager,\n ) {}\n\n async start(): Promise<INetworkEndpoint> {\n this.logger.info(`Starting Cloudflare tunnel (${this.config.mode})`)\n\n const processConfig: ProcessConfig = {\n id: 'cloudflared-tunnel',\n label: 'Cloudflare Tunnel',\n command: 'cloudflared',\n args:\n this.config.mode === 'quick'\n ? ['tunnel', '--url', `http://localhost:${this.config.localPort}`]\n : ['tunnel', 'run', '--token', this.config.namedTunnelToken!],\n autoRestart: true,\n maxRestarts: 5,\n }\n\n this.processManager.register(processConfig)\n await this.processManager.start('cloudflared-tunnel')\n this.processId = 'cloudflared-tunnel'\n\n const publicUrl =\n this.config.mode === 'named'\n ? 'https://tunnel.example.com'\n : 'https://pending.trycloudflare.com'\n\n this.endpoint = {\n id: 'cloudflare-tunnel',\n type: 'tunnel',\n provider: 'cloudflare',\n url: publicUrl,\n internal: false,\n capabilities: {\n supportsWebRTC: false,\n supportsWebSocket: true,\n supportsSSE: true,\n },\n priority: 50,\n status: 'online',\n }\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: 'network.tunnel.started',\n data: { url: publicUrl },\n })\n\n return this.endpoint\n }\n\n async stop(): Promise<void> {\n if (this.processId) {\n await this.processManager.stop(this.processId)\n }\n this.endpoint = null\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: 'network.tunnel.stopped',\n data: {},\n })\n }\n\n getEndpoint(): INetworkEndpoint | null {\n return this.endpoint\n }\n\n getStatus(): NetworkAccessStatus {\n return {\n connected: this.endpoint !== null,\n publicUrl: this.endpoint?.url,\n }\n }\n}\n","import type {\n ICamstackAddon, AddonManifest, AddonContext,\n IConfigurable, ConfigUISchema, CapabilityProviderMap,\n IProcessManager,\n} from '@camstack/types'\nimport { CloudflareTunnelService } from './cloudflare-tunnel'\nimport type { CloudflareTunnelConfig } from './cloudflare-tunnel'\n\nexport class CloudflareTunnelAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'cloudflare-tunnel',\n name: 'Cloudflare Tunnel',\n version: '1.0.0',\n capabilities: ['network-access'],\n }\n\n private service: CloudflareTunnelService | null = null\n private currentConfig: Partial<CloudflareTunnelConfig> = {\n mode: 'quick',\n localPort: 3000,\n }\n\n async initialize(context: AddonContext): Promise<void> {\n this.currentConfig = {\n mode: (context.addonConfig.mode as CloudflareTunnelConfig['mode']) ?? this.currentConfig.mode,\n namedTunnelToken: (context.addonConfig.namedTunnelToken as string | undefined) ?? this.currentConfig.namedTunnelToken,\n localPort: (context.addonConfig.localPort as number) ?? this.currentConfig.localPort,\n }\n // Service creation is deferred until processManager is provided via setProcessManager\n context.logger.info('Cloudflare Tunnel addon initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.service?.stop()\n this.service = null\n }\n\n /** Provide the ProcessManagerService to enable tunnel management */\n setProcessManager(\n processManager: IProcessManager,\n config: CloudflareTunnelConfig,\n context: AddonContext,\n ): void {\n this.service = new CloudflareTunnelService(\n config,\n context.logger,\n context.eventBus,\n processManager,\n )\n }\n\n getService(): CloudflareTunnelService {\n if (!this.service) throw new Error('Cloudflare Tunnel not initialized')\n return this.service\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'network-access' && this.service) {\n return this.service as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'tunnel',\n title: 'Tunnel Settings',\n fields: [\n {\n type: 'select',\n key: 'mode',\n label: 'Tunnel Mode',\n description: 'Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel with your Cloudflare account.',\n options: [\n { value: 'quick', label: 'Quick Tunnel', description: 'Temporary public URL, no Cloudflare account required' },\n { value: 'named', label: 'Named Tunnel', description: 'Persistent tunnel using a Cloudflare tunnel token' },\n ],\n },\n {\n type: 'password',\n key: 'namedTunnelToken',\n label: 'Tunnel Token',\n description: 'Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)',\n showToggle: true,\n showWhen: { field: 'mode', equals: 'named' },\n },\n {\n type: 'number',\n key: 'localPort',\n label: 'Local Port',\n description: 'The local port that the tunnel will expose publicly',\n min: 1,\n max: 65535,\n step: 1,\n },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig = {\n mode: (config.mode as CloudflareTunnelConfig['mode']) ?? this.currentConfig.mode,\n namedTunnelToken: (config.namedTunnelToken as string | undefined) ?? this.currentConfig.namedTunnelToken,\n localPort: (config.localPort as number) ?? this.currentConfig.localPort,\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cloudflare-tunnel.ts","../src/cloudflare-tunnel.addon.ts"],"sourcesContent":["export { CloudflareTunnelService } from './cloudflare-tunnel'\nexport type { CloudflareTunnelConfig } from './cloudflare-tunnel'\nexport { CloudflareTunnelAddon } from './cloudflare-tunnel.addon'\n","import { randomUUID } from 'node:crypto'\nimport { EventCategory } from '@camstack/types'\nimport type {\n IScopedLogger, IEventBus,\n INetworkAccessProvider, INetworkEndpoint, NetworkAccessStatus,\n IProcessManager, ProcessConfig,\n} from '@camstack/types'\n\nexport interface CloudflareTunnelConfig {\n readonly mode: 'quick' | 'named'\n readonly namedTunnelToken?: string\n readonly localPort: number\n}\n\nexport class CloudflareTunnelService implements INetworkAccessProvider {\n readonly id = 'cloudflare-tunnel'\n readonly type = 'cloudflare'\n\n private endpoint: INetworkEndpoint | null = null\n private processId: string | null = null\n\n constructor(\n private readonly config: CloudflareTunnelConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n private readonly processManager: IProcessManager,\n ) {}\n\n async start(): Promise<INetworkEndpoint> {\n this.logger.info('Starting Cloudflare tunnel', { meta: { mode: this.config.mode } })\n\n const processConfig: ProcessConfig = {\n id: 'cloudflared-tunnel',\n label: 'Cloudflare Tunnel',\n command: 'cloudflared',\n args:\n this.config.mode === 'quick'\n ? ['tunnel', '--url', `http://localhost:${this.config.localPort}`]\n : ['tunnel', 'run', '--token', this.config.namedTunnelToken!],\n autoRestart: true,\n maxRestarts: 5,\n }\n\n this.processManager.register(processConfig)\n await this.processManager.start('cloudflared-tunnel')\n this.processId = 'cloudflared-tunnel'\n\n const publicUrl =\n this.config.mode === 'named'\n ? 'https://tunnel.example.com'\n : 'https://pending.trycloudflare.com'\n\n this.endpoint = {\n id: 'cloudflare-tunnel',\n type: 'tunnel',\n provider: 'cloudflare',\n url: publicUrl,\n internal: false,\n capabilities: {\n supportsWebRTC: false,\n supportsWebSocket: true,\n supportsSSE: true,\n },\n priority: 50,\n status: 'online',\n }\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: EventCategory.NetworkTunnelStarted,\n data: { url: publicUrl },\n })\n\n return this.endpoint\n }\n\n async stop(): Promise<void> {\n if (this.processId) {\n await this.processManager.stop(this.processId)\n }\n this.endpoint = null\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: EventCategory.NetworkTunnelStopped,\n data: {},\n })\n }\n\n getEndpoint(): INetworkEndpoint | null {\n return this.endpoint\n }\n\n getStatus(): NetworkAccessStatus {\n return {\n connected: this.endpoint !== null,\n publicUrl: this.endpoint?.url,\n }\n }\n}\n","import type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, networkAccessCapability } from '@camstack/types'\n\ninterface TunnelConfig {\n readonly mode: 'quick' | 'named'\n readonly namedTunnelToken: string\n readonly localPort: number\n}\n\n/**\n * Cloudflare Tunnel — exposes CamStack via Cloudflare's network.\n * Settings appear under Cluster → NodeDetail → Settings.\n */\nexport class CloudflareTunnelAddon extends BaseAddon<TunnelConfig> {\n constructor() {\n super({ mode: 'quick', namedTunnelToken: '', localPort: 3000 })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n this.ctx.logger.info('Cloudflare Tunnel addon initialized')\n return [{ capability: networkAccessCapability, provider: this }]\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'tunnel',\n title: 'Tunnel Settings',\n fields: [\n this.field({\n type: 'select',\n key: 'mode',\n label: 'Tunnel Mode',\n description: 'Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel.',\n default: 'quick',\n options: [\n { value: 'quick', label: 'Quick Tunnel', description: 'Temporary public URL, no Cloudflare account required' },\n { value: 'named', label: 'Named Tunnel', description: 'Persistent tunnel using a Cloudflare tunnel token' },\n ],\n }),\n this.field({\n type: 'password',\n key: 'namedTunnelToken',\n label: 'Tunnel Token',\n description: 'Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)',\n showToggle: true,\n showWhen: { field: 'mode', equals: 'named' },\n }),\n this.field({\n type: 'number',\n key: 'localPort',\n label: 'Local Port',\n description: 'The local port that the tunnel will expose publicly',\n min: 1, max: 65535, step: 1, default: 3000,\n }),\n ],\n }],\n })\n }\n}\n"],"mappings":"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","names":["import_types"]}
package/dist/index.mjs CHANGED
@@ -1,7 +1,85 @@
1
1
  import {
2
- CloudflareTunnelAddon,
3
- CloudflareTunnelService
4
- } from "./chunk-HHH5U2SN.mjs";
2
+ CloudflareTunnelAddon
3
+ } from "./chunk-VHOC5TFB.mjs";
4
+
5
+ // src/cloudflare-tunnel.ts
6
+ import { randomUUID } from "crypto";
7
+ import { EventCategory } from "@camstack/types";
8
+ var CloudflareTunnelService = class {
9
+ constructor(config, logger, eventBus, processManager) {
10
+ this.config = config;
11
+ this.logger = logger;
12
+ this.eventBus = eventBus;
13
+ this.processManager = processManager;
14
+ }
15
+ config;
16
+ logger;
17
+ eventBus;
18
+ processManager;
19
+ id = "cloudflare-tunnel";
20
+ type = "cloudflare";
21
+ endpoint = null;
22
+ processId = null;
23
+ async start() {
24
+ this.logger.info("Starting Cloudflare tunnel", { meta: { mode: this.config.mode } });
25
+ const processConfig = {
26
+ id: "cloudflared-tunnel",
27
+ label: "Cloudflare Tunnel",
28
+ command: "cloudflared",
29
+ args: this.config.mode === "quick" ? ["tunnel", "--url", `http://localhost:${this.config.localPort}`] : ["tunnel", "run", "--token", this.config.namedTunnelToken],
30
+ autoRestart: true,
31
+ maxRestarts: 5
32
+ };
33
+ this.processManager.register(processConfig);
34
+ await this.processManager.start("cloudflared-tunnel");
35
+ this.processId = "cloudflared-tunnel";
36
+ const publicUrl = this.config.mode === "named" ? "https://tunnel.example.com" : "https://pending.trycloudflare.com";
37
+ this.endpoint = {
38
+ id: "cloudflare-tunnel",
39
+ type: "tunnel",
40
+ provider: "cloudflare",
41
+ url: publicUrl,
42
+ internal: false,
43
+ capabilities: {
44
+ supportsWebRTC: false,
45
+ supportsWebSocket: true,
46
+ supportsSSE: true
47
+ },
48
+ priority: 50,
49
+ status: "online"
50
+ };
51
+ this.eventBus.emit({
52
+ id: randomUUID(),
53
+ timestamp: /* @__PURE__ */ new Date(),
54
+ source: { type: "addon", id: "cloudflare-tunnel" },
55
+ category: EventCategory.NetworkTunnelStarted,
56
+ data: { url: publicUrl }
57
+ });
58
+ return this.endpoint;
59
+ }
60
+ async stop() {
61
+ if (this.processId) {
62
+ await this.processManager.stop(this.processId);
63
+ }
64
+ this.endpoint = null;
65
+ this.eventBus.emit({
66
+ id: randomUUID(),
67
+ timestamp: /* @__PURE__ */ new Date(),
68
+ source: { type: "addon", id: "cloudflare-tunnel" },
69
+ category: EventCategory.NetworkTunnelStopped,
70
+ data: {}
71
+ });
72
+ }
73
+ getEndpoint() {
74
+ return this.endpoint;
75
+ }
76
+ getStatus() {
77
+ return {
78
+ connected: this.endpoint !== null,
79
+ publicUrl: this.endpoint?.url
80
+ };
81
+ }
82
+ };
5
83
  export {
6
84
  CloudflareTunnelAddon,
7
85
  CloudflareTunnelService
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/cloudflare-tunnel.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport { EventCategory } from '@camstack/types'\nimport type {\n IScopedLogger, IEventBus,\n INetworkAccessProvider, INetworkEndpoint, NetworkAccessStatus,\n IProcessManager, ProcessConfig,\n} from '@camstack/types'\n\nexport interface CloudflareTunnelConfig {\n readonly mode: 'quick' | 'named'\n readonly namedTunnelToken?: string\n readonly localPort: number\n}\n\nexport class CloudflareTunnelService implements INetworkAccessProvider {\n readonly id = 'cloudflare-tunnel'\n readonly type = 'cloudflare'\n\n private endpoint: INetworkEndpoint | null = null\n private processId: string | null = null\n\n constructor(\n private readonly config: CloudflareTunnelConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n private readonly processManager: IProcessManager,\n ) {}\n\n async start(): Promise<INetworkEndpoint> {\n this.logger.info('Starting Cloudflare tunnel', { meta: { mode: this.config.mode } })\n\n const processConfig: ProcessConfig = {\n id: 'cloudflared-tunnel',\n label: 'Cloudflare Tunnel',\n command: 'cloudflared',\n args:\n this.config.mode === 'quick'\n ? ['tunnel', '--url', `http://localhost:${this.config.localPort}`]\n : ['tunnel', 'run', '--token', this.config.namedTunnelToken!],\n autoRestart: true,\n maxRestarts: 5,\n }\n\n this.processManager.register(processConfig)\n await this.processManager.start('cloudflared-tunnel')\n this.processId = 'cloudflared-tunnel'\n\n const publicUrl =\n this.config.mode === 'named'\n ? 'https://tunnel.example.com'\n : 'https://pending.trycloudflare.com'\n\n this.endpoint = {\n id: 'cloudflare-tunnel',\n type: 'tunnel',\n provider: 'cloudflare',\n url: publicUrl,\n internal: false,\n capabilities: {\n supportsWebRTC: false,\n supportsWebSocket: true,\n supportsSSE: true,\n },\n priority: 50,\n status: 'online',\n }\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: EventCategory.NetworkTunnelStarted,\n data: { url: publicUrl },\n })\n\n return this.endpoint\n }\n\n async stop(): Promise<void> {\n if (this.processId) {\n await this.processManager.stop(this.processId)\n }\n this.endpoint = null\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: EventCategory.NetworkTunnelStopped,\n data: {},\n })\n }\n\n getEndpoint(): INetworkEndpoint | null {\n return this.endpoint\n }\n\n getStatus(): NetworkAccessStatus {\n return {\n connected: this.endpoint !== null,\n publicUrl: this.endpoint?.url,\n }\n }\n}\n"],"mappings":";;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAavB,IAAM,0BAAN,MAAgE;AAAA,EAOrE,YACmB,QACA,QACA,UACA,gBACjB;AAJiB;AACA;AACA;AACA;AAAA,EAChB;AAAA,EAJgB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAVV,KAAK;AAAA,EACL,OAAO;AAAA,EAER,WAAoC;AAAA,EACpC,YAA2B;AAAA,EASnC,MAAM,QAAmC;AACvC,SAAK,OAAO,KAAK,8BAA8B,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,KAAK,EAAE,CAAC;AAEnF,UAAM,gBAA+B;AAAA,MACnC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,SAAS;AAAA,MACT,MACE,KAAK,OAAO,SAAS,UACjB,CAAC,UAAU,SAAS,oBAAoB,KAAK,OAAO,SAAS,EAAE,IAC/D,CAAC,UAAU,OAAO,WAAW,KAAK,OAAO,gBAAiB;AAAA,MAChE,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,SAAK,eAAe,SAAS,aAAa;AAC1C,UAAM,KAAK,eAAe,MAAM,oBAAoB;AACpD,SAAK,YAAY;AAEjB,UAAM,YACJ,KAAK,OAAO,SAAS,UACjB,+BACA;AAEN,SAAK,WAAW;AAAA,MACd,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,MACL,UAAU;AAAA,MACV,cAAc;AAAA,QACZ,gBAAgB;AAAA,QAChB,mBAAmB;AAAA,QACnB,aAAa;AAAA,MACf;AAAA,MACA,UAAU;AAAA,MACV,QAAQ;AAAA,IACV;AAEA,SAAK,SAAS,KAAK;AAAA,MACjB,IAAI,WAAW;AAAA,MACf,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ,EAAE,MAAM,SAAS,IAAI,oBAAoB;AAAA,MACjD,UAAU,cAAc;AAAA,MACxB,MAAM,EAAE,KAAK,UAAU;AAAA,IACzB,CAAC;AAED,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,WAAW;AAClB,YAAM,KAAK,eAAe,KAAK,KAAK,SAAS;AAAA,IAC/C;AACA,SAAK,WAAW;AAEhB,SAAK,SAAS,KAAK;AAAA,MACjB,IAAI,WAAW;AAAA,MACf,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ,EAAE,MAAM,SAAS,IAAI,oBAAoB;AAAA,MACjD,UAAU,cAAc;AAAA,MACxB,MAAM,CAAC;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,cAAuC;AACrC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,YAAiC;AAC/B,WAAO;AAAA,MACL,WAAW,KAAK,aAAa;AAAA,MAC7B,WAAW,KAAK,UAAU;AAAA,IAC5B;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-cloudflare-tunnel",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Cloudflare Tunnel addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",
@@ -32,12 +32,12 @@
32
32
  "addons": [
33
33
  {
34
34
  "id": "cloudflare-tunnel",
35
+ "name": "Cloudflare Tunnel",
36
+ "version": "1.0.0",
35
37
  "entry": "./dist/cloudflare-tunnel.addon.js",
36
- "slot": null,
37
38
  "capabilities": [
38
39
  {
39
- "name": "network-access",
40
- "mode": "collection"
40
+ "name": "network-access"
41
41
  }
42
42
  ]
43
43
  }
@@ -1,174 +0,0 @@
1
- // src/cloudflare-tunnel.ts
2
- import { randomUUID } from "crypto";
3
- var CloudflareTunnelService = class {
4
- constructor(config, logger, eventBus, processManager) {
5
- this.config = config;
6
- this.logger = logger;
7
- this.eventBus = eventBus;
8
- this.processManager = processManager;
9
- }
10
- id = "cloudflare-tunnel";
11
- type = "cloudflare";
12
- endpoint = null;
13
- processId = null;
14
- async start() {
15
- this.logger.info(`Starting Cloudflare tunnel (${this.config.mode})`);
16
- const processConfig = {
17
- id: "cloudflared-tunnel",
18
- label: "Cloudflare Tunnel",
19
- command: "cloudflared",
20
- args: this.config.mode === "quick" ? ["tunnel", "--url", `http://localhost:${this.config.localPort}`] : ["tunnel", "run", "--token", this.config.namedTunnelToken],
21
- autoRestart: true,
22
- maxRestarts: 5
23
- };
24
- this.processManager.register(processConfig);
25
- await this.processManager.start("cloudflared-tunnel");
26
- this.processId = "cloudflared-tunnel";
27
- const publicUrl = this.config.mode === "named" ? "https://tunnel.example.com" : "https://pending.trycloudflare.com";
28
- this.endpoint = {
29
- id: "cloudflare-tunnel",
30
- type: "tunnel",
31
- provider: "cloudflare",
32
- url: publicUrl,
33
- internal: false,
34
- capabilities: {
35
- supportsWebRTC: false,
36
- supportsWebSocket: true,
37
- supportsSSE: true
38
- },
39
- priority: 50,
40
- status: "online"
41
- };
42
- this.eventBus.emit({
43
- id: randomUUID(),
44
- timestamp: /* @__PURE__ */ new Date(),
45
- source: { type: "addon", id: "cloudflare-tunnel" },
46
- category: "network.tunnel.started",
47
- data: { url: publicUrl }
48
- });
49
- return this.endpoint;
50
- }
51
- async stop() {
52
- if (this.processId) {
53
- await this.processManager.stop(this.processId);
54
- }
55
- this.endpoint = null;
56
- this.eventBus.emit({
57
- id: randomUUID(),
58
- timestamp: /* @__PURE__ */ new Date(),
59
- source: { type: "addon", id: "cloudflare-tunnel" },
60
- category: "network.tunnel.stopped",
61
- data: {}
62
- });
63
- }
64
- getEndpoint() {
65
- return this.endpoint;
66
- }
67
- getStatus() {
68
- return {
69
- connected: this.endpoint !== null,
70
- publicUrl: this.endpoint?.url
71
- };
72
- }
73
- };
74
-
75
- // src/cloudflare-tunnel.addon.ts
76
- var CloudflareTunnelAddon = class {
77
- manifest = {
78
- id: "cloudflare-tunnel",
79
- name: "Cloudflare Tunnel",
80
- version: "1.0.0",
81
- capabilities: ["network-access"]
82
- };
83
- service = null;
84
- currentConfig = {
85
- mode: "quick",
86
- localPort: 3e3
87
- };
88
- async initialize(context) {
89
- this.currentConfig = {
90
- mode: context.addonConfig.mode ?? this.currentConfig.mode,
91
- namedTunnelToken: context.addonConfig.namedTunnelToken ?? this.currentConfig.namedTunnelToken,
92
- localPort: context.addonConfig.localPort ?? this.currentConfig.localPort
93
- };
94
- context.logger.info("Cloudflare Tunnel addon initialized");
95
- }
96
- async shutdown() {
97
- await this.service?.stop();
98
- this.service = null;
99
- }
100
- /** Provide the ProcessManagerService to enable tunnel management */
101
- setProcessManager(processManager, config, context) {
102
- this.service = new CloudflareTunnelService(
103
- config,
104
- context.logger,
105
- context.eventBus,
106
- processManager
107
- );
108
- }
109
- getService() {
110
- if (!this.service) throw new Error("Cloudflare Tunnel not initialized");
111
- return this.service;
112
- }
113
- getCapabilityProvider(name) {
114
- if (name === "network-access" && this.service) {
115
- return this.service;
116
- }
117
- return null;
118
- }
119
- getConfigSchema() {
120
- return {
121
- sections: [
122
- {
123
- id: "tunnel",
124
- title: "Tunnel Settings",
125
- fields: [
126
- {
127
- type: "select",
128
- key: "mode",
129
- label: "Tunnel Mode",
130
- description: "Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel with your Cloudflare account.",
131
- options: [
132
- { value: "quick", label: "Quick Tunnel", description: "Temporary public URL, no Cloudflare account required" },
133
- { value: "named", label: "Named Tunnel", description: "Persistent tunnel using a Cloudflare tunnel token" }
134
- ]
135
- },
136
- {
137
- type: "password",
138
- key: "namedTunnelToken",
139
- label: "Tunnel Token",
140
- description: "Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)",
141
- showToggle: true,
142
- showWhen: { field: "mode", equals: "named" }
143
- },
144
- {
145
- type: "number",
146
- key: "localPort",
147
- label: "Local Port",
148
- description: "The local port that the tunnel will expose publicly",
149
- min: 1,
150
- max: 65535,
151
- step: 1
152
- }
153
- ]
154
- }
155
- ]
156
- };
157
- }
158
- getConfig() {
159
- return { ...this.currentConfig };
160
- }
161
- async onConfigChange(config) {
162
- this.currentConfig = {
163
- mode: config.mode ?? this.currentConfig.mode,
164
- namedTunnelToken: config.namedTunnelToken ?? this.currentConfig.namedTunnelToken,
165
- localPort: config.localPort ?? this.currentConfig.localPort
166
- };
167
- }
168
- };
169
-
170
- export {
171
- CloudflareTunnelService,
172
- CloudflareTunnelAddon
173
- };
174
- //# sourceMappingURL=chunk-HHH5U2SN.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cloudflare-tunnel.ts","../src/cloudflare-tunnel.addon.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport type {\n IScopedLogger, IEventBus,\n INetworkAccessProvider, INetworkEndpoint, NetworkAccessStatus,\n IProcessManager, ProcessConfig,\n} from '@camstack/types'\n\nexport interface CloudflareTunnelConfig {\n readonly mode: 'quick' | 'named'\n readonly namedTunnelToken?: string\n readonly localPort: number\n}\n\nexport class CloudflareTunnelService implements INetworkAccessProvider {\n readonly id = 'cloudflare-tunnel'\n readonly type = 'cloudflare'\n\n private endpoint: INetworkEndpoint | null = null\n private processId: string | null = null\n\n constructor(\n private readonly config: CloudflareTunnelConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n private readonly processManager: IProcessManager,\n ) {}\n\n async start(): Promise<INetworkEndpoint> {\n this.logger.info(`Starting Cloudflare tunnel (${this.config.mode})`)\n\n const processConfig: ProcessConfig = {\n id: 'cloudflared-tunnel',\n label: 'Cloudflare Tunnel',\n command: 'cloudflared',\n args:\n this.config.mode === 'quick'\n ? ['tunnel', '--url', `http://localhost:${this.config.localPort}`]\n : ['tunnel', 'run', '--token', this.config.namedTunnelToken!],\n autoRestart: true,\n maxRestarts: 5,\n }\n\n this.processManager.register(processConfig)\n await this.processManager.start('cloudflared-tunnel')\n this.processId = 'cloudflared-tunnel'\n\n const publicUrl =\n this.config.mode === 'named'\n ? 'https://tunnel.example.com'\n : 'https://pending.trycloudflare.com'\n\n this.endpoint = {\n id: 'cloudflare-tunnel',\n type: 'tunnel',\n provider: 'cloudflare',\n url: publicUrl,\n internal: false,\n capabilities: {\n supportsWebRTC: false,\n supportsWebSocket: true,\n supportsSSE: true,\n },\n priority: 50,\n status: 'online',\n }\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: 'network.tunnel.started',\n data: { url: publicUrl },\n })\n\n return this.endpoint\n }\n\n async stop(): Promise<void> {\n if (this.processId) {\n await this.processManager.stop(this.processId)\n }\n this.endpoint = null\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'cloudflare-tunnel' },\n category: 'network.tunnel.stopped',\n data: {},\n })\n }\n\n getEndpoint(): INetworkEndpoint | null {\n return this.endpoint\n }\n\n getStatus(): NetworkAccessStatus {\n return {\n connected: this.endpoint !== null,\n publicUrl: this.endpoint?.url,\n }\n }\n}\n","import type {\n ICamstackAddon, AddonManifest, AddonContext,\n IConfigurable, ConfigUISchema, CapabilityProviderMap,\n IProcessManager,\n} from '@camstack/types'\nimport { CloudflareTunnelService } from './cloudflare-tunnel'\nimport type { CloudflareTunnelConfig } from './cloudflare-tunnel'\n\nexport class CloudflareTunnelAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'cloudflare-tunnel',\n name: 'Cloudflare Tunnel',\n version: '1.0.0',\n capabilities: ['network-access'],\n }\n\n private service: CloudflareTunnelService | null = null\n private currentConfig: Partial<CloudflareTunnelConfig> = {\n mode: 'quick',\n localPort: 3000,\n }\n\n async initialize(context: AddonContext): Promise<void> {\n this.currentConfig = {\n mode: (context.addonConfig.mode as CloudflareTunnelConfig['mode']) ?? this.currentConfig.mode,\n namedTunnelToken: (context.addonConfig.namedTunnelToken as string | undefined) ?? this.currentConfig.namedTunnelToken,\n localPort: (context.addonConfig.localPort as number) ?? this.currentConfig.localPort,\n }\n // Service creation is deferred until processManager is provided via setProcessManager\n context.logger.info('Cloudflare Tunnel addon initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.service?.stop()\n this.service = null\n }\n\n /** Provide the ProcessManagerService to enable tunnel management */\n setProcessManager(\n processManager: IProcessManager,\n config: CloudflareTunnelConfig,\n context: AddonContext,\n ): void {\n this.service = new CloudflareTunnelService(\n config,\n context.logger,\n context.eventBus,\n processManager,\n )\n }\n\n getService(): CloudflareTunnelService {\n if (!this.service) throw new Error('Cloudflare Tunnel not initialized')\n return this.service\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'network-access' && this.service) {\n return this.service as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'tunnel',\n title: 'Tunnel Settings',\n fields: [\n {\n type: 'select',\n key: 'mode',\n label: 'Tunnel Mode',\n description: 'Quick mode creates a temporary public URL; Named mode uses a persistent named tunnel with your Cloudflare account.',\n options: [\n { value: 'quick', label: 'Quick Tunnel', description: 'Temporary public URL, no Cloudflare account required' },\n { value: 'named', label: 'Named Tunnel', description: 'Persistent tunnel using a Cloudflare tunnel token' },\n ],\n },\n {\n type: 'password',\n key: 'namedTunnelToken',\n label: 'Tunnel Token',\n description: 'Token from your Cloudflare Zero Trust dashboard (required for Named Tunnel mode)',\n showToggle: true,\n showWhen: { field: 'mode', equals: 'named' },\n },\n {\n type: 'number',\n key: 'localPort',\n label: 'Local Port',\n description: 'The local port that the tunnel will expose publicly',\n min: 1,\n max: 65535,\n step: 1,\n },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig = {\n mode: (config.mode as CloudflareTunnelConfig['mode']) ?? this.currentConfig.mode,\n namedTunnelToken: (config.namedTunnelToken as string | undefined) ?? this.currentConfig.namedTunnelToken,\n localPort: (config.localPort as number) ?? this.currentConfig.localPort,\n }\n }\n}\n"],"mappings":"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","names":[]}