@invect/rbac 0.0.1 → 0.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/README.md +39 -77
- package/dist/backend/index.cjs +72 -40
- package/dist/backend/index.cjs.map +1 -1
- package/dist/backend/index.d.cts +49 -0
- package/dist/backend/index.d.cts.map +1 -0
- package/dist/backend/index.d.mts +49 -0
- package/dist/backend/index.d.mts.map +1 -0
- package/dist/backend/index.d.ts +1 -1
- package/dist/backend/index.d.ts.map +1 -1
- package/dist/backend/index.mjs +72 -40
- package/dist/backend/index.mjs.map +1 -1
- package/dist/backend/plugin.d.ts +12 -14
- package/dist/backend/plugin.d.ts.map +1 -1
- package/dist/frontend/components/TeamsPage.d.ts.map +1 -1
- package/dist/frontend/components/access-control/ScopeDetailPanel.d.ts.map +1 -1
- package/dist/frontend/components/access-control/index.d.ts +0 -1
- package/dist/frontend/components/access-control/index.d.ts.map +1 -1
- package/dist/frontend/index.cjs +61 -61
- package/dist/frontend/index.cjs.map +1 -1
- package/dist/frontend/index.d.cts +227 -0
- package/dist/frontend/index.d.cts.map +1 -0
- package/dist/frontend/index.d.mts +227 -0
- package/dist/frontend/index.d.mts.map +1 -0
- package/dist/frontend/index.d.ts +2 -2
- package/dist/frontend/index.d.ts.map +1 -1
- package/dist/frontend/index.mjs +7 -7
- package/dist/frontend/index.mjs.map +1 -1
- package/dist/frontend/types.d.ts +1 -1
- package/dist/shared/types.d.cts +2 -0
- package/dist/shared/types.d.mts +2 -0
- package/dist/types-D4DI2gyU.d.cts +175 -0
- package/dist/types-D4DI2gyU.d.cts.map +1 -0
- package/dist/types-DxJoguYy.d.mts +175 -0
- package/dist/types-DxJoguYy.d.mts.map +1 -0
- package/package.json +44 -46
package/dist/backend/index.mjs
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* ```ts
|
|
9
9
|
* import { resolveTeamIds } from '@invect/rbac/backend';
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* auth,
|
|
11
|
+
* auth({
|
|
12
|
+
* auth: betterAuthInstance,
|
|
13
13
|
* mapUser: async (user, session) => ({
|
|
14
14
|
* id: user.id,
|
|
15
15
|
* name: user.name ?? undefined,
|
|
@@ -197,6 +197,58 @@ async function listAllDirectFlowAccess(db, flowId) {
|
|
|
197
197
|
const now = Date.now();
|
|
198
198
|
return rows.map(normalizeFlowAccessRecord).filter((record) => !record.expiresAt || new Date(record.expiresAt).getTime() > now);
|
|
199
199
|
}
|
|
200
|
+
async function grantDirectFlowAccess(db, input) {
|
|
201
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
202
|
+
const existingRows = await db.query("SELECT id FROM flow_access WHERE flow_id = ? AND user_id IS ? AND team_id IS ?", [
|
|
203
|
+
input.flowId,
|
|
204
|
+
input.userId ?? null,
|
|
205
|
+
input.teamId ?? null
|
|
206
|
+
]);
|
|
207
|
+
if (existingRows.length > 0) {
|
|
208
|
+
const existingId = String(existingRows[0].id);
|
|
209
|
+
await db.execute("UPDATE flow_access SET permission = ?, granted_by = ?, granted_at = ?, expires_at = ? WHERE id = ?", [
|
|
210
|
+
input.permission,
|
|
211
|
+
input.grantedBy ?? null,
|
|
212
|
+
now,
|
|
213
|
+
input.expiresAt ?? null,
|
|
214
|
+
existingId
|
|
215
|
+
]);
|
|
216
|
+
return {
|
|
217
|
+
id: existingId,
|
|
218
|
+
flowId: input.flowId,
|
|
219
|
+
userId: input.userId ?? null,
|
|
220
|
+
teamId: input.teamId ?? null,
|
|
221
|
+
permission: input.permission,
|
|
222
|
+
grantedBy: input.grantedBy ?? null,
|
|
223
|
+
grantedAt: now,
|
|
224
|
+
expiresAt: input.expiresAt ?? null
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const id = crypto.randomUUID();
|
|
228
|
+
await db.execute("INSERT INTO flow_access (id, flow_id, user_id, team_id, permission, granted_by, granted_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [
|
|
229
|
+
id,
|
|
230
|
+
input.flowId,
|
|
231
|
+
input.userId ?? null,
|
|
232
|
+
input.teamId ?? null,
|
|
233
|
+
input.permission,
|
|
234
|
+
input.grantedBy ?? null,
|
|
235
|
+
now,
|
|
236
|
+
input.expiresAt ?? null
|
|
237
|
+
]);
|
|
238
|
+
return {
|
|
239
|
+
id,
|
|
240
|
+
flowId: input.flowId,
|
|
241
|
+
userId: input.userId ?? null,
|
|
242
|
+
teamId: input.teamId ?? null,
|
|
243
|
+
permission: input.permission,
|
|
244
|
+
grantedBy: input.grantedBy ?? null,
|
|
245
|
+
grantedAt: now,
|
|
246
|
+
expiresAt: input.expiresAt ?? null
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
async function revokeDirectFlowAccess(db, accessId) {
|
|
250
|
+
await db.execute("DELETE FROM flow_access WHERE id = ?", [accessId]);
|
|
251
|
+
}
|
|
200
252
|
async function listAllEffectiveFlowAccessForPreview(db, flowId, overrideScopeId) {
|
|
201
253
|
const direct = await listAllDirectFlowAccess(db, flowId);
|
|
202
254
|
const scopeId = overrideScopeId === void 0 ? await getFlowScopeId(db, flowId) : overrideScopeId;
|
|
@@ -279,8 +331,17 @@ async function resolveAccessChangeNames(db, entries) {
|
|
|
279
331
|
source: entry.source
|
|
280
332
|
}));
|
|
281
333
|
}
|
|
282
|
-
function
|
|
283
|
-
const {
|
|
334
|
+
function rbac(options = {}) {
|
|
335
|
+
const { frontend, ...backendOptions } = options;
|
|
336
|
+
return {
|
|
337
|
+
id: "rbac",
|
|
338
|
+
name: "Role-Based Access Control",
|
|
339
|
+
backend: _rbacBackendPlugin(backendOptions),
|
|
340
|
+
frontend
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function _rbacBackendPlugin(options = {}) {
|
|
344
|
+
const { adminPermission = "flow:read", enableTeams = true } = options;
|
|
284
345
|
const teamsSchema = enableTeams ? {
|
|
285
346
|
flows: { fields: { scope_id: {
|
|
286
347
|
type: "string",
|
|
@@ -444,10 +505,10 @@ function rbacPlugin(options = {}) {
|
|
|
444
505
|
"rbac_scope_access"
|
|
445
506
|
] : []
|
|
446
507
|
],
|
|
447
|
-
setupInstructions: "The RBAC plugin requires
|
|
508
|
+
setupInstructions: "The RBAC plugin requires user-auth tables (user, session). Make sure @invect/user-auth is configured, then run `npx invect-cli generate` followed by `npx drizzle-kit push`.",
|
|
448
509
|
init: async (ctx) => {
|
|
449
|
-
if (!ctx.hasPlugin("
|
|
450
|
-
ctx.logger.info("RBAC plugin initialized"
|
|
510
|
+
if (!ctx.hasPlugin("user-auth")) ctx.logger.warn("RBAC plugin requires the @invect/user-auth plugin. RBAC will work with reduced functionality (no session resolution). Make sure auth() is registered before rbac().");
|
|
511
|
+
ctx.logger.info("RBAC plugin initialized");
|
|
451
512
|
},
|
|
452
513
|
endpoints: [
|
|
453
514
|
{
|
|
@@ -510,13 +571,6 @@ function rbacPlugin(options = {}) {
|
|
|
510
571
|
status: 400,
|
|
511
572
|
body: { error: "Missing flowId parameter" }
|
|
512
573
|
};
|
|
513
|
-
if (!ctx.core.isFlowAccessTableEnabled()) return {
|
|
514
|
-
status: 501,
|
|
515
|
-
body: {
|
|
516
|
-
error: "Not Implemented",
|
|
517
|
-
message: "Flow access table not enabled. Set auth.useFlowAccessTable: true in config."
|
|
518
|
-
}
|
|
519
|
-
};
|
|
520
574
|
if (!ctx.identity) return {
|
|
521
575
|
status: 401,
|
|
522
576
|
body: {
|
|
@@ -533,7 +587,7 @@ function rbacPlugin(options = {}) {
|
|
|
533
587
|
};
|
|
534
588
|
return {
|
|
535
589
|
status: 200,
|
|
536
|
-
body: { access: await ctx.
|
|
590
|
+
body: { access: await listAllDirectFlowAccess(ctx.database, flowId) }
|
|
537
591
|
};
|
|
538
592
|
}
|
|
539
593
|
},
|
|
@@ -547,13 +601,6 @@ function rbacPlugin(options = {}) {
|
|
|
547
601
|
status: 400,
|
|
548
602
|
body: { error: "Missing flowId parameter" }
|
|
549
603
|
};
|
|
550
|
-
if (!ctx.core.isFlowAccessTableEnabled()) return {
|
|
551
|
-
status: 501,
|
|
552
|
-
body: {
|
|
553
|
-
error: "Not Implemented",
|
|
554
|
-
message: "Flow access table not enabled. Set auth.useFlowAccessTable: true in config."
|
|
555
|
-
}
|
|
556
|
-
};
|
|
557
604
|
const { userId, teamId, permission, expiresAt } = ctx.body;
|
|
558
605
|
if (!userId && !teamId) return {
|
|
559
606
|
status: 400,
|
|
@@ -584,7 +631,7 @@ function rbacPlugin(options = {}) {
|
|
|
584
631
|
};
|
|
585
632
|
return {
|
|
586
633
|
status: 201,
|
|
587
|
-
body: await ctx.
|
|
634
|
+
body: await grantDirectFlowAccess(ctx.database, {
|
|
588
635
|
flowId,
|
|
589
636
|
userId,
|
|
590
637
|
teamId,
|
|
@@ -605,13 +652,6 @@ function rbacPlugin(options = {}) {
|
|
|
605
652
|
status: 400,
|
|
606
653
|
body: { error: "Missing flowId or accessId parameter" }
|
|
607
654
|
};
|
|
608
|
-
if (!ctx.core.isFlowAccessTableEnabled()) return {
|
|
609
|
-
status: 501,
|
|
610
|
-
body: {
|
|
611
|
-
error: "Not Implemented",
|
|
612
|
-
message: "Flow access table not enabled. Set auth.useFlowAccessTable: true in config."
|
|
613
|
-
}
|
|
614
|
-
};
|
|
615
655
|
if (!ctx.identity) return {
|
|
616
656
|
status: 401,
|
|
617
657
|
body: {
|
|
@@ -626,7 +666,7 @@ function rbacPlugin(options = {}) {
|
|
|
626
666
|
message: "Owner access is required to manage sharing"
|
|
627
667
|
}
|
|
628
668
|
};
|
|
629
|
-
await ctx.
|
|
669
|
+
await revokeDirectFlowAccess(ctx.database, accessId);
|
|
630
670
|
return {
|
|
631
671
|
status: 204,
|
|
632
672
|
body: null
|
|
@@ -638,13 +678,6 @@ function rbacPlugin(options = {}) {
|
|
|
638
678
|
path: "/rbac/flows/accessible",
|
|
639
679
|
isPublic: false,
|
|
640
680
|
handler: async (ctx) => {
|
|
641
|
-
if (!ctx.core.isFlowAccessTableEnabled()) return {
|
|
642
|
-
status: 501,
|
|
643
|
-
body: {
|
|
644
|
-
error: "Not Implemented",
|
|
645
|
-
message: "Flow access table not enabled. Set auth.useFlowAccessTable: true in config."
|
|
646
|
-
}
|
|
647
|
-
};
|
|
648
681
|
const identity = ctx.identity;
|
|
649
682
|
if (!identity) return {
|
|
650
683
|
status: 401,
|
|
@@ -1323,7 +1356,6 @@ function rbacPlugin(options = {}) {
|
|
|
1323
1356
|
} catch {}
|
|
1324
1357
|
} : void 0,
|
|
1325
1358
|
onAuthorize: async (context) => {
|
|
1326
|
-
if (!useFlowAccessTable) return;
|
|
1327
1359
|
const { identity, resource, action } = context;
|
|
1328
1360
|
if (!identity || !resource?.id) return;
|
|
1329
1361
|
if (!FLOW_RESOURCE_TYPES.has(resource.type)) return;
|
|
@@ -1358,6 +1390,6 @@ function rbacPlugin(options = {}) {
|
|
|
1358
1390
|
};
|
|
1359
1391
|
}
|
|
1360
1392
|
//#endregion
|
|
1361
|
-
export {
|
|
1393
|
+
export { rbac, resolveTeamIds };
|
|
1362
1394
|
|
|
1363
1395
|
//# sourceMappingURL=index.mjs.map
|