@roster-lock/match-agent 0.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.
- package/LICENSE.md +11 -0
- package/dist/authentication.js +53 -0
- package/dist/authentication.js.map +1 -0
- package/dist/config/constants.js +12 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/findFile.js +32 -0
- package/dist/config/findFile.js.map +1 -0
- package/dist/config/index.js +29 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/manage.js +41 -0
- package/dist/config/manage.js.map +1 -0
- package/dist/cors.js +20 -0
- package/dist/cors.js.map +1 -0
- package/dist/editor-support/index.js +247 -0
- package/dist/editor-support/index.js.map +1 -0
- package/dist/handle-room/version-1/file-routes.js +53 -0
- package/dist/handle-room/version-1/file-routes.js.map +1 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/MultiAbort.js +76 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/MultiAbort.js.map +1 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/ensurePieceExists.js +218 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/ensurePieceExists.js.map +1 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/getVersions.js +18 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/getVersions.js.map +1 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/index.js +16 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/index.js.map +1 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/schema.js +370 -0
- package/dist/handle-room/version-1/globals/FolderDB/SQLFolderDB/schema.js.map +1 -0
- package/dist/handle-room/version-1/globals/FolderDB/index.js +18 -0
- package/dist/handle-room/version-1/globals/FolderDB/index.js.map +1 -0
- package/dist/handle-room/version-1/globals/FolderDB/types.js +3 -0
- package/dist/handle-room/version-1/globals/FolderDB/types.js.map +1 -0
- package/dist/handle-room/version-1/globals/Room/WebsocketRoom.js +95 -0
- package/dist/handle-room/version-1/globals/Room/WebsocketRoom.js.map +1 -0
- package/dist/handle-room/version-1/globals/Room/index.js +18 -0
- package/dist/handle-room/version-1/globals/Room/index.js.map +1 -0
- package/dist/handle-room/version-1/globals/Room/room.js +3 -0
- package/dist/handle-room/version-1/globals/Room/room.js.map +1 -0
- package/dist/handle-room/version-1/globals/index.js +20 -0
- package/dist/handle-room/version-1/globals/index.js.map +1 -0
- package/dist/handle-room/version-1/globals/types.js +3 -0
- package/dist/handle-room/version-1/globals/types.js.map +1 -0
- package/dist/handle-room/version-1/handleDownloads/DownloadTracker.js +83 -0
- package/dist/handle-room/version-1/handleDownloads/DownloadTracker.js.map +1 -0
- package/dist/handle-room/version-1/handleDownloads/index.js +35 -0
- package/dist/handle-room/version-1/handleDownloads/index.js.map +1 -0
- package/dist/handle-room/version-1/handleDownloads/types.js +3 -0
- package/dist/handle-room/version-1/handleDownloads/types.js.map +1 -0
- package/dist/handle-room/version-1/handleRoomSelections/encryption.js +21 -0
- package/dist/handle-room/version-1/handleRoomSelections/encryption.js.map +1 -0
- package/dist/handle-room/version-1/handleRoomSelections/random.js +12 -0
- package/dist/handle-room/version-1/handleRoomSelections/random.js.map +1 -0
- package/dist/handle-room/version-1/index.js +28 -0
- package/dist/handle-room/version-1/index.js.map +1 -0
- package/dist/handle-room/version-1/piece-sort.js +71 -0
- package/dist/handle-room/version-1/piece-sort.js.map +1 -0
- package/dist/handle-room/version-1/room-handler-bridge/exchange-and-download-selections.js +89 -0
- package/dist/handle-room/version-1/room-handler-bridge/exchange-and-download-selections.js.map +1 -0
- package/dist/handle-room/version-1/room-handler-bridge/http-handler.js +19 -0
- package/dist/handle-room/version-1/room-handler-bridge/http-handler.js.map +1 -0
- package/dist/handle-room/version-1/room-handler-bridge/steps.js +170 -0
- package/dist/handle-room/version-1/room-handler-bridge/steps.js.map +1 -0
- package/dist/handle-room/version-1/room-handler-bridge/ws-handler.js +28 -0
- package/dist/handle-room/version-1/room-handler-bridge/ws-handler.js.map +1 -0
- package/dist/handle-room/version-1/schema/count.js +16 -0
- package/dist/handle-room/version-1/schema/count.js.map +1 -0
- package/dist/handle-room/version-1/schema/lock.js +46 -0
- package/dist/handle-room/version-1/schema/lock.js.map +1 -0
- package/dist/handle-room/version-1/schema/selected.js +13 -0
- package/dist/handle-room/version-1/schema/selected.js.map +1 -0
- package/dist/handle-room/version-1/select.js +94 -0
- package/dist/handle-room/version-1/select.js.map +1 -0
- package/dist/index.js +180 -0
- package/dist/index.js.map +1 -0
- package/dist/server.js +88 -0
- package/dist/server.js.map +1 -0
- package/dist/utils/fs.js +32 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/http-router.js +49 -0
- package/dist/utils/http-router.js.map +1 -0
- package/dist/utils/pagination.js +23 -0
- package/dist/utils/pagination.js.map +1 -0
- package/dist/utils/websocket-router.js +15 -0
- package/dist/utils/websocket-router.js.map +1 -0
- package/package.json +66 -0
- package/src/authentication.ts +48 -0
- package/src/config/constants.ts +7 -0
- package/src/config/findFile.ts +34 -0
- package/src/config/index.ts +17 -0
- package/src/config/manage.ts +48 -0
- package/src/cors.ts +23 -0
- package/src/editor-support/index.ts +289 -0
- package/src/handle-room/version-0/piece-download/availableGamePiece/index.ts +109 -0
- package/src/handle-room/version-0/piece-download/availableGamePiece/isUpToDate.ts +78 -0
- package/src/handle-room/version-0/piece-download/downloadPieceAssets/downloadSingleAsset.ts +129 -0
- package/src/handle-room/version-0/piece-download/downloadPieceAssets/example.ts +116 -0
- package/src/handle-room/version-0/piece-download/downloadPieceAssets/index.ts +144 -0
- package/src/handle-room/version-0/piece-download/downloadPieceAssets/types.ts +32 -0
- package/src/handle-room/version-0/piece-download/downloadPieceAssets/validateAssetFile.ts +54 -0
- package/src/handle-room/version-0/piece-download/index.ts +5 -0
- package/src/handle-room/version-0/piece-selection/constants.ts +39 -0
- package/src/handle-room/version-0/piece-selection/handleRoomSelections.ts +202 -0
- package/src/handle-room/version-0/piece-selection/index.ts +31 -0
- package/src/handle-room/version-0/piece-selection/roomErrors.ts +25 -0
- package/src/handle-room/version-0/piece-selection/steps/encrypton.ts +70 -0
- package/src/handle-room/version-0/piece-selection/steps/final-selection.ts +72 -0
- package/src/handle-room/version-0/piece-selection/steps/player-selection.ts +100 -0
- package/src/handle-room/version-1/constants.ts +44 -0
- package/src/handle-room/version-1/file-routes.ts +68 -0
- package/src/handle-room/version-1/globals/FolderDB/SQLFolderDB/MultiAbort.ts +83 -0
- package/src/handle-room/version-1/globals/FolderDB/SQLFolderDB/ensurePieceExists.ts +317 -0
- package/src/handle-room/version-1/globals/FolderDB/SQLFolderDB/getVersions.ts +31 -0
- package/src/handle-room/version-1/globals/FolderDB/SQLFolderDB/index.ts +13 -0
- package/src/handle-room/version-1/globals/FolderDB/SQLFolderDB/schema.ts +547 -0
- package/src/handle-room/version-1/globals/FolderDB/SQLFolderDB/types.ts +6 -0
- package/src/handle-room/version-1/globals/FolderDB/index.ts +3 -0
- package/src/handle-room/version-1/globals/FolderDB/types.ts +72 -0
- package/src/handle-room/version-1/globals/Room/WebsocketRoom.ts +118 -0
- package/src/handle-room/version-1/globals/Room/index.ts +3 -0
- package/src/handle-room/version-1/globals/Room/room.ts +8 -0
- package/src/handle-room/version-1/globals/index.ts +4 -0
- package/src/handle-room/version-1/globals/types.ts +7 -0
- package/src/handle-room/version-1/handleDownloads/DownloadTracker.ts +98 -0
- package/src/handle-room/version-1/handleDownloads/index.ts +41 -0
- package/src/handle-room/version-1/handleDownloads/types.ts +9 -0
- package/src/handle-room/version-1/handleRoomSelections/encryption.ts +29 -0
- package/src/handle-room/version-1/handleRoomSelections/random.ts +9 -0
- package/src/handle-room/version-1/index.ts +33 -0
- package/src/handle-room/version-1/piece-sort.ts +96 -0
- package/src/handle-room/version-1/room-handler-bridge/exchange-and-download-selections.ts +125 -0
- package/src/handle-room/version-1/room-handler-bridge/http-handler.ts +16 -0
- package/src/handle-room/version-1/room-handler-bridge/server.pseudo.ts +85 -0
- package/src/handle-room/version-1/room-handler-bridge/steps.ts +255 -0
- package/src/handle-room/version-1/room-handler-bridge/ws-handler.ts +30 -0
- package/src/handle-room/version-1/room-handler-state/RoomState.ts +132 -0
- package/src/handle-room/version-1/room-handler-state/bind-to-websocket.ts +93 -0
- package/src/handle-room/version-1/room-handler-state/handleRoomSelections.ts +71 -0
- package/src/handle-room/version-1/room-handler-state/handleRoomWithErrors.ts +55 -0
- package/src/handle-room/version-1/room-handler-state/roomErrors.ts +35 -0
- package/src/handle-room/version-1/room-handler-state/user-selection.ts +98 -0
- package/src/handle-room/version-1/schema/count.ts +13 -0
- package/src/handle-room/version-1/schema/lock.ts +47 -0
- package/src/handle-room/version-1/schema/selected.ts +14 -0
- package/src/handle-room/version-1/select.ts +130 -0
- package/src/handle-room/version-1/validateUnknown.ts +11 -0
- package/src/index.old.ts +71 -0
- package/src/index.ts +231 -0
- package/src/server.ts +85 -0
- package/src/utils/fs.ts +43 -0
- package/src/utils/http-router.ts +55 -0
- package/src/utils/pagination.ts +17 -0
- package/src/utils/websocket-router.ts +23 -0
- package/tests/integration/editor-pieces-search.test.ts +147 -0
- package/tests/integration/game-complete.test.ts +72 -0
- package/tests/integration/handle-full-selection.test.ts +143 -0
- package/tests/integration/helpers/bridge.ts +22 -0
- package/tests/integration/helpers/fakeFolderDB.ts +37 -0
- package/tests/integration/helpers/fakePluginRuntime.ts +46 -0
- package/tests/integration/helpers/lockConfig.ts +71 -0
- package/tests/integration/helpers/make-tar-gz.ts +41 -0
- package/tests/integration/helpers/piece.ts +98 -0
- package/tests/integration/helpers/plugin-dir.ts +26 -0
- package/tests/integration/helpers/room.ts +42 -0
- package/tests/integration/helpers/server.ts +51 -0
- package/tests/integration/helpers/validLockConfig.ts +80 -0
- package/tests/integration/piece-download-and-list.test.ts +194 -0
- package/tests/integration/piece-ensure-ws.test.ts +256 -0
- package/tests/integration/piece-files.test.ts +139 -0
- package/tests/integration/piece-sort-list.test.ts +113 -0
- package/tests/integration/protocol.test.ts +129 -0
- package/tests/integration/root-and-auth.test.ts +100 -0
- package/tests/integration/sync-dl.test.ts +62 -0
- package/tests/tsconfig.json +14 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +10 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MatchAgentServer = void 0;
|
|
4
|
+
const http_1 = require("http");
|
|
5
|
+
const ws_1 = require("ws");
|
|
6
|
+
const websocket_router_1 = require("./utils/websocket-router");
|
|
7
|
+
const http_router_1 = require("./utils/http-router");
|
|
8
|
+
class MatchAgentServer {
|
|
9
|
+
httpServer;
|
|
10
|
+
wss;
|
|
11
|
+
wsRouter = new websocket_router_1.WebSocketRouter();
|
|
12
|
+
httpRouter = new http_router_1.HTTPRouter();
|
|
13
|
+
constructor(debug = true) {
|
|
14
|
+
this.httpServer = new http_1.Server();
|
|
15
|
+
this.wss = new ws_1.WebSocketServer({ noServer: true });
|
|
16
|
+
this.httpServer.on('upgrade', async (request, socket, head) => {
|
|
17
|
+
const context = await (async () => {
|
|
18
|
+
try {
|
|
19
|
+
if (!request.url)
|
|
20
|
+
throw new Error("No URL");
|
|
21
|
+
const url = new URL(request.url, "ws://localhost");
|
|
22
|
+
const ws = await handleUpgrade(this.wss, request, socket, head);
|
|
23
|
+
return { ws, req: request };
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
console.log("Failed to upgrade connection", e);
|
|
27
|
+
socket.destroy();
|
|
28
|
+
throw e;
|
|
29
|
+
}
|
|
30
|
+
})();
|
|
31
|
+
this.wsRouter.handleRequest(context, (err) => {
|
|
32
|
+
debug && console.log("WS Error:", err);
|
|
33
|
+
context.ws.terminate();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
this.httpServer.on('request', (req, res) => {
|
|
37
|
+
this.httpRouter.handleRequest({ req, res }, (err) => {
|
|
38
|
+
debug && console.log("HTTP Error:", err);
|
|
39
|
+
if (res.writableEnded) {
|
|
40
|
+
debug && console.warn("Router threw error and response ended");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (res.headersSent) {
|
|
44
|
+
debug && console.warn("Router threw error and headers already sent");
|
|
45
|
+
res.destroy();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const error = (() => {
|
|
49
|
+
if (err instanceof http_router_1.HTTPError)
|
|
50
|
+
return err;
|
|
51
|
+
if (!err) {
|
|
52
|
+
return new http_router_1.HTTPError(404, "Not Found");
|
|
53
|
+
}
|
|
54
|
+
else if (typeof err === "string") {
|
|
55
|
+
return new http_router_1.HTTPError(500, err);
|
|
56
|
+
}
|
|
57
|
+
else if (err instanceof Error) {
|
|
58
|
+
return new http_router_1.HTTPError(500, err.message);
|
|
59
|
+
}
|
|
60
|
+
else if (typeof err !== "object" || err === null || Array.isArray(err)) {
|
|
61
|
+
return new http_router_1.HTTPError(500, "Unknown Error");
|
|
62
|
+
}
|
|
63
|
+
return new http_router_1.HTTPError("statusCode" in err && typeof err.statusCode === "number" ? err.statusCode : 500, "message" in err && typeof err.message === "string" ? err.message : "Unknown Error");
|
|
64
|
+
})();
|
|
65
|
+
res.writeHead(error.statusCode, { "Content-Type": "application/json" });
|
|
66
|
+
res.end(JSON.stringify({
|
|
67
|
+
error: error.message,
|
|
68
|
+
context: error.context,
|
|
69
|
+
}));
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
listen(...args) {
|
|
74
|
+
return this.httpServer.listen(...args);
|
|
75
|
+
}
|
|
76
|
+
close(...args) {
|
|
77
|
+
return this.httpServer.close(...args);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.MatchAgentServer = MatchAgentServer;
|
|
81
|
+
function handleUpgrade(wss, request, socket, head) {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
wss.handleUpgrade(request, socket, head, function done(ws) {
|
|
84
|
+
resolve(ws);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/fs.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFilesFromFolder = getFilesFromFolder;
|
|
4
|
+
exports.mimeTypeFor = mimeTypeFor;
|
|
5
|
+
const promises_1 = require("fs/promises");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const mime_types_1 = require("mime-types");
|
|
8
|
+
async function* getFilesFromFolder(rootPath, relative = "./") {
|
|
9
|
+
for (const file of await (0, promises_1.readdir)((0, path_1.join)(rootPath, relative))) {
|
|
10
|
+
const stat = await (0, promises_1.stat)((0, path_1.join)(rootPath, relative, file));
|
|
11
|
+
if (stat.isDirectory()) {
|
|
12
|
+
yield* getFilesFromFolder(rootPath, (0, path_1.join)(relative, file));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
yield (0, path_1.join)(relative, file).split(path_1.sep).join("/");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const WEB_SAFE_EXTENSIONS = new Set([
|
|
20
|
+
"png", "jpg", "jpeg", "gif", "webp", "avif", "bmp", "ico", "svg",
|
|
21
|
+
"mp3", "wav", "ogg", "oga", "m4a", "flac", "aac",
|
|
22
|
+
"mp4", "webm", "ogv",
|
|
23
|
+
"woff", "woff2", "ttf", "otf",
|
|
24
|
+
"json", "txt", "csv", "xml", "html", "css",
|
|
25
|
+
]);
|
|
26
|
+
function mimeTypeFor(filePath) {
|
|
27
|
+
const ext = (0, path_1.extname)(filePath).slice(1).toLowerCase();
|
|
28
|
+
if (!WEB_SAFE_EXTENSIONS.has(ext))
|
|
29
|
+
return "application/octet-stream";
|
|
30
|
+
return (0, mime_types_1.lookup)(filePath) || "application/octet-stream";
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":";;;;AAAA,0CAAuD;AACvD,+BAAiE;AACjE,2CAAkD;AAK3C,KAAK,SAAS,CAAC,oBAAoB,QAAgB,EAAE,QAAQ,GAAW,IAAI;IACjF,KAAI,MAAM,IAAI,IAAI,MAAM,IAAA,kBAAO,EAAC,IAAA,WAAQ,EAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,MAAM,IAAA,eAAO,EAAC,IAAA,WAAQ,EAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/D,IAAG,IAAI,CAAC,WAAW,EAAE,EAAC,CAAC;YACrB,KAAK,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAA,WAAQ,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAA;QAC/D,CAAC;aAAM,CAAC;YACN,MAAM,IAAA,WAAQ,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,UAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;AACH,CAAC;AAQD,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAElC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;IAEhE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK;IAEhD,KAAK,EAAE,MAAM,EAAE,KAAK;IAEpB,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK;IAE7B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK;CAC3C,CAAC,CAAC;AAEH,qBAA4B,QAAgB;IAC1C,MAAM,GAAG,GAAG,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACrD,IAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,0BAA0B,CAAC;IACpE,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,IAAI,0BAA0B,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HTTPError = exports.HTTPRouter = void 0;
|
|
4
|
+
exports.jsonBody = jsonBody;
|
|
5
|
+
const utils_1 = require("@roster-lock/utils");
|
|
6
|
+
async function jsonBody(req) {
|
|
7
|
+
const data = await new Promise((resolve, reject) => {
|
|
8
|
+
let data = "";
|
|
9
|
+
req.on("data", (chunk) => { data += chunk; });
|
|
10
|
+
req.on("end", () => { resolve(data); });
|
|
11
|
+
req.on("error", reject);
|
|
12
|
+
});
|
|
13
|
+
return JSON.parse(data);
|
|
14
|
+
}
|
|
15
|
+
class HTTPRouter extends utils_1.GenericRouter {
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
super((request) => new URL(request.req.url || "/", "ws://localhost:80"), (request) => ((request.req.method || "GET").toUpperCase()), config);
|
|
18
|
+
}
|
|
19
|
+
get(path, ...callbacks) {
|
|
20
|
+
return this.addHandler("GET", path, false, ...callbacks);
|
|
21
|
+
}
|
|
22
|
+
query(path, ...callbacks) {
|
|
23
|
+
return this.addHandler("QUERY", path, false, ...callbacks);
|
|
24
|
+
}
|
|
25
|
+
post(path, ...callbacks) {
|
|
26
|
+
return this.addHandler("POST", path, false, ...callbacks);
|
|
27
|
+
}
|
|
28
|
+
put(path, ...callbacks) {
|
|
29
|
+
return this.addHandler("PUT", path, false, ...callbacks);
|
|
30
|
+
}
|
|
31
|
+
patch(path, ...callbacks) {
|
|
32
|
+
return this.addHandler("PATCH", path, false, ...callbacks);
|
|
33
|
+
}
|
|
34
|
+
delete(path, ...callbacks) {
|
|
35
|
+
return this.addHandler("DELETE", path, false, ...callbacks);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.HTTPRouter = HTTPRouter;
|
|
39
|
+
class HTTPError extends Error {
|
|
40
|
+
statusCode;
|
|
41
|
+
context;
|
|
42
|
+
constructor(statusCode, message, context) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.statusCode = statusCode;
|
|
45
|
+
this.context = context;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.HTTPError = HTTPError;
|
|
49
|
+
//# sourceMappingURL=http-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-router.js","sourceRoot":"","sources":["../../src/utils/http-router.ts"],"names":[],"mappings":";;;;AAEA,8CAAmH;AAE5G,KAAK,mBAAmB,GAAoB;IACjD,MAAM,IAAI,GAAW,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAC,EAAE;QACxD,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAC,EAAE,GAAC,IAAI,IAAI,KAAK,CAAA,CAAA,CAAC,CAAC,CAAC;QACzC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAE,EAAE,GAAC,OAAO,CAAC,IAAI,CAAC,CAAA,CAAA,CAAC,CAAC,CAAC;QACnC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAA;IACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAMD,gBAAwB,SAAQ,qBAA0B;IACxD,YAAY,MAAM,GAAkB,EAAE;QACpC,KAAK,CACH,CAAC,OAAO,EAAC,EAAE,CAAA,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,mBAAmB,CAAC,EAC/D,CAAC,OAAO,EAAC,EAAE,CAAA,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,EACxD,MAAM,CACP,CAAC;IACJ,CAAC;IACD,GAAG,CAAC,IAAY,EAAE,GAAG,SAAuD;QAC1E,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;IAC3D,CAAC;IACD,KAAK,CAAC,IAAY,EAAE,GAAG,SAAuD;QAC5E,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,CAAC,IAAY,EAAE,GAAG,SAAuD;QAC3E,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;IAC5D,CAAC;IACD,GAAG,CAAC,IAAY,EAAE,GAAG,SAAuD;QAC1E,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;IAC3D,CAAC;IACD,KAAK,CAAC,IAAY,EAAE,GAAG,SAAuD;QAC5E,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,CAAC,IAAY,EAAE,GAAG,SAAuD;QAC7E,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;IAC9D,CAAC;CACF;;AAED,eAAuB,SAAQ,KAAK;IAEzB,UAAU;IAEV,OAAO;IAHhB,YACS,UAAkB,EACzB,OAAe,EACR,OAAa;QAEpB,KAAK,CAAC,OAAO,CAAC,CAAC;0BAJR,UAAU;uBAEV,OAAO;IAGhB,CAAC;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handlePagination = handlePagination;
|
|
4
|
+
const http_router_1 = require("./http-router");
|
|
5
|
+
function handlePagination(search) {
|
|
6
|
+
const page = handleNumber(search, "page", 0);
|
|
7
|
+
if (page < 0)
|
|
8
|
+
throw new http_router_1.HTTPError(400, "should be greater than or equal to 0", { key: "page" });
|
|
9
|
+
const limit = handleNumber(search, "limit", 200);
|
|
10
|
+
if (limit <= 0)
|
|
11
|
+
throw new http_router_1.HTTPError(400, "should be greater than or equal to 0", { key: "limit" });
|
|
12
|
+
return { page, limit };
|
|
13
|
+
}
|
|
14
|
+
function handleNumber(search, key, defaultValue) {
|
|
15
|
+
const value = search.get(key);
|
|
16
|
+
if (value === null)
|
|
17
|
+
return defaultValue;
|
|
18
|
+
const numValue = Number.parseInt(value);
|
|
19
|
+
if (Number.isNaN(numValue))
|
|
20
|
+
throw new http_router_1.HTTPError(400, "invalid number", { key });
|
|
21
|
+
return numValue;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/utils/pagination.ts"],"names":[],"mappings":";;;AAAA,+CAA0C;AAE1C,0BAAiC,MAAuB;IACtD,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7C,IAAG,IAAI,GAAG,CAAC;QAAE,MAAM,IAAI,uBAAS,CAAC,GAAG,EAAE,sCAAsC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAA;IAC9F,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IACjD,IAAG,KAAK,IAAI,CAAC;QAAE,MAAM,IAAI,uBAAS,CAAC,GAAG,EAAE,sCAAsC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IACjG,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;AACxB,CAAC;AAED,SAAS,YAAY,CAAC,MAAuB,EAAE,GAAW,EAAE,YAAoB;IAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAG,KAAK,KAAK,IAAI;QAAE,OAAO,YAAY,CAAC;IACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,IAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,uBAAS,CAAC,GAAG,EAAE,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/E,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebSocketRouter = void 0;
|
|
4
|
+
const utils_1 = require("@roster-lock/utils");
|
|
5
|
+
const WEBSOCKET_METHOD = "WebSocket";
|
|
6
|
+
class WebSocketRouter extends utils_1.GenericRouter {
|
|
7
|
+
constructor(config = {}) {
|
|
8
|
+
super(({ req }) => new URL(req.url || "/", "ws://localhost:80"), (request) => WEBSOCKET_METHOD, config);
|
|
9
|
+
}
|
|
10
|
+
mount(path, ...callbacks) {
|
|
11
|
+
return this.addHandler(WEBSOCKET_METHOD, path, false, ...callbacks);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.WebSocketRouter = WebSocketRouter;
|
|
15
|
+
//# sourceMappingURL=websocket-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-router.js","sourceRoot":"","sources":["../../src/utils/websocket-router.ts"],"names":[],"mappings":";;;AAGA,8CAAmH;AAEnH,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAKrC,qBAA6B,SAAQ,qBAAwB;IAC3D,YAAY,MAAM,GAAkB,EAAE;QACpC,KAAK,CACH,CAAC,EAAE,GAAG,EAAE,EAAC,EAAE,CAAA,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,mBAAmB,CAAC,EACvD,CAAC,OAAO,EAAC,EAAE,CAAA,gBAAgB,EAC3B,MAAM,CACP,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAY,EAAE,GAAG,SAAqD;QAC1E,OAAO,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;IACtE,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@roster-lock/match-agent",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "To be used in game to ensure all peices are ready",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"roster-lock",
|
|
7
|
+
"game"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://github.com/formula1/roster-lock#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/formula1/roster-lock/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/formula1/roster-lock.git",
|
|
16
|
+
"directory": "core/match-agent"
|
|
17
|
+
},
|
|
18
|
+
"license": "JSON",
|
|
19
|
+
"author": "Sam Tobia",
|
|
20
|
+
"type": "commonjs",
|
|
21
|
+
"main": "dist/index.js",
|
|
22
|
+
"types": "src/index.ts",
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"bin": {
|
|
27
|
+
"rosterlock-match-agent": "dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/async": "^3.2.25",
|
|
31
|
+
"@types/mime-types": "^2.1.4",
|
|
32
|
+
"@types/node": "^22.14.1",
|
|
33
|
+
"@types/webtorrent": "^0.110.0",
|
|
34
|
+
"@types/ws": "^8.18.1",
|
|
35
|
+
"rimraf": "^6.1.3",
|
|
36
|
+
"typescript": "^7.0.2",
|
|
37
|
+
"vitest": "^4.1.5",
|
|
38
|
+
"@roster-lock/dl-archive-tar": "1.0.0",
|
|
39
|
+
"@roster-lock/dl-compression-gzip": "1.0.0",
|
|
40
|
+
"@roster-lock/dl-protocol-http": "1.0.0",
|
|
41
|
+
"@roster-lock/piece-selection-sort-most-used-locally": "1.0.0",
|
|
42
|
+
"@roster-lock/piece-selection-sort-highest-winrate-locally": "1.0.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"ajv": "^8.17.1",
|
|
46
|
+
"async": "^3.2.6",
|
|
47
|
+
"commander": "14.0.3",
|
|
48
|
+
"mime-types": "^2.1.35",
|
|
49
|
+
"node-fetch-commonjs": "^3.3.2",
|
|
50
|
+
"path-to-regexp": "^8.3.0",
|
|
51
|
+
"runtypes": "^7.0.4",
|
|
52
|
+
"tar": "^7.4.3",
|
|
53
|
+
"ulid": "^3.0.2",
|
|
54
|
+
"webtorrent": "^2.6.3",
|
|
55
|
+
"ws": "^8.19.0",
|
|
56
|
+
"zod": "^4.3.5",
|
|
57
|
+
"@roster-lock/plugin-runtime": "^0.1.0",
|
|
58
|
+
"@roster-lock/shared": "0.1.0",
|
|
59
|
+
"@roster-lock/types": "1.0.0",
|
|
60
|
+
"@roster-lock/utils": "1.0.0"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"test": "vitest run",
|
|
64
|
+
"build": "rimraf ./dist && tsc"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { uint8ArrayToHex } from "@roster-lock/utils";
|
|
2
|
+
import { GenericHandlerCallback } from "@roster-lock/utils"
|
|
3
|
+
import { IncomingMessage } from "http";
|
|
4
|
+
import { HTTPError } from "./utils/http-router";
|
|
5
|
+
|
|
6
|
+
export function generateAuthCode(length = 32){
|
|
7
|
+
const bytes = crypto.getRandomValues(new Uint8Array(length));
|
|
8
|
+
return uint8ArrayToHex(bytes);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function authMiddleware(authCode: string): GenericHandlerCallback<{ req: IncomingMessage }>{
|
|
12
|
+
return ({ req }, routeInfo, next)=>{
|
|
13
|
+
const authHeader = req.headers["authorization"];
|
|
14
|
+
if(authHeader){
|
|
15
|
+
if(`Bearer ${authCode}` !== authHeader){
|
|
16
|
+
throw new HTTPError(401, "Invalid User")
|
|
17
|
+
}
|
|
18
|
+
return next()
|
|
19
|
+
}
|
|
20
|
+
const searchParams = new URL(req.url || "/", "http://localhost:80");
|
|
21
|
+
const authSearch = searchParams.searchParams.get("authorization");
|
|
22
|
+
if(authSearch){
|
|
23
|
+
if(authCode !== authSearch){
|
|
24
|
+
throw new HTTPError(401, "Invalid User")
|
|
25
|
+
}
|
|
26
|
+
return next()
|
|
27
|
+
}
|
|
28
|
+
throw new HTTPError(401, "User Required")
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
import { jsonBody, HTTPRequestHandler } from "./utils/http-router";
|
|
33
|
+
import z, { ZodType } from "zod";
|
|
34
|
+
const authCodeSchema: ZodType<{ authCode: string }> = z.object({
|
|
35
|
+
authCode: z.string()
|
|
36
|
+
})
|
|
37
|
+
export const validateAuthCode: (authCode: string)=>HTTPRequestHandler = (authCode)=>{
|
|
38
|
+
return async ({ req, res })=>{
|
|
39
|
+
const body = await jsonBody(req);
|
|
40
|
+
const parsed = authCodeSchema.safeParse(body);
|
|
41
|
+
if(!parsed.success){
|
|
42
|
+
throw new HTTPError(400, "Bad body")
|
|
43
|
+
}
|
|
44
|
+
const isValid = authCode === parsed.data.authCode;
|
|
45
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
46
|
+
res.end(JSON.stringify(isValid));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { join as pathJoin } from "node:path";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const CONFIG_FILE_NAME = "match-agent.json";
|
|
6
|
+
export const DEFAULT_MATCH_CONIFG = pathJoin(os.homedir(), "roster-lock", CONFIG_FILE_NAME);
|
|
7
|
+
export const DEFAULT_PIECE_DIR = pathJoin(os.homedir(), "roster-lock", "pieces");
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { realpath } from "node:fs/promises";
|
|
3
|
+
import { resolve as pathResolve, join as pathJoin } from "path";
|
|
4
|
+
import { CONFIG_FILE_NAME, DEFAULT_MATCH_CONIFG } from "./constants";
|
|
5
|
+
import { configExists } from "./manage";
|
|
6
|
+
|
|
7
|
+
// The bin entry (dist/index.js) is usually reached through a symlink -
|
|
8
|
+
// node_modules/.bin, a pnpm shim, etc. - so argv[1] alone isn't reliable for
|
|
9
|
+
// finding "the folder this executable actually lives in" (e.g. a USB mount).
|
|
10
|
+
// realpath resolves through those symlinks to the real file location.
|
|
11
|
+
export async function getExecutableDir(){
|
|
12
|
+
const scriptPath = process.argv[1];
|
|
13
|
+
if(!scriptPath) return null;
|
|
14
|
+
try {
|
|
15
|
+
return dirname(await realpath(scriptPath));
|
|
16
|
+
}catch(e){
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Finds the config file that governs this run: an explicit --config-file
|
|
22
|
+
// wins; otherwise a config sitting next to the running executable (e.g. on a
|
|
23
|
+
// mounted USB, written by `mount-usb`) takes priority over the per-user home
|
|
24
|
+
// config, so a USB can be picked up on any machine without touching that
|
|
25
|
+
// machine's own defaults.
|
|
26
|
+
export async function findConfigFile(explicitPath?: string): Promise<string> {
|
|
27
|
+
if(explicitPath) return pathResolve(explicitPath);
|
|
28
|
+
const execDir = await getExecutableDir();
|
|
29
|
+
if(execDir){
|
|
30
|
+
const sibling = pathJoin(execDir, CONFIG_FILE_NAME);
|
|
31
|
+
if(await configExists(sibling)) return sibling;
|
|
32
|
+
}
|
|
33
|
+
return DEFAULT_MATCH_CONIFG;
|
|
34
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
export * from "./constants";
|
|
3
|
+
export * from "./manage";
|
|
4
|
+
export * from "./findFile";
|
|
5
|
+
|
|
6
|
+
import { dirname, resolve as pathResolve } from "node:path";
|
|
7
|
+
import { MatchAgentConfig } from "./manage";
|
|
8
|
+
|
|
9
|
+
// Resolves a config's pieceFolder/pluginFolder (relative to the config file's
|
|
10
|
+
// own directory, defaulting to "pieces"/"plugins") to absolute paths.
|
|
11
|
+
export function resolveConfigFolders(configFilePath: string, config: Pick<MatchAgentConfig, "pieceFolder" | "pluginFolder">){
|
|
12
|
+
const configDir = dirname(configFilePath);
|
|
13
|
+
return {
|
|
14
|
+
pieceFolder: pathResolve(configDir, config.pieceFolder ?? "pieces"),
|
|
15
|
+
pluginFolder: pathResolve(configDir, config.pluginFolder ?? "plugins"),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { readFile, writeFile, mkdir, stat } from "node:fs/promises";
|
|
5
|
+
import { DEFAULT_MATCH_CONIFG } from "./constants";
|
|
6
|
+
|
|
7
|
+
const initializeConfig = Promise.resolve().then(()=>{
|
|
8
|
+
return mkdir(dirname(DEFAULT_MATCH_CONIFG), { recursive: true })
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
// pieceFolder/pluginFolder are stored relative to the config file itself, so
|
|
12
|
+
// the same config (and the folders it points to) stay valid no matter where
|
|
13
|
+
// they're mounted - a drive letter on one machine, a different mount point
|
|
14
|
+
// on another. Absent (e.g. the pre-existing home config), they default to
|
|
15
|
+
// "pieces"/"plugins" siblings of the config file.
|
|
16
|
+
export type MatchAgentConfig = { authCode: string, pieceFolder?: string, pluginFolder?: string };
|
|
17
|
+
|
|
18
|
+
import { z, ZodType } from "zod";
|
|
19
|
+
|
|
20
|
+
const matchAgentConfig: ZodType<MatchAgentConfig> = z.object({
|
|
21
|
+
authCode: z.string(),
|
|
22
|
+
pieceFolder: z.string().optional(),
|
|
23
|
+
pluginFolder: z.string().optional(),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export async function getConfig(filePath: string){
|
|
27
|
+
await initializeConfig;
|
|
28
|
+
const contents = await readFile(filePath, "utf8");
|
|
29
|
+
const json = JSON.parse(contents);
|
|
30
|
+
const casted = matchAgentConfig.safeParse(json);
|
|
31
|
+
if(!casted.success) throw new Error("Invalid config");
|
|
32
|
+
return casted.data;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function setConfig(filePath: string, newValues: MatchAgentConfig){
|
|
36
|
+
await initializeConfig;
|
|
37
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
38
|
+
await writeFile(filePath, JSON.stringify(newValues, null, 2) + "\n")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function configExists(filePath: string){
|
|
42
|
+
try {
|
|
43
|
+
const info = await stat(filePath);
|
|
44
|
+
return info.isFile();
|
|
45
|
+
}catch(e){
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/cors.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { GenericHandlerCallback } from "@roster-lock/utils";
|
|
2
|
+
import { HTTPRequest } from "./utils/http-router";
|
|
3
|
+
|
|
4
|
+
// Browser clients (the config-editor PWA) live on a different origin than
|
|
5
|
+
// the agent. The auth code is what actually gates access, so any origin may
|
|
6
|
+
// attempt a request - reflect it and answer preflights before auth runs
|
|
7
|
+
// (preflights carry no Authorization header).
|
|
8
|
+
export const corsMiddleware: GenericHandlerCallback<HTTPRequest> = ({ req, res }, routeInfo, next)=>{
|
|
9
|
+
const origin = req.headers.origin;
|
|
10
|
+
if(!origin) return next();
|
|
11
|
+
|
|
12
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
13
|
+
res.setHeader("Vary", "Origin");
|
|
14
|
+
res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
|
|
15
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
|
16
|
+
|
|
17
|
+
if(req.method === "OPTIONS"){
|
|
18
|
+
res.writeHead(204);
|
|
19
|
+
res.end();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
next();
|
|
23
|
+
};
|