@workadventure/map-starter-kit-core 0.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/server.d.ts +5 -0
  2. package/dist/server.js +524 -0
  3. package/dist/server.js.map +1 -0
  4. package/package.json +23 -4
  5. package/.github/workflows/release.yml +0 -47
  6. package/semantic-release.config.js +0 -8
  7. package/src/controllers/FrontController.ts +0 -95
  8. package/src/controllers/MapController.ts +0 -104
  9. package/src/controllers/UploaderController.ts +0 -333
  10. package/src/getCoreRoot.ts +0 -40
  11. package/src/views/index.html +0 -169
  12. package/src/views/step1-git.html +0 -154
  13. package/src/views/step2-hosting.html +0 -153
  14. package/src/views/step3-steps-selfhosted.html +0 -502
  15. package/src/views/step3-steps.html +0 -549
  16. package/src/views/step4-validated-selfhosted.html +0 -188
  17. package/src/views/step4-validated.html +0 -80
  18. package/tsconfig.json +0 -35
  19. package/vite.config.ts +0 -53
  20. /package/{public → dist}/assets/index.js +0 -0
  21. /package/{public → dist}/images/badumtss.svg +0 -0
  22. /package/{public → dist}/images/brand-discord.svg +0 -0
  23. /package/{public → dist}/images/brand-github.svg +0 -0
  24. /package/{public → dist}/images/brand-linkedin.svg +0 -0
  25. /package/{public → dist}/images/brand-x.svg +0 -0
  26. /package/{public → dist}/images/brand-youtube.svg +0 -0
  27. /package/{public → dist}/images/favicon.svg +0 -0
  28. /package/{public → dist}/images/logo.svg +0 -0
  29. /package/{public → dist}/images/unknown-room-image copy.png +0 -0
  30. /package/{public → dist}/images/unknown-room-image.png +0 -0
  31. /package/{public → dist}/styles/styles.css +0 -0
  32. /package/{public → dist}/styles/styles.css.map +0 -0
