@objectstack/runtime 14.3.0 → 14.6.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/dist/index.cjs +54 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +50 -9
- package/dist/index.js.map +1 -1
- package/package.json +20 -20
package/dist/index.cjs
CHANGED
|
@@ -2161,7 +2161,7 @@ function safeGet(ctx, name) {
|
|
|
2161
2161
|
var import_core5 = require("@objectstack/core");
|
|
2162
2162
|
var import_types3 = require("@objectstack/types");
|
|
2163
2163
|
var import_system = require("@objectstack/spec/system");
|
|
2164
|
-
var
|
|
2164
|
+
var import_ai2 = require("@objectstack/spec/ai");
|
|
2165
2165
|
var import_shared2 = require("@objectstack/spec/shared");
|
|
2166
2166
|
init_package_state_store();
|
|
2167
2167
|
|
|
@@ -2195,6 +2195,7 @@ function checkApiExposure(def, action) {
|
|
|
2195
2195
|
}
|
|
2196
2196
|
|
|
2197
2197
|
// src/security/resolve-execution-context.ts
|
|
2198
|
+
var import_ai = require("@objectstack/spec/ai");
|
|
2198
2199
|
var import_core3 = require("@objectstack/core");
|
|
2199
2200
|
function extractJwtBearer(headers) {
|
|
2200
2201
|
const auth = headers.get("authorization");
|
|
@@ -2255,7 +2256,15 @@ async function resolveExecutionContext(opts) {
|
|
|
2255
2256
|
isSystem: false
|
|
2256
2257
|
};
|
|
2257
2258
|
if (authz.userId) {
|
|
2258
|
-
|
|
2259
|
+
if (oauthPrincipal?.clientId) {
|
|
2260
|
+
ctx.principalKind = "agent";
|
|
2261
|
+
ctx.onBehalfOf = { userId: authz.userId, principalKind: "human" };
|
|
2262
|
+
ctx.permissions = (0, import_ai.scopesToAgentPermissionSets)(oauthPrincipal.scopes);
|
|
2263
|
+
ctx.positions = [];
|
|
2264
|
+
ctx.systemPermissions = oauthPrincipal.scopes?.includes(import_ai.MCP_OAUTH_SCOPE_ACTIONS) ? authz.systemPermissions ?? [] : [];
|
|
2265
|
+
} else {
|
|
2266
|
+
ctx.principalKind = "human";
|
|
2267
|
+
}
|
|
2259
2268
|
} else {
|
|
2260
2269
|
ctx.principalKind = "guest";
|
|
2261
2270
|
ctx.positions = ["guest"];
|
|
@@ -2331,6 +2340,7 @@ var _HttpDispatcher = class _HttpDispatcher {
|
|
|
2331
2340
|
}
|
|
2332
2341
|
};
|
|
2333
2342
|
this.enforceMembership = options?.enforceProjectMembership ?? true;
|
|
2343
|
+
this.requireAuth = options?.requireAuth ?? false;
|
|
2334
2344
|
this.kernelResolver = options?.kernelResolver ?? resolveService("kernel-resolver");
|
|
2335
2345
|
this.scopeManager = options?.scopeManager ?? resolveService("scope-manager");
|
|
2336
2346
|
}
|
|
@@ -2548,14 +2558,14 @@ var _HttpDispatcher = class _HttpDispatcher {
|
|
|
2548
2558
|
return { handled: true, response };
|
|
2549
2559
|
}
|
|
2550
2560
|
const grantedScopes = Array.isArray(ec.oauthScopes) ? ec.oauthScopes : void 0;
|
|
2551
|
-
if (grantedScopes && !grantedScopes.some((s) =>
|
|
2561
|
+
if (grantedScopes && !grantedScopes.some((s) => import_ai2.MCP_OAUTH_SCOPES.includes(s))) {
|
|
2552
2562
|
const resourceMetadataUrl = await this.getMcpResourceMetadataUrl(context);
|
|
2553
2563
|
const response = this.error(
|
|
2554
|
-
`Forbidden: the access token grants none of the MCP scopes (${
|
|
2564
|
+
`Forbidden: the access token grants none of the MCP scopes (${import_ai2.MCP_OAUTH_SCOPES.join(", ")})`,
|
|
2555
2565
|
403
|
|
2556
2566
|
);
|
|
2557
2567
|
response.headers = {
|
|
2558
|
-
"WWW-Authenticate": `Bearer error="insufficient_scope", scope="${
|
|
2568
|
+
"WWW-Authenticate": `Bearer error="insufficient_scope", scope="${import_ai2.MCP_OAUTH_SCOPES.join(" ")}"` + (resourceMetadataUrl ? `, resource_metadata="${resourceMetadataUrl}"` : "")
|
|
2559
2569
|
};
|
|
2560
2570
|
return { handled: true, response };
|
|
2561
2571
|
}
|
|
@@ -3496,6 +3506,15 @@ var _HttpDispatcher = class _HttpDispatcher {
|
|
|
3496
3506
|
* Fallback for backward compat: /metadata (all objects), /metadata/:objectName (get object)
|
|
3497
3507
|
*/
|
|
3498
3508
|
async handleMetadata(path, _context, method, body, query) {
|
|
3509
|
+
if (this.requireAuth) {
|
|
3510
|
+
const ec = _context.executionContext;
|
|
3511
|
+
if (!ec?.userId && !ec?.isSystem) {
|
|
3512
|
+
return {
|
|
3513
|
+
handled: true,
|
|
3514
|
+
response: this.error("Authentication is required to access this endpoint.", 401, { code: "unauthenticated" })
|
|
3515
|
+
};
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3499
3518
|
const parts = path.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
3500
3519
|
if (parts[0] === "types") {
|
|
3501
3520
|
const protocol = await this.resolveService("protocol");
|
|
@@ -3795,13 +3814,13 @@ var _HttpDispatcher = class _HttpDispatcher {
|
|
|
3795
3814
|
* Handles Analytics requests
|
|
3796
3815
|
* path: sub-path after /analytics/
|
|
3797
3816
|
*/
|
|
3798
|
-
async handleAnalytics(path, method, body,
|
|
3817
|
+
async handleAnalytics(path, method, body, context) {
|
|
3799
3818
|
const analyticsService = await this.getService(import_system.CoreServiceName.enum.analytics);
|
|
3800
3819
|
if (!analyticsService) return { handled: false };
|
|
3801
3820
|
const m = method.toUpperCase();
|
|
3802
3821
|
const subPath = path.replace(/^\/+/, "");
|
|
3803
3822
|
if (subPath === "query" && m === "POST") {
|
|
3804
|
-
const result = await analyticsService.query(body);
|
|
3823
|
+
const result = await analyticsService.query(body, context?.executionContext);
|
|
3805
3824
|
return { handled: true, response: this.success(result) };
|
|
3806
3825
|
}
|
|
3807
3826
|
if (subPath === "meta" && m === "GET") {
|
|
@@ -3809,7 +3828,7 @@ var _HttpDispatcher = class _HttpDispatcher {
|
|
|
3809
3828
|
return { handled: true, response: this.success(result) };
|
|
3810
3829
|
}
|
|
3811
3830
|
if (subPath === "sql" && m === "POST") {
|
|
3812
|
-
const result = await analyticsService.generateSql(body);
|
|
3831
|
+
const result = await analyticsService.generateSql(body, context?.executionContext);
|
|
3813
3832
|
return { handled: true, response: this.success(result) };
|
|
3814
3833
|
}
|
|
3815
3834
|
return { handled: false };
|
|
@@ -4997,6 +5016,15 @@ var _HttpDispatcher = class _HttpDispatcher {
|
|
|
4997
5016
|
if (route.method !== method) continue;
|
|
4998
5017
|
const params = matchRoute(route.path, fullPath);
|
|
4999
5018
|
if (params === null) continue;
|
|
5019
|
+
if (this.requireAuth && route.auth !== false) {
|
|
5020
|
+
const gec = context.executionContext;
|
|
5021
|
+
if (!gec?.userId && !gec?.isSystem) {
|
|
5022
|
+
return {
|
|
5023
|
+
handled: true,
|
|
5024
|
+
response: this.error("Authentication is required to access this endpoint.", 401, { code: "unauthenticated" })
|
|
5025
|
+
};
|
|
5026
|
+
}
|
|
5027
|
+
}
|
|
5000
5028
|
const ec = context.executionContext;
|
|
5001
5029
|
const user = ec?.userId ? {
|
|
5002
5030
|
userId: ec.userId,
|
|
@@ -5719,7 +5747,7 @@ function resolveErrorReporter(ctx, override) {
|
|
|
5719
5747
|
}
|
|
5720
5748
|
|
|
5721
5749
|
// src/dispatcher-plugin.ts
|
|
5722
|
-
function mountRouteOnServer(route, server, routePath, securityHeaders, resolveUser) {
|
|
5750
|
+
function mountRouteOnServer(route, server, routePath, securityHeaders, resolveUser, requireAuth = false) {
|
|
5723
5751
|
const handler = async (req, res) => {
|
|
5724
5752
|
try {
|
|
5725
5753
|
let user;
|
|
@@ -5729,6 +5757,17 @@ function mountRouteOnServer(route, server, routePath, securityHeaders, resolveUs
|
|
|
5729
5757
|
} catch {
|
|
5730
5758
|
}
|
|
5731
5759
|
}
|
|
5760
|
+
if (requireAuth && route.auth !== false && !user) {
|
|
5761
|
+
res.status(401);
|
|
5762
|
+
if (securityHeaders) {
|
|
5763
|
+
for (const [k, v] of Object.entries(securityHeaders)) res.header(k, v);
|
|
5764
|
+
}
|
|
5765
|
+
res.json({
|
|
5766
|
+
error: "unauthenticated",
|
|
5767
|
+
message: "Authentication is required to access this endpoint."
|
|
5768
|
+
});
|
|
5769
|
+
return;
|
|
5770
|
+
}
|
|
5732
5771
|
const result = await route.handler({
|
|
5733
5772
|
body: req.body,
|
|
5734
5773
|
params: req.params,
|
|
@@ -5912,8 +5951,10 @@ function createDispatcherPlugin(config = {}) {
|
|
|
5912
5951
|
if (!server) return;
|
|
5913
5952
|
const kernel = ctx.getKernel();
|
|
5914
5953
|
const enforceMembership = config.enforceProjectMembership ?? (config.scoping?.enableProjectScoping ?? false);
|
|
5954
|
+
const requireAuth = config.requireAuth ?? config.scoping?.requireAuth ?? false;
|
|
5915
5955
|
const dispatcher = new HttpDispatcher(kernel, void 0, {
|
|
5916
|
-
enforceProjectMembership: enforceMembership
|
|
5956
|
+
enforceProjectMembership: enforceMembership,
|
|
5957
|
+
requireAuth
|
|
5917
5958
|
});
|
|
5918
5959
|
const prefix = config.prefix || "/api/v1";
|
|
5919
5960
|
const securityHeaders = config.securityHeaders === false ? void 0 : buildSecurityHeaders(
|
|
@@ -6423,11 +6464,11 @@ function createDispatcherPlugin(config = {}) {
|
|
|
6423
6464
|
const routePath = route.path.startsWith("/api/v1") ? route.path : `${prefix}${route.path}`;
|
|
6424
6465
|
let count = 0;
|
|
6425
6466
|
if (enableProjectScoping && projectResolution === "required") {
|
|
6426
|
-
if (mountRouteOnServer(route, server, toScopedPath(routePath), securityHeaders, resolveRequestUser)) count++;
|
|
6467
|
+
if (mountRouteOnServer(route, server, toScopedPath(routePath), securityHeaders, resolveRequestUser, requireAuth)) count++;
|
|
6427
6468
|
} else {
|
|
6428
|
-
if (mountRouteOnServer(route, server, routePath, securityHeaders, resolveRequestUser)) count++;
|
|
6469
|
+
if (mountRouteOnServer(route, server, routePath, securityHeaders, resolveRequestUser, requireAuth)) count++;
|
|
6429
6470
|
if (enableProjectScoping) {
|
|
6430
|
-
if (mountRouteOnServer(route, server, toScopedPath(routePath), securityHeaders, resolveRequestUser)) count++;
|
|
6471
|
+
if (mountRouteOnServer(route, server, toScopedPath(routePath), securityHeaders, resolveRequestUser, requireAuth)) count++;
|
|
6431
6472
|
}
|
|
6432
6473
|
}
|
|
6433
6474
|
return count;
|