@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.mjs
CHANGED
|
@@ -22,7 +22,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
24
|
HonoHttpServer: () => HonoHttpServer,
|
|
25
|
-
HonoServerPlugin: () => HonoServerPlugin
|
|
25
|
+
HonoServerPlugin: () => HonoServerPlugin,
|
|
26
|
+
createOriginMatcher: () => createOriginMatcher,
|
|
27
|
+
hasWildcardPattern: () => hasWildcardPattern,
|
|
28
|
+
isLocalhostOrigin: () => isLocalhostOrigin,
|
|
29
|
+
matchOriginPattern: () => matchOriginPattern,
|
|
30
|
+
normalizeOriginPatterns: () => normalizeOriginPatterns
|
|
26
31
|
});
|
|
27
32
|
|
|
28
33
|
// src/adapter.ts
|
|
@@ -48,7 +53,9 @@ var HonoHttpServer = class {
|
|
|
48
53
|
wrap(handler) {
|
|
49
54
|
return async (c) => {
|
|
50
55
|
let body = {};
|
|
51
|
-
|
|
56
|
+
const contentType = c.req.header("content-type") ?? "";
|
|
57
|
+
const isOctetStream = contentType.includes("application/octet-stream");
|
|
58
|
+
if (contentType.includes("application/json")) {
|
|
52
59
|
try {
|
|
53
60
|
body = await c.req.json();
|
|
54
61
|
} catch (e) {
|
|
@@ -57,19 +64,31 @@ var HonoHttpServer = class {
|
|
|
57
64
|
} catch (e2) {
|
|
58
65
|
}
|
|
59
66
|
}
|
|
60
|
-
} else {
|
|
67
|
+
} else if (!isOctetStream) {
|
|
61
68
|
try {
|
|
62
69
|
body = await c.req.parseBody();
|
|
63
70
|
} catch (e) {
|
|
64
71
|
}
|
|
65
72
|
}
|
|
73
|
+
const rawHeaders = c.req.header();
|
|
74
|
+
if (!rawHeaders.host) {
|
|
75
|
+
try {
|
|
76
|
+
const u = new URL(c.req.url);
|
|
77
|
+
if (u.host) rawHeaders.host = u.host;
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
}
|
|
66
81
|
const req = {
|
|
67
82
|
params: c.req.param(),
|
|
68
83
|
query: c.req.query(),
|
|
69
84
|
body,
|
|
70
|
-
headers:
|
|
85
|
+
headers: rawHeaders,
|
|
71
86
|
method: c.req.method,
|
|
72
|
-
path: c.req.path
|
|
87
|
+
path: c.req.path,
|
|
88
|
+
rawBody: async () => {
|
|
89
|
+
const ab = await c.req.arrayBuffer();
|
|
90
|
+
return Buffer.from(ab);
|
|
91
|
+
}
|
|
73
92
|
};
|
|
74
93
|
let capturedResponse;
|
|
75
94
|
let streamController = null;
|
|
@@ -124,13 +143,13 @@ var HonoHttpServer = class {
|
|
|
124
143
|
streamController?.close();
|
|
125
144
|
resolve2(null);
|
|
126
145
|
}
|
|
127
|
-
}).catch(() => {
|
|
146
|
+
}).catch((err) => {
|
|
128
147
|
streamController?.close();
|
|
129
148
|
resolve2(null);
|
|
130
149
|
});
|
|
131
150
|
});
|
|
132
151
|
const streamResponse = await streamPromise;
|
|
133
|
-
return streamResponse ?? capturedResponse;
|
|
152
|
+
return streamResponse ?? capturedResponse ?? c.json({ error: "No response from handler" }, 500);
|
|
134
153
|
};
|
|
135
154
|
}
|
|
136
155
|
get(path2, handler) {
|
|
@@ -151,11 +170,23 @@ var HonoHttpServer = class {
|
|
|
151
170
|
use(pathOrHandler, handler) {
|
|
152
171
|
if (typeof pathOrHandler === "string" && handler) {
|
|
153
172
|
this.app.use(pathOrHandler, async (c, next) => {
|
|
154
|
-
|
|
173
|
+
let nextCalled = false;
|
|
174
|
+
const wrappedNext = () => {
|
|
175
|
+
nextCalled = true;
|
|
176
|
+
return next();
|
|
177
|
+
};
|
|
178
|
+
await handler({}, {}, wrappedNext);
|
|
179
|
+
if (!nextCalled) await next();
|
|
155
180
|
});
|
|
156
181
|
} else if (typeof pathOrHandler === "function") {
|
|
157
182
|
this.app.use("*", async (c, next) => {
|
|
158
|
-
|
|
183
|
+
let nextCalled = false;
|
|
184
|
+
const wrappedNext = () => {
|
|
185
|
+
nextCalled = true;
|
|
186
|
+
return next();
|
|
187
|
+
};
|
|
188
|
+
await pathOrHandler({}, {}, wrappedNext);
|
|
189
|
+
if (!nextCalled) await next();
|
|
159
190
|
});
|
|
160
191
|
}
|
|
161
192
|
}
|
|
@@ -210,9 +241,13 @@ var HonoHttpServer = class {
|
|
|
210
241
|
return this.app;
|
|
211
242
|
}
|
|
212
243
|
async close() {
|
|
213
|
-
if (this.server
|
|
214
|
-
|
|
244
|
+
if (!this.server) return;
|
|
245
|
+
if (typeof this.server.closeAllConnections === "function") {
|
|
246
|
+
this.server.closeAllConnections();
|
|
215
247
|
}
|
|
248
|
+
await new Promise((resolve2, reject) => {
|
|
249
|
+
this.server.close((err) => err ? reject(err) : resolve2());
|
|
250
|
+
});
|
|
216
251
|
}
|
|
217
252
|
};
|
|
218
253
|
|
|
@@ -221,21 +256,29 @@ import { cors } from "hono/cors";
|
|
|
221
256
|
import { serveStatic as serveStatic2 } from "@hono/node-server/serve-static";
|
|
222
257
|
import * as fs from "fs";
|
|
223
258
|
import * as path from "path";
|
|
259
|
+
|
|
260
|
+
// src/pattern-matcher.ts
|
|
261
|
+
function isLocalhostOrigin(origin) {
|
|
262
|
+
return /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/.test(origin);
|
|
263
|
+
}
|
|
224
264
|
function matchOriginPattern(origin, pattern) {
|
|
265
|
+
if (isLocalhostOrigin(origin)) return true;
|
|
225
266
|
if (pattern === "*") return true;
|
|
226
267
|
if (pattern === origin) return true;
|
|
227
268
|
const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
228
269
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
229
270
|
return regex.test(origin);
|
|
230
271
|
}
|
|
231
|
-
function
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
patternList = patterns.includes(",") ? patterns.split(",").map((s) => s.trim()).filter(Boolean) : [patterns];
|
|
235
|
-
} else {
|
|
236
|
-
patternList = patterns;
|
|
272
|
+
function normalizeOriginPatterns(patterns) {
|
|
273
|
+
if (Array.isArray(patterns)) {
|
|
274
|
+
return patterns.map((p) => p.trim()).filter(Boolean);
|
|
237
275
|
}
|
|
276
|
+
return patterns.includes(",") ? patterns.split(",").map((s) => s.trim()).filter(Boolean) : [patterns.trim()].filter(Boolean);
|
|
277
|
+
}
|
|
278
|
+
function createOriginMatcher(patterns) {
|
|
279
|
+
const patternList = normalizeOriginPatterns(patterns);
|
|
238
280
|
return (requestOrigin) => {
|
|
281
|
+
if (!requestOrigin) return null;
|
|
239
282
|
for (const pattern of patternList) {
|
|
240
283
|
if (matchOriginPattern(requestOrigin, pattern)) {
|
|
241
284
|
return requestOrigin;
|
|
@@ -244,6 +287,12 @@ function createOriginMatcher(patterns) {
|
|
|
244
287
|
return null;
|
|
245
288
|
};
|
|
246
289
|
}
|
|
290
|
+
function hasWildcardPattern(patterns) {
|
|
291
|
+
const list = Array.isArray(patterns) ? patterns : [patterns];
|
|
292
|
+
return list.some((p) => p.includes("*"));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/hono-plugin.ts
|
|
247
296
|
var HonoServerPlugin = class {
|
|
248
297
|
constructor(options = {}) {
|
|
249
298
|
__publicField(this, "name", "com.objectstack.server.hono");
|
|
@@ -279,23 +328,27 @@ var HonoServerPlugin = class {
|
|
|
279
328
|
const credentials = corsOpts.credentials ?? process.env.CORS_CREDENTIALS !== "false";
|
|
280
329
|
const maxAge = corsOpts.maxAge ?? (process.env.CORS_MAX_AGE ? parseInt(process.env.CORS_MAX_AGE, 10) : 86400);
|
|
281
330
|
let origin;
|
|
282
|
-
const hasWildcard = (patterns) => {
|
|
283
|
-
const list = Array.isArray(patterns) ? patterns : [patterns];
|
|
284
|
-
return list.some((p) => p.includes("*"));
|
|
285
|
-
};
|
|
286
331
|
if (configuredOrigin === "*" && credentials) {
|
|
287
332
|
origin = (requestOrigin) => requestOrigin || "*";
|
|
288
|
-
} else if (
|
|
333
|
+
} else if (hasWildcardPattern(configuredOrigin)) {
|
|
289
334
|
origin = createOriginMatcher(configuredOrigin);
|
|
290
335
|
} else {
|
|
291
|
-
|
|
336
|
+
const matcher = createOriginMatcher(configuredOrigin);
|
|
337
|
+
origin = (requestOrigin) => matcher(requestOrigin);
|
|
292
338
|
}
|
|
293
339
|
const rawApp = this.server.getRawApp();
|
|
340
|
+
const defaultAllowHeaders = ["Content-Type", "Authorization", "X-Requested-With", "X-Tenant-ID", "X-Project-Id"];
|
|
341
|
+
const defaultExposeHeaders = ["set-auth-token"];
|
|
342
|
+
const allowHeaders = corsOpts.allowHeaders ?? defaultAllowHeaders;
|
|
343
|
+
const exposeHeaders = Array.from(/* @__PURE__ */ new Set([
|
|
344
|
+
...defaultExposeHeaders,
|
|
345
|
+
...corsOpts.exposeHeaders ?? []
|
|
346
|
+
]));
|
|
294
347
|
rawApp.use("*", cors({
|
|
295
348
|
origin,
|
|
296
349
|
allowMethods: corsOpts.methods || ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"],
|
|
297
|
-
allowHeaders
|
|
298
|
-
exposeHeaders
|
|
350
|
+
allowHeaders,
|
|
351
|
+
exposeHeaders,
|
|
299
352
|
credentials,
|
|
300
353
|
maxAge
|
|
301
354
|
}));
|
|
@@ -396,10 +449,16 @@ var HonoServerPlugin = class {
|
|
|
396
449
|
});
|
|
397
450
|
}
|
|
398
451
|
}
|
|
399
|
-
|
|
400
|
-
|
|
452
|
+
const rawAppForNotFound = this.server.getRawApp();
|
|
453
|
+
if (typeof rawAppForNotFound.notFound === "function") {
|
|
454
|
+
rawAppForNotFound.notFound((c) => c.json({ error: "Not found" }, 404));
|
|
455
|
+
}
|
|
456
|
+
if (this.options.registerStandardEndpoints) {
|
|
457
|
+
ctx.hook("kernel:ready", async () => {
|
|
401
458
|
this.registerDiscoveryAndCrudEndpoints(ctx);
|
|
402
|
-
}
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
ctx.hook("kernel:listening", async () => {
|
|
403
462
|
const port = this.options.port ?? 3e3;
|
|
404
463
|
ctx.logger.debug("Starting HTTP server", { port });
|
|
405
464
|
await this.server.listen(port);
|
|
@@ -452,33 +511,228 @@ var HonoServerPlugin = class {
|
|
|
452
511
|
rawApp.get(`${prefix}/discovery`, (c) => c.json({ data: discovery }));
|
|
453
512
|
ctx.logger.info("Registered discovery endpoints", { prefix });
|
|
454
513
|
const getObjectQL = () => ctx.getService("objectql");
|
|
514
|
+
const resolveCtx = async (c) => {
|
|
515
|
+
try {
|
|
516
|
+
const authService = ctx.getService("auth");
|
|
517
|
+
if (!authService) return void 0;
|
|
518
|
+
let api = authService.api;
|
|
519
|
+
if (!api && typeof authService.getApi === "function") {
|
|
520
|
+
api = await authService.getApi();
|
|
521
|
+
}
|
|
522
|
+
if (!api?.getSession) return void 0;
|
|
523
|
+
const session = await api.getSession({ headers: c.req.raw.headers });
|
|
524
|
+
if (!session?.user?.id) return void 0;
|
|
525
|
+
const userId = session.user.id;
|
|
526
|
+
const tenantId = session.session?.activeOrganizationId ?? void 0;
|
|
527
|
+
const permissions = [];
|
|
528
|
+
const roles = [];
|
|
529
|
+
try {
|
|
530
|
+
const ql = getObjectQL();
|
|
531
|
+
const sysCtx = { context: { isSystem: true } };
|
|
532
|
+
const memberRows = await ql?.find?.(
|
|
533
|
+
"sys_member",
|
|
534
|
+
{
|
|
535
|
+
where: tenantId ? { user_id: userId, organization_id: tenantId } : { user_id: userId },
|
|
536
|
+
limit: 50,
|
|
537
|
+
...sysCtx
|
|
538
|
+
}
|
|
539
|
+
).catch(() => []);
|
|
540
|
+
for (const m of memberRows ?? []) {
|
|
541
|
+
if (typeof m.role === "string") {
|
|
542
|
+
for (const r of m.role.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
543
|
+
if (!roles.includes(r)) roles.push(r);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
const upsRows = await ql?.find?.(
|
|
548
|
+
"sys_user_permission_set",
|
|
549
|
+
{ where: { user_id: userId }, limit: 100, ...sysCtx }
|
|
550
|
+
).catch(() => []);
|
|
551
|
+
const psIds = /* @__PURE__ */ new Set();
|
|
552
|
+
for (const r of upsRows ?? []) {
|
|
553
|
+
const orgScope = r.organization_id ?? null;
|
|
554
|
+
if (!orgScope || tenantId && orgScope === tenantId) {
|
|
555
|
+
const pid = r.permission_set_id ?? r.permissionSetId;
|
|
556
|
+
if (pid) psIds.add(pid);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (psIds.size > 0) {
|
|
560
|
+
const psRows = await ql?.find?.(
|
|
561
|
+
"sys_permission_set",
|
|
562
|
+
{ where: { id: { $in: Array.from(psIds) } }, limit: 500, ...sysCtx }
|
|
563
|
+
).catch(() => []);
|
|
564
|
+
for (const ps of psRows ?? []) {
|
|
565
|
+
if (ps.name && !permissions.includes(ps.name)) permissions.push(ps.name);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
} catch {
|
|
569
|
+
}
|
|
570
|
+
return {
|
|
571
|
+
userId,
|
|
572
|
+
tenantId,
|
|
573
|
+
roles,
|
|
574
|
+
permissions,
|
|
575
|
+
isSystem: false
|
|
576
|
+
};
|
|
577
|
+
} catch {
|
|
578
|
+
return void 0;
|
|
579
|
+
}
|
|
580
|
+
};
|
|
455
581
|
rawApp.post(`${prefix}/data/:object`, async (c) => {
|
|
456
582
|
const ql = getObjectQL();
|
|
457
583
|
if (!ql) return c.json({ error: "Data service not available" }, 503);
|
|
458
584
|
const object = c.req.param("object");
|
|
459
585
|
const data = await c.req.json().catch(() => ({}));
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
586
|
+
const execCtx = await resolveCtx(c);
|
|
587
|
+
try {
|
|
588
|
+
const res = await ql.insert(object, data, { context: execCtx });
|
|
589
|
+
const record = { ...data, ...res };
|
|
590
|
+
return c.json({ object, id: record.id, record });
|
|
591
|
+
} catch (err) {
|
|
592
|
+
if (err?.code === "PERMISSION_DENIED" || err?.name === "PermissionDeniedError") {
|
|
593
|
+
return c.json({ error: err.message ?? "Forbidden" }, 403);
|
|
594
|
+
}
|
|
595
|
+
throw err;
|
|
596
|
+
}
|
|
463
597
|
});
|
|
464
598
|
rawApp.get(`${prefix}/data/:object/:id`, async (c) => {
|
|
465
599
|
const ql = getObjectQL();
|
|
466
600
|
if (!ql) return c.json({ error: "Data service not available" }, 503);
|
|
467
601
|
const object = c.req.param("object");
|
|
468
602
|
const id = c.req.param("id");
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
603
|
+
const execCtx = await resolveCtx(c);
|
|
604
|
+
try {
|
|
605
|
+
let all = await ql.find(object, { context: execCtx });
|
|
606
|
+
if (!all) all = [];
|
|
607
|
+
const match = all.find((i) => i.id === id);
|
|
608
|
+
return match ? c.json({ object, id, record: match }) : c.json({ error: "Not found" }, 404);
|
|
609
|
+
} catch (err) {
|
|
610
|
+
if (err?.code === "PERMISSION_DENIED" || err?.name === "PermissionDeniedError") {
|
|
611
|
+
return c.json({ error: err.message ?? "Forbidden" }, 403);
|
|
612
|
+
}
|
|
613
|
+
throw err;
|
|
614
|
+
}
|
|
473
615
|
});
|
|
474
616
|
rawApp.get(`${prefix}/data/:object`, async (c) => {
|
|
475
617
|
const ql = getObjectQL();
|
|
476
618
|
if (!ql) return c.json({ error: "Data service not available" }, 503);
|
|
477
619
|
const object = c.req.param("object");
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
620
|
+
const execCtx = await resolveCtx(c);
|
|
621
|
+
try {
|
|
622
|
+
let all = await ql.find(object, { context: execCtx });
|
|
623
|
+
if (!Array.isArray(all) && all && all.value) all = all.value;
|
|
624
|
+
if (!all) all = [];
|
|
625
|
+
return c.json({ object, records: all, total: all.length });
|
|
626
|
+
} catch (err) {
|
|
627
|
+
if (err?.code === "PERMISSION_DENIED" || err?.name === "PermissionDeniedError") {
|
|
628
|
+
return c.json({ error: err.message ?? "Forbidden" }, 403);
|
|
629
|
+
}
|
|
630
|
+
throw err;
|
|
631
|
+
}
|
|
632
|
+
});
|
|
633
|
+
rawApp.get(`${prefix}/auth/me/permissions`, async (c) => {
|
|
634
|
+
const execCtx = await resolveCtx(c);
|
|
635
|
+
if (!execCtx?.userId) {
|
|
636
|
+
return c.json({ authenticated: false });
|
|
637
|
+
}
|
|
638
|
+
try {
|
|
639
|
+
const metadata = ctx.getService("metadata");
|
|
640
|
+
const evaluator = ctx.getService("security.permissions");
|
|
641
|
+
const bootstrap = (() => {
|
|
642
|
+
try {
|
|
643
|
+
return ctx.getService("security.bootstrapPermissionSets") ?? [];
|
|
644
|
+
} catch {
|
|
645
|
+
return [];
|
|
646
|
+
}
|
|
647
|
+
})();
|
|
648
|
+
const fallbackName = (() => {
|
|
649
|
+
try {
|
|
650
|
+
return ctx.getService("security.fallbackPermissionSet") ?? "member_default";
|
|
651
|
+
} catch {
|
|
652
|
+
return "member_default";
|
|
653
|
+
}
|
|
654
|
+
})();
|
|
655
|
+
const ql = (() => {
|
|
656
|
+
try {
|
|
657
|
+
return ctx.getService("objectql");
|
|
658
|
+
} catch {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
})();
|
|
662
|
+
const dbLoader = ql ? async (names) => {
|
|
663
|
+
let rows;
|
|
664
|
+
try {
|
|
665
|
+
rows = await ql.find(
|
|
666
|
+
"sys_permission_set",
|
|
667
|
+
{ where: { name: { $in: names } }, limit: names.length },
|
|
668
|
+
{ context: { isSystem: true } }
|
|
669
|
+
);
|
|
670
|
+
} catch {
|
|
671
|
+
rows = [];
|
|
672
|
+
}
|
|
673
|
+
const list = Array.isArray(rows) ? rows : rows?.records ?? [];
|
|
674
|
+
return list.map((r) => ({
|
|
675
|
+
name: r.name,
|
|
676
|
+
label: r.label,
|
|
677
|
+
objects: typeof r.object_permissions === "string" ? JSON.parse(r.object_permissions || "{}") : r.object_permissions ?? {},
|
|
678
|
+
fields: typeof r.field_permissions === "string" ? JSON.parse(r.field_permissions || "{}") : r.field_permissions ?? {}
|
|
679
|
+
}));
|
|
680
|
+
} : void 0;
|
|
681
|
+
if (!evaluator || !metadata) {
|
|
682
|
+
return c.json({
|
|
683
|
+
authenticated: true,
|
|
684
|
+
userId: execCtx.userId,
|
|
685
|
+
tenantId: execCtx.tenantId ?? null,
|
|
686
|
+
roles: execCtx.roles ?? [],
|
|
687
|
+
permissionSets: execCtx.permissions ?? [],
|
|
688
|
+
objects: {},
|
|
689
|
+
fields: {}
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
const requested = [
|
|
693
|
+
...execCtx.roles ?? [],
|
|
694
|
+
...execCtx.permissions ?? []
|
|
695
|
+
];
|
|
696
|
+
let resolved = await evaluator.resolvePermissionSets(requested, metadata, bootstrap, dbLoader).catch(() => []);
|
|
697
|
+
if (resolved.length === 0 && fallbackName) {
|
|
698
|
+
resolved = await evaluator.resolvePermissionSets([fallbackName], metadata, bootstrap, dbLoader).catch(() => []);
|
|
699
|
+
}
|
|
700
|
+
const objects = {};
|
|
701
|
+
const fields = {};
|
|
702
|
+
for (const ps of resolved) {
|
|
703
|
+
if (ps?.objects) {
|
|
704
|
+
for (const [obj, perm] of Object.entries(ps.objects)) {
|
|
705
|
+
const acc = objects[obj] ?? {};
|
|
706
|
+
for (const [k, v] of Object.entries(perm)) {
|
|
707
|
+
if (v === true) acc[k] = true;
|
|
708
|
+
else if (acc[k] === void 0) acc[k] = v;
|
|
709
|
+
}
|
|
710
|
+
objects[obj] = acc;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (ps?.fields) {
|
|
714
|
+
for (const [key, perm] of Object.entries(ps.fields)) {
|
|
715
|
+
const acc = fields[key] ?? { readable: false, editable: false };
|
|
716
|
+
const p = perm;
|
|
717
|
+
if (p.readable) acc.readable = true;
|
|
718
|
+
if (p.editable) acc.editable = true;
|
|
719
|
+
fields[key] = acc;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return c.json({
|
|
724
|
+
authenticated: true,
|
|
725
|
+
userId: execCtx.userId,
|
|
726
|
+
tenantId: execCtx.tenantId ?? null,
|
|
727
|
+
roles: execCtx.roles ?? [],
|
|
728
|
+
permissionSets: resolved.map((p) => p?.name).filter(Boolean),
|
|
729
|
+
objects,
|
|
730
|
+
fields
|
|
731
|
+
});
|
|
732
|
+
} catch (err) {
|
|
733
|
+
ctx.logger.warn("[hono] /auth/me/permissions failed", { err: err?.message });
|
|
734
|
+
return c.json({ authenticated: true, userId: execCtx.userId, objects: {}, fields: {} });
|
|
735
|
+
}
|
|
482
736
|
});
|
|
483
737
|
ctx.logger.debug("Registered standard CRUD data endpoints", { prefix });
|
|
484
738
|
}
|
|
@@ -499,6 +753,11 @@ __publicField(HonoServerPlugin, "DISCOVERY_ENDPOINT_PRIORITY", 900);
|
|
|
499
753
|
__reExport(index_exports, adapter_exports);
|
|
500
754
|
export {
|
|
501
755
|
HonoHttpServer,
|
|
502
|
-
HonoServerPlugin
|
|
756
|
+
HonoServerPlugin,
|
|
757
|
+
createOriginMatcher,
|
|
758
|
+
hasWildcardPattern,
|
|
759
|
+
isLocalhostOrigin,
|
|
760
|
+
matchOriginPattern,
|
|
761
|
+
normalizeOriginPatterns
|
|
503
762
|
};
|
|
504
763
|
//# sourceMappingURL=index.mjs.map
|