ccphoto 0.2.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 @@
1
+ {"version":3,"file":"mobile-page.js","sourceRoot":"","sources":["../src/mobile-page.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBA+sBW,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA+zBjC,CAAC;AACT,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function getLocalIPv4(): string | null;
@@ -0,0 +1,30 @@
1
+ import os from "node:os";
2
+ const PREFERRED_INTERFACES = ["en0", "wlan0", "Wi-Fi"];
3
+ export function getLocalIPv4() {
4
+ const interfaces = os.networkInterfaces();
5
+ let fallback = null;
6
+ for (const name of PREFERRED_INTERFACES) {
7
+ const addrs = interfaces[name];
8
+ if (!addrs)
9
+ continue;
10
+ for (const addr of addrs) {
11
+ if (addr.family === "IPv4" && !addr.internal) {
12
+ return addr.address;
13
+ }
14
+ }
15
+ }
16
+ for (const [, addrs] of Object.entries(interfaces)) {
17
+ if (!addrs)
18
+ continue;
19
+ for (const addr of addrs) {
20
+ if (addr.family === "IPv4" && !addr.internal) {
21
+ fallback = addr.address;
22
+ break;
23
+ }
24
+ }
25
+ if (fallback)
26
+ break;
27
+ }
28
+ return fallback;
29
+ }
30
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAEvD,MAAM,UAAU,YAAY;IAC1B,MAAM,UAAU,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;IAE1C,IAAI,QAAQ,GAAkB,IAAI,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,oBAAoB,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC7C,OAAO,IAAI,CAAC,OAAO,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC7C,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;gBACxB,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,QAAQ;YAAE,MAAM;IACtB,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { PhotoMeta, ServerConfig, OutgoingMessage, FrameData, CertPems } from "./types.js";
2
+ export interface UserAction {
3
+ action: string;
4
+ data?: Record<string, unknown>;
5
+ }
6
+ export declare function waitForPhoto(timeoutMs: number): Promise<PhotoMeta | null | UserAction>;
7
+ export declare function startHttpsServer(cfg: ServerConfig, certs: CertPems): Promise<ServerConfig>;
8
+ export declare function getLatestFrame(): FrameData | null;
9
+ export declare function isHttpsServerRunning(): boolean;
10
+ export declare function isServerRunning(): boolean;
11
+ export declare function getServerConfig(): ServerConfig | null;
12
+ export declare function startServer(cfg: ServerConfig): Promise<ServerConfig>;
13
+ export declare function requestPhoto(): void;
14
+ export declare function switchToLiveMode(): void;
15
+ export declare function hasConnectedClients(): boolean;
16
+ export declare function sendToPhone(message: OutgoingMessage): boolean;
17
+ export declare function _resetState(): void;
18
+ export declare function stopServer(): void;
package/dist/server.js ADDED
@@ -0,0 +1,393 @@
1
+ import http from "node:http";
2
+ import https from "node:https";
3
+ import { URL } from "node:url";
4
+ import Busboy from "busboy";
5
+ import { renderMobilePage } from "./mobile-page.js";
6
+ import { validateToken } from "./token.js";
7
+ import { savePhoto, ensureOutputDir } from "./storage.js";
8
+ let server = null;
9
+ let httpsServer = null;
10
+ let config = null;
11
+ const photoListeners = [];
12
+ // Buffer for photos that arrive when no listener is waiting (race condition fix)
13
+ let pendingPhoto = null;
14
+ let latestFrame = null;
15
+ const sseClients = new Set();
16
+ const actionListeners = [];
17
+ let pendingAction = null;
18
+ export function waitForPhoto(timeoutMs) {
19
+ // Check if a photo or action already arrived before we started waiting
20
+ if (pendingPhoto) {
21
+ const meta = pendingPhoto;
22
+ pendingPhoto = null;
23
+ return Promise.resolve(meta);
24
+ }
25
+ if (pendingAction) {
26
+ const action = pendingAction;
27
+ pendingAction = null;
28
+ return Promise.resolve(action);
29
+ }
30
+ return new Promise((resolve) => {
31
+ const timer = setTimeout(() => {
32
+ cleanup();
33
+ resolve(null);
34
+ }, timeoutMs);
35
+ function cleanup() {
36
+ const photoIdx = photoListeners.indexOf(photoListener);
37
+ if (photoIdx !== -1)
38
+ photoListeners.splice(photoIdx, 1);
39
+ const actionIdx = actionListeners.indexOf(actionListener);
40
+ if (actionIdx !== -1)
41
+ actionListeners.splice(actionIdx, 1);
42
+ }
43
+ function photoListener(meta) {
44
+ clearTimeout(timer);
45
+ cleanup();
46
+ resolve(meta);
47
+ }
48
+ function actionListener(action) {
49
+ clearTimeout(timer);
50
+ cleanup();
51
+ resolve(action);
52
+ }
53
+ photoListeners.push(photoListener);
54
+ actionListeners.push(actionListener);
55
+ });
56
+ }
57
+ function notifyPhotoListeners(meta) {
58
+ if (photoListeners.length === 0) {
59
+ pendingPhoto = meta;
60
+ return;
61
+ }
62
+ const listeners = [...photoListeners];
63
+ for (const listener of listeners) {
64
+ listener(meta);
65
+ }
66
+ }
67
+ function notifyActionListeners(action) {
68
+ if (actionListeners.length === 0) {
69
+ pendingAction = action;
70
+ return;
71
+ }
72
+ const listeners = [...actionListeners];
73
+ for (const listener of listeners) {
74
+ listener(action);
75
+ }
76
+ }
77
+ function handleModeSwitch(req, res, cfg) {
78
+ const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
79
+ if (!checkToken(url, cfg.token)) {
80
+ res.writeHead(403, { "Content-Type": "application/json" });
81
+ res.end(JSON.stringify({ error: "Forbidden" }));
82
+ return;
83
+ }
84
+ const chunks = [];
85
+ let totalSize = 0;
86
+ const MAX_BODY_SIZE = 64 * 1024; // 64KB
87
+ req.on("data", (chunk) => {
88
+ totalSize += chunk.length;
89
+ if (totalSize <= MAX_BODY_SIZE) {
90
+ chunks.push(chunk);
91
+ }
92
+ });
93
+ req.on("end", () => {
94
+ if (totalSize > MAX_BODY_SIZE) {
95
+ res.writeHead(413, { "Content-Type": "application/json" });
96
+ res.end(JSON.stringify({ error: "Body too large" }));
97
+ return;
98
+ }
99
+ try {
100
+ const body = JSON.parse(Buffer.concat(chunks).toString());
101
+ const action = { action: body.action ?? "unknown", data: body };
102
+ notifyActionListeners(action);
103
+ res.writeHead(200, {
104
+ "Content-Type": "application/json",
105
+ "Access-Control-Allow-Origin": "*",
106
+ });
107
+ res.end(JSON.stringify({ ok: true }));
108
+ }
109
+ catch {
110
+ res.writeHead(400, { "Content-Type": "application/json" });
111
+ res.end(JSON.stringify({ error: "Invalid JSON" }));
112
+ }
113
+ });
114
+ }
115
+ function checkToken(url, expected) {
116
+ const token = url.searchParams.get("token") ?? "";
117
+ return validateToken(token, expected);
118
+ }
119
+ function handleGetRoot(req, res, cfg) {
120
+ const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
121
+ if (!checkToken(url, cfg.token)) {
122
+ res.writeHead(403, { "Content-Type": "text/plain" });
123
+ res.end("Forbidden");
124
+ return;
125
+ }
126
+ const html = renderMobilePage(cfg.token);
127
+ res.writeHead(200, {
128
+ "Content-Type": "text/html; charset=utf-8",
129
+ "Cache-Control": "no-store",
130
+ });
131
+ res.end(html);
132
+ }
133
+ function handleUpload(req, res, cfg) {
134
+ const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
135
+ if (!checkToken(url, cfg.token)) {
136
+ res.writeHead(403, { "Content-Type": "application/json" });
137
+ res.end(JSON.stringify({ error: "Forbidden" }));
138
+ return;
139
+ }
140
+ const contentType = req.headers["content-type"];
141
+ if (!contentType || !contentType.includes("multipart/form-data")) {
142
+ res.writeHead(400, { "Content-Type": "application/json" });
143
+ res.end(JSON.stringify({ error: "Expected multipart/form-data" }));
144
+ return;
145
+ }
146
+ const busboy = Busboy({ headers: req.headers, limits: { fileSize: 50 * 1024 * 1024 } });
147
+ let saved = false;
148
+ busboy.on("file", (_fieldname, stream, info) => {
149
+ const chunks = [];
150
+ stream.on("data", (chunk) => {
151
+ chunks.push(chunk);
152
+ });
153
+ stream.on("end", () => {
154
+ if (saved)
155
+ return;
156
+ saved = true;
157
+ const data = Buffer.concat(chunks);
158
+ const meta = savePhoto(cfg.outputDir, info.filename, data);
159
+ notifyPhotoListeners(meta);
160
+ process.stderr.write(`\n[ccphoto] Photo saved: ${meta.absolutePath} (${(meta.sizeBytes / 1024).toFixed(0)} KB)\n`);
161
+ res.writeHead(200, {
162
+ "Content-Type": "application/json",
163
+ "Access-Control-Allow-Origin": "*",
164
+ });
165
+ res.end(JSON.stringify({
166
+ filename: meta.filename,
167
+ path: meta.absolutePath,
168
+ size: meta.sizeBytes,
169
+ }));
170
+ });
171
+ });
172
+ busboy.on("error", () => {
173
+ if (!saved) {
174
+ res.writeHead(500, { "Content-Type": "application/json" });
175
+ res.end(JSON.stringify({ error: "Upload failed" }));
176
+ }
177
+ });
178
+ req.pipe(busboy);
179
+ }
180
+ function handleEvents(req, res, cfg) {
181
+ const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
182
+ if (!checkToken(url, cfg.token)) {
183
+ res.writeHead(403, { "Content-Type": "text/plain" });
184
+ res.end("Forbidden");
185
+ return;
186
+ }
187
+ const MAX_SSE_CLIENTS = 10;
188
+ if (sseClients.size >= MAX_SSE_CLIENTS) {
189
+ res.writeHead(503, { "Content-Type": "text/plain" });
190
+ res.end("Too many connections");
191
+ return;
192
+ }
193
+ res.writeHead(200, {
194
+ "Content-Type": "text/event-stream",
195
+ "Cache-Control": "no-cache",
196
+ "Connection": "keep-alive",
197
+ "Access-Control-Allow-Origin": "*",
198
+ });
199
+ res.write("event: connected\ndata: {}\n\n");
200
+ sseClients.add(res);
201
+ req.on("close", () => {
202
+ sseClients.delete(res);
203
+ });
204
+ }
205
+ function handleUnifiedRequest(req, res, cfg) {
206
+ const url = new URL(req.url ?? "/", `${req.socket.encrypted ? 'https' : 'http'}://${req.headers.host}`);
207
+ if (req.method === "OPTIONS") {
208
+ res.writeHead(204, {
209
+ "Access-Control-Allow-Origin": "*",
210
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
211
+ "Access-Control-Allow-Headers": "Content-Type",
212
+ });
213
+ res.end();
214
+ return;
215
+ }
216
+ if (req.method === "GET" && url.pathname === "/") {
217
+ handleGetRoot(req, res, cfg);
218
+ return;
219
+ }
220
+ if (req.method === "GET" && url.pathname === "/health") {
221
+ res.writeHead(200, { "Content-Type": "text/plain" });
222
+ res.end("ok");
223
+ return;
224
+ }
225
+ if (req.method === "POST" && url.pathname === "/upload") {
226
+ handleUpload(req, res, cfg);
227
+ return;
228
+ }
229
+ if (req.method === "POST" && url.pathname === "/frame") {
230
+ handleFrameUpload(req, res, cfg);
231
+ return;
232
+ }
233
+ if (req.method === "GET" && url.pathname === "/events") {
234
+ handleEvents(req, res, cfg);
235
+ return;
236
+ }
237
+ if (req.method === "POST" && url.pathname === "/mode-switch") {
238
+ handleModeSwitch(req, res, cfg);
239
+ return;
240
+ }
241
+ res.writeHead(404, { "Content-Type": "text/plain" });
242
+ res.end("Not Found");
243
+ }
244
+ function handleFrameUpload(req, res, cfg) {
245
+ const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
246
+ if (!checkToken(url, cfg.token)) {
247
+ res.writeHead(403, { "Content-Type": "application/json" });
248
+ res.end(JSON.stringify({ error: "Forbidden" }));
249
+ return;
250
+ }
251
+ const chunks = [];
252
+ let totalSize = 0;
253
+ const MAX_FRAME_SIZE = 2 * 1024 * 1024; // 2MB
254
+ req.on("data", (chunk) => {
255
+ totalSize += chunk.length;
256
+ if (totalSize <= MAX_FRAME_SIZE) {
257
+ chunks.push(chunk);
258
+ }
259
+ });
260
+ req.on("end", () => {
261
+ if (totalSize > MAX_FRAME_SIZE) {
262
+ res.writeHead(413, { "Content-Type": "application/json" });
263
+ res.end(JSON.stringify({ error: "Frame too large" }));
264
+ return;
265
+ }
266
+ const data = Buffer.concat(chunks);
267
+ const w = parseInt(url.searchParams.get("w") ?? "0", 10);
268
+ const h = parseInt(url.searchParams.get("h") ?? "0", 10);
269
+ latestFrame = {
270
+ data,
271
+ timestamp: new Date(),
272
+ width: w,
273
+ height: h,
274
+ mimeType: "image/jpeg",
275
+ };
276
+ res.writeHead(200, {
277
+ "Content-Type": "application/json",
278
+ "Access-Control-Allow-Origin": "*",
279
+ });
280
+ res.end(JSON.stringify({ ok: true, timestamp: latestFrame.timestamp.toISOString() }));
281
+ });
282
+ }
283
+ export async function startHttpsServer(cfg, certs) {
284
+ ensureOutputDir(cfg.outputDir);
285
+ if (httpsServer)
286
+ return config;
287
+ const httpsPort = cfg.httpsPort ?? cfg.port + 1;
288
+ cfg.httpsPort = httpsPort;
289
+ return new Promise((resolve, reject) => {
290
+ const s = https.createServer({ key: certs.key, cert: certs.cert }, (req, res) => handleUnifiedRequest(req, res, cfg));
291
+ s.on("error", (err) => {
292
+ if (err.code === "EADDRINUSE") {
293
+ cfg.httpsPort = (cfg.httpsPort ?? httpsPort) + 1;
294
+ s.listen(cfg.httpsPort, "0.0.0.0");
295
+ }
296
+ else {
297
+ reject(err);
298
+ }
299
+ });
300
+ s.on("listening", () => {
301
+ httpsServer = s;
302
+ config = cfg;
303
+ resolve(cfg);
304
+ });
305
+ s.listen(httpsPort, "0.0.0.0");
306
+ });
307
+ }
308
+ export function getLatestFrame() {
309
+ return latestFrame;
310
+ }
311
+ export function isHttpsServerRunning() {
312
+ return httpsServer !== null;
313
+ }
314
+ export function isServerRunning() {
315
+ return server !== null;
316
+ }
317
+ export function getServerConfig() {
318
+ return config;
319
+ }
320
+ export async function startServer(cfg) {
321
+ if (server)
322
+ return config;
323
+ ensureOutputDir(cfg.outputDir);
324
+ config = cfg;
325
+ return new Promise((resolve, reject) => {
326
+ const s = http.createServer((req, res) => handleUnifiedRequest(req, res, cfg));
327
+ s.on("error", (err) => {
328
+ if (err.code === "EADDRINUSE") {
329
+ cfg.port++;
330
+ s.listen(cfg.port, "0.0.0.0");
331
+ }
332
+ else {
333
+ reject(err);
334
+ }
335
+ });
336
+ s.on("listening", () => {
337
+ server = s;
338
+ config = cfg;
339
+ resolve(cfg);
340
+ });
341
+ s.listen(cfg.port, "0.0.0.0");
342
+ });
343
+ }
344
+ export function requestPhoto() {
345
+ for (const client of sseClients) {
346
+ client.write("event: photo-requested\ndata: {}\n\n");
347
+ }
348
+ }
349
+ export function switchToLiveMode() {
350
+ for (const client of sseClients) {
351
+ client.write("event: switch-to-live\ndata: {}\n\n");
352
+ }
353
+ }
354
+ export function hasConnectedClients() {
355
+ return sseClients.size > 0;
356
+ }
357
+ export function sendToPhone(message) {
358
+ if (sseClients.size === 0)
359
+ return false;
360
+ const payload = JSON.stringify(message);
361
+ for (const client of sseClients) {
362
+ client.write(`event: content-push\ndata: ${payload}\n\n`);
363
+ }
364
+ return true;
365
+ }
366
+ export function _resetState() {
367
+ pendingPhoto = null;
368
+ pendingAction = null;
369
+ latestFrame = null;
370
+ photoListeners.length = 0;
371
+ actionListeners.length = 0;
372
+ for (const client of sseClients) {
373
+ client.end();
374
+ }
375
+ sseClients.clear();
376
+ }
377
+ export function stopServer() {
378
+ if (httpsServer) {
379
+ httpsServer.close();
380
+ httpsServer = null;
381
+ }
382
+ latestFrame = null;
383
+ if (server) {
384
+ for (const client of sseClients) {
385
+ client.end();
386
+ }
387
+ sseClients.clear();
388
+ server.close();
389
+ server = null;
390
+ config = null;
391
+ }
392
+ }
393
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { PhotoMeta } from "./types.js";
2
+ export declare function ensureOutputDir(dir: string): void;
3
+ export declare function savePhoto(dir: string, originalName: string, data: Buffer): PhotoMeta;
4
+ export declare function listPhotos(dir: string): PhotoMeta[];
5
+ export declare function getLatestPhoto(dir: string): PhotoMeta | null;
6
+ export declare function getPhotoByFilename(dir: string, filename: string): PhotoMeta | null;
@@ -0,0 +1,109 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ const IMAGE_EXTENSIONS = new Set([
4
+ ".jpg",
5
+ ".jpeg",
6
+ ".png",
7
+ ".gif",
8
+ ".webp",
9
+ ".heic",
10
+ ".heif",
11
+ ]);
12
+ const MIME_TYPES = {
13
+ ".jpg": "image/jpeg",
14
+ ".jpeg": "image/jpeg",
15
+ ".png": "image/png",
16
+ ".gif": "image/gif",
17
+ ".webp": "image/webp",
18
+ ".heic": "image/heic",
19
+ ".heif": "image/heif",
20
+ };
21
+ function mimeFromExt(ext) {
22
+ return MIME_TYPES[ext.toLowerCase()] ?? "application/octet-stream";
23
+ }
24
+ function formatTimestamp(date) {
25
+ const y = date.getFullYear();
26
+ const mo = String(date.getMonth() + 1).padStart(2, "0");
27
+ const d = String(date.getDate()).padStart(2, "0");
28
+ const h = String(date.getHours()).padStart(2, "0");
29
+ const mi = String(date.getMinutes()).padStart(2, "0");
30
+ const s = String(date.getSeconds()).padStart(2, "0");
31
+ return `${y}-${mo}-${d}-${h}${mi}${s}`;
32
+ }
33
+ export function ensureOutputDir(dir) {
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ }
36
+ export function savePhoto(dir, originalName, data) {
37
+ let ext = path.extname(originalName).toLowerCase();
38
+ if (!ext || !IMAGE_EXTENSIONS.has(ext)) {
39
+ ext = ".jpg";
40
+ }
41
+ const timestamp = new Date();
42
+ const base = `photo-${formatTimestamp(timestamp)}`;
43
+ let filename = `${base}${ext}`;
44
+ let absolutePath = path.join(dir, filename);
45
+ let suffix = 0;
46
+ while (fs.existsSync(absolutePath)) {
47
+ suffix++;
48
+ filename = `${base}-${suffix}${ext}`;
49
+ absolutePath = path.join(dir, filename);
50
+ }
51
+ fs.writeFileSync(absolutePath, data);
52
+ return {
53
+ filename,
54
+ absolutePath,
55
+ timestamp,
56
+ sizeBytes: data.length,
57
+ mimeType: mimeFromExt(ext),
58
+ };
59
+ }
60
+ export function listPhotos(dir) {
61
+ if (!fs.existsSync(dir)) {
62
+ return [];
63
+ }
64
+ const entries = fs.readdirSync(dir);
65
+ const photos = [];
66
+ for (const entry of entries) {
67
+ const ext = path.extname(entry).toLowerCase();
68
+ if (!IMAGE_EXTENSIONS.has(ext))
69
+ continue;
70
+ const absolutePath = path.join(dir, entry);
71
+ const stat = fs.statSync(absolutePath);
72
+ if (!stat.isFile())
73
+ continue;
74
+ photos.push({
75
+ filename: entry,
76
+ absolutePath,
77
+ timestamp: stat.mtime,
78
+ sizeBytes: stat.size,
79
+ mimeType: mimeFromExt(ext),
80
+ });
81
+ }
82
+ photos.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
83
+ return photos;
84
+ }
85
+ export function getLatestPhoto(dir) {
86
+ const photos = listPhotos(dir);
87
+ return photos.length > 0 ? photos[0] : null;
88
+ }
89
+ export function getPhotoByFilename(dir, filename) {
90
+ // Prevent path traversal
91
+ const safeName = path.basename(filename);
92
+ const absolutePath = path.join(dir, safeName);
93
+ if (!fs.existsSync(absolutePath))
94
+ return null;
95
+ const ext = path.extname(safeName).toLowerCase();
96
+ if (!IMAGE_EXTENSIONS.has(ext))
97
+ return null;
98
+ const stat = fs.statSync(absolutePath);
99
+ if (!stat.isFile())
100
+ return null;
101
+ return {
102
+ filename: safeName,
103
+ absolutePath,
104
+ timestamp: stat.mtime,
105
+ sizeBytes: stat.size,
106
+ mimeType: mimeFromExt(ext),
107
+ };
108
+ }
109
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function generateToken(): string;
2
+ export declare function validateToken(provided: string, expected: string): boolean;
package/dist/token.js ADDED
@@ -0,0 +1,13 @@
1
+ import crypto from "node:crypto";
2
+ export function generateToken() {
3
+ return crypto.randomBytes(16).toString("hex");
4
+ }
5
+ export function validateToken(provided, expected) {
6
+ if (provided.length !== expected.length) {
7
+ return false;
8
+ }
9
+ const a = Buffer.from(provided, "utf-8");
10
+ const b = Buffer.from(expected, "utf-8");
11
+ return crypto.timingSafeEqual(a, b);
12
+ }
13
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,QAAgB;IAC9D,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAEzC,OAAO,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,31 @@
1
+ export interface PhotoMeta {
2
+ filename: string;
3
+ absolutePath: string;
4
+ timestamp: Date;
5
+ sizeBytes: number;
6
+ mimeType: string;
7
+ }
8
+ export interface ServerConfig {
9
+ port: number;
10
+ outputDir: string;
11
+ token: string;
12
+ host: string;
13
+ httpsPort?: number;
14
+ }
15
+ export interface OutgoingMessage {
16
+ text?: string;
17
+ imageData?: string;
18
+ mimeType?: string;
19
+ speak?: boolean;
20
+ }
21
+ export interface FrameData {
22
+ data: Buffer;
23
+ timestamp: Date;
24
+ width: number;
25
+ height: number;
26
+ mimeType: string;
27
+ }
28
+ export interface CertPems {
29
+ key: string;
30
+ cert: string;
31
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}