@betterportal/tunnels 1.0.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 (116) hide show
  1. package/README.md +76 -0
  2. package/SPEC.md +524 -0
  3. package/lib/.bsb/clients/service-tunnel-client-api.d.ts +133 -0
  4. package/lib/.bsb/clients/service-tunnel-client-api.d.ts.map +1 -0
  5. package/lib/.bsb/clients/service-tunnel-client-api.js +102 -0
  6. package/lib/.bsb/clients/service-tunnel-client-api.js.map +1 -0
  7. package/lib/.bsb/clients/service-tunnel-web.d.ts +43 -0
  8. package/lib/.bsb/clients/service-tunnel-web.d.ts.map +1 -0
  9. package/lib/.bsb/clients/service-tunnel-web.js +47 -0
  10. package/lib/.bsb/clients/service-tunnel-web.js.map +1 -0
  11. package/lib/auth.d.ts +12 -0
  12. package/lib/auth.d.ts.map +1 -0
  13. package/lib/auth.js +59 -0
  14. package/lib/auth.js.map +1 -0
  15. package/lib/cli.d.ts +2 -0
  16. package/lib/cli.d.ts.map +1 -0
  17. package/lib/cli.js +295 -0
  18. package/lib/cli.js.map +1 -0
  19. package/lib/plugins/service-betterportal/.bp-generated/registry.d.ts +3 -0
  20. package/lib/plugins/service-betterportal/.bp-generated/registry.d.ts.map +1 -0
  21. package/lib/plugins/service-betterportal/.bp-generated/registry.js +127 -0
  22. package/lib/plugins/service-betterportal/.bp-generated/registry.js.map +1 -0
  23. package/lib/plugins/service-betterportal/assets/brand/bettertunnels-horizontal-light.svg +18 -0
  24. package/lib/plugins/service-betterportal/assets/brand/bettertunnels-square-dark-1024x1024.png +0 -0
  25. package/lib/plugins/service-betterportal/assets/brand/favicon.svg +12 -0
  26. package/lib/plugins/service-betterportal/betterportal-logo.png +0 -0
  27. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/_theme.bootstrap1/index.d.ts +5 -0
  28. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/_theme.bootstrap1/index.d.ts.map +1 -0
  29. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/_theme.bootstrap1/index.js +6 -0
  30. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/_theme.bootstrap1/index.js.map +1 -0
  31. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/index.d.ts +25 -0
  32. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/index.d.ts.map +1 -0
  33. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/index.js +59 -0
  34. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/index.js.map +1 -0
  35. package/lib/plugins/service-betterportal/bp-routes/dashboard/_theme.bootstrap1/index.d.ts +5 -0
  36. package/lib/plugins/service-betterportal/bp-routes/dashboard/_theme.bootstrap1/index.d.ts.map +1 -0
  37. package/lib/plugins/service-betterportal/bp-routes/dashboard/_theme.bootstrap1/index.js +22 -0
  38. package/lib/plugins/service-betterportal/bp-routes/dashboard/_theme.bootstrap1/index.js.map +1 -0
  39. package/lib/plugins/service-betterportal/bp-routes/dashboard/index.d.ts +40 -0
  40. package/lib/plugins/service-betterportal/bp-routes/dashboard/index.d.ts.map +1 -0
  41. package/lib/plugins/service-betterportal/bp-routes/dashboard/index.js +57 -0
  42. package/lib/plugins/service-betterportal/bp-routes/dashboard/index.js.map +1 -0
  43. package/lib/plugins/service-betterportal/bp-routes/downloads/_theme.bootstrap1/index.d.ts +5 -0
  44. package/lib/plugins/service-betterportal/bp-routes/downloads/_theme.bootstrap1/index.d.ts.map +1 -0
  45. package/lib/plugins/service-betterportal/bp-routes/downloads/_theme.bootstrap1/index.js +5 -0
  46. package/lib/plugins/service-betterportal/bp-routes/downloads/_theme.bootstrap1/index.js.map +1 -0
  47. package/lib/plugins/service-betterportal/bp-routes/downloads/index.d.ts +30 -0
  48. package/lib/plugins/service-betterportal/bp-routes/downloads/index.d.ts.map +1 -0
  49. package/lib/plugins/service-betterportal/bp-routes/downloads/index.js +45 -0
  50. package/lib/plugins/service-betterportal/bp-routes/downloads/index.js.map +1 -0
  51. package/lib/plugins/service-betterportal/bp-routes/landing/_theme.bootstrap1/index.d.ts +5 -0
  52. package/lib/plugins/service-betterportal/bp-routes/landing/_theme.bootstrap1/index.d.ts.map +1 -0
  53. package/lib/plugins/service-betterportal/bp-routes/landing/_theme.bootstrap1/index.js +5 -0
  54. package/lib/plugins/service-betterportal/bp-routes/landing/_theme.bootstrap1/index.js.map +1 -0
  55. package/lib/plugins/service-betterportal/bp-routes/landing/index.d.ts +40 -0
  56. package/lib/plugins/service-betterportal/bp-routes/landing/index.d.ts.map +1 -0
  57. package/lib/plugins/service-betterportal/bp-routes/landing/index.js +63 -0
  58. package/lib/plugins/service-betterportal/bp-routes/landing/index.js.map +1 -0
  59. package/lib/plugins/service-betterportal/bp-routes/tunnels/_theme.bootstrap1/index.d.ts +5 -0
  60. package/lib/plugins/service-betterportal/bp-routes/tunnels/_theme.bootstrap1/index.d.ts.map +1 -0
  61. package/lib/plugins/service-betterportal/bp-routes/tunnels/_theme.bootstrap1/index.js +5 -0
  62. package/lib/plugins/service-betterportal/bp-routes/tunnels/_theme.bootstrap1/index.js.map +1 -0
  63. package/lib/plugins/service-betterportal/bp-routes/tunnels/index.d.ts +44 -0
  64. package/lib/plugins/service-betterportal/bp-routes/tunnels/index.d.ts.map +1 -0
  65. package/lib/plugins/service-betterportal/bp-routes/tunnels/index.js +59 -0
  66. package/lib/plugins/service-betterportal/bp-routes/tunnels/index.js.map +1 -0
  67. package/lib/plugins/service-betterportal/brand-assets.d.ts +7 -0
  68. package/lib/plugins/service-betterportal/brand-assets.d.ts.map +1 -0
  69. package/lib/plugins/service-betterportal/brand-assets.js +24 -0
  70. package/lib/plugins/service-betterportal/brand-assets.js.map +1 -0
  71. package/lib/plugins/service-betterportal/index.d.ts +57 -0
  72. package/lib/plugins/service-betterportal/index.d.ts.map +1 -0
  73. package/lib/plugins/service-betterportal/index.js +108 -0
  74. package/lib/plugins/service-betterportal/index.js.map +1 -0
  75. package/lib/plugins/service-tunnel-client-api/ids.d.ts +6 -0
  76. package/lib/plugins/service-tunnel-client-api/ids.d.ts.map +1 -0
  77. package/lib/plugins/service-tunnel-client-api/ids.js +17 -0
  78. package/lib/plugins/service-tunnel-client-api/ids.js.map +1 -0
  79. package/lib/plugins/service-tunnel-client-api/index.d.ts +158 -0
  80. package/lib/plugins/service-tunnel-client-api/index.d.ts.map +1 -0
  81. package/lib/plugins/service-tunnel-client-api/index.js +591 -0
  82. package/lib/plugins/service-tunnel-client-api/index.js.map +1 -0
  83. package/lib/plugins/service-tunnel-client-api/registry.d.ts +36 -0
  84. package/lib/plugins/service-tunnel-client-api/registry.d.ts.map +1 -0
  85. package/lib/plugins/service-tunnel-client-api/registry.js +14 -0
  86. package/lib/plugins/service-tunnel-client-api/registry.js.map +1 -0
  87. package/lib/plugins/service-tunnel-client-api/schemas.d.ts +66 -0
  88. package/lib/plugins/service-tunnel-client-api/schemas.d.ts.map +1 -0
  89. package/lib/plugins/service-tunnel-client-api/schemas.js +56 -0
  90. package/lib/plugins/service-tunnel-client-api/schemas.js.map +1 -0
  91. package/lib/plugins/service-tunnel-web/http.d.ts +4 -0
  92. package/lib/plugins/service-tunnel-web/http.d.ts.map +1 -0
  93. package/lib/plugins/service-tunnel-web/http.js +119 -0
  94. package/lib/plugins/service-tunnel-web/http.js.map +1 -0
  95. package/lib/plugins/service-tunnel-web/index.d.ts +79 -0
  96. package/lib/plugins/service-tunnel-web/index.d.ts.map +1 -0
  97. package/lib/plugins/service-tunnel-web/index.js +278 -0
  98. package/lib/plugins/service-tunnel-web/index.js.map +1 -0
  99. package/lib/plugins/service-tunnel-web/verification.d.ts +27 -0
  100. package/lib/plugins/service-tunnel-web/verification.d.ts.map +1 -0
  101. package/lib/plugins/service-tunnel-web/verification.js +209 -0
  102. package/lib/plugins/service-tunnel-web/verification.js.map +1 -0
  103. package/lib/prisma.d.ts +6 -0
  104. package/lib/prisma.d.ts.map +1 -0
  105. package/lib/prisma.js +10 -0
  106. package/lib/prisma.js.map +1 -0
  107. package/lib/schemas/service-betterportal.json +109 -0
  108. package/lib/schemas/service-tunnel-client-api.json +300 -0
  109. package/lib/schemas/service-tunnel-web.json +140 -0
  110. package/package.json +60 -0
  111. package/prisma/migrations/0001_init/migration.sql +63 -0
  112. package/prisma/migrations/0002_account_plan/migration.sql +6 -0
  113. package/prisma/migrations/0003_tunnel_owner_server/migration.sql +1 -0
  114. package/prisma/migrations/20260701000000_add_client_auth/migration.sql +46 -0
  115. package/prisma/migrations/migration_lock.toml +3 -0
  116. package/prisma/schema.prisma +141 -0
