@objectstack/platform-objects 0.1.0 → 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/dist/apps/index.d.mts +16 -48
- package/dist/apps/index.d.ts +16 -48
- package/dist/apps/index.js +139 -215
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/index.mjs +140 -210
- package/dist/apps/index.mjs.map +1 -1
- package/dist/audit/index.d.mts +40249 -150
- package/dist/audit/index.d.ts +40249 -150
- package/dist/audit/index.js +1428 -0
- package/dist/audit/index.js.map +1 -1
- package/dist/audit/index.mjs +1417 -1
- package/dist/audit/index.mjs.map +1 -1
- package/dist/identity/index.d.mts +18792 -2520
- package/dist/identity/index.d.ts +18792 -2520
- package/dist/identity/index.js +1107 -6
- package/dist/identity/index.js.map +1 -1
- package/dist/identity/index.mjs +1106 -7
- package/dist/identity/index.mjs.map +1 -1
- package/dist/index.d.mts +9 -7
- package/dist/index.d.ts +9 -7
- package/dist/index.js +3939 -1504
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3917 -1487
- package/dist/index.mjs.map +1 -1
- package/dist/integration/index.d.mts +2905 -0
- package/dist/integration/index.d.ts +2905 -0
- package/dist/integration/index.js +140 -0
- package/dist/integration/index.js.map +1 -0
- package/dist/integration/index.mjs +138 -0
- package/dist/integration/index.mjs.map +1 -0
- package/dist/metadata/index.d.mts +1426 -19092
- package/dist/metadata/index.d.ts +1426 -19092
- package/dist/metadata/index.js +29 -619
- package/dist/metadata/index.js.map +1 -1
- package/dist/metadata/index.mjs +30 -615
- package/dist/metadata/index.mjs.map +1 -1
- package/dist/security/index.d.mts +10759 -60
- package/dist/security/index.d.ts +10759 -60
- package/dist/security/index.js +786 -0
- package/dist/security/index.js.map +1 -1
- package/dist/security/index.mjs +782 -1
- package/dist/security/index.mjs.map +1 -1
- package/dist/system/index.d.mts +8409 -0
- package/dist/system/index.d.ts +8409 -0
- package/dist/system/index.js +395 -0
- package/dist/system/index.js.map +1 -0
- package/dist/system/index.mjs +391 -0
- package/dist/system/index.mjs.map +1 -0
- package/package.json +13 -8
- package/dist/tenant/index.d.mts +0 -16454
- package/dist/tenant/index.d.ts +0 -16454
- package/dist/tenant/index.js +0 -741
- package/dist/tenant/index.js.map +0 -1
- package/dist/tenant/index.mjs +0 -733
- package/dist/tenant/index.mjs.map +0 -1
- /package/dist/{state-machine.zod-BFg-VE0M.d-Ek3_yo9P.d.mts → state-machine.zod-BNanU03M.d-Ek3_yo9P.d.mts} +0 -0
- /package/dist/{state-machine.zod-BFg-VE0M.d-Ek3_yo9P.d.ts → state-machine.zod-BNanU03M.d-Ek3_yo9P.d.ts} +0 -0
package/dist/security/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var data = require('@objectstack/spec/data');
|
|
4
|
+
var security = require('@objectstack/spec/security');
|
|
4
5
|
|
|
5
6
|
// src/security/sys-role.object.ts
|
|
6
7
|
var SysRole = data.ObjectSchema.create({
|
|
@@ -9,10 +10,52 @@ var SysRole = data.ObjectSchema.create({
|
|
|
9
10
|
pluralLabel: "Roles",
|
|
10
11
|
icon: "shield",
|
|
11
12
|
isSystem: true,
|
|
13
|
+
managedBy: "config",
|
|
12
14
|
description: "Role definitions for RBAC access control",
|
|
13
15
|
displayNameField: "label",
|
|
14
16
|
titleFormat: "{label}",
|
|
15
17
|
compactLayout: ["label", "name", "active", "is_default"],
|
|
18
|
+
listViews: {
|
|
19
|
+
active: {
|
|
20
|
+
type: "grid",
|
|
21
|
+
name: "active",
|
|
22
|
+
label: "Active",
|
|
23
|
+
data: { provider: "object", object: "sys_role" },
|
|
24
|
+
columns: ["label", "name", "is_default", "updated_at"],
|
|
25
|
+
filter: [{ field: "active", operator: "equals", value: true }],
|
|
26
|
+
sort: [{ field: "label", order: "asc" }],
|
|
27
|
+
pagination: { pageSize: 50 }
|
|
28
|
+
},
|
|
29
|
+
default_roles: {
|
|
30
|
+
type: "grid",
|
|
31
|
+
name: "default_roles",
|
|
32
|
+
label: "Default",
|
|
33
|
+
data: { provider: "object", object: "sys_role" },
|
|
34
|
+
columns: ["label", "name", "description", "active"],
|
|
35
|
+
filter: [{ field: "is_default", operator: "equals", value: true }],
|
|
36
|
+
sort: [{ field: "label", order: "asc" }],
|
|
37
|
+
pagination: { pageSize: 50 }
|
|
38
|
+
},
|
|
39
|
+
custom: {
|
|
40
|
+
type: "grid",
|
|
41
|
+
name: "custom",
|
|
42
|
+
label: "Custom",
|
|
43
|
+
data: { provider: "object", object: "sys_role" },
|
|
44
|
+
columns: ["label", "name", "active", "updated_at"],
|
|
45
|
+
filter: [{ field: "is_default", operator: "equals", value: false }],
|
|
46
|
+
sort: [{ field: "label", order: "asc" }],
|
|
47
|
+
pagination: { pageSize: 50 }
|
|
48
|
+
},
|
|
49
|
+
all_roles: {
|
|
50
|
+
type: "grid",
|
|
51
|
+
name: "all_roles",
|
|
52
|
+
label: "All",
|
|
53
|
+
data: { provider: "object", object: "sys_role" },
|
|
54
|
+
columns: ["label", "name", "active", "is_default", "updated_at"],
|
|
55
|
+
sort: [{ field: "label", order: "asc" }],
|
|
56
|
+
pagination: { pageSize: 50 }
|
|
57
|
+
}
|
|
58
|
+
},
|
|
16
59
|
fields: {
|
|
17
60
|
// ── Identity ─────────────────────────────────────────────────
|
|
18
61
|
label: data.Field.text({
|
|
@@ -93,10 +136,42 @@ var SysPermissionSet = data.ObjectSchema.create({
|
|
|
93
136
|
pluralLabel: "Permission Sets",
|
|
94
137
|
icon: "lock",
|
|
95
138
|
isSystem: true,
|
|
139
|
+
managedBy: "config",
|
|
96
140
|
description: "Named permission groupings for fine-grained access control",
|
|
97
141
|
displayNameField: "label",
|
|
98
142
|
titleFormat: "{label}",
|
|
99
143
|
compactLayout: ["label", "name", "active"],
|
|
144
|
+
listViews: {
|
|
145
|
+
active: {
|
|
146
|
+
type: "grid",
|
|
147
|
+
name: "active",
|
|
148
|
+
label: "Active",
|
|
149
|
+
data: { provider: "object", object: "sys_permission_set" },
|
|
150
|
+
columns: ["label", "name", "description", "updated_at"],
|
|
151
|
+
filter: [{ field: "active", operator: "equals", value: true }],
|
|
152
|
+
sort: [{ field: "label", order: "asc" }],
|
|
153
|
+
pagination: { pageSize: 50 }
|
|
154
|
+
},
|
|
155
|
+
inactive: {
|
|
156
|
+
type: "grid",
|
|
157
|
+
name: "inactive",
|
|
158
|
+
label: "Inactive",
|
|
159
|
+
data: { provider: "object", object: "sys_permission_set" },
|
|
160
|
+
columns: ["label", "name", "updated_at"],
|
|
161
|
+
filter: [{ field: "active", operator: "equals", value: false }],
|
|
162
|
+
sort: [{ field: "label", order: "asc" }],
|
|
163
|
+
pagination: { pageSize: 50 }
|
|
164
|
+
},
|
|
165
|
+
all_permsets: {
|
|
166
|
+
type: "grid",
|
|
167
|
+
name: "all_permsets",
|
|
168
|
+
label: "All",
|
|
169
|
+
data: { provider: "object", object: "sys_permission_set" },
|
|
170
|
+
columns: ["label", "name", "active", "updated_at"],
|
|
171
|
+
sort: [{ field: "label", order: "asc" }],
|
|
172
|
+
pagination: { pageSize: 50 }
|
|
173
|
+
}
|
|
174
|
+
},
|
|
100
175
|
fields: {
|
|
101
176
|
// ── Identity ─────────────────────────────────────────────────
|
|
102
177
|
label: data.Field.text({
|
|
@@ -171,8 +246,719 @@ var SysPermissionSet = data.ObjectSchema.create({
|
|
|
171
246
|
mru: true
|
|
172
247
|
}
|
|
173
248
|
});
|
|
249
|
+
var SysUserPermissionSet = data.ObjectSchema.create({
|
|
250
|
+
name: "sys_user_permission_set",
|
|
251
|
+
label: "User Permission Set",
|
|
252
|
+
pluralLabel: "User Permission Sets",
|
|
253
|
+
icon: "user-check",
|
|
254
|
+
isSystem: true,
|
|
255
|
+
managedBy: "system",
|
|
256
|
+
description: "Direct assignment of a permission set to a user (optionally scoped to an organization).",
|
|
257
|
+
titleFormat: "{user_id} \u2192 {permission_set_id}",
|
|
258
|
+
compactLayout: ["user_id", "permission_set_id", "organization_id"],
|
|
259
|
+
fields: {
|
|
260
|
+
id: data.Field.text({
|
|
261
|
+
label: "Assignment ID",
|
|
262
|
+
required: true,
|
|
263
|
+
readonly: true,
|
|
264
|
+
description: "UUID of the assignment."
|
|
265
|
+
}),
|
|
266
|
+
user_id: data.Field.lookup("sys_user", {
|
|
267
|
+
label: "User",
|
|
268
|
+
required: true,
|
|
269
|
+
description: "Foreign key to sys_user."
|
|
270
|
+
}),
|
|
271
|
+
permission_set_id: data.Field.lookup("sys_permission_set", {
|
|
272
|
+
label: "Permission Set",
|
|
273
|
+
required: true,
|
|
274
|
+
description: "Foreign key to sys_permission_set."
|
|
275
|
+
}),
|
|
276
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
277
|
+
label: "Organization",
|
|
278
|
+
required: false,
|
|
279
|
+
description: "Optional organization scope. NULL = applies in every org context."
|
|
280
|
+
}),
|
|
281
|
+
granted_by: data.Field.lookup("sys_user", {
|
|
282
|
+
label: "Granted By",
|
|
283
|
+
required: false,
|
|
284
|
+
description: "User who granted this permission set."
|
|
285
|
+
}),
|
|
286
|
+
created_at: data.Field.datetime({
|
|
287
|
+
label: "Created At",
|
|
288
|
+
defaultValue: "NOW()",
|
|
289
|
+
readonly: true
|
|
290
|
+
}),
|
|
291
|
+
updated_at: data.Field.datetime({
|
|
292
|
+
label: "Updated At",
|
|
293
|
+
defaultValue: "NOW()",
|
|
294
|
+
readonly: true
|
|
295
|
+
})
|
|
296
|
+
},
|
|
297
|
+
indexes: [
|
|
298
|
+
{ fields: ["user_id", "permission_set_id", "organization_id"], unique: true },
|
|
299
|
+
{ fields: ["user_id"] },
|
|
300
|
+
{ fields: ["organization_id"] },
|
|
301
|
+
{ fields: ["permission_set_id"] }
|
|
302
|
+
],
|
|
303
|
+
enable: {
|
|
304
|
+
trackHistory: true,
|
|
305
|
+
searchable: true,
|
|
306
|
+
apiEnabled: true,
|
|
307
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
308
|
+
trash: true,
|
|
309
|
+
mru: false
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
var SysRolePermissionSet = data.ObjectSchema.create({
|
|
313
|
+
name: "sys_role_permission_set",
|
|
314
|
+
label: "Role Permission Set",
|
|
315
|
+
pluralLabel: "Role Permission Sets",
|
|
316
|
+
icon: "shield-plus",
|
|
317
|
+
isSystem: true,
|
|
318
|
+
managedBy: "system",
|
|
319
|
+
description: "Binds a permission set to a role.",
|
|
320
|
+
titleFormat: "{role_id} \u2192 {permission_set_id}",
|
|
321
|
+
compactLayout: ["role_id", "permission_set_id"],
|
|
322
|
+
fields: {
|
|
323
|
+
id: data.Field.text({
|
|
324
|
+
label: "Binding ID",
|
|
325
|
+
required: true,
|
|
326
|
+
readonly: true,
|
|
327
|
+
description: "UUID of the role-permission-set binding."
|
|
328
|
+
}),
|
|
329
|
+
role_id: data.Field.lookup("sys_role", {
|
|
330
|
+
label: "Role",
|
|
331
|
+
required: true,
|
|
332
|
+
description: "Foreign key to sys_role."
|
|
333
|
+
}),
|
|
334
|
+
permission_set_id: data.Field.lookup("sys_permission_set", {
|
|
335
|
+
label: "Permission Set",
|
|
336
|
+
required: true,
|
|
337
|
+
description: "Foreign key to sys_permission_set."
|
|
338
|
+
}),
|
|
339
|
+
created_at: data.Field.datetime({
|
|
340
|
+
label: "Created At",
|
|
341
|
+
defaultValue: "NOW()",
|
|
342
|
+
readonly: true
|
|
343
|
+
}),
|
|
344
|
+
updated_at: data.Field.datetime({
|
|
345
|
+
label: "Updated At",
|
|
346
|
+
defaultValue: "NOW()",
|
|
347
|
+
readonly: true
|
|
348
|
+
})
|
|
349
|
+
},
|
|
350
|
+
indexes: [
|
|
351
|
+
{ fields: ["role_id", "permission_set_id"], unique: true },
|
|
352
|
+
{ fields: ["role_id"] },
|
|
353
|
+
{ fields: ["permission_set_id"] }
|
|
354
|
+
],
|
|
355
|
+
enable: {
|
|
356
|
+
trackHistory: true,
|
|
357
|
+
searchable: true,
|
|
358
|
+
apiEnabled: true,
|
|
359
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
360
|
+
trash: true,
|
|
361
|
+
mru: false
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
var SysRecordShare = data.ObjectSchema.create({
|
|
365
|
+
name: "sys_record_share",
|
|
366
|
+
label: "Record Share",
|
|
367
|
+
pluralLabel: "Record Shares",
|
|
368
|
+
icon: "share",
|
|
369
|
+
isSystem: true,
|
|
370
|
+
managedBy: "system",
|
|
371
|
+
description: "Per-record sharing grant \u2014 extends OWD with explicit access",
|
|
372
|
+
titleFormat: "{object_name}/{record_id} \u2192 {recipient_id} ({access_level})",
|
|
373
|
+
compactLayout: ["object_name", "record_id", "recipient_id", "access_level", "source"],
|
|
374
|
+
listViews: {
|
|
375
|
+
granted_to_me: {
|
|
376
|
+
type: "grid",
|
|
377
|
+
name: "granted_to_me",
|
|
378
|
+
label: "Granted to Me",
|
|
379
|
+
data: { provider: "object", object: "sys_record_share" },
|
|
380
|
+
columns: ["object_name", "record_id", "access_level", "source", "granted_by", "created_at"],
|
|
381
|
+
filter: [
|
|
382
|
+
{ field: "recipient_type", operator: "equals", value: "user" },
|
|
383
|
+
{ field: "recipient_id", operator: "equals", value: "{current_user_id}" }
|
|
384
|
+
],
|
|
385
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
386
|
+
pagination: { pageSize: 50 }
|
|
387
|
+
},
|
|
388
|
+
granted_by_me: {
|
|
389
|
+
type: "grid",
|
|
390
|
+
name: "granted_by_me",
|
|
391
|
+
label: "Granted by Me",
|
|
392
|
+
data: { provider: "object", object: "sys_record_share" },
|
|
393
|
+
columns: ["object_name", "record_id", "recipient_id", "access_level", "source", "created_at"],
|
|
394
|
+
filter: [
|
|
395
|
+
{ field: "granted_by", operator: "equals", value: "{current_user_id}" }
|
|
396
|
+
],
|
|
397
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
398
|
+
pagination: { pageSize: 50 }
|
|
399
|
+
},
|
|
400
|
+
by_object: {
|
|
401
|
+
type: "grid",
|
|
402
|
+
name: "by_object",
|
|
403
|
+
label: "By Object",
|
|
404
|
+
data: { provider: "object", object: "sys_record_share" },
|
|
405
|
+
columns: ["object_name", "record_id", "recipient_id", "access_level", "source", "created_at"],
|
|
406
|
+
sort: [{ field: "object_name", order: "asc" }, { field: "created_at", order: "desc" }],
|
|
407
|
+
grouping: { fields: [{ field: "object_name", order: "asc", collapsed: false }] },
|
|
408
|
+
pagination: { pageSize: 100 }
|
|
409
|
+
},
|
|
410
|
+
manual_grants: {
|
|
411
|
+
type: "grid",
|
|
412
|
+
name: "manual_grants",
|
|
413
|
+
label: "Manual Grants",
|
|
414
|
+
data: { provider: "object", object: "sys_record_share" },
|
|
415
|
+
columns: ["object_name", "record_id", "recipient_id", "access_level", "granted_by", "reason", "created_at"],
|
|
416
|
+
filter: [{ field: "source", operator: "equals", value: "manual" }],
|
|
417
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
418
|
+
pagination: { pageSize: 50 }
|
|
419
|
+
},
|
|
420
|
+
rule_grants: {
|
|
421
|
+
type: "grid",
|
|
422
|
+
name: "rule_grants",
|
|
423
|
+
label: "Rule Grants",
|
|
424
|
+
data: { provider: "object", object: "sys_record_share" },
|
|
425
|
+
columns: ["object_name", "record_id", "recipient_id", "access_level", "source_id", "created_at"],
|
|
426
|
+
filter: [{ field: "source", operator: "in", value: ["rule", "team", "inherited"] }],
|
|
427
|
+
sort: [{ field: "source_id", order: "asc" }, { field: "created_at", order: "desc" }],
|
|
428
|
+
pagination: { pageSize: 50 }
|
|
429
|
+
},
|
|
430
|
+
all_shares: {
|
|
431
|
+
type: "grid",
|
|
432
|
+
name: "all_shares",
|
|
433
|
+
label: "All",
|
|
434
|
+
data: { provider: "object", object: "sys_record_share" },
|
|
435
|
+
columns: ["object_name", "record_id", "recipient_type", "recipient_id", "access_level", "source", "created_at"],
|
|
436
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
437
|
+
pagination: { pageSize: 100 }
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
fields: {
|
|
441
|
+
id: data.Field.text({
|
|
442
|
+
label: "Share ID",
|
|
443
|
+
required: true,
|
|
444
|
+
readonly: true,
|
|
445
|
+
group: "System"
|
|
446
|
+
}),
|
|
447
|
+
// ── Target (which record is being shared) ────────────────────
|
|
448
|
+
object_name: data.Field.text({
|
|
449
|
+
label: "Object",
|
|
450
|
+
required: true,
|
|
451
|
+
maxLength: 100,
|
|
452
|
+
description: "Short object name of the shared record",
|
|
453
|
+
group: "Target"
|
|
454
|
+
}),
|
|
455
|
+
record_id: data.Field.text({
|
|
456
|
+
label: "Record",
|
|
457
|
+
required: true,
|
|
458
|
+
maxLength: 100,
|
|
459
|
+
description: "Primary key of the shared record within object_name",
|
|
460
|
+
group: "Target"
|
|
461
|
+
}),
|
|
462
|
+
// ── Recipient (who receives access) ──────────────────────────
|
|
463
|
+
recipient_type: data.Field.select(
|
|
464
|
+
["user", "group", "role", "role_and_subordinates", "guest"],
|
|
465
|
+
{
|
|
466
|
+
label: "Recipient Type",
|
|
467
|
+
required: true,
|
|
468
|
+
defaultValue: "user",
|
|
469
|
+
description: "Kind of principal that holds the grant",
|
|
470
|
+
group: "Recipient"
|
|
471
|
+
}
|
|
472
|
+
),
|
|
473
|
+
recipient_id: data.Field.text({
|
|
474
|
+
label: "Recipient",
|
|
475
|
+
required: true,
|
|
476
|
+
maxLength: 100,
|
|
477
|
+
description: "ID of the user/group/role that receives access",
|
|
478
|
+
group: "Recipient"
|
|
479
|
+
}),
|
|
480
|
+
access_level: data.Field.select(
|
|
481
|
+
["read", "edit", "full"],
|
|
482
|
+
{
|
|
483
|
+
label: "Access Level",
|
|
484
|
+
required: true,
|
|
485
|
+
defaultValue: "read",
|
|
486
|
+
description: "What the recipient can do \u2014 read | edit | full (transfer/share/delete)",
|
|
487
|
+
group: "Recipient"
|
|
488
|
+
}
|
|
489
|
+
),
|
|
490
|
+
// ── Provenance ───────────────────────────────────────────────
|
|
491
|
+
source: data.Field.select(
|
|
492
|
+
["manual", "rule", "team", "inherited"],
|
|
493
|
+
{
|
|
494
|
+
label: "Source",
|
|
495
|
+
required: true,
|
|
496
|
+
defaultValue: "manual",
|
|
497
|
+
description: "Why this grant exists \u2014 used by the rule evaluator to reconcile",
|
|
498
|
+
group: "Provenance"
|
|
499
|
+
}
|
|
500
|
+
),
|
|
501
|
+
source_id: data.Field.text({
|
|
502
|
+
label: "Source ID",
|
|
503
|
+
required: false,
|
|
504
|
+
maxLength: 200,
|
|
505
|
+
description: "Rule name / team id when source != manual",
|
|
506
|
+
group: "Provenance"
|
|
507
|
+
}),
|
|
508
|
+
granted_by: data.Field.lookup("sys_user", {
|
|
509
|
+
label: "Granted By",
|
|
510
|
+
required: false,
|
|
511
|
+
description: "User that created the grant (manual only)",
|
|
512
|
+
group: "Provenance"
|
|
513
|
+
}),
|
|
514
|
+
reason: data.Field.text({
|
|
515
|
+
label: "Reason",
|
|
516
|
+
required: false,
|
|
517
|
+
maxLength: 500,
|
|
518
|
+
description: "Optional free-text explanation surfaced to the recipient",
|
|
519
|
+
group: "Provenance"
|
|
520
|
+
}),
|
|
521
|
+
// ── Lifecycle ────────────────────────────────────────────────
|
|
522
|
+
created_at: data.Field.datetime({
|
|
523
|
+
label: "Created At",
|
|
524
|
+
required: true,
|
|
525
|
+
defaultValue: "NOW()",
|
|
526
|
+
readonly: true,
|
|
527
|
+
group: "System"
|
|
528
|
+
}),
|
|
529
|
+
updated_at: data.Field.datetime({
|
|
530
|
+
label: "Updated At",
|
|
531
|
+
required: false,
|
|
532
|
+
group: "System"
|
|
533
|
+
})
|
|
534
|
+
},
|
|
535
|
+
indexes: [
|
|
536
|
+
// Hot path: "all records visible to user U on object O" — the
|
|
537
|
+
// middleware reads (object_name, recipient_type, recipient_id) to
|
|
538
|
+
// build the `id IN (...)` predicate on every find.
|
|
539
|
+
{ fields: ["object_name", "recipient_type", "recipient_id"] },
|
|
540
|
+
// "all grants on this record" — used by the share-management UI
|
|
541
|
+
// and by canEdit() to look up explicit grants.
|
|
542
|
+
{ fields: ["object_name", "record_id"] },
|
|
543
|
+
// Reconciliation key for rule-driven shares.
|
|
544
|
+
{ fields: ["source", "source_id"] }
|
|
545
|
+
]
|
|
546
|
+
});
|
|
547
|
+
var SysSharingRule = data.ObjectSchema.create({
|
|
548
|
+
name: "sys_sharing_rule",
|
|
549
|
+
label: "Sharing Rule",
|
|
550
|
+
pluralLabel: "Sharing Rules",
|
|
551
|
+
icon: "shield-check",
|
|
552
|
+
isSystem: true,
|
|
553
|
+
managedBy: "config",
|
|
554
|
+
// Sharing rules can now be authored visually via the Studio criteria
|
|
555
|
+
// builder (apps/studio/src/components/SharingCriteriaBuilder.tsx).
|
|
556
|
+
// We still recommend `defineSharingRule({...})` for repo-controlled
|
|
557
|
+
// baselines, but admins can safely create/edit/delete from the UI.
|
|
558
|
+
userActions: { create: true, edit: true, delete: true, import: false },
|
|
559
|
+
description: "Declarative sharing rule that auto-materialises sys_record_share grants. Authored via defineSharingRule() in code or the Studio criteria builder.",
|
|
560
|
+
displayNameField: "name",
|
|
561
|
+
titleFormat: "{label}",
|
|
562
|
+
compactLayout: ["name", "object_name", "recipient_type", "recipient_id", "access_level", "active"],
|
|
563
|
+
listViews: {
|
|
564
|
+
active: {
|
|
565
|
+
type: "grid",
|
|
566
|
+
name: "active",
|
|
567
|
+
label: "Active",
|
|
568
|
+
data: { provider: "object", object: "sys_sharing_rule" },
|
|
569
|
+
columns: ["label", "object_name", "recipient_type", "recipient_id", "access_level", "updated_at"],
|
|
570
|
+
filter: [{ field: "active", operator: "equals", value: true }],
|
|
571
|
+
sort: [{ field: "object_name", order: "asc" }, { field: "label", order: "asc" }],
|
|
572
|
+
pagination: { pageSize: 50 }
|
|
573
|
+
},
|
|
574
|
+
inactive: {
|
|
575
|
+
type: "grid",
|
|
576
|
+
name: "inactive",
|
|
577
|
+
label: "Inactive",
|
|
578
|
+
data: { provider: "object", object: "sys_sharing_rule" },
|
|
579
|
+
columns: ["label", "object_name", "recipient_type", "recipient_id", "updated_at"],
|
|
580
|
+
filter: [{ field: "active", operator: "equals", value: false }],
|
|
581
|
+
sort: [{ field: "label", order: "asc" }],
|
|
582
|
+
pagination: { pageSize: 50 }
|
|
583
|
+
},
|
|
584
|
+
by_object: {
|
|
585
|
+
type: "grid",
|
|
586
|
+
name: "by_object",
|
|
587
|
+
label: "By Object",
|
|
588
|
+
data: { provider: "object", object: "sys_sharing_rule" },
|
|
589
|
+
columns: ["object_name", "label", "recipient_type", "access_level", "active"],
|
|
590
|
+
sort: [{ field: "object_name", order: "asc" }, { field: "label", order: "asc" }],
|
|
591
|
+
grouping: { fields: [{ field: "object_name", order: "asc", collapsed: false }] },
|
|
592
|
+
pagination: { pageSize: 100 }
|
|
593
|
+
},
|
|
594
|
+
all_rules: {
|
|
595
|
+
type: "grid",
|
|
596
|
+
name: "all_rules",
|
|
597
|
+
label: "All",
|
|
598
|
+
data: { provider: "object", object: "sys_sharing_rule" },
|
|
599
|
+
columns: ["label", "object_name", "recipient_type", "recipient_id", "access_level", "active", "updated_at"],
|
|
600
|
+
sort: [{ field: "label", order: "asc" }],
|
|
601
|
+
pagination: { pageSize: 50 }
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
fields: {
|
|
605
|
+
id: data.Field.text({ label: "Rule ID", required: true, readonly: true, group: "System" }),
|
|
606
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
607
|
+
label: "Organization",
|
|
608
|
+
required: false,
|
|
609
|
+
group: "System",
|
|
610
|
+
description: "Tenant that owns this rule; null = global"
|
|
611
|
+
}),
|
|
612
|
+
name: data.Field.text({
|
|
613
|
+
label: "Name",
|
|
614
|
+
required: true,
|
|
615
|
+
maxLength: 100,
|
|
616
|
+
description: "Unique snake_case rule name",
|
|
617
|
+
group: "Identity"
|
|
618
|
+
}),
|
|
619
|
+
label: data.Field.text({
|
|
620
|
+
label: "Display Label",
|
|
621
|
+
required: true,
|
|
622
|
+
maxLength: 200,
|
|
623
|
+
group: "Identity"
|
|
624
|
+
}),
|
|
625
|
+
description: data.Field.textarea({
|
|
626
|
+
label: "Description",
|
|
627
|
+
required: false,
|
|
628
|
+
group: "Identity"
|
|
629
|
+
}),
|
|
630
|
+
object_name: data.Field.text({
|
|
631
|
+
label: "Object",
|
|
632
|
+
required: true,
|
|
633
|
+
maxLength: 100,
|
|
634
|
+
description: "Short object name (e.g. opportunity, account)",
|
|
635
|
+
group: "Target"
|
|
636
|
+
}),
|
|
637
|
+
criteria_json: data.Field.textarea({
|
|
638
|
+
label: "Criteria (FilterCondition JSON)",
|
|
639
|
+
required: false,
|
|
640
|
+
description: "JSON FilterCondition matched against records of object_name. Empty = match all.",
|
|
641
|
+
group: "Target"
|
|
642
|
+
}),
|
|
643
|
+
recipient_type: data.Field.select(
|
|
644
|
+
["user", "team", "department", "role", "queue"],
|
|
645
|
+
{
|
|
646
|
+
label: "Recipient Type",
|
|
647
|
+
required: true,
|
|
648
|
+
defaultValue: "department",
|
|
649
|
+
description: "Kind of principal that receives access \u2014 expanded to user grants at evaluation time. `department` walks the parent_department_id tree; `team` is flat (better-auth).",
|
|
650
|
+
group: "Recipient"
|
|
651
|
+
}
|
|
652
|
+
),
|
|
653
|
+
recipient_id: data.Field.text({
|
|
654
|
+
label: "Recipient",
|
|
655
|
+
required: true,
|
|
656
|
+
maxLength: 200,
|
|
657
|
+
description: "department id / team id / role name / queue name / user id depending on recipient_type",
|
|
658
|
+
group: "Recipient"
|
|
659
|
+
}),
|
|
660
|
+
access_level: data.Field.select(
|
|
661
|
+
["read", "edit", "full"],
|
|
662
|
+
{
|
|
663
|
+
label: "Access Level",
|
|
664
|
+
required: true,
|
|
665
|
+
defaultValue: "read",
|
|
666
|
+
group: "Recipient"
|
|
667
|
+
}
|
|
668
|
+
),
|
|
669
|
+
active: data.Field.boolean({
|
|
670
|
+
label: "Active",
|
|
671
|
+
required: false,
|
|
672
|
+
defaultValue: true,
|
|
673
|
+
description: "Only active rules participate in lifecycle evaluation",
|
|
674
|
+
group: "Lifecycle"
|
|
675
|
+
}),
|
|
676
|
+
created_at: data.Field.datetime({
|
|
677
|
+
label: "Created At",
|
|
678
|
+
required: true,
|
|
679
|
+
defaultValue: "NOW()",
|
|
680
|
+
readonly: true,
|
|
681
|
+
group: "System"
|
|
682
|
+
}),
|
|
683
|
+
updated_at: data.Field.datetime({
|
|
684
|
+
label: "Updated At",
|
|
685
|
+
required: false,
|
|
686
|
+
group: "System"
|
|
687
|
+
})
|
|
688
|
+
},
|
|
689
|
+
indexes: [
|
|
690
|
+
{ fields: ["object_name", "active"] },
|
|
691
|
+
{ fields: ["name"], unique: true },
|
|
692
|
+
{ fields: ["organization_id"] }
|
|
693
|
+
]
|
|
694
|
+
});
|
|
695
|
+
var BETTER_AUTH_MANAGED_OBJECTS = [
|
|
696
|
+
"sys_user",
|
|
697
|
+
"sys_account",
|
|
698
|
+
"sys_session",
|
|
699
|
+
"sys_organization",
|
|
700
|
+
"sys_member",
|
|
701
|
+
"sys_invitation",
|
|
702
|
+
"sys_team",
|
|
703
|
+
"sys_team_member",
|
|
704
|
+
"sys_api_key",
|
|
705
|
+
"sys_two_factor",
|
|
706
|
+
"sys_verification",
|
|
707
|
+
"sys_jwks",
|
|
708
|
+
"sys_device_code",
|
|
709
|
+
"sys_oauth_application",
|
|
710
|
+
"sys_oauth_access_token",
|
|
711
|
+
"sys_oauth_refresh_token",
|
|
712
|
+
"sys_oauth_consent"
|
|
713
|
+
];
|
|
714
|
+
var denyWritesOnManagedObjects = () => Object.fromEntries(
|
|
715
|
+
BETTER_AUTH_MANAGED_OBJECTS.map((name) => [
|
|
716
|
+
name,
|
|
717
|
+
{ allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false }
|
|
718
|
+
])
|
|
719
|
+
);
|
|
720
|
+
var defaultPermissionSets = [
|
|
721
|
+
security.PermissionSetSchema.parse({
|
|
722
|
+
name: "admin_full_access",
|
|
723
|
+
label: "Administrator \u2014 Full Access",
|
|
724
|
+
isProfile: true,
|
|
725
|
+
objects: {
|
|
726
|
+
"*": {
|
|
727
|
+
allowRead: true,
|
|
728
|
+
allowCreate: true,
|
|
729
|
+
allowEdit: true,
|
|
730
|
+
allowDelete: true,
|
|
731
|
+
viewAllRecords: true,
|
|
732
|
+
modifyAllRecords: true
|
|
733
|
+
}
|
|
734
|
+
},
|
|
735
|
+
systemPermissions: ["manage_users", "manage_metadata", "setup.access"]
|
|
736
|
+
}),
|
|
737
|
+
security.PermissionSetSchema.parse({
|
|
738
|
+
name: "member_default",
|
|
739
|
+
label: "Member \u2014 Standard Access",
|
|
740
|
+
isProfile: true,
|
|
741
|
+
objects: {
|
|
742
|
+
"*": {
|
|
743
|
+
allowRead: true,
|
|
744
|
+
allowCreate: true,
|
|
745
|
+
allowEdit: true,
|
|
746
|
+
allowDelete: true
|
|
747
|
+
},
|
|
748
|
+
// Identity tables are managed by better-auth — no direct writes.
|
|
749
|
+
...denyWritesOnManagedObjects()
|
|
750
|
+
},
|
|
751
|
+
rowLevelSecurity: [
|
|
752
|
+
{
|
|
753
|
+
name: "tenant_isolation",
|
|
754
|
+
object: "*",
|
|
755
|
+
operation: "all",
|
|
756
|
+
using: "organization_id = current_user.organization_id"
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
name: "owner_only_writes",
|
|
760
|
+
object: "*",
|
|
761
|
+
operation: "update",
|
|
762
|
+
using: "owner_id = current_user.id"
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
name: "owner_only_deletes",
|
|
766
|
+
object: "*",
|
|
767
|
+
operation: "delete",
|
|
768
|
+
using: "owner_id = current_user.id"
|
|
769
|
+
},
|
|
770
|
+
// ── better-auth system tables that lack `organization_id` and would
|
|
771
|
+
// otherwise be left unprotected by the wildcard rule above. ────
|
|
772
|
+
//
|
|
773
|
+
// The security plugin's RLS injector treats wildcard policies that
|
|
774
|
+
// target a missing field as `RLS_DENY_FILTER` (zero rows) unless a
|
|
775
|
+
// per-object policy contributes an alternate match. Each `*_self`
|
|
776
|
+
// policy below restores per-user visibility on a better-auth table
|
|
777
|
+
// that has `user_id` but no `organization_id`. Tables without
|
|
778
|
+
// `user_id` (`sys_verification`, `sys_jwks`, empty `sys_passkey`)
|
|
779
|
+
// stay DENY for non-admins by design — only platform admins (via
|
|
780
|
+
// `admin_full_access`, which has no RLS) should inspect them.
|
|
781
|
+
{
|
|
782
|
+
name: "sys_organization_self",
|
|
783
|
+
object: "sys_organization",
|
|
784
|
+
operation: "all",
|
|
785
|
+
using: "id = current_user.organization_id"
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
name: "sys_user_self",
|
|
789
|
+
object: "sys_user",
|
|
790
|
+
operation: "select",
|
|
791
|
+
using: "id = current_user.id"
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
name: "sys_session_self",
|
|
795
|
+
object: "sys_session",
|
|
796
|
+
operation: "all",
|
|
797
|
+
using: "user_id = current_user.id"
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: "sys_account_self",
|
|
801
|
+
object: "sys_account",
|
|
802
|
+
operation: "select",
|
|
803
|
+
using: "user_id = current_user.id"
|
|
804
|
+
},
|
|
805
|
+
{
|
|
806
|
+
name: "sys_team_member_self",
|
|
807
|
+
object: "sys_team_member",
|
|
808
|
+
operation: "select",
|
|
809
|
+
using: "user_id = current_user.id"
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
name: "sys_two_factor_self",
|
|
813
|
+
object: "sys_two_factor",
|
|
814
|
+
operation: "all",
|
|
815
|
+
using: "user_id = current_user.id"
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
name: "sys_user_preference_self",
|
|
819
|
+
object: "sys_user_preference",
|
|
820
|
+
operation: "all",
|
|
821
|
+
using: "user_id = current_user.id"
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
name: "sys_api_key_self",
|
|
825
|
+
object: "sys_api_key",
|
|
826
|
+
operation: "all",
|
|
827
|
+
using: "user_id = current_user.id"
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
name: "sys_device_code_self",
|
|
831
|
+
object: "sys_device_code",
|
|
832
|
+
operation: "all",
|
|
833
|
+
using: "user_id = current_user.id"
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
name: "sys_oauth_access_token_self",
|
|
837
|
+
object: "sys_oauth_access_token",
|
|
838
|
+
operation: "select",
|
|
839
|
+
using: "user_id = current_user.id"
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
name: "sys_oauth_refresh_token_self",
|
|
843
|
+
object: "sys_oauth_refresh_token",
|
|
844
|
+
operation: "select",
|
|
845
|
+
using: "user_id = current_user.id"
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
name: "sys_oauth_consent_self",
|
|
849
|
+
object: "sys_oauth_consent",
|
|
850
|
+
operation: "all",
|
|
851
|
+
using: "user_id = current_user.id"
|
|
852
|
+
}
|
|
853
|
+
]
|
|
854
|
+
}),
|
|
855
|
+
security.PermissionSetSchema.parse({
|
|
856
|
+
name: "viewer_readonly",
|
|
857
|
+
label: "Viewer \u2014 Read-Only",
|
|
858
|
+
isProfile: true,
|
|
859
|
+
objects: {
|
|
860
|
+
"*": {
|
|
861
|
+
allowRead: true,
|
|
862
|
+
allowCreate: false,
|
|
863
|
+
allowEdit: false,
|
|
864
|
+
allowDelete: false
|
|
865
|
+
},
|
|
866
|
+
// Belt-and-suspenders: explicit deny on managed objects even though
|
|
867
|
+
// the wildcard already denies — keeps the policy readable when
|
|
868
|
+
// future relaxations might widen the wildcard.
|
|
869
|
+
...denyWritesOnManagedObjects()
|
|
870
|
+
},
|
|
871
|
+
rowLevelSecurity: [
|
|
872
|
+
{
|
|
873
|
+
name: "tenant_isolation",
|
|
874
|
+
object: "*",
|
|
875
|
+
operation: "select",
|
|
876
|
+
using: "organization_id = current_user.organization_id"
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
name: "sys_organization_self",
|
|
880
|
+
object: "sys_organization",
|
|
881
|
+
operation: "select",
|
|
882
|
+
using: "id = current_user.organization_id"
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
name: "sys_user_self",
|
|
886
|
+
object: "sys_user",
|
|
887
|
+
operation: "select",
|
|
888
|
+
using: "id = current_user.id"
|
|
889
|
+
},
|
|
890
|
+
// ── Per-user visibility on better-auth tables that lack
|
|
891
|
+
// `organization_id` (matches the `member_default` carve-outs).
|
|
892
|
+
{
|
|
893
|
+
name: "sys_session_self",
|
|
894
|
+
object: "sys_session",
|
|
895
|
+
operation: "select",
|
|
896
|
+
using: "user_id = current_user.id"
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
name: "sys_account_self",
|
|
900
|
+
object: "sys_account",
|
|
901
|
+
operation: "select",
|
|
902
|
+
using: "user_id = current_user.id"
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
name: "sys_team_member_self",
|
|
906
|
+
object: "sys_team_member",
|
|
907
|
+
operation: "select",
|
|
908
|
+
using: "user_id = current_user.id"
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
name: "sys_two_factor_self",
|
|
912
|
+
object: "sys_two_factor",
|
|
913
|
+
operation: "select",
|
|
914
|
+
using: "user_id = current_user.id"
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
name: "sys_user_preference_self",
|
|
918
|
+
object: "sys_user_preference",
|
|
919
|
+
operation: "select",
|
|
920
|
+
using: "user_id = current_user.id"
|
|
921
|
+
},
|
|
922
|
+
{
|
|
923
|
+
name: "sys_api_key_self",
|
|
924
|
+
object: "sys_api_key",
|
|
925
|
+
operation: "select",
|
|
926
|
+
using: "user_id = current_user.id"
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
name: "sys_device_code_self",
|
|
930
|
+
object: "sys_device_code",
|
|
931
|
+
operation: "select",
|
|
932
|
+
using: "user_id = current_user.id"
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
name: "sys_oauth_access_token_self",
|
|
936
|
+
object: "sys_oauth_access_token",
|
|
937
|
+
operation: "select",
|
|
938
|
+
using: "user_id = current_user.id"
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
name: "sys_oauth_refresh_token_self",
|
|
942
|
+
object: "sys_oauth_refresh_token",
|
|
943
|
+
operation: "select",
|
|
944
|
+
using: "user_id = current_user.id"
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
name: "sys_oauth_consent_self",
|
|
948
|
+
object: "sys_oauth_consent",
|
|
949
|
+
operation: "select",
|
|
950
|
+
using: "user_id = current_user.id"
|
|
951
|
+
}
|
|
952
|
+
]
|
|
953
|
+
})
|
|
954
|
+
];
|
|
174
955
|
|
|
175
956
|
exports.SysPermissionSet = SysPermissionSet;
|
|
957
|
+
exports.SysRecordShare = SysRecordShare;
|
|
176
958
|
exports.SysRole = SysRole;
|
|
959
|
+
exports.SysRolePermissionSet = SysRolePermissionSet;
|
|
960
|
+
exports.SysSharingRule = SysSharingRule;
|
|
961
|
+
exports.SysUserPermissionSet = SysUserPermissionSet;
|
|
962
|
+
exports.defaultPermissionSets = defaultPermissionSets;
|
|
177
963
|
//# sourceMappingURL=index.js.map
|
|
178
964
|
//# sourceMappingURL=index.js.map
|