@@ -0,0 +1,5 @@
1
+ declare module "@workadventure/map-starter-kit-core/dist/server.js" {
2
+ import type { Application } from "express";
3
+ const core: { default: Application; viteNodeApp: Application };
4
+ export default core;
5
+ }
package/dist/server.js ADDED
@@ -0,0 +1,524 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
25
+ const express = require("express");
26
+ const path = require("node:path");
27
+ const fs = require("node:fs");
28
+ const cors = require("cors");
29
+ const node_url = require("node:url");
30
+ const Mustache = require("mustache");
31
+ const node_child_process = require("node:child_process");
32
+ const node_util = require("node:util");
33
+ var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
34
+ function _interopNamespaceDefault(e) {
35
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
36
+ if (e) {
37
+ for (const k in e) {
38
+ if (k !== "default") {
39
+ const d = Object.getOwnPropertyDescriptor(e, k);
40
+ Object.defineProperty(n, k, d.get ? d : {
41
+ enumerable: true,
42
+ get: () => e[k]
43
+ });
44
+ }
45
+ }
46
+ }
47
+ n.default = e;
48
+ return Object.freeze(n);
49
+ }
50
+ const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path);
51
+ const fs__namespace = /* @__PURE__ */ _interopNamespaceDefault(fs);
52
+ let coreRoot = null;
53
+ function getCoreRoot() {
54
+ if (coreRoot !== null) {
55
+ return coreRoot;
56
+ }
57
+ try {
58
+ const dir = path__namespace.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("server.js", document.baseURI).href));
59
+ const candidate = path__namespace.dirname(dir);
60
+ const packagePath = path__namespace.join(candidate, "package.json");
61
+ if (fs__namespace.existsSync(packagePath)) {
62
+ const pkg = JSON.parse(fs__namespace.readFileSync(packagePath, "utf-8"));
63
+ if (pkg.name === "@workadventure/map-starter-kit-core") {
64
+ coreRoot = candidate;
65
+ return coreRoot;
66
+ }
67
+ }
68
+ } catch {
69
+ }
70
+ coreRoot = process.cwd();
71
+ return coreRoot;
72
+ }
73
+ class FrontController {
74
+ app;
75
+ constructor(app2) {
76
+ this.app = app2;
77
+ this.setupRoutes();
78
+ this.setupRoutesStep1();
79
+ this.setupRoutesStep2();
80
+ this.setupRoutesStep3();
81
+ this.setupRoutesStep4();
82
+ }
83
+ setupRoutes() {
84
+ this.app.get("/", async (_, res) => {
85
+ try {
86
+ res.send(await this.renderTemplate("index"));
87
+ } catch (error) {
88
+ console.error("Error rendering template:", error);
89
+ res.status(500).send("Error rendering template");
90
+ }
91
+ });
92
+ }
93
+ /**
94
+ * Render a template file
95
+ * @param filename - The filename of the template to render
96
+ * @returns The rendered template
97
+ */
98
+ async renderTemplate(filename) {
99
+ const coreRoot2 = getCoreRoot();
100
+ const templatesDir = path__namespace.join(coreRoot2, "src/views");
101
+ if (!fs__namespace.existsSync(templatesDir)) {
102
+ throw new Error(`Templates directory not found: ${templatesDir}`);
103
+ }
104
+ const templatePath = path__namespace.join(templatesDir, `${filename}.html`);
105
+ const template = await fs__namespace.promises.readFile(templatePath, "utf-8");
106
+ return Mustache.render(template, {});
107
+ }
108
+ /**
109
+ * Setup the routes for file "step1-git.html"
110
+ * @returns void
111
+ */
112
+ setupRoutesStep1() {
113
+ this.app.get("/step1-git", async (_, res) => {
114
+ res.send(await this.renderTemplate("step1-git"));
115
+ });
116
+ }
117
+ /**
118
+ * Setup the routes for file "step2-hosting.html"
119
+ * @returns void
120
+ */
121
+ setupRoutesStep2() {
122
+ this.app.get("/step2-hosting", async (_, res) => {
123
+ res.send(await this.renderTemplate("step2-hosting"));
124
+ });
125
+ }
126
+ /**
127
+ * Setup the routes for file "step3-steps.html"
128
+ * @returns void
129
+ */
130
+ setupRoutesStep3() {
131
+ this.app.get("/step3-steps", async (_, res) => {
132
+ res.send(await this.renderTemplate("step3-steps"));
133
+ });
134
+ this.app.get("/step3-steps-selfhosted", async (_, res) => {
135
+ res.send(await this.renderTemplate("step3-steps-selfhosted"));
136
+ });
137
+ }
138
+ /**
139
+ * Setup the routes for file "step4-map.html"
140
+ * @returns void
141
+ */
142
+ setupRoutesStep4() {
143
+ this.app.get("/step4-validated", async (_, res) => {
144
+ res.send(await this.renderTemplate("step4-validated"));
145
+ });
146
+ this.app.get("/step4-validated-selfhosted", async (_, res) => {
147
+ res.send(await this.renderTemplate("step4-validated-selfhosted"));
148
+ });
149
+ }
150
+ }
151
+ class MapController {
152
+ router;
153
+ app;
154
+ constructor(app2) {
155
+ this.app = app2;
156
+ this.router = express.Router();
157
+ this.setupRoutes();
158
+ this.app.use("/maps", this.router);
159
+ }
160
+ /**
161
+ * Setup the routes for the map controller
162
+ * @returns void
163
+ */
164
+ setupRoutes() {
165
+ this.router.get("/list", async (_, res) => {
166
+ try {
167
+ const mapsDir = "./";
168
+ const maps = await this.getMapsWithProperties(mapsDir);
169
+ res.json(maps);
170
+ } catch (error) {
171
+ console.error("Error getting maps list:", error);
172
+ res.status(500).json({ error: "Error getting maps list" });
173
+ }
174
+ });
175
+ }
176
+ /**
177
+ * Get the list of maps with their properties
178
+ * @param dir - The directory to search for maps
179
+ * @param baseDir - The base directory to use for relative paths
180
+ * @returns The list of maps with their properties
181
+ */
182
+ async getMapsWithProperties(dir, baseDir = dir) {
183
+ let files = await fs__namespace.promises.readdir(dir, { withFileTypes: true });
184
+ const maps = [];
185
+ for (const file of files) {
186
+ const fullPath = path__namespace.join(dir, file.name);
187
+ if (file.name === "dist") continue;
188
+ if (file.isDirectory()) {
189
+ const subMaps = await this.getMapsWithProperties(fullPath, baseDir);
190
+ maps.push(...subMaps);
191
+ } else if (file.name.endsWith(".tmj")) {
192
+ try {
193
+ const tmjContent = await fs__namespace.promises.readFile(fullPath, "utf-8");
194
+ const tmjData = JSON.parse(tmjContent);
195
+ const properties = tmjData.properties || [];
196
+ const findProperty = (key) => {
197
+ const item = properties.find((p) => p.name === key);
198
+ return item ? item.value : null;
199
+ };
200
+ const stats = await fs__namespace.promises.stat(fullPath);
201
+ const fileSizeInMB = (stats.size / (1024 * 1024)).toFixed(2);
202
+ const lastModified = stats.mtime;
203
+ const relativePath = path__namespace.relative(baseDir, fullPath).replace(/\\/g, "/");
204
+ const filename = path__namespace.basename(file.name, ".tmj");
205
+ maps.push({
206
+ path: relativePath,
207
+ filename,
208
+ mapName: findProperty("mapName") || filename,
209
+ mapImage: findProperty("mapImage") || null,
210
+ mapDescription: findProperty("mapDescription") || "",
211
+ mapCopyright: findProperty("mapCopyright") || "",
212
+ size: fileSizeInMB,
213
+ lastModified: lastModified.toISOString(),
214
+ lastModifiedFormatted: lastModified.toLocaleDateString("fr-FR", {
215
+ day: "2-digit",
216
+ month: "2-digit",
217
+ year: "numeric",
218
+ hour: "2-digit",
219
+ minute: "2-digit"
220
+ })
221
+ });
222
+ } catch (error) {
223
+ console.error(`Error reading TMJ file ${fullPath}:`, error);
224
+ }
225
+ }
226
+ }
227
+ return maps;
228
+ }
229
+ }
230
+ const execAsync = node_util.promisify(node_child_process.exec);
231
+ function hydrateMapStorageList(raw, mapStorageBaseUrl) {
232
+ const list = [];
233
+ const baseUrl = mapStorageBaseUrl.replace(/\/$/, "");
234
+ for (const [wamFile, entry] of Object.entries(raw)) {
235
+ if (!entry || typeof entry !== "object") continue;
236
+ const rawWamFileUrl = entry.wamFileUrl ?? wamFile;
237
+ const wamFileUrlNormalized = rawWamFileUrl.startsWith("http") ? new URL(rawWamFileUrl).pathname.replace(/^\//, "") : rawWamFileUrl.replace(/^\//, "");
238
+ const filename = wamFileUrlNormalized.split("/").pop() ?? wamFileUrlNormalized;
239
+ const nameFromFile = filename.replace(/\.(tmj|wam)$/i, "");
240
+ const meta = entry.metadata ?? {};
241
+ const mapUrl = entry.mapUrl ?? entry.mapUrl ?? "";
242
+ let mapImage = null;
243
+ if (meta.thumbnail) {
244
+ if (meta.thumbnail.startsWith("http")) {
245
+ mapImage = meta.thumbnail;
246
+ } else {
247
+ const thumbFile = meta.thumbnail.replace(/^\//, "");
248
+ const wamDir = wamFileUrlNormalized.includes("/") ? wamFileUrlNormalized.replace(/\/[^/]*$/, "") : "";
249
+ const thumbPath = wamDir ? `${wamDir}/${thumbFile}` : thumbFile;
250
+ mapImage = `${baseUrl}/${thumbPath}`;
251
+ }
252
+ }
253
+ list.push({
254
+ wamFileUrl: wamFileUrlNormalized,
255
+ filename,
256
+ mapName: meta.name ?? nameFromFile,
257
+ mapDescription: meta.description,
258
+ mapCopyright: meta.copyright,
259
+ mapImage,
260
+ mapUrl: mapUrl.startsWith("http") ? mapUrl : `${baseUrl}/${mapUrl.replace(/^\//, "")}`
261
+ });
262
+ }
263
+ return list;
264
+ }
265
+ class UploaderController {
266
+ router;
267
+ app;
268
+ constructor(app2) {
269
+ this.app = app2;
270
+ this.router = express.Router();
271
+ this.setupMiddleware();
272
+ this.setupRoutes();
273
+ this.app.use("/uploader", this.router);
274
+ }
275
+ setupMiddleware() {
276
+ this.router.use(express.json());
277
+ }
278
+ setupRoutes() {
279
+ this.router.post("/configure", async (req, res) => {
280
+ try {
281
+ const { mapStorageUrl, mapStorageApiKey, uploadDirectory } = req.body;
282
+ if (!mapStorageUrl || !mapStorageApiKey || !uploadDirectory) {
283
+ return res.status(400).json({
284
+ error: "Missing required fields",
285
+ required: ["mapStorageUrl", "mapStorageApiKey", "uploadDirectory"]
286
+ });
287
+ }
288
+ await this.createEnvSecretFile({
289
+ mapStorageUrl,
290
+ mapStorageApiKey,
291
+ uploadDirectory
292
+ });
293
+ return res.json({
294
+ success: true,
295
+ message: "Configuration updated successfully"
296
+ });
297
+ } catch (error) {
298
+ console.error("Error configuring uploader:", error);
299
+ return res.status(500).json({
300
+ error: "Error configuring uploader",
301
+ message: error instanceof Error ? error.message : "Unknown error"
302
+ });
303
+ }
304
+ });
305
+ this.router.get("/status", async (_, res) => {
306
+ try {
307
+ const envSecretPath = path__namespace.join(process.cwd(), "src/.env.secret");
308
+ const hasSecretFile = await fs__namespace.promises.access(envSecretPath).then(() => true).catch(() => false);
309
+ let secretConfig = null;
310
+ if (hasSecretFile) {
311
+ const secretContent = await fs__namespace.promises.readFile(envSecretPath, "utf-8");
312
+ const mapStorageUrl = secretContent.match(/MAP_STORAGE_URL=(.+)/)?.[1]?.trim();
313
+ const mapStorageApiKey = secretContent.match(/MAP_STORAGE_API_KEY=(.+)/)?.[1]?.trim();
314
+ const uploadDirectory = secretContent.match(/UPLOAD_DIRECTORY=(.+)/)?.[1]?.trim();
315
+ secretConfig = {
316
+ mapStorageUrl: mapStorageUrl || null,
317
+ mapStorageApiKey: mapStorageApiKey || null,
318
+ // Hide the actual key
319
+ uploadDirectory: uploadDirectory || null
320
+ };
321
+ }
322
+ res.json({
323
+ hasSecretFile,
324
+ secretConfig
325
+ });
326
+ } catch (error) {
327
+ console.error("Error getting uploader status:", error);
328
+ res.status(500).json({
329
+ error: "Error getting uploader status",
330
+ message: error instanceof Error ? error.message : "Unknown error"
331
+ });
332
+ }
333
+ });
334
+ this.router.get("/maps-storage-list", async (_, res) => {
335
+ try {
336
+ const envSecretPath = path__namespace.join(process.cwd(), ".env.secret");
337
+ const hasSecretFile = await fs__namespace.promises.access(envSecretPath).then(() => true).catch(() => false);
338
+ if (!hasSecretFile) {
339
+ return res.status(400).json({
340
+ error: "Configuration not found",
341
+ message: "Please configure the upload settings first."
342
+ });
343
+ }
344
+ const secretContent = await fs__namespace.promises.readFile(envSecretPath, "utf-8");
345
+ const mapStorageUrl = secretContent.match(/MAP_STORAGE_URL=(.+)/)?.[1]?.trim();
346
+ const mapStorageApiKey = secretContent.match(/MAP_STORAGE_API_KEY=(.+)/)?.[1]?.trim();
347
+ if (!mapStorageUrl || !mapStorageApiKey) {
348
+ return res.status(400).json({
349
+ error: "Missing map-storage configuration",
350
+ message: "MAP_STORAGE_URL and MAP_STORAGE_API_KEY must be set in .env.secret."
351
+ });
352
+ }
353
+ const baseUrl = mapStorageUrl.replace(/\/$/, "");
354
+ const listUrl = `${baseUrl}/maps/`;
355
+ const response = await fetch(listUrl, {
356
+ method: "GET",
357
+ headers: {
358
+ "Authorization": `Bearer ${mapStorageApiKey}`,
359
+ "Content-Type": "application/json"
360
+ }
361
+ });
362
+ if (!response.ok) {
363
+ const text = await response.text();
364
+ console.error("Map-storage list error:", response.status, text);
365
+ return res.status(response.status).json({
366
+ error: "Map-storage request failed",
367
+ message: response.status === 401 ? "Invalid API key. Check MAP_STORAGE_API_KEY in your .env.secret." : `Map-storage returned ${response.status}: ${text.slice(0, 200)}`
368
+ });
369
+ }
370
+ const data = await response.json();
371
+ const raw = typeof data === "object" && data !== null ? data : {};
372
+ const rawMap = !Array.isArray(raw) && typeof raw.maps === "object" && raw.maps !== null ? raw.maps : !Array.isArray(raw) ? raw : {};
373
+ const maps = hydrateMapStorageList(rawMap, baseUrl);
374
+ const playBaseUrl = secretContent.match(/PLAY_BASE_URL=(.+)/)?.[1]?.trim() || null;
375
+ return res.json({ maps, mapStorageUrl: baseUrl, playBaseUrl });
376
+ } catch (error) {
377
+ console.error("Error fetching maps from map-storage:", error);
378
+ return res.status(500).json({
379
+ error: "Error fetching maps list",
380
+ message: error instanceof Error ? error.message : "Unknown error"
381
+ });
382
+ }
383
+ });
384
+ this.router.post("/upload", async (_, res) => {
385
+ try {
386
+ const envSecretPath = path__namespace.join(process.cwd(), ".env.secret");
387
+ const hasSecretFile = await fs__namespace.promises.access(envSecretPath).then(() => true).catch(() => false);
388
+ if (!hasSecretFile) {
389
+ return res.status(400).json({
390
+ error: "Configuration not found",
391
+ message: "Please configure the upload settings first using /uploader/configure"
392
+ });
393
+ }
394
+ await this.runUpload();
395
+ return res.json({
396
+ success: true,
397
+ message: "Map uploaded successfully"
398
+ });
399
+ } catch (error) {
400
+ console.error("Error uploading map:", error);
401
+ return res.status(500).json({
402
+ error: "Error uploading map",
403
+ message: error instanceof Error ? error.message : "Unknown error"
404
+ });
405
+ }
406
+ });
407
+ }
408
+ async runUpload() {
409
+ const projectRoot = process.cwd();
410
+ try {
411
+ const { stdout, stderr } = await execAsync("npm run upload", {
412
+ cwd: projectRoot,
413
+ env: {
414
+ ...process.env,
415
+ // Ensure we're using the current process environment
416
+ NODE_ENV: process.env.NODE_ENV || "development"
417
+ },
418
+ maxBuffer: 10 * 1024 * 1024
419
+ // 10MB buffer for output
420
+ });
421
+ if (stderr && !stderr.includes("warning")) {
422
+ console.warn("Upload stderr:", stderr);
423
+ }
424
+ console.info("Upload stdout:", stdout);
425
+ console.info("Upload completed successfully");
426
+ } catch (error) {
427
+ console.error("Error executing upload-only:", error);
428
+ throw error;
429
+ }
430
+ }
431
+ async createEnvSecretFile(config) {
432
+ const envSecretPath = path__namespace.join(process.cwd(), ".env.secret");
433
+ const secretContent = `# Secret configuration file for MAP_STORAGE upload mode
434
+ # This file is not committed to git (see .gitignore)
435
+
436
+ MAP_STORAGE_URL=${config.mapStorageUrl}
437
+ MAP_STORAGE_API_KEY=${config.mapStorageApiKey}
438
+ UPLOAD_DIRECTORY=${config.uploadDirectory}
439
+ `;
440
+ await fs__namespace.promises.writeFile(envSecretPath, secretContent, "utf-8");
441
+ }
442
+ }
443
+ const app = express();
444
+ const corsOptions = {
445
+ credentials: true,
446
+ // Allow sending cookies
447
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
448
+ allowedHeaders: [
449
+ "Content-Type",
450
+ "Authorization",
451
+ "X-Requested-With",
452
+ "Accept",
453
+ "Origin",
454
+ "Access-Control-Request-Method",
455
+ "Access-Control-Request-Headers"
456
+ ],
457
+ exposedHeaders: ["Content-Length", "Content-Type"],
458
+ maxAge: 86400
459
+ // Cache the OPTIONS requests for 24 hours
460
+ };
461
+ app.use(cors(corsOptions));
462
+ app.use(express.json());
463
+ const staticOptions = {
464
+ maxAge: "1d",
465
+ // Cache the files for 1 day
466
+ etag: true,
467
+ // Enable ETag for cache validation
468
+ lastModified: true
469
+ // Enable Last-Modified header
470
+ };
471
+ app.use("/assets", express.static(path__namespace.join(process.cwd(), "dist", "assets"), staticOptions));
472
+ app.use("/public", express.static(path__namespace.join(getCoreRoot(), "public"), staticOptions));
473
+ app.use("/tilesets", express.static(path__namespace.join(process.cwd(), "tilesets"), {
474
+ maxAge: "7d",
475
+ etag: true,
476
+ lastModified: true
477
+ }));
478
+ const staticMiddleware = express.static(".", staticOptions);
479
+ app.use("/src", async (req, res, next) => {
480
+ if (req.path.endsWith(".ts") || req.path.endsWith(".tsx")) {
481
+ try {
482
+ const filePath = path__namespace.join(process.cwd(), "src", req.path.startsWith("/") ? req.path.slice(1) : req.path);
483
+ if (!fs__namespace.existsSync(filePath)) {
484
+ return res.status(404).send("File not found");
485
+ }
486
+ const esbuild = await import("esbuild");
487
+ const result = await esbuild.build({
488
+ entryPoints: [filePath],
489
+ bundle: true,
490
+ format: "esm",
491
+ target: "esnext",
492
+ write: false,
493
+ platform: "browser",
494
+ sourcemap: false,
495
+ // Externalize WorkAdventure global API (available in the browser)
496
+ external: ["WA"]
497
+ });
498
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
499
+ return res.send(result.outputFiles[0].text);
500
+ } catch (error) {
501
+ console.error("Error transforming TypeScript file:", error);
502
+ return next(error);
503
+ }
504
+ }
505
+ next();
506
+ });
507
+ app.use((req, res, next) => {
508
+ if (req.path.startsWith("/src/")) {
509
+ return next();
510
+ }
511
+ staticMiddleware(req, res, next);
512
+ });
513
+ const controllers = [
514
+ new MapController(app),
515
+ new FrontController(app),
516
+ new UploaderController(app)
517
+ ];
518
+ controllers.forEach((controller) => {
519
+ console.info(`Controller started: ${controller.constructor.name}`);
520
+ });
521
+ const viteNodeApp = app;
522
+ exports.default = app;
523
+ exports.viteNodeApp = viteNodeApp;
524
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sources":["../src/getCoreRoot.ts","../src/controllers/FrontController.ts","../src/controllers/MapController.ts","../src/controllers/UploaderController.ts","../src/server.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nlet coreRoot: string | null = null;\n\n/**\n * Returns the root directory of the \"core\" package (app + templates + public).\n * - When running from the project root: returns process.cwd().\n * - When running from packages/map-starter-kit-core or node_modules: returns the package directory.\n * Allows updating the core package without touching user files (maps, .env, tilesets).\n */\nexport function getCoreRoot(): string {\n if (coreRoot !== null) {\n return coreRoot;\n }\n try {\n const dir = path.dirname(fileURLToPath(import.meta.url));\n const candidate = path.dirname(dir);\n const packagePath = path.join(candidate, \"package.json\");\n if (fs.existsSync(packagePath)) {\n const pkg = JSON.parse(fs.readFileSync(packagePath, \"utf-8\"));\n if (pkg.name === \"@workadventure/map-starter-kit-core\") {\n coreRoot = candidate;\n return coreRoot;\n }\n }\n } catch {\n // ignore\n }\n coreRoot = process.cwd();\n return coreRoot;\n}\n\n/**\n * Override the core root (e.g. for tests or custom layout).\n */\nexport function setCoreRoot(root: string): void {\n coreRoot = root;\n}\n","import express from 'express';\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport Mustache from 'mustache';\nimport { getCoreRoot } from '../getCoreRoot.js';\n\nexport class FrontController {\n private app: express.Application;\n\n constructor(app: express.Application) {\n this.app = app;\n // Assets are now configured in app.ts\n this.setupRoutes();\n this.setupRoutesStep1();\n this.setupRoutesStep2();\n this.setupRoutesStep3();\n this.setupRoutesStep4();\n }\n\n private setupRoutes() {\n // Route for the Mustache renderer on \"/\"\n this.app.get('/', async (_, res) => {\n try {\n res.send(await this.renderTemplate('index'));\n } catch (error) {\n console.error('Error rendering template:', error);\n res.status(500).send('Error rendering template');\n }\n });\n }\n\n /**\n * Render a template file\n * @param filename - The filename of the template to render\n * @returns The rendered template\n */\n private async renderTemplate(filename: string): Promise<string> {\n const coreRoot = getCoreRoot();\n const templatesDir = path.join(coreRoot, 'src/views');\n if(!fs.existsSync(templatesDir)) {\n throw new Error(`Templates directory not found: ${templatesDir}`);\n }\n const templatePath = path.join(templatesDir, `${filename}.html`);\n const template = await fs.promises.readFile(templatePath, 'utf-8');\n // Render the template with Mustache (without data for now)\n return Mustache.render(template, {});\n }\n\n /**\n * Setup the routes for file \"step1-git.html\"\n * @returns void\n */\n private setupRoutesStep1() {\n this.app.get('/step1-git', async (_, res) => {\n res.send(await this.renderTemplate('step1-git'));\n });\n }\n\n /**\n * Setup the routes for file \"step2-hosting.html\"\n * @returns void\n */\n private setupRoutesStep2() {\n this.app.get('/step2-hosting', async (_, res) => {\n res.send(await this.renderTemplate('step2-hosting'));\n });\n }\n\n /**\n * Setup the routes for file \"step3-steps.html\"\n * @returns void\n */\n private setupRoutesStep3() {\n this.app.get('/step3-steps', async (_, res) => {\n res.send(await this.renderTemplate('step3-steps'));\n });\n this.app.get('/step3-steps-selfhosted', async (_, res) => {\n res.send(await this.renderTemplate('step3-steps-selfhosted'));\n });\n }\n\n /**\n * Setup the routes for file \"step4-map.html\"\n * @returns void\n */\n private setupRoutesStep4() {\n this.app.get('/step4-validated', async (_, res) => {\n res.send(await this.renderTemplate('step4-validated'));\n });\n this.app.get('/step4-validated-selfhosted', async (_, res) => {\n res.send(await this.renderTemplate('step4-validated-selfhosted'));\n });\n }\n \n}\n","import express from 'express';\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nexport class MapController {\n private router: express.Router;\n private app: express.Application;\n\n constructor(app: express.Application) {\n this.app = app;\n this.router = express.Router();\n this.setupRoutes();\n // Register the router on the application with the \"/maps\" prefix\n this.app.use('/maps', this.router);\n }\n\n /**\n * Setup the routes for the map controller\n * @returns void\n */\n private setupRoutes() {\n // Route to retrieve the list of maps with their properties\n this.router.get('/list', async (_, res) => {\n try {\n const mapsDir = './';\n const maps = await this.getMapsWithProperties(mapsDir);\n res.json(maps);\n } catch (error) {\n console.error('Error getting maps list:', error);\n res.status(500).json({ error: 'Error getting maps list' });\n }\n });\n }\n\n /**\n * Get the list of maps with their properties\n * @param dir - The directory to search for maps\n * @param baseDir - The base directory to use for relative paths\n * @returns The list of maps with their properties\n */\n private async getMapsWithProperties(dir: string, baseDir: string = dir): Promise<any[]> {\n let files = await fs.promises.readdir(dir, { withFileTypes: true });\n const maps: any[] = [];\n\n for (const file of files) {\n const fullPath = path.join(dir, file.name);\n\n // Exclude the \"dist\" folder\n if(file.name === 'dist') continue;\n\n if (file.isDirectory()) {\n // Recursively search subdirectories\n const subMaps = await this.getMapsWithProperties(fullPath, baseDir);\n maps.push(...subMaps);\n } else if (file.name.endsWith('.tmj')) {\n try {\n // Read and parse TMJ file\n const tmjContent = await fs.promises.readFile(fullPath, 'utf-8');\n const tmjData = JSON.parse(tmjContent);\n\n // Extract properties\n const properties = tmjData.properties || [];\n const findProperty = (key: string) => {\n const item = properties.find((p: any) => p.name === key);\n return item ? item.value : null;\n };\n\n // Get file stats for size and date\n const stats = await fs.promises.stat(fullPath);\n const fileSizeInMB = (stats.size / (1024 * 1024)).toFixed(2);\n const lastModified = stats.mtime;\n\n // Get relative path\n const relativePath = path.relative(baseDir, fullPath).replace(/\\\\/g, '/');\n\n // Extract filename without extension\n const filename = path.basename(file.name, '.tmj');\n\n maps.push({\n path: relativePath,\n filename: filename,\n mapName: findProperty('mapName') || filename,\n mapImage: findProperty('mapImage') || null,\n mapDescription: findProperty('mapDescription') || '',\n mapCopyright: findProperty('mapCopyright') || '',\n size: fileSizeInMB,\n lastModified: lastModified.toISOString(),\n lastModifiedFormatted: lastModified.toLocaleDateString('fr-FR', {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n })\n });\n } catch (error) {\n console.error(`Error reading TMJ file ${fullPath}:`, error);\n }\n }\n }\n\n return maps;\n }\n}\n","import express from 'express';\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execAsync = promisify(exec);\n\n/** Metadata returned by map-storage for each map (WAM file). */\nexport interface MapStorageMetadata {\n copyright?: string;\n description?: string;\n name?: string;\n thumbnail?: string;\n}\n\n/** Single map entry returned by map-storage GET /maps/ (value in the map). */\nexport interface MapStorageEntry {\n mapUrl: string;\n wamFileUrl?: string;\n metadata?: MapStorageMetadata;\n}\n\n/** Response shape: Map<wamfile, { mapUrl, metadata }>. In JSON this is a plain object. */\nexport interface MapStorageListResponse {\n [wamFile: string]: MapStorageEntry;\n}\n\n/** Hydrated map item returned by our API to the frontend. */\nexport interface MapListItem {\n wamFileUrl: string;\n filename: string;\n mapName: string | null;\n mapDescription?: string;\n mapCopyright?: string;\n mapImage: string | null;\n mapUrl: string;\n}\n\n/**\n * Converts the map-storage response (Map<wamfile, entry>) into a list of MapListItem.\n */\nexport function hydrateMapStorageList(\n raw: MapStorageListResponse,\n mapStorageBaseUrl: string\n): MapListItem[] {\n const list: MapListItem[] = [];\n const baseUrl = mapStorageBaseUrl.replace(/\\/$/, '');\n\n for (const [wamFile, entry] of Object.entries(raw)) {\n if (!entry || typeof entry !== 'object') continue;\n\n const rawWamFileUrl = entry.wamFileUrl ?? wamFile;\n const wamFileUrlNormalized = rawWamFileUrl.startsWith('http')\n ? new URL(rawWamFileUrl).pathname.replace(/^\\//, '')\n : rawWamFileUrl.replace(/^\\//, '');\n\n const filename = wamFileUrlNormalized.split('/').pop() ?? wamFileUrlNormalized;\n const nameFromFile = filename.replace(/\\.(tmj|wam)$/i, '');\n\n const meta = entry.metadata ?? {};\n const mapUrl = entry.mapUrl ?? (entry as unknown as { mapUrl?: string }).mapUrl ?? '';\n\n let mapImage: string | null = null;\n if (meta.thumbnail) {\n if (meta.thumbnail.startsWith('http')) {\n mapImage = meta.thumbnail;\n } else {\n const thumbFile = meta.thumbnail.replace(/^\\//, '');\n const wamDir = wamFileUrlNormalized.includes('/')\n ? wamFileUrlNormalized.replace(/\\/[^/]*$/, '')\n : '';\n const thumbPath = wamDir ? `${wamDir}/${thumbFile}` : thumbFile;\n mapImage = `${baseUrl}/${thumbPath}`;\n }\n }\n\n list.push({\n wamFileUrl: wamFileUrlNormalized,\n filename,\n mapName: meta.name ?? nameFromFile,\n mapDescription: meta.description,\n mapCopyright: meta.copyright,\n mapImage,\n mapUrl: mapUrl.startsWith('http') ? mapUrl : `${baseUrl}/${mapUrl.replace(/^\\//, '')}`,\n });\n }\n\n return list;\n}\n\nexport class UploaderController {\n private router: express.Router;\n private app: express.Application;\n\n constructor(app: express.Application) {\n this.app = app;\n this.router = express.Router();\n this.setupMiddleware();\n this.setupRoutes();\n // Register the router on the application with the \"/uploader\" prefix\n this.app.use('/uploader', this.router);\n }\n\n private setupMiddleware() {\n // Middleware to parse JSON bodies\n this.router.use(express.json());\n }\n\n private setupRoutes() {\n // Route to configure MAP_STORAGE mode\n this.router.post('/configure', async (req, res) => {\n try {\n const { mapStorageUrl, mapStorageApiKey, uploadDirectory } = req.body;\n\n // Validate required fields\n if (!mapStorageUrl || !mapStorageApiKey || !uploadDirectory) {\n return res.status(400).json({\n error: 'Missing required fields',\n required: ['mapStorageUrl', 'mapStorageApiKey', 'uploadDirectory']\n });\n }\n\n // Create or update .env.secret file\n await this.createEnvSecretFile({\n mapStorageUrl,\n mapStorageApiKey,\n uploadDirectory\n });\n\n return res.json({\n success: true,\n message: 'Configuration updated successfully'\n });\n } catch (error) {\n console.error('Error configuring uploader:', error);\n return res.status(500).json({\n error: 'Error configuring uploader',\n message: error instanceof Error ? error.message : 'Unknown error'\n });\n }\n });\n\n // Route to get current configuration status\n this.router.get('/status', async (_, res) => {\n try {\n const envSecretPath = path.join(process.cwd(), 'src/.env.secret');\n\n const hasSecretFile = await fs.promises.access(envSecretPath)\n .then(() => true)\n .catch(() => false);\n\n let secretConfig: {\n mapStorageUrl: string | null;\n mapStorageApiKey: string | null;\n uploadDirectory: string | null;\n } | null = null;\n if (hasSecretFile) {\n const secretContent = await fs.promises.readFile(envSecretPath, 'utf-8');\n const mapStorageUrl = secretContent.match(/MAP_STORAGE_URL=(.+)/)?.[1]?.trim();\n const mapStorageApiKey = secretContent.match(/MAP_STORAGE_API_KEY=(.+)/)?.[1]?.trim();\n const uploadDirectory = secretContent.match(/UPLOAD_DIRECTORY=(.+)/)?.[1]?.trim();\n\n secretConfig = {\n mapStorageUrl: mapStorageUrl || null,\n mapStorageApiKey: mapStorageApiKey || null, // Hide the actual key\n uploadDirectory: uploadDirectory || null\n };\n }\n\n res.json({\n hasSecretFile,\n secretConfig\n });\n } catch (error) {\n console.error('Error getting uploader status:', error);\n res.status(500).json({\n error: 'Error getting uploader status',\n message: error instanceof Error ? error.message : 'Unknown error'\n });\n }\n });\n\n // Route to get list of maps from map-storage (for self-hosted step4)\n this.router.get('/maps-storage-list', async (_, res) => {\n try {\n const envSecretPath = path.join(process.cwd(), '.env.secret');\n const hasSecretFile = await fs.promises.access(envSecretPath)\n .then(() => true)\n .catch(() => false);\n\n if (!hasSecretFile) {\n return res.status(400).json({\n error: 'Configuration not found',\n message: 'Please configure the upload settings first.'\n });\n }\n\n const secretContent = await fs.promises.readFile(envSecretPath, 'utf-8');\n const mapStorageUrl = secretContent.match(/MAP_STORAGE_URL=(.+)/)?.[1]?.trim();\n const mapStorageApiKey = secretContent.match(/MAP_STORAGE_API_KEY=(.+)/)?.[1]?.trim();\n\n if (!mapStorageUrl || !mapStorageApiKey) {\n return res.status(400).json({\n error: 'Missing map-storage configuration',\n message: 'MAP_STORAGE_URL and MAP_STORAGE_API_KEY must be set in .env.secret.'\n });\n }\n\n const baseUrl = mapStorageUrl.replace(/\\/$/, '');\n const listUrl = `${baseUrl}/maps/`;\n\n const response = await fetch(listUrl, {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${mapStorageApiKey}`,\n 'Content-Type': 'application/json'\n }\n });\n\n if (!response.ok) {\n const text = await response.text();\n console.error('Map-storage list error:', response.status, text);\n return res.status(response.status).json({\n error: 'Map-storage request failed',\n message: response.status === 401\n ? 'Invalid API key. Check MAP_STORAGE_API_KEY in your .env.secret.'\n : `Map-storage returned ${response.status}: ${text.slice(0, 200)}`\n });\n }\n\n const data = await response.json();\n // Map-storage returns Map<wamfile, { mapUrl, metadata }> (as a plain object in JSON)\n const raw = typeof data === 'object' && data !== null ? data : {};\n const rawMap: MapStorageListResponse = !Array.isArray(raw) && typeof raw.maps === 'object' && raw.maps !== null\n ? (raw.maps as MapStorageListResponse)\n : !Array.isArray(raw)\n ? (raw as MapStorageListResponse)\n : {};\n const maps = hydrateMapStorageList(rawMap, baseUrl);\n const playBaseUrl = secretContent.match(/PLAY_BASE_URL=(.+)/)?.[1]?.trim() || null;\n return res.json({ maps, mapStorageUrl: baseUrl, playBaseUrl });\n } catch (error) {\n console.error('Error fetching maps from map-storage:', error);\n return res.status(500).json({\n error: 'Error fetching maps list',\n message: error instanceof Error ? error.message : 'Unknown error'\n });\n }\n });\n\n // Route to upload map\n this.router.post('/upload', async (_, res) => {\n try {\n // Verify that configuration exists\n const envSecretPath = path.join(process.cwd(), '.env.secret');\n\n // Check if .env.secret exists\n const hasSecretFile = await fs.promises.access(envSecretPath)\n .then(() => true)\n .catch(() => false);\n\n if (!hasSecretFile) {\n return res.status(400).json({\n error: 'Configuration not found',\n message: 'Please configure the upload settings first using /uploader/configure'\n });\n }\n\n // Execute upload\n await this.runUpload();\n\n return res.json({\n success: true,\n message: 'Map uploaded successfully'\n });\n } catch (error) {\n console.error('Error uploading map:', error);\n return res.status(500).json({\n error: 'Error uploading map',\n message: error instanceof Error ? error.message : 'Unknown error'\n });\n }\n });\n }\n\n private async runUpload(): Promise<void> {\n const projectRoot = process.cwd();\n \n try {\n // Execute npm run upload-only\n // The command will read environment variables from .env and .env.secret\n const { stdout, stderr } = await execAsync('npm run upload', {\n cwd: projectRoot,\n env: {\n ...process.env,\n // Ensure we're using the current process environment\n NODE_ENV: process.env.NODE_ENV || 'development'\n },\n maxBuffer: 10 * 1024 * 1024 // 10MB buffer for output\n });\n\n if (stderr && !stderr.includes('warning')) {\n console.warn('Upload stderr:', stderr);\n }\n \n console.info('Upload stdout:', stdout);\n console.info('Upload completed successfully');\n } catch (error) {\n console.error('Error executing upload-only:', error);\n throw error;\n }\n }\n\n private async createEnvSecretFile(config: {\n mapStorageUrl: string;\n mapStorageApiKey: string;\n uploadDirectory: string;\n }): Promise<void> {\n const envSecretPath = path.join(process.cwd(), '.env.secret');\n\n // Create the .env.secret file with the provided configuration\n const secretContent = `# Secret configuration file for MAP_STORAGE upload mode\n# This file is not committed to git (see .gitignore)\n\nMAP_STORAGE_URL=${config.mapStorageUrl}\nMAP_STORAGE_API_KEY=${config.mapStorageApiKey}\nUPLOAD_DIRECTORY=${config.uploadDirectory}\n`;\n\n await fs.promises.writeFile(envSecretPath, secretContent, 'utf-8');\n }\n}\n","import express from 'express';\nimport * as path from \"node:path\";\nimport * as fs from \"node:fs\";\nimport cors from 'cors';\nimport { getCoreRoot } from './getCoreRoot.js';\nimport { FrontController } from './controllers/FrontController.js';\nimport { MapController } from './controllers/MapController.js';\nimport { UploaderController } from './controllers/UploaderController.js';\n\nconst app = express();\n\nconst corsOptions = {\n credentials: true, // Allow sending cookies\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],\n allowedHeaders: [\n 'Content-Type',\n 'Authorization',\n 'X-Requested-With',\n 'Accept',\n 'Origin',\n 'Access-Control-Request-Method',\n 'Access-Control-Request-Headers'\n ],\n exposedHeaders: ['Content-Length', 'Content-Type'],\n maxAge: 86400, // Cache the OPTIONS requests for 24 hours\n};\n\n// Apply the CORS middleware\n// The CORS middleware automatically handles the OPTIONS requests (preflight)\napp.use(cors(corsOptions));\n\n// Parse JSON bodies\napp.use(express.json());\n\n// Configure the static assets for Express\nconst staticOptions = {\n maxAge: '1d', // Cache the files for 1 day\n etag: true, // Enable ETag for cache validation\n lastModified: true, // Enable Last-Modified header\n};\n\n// Serve dist/assets FIRST with explicit MIME type configuration\n// This ensures compiled JavaScript files from getMapsScripts are served correctly\n// This route must be before express.static('.') to take precedence\napp.use('/assets', express.static(path.join(process.cwd(), 'dist', 'assets'), staticOptions));\n// Serve the public folder from core (project root or package root for easy updates)\napp.use('/public', express.static(path.join(getCoreRoot(), 'public'), staticOptions));\n// Serve the tilesets folder with a longer cache (rarely modified)\napp.use('/tilesets', express.static(path.join(process.cwd(), 'tilesets'), {\n maxAge: '7d',\n etag: true,\n lastModified: true,\n}));\n\n// Middleware to exclude /src from express.static - let Vite handle TypeScript transformation\n// VitePluginNode will automatically add Vite middleware that transforms TypeScript files\nconst staticMiddleware = express.static('.', staticOptions);\n\n// Middleware to transform and serve TypeScript files as JavaScript\n// This bundles the file with its dependencies to resolve npm imports\napp.use('/src', async (req, res, next) => {\n // Only handle .ts and .tsx files - transform them to JavaScript\n if (req.path.endsWith('.ts') || req.path.endsWith('.tsx')) {\n try {\n // req.path includes /src/, so we need to join it correctly\n const filePath = path.join(process.cwd(), 'src', req.path.startsWith('/') ? req.path.slice(1) : req.path);\n \n // Check if file exists\n if (!fs.existsSync(filePath)) {\n return res.status(404).send('File not found');\n }\n \n // Use dynamic import to get esbuild (available via Vite)\n const esbuild = await import('esbuild');\n \n // Bundle the TypeScript file with its dependencies\n // This resolves npm imports like @workadventure/scripting-api-extra\n const result = await esbuild.build({\n entryPoints: [filePath],\n bundle: true,\n format: 'esm',\n target: 'esnext',\n write: false,\n platform: 'browser',\n sourcemap: false,\n // Externalize WorkAdventure global API (available in the browser)\n external: ['WA'],\n });\n \n res.setHeader('Content-Type', 'application/javascript; charset=utf-8');\n return res.send(result.outputFiles[0].text);\n } catch (error) {\n console.error('Error transforming TypeScript file:', error);\n return next(error);\n }\n }\n // For non-TypeScript files in /src, pass to next middleware\n next();\n});\n\n// Serve static files, but skip /src (handled above)\napp.use((req, res, next) => {\n // Skip /src requests - they are handled by the transformation middleware above\n if (req.path.startsWith('/src/')) {\n return next(); // Let the transformation middleware handle it or pass to Vite\n }\n // For other files, use express.static\n staticMiddleware(req, res, next);\n});\n\nconst controllers = [\n new MapController(app),\n new FrontController(app),\n new UploaderController(app),\n];\n\n// Verify and log all controllers created\ncontrollers.forEach(controller => {\n console.info(`Controller started: ${controller.constructor.name}`);\n});\n\nexport default app;\n// Export for VitePluginNode compatibility\nexport const viteNodeApp = app;\n"],"names":["path","fileURLToPath","fs","app","coreRoot","promisify","exec"],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@workadventure/map-starter-kit-core",
3
- "version": "0.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Core app, HTML pages and static assets for the WorkAdventure Map Starter Kit. Update this package to get new UI and server features without touching your maps or config.",
5
- "main": "src/app.ts",
5
+ "main": "src/server.ts",
6
6
  "scripts": {
7
7
  "dev": "vite",
8
- "build": "tsc && vite build"
8
+ "build": "tsc && vite build && node -e \"require('fs').copyFileSync('types/server.d.ts','dist/server.d.ts')\""
9
9
  },
10
10
  "repository": {
11
11
  "type": "git",
@@ -24,7 +24,26 @@
24
24
  },
25
25
  "homepage": "https://github.com/workadventure/map-starter-kit-core#readme",
26
26
  "release": {
27
- "branches": ["main", "master"]
27
+ "branches": [
28
+ "main",
29
+ "master"
30
+ ]
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "exports": {
37
+ ".": {
38
+ "types": "./dist/server.d.ts",
39
+ "import": "./dist/server.js",
40
+ "require": "./dist/server.js"
41
+ },
42
+ "./dist/server.js": {
43
+ "types": "./dist/server.d.ts",
44
+ "import": "./dist/server.js",
45
+ "require": "./dist/server.js"
46
+ }
28
47
  },
29
48
  "devDependencies": {
30
49
  "@types/cors": "^2.8.19",