@@ -0,0 +1,109 @@
1
+ {
2
+ "pluginName": "service-betterportal",
3
+ "events": {},
4
+ "version": "1.0.0",
5
+ "configSchema": {
6
+ "anyvaliVersion": "1.0",
7
+ "schemaVersion": "1.1",
8
+ "root": {
9
+ "kind": "object",
10
+ "properties": {
11
+ "host": {
12
+ "kind": "string",
13
+ "minLength": 1,
14
+ "default": "0.0.0.0"
15
+ },
16
+ "port": {
17
+ "kind": "int",
18
+ "min": 1,
19
+ "default": 8083
20
+ },
21
+ "betterportal": {
22
+ "kind": "optional",
23
+ "inner": {
24
+ "kind": "object",
25
+ "properties": {
26
+ "bpConfigPath": {
27
+ "kind": "optional",
28
+ "inner": {
29
+ "kind": "string",
30
+ "minLength": 1
31
+ }
32
+ },
33
+ "configApiToken": {
34
+ "kind": "optional",
35
+ "inner": {
36
+ "kind": "string",
37
+ "minLength": 1
38
+ }
39
+ },
40
+ "configEncryptionKey": {
41
+ "kind": "optional",
42
+ "inner": {
43
+ "kind": "string",
44
+ "minLength": 16
45
+ }
46
+ },
47
+ "controlPlaneUrl": {
48
+ "kind": "optional",
49
+ "inner": {
50
+ "kind": "string",
51
+ "minLength": 1
52
+ }
53
+ },
54
+ "serviceApiKey": {
55
+ "kind": "optional",
56
+ "inner": {
57
+ "kind": "string",
58
+ "minLength": 1
59
+ }
60
+ },
61
+ "bootstrapStatePath": {
62
+ "kind": "string",
63
+ "minLength": 1,
64
+ "default": "./.bp-bootstrap/state.enc"
65
+ },
66
+ "scopedConfigCachePath": {
67
+ "kind": "string",
68
+ "minLength": 1,
69
+ "default": "./.bp-sync-cache/scoped.json"
70
+ },
71
+ "trustedProxyHeaders": {
72
+ "kind": "bool",
73
+ "default": false
74
+ },
75
+ "cfProxy": {
76
+ "kind": "bool",
77
+ "default": false
78
+ },
79
+ "trustedProxyIps": {
80
+ "kind": "array",
81
+ "items": {
82
+ "kind": "string",
83
+ "minLength": 1
84
+ },
85
+ "default": []
86
+ }
87
+ },
88
+ "required": [
89
+ "bootstrapStatePath",
90
+ "scopedConfigCachePath",
91
+ "trustedProxyHeaders",
92
+ "cfProxy",
93
+ "trustedProxyIps"
94
+ ],
95
+ "unknownKeys": "strip"
96
+ }
97
+ }
98
+ },
99
+ "required": [
100
+ "host",
101
+ "port"
102
+ ],
103
+ "unknownKeys": "strip"
104
+ },
105
+ "definitions": {},
106
+ "extensions": {}
107
+ },
108
+ "pluginType": "service"
109
+ }
@@ -0,0 +1,300 @@
1
+ {
2
+ "pluginName": "service-tunnel-client-api",
3
+ "events": {
4
+ "ws.toOrigin": {
5
+ "type": "fire-and-forget",
6
+ "category": "onEvents",
7
+ "description": "Relay a public websocket frame to the connected tunnel client",
8
+ "inputSchema": {
9
+ "anyvaliVersion": "1.0",
10
+ "schemaVersion": "1.1",
11
+ "root": {
12
+ "kind": "object",
13
+ "properties": {
14
+ "publicServerId": {
15
+ "kind": "string"
16
+ },
17
+ "publicSocketId": {
18
+ "kind": "string"
19
+ },
20
+ "hostname": {
21
+ "kind": "string"
22
+ },
23
+ "path": {
24
+ "kind": "string"
25
+ },
26
+ "frameType": {
27
+ "kind": "string"
28
+ },
29
+ "event": {
30
+ "kind": "optional",
31
+ "inner": {
32
+ "kind": "string"
33
+ }
34
+ },
35
+ "body": {
36
+ "kind": "optional",
37
+ "inner": {
38
+ "kind": "string"
39
+ }
40
+ }
41
+ },
42
+ "required": [
43
+ "publicServerId",
44
+ "publicSocketId",
45
+ "hostname",
46
+ "path",
47
+ "frameType"
48
+ ],
49
+ "unknownKeys": "strip"
50
+ },
51
+ "definitions": {},
52
+ "extensions": {
53
+ "bsb": {
54
+ "description": "Public websocket frame to origin"
55
+ }
56
+ }
57
+ },
58
+ "outputSchema": null
59
+ },
60
+ "proxy.metrics": {
61
+ "type": "fire-and-forget",
62
+ "category": "onEvents",
63
+ "description": "Send final proxy request timings to the connected tunnel client",
64
+ "inputSchema": {
65
+ "anyvaliVersion": "1.0",
66
+ "schemaVersion": "1.1",
67
+ "root": {
68
+ "kind": "object",
69
+ "properties": {
70
+ "hostname": {
71
+ "kind": "string"
72
+ },
73
+ "requestId": {
74
+ "kind": "string"
75
+ },
76
+ "totalMs": {
77
+ "kind": "number"
78
+ },
79
+ "clientApiRoundtripMs": {
80
+ "kind": "optional",
81
+ "inner": {
82
+ "kind": "number"
83
+ }
84
+ },
85
+ "cliOverheadMs": {
86
+ "kind": "optional",
87
+ "inner": {
88
+ "kind": "number"
89
+ }
90
+ },
91
+ "originMs": {
92
+ "kind": "optional",
93
+ "inner": {
94
+ "kind": "number"
95
+ }
96
+ },
97
+ "internalServerMs": {
98
+ "kind": "optional",
99
+ "inner": {
100
+ "kind": "number"
101
+ }
102
+ }
103
+ },
104
+ "required": [
105
+ "hostname",
106
+ "requestId",
107
+ "totalMs"
108
+ ],
109
+ "unknownKeys": "strip"
110
+ },
111
+ "definitions": {},
112
+ "extensions": {
113
+ "bsb": {
114
+ "description": "Proxy request metrics"
115
+ }
116
+ }
117
+ },
118
+ "outputSchema": null
119
+ },
120
+ "proxy.request": {
121
+ "type": "returnable",
122
+ "category": "onReturnableEvents",
123
+ "description": "Proxy an HTTP request through a connected tunnel client",
124
+ "defaultTimeout": 60,
125
+ "inputSchema": {
126
+ "anyvaliVersion": "1.0",
127
+ "schemaVersion": "1.1",
128
+ "root": {
129
+ "kind": "object",
130
+ "properties": {
131
+ "hostname": {
132
+ "kind": "string"
133
+ },
134
+ "method": {
135
+ "kind": "string"
136
+ },
137
+ "path": {
138
+ "kind": "string"
139
+ },
140
+ "headers": {
141
+ "kind": "record",
142
+ "valueSchema": {
143
+ "kind": "string"
144
+ }
145
+ },
146
+ "body": {
147
+ "kind": "optional",
148
+ "inner": {
149
+ "kind": "string"
150
+ }
151
+ },
152
+ "webStartedAt": {
153
+ "kind": "number"
154
+ }
155
+ },
156
+ "required": [
157
+ "hostname",
158
+ "method",
159
+ "path",
160
+ "headers",
161
+ "webStartedAt"
162
+ ],
163
+ "unknownKeys": "strip"
164
+ },
165
+ "definitions": {},
166
+ "extensions": {
167
+ "bsb": {
168
+ "description": "Proxy request"
169
+ }
170
+ }
171
+ },
172
+ "outputSchema": {
173
+ "anyvaliVersion": "1.0",
174
+ "schemaVersion": "1.1",
175
+ "root": {
176
+ "kind": "object",
177
+ "properties": {
178
+ "requestId": {
179
+ "kind": "string"
180
+ },
181
+ "ownerServerId": {
182
+ "kind": "string"
183
+ },
184
+ "status": {
185
+ "kind": "number"
186
+ },
187
+ "headers": {
188
+ "kind": "record",
189
+ "valueSchema": {
190
+ "kind": "string"
191
+ }
192
+ },
193
+ "body": {
194
+ "kind": "string"
195
+ },
196
+ "webStartedAt": {
197
+ "kind": "number"
198
+ },
199
+ "clientApiRoundtripMs": {
200
+ "kind": "number"
201
+ },
202
+ "cliOverheadMs": {
203
+ "kind": "optional",
204
+ "inner": {
205
+ "kind": "number"
206
+ }
207
+ },
208
+ "originMs": {
209
+ "kind": "optional",
210
+ "inner": {
211
+ "kind": "number"
212
+ }
213
+ }
214
+ },
215
+ "required": [
216
+ "requestId",
217
+ "ownerServerId",
218
+ "status",
219
+ "headers",
220
+ "body",
221
+ "webStartedAt",
222
+ "clientApiRoundtripMs"
223
+ ],
224
+ "unknownKeys": "strip"
225
+ },
226
+ "definitions": {},
227
+ "extensions": {
228
+ "bsb": {
229
+ "description": "Proxy response"
230
+ }
231
+ }
232
+ }
233
+ }
234
+ },
235
+ "version": "1.0.0",
236
+ "configSchema": {
237
+ "anyvaliVersion": "1.0",
238
+ "schemaVersion": "1.1",
239
+ "root": {
240
+ "kind": "object",
241
+ "properties": {
242
+ "port": {
243
+ "kind": "number",
244
+ "default": 8081,
245
+ "metadata": {
246
+ "description": "Client API listener port"
247
+ }
248
+ },
249
+ "domain": {
250
+ "kind": "string",
251
+ "default": "tunnels.betterportal.dev",
252
+ "metadata": {
253
+ "description": "Default public tunnel domain"
254
+ }
255
+ },
256
+ "publicUrl": {
257
+ "kind": "string",
258
+ "default": "https://tunnels.betterportal.dev",
259
+ "metadata": {
260
+ "description": "Public base URL"
261
+ }
262
+ },
263
+ "authAppBaseUrl": {
264
+ "kind": "string",
265
+ "default": "https://betterportal.cloud",
266
+ "metadata": {
267
+ "description": "BetterPortal app URL used for CLI auth"
268
+ }
269
+ },
270
+ "authVerifyPath": {
271
+ "kind": "string",
272
+ "default": "/cli-auth/verify",
273
+ "metadata": {
274
+ "description": "BetterPortal CLI auth verify route"
275
+ }
276
+ }
277
+ },
278
+ "required": [
279
+ "port",
280
+ "domain",
281
+ "publicUrl",
282
+ "authAppBaseUrl",
283
+ "authVerifyPath"
284
+ ],
285
+ "unknownKeys": "strip",
286
+ "metadata": {
287
+ "description": "service-tunnel-client-api config"
288
+ }
289
+ },
290
+ "definitions": {},
291
+ "extensions": {}
292
+ },
293
+ "pluginType": "service",
294
+ "dependencies": [
295
+ {
296
+ "id": "_/service-tunnel-web.js",
297
+ "version": "1.0.0"
298
+ }
299
+ ]
300
+ }
@@ -0,0 +1,140 @@
1
+ {
2
+ "pluginName": "service-tunnel-web",
3
+ "events": {
4
+ "ws.fromOrigin": {
5
+ "type": "fire-and-forget",
6
+ "category": "onEvents",
7
+ "description": "Relay an origin websocket frame to the public websocket",
8
+ "inputSchema": {
9
+ "anyvaliVersion": "1.0",
10
+ "schemaVersion": "1.1",
11
+ "root": {
12
+ "kind": "object",
13
+ "properties": {
14
+ "publicSocketId": {
15
+ "kind": "string"
16
+ },
17
+ "frameType": {
18
+ "kind": "string"
19
+ },
20
+ "event": {
21
+ "kind": "optional",
22
+ "inner": {
23
+ "kind": "string"
24
+ }
25
+ },
26
+ "body": {
27
+ "kind": "optional",
28
+ "inner": {
29
+ "kind": "string"
30
+ }
31
+ }
32
+ },
33
+ "required": [
34
+ "publicSocketId",
35
+ "frameType"
36
+ ],
37
+ "unknownKeys": "strip"
38
+ },
39
+ "definitions": {},
40
+ "extensions": {
41
+ "bsb": {
42
+ "description": "Origin websocket frame to public client"
43
+ }
44
+ }
45
+ },
46
+ "outputSchema": null
47
+ }
48
+ },
49
+ "version": "1.0.0",
50
+ "configSchema": {
51
+ "anyvaliVersion": "1.0",
52
+ "schemaVersion": "1.1",
53
+ "root": {
54
+ "kind": "object",
55
+ "properties": {
56
+ "port": {
57
+ "kind": "number",
58
+ "default": 8080,
59
+ "metadata": {
60
+ "description": "Public web listener port"
61
+ }
62
+ },
63
+ "domain": {
64
+ "kind": "string",
65
+ "default": "tunnels.betterportal.dev",
66
+ "metadata": {
67
+ "description": "Tunnel root domain"
68
+ }
69
+ },
70
+ "verificationHost": {
71
+ "kind": "string",
72
+ "default": "verify.tunnels.betterportal.dev",
73
+ "metadata": {
74
+ "description": "Verification host"
75
+ }
76
+ },
77
+ "cookieSecret": {
78
+ "kind": "string",
79
+ "default": "dev-cookie-secret",
80
+ "metadata": {
81
+ "description": "Signed verification cookie secret"
82
+ }
83
+ },
84
+ "turnstileSiteKey": {
85
+ "kind": "optional",
86
+ "inner": {
87
+ "kind": "string"
88
+ },
89
+ "metadata": {
90
+ "description": "Cloudflare Turnstile site key"
91
+ }
92
+ },
93
+ "turnstileSecretKey": {
94
+ "kind": "optional",
95
+ "inner": {
96
+ "kind": "string"
97
+ },
98
+ "metadata": {
99
+ "description": "Cloudflare Turnstile secret key"
100
+ }
101
+ },
102
+ "maxHeaderBytes": {
103
+ "kind": "number",
104
+ "default": 32768,
105
+ "metadata": {
106
+ "description": "Maximum accepted request header bytes"
107
+ }
108
+ },
109
+ "maxBodyBytes": {
110
+ "kind": "number",
111
+ "default": 2097152,
112
+ "metadata": {
113
+ "description": "Maximum accepted request body bytes"
114
+ }
115
+ }
116
+ },
117
+ "required": [
118
+ "port",
119
+ "domain",
120
+ "verificationHost",
121
+ "cookieSecret",
122
+ "maxHeaderBytes",
123
+ "maxBodyBytes"
124
+ ],
125
+ "unknownKeys": "strip",
126
+ "metadata": {
127
+ "description": "service-tunnel-web config"
128
+ }
129
+ },
130
+ "definitions": {},
131
+ "extensions": {}
132
+ },
133
+ "pluginType": "service",
134
+ "dependencies": [
135
+ {
136
+ "id": "_/service-tunnel-client-api.js",
137
+ "version": "1.0.0"
138
+ }
139
+ ]
140
+ }
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@betterportal/tunnels",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "license": "(AGPL-3.0-only OR Commercial)",
6
+ "files": [
7
+ "lib/",
8
+ "prisma/",
9
+ "README.md",
10
+ "SPEC.md",
11
+ "package.json"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "scripts": {
17
+ "build": "bsb-plugin-cli build",
18
+ "typecheck": "tsc -p tsconfig.json",
19
+ "dev": "bsb-plugin-cli dev",
20
+ "start": "bsb-plugin-cli start",
21
+ "cli": "tsx src/cli.ts",
22
+ "bp-codegen": "bp-codegen",
23
+ "prisma:generate": "prisma generate",
24
+ "prisma:migrate": "prisma migrate dev",
25
+ "test": "node --import tsx --test tests/*.test.ts",
26
+ "check": "npm run build && npm test"
27
+ },
28
+ "dependencies": {
29
+ "@betterportal/framework": "^10.0.0",
30
+ "@betterportal/plugin-bsb": "^10.0.0",
31
+ "@bsb/base": "^9.6.41",
32
+ "@bsb/config-vault": "^9.6.47",
33
+ "@prisma/adapter-pg": "^7.8.0",
34
+ "@prisma/client": "^7.8.0",
35
+ "anyvali": "^1.0.6",
36
+ "dotenv": "^17.2.3",
37
+ "h3": "^2.0.1-rc.22",
38
+ "jsx-htmx": "^4.0.0-beta2",
39
+ "pg": "^8.22.0",
40
+ "ws": "^8.18.3"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^24.10.1",
44
+ "@types/ws": "^8.18.1",
45
+ "prisma": "^7.8.0",
46
+ "tsx": "^4.21.0",
47
+ "typescript": "^5.9.3"
48
+ },
49
+ "bsb": {
50
+ "hooks": {
51
+ "afterSchemas": "bp-codegen",
52
+ "beforeCompile": "prisma:generate"
53
+ }
54
+ },
55
+ "betterportal": {
56
+ "routes": [
57
+ "src/plugins/service-betterportal/bp-routes/"
58
+ ]
59
+ }
60
+ }
@@ -0,0 +1,63 @@
1
+ CREATE TYPE "TunnelStatus" AS ENUM ('created', 'active', 'draining', 'disconnected', 'expired', 'closed');
2
+
3
+ CREATE TABLE "Account" (
4
+ "id" TEXT PRIMARY KEY,
5
+ "email" TEXT UNIQUE,
6
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
7
+ );
8
+
9
+ CREATE TABLE "ClientSession" (
10
+ "id" TEXT PRIMARY KEY,
11
+ "accountId" TEXT,
12
+ "ipHash" TEXT,
13
+ "userAgent" TEXT,
14
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
15
+ "expiresAt" TIMESTAMPTZ
16
+ );
17
+
18
+ CREATE TABLE "Tunnel" (
19
+ "id" TEXT PRIMARY KEY,
20
+ "accountId" TEXT,
21
+ "sessionId" TEXT NOT NULL,
22
+ "subdomain" TEXT NOT NULL UNIQUE,
23
+ "targetHost" TEXT NOT NULL,
24
+ "targetPort" INTEGER NOT NULL,
25
+ "authenticated" BOOLEAN NOT NULL DEFAULT false,
26
+ "status" "TunnelStatus" NOT NULL DEFAULT 'created',
27
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
28
+ "expiresAt" TIMESTAMPTZ NOT NULL,
29
+ CONSTRAINT "Tunnel_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account"("id") ON DELETE SET NULL ON UPDATE CASCADE,
30
+ CONSTRAINT "Tunnel_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "ClientSession"("id") ON DELETE RESTRICT ON UPDATE CASCADE
31
+ );
32
+
33
+ CREATE TABLE "VisitorValidation" (
34
+ "id" TEXT PRIMARY KEY,
35
+ "tunnelId" TEXT NOT NULL,
36
+ "visitorIpHash" TEXT NOT NULL,
37
+ "userAgentHash" TEXT NOT NULL,
38
+ "validationCookieHash" TEXT NOT NULL,
39
+ "validatedAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
40
+ "expiresAt" TIMESTAMPTZ NOT NULL,
41
+ CONSTRAINT "VisitorValidation_tunnelId_fkey" FOREIGN KEY ("tunnelId") REFERENCES "Tunnel"("id") ON DELETE RESTRICT ON UPDATE CASCADE
42
+ );
43
+
44
+ CREATE TABLE "UsageCounter" (
45
+ "tunnelId" TEXT PRIMARY KEY,
46
+ "requests" INTEGER NOT NULL DEFAULT 0,
47
+ "bytesIn" BIGINT NOT NULL DEFAULT 0,
48
+ "bytesOut" BIGINT NOT NULL DEFAULT 0,
49
+ "updatedAt" TIMESTAMPTZ NOT NULL,
50
+ CONSTRAINT "UsageCounter_tunnelId_fkey" FOREIGN KEY ("tunnelId") REFERENCES "Tunnel"("id") ON DELETE RESTRICT ON UPDATE CASCADE
51
+ );
52
+
53
+ CREATE TABLE "AuditEvent" (
54
+ "id" TEXT PRIMARY KEY,
55
+ "event" TEXT NOT NULL,
56
+ "subjectId" TEXT,
57
+ "data" JSONB,
58
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
59
+ );
60
+
61
+ CREATE INDEX "Tunnel_sessionId_idx" ON "Tunnel"("sessionId");
62
+ CREATE INDEX "Tunnel_expiresAt_idx" ON "Tunnel"("expiresAt");
63
+ CREATE INDEX "VisitorValidation_tunnelId_visitorIpHash_userAgentHash_idx" ON "VisitorValidation"("tunnelId", "visitorIpHash", "userAgentHash");
@@ -0,0 +1,6 @@
1
+ CREATE TYPE "AccountPlan" AS ENUM ('anonymous', 'free', 'paid', 'admin');
2
+
3
+ ALTER TABLE "Account"
4
+ ADD COLUMN "plan" "AccountPlan" NOT NULL DEFAULT 'anonymous',
5
+ ADD COLUMN "verificationBypass" BOOLEAN NOT NULL DEFAULT false,
6
+ ADD COLUMN "ipVerification" BOOLEAN NOT NULL DEFAULT false;
@@ -0,0 +1 @@
1
+ ALTER TABLE "Tunnel" ADD COLUMN "ownerServerId" TEXT;