@tapflowio/relay 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/RelayServer.d.ts +10 -0
- package/dist/RelayServer.d.ts.map +1 -1
- package/dist/RelayServer.js +53 -5
- package/dist/RelayServer.js.map +1 -1
- package/dist/api/builds.d.ts.map +1 -1
- package/dist/api/builds.js +14 -13
- package/dist/api/builds.js.map +1 -1
- package/dist/api/comments.d.ts.map +1 -1
- package/dist/api/comments.js +23 -10
- package/dist/api/comments.js.map +1 -1
- package/dist/api/team.d.ts.map +1 -1
- package/dist/api/team.js +4 -2
- package/dist/api/team.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/cert/AcmeCertProvider.d.ts +55 -0
- package/dist/lib/cert/AcmeCertProvider.d.ts.map +1 -0
- package/dist/lib/cert/AcmeCertProvider.js +62 -0
- package/dist/lib/cert/AcmeCertProvider.js.map +1 -0
- package/dist/lib/cert/AcmeClientIssuer.d.ts +23 -0
- package/dist/lib/cert/AcmeClientIssuer.d.ts.map +1 -0
- package/dist/lib/cert/AcmeClientIssuer.js +54 -0
- package/dist/lib/cert/AcmeClientIssuer.js.map +1 -0
- package/dist/lib/cert/CertProvider.d.ts +30 -0
- package/dist/lib/cert/CertProvider.d.ts.map +1 -0
- package/dist/lib/cert/CertProvider.js +4 -0
- package/dist/lib/cert/CertProvider.js.map +1 -0
- package/dist/lib/cert/CloudflareDnsProvider.d.ts +40 -0
- package/dist/lib/cert/CloudflareDnsProvider.d.ts.map +1 -0
- package/dist/lib/cert/CloudflareDnsProvider.js +93 -0
- package/dist/lib/cert/CloudflareDnsProvider.js.map +1 -0
- package/dist/lib/cert/DiskCertStore.d.ts +10 -0
- package/dist/lib/cert/DiskCertStore.d.ts.map +1 -0
- package/dist/lib/cert/DiskCertStore.js +35 -0
- package/dist/lib/cert/DiskCertStore.js.map +1 -0
- package/dist/lib/cert/DnsProvider.d.ts +7 -0
- package/dist/lib/cert/DnsProvider.d.ts.map +1 -0
- package/dist/lib/cert/DnsProvider.js +2 -0
- package/dist/lib/cert/DnsProvider.js.map +1 -0
- package/dist/lib/cert/ImportCertProvider.d.ts +20 -0
- package/dist/lib/cert/ImportCertProvider.d.ts.map +1 -0
- package/dist/lib/cert/ImportCertProvider.js +24 -0
- package/dist/lib/cert/ImportCertProvider.js.map +1 -0
- package/dist/lib/cert/VercelDnsProvider.d.ts +38 -0
- package/dist/lib/cert/VercelDnsProvider.d.ts.map +1 -0
- package/dist/lib/cert/VercelDnsProvider.js +146 -0
- package/dist/lib/cert/VercelDnsProvider.js.map +1 -0
- package/dist/lib/cert/accountKey.d.ts +2 -0
- package/dist/lib/cert/accountKey.d.ts.map +1 -0
- package/dist/lib/cert/accountKey.js +23 -0
- package/dist/lib/cert/accountKey.js.map +1 -0
- package/dist/lib/cert/addressPublisher.d.ts +20 -0
- package/dist/lib/cert/addressPublisher.d.ts.map +1 -0
- package/dist/lib/cert/addressPublisher.js +103 -0
- package/dist/lib/cert/addressPublisher.js.map +1 -0
- package/dist/lib/cert/createCertProvider.d.ts +20 -0
- package/dist/lib/cert/createCertProvider.d.ts.map +1 -0
- package/dist/lib/cert/createCertProvider.js +25 -0
- package/dist/lib/cert/createCertProvider.js.map +1 -0
- package/dist/lib/cert/dnsRegistry.d.ts +24 -0
- package/dist/lib/cert/dnsRegistry.d.ts.map +1 -0
- package/dist/lib/cert/dnsRegistry.js +36 -0
- package/dist/lib/cert/dnsRegistry.js.map +1 -0
- package/dist/lib/cert/index.d.ts +23 -0
- package/dist/lib/cert/index.d.ts.map +1 -0
- package/dist/lib/cert/index.js +12 -0
- package/dist/lib/cert/index.js.map +1 -0
- package/dist/lib/cert/parseCert.d.ts +3 -0
- package/dist/lib/cert/parseCert.d.ts.map +1 -0
- package/dist/lib/cert/parseCert.js +6 -0
- package/dist/lib/cert/parseCert.js.map +1 -0
- package/dist/lib/cert/renewal.d.ts +13 -0
- package/dist/lib/cert/renewal.d.ts.map +1 -0
- package/dist/lib/cert/renewal.js +28 -0
- package/dist/lib/cert/renewal.js.map +1 -0
- package/dist/lib/config.d.ts +22 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +39 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/cors.d.ts +2 -0
- package/dist/lib/cors.d.ts.map +1 -0
- package/dist/lib/cors.js +18 -0
- package/dist/lib/cors.js.map +1 -0
- package/dist/lib/csrf.d.ts +3 -0
- package/dist/lib/csrf.d.ts.map +1 -0
- package/dist/lib/csrf.js +42 -0
- package/dist/lib/csrf.js.map +1 -0
- package/dist/lib/loadEnvFile.d.ts +2 -0
- package/dist/lib/loadEnvFile.d.ts.map +1 -0
- package/dist/lib/loadEnvFile.js +17 -0
- package/dist/lib/loadEnvFile.js.map +1 -0
- package/dist/lib/proxyConfig.d.ts +6 -0
- package/dist/lib/proxyConfig.d.ts.map +1 -0
- package/dist/lib/proxyConfig.js +27 -0
- package/dist/lib/proxyConfig.js.map +1 -0
- package/dist/lib/publicUrl.d.ts +3 -0
- package/dist/lib/publicUrl.d.ts.map +1 -0
- package/dist/lib/publicUrl.js +17 -0
- package/dist/lib/publicUrl.js.map +1 -0
- package/dist/lib/uploads.d.ts +2 -0
- package/dist/lib/uploads.d.ts.map +1 -0
- package/dist/lib/uploads.js +14 -0
- package/dist/lib/uploads.js.map +1 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +13 -1
- package/dist/router.js.map +1 -1
- package/dist/server.js +44 -5
- package/dist/server.js.map +1 -1
- package/package.json +6 -5
- package/public/assets/AppCenter-CaY73Tvf.js +16 -0
- package/public/assets/AppCenter-CaY73Tvf.js.br +0 -0
- package/public/assets/Default-DQiKj0NT.js +1 -0
- package/public/assets/Default-DQiKj0NT.js.br +0 -0
- package/public/assets/Invite-B4MMcQtw.js +1 -0
- package/public/assets/Invite-B4MMcQtw.js.br +0 -0
- package/public/assets/MacResources-BfZAJ5BP.js +5 -0
- package/public/assets/MacResources-BfZAJ5BP.js.br +0 -0
- package/public/assets/NotFound-D85RKzwv.js +1 -0
- package/public/assets/NotFound-D85RKzwv.js.br +0 -0
- package/public/assets/QASession-B9FSUtZo.js +130 -0
- package/public/assets/QASession-B9FSUtZo.js.br +0 -0
- package/public/assets/ResetPassword-Degmb6sl.js +1 -0
- package/public/assets/ResetPassword-Degmb6sl.js.br +0 -0
- package/public/assets/Setup-DKOFxDo2.js +1 -0
- package/public/assets/Setup-DKOFxDo2.js.br +0 -0
- package/public/assets/Team-Bgspan2B.js +6 -0
- package/public/assets/Team-Bgspan2B.js.br +0 -0
- package/public/assets/Tokens-C3u48FUG.js +6 -0
- package/public/assets/Tokens-C3u48FUG.js.br +0 -0
- package/public/assets/alert-dialog-Ci_cWoVo.js +7 -0
- package/public/assets/alert-dialog-Ci_cWoVo.js.br +0 -0
- package/public/assets/badge-Cktrrdvf.js +1 -0
- package/public/assets/badge-Cktrrdvf.js.br +0 -0
- package/public/assets/build-format-Blzidb1D.js +11 -0
- package/public/assets/build-format-Blzidb1D.js.br +0 -0
- package/public/assets/dialog-BuZjQWBQ.js +11 -0
- package/public/assets/dialog-BuZjQWBQ.js.br +0 -0
- package/public/assets/index-BI7E3MD-.css +1 -0
- package/public/assets/index-BI7E3MD-.css.br +0 -0
- package/public/assets/index-ClAB0eKw.js +258 -0
- package/public/assets/index-ClAB0eKw.js.br +0 -0
- package/public/assets/inter-latin-ext-standard-normal-DpK-iCPk.woff2 +0 -0
- package/public/assets/inter-latin-standard-normal-BwkfbSeq.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/public/assets/pencil-BoxokH2R.js +6 -0
- package/public/assets/pencil-BoxokH2R.js.br +0 -0
- package/public/assets/plus-C0Y4Yk9P.js +6 -0
- package/public/assets/plus-C0Y4Yk9P.js.br +0 -0
- package/public/assets/table-NBRnBazr.js +1 -0
- package/public/assets/table-NBRnBazr.js.br +0 -0
- package/public/assets/tabs-CB9a8dpY.js +1 -0
- package/public/assets/tabs-CB9a8dpY.js.br +0 -0
- package/public/assets/tinyh264.worker-DiJ50Hai.js.br +0 -0
- package/public/favicon.svg.br +0 -0
- package/public/index.html +2 -2
- package/public/index.html.br +0 -0
- package/public/logo-dark.svg.br +0 -0
- package/public/logo.svg.br +0 -0
- package/public/assets/index-Bhoumejm.js +0 -520
- package/public/assets/index-DX5Pf9T6.css +0 -1
- package/public/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/public/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/public/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/public/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/public/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
- package/public/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- package/public/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/public/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/public/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/public/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/public/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
- package/public/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- package/public/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/public/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/public/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/public/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/public/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
- package/public/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- package/public/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/public/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/public/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/public/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/public/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
- package/public/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- package/public/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/public/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/public/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/public/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/public/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- package/public/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/public/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/public/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/public/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/public/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/public/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
- package/public/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- package/public/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/public/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/public/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/public/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/public/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
- package/public/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- package/public/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/public/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/public/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/public/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/public/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/public/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
package/dist/lib/config.d.ts
CHANGED
|
@@ -22,6 +22,17 @@ declare const configSchema: z.ZodObject<{
|
|
|
22
22
|
provider: z.ZodLiteral<"tailscale">;
|
|
23
23
|
publicUrl: z.ZodOptional<z.ZodString>;
|
|
24
24
|
}, z.core.$strip>], "provider">>;
|
|
25
|
+
tls: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
26
|
+
mode: z.ZodLiteral<"byo-api-token">;
|
|
27
|
+
domain: z.ZodString;
|
|
28
|
+
dnsProvider: z.ZodString;
|
|
29
|
+
publishAddress: z.ZodOptional<z.ZodBoolean>;
|
|
30
|
+
address: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
32
|
+
mode: z.ZodLiteral<"import-cert">;
|
|
33
|
+
certPath: z.ZodString;
|
|
34
|
+
keyPath: z.ZodString;
|
|
35
|
+
}, z.core.$strip>], "mode">>;
|
|
25
36
|
smtp: z.ZodObject<{
|
|
26
37
|
host: z.ZodString;
|
|
27
38
|
port: z.ZodNumber;
|
|
@@ -56,6 +67,17 @@ export declare const config: {
|
|
|
56
67
|
provider: "tailscale";
|
|
57
68
|
publicUrl?: string | undefined;
|
|
58
69
|
} | null;
|
|
70
|
+
tls: {
|
|
71
|
+
mode: "byo-api-token";
|
|
72
|
+
domain: string;
|
|
73
|
+
dnsProvider: string;
|
|
74
|
+
publishAddress?: boolean | undefined;
|
|
75
|
+
address?: string | undefined;
|
|
76
|
+
} | {
|
|
77
|
+
mode: "import-cert";
|
|
78
|
+
certPath: string;
|
|
79
|
+
keyPath: string;
|
|
80
|
+
} | null;
|
|
59
81
|
smtp: {
|
|
60
82
|
host: string;
|
|
61
83
|
port: number;
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAkDvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoBhB,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAiIxD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkBnE;AAaD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAS,CAAA;AAC5B,eAAO,MAAM,SAAS,QAAkB,CAAA"}
|
package/dist/lib/config.js
CHANGED
|
@@ -4,6 +4,7 @@ import crypto from 'crypto';
|
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { createLogger } from '@tapflowio/agent-core';
|
|
6
6
|
import { parseTrustedProxies } from './clientAddress.js';
|
|
7
|
+
import { dnsProviders } from './cert/dnsRegistry.js';
|
|
7
8
|
const logger = createLogger('relay:config');
|
|
8
9
|
const tunnelSshSchema = z.object({
|
|
9
10
|
host: z.string().min(1),
|
|
@@ -21,6 +22,26 @@ const tailscaleTunnelSchema = z.object({
|
|
|
21
22
|
publicUrl: z.string().optional(),
|
|
22
23
|
});
|
|
23
24
|
const tunnelSchema = z.discriminatedUnion('provider', [ratholeTunnelSchema, tailscaleTunnelSchema]);
|
|
25
|
+
// LAN HTTPS (issue #232) — secure context용 TLS 종단 설정. 골격: v1은 LAN 가지만 구현.
|
|
26
|
+
// 비밀(DNS API 토큰)은 config 파일이 아니라 env에서 읽는다(예: TAPFLOW_CLOUDFLARE_TOKEN).
|
|
27
|
+
const importCertTlsSchema = z.object({
|
|
28
|
+
mode: z.literal('import-cert'),
|
|
29
|
+
certPath: z.string().min(1),
|
|
30
|
+
keyPath: z.string().min(1),
|
|
31
|
+
});
|
|
32
|
+
const byoApiTokenTlsSchema = z.object({
|
|
33
|
+
mode: z.literal('byo-api-token'),
|
|
34
|
+
domain: z.string().min(1),
|
|
35
|
+
// 유효 provider는 레지스트리가 정한다(새 provider 추가 시 스키마 무변경).
|
|
36
|
+
dnsProvider: z.string().min(1).refine((n) => dnsProviders.has(n), {
|
|
37
|
+
message: `unknown dnsProvider (available: ${dnsProviders.names().join(', ')})`,
|
|
38
|
+
}),
|
|
39
|
+
// 도메인 A 레코드를 LAN IP로 자동 발행(기본 ON). false면 사용자가 직접 관리.
|
|
40
|
+
publishAddress: z.boolean().optional(),
|
|
41
|
+
// 자동 감지 대신 쓸 고정 LAN IP(멀티NIC/VPN 환경 오버라이드).
|
|
42
|
+
address: z.string().min(1).optional(),
|
|
43
|
+
});
|
|
44
|
+
const tlsSchema = z.discriminatedUnion('mode', [byoApiTokenTlsSchema, importCertTlsSchema]);
|
|
24
45
|
const configSchema = z.object({
|
|
25
46
|
local: z.object({
|
|
26
47
|
port: z.number().int().min(1).max(65535),
|
|
@@ -32,6 +53,7 @@ const configSchema = z.object({
|
|
|
32
53
|
url: z.string().nullable(),
|
|
33
54
|
}),
|
|
34
55
|
tunnel: tunnelSchema.nullable(),
|
|
56
|
+
tls: tlsSchema.nullable(),
|
|
35
57
|
smtp: z.object({
|
|
36
58
|
host: z.string(),
|
|
37
59
|
port: z.number().int().min(1).max(65535),
|
|
@@ -52,6 +74,7 @@ const DEFAULTS = {
|
|
|
52
74
|
url: null,
|
|
53
75
|
},
|
|
54
76
|
tunnel: null,
|
|
77
|
+
tls: null,
|
|
55
78
|
smtp: {
|
|
56
79
|
host: '',
|
|
57
80
|
port: 587,
|
|
@@ -105,6 +128,22 @@ function load() {
|
|
|
105
128
|
: null,
|
|
106
129
|
};
|
|
107
130
|
})(),
|
|
131
|
+
tls: (() => {
|
|
132
|
+
if (file.tls == null)
|
|
133
|
+
return null;
|
|
134
|
+
const t = file.tls;
|
|
135
|
+
if (t.mode === 'import-cert') {
|
|
136
|
+
return { mode: 'import-cert', certPath: t.certPath ?? '', keyPath: t.keyPath ?? '' };
|
|
137
|
+
}
|
|
138
|
+
// Pass mode/provider through (no silent default) so zod rejects a missing/misspelled provider.
|
|
139
|
+
return {
|
|
140
|
+
mode: t.mode,
|
|
141
|
+
domain: t.domain ?? '',
|
|
142
|
+
dnsProvider: t.dnsProvider ?? '',
|
|
143
|
+
...(t.publishAddress !== undefined ? { publishAddress: t.publishAddress } : {}),
|
|
144
|
+
...(t.address !== undefined ? { address: t.address } : {}),
|
|
145
|
+
};
|
|
146
|
+
})(),
|
|
108
147
|
smtp: {
|
|
109
148
|
host: file.smtp?.host ?? DEFAULTS.smtp.host,
|
|
110
149
|
port: file.smtp?.port ?? DEFAULTS.smtp.port,
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,MAAM,MAAM,QAAQ,CAAA;AAC3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/lib/cors.ts"],"names":[],"mappings":"AAKA,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAS/B"}
|
package/dist/lib/cors.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// #4 — CORS 출처 제한.
|
|
2
|
+
// 기존엔 모든 응답에 `Access-Control-Allow-Origin: *` + `Allow-Headers: Authorization`을 줘서,
|
|
3
|
+
// PAT(Authorization 헤더)를 cross-origin 스크립트에서 사용할 수 있었다. 허용 출처 allowlist에
|
|
4
|
+
// 든 origin만 에코하고, 그 외에는 CORS 헤더를 부여하지 않는다(브라우저가 cross-origin을 차단).
|
|
5
|
+
// same-origin 요청과 비-브라우저(CLI/서버-서버, Origin 헤더 없음)는 CORS와 무관하게 그대로 동작한다.
|
|
6
|
+
export function resolveCorsHeaders(origin, allowedOrigins) {
|
|
7
|
+
if (!origin)
|
|
8
|
+
return null;
|
|
9
|
+
if (!allowedOrigins.has(origin))
|
|
10
|
+
return null;
|
|
11
|
+
return {
|
|
12
|
+
'Access-Control-Allow-Origin': origin,
|
|
13
|
+
'Vary': 'Origin',
|
|
14
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
15
|
+
'Access-Control-Allow-Methods': 'GET, POST, PATCH, DELETE, OPTIONS',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/lib/cors.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,oFAAoF;AACpF,yEAAyE;AACzE,mEAAmE;AACnE,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAChC,MAA0B,EAC1B,cAA2B;IAE3B,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACxB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5C,OAAO;QACL,6BAA6B,EAAE,MAAM;QACrC,MAAM,EAAE,QAAQ;QAChB,8BAA8B,EAAE,6BAA6B;QAC7D,8BAA8B,EAAE,mCAAmC;KACpE,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/lib/csrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAkB5B,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,IAAI,CAAC,mBAAmB,EACjC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,OAAO,CAoBT"}
|
package/dist/lib/csrf.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// #5 — CSRF 경량 가드.
|
|
2
|
+
// 상태 변경 API가 `SameSite=Lax` 쿠키에만 의존하면 일부 cross-site 요청이 통과할 수 있다.
|
|
3
|
+
// 쿠키로 인증된 상태 변경 요청은 Origin이 same-origin(Host 일치)이거나 신뢰 allowlist에 있을 때만
|
|
4
|
+
// 허용하고, 그 외 cross-origin은 차단한다. 브라우저는 상태 변경 요청에 Origin을 강제로 붙이므로
|
|
5
|
+
// 대시보드(same-origin)는 그대로 통과하고, 공격자 origin은 막힌다.
|
|
6
|
+
// 면제: 안전 메서드(GET/HEAD/OPTIONS), PAT 인증(Authorization — 쿠키 자동 전송이 아님),
|
|
7
|
+
// 쿠키 없는 요청(미인증/login/init), Origin 없는 요청(비-브라우저; 브라우저는 cross-site에 Origin을 생략하지 못한다).
|
|
8
|
+
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
|
9
|
+
// Loopback origins are the local dev machine (e.g. Vite :3001 proxying to the relay :4000), never a
|
|
10
|
+
// remote attacker — a cross-site page can't forge a localhost Origin, so exempting these is safe.
|
|
11
|
+
function isLoopbackHost(hostname) {
|
|
12
|
+
const h = hostname.replace(/^\[|\]$/g, '');
|
|
13
|
+
return h === 'localhost' || h === '127.0.0.1' || h === '::1';
|
|
14
|
+
}
|
|
15
|
+
export function isCsrfBlocked(method, headers, allowedOrigins) {
|
|
16
|
+
if (SAFE_METHODS.has((method ?? 'GET').toUpperCase()))
|
|
17
|
+
return false;
|
|
18
|
+
if (headers['authorization'])
|
|
19
|
+
return false;
|
|
20
|
+
const cookie = headers['cookie'];
|
|
21
|
+
const hasCookieAuth = typeof cookie === 'string' && cookie.includes('tapflow_token=');
|
|
22
|
+
if (!hasCookieAuth)
|
|
23
|
+
return false;
|
|
24
|
+
const origin = headers['origin'];
|
|
25
|
+
if (!origin)
|
|
26
|
+
return false;
|
|
27
|
+
if (allowedOrigins.has(origin))
|
|
28
|
+
return false;
|
|
29
|
+
const host = headers['host'];
|
|
30
|
+
try {
|
|
31
|
+
const url = new URL(origin);
|
|
32
|
+
if (host && url.host === host)
|
|
33
|
+
return false;
|
|
34
|
+
if (isLoopbackHost(url.hostname))
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// malformed Origin → treat as cross-origin (blocked below)
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=csrf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/lib/csrf.ts"],"names":[],"mappings":"AAEA,mBAAmB;AACnB,kEAAkE;AAClE,wEAAwE;AACxE,iEAAiE;AACjE,gDAAgD;AAChD,sEAAsE;AACtE,4FAA4F;AAC5F,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;AAExD,oGAAoG;AACpG,kGAAkG;AAClG,SAAS,cAAc,CAAC,QAAgB;IACtC,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IAC1C,OAAO,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,KAAK,CAAA;AAC9D,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,MAA0B,EAC1B,OAAiC,EACjC,cAA2B;IAE3B,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,KAAK,CAAA;IACnE,IAAI,OAAO,CAAC,eAAe,CAAC;QAAE,OAAO,KAAK,CAAA;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAChC,MAAM,aAAa,GAAG,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAA;IACrF,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAA;IAEhC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAChC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACzB,IAAI,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IAE5C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;QAC3B,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,KAAK,CAAA;QAC3C,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,2DAA2D;IAC7D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadEnvFile.d.ts","sourceRoot":"","sources":["../../src/lib/loadEnvFile.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU7D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
// #287 — gitignore된 <dataDir>/.env 에서 DNS/ACME 자격 증명을 로드(loadEnvFile 은 기존 값을 안 덮으므로 ambient 우선).
|
|
4
|
+
export function loadDataDirEnv(dataDir) {
|
|
5
|
+
const envPath = path.join(dataDir, '.env');
|
|
6
|
+
if (!fs.existsSync(envPath))
|
|
7
|
+
return null;
|
|
8
|
+
try {
|
|
9
|
+
process.loadEnvFile(envPath);
|
|
10
|
+
return envPath;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// 손상된 파일은 무시 — 자격 증명이 없으면 cert 발급 시점에 명확히 실패한다.
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=loadEnvFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadEnvFile.js","sourceRoot":"","sources":["../../src/lib/loadEnvFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAA;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;QAC5B,OAAO,OAAO,CAAA;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;QAChD,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TapflowConfig } from './config.js';
|
|
2
|
+
type ProxyCfg = Pick<TapflowConfig, 'tunnel' | 'relay' | 'local'>;
|
|
3
|
+
export declare function buildCorsOrigins(cfg: ProxyCfg, port: number): string[];
|
|
4
|
+
export declare function proxyWithoutPublicUrlWarning(cfg: ProxyCfg): string | null;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=proxyConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxyConfig.d.ts","sourceRoot":"","sources":["../../src/lib/proxyConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,KAAK,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC,CAAA;AAGjE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAStE;AAGD,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAQzE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { buildInviteBaseUrl } from './publicUrl.js';
|
|
2
|
+
// Allow cross-origin PAT use only from the configured public origin + loopback (LAN is same-origin).
|
|
3
|
+
export function buildCorsOrigins(cfg, port) {
|
|
4
|
+
// Skip buildInviteBaseUrl's localhost fallback — it would allowlist a stale loopback at config.local.port under a different --port.
|
|
5
|
+
const configuredOrigin = (() => {
|
|
6
|
+
if (!cfg.tunnel?.publicUrl && !cfg.relay.url)
|
|
7
|
+
return null;
|
|
8
|
+
try {
|
|
9
|
+
return new URL(buildInviteBaseUrl(cfg)).origin;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
})();
|
|
15
|
+
const origins = [configuredOrigin, `http://localhost:${port}`, `http://127.0.0.1:${port}`]
|
|
16
|
+
.filter((o) => o !== null);
|
|
17
|
+
return [...new Set(origins)];
|
|
18
|
+
}
|
|
19
|
+
// A proxied/tunneled relay needs a public URL, or the CSRF/CORS allowlist stays loopback-only and blocks proxied POSTs.
|
|
20
|
+
export function proxyWithoutPublicUrlWarning(cfg) {
|
|
21
|
+
if (cfg.local.trustedProxies.length > 0 && !cfg.tunnel?.publicUrl && !cfg.relay.url) {
|
|
22
|
+
return ('TAPFLOW_TRUSTED_PROXIES is set but no public URL (tunnel.publicUrl / relay.url) is configured. ' +
|
|
23
|
+
'Cross-origin dashboard requests may be blocked by the CSRF guard — set the public URL for proxied deployments.');
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=proxyConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxyConfig.js","sourceRoot":"","sources":["../../src/lib/proxyConfig.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAInD,qGAAqG;AACrG,MAAM,UAAU,gBAAgB,CAAC,GAAa,EAAE,IAAY;IAC1D,oIAAoI;IACpI,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE;QAC7B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QACzD,IAAI,CAAC;YAAC,OAAO,IAAI,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,IAAI,CAAA;QAAC,CAAC;IAC9E,CAAC,CAAC,EAAE,CAAA;IACJ,MAAM,OAAO,GAAG,CAAC,gBAAgB,EAAE,oBAAoB,IAAI,EAAE,EAAE,oBAAoB,IAAI,EAAE,CAAC;SACvF,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAA;IACzC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;AAC9B,CAAC;AAED,wHAAwH;AACxH,MAAM,UAAU,4BAA4B,CAAC,GAAa;IACxD,IAAI,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACpF,OAAO,CACL,iGAAiG;YACjG,gHAAgH,CACjH,CAAA;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publicUrl.d.ts","sourceRoot":"","sources":["../../src/lib/publicUrl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC,GAAG,MAAM,CAOjG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// #6 — 초대/공개 링크의 신뢰 base URL.
|
|
2
|
+
// `req.headers.host`/`x-forwarded-proto`는 클라이언트가 조작할 수 있어(Host 인젝션) 피싱 링크가
|
|
3
|
+
// 정상 메일로 발송될 수 있다. 따라서 Host 헤더 대신 설정값에서만 base를 도출한다.
|
|
4
|
+
// 우선순위: 터널 공개 URL → 설정된 relay URL(ws→http 변환) → localhost 폴백.
|
|
5
|
+
export function buildInviteBaseUrl(cfg) {
|
|
6
|
+
if (cfg.tunnel?.publicUrl)
|
|
7
|
+
return stripTrailingSlash(cfg.tunnel.publicUrl);
|
|
8
|
+
if (cfg.relay.url) {
|
|
9
|
+
const http = cfg.relay.url.replace(/^ws:\/\//i, 'http://').replace(/^wss:\/\//i, 'https://');
|
|
10
|
+
return stripTrailingSlash(http);
|
|
11
|
+
}
|
|
12
|
+
return `http://localhost:${cfg.local.port}`;
|
|
13
|
+
}
|
|
14
|
+
function stripTrailingSlash(u) {
|
|
15
|
+
return u.replace(/\/+$/, '');
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=publicUrl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publicUrl.js","sourceRoot":"","sources":["../../src/lib/publicUrl.ts"],"names":[],"mappings":"AAEA,8BAA8B;AAC9B,2EAA2E;AAC3E,qDAAqD;AACrD,8DAA8D;AAC9D,MAAM,UAAU,kBAAkB,CAAC,GAAsD;IACvF,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS;QAAE,OAAO,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAC1E,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;QAC5F,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,oBAAoB,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;AAC7C,CAAC;AAED,SAAS,kBAAkB,CAAC,CAAS;IACnC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQhE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
// 업로드 정리: 파일을 삭제하되 이미 없으면(ENOENT) 조용히 넘기고, 그 외 에러만 경고한다.
|
|
3
|
+
// builds/comments 업로드 핸들러가 거부·만료된 파일을 정리할 때 공유한다.
|
|
4
|
+
export function unlinkSafe(filePath, label) {
|
|
5
|
+
try {
|
|
6
|
+
fs.unlinkSync(filePath);
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
if (err.code !== 'ENOENT') {
|
|
10
|
+
console.warn(`[tapflow] failed to delete ${label}`, err.message);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=uploads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploads.js","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,yDAAyD;AACzD,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAa;IACxD,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,8BAA8B,KAAK,EAAE,EAAG,GAAa,CAAC,OAAO,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAa5B,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAS5H,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAc;IAE5B,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAQxD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACnC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACpC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAE/B,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;CAsBpF;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAIlF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAOnE;AAED,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC,CAGjF"}
|
package/dist/router.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import { createLogger } from '@tapflowio/agent-core';
|
|
2
|
+
const logger = createLogger('relay:router');
|
|
3
|
+
// 로그에 토큰이 새지 않도록 마스킹: PAT(tflw_pat_…)와 세션 JWT(eyJ….….…).
|
|
4
|
+
// 메시지·스택뿐 아니라 method/url(경로 파라미터에 토큰이 섞인 경우)까지 포함해 로그 라인 전체에 적용한다.
|
|
5
|
+
function redactSecrets(s) {
|
|
6
|
+
return s
|
|
7
|
+
.replace(/tflw_pat_[A-Za-z0-9_-]+/g, 'tflw_pat_***')
|
|
8
|
+
.replace(/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '[jwt]');
|
|
9
|
+
}
|
|
1
10
|
export class Router {
|
|
2
11
|
routes = [];
|
|
3
12
|
on(method, path, handler) {
|
|
@@ -25,7 +34,10 @@ export class Router {
|
|
|
25
34
|
try {
|
|
26
35
|
await route.handler(req, res, params);
|
|
27
36
|
}
|
|
28
|
-
catch (
|
|
37
|
+
catch (err) {
|
|
38
|
+
// 관측성: 스택을 삼키지 말고 기록한다. 단 응답 본문에는 상세를 노출하지 않는다.
|
|
39
|
+
const detail = err instanceof Error ? (err.stack ?? err.message) : String(err);
|
|
40
|
+
logger.error(redactSecrets(`${method} ${url} — handler error: ${detail}`));
|
|
29
41
|
json(res, 500, { error: 'Internal server error' });
|
|
30
42
|
}
|
|
31
43
|
return true;
|
package/dist/router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -2,16 +2,55 @@ import path from 'path';
|
|
|
2
2
|
import { initDb } from './db.js';
|
|
3
3
|
import { RelayServer } from './RelayServer.js';
|
|
4
4
|
import { config } from './lib/config.js';
|
|
5
|
+
import { buildCorsOrigins, proxyWithoutPublicUrlWarning } from './lib/proxyConfig.js';
|
|
6
|
+
import { createCertProvider, startCertRenewal, startAddressPublisher } from './lib/cert/index.js';
|
|
7
|
+
import { loadDataDirEnv } from './lib/loadEnvFile.js';
|
|
5
8
|
import { createLogger } from '@tapflowio/agent-core';
|
|
6
9
|
const logger = createLogger('relay');
|
|
7
10
|
const { port, dataDir } = config.local;
|
|
11
|
+
// Load gitignored credentials (DNS/ACME tokens) before any cert issuance reads process.env.
|
|
12
|
+
const envPath = loadDataDirEnv(dataDir);
|
|
13
|
+
if (envPath)
|
|
14
|
+
logger.info(`Loaded credentials from ${envPath}`);
|
|
8
15
|
const dbPath = path.join(dataDir, 'tapflow.db');
|
|
9
16
|
const uploadsDir = path.join(dataDir, 'uploads');
|
|
10
17
|
initDb(dbPath);
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
const corsOrigins = buildCorsOrigins(config, port);
|
|
19
|
+
const proxyWarning = proxyWithoutPublicUrlWarning(config);
|
|
20
|
+
if (proxyWarning)
|
|
21
|
+
logger.warn(proxyWarning);
|
|
22
|
+
async function main() {
|
|
23
|
+
let tls;
|
|
24
|
+
let provider = null;
|
|
25
|
+
if (config.tls) {
|
|
26
|
+
provider = createCertProvider(config.tls, { dataDir });
|
|
27
|
+
const material = await provider.ensureCert();
|
|
28
|
+
tls = { cert: material.cert, key: material.key };
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logger.info('TLS disabled — serving HTTP. Secure-context features (e.g. WebCodecs hardware decode) require HTTPS; ' +
|
|
32
|
+
'configure tls in tapflow.config.json to enable.');
|
|
33
|
+
}
|
|
34
|
+
const server = new RelayServer({ port, uploadsDir, wsBackpressureBytes: config.local.wsBackpressureBytes, trustedProxies: config.local.trustedProxies, corsOrigins, tls });
|
|
35
|
+
await server.start();
|
|
36
|
+
logger.info(`tapflow relay running on port ${port} (${tls ? 'https' : 'http'})`);
|
|
37
|
+
const stopRenewal = provider
|
|
38
|
+
? startCertRenewal(provider, { onRenew: (m) => server.updateTlsContext({ cert: m.cert, key: m.key }) })
|
|
39
|
+
: null;
|
|
40
|
+
// byo-api-token: publish the relay's LAN IP to the domain's A record so teammates just open the URL.
|
|
41
|
+
const stopPublish = config.tls?.mode === 'byo-api-token' && config.tls.publishAddress !== false
|
|
42
|
+
? startAddressPublisher(config.tls)
|
|
43
|
+
: null;
|
|
44
|
+
const shutdown = () => {
|
|
45
|
+
stopRenewal?.();
|
|
46
|
+
stopPublish?.();
|
|
47
|
+
void server.stop().then(() => process.exit(0));
|
|
48
|
+
};
|
|
49
|
+
process.on('SIGTERM', shutdown);
|
|
50
|
+
process.on('SIGINT', shutdown);
|
|
51
|
+
}
|
|
52
|
+
void main().catch((err) => {
|
|
53
|
+
logger.error(`relay failed to start: ${String(err)}`);
|
|
54
|
+
process.exit(1);
|
|
14
55
|
});
|
|
15
|
-
process.on('SIGTERM', () => server.stop().then(() => process.exit(0)));
|
|
16
|
-
process.on('SIGINT', () => server.stop().then(() => process.exit(0)));
|
|
17
56
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;AAEpC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,CAAA;AACtC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;AAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;AAEhD,MAAM,CAAC,MAAM,CAAC,CAAA;AAEd,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tapflowio/relay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "WebSocket relay server for tapflow — NAT traversal, session routing, JWT auth, bundled dashboard",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tapflow",
|
|
@@ -39,19 +39,20 @@
|
|
|
39
39
|
"LICENSE"
|
|
40
40
|
],
|
|
41
41
|
"engines": {
|
|
42
|
-
"node": ">=20"
|
|
42
|
+
"node": ">=20.12.0"
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
+
"acme-client": "^5.4.0",
|
|
48
49
|
"better-sqlite3": "^12.9.0",
|
|
49
50
|
"busboy": "^1.6.0",
|
|
50
51
|
"jsonwebtoken": "^9.0.3",
|
|
51
|
-
"nodemailer": "^8.0.
|
|
52
|
-
"ws": "^8.
|
|
52
|
+
"nodemailer": "^8.0.11",
|
|
53
|
+
"ws": "^8.21.0",
|
|
53
54
|
"zod": "^4.4.3",
|
|
54
|
-
"@tapflowio/agent-core": "0.
|
|
55
|
+
"@tapflowio/agent-core": "0.9.0"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@types/better-sqlite3": "^7.6.13",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import{Z as T,a9 as n,a6 as e,B as b,L as y,ab as _,J as G,I as L,S as E,g as J,an as Q,ao as Z}from"./index-ClAB0eKw.js";import{d as K,S as W,P as X,g as ee,f as se,h as ae,b as te,u as le}from"./build-format-Blzidb1D.js";import{D as U,f as z,a as M,d as V,e as q,S as k,i as D,j as A,g as C,h as c,C as ne}from"./dialog-BuZjQWBQ.js";import{P as re}from"./plus-C0Y4Yk9P.js";import{B as O}from"./badge-Cktrrdvf.js";import{A as ie,c as ce,f as de,g as oe,d as xe,e as ue,b as pe,a as he}from"./alert-dialog-Ci_cWoVo.js";/**
|
|
2
|
+
* @license lucide-react v0.468.0 - ISC
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the ISC license.
|
|
5
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/const me=T("Layers",[["path",{d:"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",key:"zw3jo"}],["path",{d:"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",key:"1wduqc"}],["path",{d:"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",key:"kqbvx6"}]]);/**
|
|
7
|
+
* @license lucide-react v0.468.0 - ISC
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the ISC license.
|
|
10
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
+
*/const fe=T("Package",[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["path",{d:"m3.3 7 7.703 4.734a2 2 0 0 0 1.994 0L20.7 7",key:"yx3hmr"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]]);/**
|
|
12
|
+
* @license lucide-react v0.468.0 - ISC
|
|
13
|
+
*
|
|
14
|
+
* This source code is licensed under the ISC license.
|
|
15
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
16
|
+
*/const ge=T("Upload",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"17 8 12 3 7 8",key:"t8dd8p"}],["line",{x1:"12",x2:"12",y1:"3",y2:"15",key:"widbto"}]]);function je({onSuccess:s,appId:l}){const[u,r]=n.useState(!1),[a,h]=n.useState(null),[d,p]=n.useState("none"),g=n.useRef(null);function f(i){if(i.preventDefault(),!a)return;const o=new FormData;o.append("file",a),d!=="none"&&o.append("status",d),l&&o.append("app_id",String(l));const N=fetch("/api/v1/builds",{method:"POST",credentials:"include",body:o}).then(async x=>{if(!x.ok){const m=await x.json().catch(()=>({}));throw new Error(m.error??"Upload failed. Check the file format.")}s()});_.promise(N,{loading:"Uploading build…",success:"Build uploaded",error:x=>x instanceof Error?x.message:"Failed to upload build"}),r(!1),h(null),p("none")}function v(i){r(i),i||(h(null),p("none"))}return e.jsxs(U,{open:u,onOpenChange:v,children:[e.jsx(z,{asChild:!0,children:e.jsxs(b,{size:"sm",children:[e.jsx(ge,{className:"mr-2 h-4 w-4"}),"Upload build"]})}),e.jsxs(M,{className:"sm:max-w-md",children:[e.jsx(V,{children:e.jsx(q,{children:"Upload build"})}),e.jsxs("form",{onSubmit:f,className:"flex flex-col gap-4 pt-2",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(y,{children:"File"}),e.jsx("div",{className:"flex h-24 cursor-pointer items-center justify-center rounded-md border-2 border-dashed text-sm text-muted-foreground hover:border-primary",onClick:()=>{var i;return(i=g.current)==null?void 0:i.click()},onDragOver:i=>i.preventDefault(),onDrop:i=>{i.preventDefault();const o=i.dataTransfer.files[0];o&&h(o)},children:a?a.name:"Click or drag to upload"}),e.jsx("input",{ref:g,type:"file",accept:".zip,.apk",className:"hidden",onChange:i=>{var o;return h(((o=i.target.files)==null?void 0:o[0])??null)}}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["iOS: ",e.jsx("code",{children:".app.zip"})," (zip the ",e.jsx("code",{children:".app"})," folder after ",e.jsx("code",{children:"xcodebuild -sdk iphonesimulator"}),") · Android: ",e.jsx("code",{children:".apk"})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(y,{children:["Status ",e.jsx("span",{className:"text-muted-foreground",children:"(optional)"})]}),e.jsxs(k,{value:d,onValueChange:p,children:[e.jsx(D,{children:e.jsx(A,{})}),e.jsxs(C,{children:[e.jsx(c,{value:"none",children:"None"}),e.jsx(c,{value:"Backlog",children:"Backlog"}),e.jsx(c,{value:"In Progress",children:"In Progress"}),e.jsx(c,{value:"Done",children:"Done"}),e.jsx(c,{value:"Rejected",children:"Rejected"})]})]})]}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(b,{type:"button",variant:"outline",className:"w-24",onClick:()=>r(!1),children:"Cancel"}),e.jsx(b,{type:"submit",className:"w-24",disabled:!a,children:"Upload"})]})]})]})]})}function w({className:s,...l}){return e.jsx("span",{className:G("font-mono text-xs tabular-nums tracking-tight",s),...l})}function ve({onSuccess:s}){const[l,u]=n.useState(!1),[r,a]=n.useState(""),[h,d]=n.useState(""),[p,g]=n.useState("ios"),[f,v]=n.useState(""),[i,o]=n.useState(!1);async function N(x){x.preventDefault(),v(""),o(!0);try{const m=await K({name:r.trim(),bundle_id_key:h.trim(),platform:p});if(!m){v("Failed to create app");return}if("error"in m){v(m.error);return}u(!1),a(""),d(""),g("ios"),_.success("App created"),s()}catch{_.error("Failed to create app — check your network")}finally{o(!1)}}return e.jsxs(U,{open:l,onOpenChange:u,children:[e.jsx(z,{asChild:!0,children:e.jsxs("button",{className:"flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 text-left text-sm text-muted-foreground hover:bg-accent hover:text-foreground transition-colors",children:[e.jsx(re,{className:"size-3.5 shrink-0"}),e.jsx("span",{children:"Add App"})]})}),e.jsxs(M,{className:"sm:max-w-sm",children:[e.jsx(V,{children:e.jsx(q,{children:"Add App"})}),e.jsxs("form",{onSubmit:N,className:"flex flex-col gap-4 pt-2",children:[e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(y,{htmlFor:"app-name",children:"Name"}),e.jsx(L,{id:"app-name",value:r,onChange:x=>a(x.target.value),placeholder:"My App",required:!0})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(y,{htmlFor:"bundle-id",children:"Bundle ID"}),e.jsx(L,{id:"bundle-id",value:h,onChange:x=>d(x.target.value),placeholder:"com.example.myapp",required:!0})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(y,{htmlFor:"platform",children:"Platform"}),e.jsxs(k,{value:p,onValueChange:x=>g(x),children:[e.jsx(D,{id:"platform",children:e.jsx(A,{})}),e.jsxs(C,{children:[e.jsx(c,{value:"ios",children:"iOS"}),e.jsx(c,{value:"android",children:"Android"}),e.jsx(c,{value:"both",children:"Both"})]})]})]}),f&&e.jsx("p",{className:"text-sm text-destructive",children:f}),e.jsx(b,{type:"submit",disabled:i,className:"w-full",children:i?"Creating…":"Create App"})]})]})]})}function Ne({apps:s,selectedAppId:l,onSelect:u,onAdd:r}){return e.jsxs("aside",{className:"w-64 shrink-0 border-r flex flex-col gap-1 p-3 overflow-y-auto",children:[e.jsx("span",{className:"px-2 pb-1 font-mono text-xs font-medium text-muted-foreground uppercase tracking-wider",children:"Apps"}),s.length===0&&e.jsx("span",{className:"px-2 text-sm text-muted-foreground",children:"No apps yet"}),s.map(a=>e.jsxs("button",{onClick:()=>u(a.id),className:["flex flex-col gap-0.5 rounded-md px-2 py-2 text-left text-sm hover:bg-accent overflow-hidden",a.id===l?"bg-accent font-medium":""].join(" "),children:[e.jsx("span",{className:"truncate",children:a.name}),e.jsx(w,{className:"text-muted-foreground truncate",children:a.bundle_id_key})]},a.id)),e.jsx("div",{className:"mt-1 border-t pt-1",children:e.jsx(ve,{onSuccess:r})})]})}function Se(s){const r=new Date(s).getTime()+6048e5-Date.now();if(r<=0)return{label:"Expired",urgent:!0};const a=Math.floor(r/36e5);return a<1?{label:"< 1 hour left",urgent:!0}:a<24?{label:`Expires in ${a}h`,urgent:a<6}:{label:`Expires in ${Math.floor(a/24)}d`,urgent:!1}}function be({build:s,isLast:l,onNavigate:u,onStatusChange:r}){const[a,h]=n.useState(!1),d=s.status_label==="Done",p=d&&s.completed_at?Se(s.completed_at):null;function g(f){if(f==="Done"){h(!0);return}r(s.id,f==="none"?null:f)}return e.jsxs(e.Fragment,{children:[e.jsx(ie,{open:a,onOpenChange:h,children:e.jsxs(ce,{children:[e.jsxs(de,{children:[e.jsx(oe,{children:"Mark as Done?"}),e.jsx(xe,{children:"Build files will be automatically deleted after 7 days. Reverting the status will cancel the scheduled deletion."})]}),e.jsxs(ue,{children:[e.jsx(pe,{children:"Cancel"}),e.jsx(he,{onClick:()=>{r(s.id,"Done"),h(!1)},children:"Confirm"})]})]})}),e.jsxs("div",{className:["flex items-center gap-3 px-4 py-3",l?"":"border-b"].join(" "),children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs("span",{className:"text-sm font-medium",children:["build ",e.jsx(w,{children:s.build_number??"—"})]}),e.jsx(O,{tone:s.platform==="ios"?"ios":"android",className:"text-xs capitalize",children:s.platform}),s.status_label&&e.jsx(O,{tone:W[s.status_label],className:"text-xs",children:s.status_label})]}),e.jsxs("div",{style:{display:"flex",flexDirection:"row",gap:"14px",marginTop:"0.7rem",alignItems:"center"},className:"text-xs text-muted-foreground",children:[s.uploader&&e.jsxs(e.Fragment,{children:[e.jsx("span",{children:s.uploader}),e.jsx(E,{orientation:"vertical",className:"h-3"})]}),e.jsx(w,{children:new Date(s.uploaded_at).toLocaleDateString()}),p&&e.jsxs(e.Fragment,{children:[e.jsx(E,{orientation:"vertical",className:"h-3"}),e.jsx("span",{className:p.urgent?"text-destructive":"",children:p.label})]})]})]}),e.jsxs(k,{value:s.status_label??"none",onValueChange:g,children:[e.jsx(D,{className:"h-9 w-32 text-xs",children:e.jsx(A,{})}),e.jsxs(C,{children:[e.jsx(c,{value:"none",children:e.jsx("span",{className:"text-muted-foreground",children:"—"})}),e.jsx(c,{value:"Backlog",children:"Backlog"}),e.jsx(c,{value:"In Progress",children:"In Progress"}),e.jsx(c,{value:"Done",children:"Done"}),e.jsx(c,{value:"Rejected",children:"Rejected"})]})]}),e.jsxs(b,{size:"sm",onClick:()=>u(s.id),disabled:d,children:[e.jsx(X,{className:"mr-1.5 h-3.5 w-3.5"}),"Start QA"]})]})]})}function ye({versionName:s,builds:l,isOpen:u,onToggle:r,onNavigate:a,onStatusChange:h}){return e.jsxs("div",{className:"rounded-lg shadow-card-2 overflow-hidden",children:[e.jsxs("button",{className:"flex w-full items-center gap-2 px-4 py-3 text-left hover:bg-accent/50 bg-card",onClick:r,children:[u?e.jsx(ne,{className:"h-4 w-4 shrink-0 text-muted-foreground"}):e.jsx(J,{className:"h-4 w-4 shrink-0 text-muted-foreground"}),e.jsx(w,{className:"font-medium text-sm text-foreground",children:s}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:["(",l.length," build",l.length>1?"s":"",")"]})]}),u&&e.jsx("div",{className:"border-t bg-card",children:l.map((d,p)=>e.jsx(be,{build:d,isLast:p===l.length-1,onNavigate:a,onStatusChange:h},d.id))})]})}function Ie(){const s=Q(),[l,u]=Z(),[r,a]=n.useState([]),[h,d]=n.useState([]),[p,g]=n.useState(""),[f,v]=n.useState("all"),[i,o]=n.useState(!0),[N,x]=n.useState(new Set),m=l.get("appId")?Number(l.get("appId")):null,R=r.find(t=>t.id===m)??null,B=n.useCallback(async()=>{const t=await ee();a(t),!l.get("appId")&&t.length>0&&u({appId:String(t[0].id)},{replace:!0})},[l,u]),I=n.useCallback(async()=>{if(!m){d([]),o(!1);return}o(!0);try{const t=await se({appId:m,search:p,statusFilter:f});d(t),t.length>0&&N.size===0&&x(new Set([t[0].version_name??"Unversioned"]))}finally{o(!1)}},[m,p,f]);n.useEffect(()=>{B()},[]),n.useEffect(()=>{I()},[I]);function H(t){t!==m&&(d([]),x(new Set)),u({appId:String(t)})}function $(t){x(S=>{const j=new Set(S);return j.has(t)?j.delete(t):j.add(t),j})}async function Y(t,S){await le(t,S),d(j=>j.map(P=>P.id===t?{...P,status_label:S}:P))}const F=ae(h);return e.jsxs("div",{className:"flex h-full gap-0",children:[e.jsx(Ne,{apps:r,selectedAppId:m,onSelect:H,onAdd:B}),e.jsxs("main",{className:"flex-1 flex flex-col gap-4 p-4 overflow-y-auto min-w-0",children:[e.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-2",children:[e.jsx("h1",{className:"text-xl font-semibold tracking-display-sm",children:R?R.name:"App Center"}),e.jsx(je,{onSuccess:()=>{B(),I()},appId:m})]}),m?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(te,{placeholder:"Search version…",value:p,onChange:g}),e.jsxs(k,{value:f,onValueChange:v,children:[e.jsx(D,{className:"h-8 w-36",children:e.jsx(A,{placeholder:"Status"})}),e.jsxs(C,{children:[e.jsx(c,{value:"all",children:"All statuses"}),e.jsx(c,{value:"Backlog",children:"Backlog"}),e.jsx(c,{value:"In Progress",children:"In Progress"}),e.jsx(c,{value:"Done",children:"Done"}),e.jsx(c,{value:"Rejected",children:"Rejected"})]})]})]}),i?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"}):F.length===0?e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-2 text-center",children:[e.jsx(fe,{className:"w-8 h-8 text-muted-foreground/40"}),e.jsx("p",{className:"text-sm font-medium",children:"No builds yet"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Upload the first build to get started."})]}):e.jsx("div",{className:"flex flex-col gap-2",children:F.map(({versionName:t,builds:S})=>e.jsx(ye,{versionName:t,builds:S,isOpen:N.has(t),onToggle:()=>$(t),onNavigate:j=>s(`/app-center/build?id=${j}`),onStatusChange:Y},t))})]}):e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-2 text-center",children:[e.jsx(me,{className:"w-8 h-8 text-muted-foreground/40"}),e.jsx("p",{className:"text-sm font-medium",children:"No app selected"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Choose an app from the sidebar to view its builds."})]})]})]})}export{Ie as AppCenter};
|
|
Binary file
|