@objectstack/runtime 4.0.2 → 4.0.3
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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +9 -0
- package/dist/index.cjs +135 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +135 -54
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/dispatcher-plugin.ts +93 -59
- package/src/http-dispatcher.ts +83 -7
- package/vitest.config.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -781,6 +781,7 @@ var AppPlugin = class {
|
|
|
781
781
|
// src/http-dispatcher.ts
|
|
782
782
|
import { getEnv, resolveLocale } from "@objectstack/core";
|
|
783
783
|
import { CoreServiceName } from "@objectstack/spec/system";
|
|
784
|
+
import { pluralToSingular } from "@objectstack/spec/shared";
|
|
784
785
|
function randomUUID() {
|
|
785
786
|
if (globalThis.crypto && typeof globalThis.crypto.randomUUID === "function") {
|
|
786
787
|
return globalThis.crypto.randomUUID();
|
|
@@ -1065,18 +1066,66 @@ var HttpDispatcher = class {
|
|
|
1065
1066
|
const broker = this.kernel.broker ?? null;
|
|
1066
1067
|
const parts = path.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
1067
1068
|
if (parts[0] === "types") {
|
|
1069
|
+
console.log("[HttpDispatcher] Attempting to resolve MetadataService...");
|
|
1070
|
+
console.log("[HttpDispatcher] Available kernel methods:", {
|
|
1071
|
+
hasGetServiceAsync: typeof this.kernel.getServiceAsync === "function",
|
|
1072
|
+
hasGetService: typeof this.kernel.getService === "function",
|
|
1073
|
+
hasContext: !!this.kernel.context,
|
|
1074
|
+
hasContextGetService: typeof this.kernel.context?.getService === "function"
|
|
1075
|
+
});
|
|
1076
|
+
let metadataService = null;
|
|
1077
|
+
if (typeof this.kernel.getServiceAsync === "function") {
|
|
1078
|
+
try {
|
|
1079
|
+
metadataService = await this.kernel.getServiceAsync("metadata");
|
|
1080
|
+
console.log('[HttpDispatcher] kernel.getServiceAsync("metadata") returned:', !!metadataService);
|
|
1081
|
+
} catch (e) {
|
|
1082
|
+
console.log('[HttpDispatcher] kernel.getServiceAsync("metadata") failed:', e.message);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
if (!metadataService && typeof this.kernel.getService === "function") {
|
|
1086
|
+
try {
|
|
1087
|
+
metadataService = await this.kernel.getService("metadata");
|
|
1088
|
+
console.log('[HttpDispatcher] kernel.getService("metadata") returned:', !!metadataService);
|
|
1089
|
+
} catch (e) {
|
|
1090
|
+
console.log('[HttpDispatcher] kernel.getService("metadata") failed:', e.message);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (!metadataService && this.kernel.context?.getService) {
|
|
1094
|
+
try {
|
|
1095
|
+
metadataService = await this.kernel.context.getService("metadata");
|
|
1096
|
+
console.log('[HttpDispatcher] kernel.context.getService("metadata") returned:', !!metadataService);
|
|
1097
|
+
} catch (e) {
|
|
1098
|
+
console.log('[HttpDispatcher] kernel.context.getService("metadata") failed:', e.message);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
console.log("[HttpDispatcher] Final metadataService:", !!metadataService, "has getRegisteredTypes:", typeof metadataService?.getRegisteredTypes);
|
|
1102
|
+
if (metadataService && typeof metadataService.getRegisteredTypes === "function") {
|
|
1103
|
+
try {
|
|
1104
|
+
const types = await metadataService.getRegisteredTypes();
|
|
1105
|
+
console.log("[HttpDispatcher] MetadataService.getRegisteredTypes() returned:", types);
|
|
1106
|
+
return { handled: true, response: this.success({ types }) };
|
|
1107
|
+
} catch (e) {
|
|
1108
|
+
console.warn("[HttpDispatcher] MetadataService.getRegisteredTypes() failed:", e.message, e.stack);
|
|
1109
|
+
}
|
|
1110
|
+
} else {
|
|
1111
|
+
console.log("[HttpDispatcher] MetadataService not available or missing getRegisteredTypes, falling back to protocol service");
|
|
1112
|
+
}
|
|
1068
1113
|
const protocol = await this.resolveService("protocol");
|
|
1069
1114
|
if (protocol && typeof protocol.getMetaTypes === "function") {
|
|
1070
1115
|
const result = await protocol.getMetaTypes({});
|
|
1116
|
+
console.log("[HttpDispatcher] Protocol service returned types:", result);
|
|
1071
1117
|
return { handled: true, response: this.success(result) };
|
|
1072
1118
|
}
|
|
1073
1119
|
if (broker) {
|
|
1074
1120
|
try {
|
|
1075
1121
|
const data = await broker.call("metadata.types", {}, { request: context.request });
|
|
1122
|
+
console.log("[HttpDispatcher] Broker returned types:", data);
|
|
1076
1123
|
return { handled: true, response: this.success(data) };
|
|
1077
|
-
} catch {
|
|
1124
|
+
} catch (e) {
|
|
1125
|
+
console.log("[HttpDispatcher] Broker call failed:", e);
|
|
1078
1126
|
}
|
|
1079
1127
|
}
|
|
1128
|
+
console.warn("[HttpDispatcher] Falling back to hardcoded defaults for metadata types");
|
|
1080
1129
|
return { handled: true, response: this.success({ types: ["object", "app", "plugin"] }) };
|
|
1081
1130
|
}
|
|
1082
1131
|
if (parts.length === 3 && parts[2] === "published" && (!method || method === "GET")) {
|
|
@@ -1133,7 +1182,7 @@ var HttpDispatcher = class {
|
|
|
1133
1182
|
}
|
|
1134
1183
|
return { handled: true, response: this.error("Not found", 404) };
|
|
1135
1184
|
}
|
|
1136
|
-
const singularType =
|
|
1185
|
+
const singularType = pluralToSingular(type);
|
|
1137
1186
|
const protocol = await this.resolveService("protocol");
|
|
1138
1187
|
if (protocol && typeof protocol.getMetaItem === "function") {
|
|
1139
1188
|
try {
|
|
@@ -1165,6 +1214,18 @@ var HttpDispatcher = class {
|
|
|
1165
1214
|
} catch {
|
|
1166
1215
|
}
|
|
1167
1216
|
}
|
|
1217
|
+
const metadataService = await this.getService(CoreServiceName.enum.metadata);
|
|
1218
|
+
if (metadataService && typeof metadataService.list === "function") {
|
|
1219
|
+
try {
|
|
1220
|
+
const items = await metadataService.list(typeOrName);
|
|
1221
|
+
if (items && items.length > 0) {
|
|
1222
|
+
return { handled: true, response: this.success({ type: typeOrName, items }) };
|
|
1223
|
+
}
|
|
1224
|
+
} catch (e) {
|
|
1225
|
+
const sanitizedType = String(typeOrName).replace(/[\r\n\t]/g, "");
|
|
1226
|
+
console.debug(`[HttpDispatcher] MetadataService.list() failed for type:`, sanitizedType, "error:", e.message);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1168
1229
|
if (broker) {
|
|
1169
1230
|
try {
|
|
1170
1231
|
if (typeOrName === "objects") {
|
|
@@ -1931,6 +1992,64 @@ var HttpDispatcher = class {
|
|
|
1931
1992
|
};
|
|
1932
1993
|
|
|
1933
1994
|
// src/dispatcher-plugin.ts
|
|
1995
|
+
function mountRouteOnServer(route, server, routePath) {
|
|
1996
|
+
const handler = async (req, res) => {
|
|
1997
|
+
try {
|
|
1998
|
+
const result = await route.handler({
|
|
1999
|
+
body: req.body,
|
|
2000
|
+
params: req.params,
|
|
2001
|
+
query: req.query
|
|
2002
|
+
});
|
|
2003
|
+
if (result.stream && result.events) {
|
|
2004
|
+
res.status(result.status);
|
|
2005
|
+
if (result.headers) {
|
|
2006
|
+
for (const [k, v] of Object.entries(result.headers)) {
|
|
2007
|
+
res.header(k, String(v));
|
|
2008
|
+
}
|
|
2009
|
+
} else {
|
|
2010
|
+
res.header("Content-Type", "text/event-stream");
|
|
2011
|
+
res.header("Cache-Control", "no-cache");
|
|
2012
|
+
res.header("Connection", "keep-alive");
|
|
2013
|
+
}
|
|
2014
|
+
if (typeof res.write === "function" && typeof res.end === "function") {
|
|
2015
|
+
for await (const event of result.events) {
|
|
2016
|
+
res.write(typeof event === "string" ? event : `data: ${JSON.stringify(event)}
|
|
2017
|
+
|
|
2018
|
+
`);
|
|
2019
|
+
}
|
|
2020
|
+
res.end();
|
|
2021
|
+
} else {
|
|
2022
|
+
const events = [];
|
|
2023
|
+
for await (const event of result.events) {
|
|
2024
|
+
events.push(event);
|
|
2025
|
+
}
|
|
2026
|
+
res.json({ events });
|
|
2027
|
+
}
|
|
2028
|
+
} else {
|
|
2029
|
+
res.status(result.status);
|
|
2030
|
+
if (result.body !== void 0) {
|
|
2031
|
+
res.json(result.body);
|
|
2032
|
+
} else {
|
|
2033
|
+
res.end();
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
} catch (err) {
|
|
2037
|
+
errorResponse(err, res);
|
|
2038
|
+
}
|
|
2039
|
+
};
|
|
2040
|
+
const m = route.method.toLowerCase();
|
|
2041
|
+
if (m === "get" && typeof server.get === "function") {
|
|
2042
|
+
server.get(routePath, handler);
|
|
2043
|
+
return true;
|
|
2044
|
+
} else if (m === "post" && typeof server.post === "function") {
|
|
2045
|
+
server.post(routePath, handler);
|
|
2046
|
+
return true;
|
|
2047
|
+
} else if (m === "delete" && typeof server.delete === "function") {
|
|
2048
|
+
server.delete(routePath, handler);
|
|
2049
|
+
return true;
|
|
2050
|
+
}
|
|
2051
|
+
return false;
|
|
2052
|
+
}
|
|
1934
2053
|
function sendResult(result, res) {
|
|
1935
2054
|
if (result.handled) {
|
|
1936
2055
|
if (result.response) {
|
|
@@ -2225,61 +2344,23 @@ function createDispatcherPlugin(config = {}) {
|
|
|
2225
2344
|
if (!server) return;
|
|
2226
2345
|
for (const route of routes) {
|
|
2227
2346
|
const routePath = route.path.startsWith("/api/v1") ? route.path : `${prefix}${route.path}`;
|
|
2228
|
-
|
|
2229
|
-
try {
|
|
2230
|
-
const result = await route.handler({
|
|
2231
|
-
body: req.body,
|
|
2232
|
-
params: req.params,
|
|
2233
|
-
query: req.query
|
|
2234
|
-
});
|
|
2235
|
-
if (result.stream && result.events) {
|
|
2236
|
-
res.status(result.status);
|
|
2237
|
-
if (result.headers) {
|
|
2238
|
-
for (const [k, v] of Object.entries(result.headers)) {
|
|
2239
|
-
res.header(k, v);
|
|
2240
|
-
}
|
|
2241
|
-
} else {
|
|
2242
|
-
res.header("Content-Type", "text/event-stream");
|
|
2243
|
-
res.header("Cache-Control", "no-cache");
|
|
2244
|
-
res.header("Connection", "keep-alive");
|
|
2245
|
-
}
|
|
2246
|
-
if (typeof res.write === "function" && typeof res.end === "function") {
|
|
2247
|
-
for await (const event of result.events) {
|
|
2248
|
-
res.write(typeof event === "string" ? event : `data: ${JSON.stringify(event)}
|
|
2249
|
-
|
|
2250
|
-
`);
|
|
2251
|
-
}
|
|
2252
|
-
res.end();
|
|
2253
|
-
} else {
|
|
2254
|
-
const events = [];
|
|
2255
|
-
for await (const event of result.events) {
|
|
2256
|
-
events.push(event);
|
|
2257
|
-
}
|
|
2258
|
-
res.json({ events });
|
|
2259
|
-
}
|
|
2260
|
-
} else {
|
|
2261
|
-
res.status(result.status);
|
|
2262
|
-
if (result.body !== void 0) {
|
|
2263
|
-
res.json(result.body);
|
|
2264
|
-
} else {
|
|
2265
|
-
res.end();
|
|
2266
|
-
}
|
|
2267
|
-
}
|
|
2268
|
-
} catch (err) {
|
|
2269
|
-
errorResponse(err, res);
|
|
2270
|
-
}
|
|
2271
|
-
};
|
|
2272
|
-
const m = route.method.toLowerCase();
|
|
2273
|
-
if (m === "get" && typeof server.get === "function") {
|
|
2274
|
-
server.get(routePath, handler);
|
|
2275
|
-
} else if (m === "post" && typeof server.post === "function") {
|
|
2276
|
-
server.post(routePath, handler);
|
|
2277
|
-
} else if (m === "delete" && typeof server.delete === "function") {
|
|
2278
|
-
server.delete(routePath, handler);
|
|
2279
|
-
}
|
|
2347
|
+
mountRouteOnServer(route, server, routePath);
|
|
2280
2348
|
}
|
|
2281
2349
|
ctx.logger.info(`[Dispatcher] Registered ${routes.length} AI routes`);
|
|
2282
2350
|
});
|
|
2351
|
+
const cachedRoutes = kernel.__aiRoutes;
|
|
2352
|
+
if (cachedRoutes && Array.isArray(cachedRoutes) && cachedRoutes.length > 0) {
|
|
2353
|
+
let registered = 0;
|
|
2354
|
+
for (const route of cachedRoutes) {
|
|
2355
|
+
const routePath = route.path.startsWith("/api/v1") ? route.path : `${prefix}${route.path}`;
|
|
2356
|
+
if (mountRouteOnServer(route, server, routePath)) {
|
|
2357
|
+
registered++;
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
if (registered > 0) {
|
|
2361
|
+
ctx.logger.info(`[Dispatcher] Recovered ${registered} cached AI routes (hook timing fallback)`);
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2283
2364
|
}
|
|
2284
2365
|
};
|
|
2285
2366
|
}
|