fwdcast 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.
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.scanDirectory = scanDirectory;
37
+ exports.calculateScanResult = calculateScanResult;
38
+ exports.scanDirectoryShallow = scanDirectoryShallow;
39
+ const fs = __importStar(require("fs/promises"));
40
+ const path = __importStar(require("path"));
41
+ /**
42
+ * Recursively scans a directory and returns all entries.
43
+ * Symlinks are skipped.
44
+ *
45
+ * @param dirPath - The directory path to scan
46
+ * @param basePath - The base path for calculating relative paths (defaults to dirPath)
47
+ * @returns Array of DirectoryEntry objects
48
+ */
49
+ async function scanDirectory(dirPath, basePath) {
50
+ const resolvedPath = path.resolve(dirPath);
51
+ const resolvedBase = basePath ? path.resolve(basePath) : resolvedPath;
52
+ const entries = [];
53
+ const items = await fs.readdir(resolvedPath, { withFileTypes: true });
54
+ for (const item of items) {
55
+ const absolutePath = path.join(resolvedPath, item.name);
56
+ // Skip symlinks as per requirements
57
+ if (item.isSymbolicLink()) {
58
+ continue;
59
+ }
60
+ const stat = await fs.stat(absolutePath);
61
+ const relativePath = path.relative(resolvedBase, absolutePath);
62
+ const entry = {
63
+ name: item.name,
64
+ relativePath,
65
+ absolutePath,
66
+ isDirectory: item.isDirectory(),
67
+ size: item.isDirectory() ? 0 : stat.size,
68
+ modifiedAt: stat.mtime,
69
+ };
70
+ entries.push(entry);
71
+ // Recursively scan subdirectories
72
+ if (item.isDirectory()) {
73
+ const subEntries = await scanDirectory(absolutePath, resolvedBase);
74
+ entries.push(...subEntries);
75
+ }
76
+ }
77
+ return entries;
78
+ }
79
+ /**
80
+ * Calculates the total size and counts from directory entries.
81
+ *
82
+ * @param entries - Array of DirectoryEntry objects
83
+ * @returns ScanResult with entries, totalSize, fileCount, and directoryCount
84
+ */
85
+ function calculateScanResult(entries) {
86
+ let totalSize = 0;
87
+ let fileCount = 0;
88
+ let directoryCount = 0;
89
+ for (const entry of entries) {
90
+ if (entry.isDirectory) {
91
+ directoryCount++;
92
+ }
93
+ else {
94
+ fileCount++;
95
+ totalSize += entry.size;
96
+ }
97
+ }
98
+ return {
99
+ entries,
100
+ totalSize,
101
+ fileCount,
102
+ directoryCount,
103
+ };
104
+ }
105
+ /**
106
+ * Scans only the immediate children of a directory (non-recursive).
107
+ * Used for dynamic directory listings.
108
+ *
109
+ * @param dirPath - The directory path to scan
110
+ * @param basePath - The base path for calculating relative paths
111
+ * @returns Array of DirectoryEntry objects for immediate children only
112
+ */
113
+ async function scanDirectoryShallow(dirPath, basePath) {
114
+ const resolvedPath = path.resolve(dirPath);
115
+ const resolvedBase = path.resolve(basePath);
116
+ const entries = [];
117
+ const items = await fs.readdir(resolvedPath, { withFileTypes: true });
118
+ for (const item of items) {
119
+ const absolutePath = path.join(resolvedPath, item.name);
120
+ // Skip symlinks as per requirements
121
+ if (item.isSymbolicLink()) {
122
+ continue;
123
+ }
124
+ const stat = await fs.stat(absolutePath);
125
+ const relativePath = path.relative(resolvedBase, absolutePath);
126
+ const entry = {
127
+ name: item.name,
128
+ relativePath,
129
+ absolutePath,
130
+ isDirectory: item.isDirectory(),
131
+ size: item.isDirectory() ? 0 : stat.size,
132
+ modifiedAt: stat.mtime,
133
+ };
134
+ entries.push(entry);
135
+ }
136
+ return entries;
137
+ }
138
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,sCAwCC;AAQD,kDAoBC;AAUD,oDAkCC;AAjJD,gDAAkC;AAClC,2CAA6B;AAwB7B;;;;;;;GAOG;AACI,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,QAAiB;IAEjB,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IACtE,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAExD,oCAAoC;QACpC,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,KAAK,GAAmB;YAC5B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,YAAY;YACZ,YAAY;YACZ,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;YAC/B,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;YACxC,UAAU,EAAE,IAAI,CAAC,KAAK;SACvB,CAAC;QAEF,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEpB,kCAAkC;QAClC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,OAAyB;IAC3D,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACtB,cAAc,EAAE,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,SAAS,EAAE,CAAC;YACZ,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO;QACP,SAAS;QACT,SAAS;QACT,cAAc;KACf,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,oBAAoB,CACxC,OAAe,EACf,QAAgB;IAEhB,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAExD,oCAAoC;QACpC,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,KAAK,GAAmB;YAC5B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,YAAY;YACZ,YAAY;YACZ,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;YAC/B,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;YACxC,UAAU,EAAE,IAAI,CAAC,KAAK;SACvB,CAAC;QAEF,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Tunnel Client Module
3
+ *
4
+ * Handles WebSocket connection to the relay server, message handling,
5
+ * and file streaming for the fwdcast CLI.
6
+ *
7
+ * Requirements: 1.5, 1.6, 3.1, 3.2, 3.6, 5.1, 5.3, 5.4, 5.5
8
+ */
9
+ import { DirectoryEntry } from './scanner';
10
+ /**
11
+ * Configuration for the tunnel client
12
+ */
13
+ export interface TunnelClientConfig {
14
+ relayUrl: string;
15
+ basePath: string;
16
+ entries: DirectoryEntry[];
17
+ expiresAt: number;
18
+ onUrl?: (url: string) => void;
19
+ onExpired?: () => void;
20
+ onDisconnect?: () => void;
21
+ onError?: (error: Error) => void;
22
+ }
23
+ /**
24
+ * Result of a successful registration
25
+ */
26
+ export interface RegistrationResult {
27
+ sessionId: string;
28
+ url: string;
29
+ }
30
+ /**
31
+ * TunnelClient manages the WebSocket connection to the relay server
32
+ * and handles incoming requests by serving files or directory listings.
33
+ */
34
+ export declare class TunnelClient {
35
+ private ws;
36
+ private config;
37
+ private connected;
38
+ private sessionId;
39
+ private registrationPromise;
40
+ constructor(config: TunnelClientConfig);
41
+ /**
42
+ * Connect to the relay server and register the session.
43
+ * Returns the public URL for the shared directory.
44
+ *
45
+ * Requirements: 1.5, 1.6, 5.1
46
+ */
47
+ connect(): Promise<RegistrationResult>;
48
+ /**
49
+ * Disconnect from the relay server
50
+ */
51
+ disconnect(): void;
52
+ /**
53
+ * Check if the client is connected
54
+ */
55
+ isConnected(): boolean;
56
+ /**
57
+ * Send the register message to the relay server
58
+ * Requirements: 5.1
59
+ */
60
+ private sendRegisterMessage;
61
+ /**
62
+ * Handle incoming WebSocket messages
63
+ */
64
+ private handleMessage;
65
+ /**
66
+ * Handle registration response from relay
67
+ * Requirements: 1.6
68
+ */
69
+ private handleRegistered;
70
+ /**
71
+ * Handle incoming request from relay
72
+ * Routes to file server or directory listing
73
+ *
74
+ * Requirements: 3.1, 3.2, 5.3, 5.4, 5.5
75
+ */
76
+ private handleRequest;
77
+ /**
78
+ * Handle session expired message
79
+ */
80
+ private handleExpired;
81
+ /**
82
+ * Serve a ZIP download of a directory
83
+ */
84
+ private serveZipDownload;
85
+ /**
86
+ * Serve a directory listing as HTML
87
+ * Requirements: 3.5
88
+ *
89
+ * Dynamically scans the directory on each request to reflect
90
+ * any files added/removed since the session started.
91
+ */
92
+ private serveDirectoryListing;
93
+ /**
94
+ * Stream a file to the relay
95
+ * Requirements: 3.6
96
+ */
97
+ private serveFile;
98
+ /**
99
+ * Stream file contents in chunks
100
+ * Requirements: 3.6, 5.4, 5.5
101
+ */
102
+ private streamFile;
103
+ /**
104
+ * Send an error response
105
+ */
106
+ private sendErrorResponse;
107
+ /**
108
+ * Send a response message
109
+ * Requirements: 5.3
110
+ */
111
+ sendResponse(id: string, status: number, headers: Record<string, string>): void;
112
+ /**
113
+ * Send a data message with base64 encoded chunk
114
+ * Requirements: 5.4
115
+ */
116
+ sendData(id: string, chunk: Buffer): void;
117
+ /**
118
+ * Send an end message
119
+ * Requirements: 5.5
120
+ */
121
+ sendEnd(id: string): void;
122
+ /**
123
+ * Send a message through the WebSocket
124
+ */
125
+ private send;
126
+ /**
127
+ * Normalize a request path
128
+ */
129
+ private normalizePath;
130
+ /**
131
+ * Get the content type for a file based on its extension
132
+ */
133
+ private getContentType;
134
+ }
135
+ /**
136
+ * Create and connect a tunnel client
137
+ * Convenience function for simple usage
138
+ */
139
+ export declare function createTunnelClient(config: TunnelClientConfig): Promise<{
140
+ client: TunnelClient;
141
+ result: RegistrationResult;
142
+ }>;
143
+ //# sourceMappingURL=tunnel-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel-client.d.ts","sourceRoot":"","sources":["../src/tunnel-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyBH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAOD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,mBAAmB,CAGX;gBAEJ,MAAM,EAAE,kBAAkB;IAItC;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC,kBAAkB,CAAC;IA6C5C;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAQ3B;;OAEG;IACH,OAAO,CAAC,aAAa;IAkBrB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;;;;OAKG;YACW,aAAa;IA6C3B;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;OAEG;YACW,gBAAgB;IA4C9B;;;;;;OAMG;YACW,qBAAqB;IA2BnC;;;OAGG;YACW,SAAS;IAwBvB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAwBlB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;;OAGG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAK/E;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzC;;;OAGG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKzB;;OAEG;IACH,OAAO,CAAC,IAAI;IAMZ;;OAEG;IACH,OAAO,CAAC,aAAa;IAQrB;;OAEG;IACH,OAAO,CAAC,cAAc;CAIvB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAI/D"}