@lobb-js/core 0.13.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/package.json +48 -0
- package/src/Lobb.ts +150 -0
- package/src/LobbError.ts +105 -0
- package/src/TypesGenerator.ts +11 -0
- package/src/api/WebServer.ts +126 -0
- package/src/api/collections/CollectionControllers.ts +485 -0
- package/src/api/collections/CollectionService.ts +162 -0
- package/src/api/collections/collectionRoutes.ts +105 -0
- package/src/api/collections/collectionStore.ts +647 -0
- package/src/api/collections/transactions.ts +166 -0
- package/src/api/collections/utils.ts +73 -0
- package/src/api/errorHandler.ts +73 -0
- package/src/api/events/index.ts +129 -0
- package/src/api/meta/route.ts +66 -0
- package/src/api/meta/service.ts +163 -0
- package/src/api/middlewares.ts +71 -0
- package/src/api/openApiRoute.ts +1017 -0
- package/src/api/schema/SchemaService.ts +71 -0
- package/src/api/schema/schemaRoutes.ts +13 -0
- package/src/config/ConfigManager.ts +252 -0
- package/src/config/validations.ts +49 -0
- package/src/coreCollections/collectionsCollection.ts +56 -0
- package/src/coreCollections/index.ts +14 -0
- package/src/coreCollections/migrationsCollection.ts +36 -0
- package/src/coreCollections/queryCollection.ts +26 -0
- package/src/coreCollections/workflowsCollection.ts +73 -0
- package/src/coreDbSetup/index.ts +72 -0
- package/src/coreMigrations/index.ts +3 -0
- package/src/database/DatabaseService.ts +44 -0
- package/src/database/DatabaseSyncManager.ts +173 -0
- package/src/database/MigrationsManager.ts +95 -0
- package/src/database/drivers/MongoDriver.ts +750 -0
- package/src/database/drivers/pgDriver/PGDriver.ts +655 -0
- package/src/database/drivers/pgDriver/QueryBuilder.ts +474 -0
- package/src/database/drivers/pgDriver/utils.ts +6 -0
- package/src/events/EventSystem.ts +191 -0
- package/src/events/coreEvents/index.ts +218 -0
- package/src/events/studioEvents/index.ts +32 -0
- package/src/extension/ExtensionSystem.ts +236 -0
- package/src/extension/dashboardRoute.ts +35 -0
- package/src/fields/ArrayField.ts +33 -0
- package/src/fields/BoolField.ts +34 -0
- package/src/fields/DateField.ts +13 -0
- package/src/fields/DateTimeField.ts +13 -0
- package/src/fields/DecimalField.ts +13 -0
- package/src/fields/FieldUtils.ts +56 -0
- package/src/fields/FloatField.ts +13 -0
- package/src/fields/IntegerField.ts +13 -0
- package/src/fields/LongField.ts +13 -0
- package/src/fields/ObjectField.ts +15 -0
- package/src/fields/StringField.ts +13 -0
- package/src/fields/TextField.ts +13 -0
- package/src/fields/TimeField.ts +13 -0
- package/src/index.ts +53 -0
- package/src/studio/Studio.ts +108 -0
- package/src/types/CollectionControllers.ts +15 -0
- package/src/types/DatabaseDriver.ts +115 -0
- package/src/types/Extension.ts +46 -0
- package/src/types/Field.ts +29 -0
- package/src/types/apiSchema.ts +12 -0
- package/src/types/collectionServiceSchema.ts +18 -0
- package/src/types/config/collectionFields.ts +85 -0
- package/src/types/config/collectionsConfig.ts +50 -0
- package/src/types/config/config.ts +66 -0
- package/src/types/config/relations.ts +17 -0
- package/src/types/filterSchema.ts +88 -0
- package/src/types/index.ts +38 -0
- package/src/types/migrations.ts +12 -0
- package/src/types/websockets.ts +34 -0
- package/src/types/workflows/processors.ts +1 -0
- package/src/utils/lockCollectionToObject.ts +204 -0
- package/src/utils/utils.ts +310 -0
- package/src/workflows/WorkflowSystem.ts +182 -0
- package/src/workflows/coreWorkflows/collectionsTable/index.ts +118 -0
- package/src/workflows/coreWorkflows/index.ts +18 -0
- package/src/workflows/coreWorkflows/processors/postOperationsWorkflows.ts +46 -0
- package/src/workflows/coreWorkflows/processors/preOperationsWorkflows.ts +27 -0
- package/src/workflows/coreWorkflows/processors/processorForDB.ts +13 -0
- package/src/workflows/coreWorkflows/processors/processors/processor.ts +23 -0
- package/src/workflows/coreWorkflows/processors/processors/processorsFunctions.ts +47 -0
- package/src/workflows/coreWorkflows/processors/utils.ts +102 -0
- package/src/workflows/coreWorkflows/processors/validator/validator.ts +19 -0
- package/src/workflows/coreWorkflows/processors/validator/validatorsFunction.ts +52 -0
- package/src/workflows/coreWorkflows/queryCoreWorkflows.ts +31 -0
- package/src/workflows/coreWorkflows/utilsCoreWorkflows.ts +40 -0
- package/src/workflows/coreWorkflows/workflowsCollection/workflowsCollectionWorkflows.ts +101 -0
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lobb-js/core",
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"license": "AGPL-3.0-only",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "bun test tests",
|
|
17
|
+
"dev": "bun run src/index.ts"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@faker-js/faker": "^9.8.0",
|
|
21
|
+
"@scalar/hono-api-reference": "^0.7.2",
|
|
22
|
+
"cron": "^4.4.0",
|
|
23
|
+
"cron-validator": "^1.4.0",
|
|
24
|
+
"hono": "^4.7.0",
|
|
25
|
+
"just-diff": "^6.0.2",
|
|
26
|
+
"lodash": "^4.17.21",
|
|
27
|
+
"mingo": "^6.4.15",
|
|
28
|
+
"nunjucks": "^3.2.4",
|
|
29
|
+
"openapi-types": "^12.1.3",
|
|
30
|
+
"pg": "^8.13.3",
|
|
31
|
+
"pg-format": "^1.0.4",
|
|
32
|
+
"qs": "^6.12.1",
|
|
33
|
+
"sucrase": "^3.35.0",
|
|
34
|
+
"validator": "^13.12.0",
|
|
35
|
+
"zod": "^3.24.2",
|
|
36
|
+
"zod-to-json-schema": "^3.24.6",
|
|
37
|
+
"zod-to-ts": "^1.2.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/lodash": "^4.17.0",
|
|
41
|
+
"@types/nunjucks": "^3.2.6",
|
|
42
|
+
"@types/pg": "^8.11.0",
|
|
43
|
+
"@types/pg-format": "^1.0.5",
|
|
44
|
+
"@types/qs": "^6.9.0",
|
|
45
|
+
"@types/validator": "^13.12.0",
|
|
46
|
+
"bun-types": "latest"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/Lobb.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { CollectionControllers } from "./types/index.ts";
|
|
2
|
+
import type { Config } from "./types/index.ts";
|
|
3
|
+
|
|
4
|
+
import { ExtensionSystem } from "./extension/ExtensionSystem.ts";
|
|
5
|
+
import { DatabaseService } from "./database/DatabaseService.ts";
|
|
6
|
+
import { WorkflowSystem } from "./workflows/WorkflowSystem.ts";
|
|
7
|
+
import { DatabaseSyncManager } from "./database/DatabaseSyncManager.ts";
|
|
8
|
+
import { WebServer } from "./api/WebServer.ts";
|
|
9
|
+
import { collectionControllers } from "./api/collections/CollectionControllers.ts";
|
|
10
|
+
import { ConfigManager } from "./config/ConfigManager.ts";
|
|
11
|
+
import { Utils } from "./utils/utils.ts";
|
|
12
|
+
import { transactions } from "./api/collections/transactions.ts";
|
|
13
|
+
import { EventSystem } from "./events/EventSystem.ts";
|
|
14
|
+
import { SchemaService } from "./api/schema/SchemaService.ts";
|
|
15
|
+
import { TypesGenerator } from "./TypesGenerator.ts";
|
|
16
|
+
import { CollectionService } from "./api/collections/CollectionService.ts";
|
|
17
|
+
import { CollectionStore } from "./api/collections/collectionStore.ts";
|
|
18
|
+
import { Studio } from "./studio/Studio.ts";
|
|
19
|
+
import { dirname } from "node:path";
|
|
20
|
+
|
|
21
|
+
export function run(config: Config) {
|
|
22
|
+
return Lobb.init(config);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class Lobb {
|
|
26
|
+
public static instance: Lobb;
|
|
27
|
+
public configManager!: ConfigManager;
|
|
28
|
+
public databaseService!: DatabaseService;
|
|
29
|
+
public workflowSystem!: WorkflowSystem;
|
|
30
|
+
public eventSystem!: EventSystem;
|
|
31
|
+
public databaseSyncManager!: DatabaseSyncManager;
|
|
32
|
+
public schemaService!: SchemaService;
|
|
33
|
+
public webServer!: WebServer;
|
|
34
|
+
public extensionSystem!: ExtensionSystem;
|
|
35
|
+
public utils = Utils;
|
|
36
|
+
public collectionControllers!: CollectionControllers;
|
|
37
|
+
public transactions!: typeof transactions;
|
|
38
|
+
public typesGenerator!: TypesGenerator;
|
|
39
|
+
public collectionStore!: CollectionStore;
|
|
40
|
+
public collectionService!: CollectionService;
|
|
41
|
+
private studio!: Studio;
|
|
42
|
+
private tempDatabase = false;
|
|
43
|
+
|
|
44
|
+
constructor() {}
|
|
45
|
+
|
|
46
|
+
public static async init(config: Config) {
|
|
47
|
+
const projectDir = dirname(Bun.main);
|
|
48
|
+
|
|
49
|
+
const studio = new Studio(projectDir);
|
|
50
|
+
|
|
51
|
+
const isTempDatabase = config.database.database === "*";
|
|
52
|
+
if (isTempDatabase) {
|
|
53
|
+
config = {
|
|
54
|
+
...config,
|
|
55
|
+
database: {
|
|
56
|
+
...config.database,
|
|
57
|
+
database: `lobb_test_${crypto.randomUUID().replace(/-/g, "")}`,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log("starting the app");
|
|
63
|
+
const lobb = new Lobb();
|
|
64
|
+
lobb.studio = studio;
|
|
65
|
+
lobb.tempDatabase = isTempDatabase;
|
|
66
|
+
Lobb.instance = lobb;
|
|
67
|
+
lobb.eventSystem = new EventSystem();
|
|
68
|
+
lobb.workflowSystem = new WorkflowSystem();
|
|
69
|
+
lobb.extensionSystem = ExtensionSystem.init();
|
|
70
|
+
lobb.initShutdownSignalListeners();
|
|
71
|
+
lobb.configManager = await ConfigManager.init(config);
|
|
72
|
+
await lobb.afterConfigInit();
|
|
73
|
+
lobb.databaseService = await DatabaseService.init();
|
|
74
|
+
lobb.collectionStore = new CollectionStore();
|
|
75
|
+
lobb.collectionService = new CollectionService();
|
|
76
|
+
await lobb.eventSystem.init();
|
|
77
|
+
await lobb.workflowSystem.init();
|
|
78
|
+
lobb.databaseSyncManager = await DatabaseSyncManager.init();
|
|
79
|
+
lobb.schemaService = await SchemaService.init();
|
|
80
|
+
const webPort = lobb.configManager.config.web_server.port ?? 3000;
|
|
81
|
+
const studioPort = await studio.start(webPort);
|
|
82
|
+
lobb.webServer = await WebServer.init(studioPort);
|
|
83
|
+
lobb.collectionControllers = collectionControllers;
|
|
84
|
+
lobb.transactions = transactions;
|
|
85
|
+
await lobb.extensionSystem.executeExtensionsInitMethods();
|
|
86
|
+
|
|
87
|
+
// emit the core.init event
|
|
88
|
+
await lobb.eventSystem.emit("core.init", {});
|
|
89
|
+
|
|
90
|
+
// generate types
|
|
91
|
+
lobb.typesGenerator = await TypesGenerator.init();
|
|
92
|
+
|
|
93
|
+
console.log("The app is running");
|
|
94
|
+
|
|
95
|
+
return lobb;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public async close() {
|
|
99
|
+
// execute the close methods of the extensions
|
|
100
|
+
await this.extensionSystem.executeExtensionsCloseMethods();
|
|
101
|
+
|
|
102
|
+
await this.workflowSystem.close();
|
|
103
|
+
await this.eventSystem.close();
|
|
104
|
+
if (this.webServer) await this.webServer.close();
|
|
105
|
+
if (this.databaseService) await this.databaseService.close();
|
|
106
|
+
if (this.tempDatabase) await this.databaseService.dropDatabase();
|
|
107
|
+
this.studio?.stop();
|
|
108
|
+
|
|
109
|
+
if (process.platform === "win32") {
|
|
110
|
+
process.off("SIGBREAK", this.onGracefulShutdown);
|
|
111
|
+
} else {
|
|
112
|
+
process.off("SIGTERM", this.onGracefulShutdown);
|
|
113
|
+
}
|
|
114
|
+
process.off("SIGINT", this.onGracefulShutdown);
|
|
115
|
+
|
|
116
|
+
// reset to the real current working directory if it was changed
|
|
117
|
+
// by the context property in the project section
|
|
118
|
+
process.chdir((globalThis as any).currentDirectory);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private initShutdownSignalListeners() {
|
|
122
|
+
if (process.platform === "win32") {
|
|
123
|
+
process.on("SIGBREAK", this.onGracefulShutdown);
|
|
124
|
+
} else {
|
|
125
|
+
process.on("SIGTERM", this.onGracefulShutdown);
|
|
126
|
+
}
|
|
127
|
+
process.on("SIGINT", this.onGracefulShutdown);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private onGracefulShutdown = async () => {
|
|
131
|
+
console.log("Performing graceful shutdown tasks...");
|
|
132
|
+
|
|
133
|
+
await this.close();
|
|
134
|
+
|
|
135
|
+
console.log("Done Performing graceful shutdown tasks!");
|
|
136
|
+
|
|
137
|
+
// exit so that all recources and ports are freed
|
|
138
|
+
process.exit(0);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
private async afterConfigInit() {
|
|
142
|
+
// change the current directory
|
|
143
|
+
const config = Lobb.instance.configManager.config;
|
|
144
|
+
(globalThis as any).currentDirectory = process.cwd();
|
|
145
|
+
process.chdir(config.project.context ?? ".");
|
|
146
|
+
|
|
147
|
+
await Lobb.instance.extensionSystem.loadExtensionsCollections();
|
|
148
|
+
this.configManager.addRelationsFromIntegerRefrences();
|
|
149
|
+
}
|
|
150
|
+
}
|
package/src/LobbError.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const LobbStatusCodes = {
|
|
4
|
+
CONTINUE: 100,
|
|
5
|
+
SWITCHING_PROTOCOLS: 101,
|
|
6
|
+
PROCESSING: 102,
|
|
7
|
+
EARLY_HINTS: 103,
|
|
8
|
+
|
|
9
|
+
OK: 200,
|
|
10
|
+
CREATED: 201,
|
|
11
|
+
ACCEPTED: 202,
|
|
12
|
+
NON_AUTHORITATIVE_INFORMATION: 203,
|
|
13
|
+
NO_CONTENT: 204,
|
|
14
|
+
RESET_CONTENT: 205,
|
|
15
|
+
PARTIAL_CONTENT: 206,
|
|
16
|
+
MULTI_STATUS: 207,
|
|
17
|
+
ALREADY_REPORTED: 208,
|
|
18
|
+
IM_USED: 226,
|
|
19
|
+
|
|
20
|
+
MULTIPLE_CHOICES: 300,
|
|
21
|
+
MOVED_PERMANENTLY: 301,
|
|
22
|
+
FOUND: 302,
|
|
23
|
+
SEE_OTHER: 303,
|
|
24
|
+
NOT_MODIFIED: 304,
|
|
25
|
+
USE_PROXY: 305,
|
|
26
|
+
SWITCH_PROXY: 306, // unused
|
|
27
|
+
TEMPORARY_REDIRECT: 307,
|
|
28
|
+
PERMANENT_REDIRECT: 308,
|
|
29
|
+
|
|
30
|
+
BAD_REQUEST: 400,
|
|
31
|
+
UNAUTHORIZED: 401,
|
|
32
|
+
PAYMENT_REQUIRED: 402,
|
|
33
|
+
FORBIDDEN: 403,
|
|
34
|
+
NOT_FOUND: 404,
|
|
35
|
+
METHOD_NOT_ALLOWED: 405,
|
|
36
|
+
NOT_ACCEPTABLE: 406,
|
|
37
|
+
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
38
|
+
REQUEST_TIMEOUT: 408,
|
|
39
|
+
CONFLICT: 409,
|
|
40
|
+
GONE: 410,
|
|
41
|
+
LENGTH_REQUIRED: 411,
|
|
42
|
+
PRECONDITION_FAILED: 412,
|
|
43
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
44
|
+
URI_TOO_LONG: 414,
|
|
45
|
+
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
46
|
+
RANGE_NOT_SATISFIABLE: 416,
|
|
47
|
+
EXPECTATION_FAILED: 417,
|
|
48
|
+
IM_A_TEAPOT: 418,
|
|
49
|
+
MISDIRECTED_REQUEST: 421,
|
|
50
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
51
|
+
LOCKED: 423,
|
|
52
|
+
FAILED_DEPENDENCY: 424,
|
|
53
|
+
TOO_EARLY: 425,
|
|
54
|
+
UPGRADE_REQUIRED: 426,
|
|
55
|
+
PRECONDITION_REQUIRED: 428,
|
|
56
|
+
TOO_MANY_REQUESTS: 429,
|
|
57
|
+
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
58
|
+
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
59
|
+
|
|
60
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
61
|
+
NOT_IMPLEMENTED: 501,
|
|
62
|
+
BAD_GATEWAY: 502,
|
|
63
|
+
SERVICE_UNAVAILABLE: 503,
|
|
64
|
+
GATEWAY_TIMEOUT: 504,
|
|
65
|
+
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
66
|
+
VARIANT_ALSO_NEGOTIATES: 506,
|
|
67
|
+
INSUFFICIENT_STORAGE: 507,
|
|
68
|
+
LOOP_DETECTED: 508,
|
|
69
|
+
NOT_EXTENDED: 510,
|
|
70
|
+
NETWORK_AUTHENTICATION_REQUIRED: 511,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Reuse your ErrorCode union
|
|
74
|
+
const ErrorCodeSchema = z.enum(
|
|
75
|
+
Object.keys(LobbStatusCodes) as [
|
|
76
|
+
keyof typeof LobbStatusCodes,
|
|
77
|
+
...Array<keyof typeof LobbStatusCodes>,
|
|
78
|
+
],
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
export const LobbErrorSchema = z.object({
|
|
82
|
+
code: ErrorCodeSchema,
|
|
83
|
+
message: z.string(),
|
|
84
|
+
details: z.any().optional(),
|
|
85
|
+
});
|
|
86
|
+
type ErrorCode = z.infer<typeof ErrorCodeSchema>;
|
|
87
|
+
export type LobbErrorOptions = z.infer<typeof LobbErrorSchema>;
|
|
88
|
+
|
|
89
|
+
export class LobbError extends Error {
|
|
90
|
+
public status: number;
|
|
91
|
+
public code: ErrorCode;
|
|
92
|
+
public details?: any;
|
|
93
|
+
|
|
94
|
+
constructor({ code, message, details }: LobbErrorOptions) {
|
|
95
|
+
super(message);
|
|
96
|
+
this.name = "LobbError";
|
|
97
|
+
this.status = LobbStatusCodes[code];
|
|
98
|
+
this.code = code;
|
|
99
|
+
this.details = details;
|
|
100
|
+
|
|
101
|
+
if (Error.captureStackTrace) {
|
|
102
|
+
Error.captureStackTrace(this, LobbError);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { WebConfig } from "../types/index.ts";
|
|
2
|
+
|
|
3
|
+
import { Hono } from "hono";
|
|
4
|
+
import type { Context } from "hono";
|
|
5
|
+
import { cors } from "hono/cors";
|
|
6
|
+
import { proxy } from "hono/proxy";
|
|
7
|
+
import { getCollectionRoute } from "./collections/collectionRoutes.ts";
|
|
8
|
+
import { getMetaRoute } from "./meta/route.ts";
|
|
9
|
+
import { errorHandler } from "./errorHandler.ts";
|
|
10
|
+
import * as middlewares from "./middlewares.ts";
|
|
11
|
+
import { getOpenApiRoute } from "./openApiRoute.ts";
|
|
12
|
+
import { Lobb } from "../Lobb.ts";
|
|
13
|
+
import { getSchemaRoutes } from "./schema/schemaRoutes.ts";
|
|
14
|
+
import { getEventsRoute } from "./events/index.ts";
|
|
15
|
+
|
|
16
|
+
export class WebServer {
|
|
17
|
+
private webConfig!: WebConfig;
|
|
18
|
+
public app!: Hono;
|
|
19
|
+
public port!: number;
|
|
20
|
+
private server!: ReturnType<typeof Bun.serve>;
|
|
21
|
+
|
|
22
|
+
public static async init(studioPort: number | null = null) {
|
|
23
|
+
const webServer = new WebServer();
|
|
24
|
+
webServer.webConfig = Lobb.instance.configManager.config.web_server;
|
|
25
|
+
webServer.app = new Hono();
|
|
26
|
+
await webServer.start(studioPort);
|
|
27
|
+
return webServer;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public close() {
|
|
31
|
+
// closing all opened sockets
|
|
32
|
+
this.server.stop(true);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public async start(studioPort: number | null = null) {
|
|
36
|
+
this.app.onError(errorHandler);
|
|
37
|
+
|
|
38
|
+
// pre middlwares
|
|
39
|
+
this.app.use(middlewares.extensionContext);
|
|
40
|
+
this.app.use(middlewares.workflowsMiddlewares);
|
|
41
|
+
|
|
42
|
+
const corsConfig = Lobb.instance.configManager.config.web_server.cors;
|
|
43
|
+
if (corsConfig) {
|
|
44
|
+
this.app.use(cors(corsConfig));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// post middlwares
|
|
48
|
+
this.app.use(middlewares.pick);
|
|
49
|
+
|
|
50
|
+
this.app.get("/", (c) => {
|
|
51
|
+
return c.json({ status: "ok", message: "API is available at /api" });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
this.app.get("/api", (c) => {
|
|
55
|
+
return c.json({ status: "ok", message: "Lobb API is up and running." });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
this.app.route("/api/meta", getMetaRoute());
|
|
59
|
+
this.app.route("/api/schema", getSchemaRoutes());
|
|
60
|
+
this.app.route("/api/collections", getCollectionRoute());
|
|
61
|
+
this.app.route("/api/openapi", getOpenApiRoute());
|
|
62
|
+
this.app.route("/api/extensions", Lobb.instance.extensionSystem.routes());
|
|
63
|
+
this.app.route("/api/events", getEventsRoute());
|
|
64
|
+
|
|
65
|
+
if (studioPort) {
|
|
66
|
+
const port = studioPort;
|
|
67
|
+
const studioProxy = (c: Context) => {
|
|
68
|
+
const targetUrl = new URL(c.req.url);
|
|
69
|
+
targetUrl.host = `localhost:${port}`;
|
|
70
|
+
return proxy(targetUrl.toString(), { headers: c.req.header() });
|
|
71
|
+
};
|
|
72
|
+
this.app.all("/studio", (c) => c.redirect("/studio/", 308));
|
|
73
|
+
this.app.all("/studio/", studioProxy);
|
|
74
|
+
this.app.all("/studio/*", studioProxy);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const isDev = process.env.LOBB_MODE !== "prod";
|
|
78
|
+
const serveBase = {
|
|
79
|
+
port: this.webConfig.port ?? 3000,
|
|
80
|
+
hostname: this.webConfig.host ?? "0.0.0.0",
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// In dev, forward WebSocket upgrade requests to the Vite dev server so that
|
|
84
|
+
// Vite's HMR can connect through the Lobb proxy instead of falling back to
|
|
85
|
+
// a direct connection (which causes a console warning).
|
|
86
|
+
if (isDev && studioPort) {
|
|
87
|
+
type WSData = { path: string; upstream?: WebSocket };
|
|
88
|
+
this.server = Bun.serve<WSData>({
|
|
89
|
+
...serveBase,
|
|
90
|
+
fetch: (req, server) => {
|
|
91
|
+
if (req.headers.get("upgrade") === "websocket") {
|
|
92
|
+
const url = new URL(req.url);
|
|
93
|
+
if (url.pathname.startsWith("/studio")) {
|
|
94
|
+
const upgraded = server.upgrade(req, { data: { path: url.pathname + url.search } });
|
|
95
|
+
if (upgraded) return undefined;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return this.app.fetch(req);
|
|
99
|
+
},
|
|
100
|
+
websocket: {
|
|
101
|
+
open(ws) {
|
|
102
|
+
const upstream = new WebSocket(`ws://localhost:${studioPort}${ws.data.path.replace(/^\/studio/, "") || "/"}`);
|
|
103
|
+
ws.data.upstream = upstream;
|
|
104
|
+
upstream.addEventListener("message", (e) => ws.send(e.data as string | ArrayBuffer));
|
|
105
|
+
upstream.addEventListener("close", (e) => ws.close(e.code, e.reason));
|
|
106
|
+
upstream.addEventListener("error", () => ws.close());
|
|
107
|
+
},
|
|
108
|
+
message(ws, message) {
|
|
109
|
+
if (ws.data.upstream?.readyState === WebSocket.OPEN) {
|
|
110
|
+
ws.data.upstream.send(message as string | ArrayBuffer);
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
close(ws, code, reason) {
|
|
114
|
+
ws.data.upstream?.close(code, reason);
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
this.server = Bun.serve({
|
|
120
|
+
...serveBase,
|
|
121
|
+
fetch: this.app.fetch,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
this.port = this.server.port!;
|
|
125
|
+
}
|
|
126
|
+
}
|