@objectstack/plugin-hono-server 4.0.4 → 4.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/README.md +22 -0
- package/dist/index.d.mts +88 -1
- package/dist/index.d.ts +88 -1
- package/dist/index.js +299 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +299 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +33 -8
- package/.turbo/turbo-build.log +0 -22
- package/CHANGELOG.md +0 -688
- package/objectstack.config.ts +0 -240
- package/src/adapter.ts +0 -228
- package/src/hono-plugin.test.ts +0 -236
- package/src/hono-plugin.ts +0 -456
- package/src/index.ts +0 -5
- package/src/pattern-matcher.test.ts +0 -180
- package/tsconfig.json +0 -24
- package/vitest.config.ts +0 -22
package/dist/index.js
CHANGED
|
@@ -34,7 +34,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
34
34
|
var index_exports = {};
|
|
35
35
|
__export(index_exports, {
|
|
36
36
|
HonoHttpServer: () => HonoHttpServer,
|
|
37
|
-
HonoServerPlugin: () => HonoServerPlugin
|
|
37
|
+
HonoServerPlugin: () => HonoServerPlugin,
|
|
38
|
+
createOriginMatcher: () => createOriginMatcher,
|
|
39
|
+
hasWildcardPattern: () => hasWildcardPattern,
|
|
40
|
+
isLocalhostOrigin: () => isLocalhostOrigin,
|
|
41
|
+
matchOriginPattern: () => matchOriginPattern,
|
|
42
|
+
normalizeOriginPatterns: () => normalizeOriginPatterns
|
|
38
43
|
});
|
|
39
44
|
module.exports = __toCommonJS(index_exports);
|
|
40
45
|
|
|
@@ -60,7 +65,9 @@ var HonoHttpServer = class {
|
|
|
60
65
|
wrap(handler) {
|
|
61
66
|
return async (c) => {
|
|
62
67
|
let body = {};
|
|
63
|
-
|
|
68
|
+
const contentType = c.req.header("content-type") ?? "";
|
|
69
|
+
const isOctetStream = contentType.includes("application/octet-stream");
|
|
70
|
+
if (contentType.includes("application/json")) {
|
|
64
71
|
try {
|
|
65
72
|
body = await c.req.json();
|
|
66
73
|
} catch (e) {
|
|
@@ -69,19 +76,31 @@ var HonoHttpServer = class {
|
|
|
69
76
|
} catch (e2) {
|
|
70
77
|
}
|
|
71
78
|
}
|
|
72
|
-
} else {
|
|
79
|
+
} else if (!isOctetStream) {
|
|
73
80
|
try {
|
|
74
81
|
body = await c.req.parseBody();
|
|
75
82
|
} catch (e) {
|
|
76
83
|
}
|
|
77
84
|
}
|
|
85
|
+
const rawHeaders = c.req.header();
|
|
86
|
+
if (!rawHeaders.host) {
|
|
87
|
+
try {
|
|
88
|
+
const u = new URL(c.req.url);
|
|
89
|
+
if (u.host) rawHeaders.host = u.host;
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
78
93
|
const req = {
|
|
79
94
|
params: c.req.param(),
|
|
80
95
|
query: c.req.query(),
|
|
81
96
|
body,
|
|
82
|
-
headers:
|
|
97
|
+
headers: rawHeaders,
|
|
83
98
|
method: c.req.method,
|
|
84
|
-
path: c.req.path
|
|
99
|
+
path: c.req.path,
|
|
100
|
+
rawBody: async () => {
|
|
101
|
+
const ab = await c.req.arrayBuffer();
|
|
102
|
+
return Buffer.from(ab);
|
|
103
|
+
}
|
|
85
104
|
};
|
|
86
105
|
let capturedResponse;
|
|
87
106
|
let streamController = null;
|
|
@@ -136,13 +155,13 @@ var HonoHttpServer = class {
|
|
|
136
155
|
streamController?.close();
|
|
137
156
|
resolve2(null);
|
|
138
157
|
}
|
|
139
|
-
}).catch(() => {
|
|
158
|
+
}).catch((err) => {
|
|
140
159
|
streamController?.close();
|
|
141
160
|
resolve2(null);
|
|
142
161
|
});
|
|
143
162
|
});
|
|
144
163
|
const streamResponse = await streamPromise;
|
|
145
|
-
return streamResponse ?? capturedResponse;
|
|
164
|
+
return streamResponse ?? capturedResponse ?? c.json({ error: "No response from handler" }, 500);
|
|
146
165
|
};
|
|
147
166
|
}
|
|
148
167
|
get(path2, handler) {
|
|
@@ -163,11 +182,23 @@ var HonoHttpServer = class {
|
|
|
163
182
|
use(pathOrHandler, handler) {
|
|
164
183
|
if (typeof pathOrHandler === "string" && handler) {
|
|
165
184
|
this.app.use(pathOrHandler, async (c, next) => {
|
|
166
|
-
|
|
185
|
+
let nextCalled = false;
|
|
186
|
+
const wrappedNext = () => {
|
|
187
|
+
nextCalled = true;
|
|
188
|
+
return next();
|
|
189
|
+
};
|
|
190
|
+
await handler({}, {}, wrappedNext);
|
|
191
|
+
if (!nextCalled) await next();
|
|
167
192
|
});
|
|
168
193
|
} else if (typeof pathOrHandler === "function") {
|
|
169
194
|
this.app.use("*", async (c, next) => {
|
|
170
|
-
|
|
195
|
+
let nextCalled = false;
|
|
196
|
+
const wrappedNext = () => {
|
|
197
|
+
nextCalled = true;
|
|
198
|
+
return next();
|
|
199
|
+
};
|
|
200
|
+
await pathOrHandler({}, {}, wrappedNext);
|
|
201
|
+
if (!nextCalled) await next();
|
|
171
202
|
});
|
|
172
203
|
}
|
|
173
204
|
}
|
|
@@ -222,9 +253,13 @@ var HonoHttpServer = class {
|
|
|
222
253
|
return this.app;
|
|
223
254
|
}
|
|
224
255
|
async close() {
|
|
225
|
-
if (this.server
|
|
226
|
-
|
|
256
|
+
if (!this.server) return;
|
|
257
|
+
if (typeof this.server.closeAllConnections === "function") {
|
|
258
|
+
this.server.closeAllConnections();
|
|
227
259
|
}
|
|
260
|
+
await new Promise((resolve2, reject) => {
|
|
261
|
+
this.server.close((err) => err ? reject(err) : resolve2());
|
|
262
|
+
});
|
|
228
263
|
}
|
|
229
264
|
};
|
|
230
265
|
|
|
@@ -233,21 +268,29 @@ var import_cors = require("hono/cors");
|
|
|
233
268
|
var import_serve_static2 = require("@hono/node-server/serve-static");
|
|
234
269
|
var fs = __toESM(require("fs"));
|
|
235
270
|
var path = __toESM(require("path"));
|
|
271
|
+
|
|
272
|
+
// src/pattern-matcher.ts
|
|
273
|
+
function isLocalhostOrigin(origin) {
|
|
274
|
+
return /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/.test(origin);
|
|
275
|
+
}
|
|
236
276
|
function matchOriginPattern(origin, pattern) {
|
|
277
|
+
if (isLocalhostOrigin(origin)) return true;
|
|
237
278
|
if (pattern === "*") return true;
|
|
238
279
|
if (pattern === origin) return true;
|
|
239
280
|
const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
240
281
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
241
282
|
return regex.test(origin);
|
|
242
283
|
}
|
|
243
|
-
function
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
patternList = patterns.includes(",") ? patterns.split(",").map((s) => s.trim()).filter(Boolean) : [patterns];
|
|
247
|
-
} else {
|
|
248
|
-
patternList = patterns;
|
|
284
|
+
function normalizeOriginPatterns(patterns) {
|
|
285
|
+
if (Array.isArray(patterns)) {
|
|
286
|
+
return patterns.map((p) => p.trim()).filter(Boolean);
|
|
249
287
|
}
|
|
288
|
+
return patterns.includes(",") ? patterns.split(",").map((s) => s.trim()).filter(Boolean) : [patterns.trim()].filter(Boolean);
|
|
289
|
+
}
|
|
290
|
+
function createOriginMatcher(patterns) {
|
|
291
|
+
const patternList = normalizeOriginPatterns(patterns);
|
|
250
292
|
return (requestOrigin) => {
|
|
293
|
+
if (!requestOrigin) return null;
|
|
251
294
|
for (const pattern of patternList) {
|
|
252
295
|
if (matchOriginPattern(requestOrigin, pattern)) {
|
|
253
296
|
return requestOrigin;
|
|
@@ -256,6 +299,12 @@ function createOriginMatcher(patterns) {
|
|
|
256
299
|
return null;
|
|
257
300
|
};
|
|
258
301
|
}
|
|
302
|
+
function hasWildcardPattern(patterns) {
|
|
303
|
+
const list = Array.isArray(patterns) ? patterns : [patterns];
|
|
304
|
+
return list.some((p) => p.includes("*"));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/hono-plugin.ts
|
|
259
308
|
var HonoServerPlugin = class {
|
|
260
309
|
constructor(options = {}) {
|
|
261
310
|
__publicField(this, "name", "com.objectstack.server.hono");
|
|
@@ -291,23 +340,27 @@ var HonoServerPlugin = class {
|
|
|
291
340
|
const credentials = corsOpts.credentials ?? process.env.CORS_CREDENTIALS !== "false";
|
|
292
341
|
const maxAge = corsOpts.maxAge ?? (process.env.CORS_MAX_AGE ? parseInt(process.env.CORS_MAX_AGE, 10) : 86400);
|
|
293
342
|
let origin;
|
|
294
|
-
const hasWildcard = (patterns) => {
|
|
295
|
-
const list = Array.isArray(patterns) ? patterns : [patterns];
|
|
296
|
-
return list.some((p) => p.includes("*"));
|
|
297
|
-
};
|
|
298
343
|
if (configuredOrigin === "*" && credentials) {
|
|
299
344
|
origin = (requestOrigin) => requestOrigin || "*";
|
|
300
|
-
} else if (
|
|
345
|
+
} else if (hasWildcardPattern(configuredOrigin)) {
|
|
301
346
|
origin = createOriginMatcher(configuredOrigin);
|
|
302
347
|
} else {
|
|
303
|
-
|
|
348
|
+
const matcher = createOriginMatcher(configuredOrigin);
|
|
349
|
+
origin = (requestOrigin) => matcher(requestOrigin);
|
|
304
350
|
}
|
|
305
351
|
const rawApp = this.server.getRawApp();
|
|
352
|
+
const defaultAllowHeaders = ["Content-Type", "Authorization", "X-Requested-With", "X-Tenant-ID", "X-Project-Id"];
|
|
353
|
+
const defaultExposeHeaders = ["set-auth-token"];
|
|
354
|
+
const allowHeaders = corsOpts.allowHeaders ?? defaultAllowHeaders;
|
|
355
|
+
const exposeHeaders = Array.from(/* @__PURE__ */ new Set([
|
|
356
|
+
...defaultExposeHeaders,
|
|
357
|
+
...corsOpts.exposeHeaders ?? []
|
|
358
|
+
]));
|
|
306
359
|
rawApp.use("*", (0, import_cors.cors)({
|
|
307
360
|
origin,
|
|
308
361
|
allowMethods: corsOpts.methods || ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"],
|
|
309
|
-
allowHeaders
|
|
310
|
-
exposeHeaders
|
|
362
|
+
allowHeaders,
|
|
363
|
+
exposeHeaders,
|
|
311
364
|
credentials,
|
|
312
365
|
maxAge
|
|
313
366
|
}));
|
|
@@ -408,10 +461,16 @@ var HonoServerPlugin = class {
|
|
|
408
461
|
});
|
|
409
462
|
}
|
|
410
463
|
}
|
|
411
|
-
|
|
412
|
-
|
|
464
|
+
const rawAppForNotFound = this.server.getRawApp();
|
|
465
|
+
if (typeof rawAppForNotFound.notFound === "function") {
|
|
466
|
+
rawAppForNotFound.notFound((c) => c.json({ error: "Not found" }, 404));
|
|
467
|
+
}
|
|
468
|
+
if (this.options.registerStandardEndpoints) {
|
|
469
|
+
ctx.hook("kernel:ready", async () => {
|
|
413
470
|
this.registerDiscoveryAndCrudEndpoints(ctx);
|
|
414
|
-
}
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
ctx.hook("kernel:listening", async () => {
|
|
415
474
|
const port = this.options.port ?? 3e3;
|
|
416
475
|
ctx.logger.debug("Starting HTTP server", { port });
|
|
417
476
|
await this.server.listen(port);
|
|
@@ -464,33 +523,228 @@ var HonoServerPlugin = class {
|
|
|
464
523
|
rawApp.get(`${prefix}/discovery`, (c) => c.json({ data: discovery }));
|
|
465
524
|
ctx.logger.info("Registered discovery endpoints", { prefix });
|
|
466
525
|
const getObjectQL = () => ctx.getService("objectql");
|
|
526
|
+
const resolveCtx = async (c) => {
|
|
527
|
+
try {
|
|
528
|
+
const authService = ctx.getService("auth");
|
|
529
|
+
if (!authService) return void 0;
|
|
530
|
+
let api = authService.api;
|
|
531
|
+
if (!api && typeof authService.getApi === "function") {
|
|
532
|
+
api = await authService.getApi();
|
|
533
|
+
}
|
|
534
|
+
if (!api?.getSession) return void 0;
|
|
535
|
+
const session = await api.getSession({ headers: c.req.raw.headers });
|
|
536
|
+
if (!session?.user?.id) return void 0;
|
|
537
|
+
const userId = session.user.id;
|
|
538
|
+
const tenantId = session.session?.activeOrganizationId ?? void 0;
|
|
539
|
+
const permissions = [];
|
|
540
|
+
const roles = [];
|
|
541
|
+
try {
|
|
542
|
+
const ql = getObjectQL();
|
|
543
|
+
const sysCtx = { context: { isSystem: true } };
|
|
544
|
+
const memberRows = await ql?.find?.(
|
|
545
|
+
"sys_member",
|
|
546
|
+
{
|
|
547
|
+
where: tenantId ? { user_id: userId, organization_id: tenantId } : { user_id: userId },
|
|
548
|
+
limit: 50,
|
|
549
|
+
...sysCtx
|
|
550
|
+
}
|
|
551
|
+
).catch(() => []);
|
|
552
|
+
for (const m of memberRows ?? []) {
|
|
553
|
+
if (typeof m.role === "string") {
|
|
554
|
+
for (const r of m.role.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
555
|
+
if (!roles.includes(r)) roles.push(r);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
const upsRows = await ql?.find?.(
|
|
560
|
+
"sys_user_permission_set",
|
|
561
|
+
{ where: { user_id: userId }, limit: 100, ...sysCtx }
|
|
562
|
+
).catch(() => []);
|
|
563
|
+
const psIds = /* @__PURE__ */ new Set();
|
|
564
|
+
for (const r of upsRows ?? []) {
|
|
565
|
+
const orgScope = r.organization_id ?? null;
|
|
566
|
+
if (!orgScope || tenantId && orgScope === tenantId) {
|
|
567
|
+
const pid = r.permission_set_id ?? r.permissionSetId;
|
|
568
|
+
if (pid) psIds.add(pid);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (psIds.size > 0) {
|
|
572
|
+
const psRows = await ql?.find?.(
|
|
573
|
+
"sys_permission_set",
|
|
574
|
+
{ where: { id: { $in: Array.from(psIds) } }, limit: 500, ...sysCtx }
|
|
575
|
+
).catch(() => []);
|
|
576
|
+
for (const ps of psRows ?? []) {
|
|
577
|
+
if (ps.name && !permissions.includes(ps.name)) permissions.push(ps.name);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
} catch {
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
userId,
|
|
584
|
+
tenantId,
|
|
585
|
+
roles,
|
|
586
|
+
permissions,
|
|
587
|
+
isSystem: false
|
|
588
|
+
};
|
|
589
|
+
} catch {
|
|
590
|
+
return void 0;
|
|
591
|
+
}
|
|
592
|
+
};
|
|
467
593
|
rawApp.post(`${prefix}/data/:object`, async (c) => {
|
|
468
594
|
const ql = getObjectQL();
|
|
469
595
|
if (!ql) return c.json({ error: "Data service not available" }, 503);
|
|
470
596
|
const object = c.req.param("object");
|
|
471
597
|
const data = await c.req.json().catch(() => ({}));
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
598
|
+
const execCtx = await resolveCtx(c);
|
|
599
|
+
try {
|
|
600
|
+
const res = await ql.insert(object, data, { context: execCtx });
|
|
601
|
+
const record = { ...data, ...res };
|
|
602
|
+
return c.json({ object, id: record.id, record });
|
|
603
|
+
} catch (err) {
|
|
604
|
+
if (err?.code === "PERMISSION_DENIED" || err?.name === "PermissionDeniedError") {
|
|
605
|
+
return c.json({ error: err.message ?? "Forbidden" }, 403);
|
|
606
|
+
}
|
|
607
|
+
throw err;
|
|
608
|
+
}
|
|
475
609
|
});
|
|
476
610
|
rawApp.get(`${prefix}/data/:object/:id`, async (c) => {
|
|
477
611
|
const ql = getObjectQL();
|
|
478
612
|
if (!ql) return c.json({ error: "Data service not available" }, 503);
|
|
479
613
|
const object = c.req.param("object");
|
|
480
614
|
const id = c.req.param("id");
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
615
|
+
const execCtx = await resolveCtx(c);
|
|
616
|
+
try {
|
|
617
|
+
let all = await ql.find(object, { context: execCtx });
|
|
618
|
+
if (!all) all = [];
|
|
619
|
+
const match = all.find((i) => i.id === id);
|
|
620
|
+
return match ? c.json({ object, id, record: match }) : c.json({ error: "Not found" }, 404);
|
|
621
|
+
} catch (err) {
|
|
622
|
+
if (err?.code === "PERMISSION_DENIED" || err?.name === "PermissionDeniedError") {
|
|
623
|
+
return c.json({ error: err.message ?? "Forbidden" }, 403);
|
|
624
|
+
}
|
|
625
|
+
throw err;
|
|
626
|
+
}
|
|
485
627
|
});
|
|
486
628
|
rawApp.get(`${prefix}/data/:object`, async (c) => {
|
|
487
629
|
const ql = getObjectQL();
|
|
488
630
|
if (!ql) return c.json({ error: "Data service not available" }, 503);
|
|
489
631
|
const object = c.req.param("object");
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
632
|
+
const execCtx = await resolveCtx(c);
|
|
633
|
+
try {
|
|
634
|
+
let all = await ql.find(object, { context: execCtx });
|
|
635
|
+
if (!Array.isArray(all) && all && all.value) all = all.value;
|
|
636
|
+
if (!all) all = [];
|
|
637
|
+
return c.json({ object, records: all, total: all.length });
|
|
638
|
+
} catch (err) {
|
|
639
|
+
if (err?.code === "PERMISSION_DENIED" || err?.name === "PermissionDeniedError") {
|
|
640
|
+
return c.json({ error: err.message ?? "Forbidden" }, 403);
|
|
641
|
+
}
|
|
642
|
+
throw err;
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
rawApp.get(`${prefix}/auth/me/permissions`, async (c) => {
|
|
646
|
+
const execCtx = await resolveCtx(c);
|
|
647
|
+
if (!execCtx?.userId) {
|
|
648
|
+
return c.json({ authenticated: false });
|
|
649
|
+
}
|
|
650
|
+
try {
|
|
651
|
+
const metadata = ctx.getService("metadata");
|
|
652
|
+
const evaluator = ctx.getService("security.permissions");
|
|
653
|
+
const bootstrap = (() => {
|
|
654
|
+
try {
|
|
655
|
+
return ctx.getService("security.bootstrapPermissionSets") ?? [];
|
|
656
|
+
} catch {
|
|
657
|
+
return [];
|
|
658
|
+
}
|
|
659
|
+
})();
|
|
660
|
+
const fallbackName = (() => {
|
|
661
|
+
try {
|
|
662
|
+
return ctx.getService("security.fallbackPermissionSet") ?? "member_default";
|
|
663
|
+
} catch {
|
|
664
|
+
return "member_default";
|
|
665
|
+
}
|
|
666
|
+
})();
|
|
667
|
+
const ql = (() => {
|
|
668
|
+
try {
|
|
669
|
+
return ctx.getService("objectql");
|
|
670
|
+
} catch {
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
})();
|
|
674
|
+
const dbLoader = ql ? async (names) => {
|
|
675
|
+
let rows;
|
|
676
|
+
try {
|
|
677
|
+
rows = await ql.find(
|
|
678
|
+
"sys_permission_set",
|
|
679
|
+
{ where: { name: { $in: names } }, limit: names.length },
|
|
680
|
+
{ context: { isSystem: true } }
|
|
681
|
+
);
|
|
682
|
+
} catch {
|
|
683
|
+
rows = [];
|
|
684
|
+
}
|
|
685
|
+
const list = Array.isArray(rows) ? rows : rows?.records ?? [];
|
|
686
|
+
return list.map((r) => ({
|
|
687
|
+
name: r.name,
|
|
688
|
+
label: r.label,
|
|
689
|
+
objects: typeof r.object_permissions === "string" ? JSON.parse(r.object_permissions || "{}") : r.object_permissions ?? {},
|
|
690
|
+
fields: typeof r.field_permissions === "string" ? JSON.parse(r.field_permissions || "{}") : r.field_permissions ?? {}
|
|
691
|
+
}));
|
|
692
|
+
} : void 0;
|
|
693
|
+
if (!evaluator || !metadata) {
|
|
694
|
+
return c.json({
|
|
695
|
+
authenticated: true,
|
|
696
|
+
userId: execCtx.userId,
|
|
697
|
+
tenantId: execCtx.tenantId ?? null,
|
|
698
|
+
roles: execCtx.roles ?? [],
|
|
699
|
+
permissionSets: execCtx.permissions ?? [],
|
|
700
|
+
objects: {},
|
|
701
|
+
fields: {}
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
const requested = [
|
|
705
|
+
...execCtx.roles ?? [],
|
|
706
|
+
...execCtx.permissions ?? []
|
|
707
|
+
];
|
|
708
|
+
let resolved = await evaluator.resolvePermissionSets(requested, metadata, bootstrap, dbLoader).catch(() => []);
|
|
709
|
+
if (resolved.length === 0 && fallbackName) {
|
|
710
|
+
resolved = await evaluator.resolvePermissionSets([fallbackName], metadata, bootstrap, dbLoader).catch(() => []);
|
|
711
|
+
}
|
|
712
|
+
const objects = {};
|
|
713
|
+
const fields = {};
|
|
714
|
+
for (const ps of resolved) {
|
|
715
|
+
if (ps?.objects) {
|
|
716
|
+
for (const [obj, perm] of Object.entries(ps.objects)) {
|
|
717
|
+
const acc = objects[obj] ?? {};
|
|
718
|
+
for (const [k, v] of Object.entries(perm)) {
|
|
719
|
+
if (v === true) acc[k] = true;
|
|
720
|
+
else if (acc[k] === void 0) acc[k] = v;
|
|
721
|
+
}
|
|
722
|
+
objects[obj] = acc;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (ps?.fields) {
|
|
726
|
+
for (const [key, perm] of Object.entries(ps.fields)) {
|
|
727
|
+
const acc = fields[key] ?? { readable: false, editable: false };
|
|
728
|
+
const p = perm;
|
|
729
|
+
if (p.readable) acc.readable = true;
|
|
730
|
+
if (p.editable) acc.editable = true;
|
|
731
|
+
fields[key] = acc;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return c.json({
|
|
736
|
+
authenticated: true,
|
|
737
|
+
userId: execCtx.userId,
|
|
738
|
+
tenantId: execCtx.tenantId ?? null,
|
|
739
|
+
roles: execCtx.roles ?? [],
|
|
740
|
+
permissionSets: resolved.map((p) => p?.name).filter(Boolean),
|
|
741
|
+
objects,
|
|
742
|
+
fields
|
|
743
|
+
});
|
|
744
|
+
} catch (err) {
|
|
745
|
+
ctx.logger.warn("[hono] /auth/me/permissions failed", { err: err?.message });
|
|
746
|
+
return c.json({ authenticated: true, userId: execCtx.userId, objects: {}, fields: {} });
|
|
747
|
+
}
|
|
494
748
|
});
|
|
495
749
|
ctx.logger.debug("Registered standard CRUD data endpoints", { prefix });
|
|
496
750
|
}
|
|
@@ -512,6 +766,11 @@ __reExport(index_exports, adapter_exports, module.exports);
|
|
|
512
766
|
// Annotate the CommonJS export names for ESM import in node:
|
|
513
767
|
0 && (module.exports = {
|
|
514
768
|
HonoHttpServer,
|
|
515
|
-
HonoServerPlugin
|
|
769
|
+
HonoServerPlugin,
|
|
770
|
+
createOriginMatcher,
|
|
771
|
+
hasWildcardPattern,
|
|
772
|
+
isLocalhostOrigin,
|
|
773
|
+
matchOriginPattern,
|
|
774
|
+
normalizeOriginPatterns
|
|
516
775
|
});
|
|
517
776
|
//# sourceMappingURL=index.js.map
|