@superdangerous/app-framework 4.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/LICENSE +21 -0
- package/README.md +652 -0
- package/dist/api/logsRouter.d.ts +20 -0
- package/dist/api/logsRouter.d.ts.map +1 -0
- package/dist/api/logsRouter.js +515 -0
- package/dist/api/logsRouter.js.map +1 -0
- package/dist/cli/dev-server.d.ts +7 -0
- package/dist/cli/dev-server.d.ts.map +1 -0
- package/dist/cli/dev-server.js +640 -0
- package/dist/cli/dev-server.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +26 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/StandardServer.d.ts +129 -0
- package/dist/core/StandardServer.d.ts.map +1 -0
- package/dist/core/StandardServer.js +453 -0
- package/dist/core/StandardServer.js.map +1 -0
- package/dist/core/apiResponse.d.ts +69 -0
- package/dist/core/apiResponse.d.ts.map +1 -0
- package/dist/core/apiResponse.js +127 -0
- package/dist/core/apiResponse.js.map +1 -0
- package/dist/core/healthCheck.d.ts +160 -0
- package/dist/core/healthCheck.d.ts.map +1 -0
- package/dist/core/healthCheck.js +398 -0
- package/dist/core/healthCheck.js.map +1 -0
- package/dist/core/index.d.ts +40 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +40 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +117 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +826 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/portUtils.d.ts +71 -0
- package/dist/core/portUtils.d.ts.map +1 -0
- package/dist/core/portUtils.js +240 -0
- package/dist/core/portUtils.js.map +1 -0
- package/dist/core/storageService.d.ts +119 -0
- package/dist/core/storageService.d.ts.map +1 -0
- package/dist/core/storageService.js +405 -0
- package/dist/core/storageService.js.map +1 -0
- package/dist/desktop/bundler.d.ts +40 -0
- package/dist/desktop/bundler.d.ts.map +1 -0
- package/dist/desktop/bundler.js +176 -0
- package/dist/desktop/bundler.js.map +1 -0
- package/dist/desktop/index.d.ts +25 -0
- package/dist/desktop/index.d.ts.map +1 -0
- package/dist/desktop/index.js +15 -0
- package/dist/desktop/index.js.map +1 -0
- package/dist/desktop/native-modules.d.ts +66 -0
- package/dist/desktop/native-modules.d.ts.map +1 -0
- package/dist/desktop/native-modules.js +200 -0
- package/dist/desktop/native-modules.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/LogCategories.d.ts +87 -0
- package/dist/logging/LogCategories.d.ts.map +1 -0
- package/dist/logging/LogCategories.js +205 -0
- package/dist/logging/LogCategories.js.map +1 -0
- package/dist/middleware/aiErrorHandler.d.ts +31 -0
- package/dist/middleware/aiErrorHandler.d.ts.map +1 -0
- package/dist/middleware/aiErrorHandler.js +181 -0
- package/dist/middleware/aiErrorHandler.js.map +1 -0
- package/dist/middleware/auth.d.ts +101 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +230 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/cors.d.ts +56 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +123 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +13 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +85 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/middleware/fileUpload.d.ts +62 -0
- package/dist/middleware/fileUpload.d.ts.map +1 -0
- package/dist/middleware/fileUpload.js +175 -0
- package/dist/middleware/fileUpload.js.map +1 -0
- package/dist/middleware/health.d.ts +48 -0
- package/dist/middleware/health.d.ts.map +1 -0
- package/dist/middleware/health.js +143 -0
- package/dist/middleware/health.js.map +1 -0
- package/dist/middleware/index.d.ts +20 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +18 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/openapi.d.ts +64 -0
- package/dist/middleware/openapi.d.ts.map +1 -0
- package/dist/middleware/openapi.js +258 -0
- package/dist/middleware/openapi.js.map +1 -0
- package/dist/middleware/requestLogging.d.ts +22 -0
- package/dist/middleware/requestLogging.d.ts.map +1 -0
- package/dist/middleware/requestLogging.js +61 -0
- package/dist/middleware/requestLogging.js.map +1 -0
- package/dist/middleware/session.d.ts +84 -0
- package/dist/middleware/session.d.ts.map +1 -0
- package/dist/middleware/session.js +189 -0
- package/dist/middleware/session.js.map +1 -0
- package/dist/middleware/validation.d.ts +1337 -0
- package/dist/middleware/validation.d.ts.map +1 -0
- package/dist/middleware/validation.js +483 -0
- package/dist/middleware/validation.js.map +1 -0
- package/dist/services/aiService.d.ts +180 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +547 -0
- package/dist/services/aiService.js.map +1 -0
- package/dist/services/conversationStorage.d.ts +38 -0
- package/dist/services/conversationStorage.d.ts.map +1 -0
- package/dist/services/conversationStorage.js +158 -0
- package/dist/services/conversationStorage.js.map +1 -0
- package/dist/services/crossPlatformBuffer.d.ts +84 -0
- package/dist/services/crossPlatformBuffer.d.ts.map +1 -0
- package/dist/services/crossPlatformBuffer.js +246 -0
- package/dist/services/crossPlatformBuffer.js.map +1 -0
- package/dist/services/index.d.ts +17 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +18 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/networkService.d.ts +81 -0
- package/dist/services/networkService.d.ts.map +1 -0
- package/dist/services/networkService.js +268 -0
- package/dist/services/networkService.js.map +1 -0
- package/dist/services/queueService.d.ts +112 -0
- package/dist/services/queueService.d.ts.map +1 -0
- package/dist/services/queueService.js +338 -0
- package/dist/services/queueService.js.map +1 -0
- package/dist/services/settingsService.d.ts +135 -0
- package/dist/services/settingsService.d.ts.map +1 -0
- package/dist/services/settingsService.js +425 -0
- package/dist/services/settingsService.js.map +1 -0
- package/dist/services/systemMonitor.d.ts +208 -0
- package/dist/services/systemMonitor.d.ts.map +1 -0
- package/dist/services/systemMonitor.js +693 -0
- package/dist/services/systemMonitor.js.map +1 -0
- package/dist/services/updateService.d.ts +78 -0
- package/dist/services/updateService.d.ts.map +1 -0
- package/dist/services/updateService.js +252 -0
- package/dist/services/updateService.js.map +1 -0
- package/dist/services/websocketEvents.d.ts +372 -0
- package/dist/services/websocketEvents.d.ts.map +1 -0
- package/dist/services/websocketEvents.js +338 -0
- package/dist/services/websocketEvents.js.map +1 -0
- package/dist/services/websocketServer.d.ts +80 -0
- package/dist/services/websocketServer.d.ts.map +1 -0
- package/dist/services/websocketServer.js +299 -0
- package/dist/services/websocketServer.js.map +1 -0
- package/dist/settings/SettingsSchema.d.ts +151 -0
- package/dist/settings/SettingsSchema.d.ts.map +1 -0
- package/dist/settings/SettingsSchema.js +424 -0
- package/dist/settings/SettingsSchema.js.map +1 -0
- package/dist/testing/TestServer.d.ts +69 -0
- package/dist/testing/TestServer.d.ts.map +1 -0
- package/dist/testing/TestServer.js +250 -0
- package/dist/testing/TestServer.js.map +1 -0
- package/dist/types/index.d.ts +137 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/appPaths.d.ts +74 -0
- package/dist/utils/appPaths.d.ts.map +1 -0
- package/dist/utils/appPaths.js +162 -0
- package/dist/utils/appPaths.js.map +1 -0
- package/dist/utils/fs-utils.d.ts +50 -0
- package/dist/utils/fs-utils.d.ts.map +1 -0
- package/dist/utils/fs-utils.js +114 -0
- package/dist/utils/fs-utils.js.map +1 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/standardConfig.d.ts +61 -0
- package/dist/utils/standardConfig.d.ts.map +1 -0
- package/dist/utils/standardConfig.js +109 -0
- package/dist/utils/standardConfig.js.map +1 -0
- package/dist/utils/startupBanner.d.ts +34 -0
- package/dist/utils/startupBanner.d.ts.map +1 -0
- package/dist/utils/startupBanner.js +169 -0
- package/dist/utils/startupBanner.js.map +1 -0
- package/dist/utils/startupLogger.d.ts +45 -0
- package/dist/utils/startupLogger.d.ts.map +1 -0
- package/dist/utils/startupLogger.js +200 -0
- package/dist/utils/startupLogger.js.map +1 -0
- package/package.json +151 -0
- package/src/api/logsRouter.ts +600 -0
- package/src/cli/dev-server.ts +803 -0
- package/src/cli/index.ts +31 -0
- package/src/core/StandardServer.ts +587 -0
- package/src/core/apiResponse.ts +202 -0
- package/src/core/healthCheck.ts +565 -0
- package/src/core/index.ts +80 -0
- package/src/core/logger.ts +1092 -0
- package/src/core/portUtils.ts +319 -0
- package/src/core/storageService.ts +595 -0
- package/src/desktop/bundler.ts +271 -0
- package/src/desktop/index.ts +18 -0
- package/src/desktop/native-modules.ts +289 -0
- package/src/index.ts +142 -0
- package/src/logging/LogCategories.ts +302 -0
- package/src/middleware/aiErrorHandler.ts +278 -0
- package/src/middleware/auth.ts +329 -0
- package/src/middleware/cors.ts +187 -0
- package/src/middleware/errorHandler.ts +103 -0
- package/src/middleware/fileUpload.ts +252 -0
- package/src/middleware/health.ts +206 -0
- package/src/middleware/index.ts +71 -0
- package/src/middleware/openapi.ts +305 -0
- package/src/middleware/requestLogging.ts +92 -0
- package/src/middleware/session.ts +238 -0
- package/src/middleware/validation.ts +603 -0
- package/src/services/aiService.ts +789 -0
- package/src/services/conversationStorage.ts +232 -0
- package/src/services/crossPlatformBuffer.ts +341 -0
- package/src/services/index.ts +47 -0
- package/src/services/networkService.ts +351 -0
- package/src/services/queueService.ts +446 -0
- package/src/services/settingsService.ts +549 -0
- package/src/services/systemMonitor.ts +936 -0
- package/src/services/updateService.ts +334 -0
- package/src/services/websocketEvents.ts +409 -0
- package/src/services/websocketServer.ts +394 -0
- package/src/settings/SettingsSchema.ts +664 -0
- package/src/testing/TestServer.ts +312 -0
- package/src/types/index.ts +154 -0
- package/src/utils/appPaths.ts +196 -0
- package/src/utils/fs-utils.ts +130 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/standardConfig.ts +178 -0
- package/src/utils/startupBanner.ts +287 -0
- package/src/utils/startupLogger.ts +268 -0
- package/ui/dist/index.d.mts +1221 -0
- package/ui/dist/index.d.ts +1221 -0
- package/ui/dist/index.js +73 -0
- package/ui/dist/index.js.map +1 -0
- package/ui/dist/index.mjs +73 -0
- package/ui/dist/index.mjs.map +1 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Service
|
|
3
|
+
* Unified service for secure file operations, user uploads, and internal data storage
|
|
4
|
+
* Provides path sanitization, validation, and consistent file handling
|
|
5
|
+
*/
|
|
6
|
+
import path from "path";
|
|
7
|
+
import * as fsUtils from "../utils/fs-utils.js";
|
|
8
|
+
import { createWriteStream } from "fs";
|
|
9
|
+
import { createLogger } from "./index.js";
|
|
10
|
+
import crypto from "crypto";
|
|
11
|
+
let logger; // Will be initialized when needed
|
|
12
|
+
function ensureLogger() {
|
|
13
|
+
if (!logger) {
|
|
14
|
+
logger = createLogger("StorageService");
|
|
15
|
+
}
|
|
16
|
+
return logger;
|
|
17
|
+
}
|
|
18
|
+
// Define safe base directories
|
|
19
|
+
const DATA_DIR = path.join(process.cwd(), "data");
|
|
20
|
+
const BASE_DIRS = {
|
|
21
|
+
attachments: path.join(DATA_DIR, "uploads", "attachments"),
|
|
22
|
+
data: DATA_DIR,
|
|
23
|
+
templates: path.join(DATA_DIR, "templates"),
|
|
24
|
+
uploads: path.join(DATA_DIR, "uploads"),
|
|
25
|
+
logs: path.join(DATA_DIR, "logs"),
|
|
26
|
+
config: path.join(DATA_DIR, "config"),
|
|
27
|
+
};
|
|
28
|
+
export class StorageService {
|
|
29
|
+
initialized = false;
|
|
30
|
+
maxFileSize = 100 * 1024 * 1024; // 100MB
|
|
31
|
+
async initialize() {
|
|
32
|
+
if (this.initialized)
|
|
33
|
+
return;
|
|
34
|
+
try {
|
|
35
|
+
// Ensure all base directories exist
|
|
36
|
+
for (const dir of Object.values(BASE_DIRS)) {
|
|
37
|
+
await fsUtils.ensureDir(dir);
|
|
38
|
+
}
|
|
39
|
+
// Ensure .gitignore exists in attachments and data directories
|
|
40
|
+
const gitignoreContent = "*\n!.gitignore\n";
|
|
41
|
+
await fsUtils.writeFile(path.join(BASE_DIRS.attachments, ".gitignore"), gitignoreContent);
|
|
42
|
+
await fsUtils.writeFile(path.join(BASE_DIRS.data, ".gitignore"), gitignoreContent);
|
|
43
|
+
this.initialized = true;
|
|
44
|
+
// Storage service initialized
|
|
45
|
+
}
|
|
46
|
+
catch (_error) {
|
|
47
|
+
ensureLogger().error("Failed to initialize storage service:", _error);
|
|
48
|
+
throw _error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Sanitize a filename to prevent path traversal attacks
|
|
53
|
+
*/
|
|
54
|
+
sanitizeFilename(filename) {
|
|
55
|
+
if (!filename || typeof filename !== "string") {
|
|
56
|
+
throw new Error("Invalid filename provided");
|
|
57
|
+
}
|
|
58
|
+
// Remove any path components and keep only the basename
|
|
59
|
+
let sanitized = path.basename(filename);
|
|
60
|
+
// Remove any remaining special characters that could cause issues
|
|
61
|
+
sanitized = sanitized.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
62
|
+
// Ensure the filename is not empty after sanitization
|
|
63
|
+
if (!sanitized || sanitized === "." || sanitized === "..") {
|
|
64
|
+
sanitized = `file_${Date.now()}`;
|
|
65
|
+
}
|
|
66
|
+
// Limit filename length
|
|
67
|
+
if (sanitized.length > 255) {
|
|
68
|
+
const ext = path.extname(sanitized);
|
|
69
|
+
const name = path.basename(sanitized, ext);
|
|
70
|
+
sanitized = name.substring(0, 255 - ext.length) + ext;
|
|
71
|
+
}
|
|
72
|
+
return sanitized;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Validate that a path is within the allowed base directory
|
|
76
|
+
*/
|
|
77
|
+
isPathSafe(filePath, baseDir) {
|
|
78
|
+
try {
|
|
79
|
+
const resolvedPath = path.resolve(filePath);
|
|
80
|
+
const resolvedBase = path.resolve(baseDir);
|
|
81
|
+
return resolvedPath.startsWith(resolvedBase);
|
|
82
|
+
}
|
|
83
|
+
catch (_error) {
|
|
84
|
+
ensureLogger().error("Error validating path safety:", _error);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get the full safe path for a file
|
|
90
|
+
*/
|
|
91
|
+
getSafePath(filename, category = "data") {
|
|
92
|
+
const sanitizedName = this.sanitizeFilename(filename);
|
|
93
|
+
const baseDir = BASE_DIRS[category];
|
|
94
|
+
const fullPath = path.join(baseDir, sanitizedName);
|
|
95
|
+
if (!this.isPathSafe(fullPath, baseDir)) {
|
|
96
|
+
throw new Error("Invalid file path detected");
|
|
97
|
+
}
|
|
98
|
+
return fullPath;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Save a file securely
|
|
102
|
+
*/
|
|
103
|
+
async saveFile(content, filename, category = "data", options = {}) {
|
|
104
|
+
await this.initialize();
|
|
105
|
+
const safePath = this.getSafePath(filename, category);
|
|
106
|
+
// Check if file exists and handle accordingly
|
|
107
|
+
if (await fsUtils.pathExists(safePath)) {
|
|
108
|
+
if (!options.overwrite) {
|
|
109
|
+
throw new Error(`File already exists: ${filename}`);
|
|
110
|
+
}
|
|
111
|
+
if (options.createBackup) {
|
|
112
|
+
const backupPath = `${safePath}.backup.${Date.now()}`;
|
|
113
|
+
await fsUtils.copy(safePath, backupPath);
|
|
114
|
+
ensureLogger().info(`Created backup: ${backupPath}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Validate content size
|
|
118
|
+
const size = Buffer.isBuffer(content)
|
|
119
|
+
? content.length
|
|
120
|
+
: Buffer.byteLength(content);
|
|
121
|
+
if (size > this.maxFileSize) {
|
|
122
|
+
throw new Error(`File size exceeds maximum allowed size of ${this.maxFileSize} bytes`);
|
|
123
|
+
}
|
|
124
|
+
// Save the file
|
|
125
|
+
await fsUtils.writeFile(safePath, content);
|
|
126
|
+
// Calculate hash
|
|
127
|
+
const hash = crypto
|
|
128
|
+
.createHash("sha256")
|
|
129
|
+
.update(Buffer.isBuffer(content) ? content : Buffer.from(content))
|
|
130
|
+
.digest("hex");
|
|
131
|
+
const stats = await fsUtils.stat(safePath);
|
|
132
|
+
ensureLogger().debug(`File saved: ${safePath} (${size} bytes)`);
|
|
133
|
+
return {
|
|
134
|
+
name: filename,
|
|
135
|
+
size,
|
|
136
|
+
path: safePath,
|
|
137
|
+
hash,
|
|
138
|
+
created: stats.birthtime,
|
|
139
|
+
modified: stats.mtime,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Read a file securely
|
|
144
|
+
*/
|
|
145
|
+
async readFile(filename, category = "data", options = {}) {
|
|
146
|
+
await this.initialize();
|
|
147
|
+
const safePath = this.getSafePath(filename, category);
|
|
148
|
+
// Check if file exists
|
|
149
|
+
if (!(await fsUtils.pathExists(safePath))) {
|
|
150
|
+
throw new Error(`File not found: ${filename}`);
|
|
151
|
+
}
|
|
152
|
+
// Check file size
|
|
153
|
+
const stats = await fsUtils.stat(safePath);
|
|
154
|
+
const maxSize = options.maxSize || this.maxFileSize;
|
|
155
|
+
if (stats.size > maxSize) {
|
|
156
|
+
throw new Error(`File size (${stats.size}) exceeds maximum allowed size (${maxSize})`);
|
|
157
|
+
}
|
|
158
|
+
// Read the file
|
|
159
|
+
const content = options.encoding
|
|
160
|
+
? await fsUtils.readFile(safePath, options.encoding)
|
|
161
|
+
: await fsUtils.readFile(safePath);
|
|
162
|
+
ensureLogger().debug(`File read: ${safePath} (${stats.size} bytes)`);
|
|
163
|
+
return content;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Delete a file securely
|
|
167
|
+
*/
|
|
168
|
+
async deleteFile(filename, category = "data") {
|
|
169
|
+
await this.initialize();
|
|
170
|
+
const safePath = this.getSafePath(filename, category);
|
|
171
|
+
if (!(await fsUtils.pathExists(safePath))) {
|
|
172
|
+
ensureLogger().warn(`File not found for deletion: ${filename}`);
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
await fsUtils.unlink(safePath);
|
|
176
|
+
ensureLogger().debug(`File deleted: ${safePath}`);
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* List files in a category
|
|
181
|
+
*/
|
|
182
|
+
async listFiles(category = "data", pattern) {
|
|
183
|
+
await this.initialize();
|
|
184
|
+
const baseDir = BASE_DIRS[category];
|
|
185
|
+
const files = [];
|
|
186
|
+
try {
|
|
187
|
+
const entries = await fsUtils.readdir(baseDir);
|
|
188
|
+
for (const entry of entries) {
|
|
189
|
+
if (pattern && !pattern.test(entry))
|
|
190
|
+
continue;
|
|
191
|
+
const fullPath = path.join(baseDir, entry);
|
|
192
|
+
const stats = await fsUtils.stat(fullPath);
|
|
193
|
+
if (stats.isFile()) {
|
|
194
|
+
files.push({
|
|
195
|
+
name: entry,
|
|
196
|
+
size: stats.size,
|
|
197
|
+
path: fullPath,
|
|
198
|
+
created: stats.birthtime,
|
|
199
|
+
modified: stats.mtime,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch (_error) {
|
|
205
|
+
ensureLogger().error(`Error listing files in ${category}:`, _error);
|
|
206
|
+
}
|
|
207
|
+
return files;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get file info
|
|
211
|
+
*/
|
|
212
|
+
async getFileInfo(filename, category = "data") {
|
|
213
|
+
await this.initialize();
|
|
214
|
+
const safePath = this.getSafePath(filename, category);
|
|
215
|
+
if (!(await fsUtils.pathExists(safePath))) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
const stats = await fsUtils.stat(safePath);
|
|
219
|
+
return {
|
|
220
|
+
name: filename,
|
|
221
|
+
size: stats.size,
|
|
222
|
+
path: safePath,
|
|
223
|
+
created: stats.birthtime,
|
|
224
|
+
modified: stats.mtime,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Move file between categories
|
|
229
|
+
*/
|
|
230
|
+
async moveFile(filename, fromCategory, toCategory) {
|
|
231
|
+
await this.initialize();
|
|
232
|
+
const sourcePath = this.getSafePath(filename, fromCategory);
|
|
233
|
+
const destPath = this.getSafePath(filename, toCategory);
|
|
234
|
+
if (!(await fsUtils.pathExists(sourcePath))) {
|
|
235
|
+
throw new Error(`Source file not found: ${filename}`);
|
|
236
|
+
}
|
|
237
|
+
await fsUtils.move(sourcePath, destPath, { overwrite: false });
|
|
238
|
+
const stats = await fsUtils.stat(destPath);
|
|
239
|
+
ensureLogger().debug(`File moved from ${fromCategory} to ${toCategory}: ${filename}`);
|
|
240
|
+
return {
|
|
241
|
+
name: filename,
|
|
242
|
+
size: stats.size,
|
|
243
|
+
path: destPath,
|
|
244
|
+
created: stats.birthtime,
|
|
245
|
+
modified: stats.mtime,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Get available base directories
|
|
250
|
+
*/
|
|
251
|
+
getBaseDirectories() {
|
|
252
|
+
return { ...BASE_DIRS };
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Save a user upload with security checks
|
|
256
|
+
* @param file - File buffer or stream
|
|
257
|
+
* @param originalName - Original filename from user
|
|
258
|
+
* @param options - Upload options
|
|
259
|
+
* @returns Information about the uploaded file
|
|
260
|
+
*/
|
|
261
|
+
async saveUserUpload(file, originalName, options = {}) {
|
|
262
|
+
await this.initialize();
|
|
263
|
+
const { maxSize = this.maxFileSize, allowedTypes = [], destination = "uploads", generateUniqueName = true, preserveExtension = true, } = options;
|
|
264
|
+
// Sanitize the original filename
|
|
265
|
+
const sanitizedName = this.sanitizeFilename(originalName);
|
|
266
|
+
const ext = path.extname(sanitizedName).toLowerCase();
|
|
267
|
+
const nameWithoutExt = path.basename(sanitizedName, ext);
|
|
268
|
+
// Check file extension if restrictions are specified
|
|
269
|
+
if (allowedTypes.length > 0 && !allowedTypes.includes(ext)) {
|
|
270
|
+
throw new Error(`File type ${ext} is not allowed. Allowed types: ${allowedTypes.join(", ")}`);
|
|
271
|
+
}
|
|
272
|
+
// Generate filename
|
|
273
|
+
let filename;
|
|
274
|
+
if (generateUniqueName) {
|
|
275
|
+
const uniqueId = crypto.randomBytes(8).toString("hex");
|
|
276
|
+
filename = preserveExtension
|
|
277
|
+
? `${nameWithoutExt}_${uniqueId}${ext}`
|
|
278
|
+
: `${uniqueId}`;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
filename = sanitizedName;
|
|
282
|
+
}
|
|
283
|
+
// Determine the upload path. Prefer known base directories, but allow custom
|
|
284
|
+
// destinations for backward compatibility with the old FileHandler API.
|
|
285
|
+
let uploadPath;
|
|
286
|
+
if (BASE_DIRS[destination]) {
|
|
287
|
+
uploadPath = this.getSafePath(filename, destination);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
const resolvedDest = path.isAbsolute(destination)
|
|
291
|
+
? destination
|
|
292
|
+
: path.join(process.cwd(), destination);
|
|
293
|
+
await fsUtils.ensureDir(resolvedDest);
|
|
294
|
+
uploadPath = path.join(resolvedDest, this.sanitizeFilename(filename));
|
|
295
|
+
}
|
|
296
|
+
// Save the file
|
|
297
|
+
if (Buffer.isBuffer(file)) {
|
|
298
|
+
// Check size for buffer
|
|
299
|
+
if (file.length > maxSize) {
|
|
300
|
+
throw new Error(`File size exceeds maximum allowed size of ${maxSize} bytes`);
|
|
301
|
+
}
|
|
302
|
+
await fsUtils.writeFile(uploadPath, file);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
// For streams, we need to check size while writing
|
|
306
|
+
const writeStream = createWriteStream(uploadPath);
|
|
307
|
+
let size = 0;
|
|
308
|
+
await new Promise((resolve, reject) => {
|
|
309
|
+
file.on("data", (chunk) => {
|
|
310
|
+
size += chunk.length;
|
|
311
|
+
if (size > maxSize) {
|
|
312
|
+
writeStream.destroy();
|
|
313
|
+
fsUtils.unlink(uploadPath).catch(() => { }); // Clean up partial file
|
|
314
|
+
reject(new Error(`File size exceeds maximum allowed size of ${maxSize} bytes`));
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
file.on("error", reject);
|
|
318
|
+
writeStream.on("error", reject);
|
|
319
|
+
writeStream.on("finish", () => resolve(undefined));
|
|
320
|
+
file.pipe(writeStream);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
// Generate file hash
|
|
324
|
+
const fileBuffer = await fsUtils.readFile(uploadPath);
|
|
325
|
+
const hash = crypto.createHash("sha256").update(fileBuffer).digest("hex");
|
|
326
|
+
// Get file stats
|
|
327
|
+
const stats = await fsUtils.stat(uploadPath);
|
|
328
|
+
const uploadedFile = {
|
|
329
|
+
originalName,
|
|
330
|
+
filename,
|
|
331
|
+
path: uploadPath,
|
|
332
|
+
size: stats.size,
|
|
333
|
+
extension: ext,
|
|
334
|
+
hash,
|
|
335
|
+
};
|
|
336
|
+
ensureLogger().info("User file uploaded successfully", {
|
|
337
|
+
originalName,
|
|
338
|
+
filename,
|
|
339
|
+
size: stats.size,
|
|
340
|
+
hash,
|
|
341
|
+
});
|
|
342
|
+
return uploadedFile;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Clean temporary files older than a given age. Falls back to ./temp to
|
|
346
|
+
* preserve the previous middleware behaviour.
|
|
347
|
+
*/
|
|
348
|
+
async cleanTempFiles(maxAgeMs = 24 * 60 * 60 * 1000, tempDir = path.join(process.cwd(), "temp")) {
|
|
349
|
+
await fsUtils.ensureDir(tempDir);
|
|
350
|
+
const now = Date.now();
|
|
351
|
+
let deletedCount = 0;
|
|
352
|
+
try {
|
|
353
|
+
const files = await fsUtils.readdir(tempDir);
|
|
354
|
+
for (const file of files) {
|
|
355
|
+
const filePath = path.join(tempDir, file);
|
|
356
|
+
const stats = await fsUtils.stat(filePath);
|
|
357
|
+
if (!stats.isFile())
|
|
358
|
+
continue;
|
|
359
|
+
if (now - stats.mtimeMs > maxAgeMs) {
|
|
360
|
+
await fsUtils.unlink(filePath);
|
|
361
|
+
deletedCount++;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (deletedCount > 0) {
|
|
365
|
+
ensureLogger().info(`Cleaned ${deletedCount} temporary file(s) older than ${Math.round(maxAgeMs / (1000 * 60 * 60))}h`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch (_error) {
|
|
369
|
+
ensureLogger().error("Error cleaning temp files:", _error);
|
|
370
|
+
}
|
|
371
|
+
return deletedCount;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Save internal application data
|
|
375
|
+
* @param data - Data to save
|
|
376
|
+
* @param filename - Filename for the data
|
|
377
|
+
* @param category - Category/directory for the data
|
|
378
|
+
* @param options - Save options
|
|
379
|
+
*/
|
|
380
|
+
async saveInternalData(data, filename, category = "data", options = {}) {
|
|
381
|
+
// If data is an object, stringify it
|
|
382
|
+
const finalData = typeof data === "object" && !Buffer.isBuffer(data)
|
|
383
|
+
? JSON.stringify(data, null, 2)
|
|
384
|
+
: data;
|
|
385
|
+
// Use the existing save method
|
|
386
|
+
return this.saveFile(finalData, filename, category, options);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// Singleton instance
|
|
390
|
+
let storageService = null;
|
|
391
|
+
export function getStorageService() {
|
|
392
|
+
if (!storageService) {
|
|
393
|
+
storageService = new StorageService();
|
|
394
|
+
}
|
|
395
|
+
return storageService;
|
|
396
|
+
}
|
|
397
|
+
// Backward compatibility export (deprecated)
|
|
398
|
+
export function getSecureFileHandler() {
|
|
399
|
+
console.warn("getSecureFileHandler is deprecated. Use getStorageService instead.");
|
|
400
|
+
return getStorageService();
|
|
401
|
+
}
|
|
402
|
+
// Export for backward compatibility (deprecated)
|
|
403
|
+
export { StorageService as SecureFileHandler };
|
|
404
|
+
export default StorageService;
|
|
405
|
+
//# sourceMappingURL=storageService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storageService.js","sourceRoot":"","sources":["../../src/core/storageService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Desktop Bundler Module
|
|
3
|
+
* Handles bundling Node.js backends for Electron desktop applications
|
|
4
|
+
*/
|
|
5
|
+
export interface BundleOptions {
|
|
6
|
+
entryPoint: string;
|
|
7
|
+
outDir: string;
|
|
8
|
+
appName: string;
|
|
9
|
+
version: string;
|
|
10
|
+
platform?: "node" | "neutral";
|
|
11
|
+
target?: string;
|
|
12
|
+
format?: "cjs" | "esm";
|
|
13
|
+
minify?: boolean;
|
|
14
|
+
sourcemap?: boolean;
|
|
15
|
+
external?: string[];
|
|
16
|
+
env?: Record<string, string>;
|
|
17
|
+
resources?: {
|
|
18
|
+
config?: string;
|
|
19
|
+
data?: string[];
|
|
20
|
+
};
|
|
21
|
+
nativeModules?: {
|
|
22
|
+
autoDetect?: boolean;
|
|
23
|
+
modules?: string[];
|
|
24
|
+
rebuild?: boolean;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Bundle a Node.js backend for desktop deployment
|
|
29
|
+
*/
|
|
30
|
+
export declare function bundleBackend(options: BundleOptions): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Bundle dependencies separately for better caching
|
|
33
|
+
*/
|
|
34
|
+
export declare function bundleDependencies(packageJsonPath: string, outDir: string): Promise<void>;
|
|
35
|
+
declare const _default: {
|
|
36
|
+
bundleBackend: typeof bundleBackend;
|
|
37
|
+
bundleDependencies: typeof bundleDependencies;
|
|
38
|
+
};
|
|
39
|
+
export default _default;
|
|
40
|
+
//# sourceMappingURL=bundler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../../src/desktop/bundler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IACF,aAAa,CAAC,EAAE;QACd,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA6HzE;AA6CD;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAqCf;;;;;AAED,wBAGE"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Desktop Bundler Module
|
|
3
|
+
* Handles bundling Node.js backends for Electron desktop applications
|
|
4
|
+
*/
|
|
5
|
+
import * as esbuild from "esbuild";
|
|
6
|
+
import { ensureDir, writeFile, stat, copy, move, remove, writeJson, } from "../utils/fs-utils.js";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
import { createLogger } from "../core/index.js";
|
|
10
|
+
import { detectNativeModules, copyNativeModules, createNativeModuleLoader, } from "./native-modules.js";
|
|
11
|
+
const logger = createLogger("DesktopBundler");
|
|
12
|
+
/**
|
|
13
|
+
* Bundle a Node.js backend for desktop deployment
|
|
14
|
+
*/
|
|
15
|
+
export async function bundleBackend(options) {
|
|
16
|
+
const { entryPoint, outDir, appName, version, platform = "node", target = "node18", format = "cjs", minify = false, sourcemap = false, external = [], env = {}, resources = {}, } = options;
|
|
17
|
+
logger.info(`Bundling backend for ${appName} v${version}`);
|
|
18
|
+
// Ensure output directory exists
|
|
19
|
+
await ensureDir(outDir);
|
|
20
|
+
// Default externals for Node.js
|
|
21
|
+
const defaultExternals = [
|
|
22
|
+
"fsevents", // Mac-specific, optional
|
|
23
|
+
"bufferutil", // Optional WebSocket performance
|
|
24
|
+
"utf-8-validate", // Optional WebSocket validation
|
|
25
|
+
"@superdangerous/app-framework/ui", // UI components not needed in backend
|
|
26
|
+
"serialport", // Optional serial port support
|
|
27
|
+
"@serialport/bindings-cpp", // Optional serial port bindings
|
|
28
|
+
"@aws-sdk/client-s3", // Optional AWS S3 support
|
|
29
|
+
"modbus-serial", // Optional Modbus communication
|
|
30
|
+
];
|
|
31
|
+
// Build with esbuild
|
|
32
|
+
const result = await esbuild.build({
|
|
33
|
+
entryPoints: [entryPoint],
|
|
34
|
+
bundle: true,
|
|
35
|
+
platform,
|
|
36
|
+
target,
|
|
37
|
+
outfile: path.join(outDir, "backend.js"),
|
|
38
|
+
format,
|
|
39
|
+
minify,
|
|
40
|
+
sourcemap,
|
|
41
|
+
external: [...defaultExternals, ...external],
|
|
42
|
+
define: {
|
|
43
|
+
"process.env.NODE_ENV": '"production"',
|
|
44
|
+
"process.env.DESKTOP_MODE": '"true"',
|
|
45
|
+
...Object.entries(env).reduce((acc, [key, value]) => {
|
|
46
|
+
acc[`process.env.${key}`] = JSON.stringify(value);
|
|
47
|
+
return acc;
|
|
48
|
+
}, {}),
|
|
49
|
+
},
|
|
50
|
+
loader: {
|
|
51
|
+
".node": "file",
|
|
52
|
+
".json": "json",
|
|
53
|
+
},
|
|
54
|
+
metafile: true,
|
|
55
|
+
logLevel: "info",
|
|
56
|
+
});
|
|
57
|
+
// Write metafile for analysis
|
|
58
|
+
await writeFile(path.join(outDir, "backend-meta.json"), JSON.stringify(result.metafile, null, 2));
|
|
59
|
+
// Create wrapper script
|
|
60
|
+
const wrapperScript = generateWrapperScript(appName, format);
|
|
61
|
+
await writeFile(path.join(outDir, "start-backend.js"), wrapperScript);
|
|
62
|
+
// Copy resources
|
|
63
|
+
if (resources.config) {
|
|
64
|
+
const configDest = path.join(outDir, "config");
|
|
65
|
+
await ensureDir(configDest);
|
|
66
|
+
await copy(resources.config, path.join(configDest, "app.json"));
|
|
67
|
+
}
|
|
68
|
+
if (resources.data) {
|
|
69
|
+
const dataDir = path.join(outDir, "data");
|
|
70
|
+
for (const dir of resources.data) {
|
|
71
|
+
await ensureDir(path.join(dataDir, dir));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Handle native modules if configured
|
|
75
|
+
if (options.nativeModules) {
|
|
76
|
+
const projectDir = path.dirname(entryPoint);
|
|
77
|
+
// Detect native modules if requested
|
|
78
|
+
let nativeModulesList = options.nativeModules.modules || [];
|
|
79
|
+
if (options.nativeModules.autoDetect) {
|
|
80
|
+
const detected = await detectNativeModules(projectDir);
|
|
81
|
+
nativeModulesList = [...new Set([...nativeModulesList, ...detected])];
|
|
82
|
+
logger.info(`Detected native modules: ${nativeModulesList.join(", ")}`);
|
|
83
|
+
}
|
|
84
|
+
// Copy native modules to output directory
|
|
85
|
+
if (nativeModulesList.length > 0) {
|
|
86
|
+
await copyNativeModules({
|
|
87
|
+
modules: nativeModulesList,
|
|
88
|
+
sourceDir: projectDir,
|
|
89
|
+
targetDir: outDir,
|
|
90
|
+
rebuild: options.nativeModules.rebuild,
|
|
91
|
+
});
|
|
92
|
+
// Create native module loader
|
|
93
|
+
await createNativeModuleLoader(path.join(outDir, "native-loader.js"), nativeModulesList);
|
|
94
|
+
logger.info(`Copied ${nativeModulesList.length} native modules`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Get bundle size
|
|
98
|
+
const stats = await stat(path.join(outDir, "backend.js"));
|
|
99
|
+
const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
|
|
100
|
+
logger.info(`✅ Backend bundled successfully!`);
|
|
101
|
+
logger.info(` Bundle size: ${sizeMB} MB`);
|
|
102
|
+
logger.info(` Location: ${outDir}/backend.js`);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Generate wrapper script for starting the bundled backend
|
|
106
|
+
*/
|
|
107
|
+
function generateWrapperScript(appName, format) {
|
|
108
|
+
return `#!/usr/bin/env node
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Desktop App Backend Wrapper for ${appName}
|
|
112
|
+
* Sets up environment and starts the bundled backend
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
${format === "esm" ? "import { fileURLToPath } from 'url';" : ""}
|
|
116
|
+
${format === "esm" ? "import { dirname, join } from 'path';" : "const path = require('path');"}
|
|
117
|
+
|
|
118
|
+
${format === "esm"
|
|
119
|
+
? `
|
|
120
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
121
|
+
const __dirname = dirname(__filename);
|
|
122
|
+
`
|
|
123
|
+
: ""}
|
|
124
|
+
|
|
125
|
+
// Set environment variables
|
|
126
|
+
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
|
|
127
|
+
process.env.DESKTOP_MODE = 'true';
|
|
128
|
+
|
|
129
|
+
// Set data directory to app data location
|
|
130
|
+
if (!process.env.DATA_DIR) {
|
|
131
|
+
// In production, this will be set by Electron
|
|
132
|
+
// For testing, use a local data directory
|
|
133
|
+
process.env.DATA_DIR = ${format === "esm" ? "join" : "path.join"}(__dirname, 'data');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Note: Using console.log in wrapper script as it runs in production without logger
|
|
137
|
+
console.log('Starting ${appName} Backend...');
|
|
138
|
+
console.log('Data directory:', process.env.DATA_DIR);
|
|
139
|
+
|
|
140
|
+
// Start the bundled backend
|
|
141
|
+
${format === "cjs" ? "require('./backend.js');" : "import('./backend.js');"}
|
|
142
|
+
`;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Bundle dependencies separately for better caching
|
|
146
|
+
*/
|
|
147
|
+
export async function bundleDependencies(packageJsonPath, outDir) {
|
|
148
|
+
const fs = await import("fs");
|
|
149
|
+
const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, "utf8"));
|
|
150
|
+
const dependencies = packageJson.dependencies || {};
|
|
151
|
+
logger.info("Installing production dependencies...");
|
|
152
|
+
// Create temporary directory for dependencies
|
|
153
|
+
const tempDir = path.join(outDir, "temp");
|
|
154
|
+
await ensureDir(tempDir);
|
|
155
|
+
// Create minimal package.json
|
|
156
|
+
const minimalPackage = {
|
|
157
|
+
name: packageJson.name,
|
|
158
|
+
version: packageJson.version,
|
|
159
|
+
dependencies,
|
|
160
|
+
};
|
|
161
|
+
await writeJson(path.join(tempDir, "package.json"), minimalPackage);
|
|
162
|
+
// Install production dependencies
|
|
163
|
+
execSync("npm install --production --no-audit --no-fund", {
|
|
164
|
+
cwd: tempDir,
|
|
165
|
+
stdio: "inherit",
|
|
166
|
+
});
|
|
167
|
+
// Move node_modules to output directory
|
|
168
|
+
await move(path.join(tempDir, "node_modules"), path.join(outDir, "node_modules"), { overwrite: true });
|
|
169
|
+
// Clean up temp directory
|
|
170
|
+
await remove(tempDir);
|
|
171
|
+
}
|
|
172
|
+
export default {
|
|
173
|
+
bundleBackend,
|
|
174
|
+
bundleDependencies,
|
|
175
|
+
};
|
|
176
|
+
//# sourceMappingURL=bundler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.js","sourceRoot":"","sources":["../../src/desktop/bundler.ts"],"names":[],"mappings":"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"}
|