@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/identity/index.js
CHANGED
|
@@ -9,10 +9,154 @@ var SysUser = data.ObjectSchema.create({
|
|
|
9
9
|
pluralLabel: "Users",
|
|
10
10
|
icon: "user",
|
|
11
11
|
isSystem: true,
|
|
12
|
+
managedBy: "better-auth",
|
|
12
13
|
description: "User accounts for authentication",
|
|
13
14
|
displayNameField: "name",
|
|
14
15
|
titleFormat: "{name}",
|
|
15
16
|
compactLayout: ["name", "email", "email_verified"],
|
|
17
|
+
// Custom actions — generic CRUD is suppressed because user accounts are
|
|
18
|
+
// managed by better-auth, but we still need first-class affordances for
|
|
19
|
+
// common operations. Each action delegates to a Console-side named script
|
|
20
|
+
// registered on the ActionRunner (see objectui `AppContent.tsx`). Adding
|
|
21
|
+
// new affordances (reset password, revoke session, …) is now a pure
|
|
22
|
+
// schema + script-registration change — no per-view code.
|
|
23
|
+
actions: [
|
|
24
|
+
{
|
|
25
|
+
name: "invite_user",
|
|
26
|
+
label: "Invite User",
|
|
27
|
+
icon: "user-plus",
|
|
28
|
+
variant: "primary",
|
|
29
|
+
locations: ["list_toolbar"],
|
|
30
|
+
type: "api",
|
|
31
|
+
target: "/api/v1/auth/organization/invite-member",
|
|
32
|
+
successMessage: "Invitation sent",
|
|
33
|
+
refreshAfter: true,
|
|
34
|
+
params: [
|
|
35
|
+
{ field: "email", required: true },
|
|
36
|
+
{ field: "role", objectOverride: "sys_member", required: true }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
// ── Platform admin operations (require better-auth `admin` plugin) ─
|
|
40
|
+
//
|
|
41
|
+
// These actions hit /api/v1/auth/admin/* endpoints that are only
|
|
42
|
+
// wired when `auth.plugins.admin` is enabled. When the plugin is
|
|
43
|
+
// disabled the actions still render (schema is static) but server
|
|
44
|
+
// returns 404. UI surfaces them under the row menu so platform
|
|
45
|
+
// admins can manage accounts without dropping to SQL or
|
|
46
|
+
// a custom Setup wizard.
|
|
47
|
+
{
|
|
48
|
+
name: "ban_user",
|
|
49
|
+
label: "Ban User",
|
|
50
|
+
icon: "ban",
|
|
51
|
+
variant: "danger",
|
|
52
|
+
locations: ["list_item"],
|
|
53
|
+
type: "api",
|
|
54
|
+
target: "/api/v1/auth/admin/ban-user",
|
|
55
|
+
recordIdParam: "userId",
|
|
56
|
+
successMessage: "User banned",
|
|
57
|
+
refreshAfter: true,
|
|
58
|
+
confirmText: "Ban this user? They will be signed out and unable to sign in until unbanned.",
|
|
59
|
+
params: [
|
|
60
|
+
{ name: "banReason", label: "Ban Reason", type: "text", required: false }
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "unban_user",
|
|
65
|
+
label: "Unban User",
|
|
66
|
+
icon: "check-circle-2",
|
|
67
|
+
variant: "secondary",
|
|
68
|
+
locations: ["list_item"],
|
|
69
|
+
type: "api",
|
|
70
|
+
target: "/api/v1/auth/admin/unban-user",
|
|
71
|
+
recordIdParam: "userId",
|
|
72
|
+
successMessage: "User unbanned",
|
|
73
|
+
refreshAfter: true
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "set_user_password",
|
|
77
|
+
label: "Set Password",
|
|
78
|
+
icon: "key-round",
|
|
79
|
+
variant: "secondary",
|
|
80
|
+
locations: ["list_item"],
|
|
81
|
+
type: "api",
|
|
82
|
+
target: "/api/v1/auth/admin/set-user-password",
|
|
83
|
+
recordIdParam: "userId",
|
|
84
|
+
successMessage: "Password updated",
|
|
85
|
+
refreshAfter: false,
|
|
86
|
+
params: [
|
|
87
|
+
{ name: "newPassword", label: "New Password", type: "text", required: true }
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "set_user_role",
|
|
92
|
+
label: "Set Platform Role",
|
|
93
|
+
icon: "shield-check",
|
|
94
|
+
variant: "secondary",
|
|
95
|
+
locations: ["list_item"],
|
|
96
|
+
type: "api",
|
|
97
|
+
target: "/api/v1/auth/admin/set-role",
|
|
98
|
+
recordIdParam: "userId",
|
|
99
|
+
successMessage: "Role updated",
|
|
100
|
+
refreshAfter: true,
|
|
101
|
+
params: [
|
|
102
|
+
{ name: "role", label: "Platform Role", type: "text", required: true }
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "impersonate_user",
|
|
107
|
+
label: "Impersonate User",
|
|
108
|
+
icon: "user-cog",
|
|
109
|
+
variant: "secondary",
|
|
110
|
+
locations: ["list_item"],
|
|
111
|
+
type: "api",
|
|
112
|
+
target: "/api/v1/auth/admin/impersonate-user",
|
|
113
|
+
recordIdParam: "userId",
|
|
114
|
+
successMessage: "Now impersonating user",
|
|
115
|
+
refreshAfter: true,
|
|
116
|
+
confirmText: "Start an impersonation session for this user? Use only for legitimate support cases \u2014 actions will be logged."
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
listViews: {
|
|
120
|
+
all_users: {
|
|
121
|
+
type: "grid",
|
|
122
|
+
name: "all_users",
|
|
123
|
+
label: "All Users",
|
|
124
|
+
data: { provider: "object", object: "sys_user" },
|
|
125
|
+
columns: ["name", "email", "email_verified", "two_factor_enabled", "created_at"],
|
|
126
|
+
sort: [{ field: "name", order: "asc" }],
|
|
127
|
+
pagination: { pageSize: 50 }
|
|
128
|
+
},
|
|
129
|
+
unverified: {
|
|
130
|
+
type: "grid",
|
|
131
|
+
name: "unverified",
|
|
132
|
+
label: "Unverified",
|
|
133
|
+
data: { provider: "object", object: "sys_user" },
|
|
134
|
+
columns: ["name", "email", "created_at"],
|
|
135
|
+
filter: [{ field: "email_verified", operator: "equals", value: false }],
|
|
136
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
137
|
+
pagination: { pageSize: 50 }
|
|
138
|
+
},
|
|
139
|
+
two_factor: {
|
|
140
|
+
type: "grid",
|
|
141
|
+
name: "two_factor",
|
|
142
|
+
label: "2FA Enabled",
|
|
143
|
+
data: { provider: "object", object: "sys_user" },
|
|
144
|
+
columns: ["name", "email", "two_factor_enabled", "updated_at"],
|
|
145
|
+
filter: [{ field: "two_factor_enabled", operator: "equals", value: true }],
|
|
146
|
+
sort: [{ field: "name", order: "asc" }],
|
|
147
|
+
pagination: { pageSize: 50 }
|
|
148
|
+
},
|
|
149
|
+
banned: {
|
|
150
|
+
type: "grid",
|
|
151
|
+
name: "banned",
|
|
152
|
+
label: "Banned",
|
|
153
|
+
data: { provider: "object", object: "sys_user" },
|
|
154
|
+
columns: ["name", "email", "banned", "ban_reason", "ban_expires"],
|
|
155
|
+
filter: [{ field: "banned", operator: "equals", value: true }],
|
|
156
|
+
sort: [{ field: "updated_at", order: "desc" }],
|
|
157
|
+
pagination: { pageSize: 50 }
|
|
158
|
+
}
|
|
159
|
+
},
|
|
16
160
|
fields: {
|
|
17
161
|
// ── Identity (primary business fields) ───────────────────────
|
|
18
162
|
name: data.Field.text({
|
|
@@ -39,6 +183,32 @@ var SysUser = data.ObjectSchema.create({
|
|
|
39
183
|
group: "Identity",
|
|
40
184
|
description: "Whether two-factor authentication is enabled for this user. Maintained by the better-auth `twoFactor` plugin."
|
|
41
185
|
}),
|
|
186
|
+
// ── Admin (managed by better-auth `admin` plugin when enabled) ───
|
|
187
|
+
role: data.Field.text({
|
|
188
|
+
label: "Platform Role",
|
|
189
|
+
required: false,
|
|
190
|
+
maxLength: 64,
|
|
191
|
+
group: "Admin",
|
|
192
|
+
description: "Platform-level role (admin, user, \u2026). Set via the Set Platform Role action."
|
|
193
|
+
}),
|
|
194
|
+
banned: data.Field.boolean({
|
|
195
|
+
label: "Banned",
|
|
196
|
+
defaultValue: false,
|
|
197
|
+
group: "Admin",
|
|
198
|
+
description: "When true, the user cannot sign in. Toggle via Ban User / Unban User actions."
|
|
199
|
+
}),
|
|
200
|
+
ban_reason: data.Field.text({
|
|
201
|
+
label: "Ban Reason",
|
|
202
|
+
required: false,
|
|
203
|
+
maxLength: 255,
|
|
204
|
+
group: "Admin"
|
|
205
|
+
}),
|
|
206
|
+
ban_expires: data.Field.datetime({
|
|
207
|
+
label: "Ban Expires",
|
|
208
|
+
required: false,
|
|
209
|
+
group: "Admin",
|
|
210
|
+
description: "When set, the ban auto-clears at this time."
|
|
211
|
+
}),
|
|
42
212
|
// ── Profile ──────────────────────────────────────────────────
|
|
43
213
|
image: data.Field.url({
|
|
44
214
|
label: "Profile Image",
|
|
@@ -94,10 +264,67 @@ var SysSession = data.ObjectSchema.create({
|
|
|
94
264
|
pluralLabel: "Sessions",
|
|
95
265
|
icon: "key",
|
|
96
266
|
isSystem: true,
|
|
267
|
+
managedBy: "better-auth",
|
|
97
268
|
description: "Active user sessions",
|
|
98
269
|
displayNameField: "user_id",
|
|
99
270
|
titleFormat: "Session \u2014 {user_id}",
|
|
100
271
|
compactLayout: ["user_id", "ip_address", "expires_at"],
|
|
272
|
+
// Custom actions — sessions are managed by better-auth (generic CRUD
|
|
273
|
+
// suppressed). "Sign out other devices" is the high-value self-service
|
|
274
|
+
// affordance every IdP exposes. Maps to better-auth's
|
|
275
|
+
// `revoke-other-sessions` endpoint which terminates every session for
|
|
276
|
+
// the current user except the one making the request.
|
|
277
|
+
actions: [
|
|
278
|
+
{
|
|
279
|
+
name: "revoke_my_other_sessions",
|
|
280
|
+
label: "Sign out other devices",
|
|
281
|
+
icon: "log-out",
|
|
282
|
+
variant: "danger",
|
|
283
|
+
locations: ["list_toolbar"],
|
|
284
|
+
type: "api",
|
|
285
|
+
target: "/api/v1/auth/revoke-other-sessions",
|
|
286
|
+
confirmText: "Sign out of every other device where you're currently logged in? Your current session will remain active.",
|
|
287
|
+
successMessage: "All other sessions revoked",
|
|
288
|
+
refreshAfter: true
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
name: "revoke_session",
|
|
292
|
+
label: "Revoke Session",
|
|
293
|
+
icon: "log-out",
|
|
294
|
+
variant: "danger",
|
|
295
|
+
mode: "delete",
|
|
296
|
+
locations: ["list_item"],
|
|
297
|
+
type: "api",
|
|
298
|
+
target: "/api/v1/auth/revoke-session",
|
|
299
|
+
// better-auth `revoke-session` keys off the session token, not the id.
|
|
300
|
+
recordIdParam: "token",
|
|
301
|
+
recordIdField: "token",
|
|
302
|
+
confirmText: "Revoke this session? The user will be signed out from that device.",
|
|
303
|
+
successMessage: "Session revoked",
|
|
304
|
+
refreshAfter: true
|
|
305
|
+
}
|
|
306
|
+
],
|
|
307
|
+
listViews: {
|
|
308
|
+
mine: {
|
|
309
|
+
type: "grid",
|
|
310
|
+
name: "mine",
|
|
311
|
+
label: "My Sessions",
|
|
312
|
+
data: { provider: "object", object: "sys_session" },
|
|
313
|
+
columns: ["ip_address", "active_organization_id", "created_at", "expires_at"],
|
|
314
|
+
filter: [{ field: "user_id", operator: "equals", value: "{current_user_id}" }],
|
|
315
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
316
|
+
pagination: { pageSize: 50 }
|
|
317
|
+
},
|
|
318
|
+
all_sessions: {
|
|
319
|
+
type: "grid",
|
|
320
|
+
name: "all_sessions",
|
|
321
|
+
label: "All",
|
|
322
|
+
data: { provider: "object", object: "sys_session" },
|
|
323
|
+
columns: ["user_id", "ip_address", "active_organization_id", "created_at", "expires_at"],
|
|
324
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
325
|
+
pagination: { pageSize: 50 }
|
|
326
|
+
}
|
|
327
|
+
},
|
|
101
328
|
fields: {
|
|
102
329
|
// ── Session owner & expiry ──────────────────────────────────
|
|
103
330
|
user_id: data.Field.lookup("sys_user", {
|
|
@@ -135,6 +362,13 @@ var SysSession = data.ObjectSchema.create({
|
|
|
135
362
|
required: false,
|
|
136
363
|
group: "Client"
|
|
137
364
|
}),
|
|
365
|
+
// ── Admin (managed by better-auth `admin` plugin) ────────────
|
|
366
|
+
impersonated_by: data.Field.lookup("sys_user", {
|
|
367
|
+
label: "Impersonated By",
|
|
368
|
+
required: false,
|
|
369
|
+
group: "Admin",
|
|
370
|
+
description: "User id of the admin that started this impersonation session, if any."
|
|
371
|
+
}),
|
|
138
372
|
// ── Secret (hidden by default) ──────────────────────────────
|
|
139
373
|
token: data.Field.text({
|
|
140
374
|
label: "Session Token",
|
|
@@ -185,9 +419,41 @@ var SysAccount = data.ObjectSchema.create({
|
|
|
185
419
|
pluralLabel: "Accounts",
|
|
186
420
|
icon: "link",
|
|
187
421
|
isSystem: true,
|
|
422
|
+
managedBy: "better-auth",
|
|
188
423
|
description: "OAuth and authentication provider accounts",
|
|
189
424
|
titleFormat: "{provider_id} - {account_id}",
|
|
190
425
|
compactLayout: ["provider_id", "user_id", "account_id"],
|
|
426
|
+
listViews: {
|
|
427
|
+
mine: {
|
|
428
|
+
type: "grid",
|
|
429
|
+
name: "mine",
|
|
430
|
+
label: "My Links",
|
|
431
|
+
data: { provider: "object", object: "sys_account" },
|
|
432
|
+
columns: ["provider_id", "account_id", "created_at", "updated_at"],
|
|
433
|
+
filter: [{ field: "user_id", operator: "equals", value: "{current_user_id}" }],
|
|
434
|
+
sort: [{ field: "provider_id", order: "asc" }],
|
|
435
|
+
pagination: { pageSize: 50 }
|
|
436
|
+
},
|
|
437
|
+
by_provider: {
|
|
438
|
+
type: "grid",
|
|
439
|
+
name: "by_provider",
|
|
440
|
+
label: "By Provider",
|
|
441
|
+
data: { provider: "object", object: "sys_account" },
|
|
442
|
+
columns: ["provider_id", "user_id", "account_id", "created_at"],
|
|
443
|
+
sort: [{ field: "provider_id", order: "asc" }, { field: "created_at", order: "desc" }],
|
|
444
|
+
grouping: { fields: [{ field: "provider_id", order: "asc", collapsed: false }] },
|
|
445
|
+
pagination: { pageSize: 100 }
|
|
446
|
+
},
|
|
447
|
+
all_links: {
|
|
448
|
+
type: "grid",
|
|
449
|
+
name: "all_links",
|
|
450
|
+
label: "All",
|
|
451
|
+
data: { provider: "object", object: "sys_account" },
|
|
452
|
+
columns: ["provider_id", "user_id", "account_id", "created_at", "updated_at"],
|
|
453
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
454
|
+
pagination: { pageSize: 100 }
|
|
455
|
+
}
|
|
456
|
+
},
|
|
191
457
|
fields: {
|
|
192
458
|
id: data.Field.text({
|
|
193
459
|
label: "Account ID",
|
|
@@ -268,6 +534,7 @@ var SysVerification = data.ObjectSchema.create({
|
|
|
268
534
|
pluralLabel: "Verifications",
|
|
269
535
|
icon: "shield-check",
|
|
270
536
|
isSystem: true,
|
|
537
|
+
managedBy: "better-auth",
|
|
271
538
|
description: "Email and phone verification tokens",
|
|
272
539
|
titleFormat: "Verification for {identifier}",
|
|
273
540
|
compactLayout: ["identifier", "expires_at", "created_at"],
|
|
@@ -322,10 +589,109 @@ var SysOrganization = data.ObjectSchema.create({
|
|
|
322
589
|
pluralLabel: "Organizations",
|
|
323
590
|
icon: "building-2",
|
|
324
591
|
isSystem: true,
|
|
592
|
+
managedBy: "better-auth",
|
|
325
593
|
description: "Organizations for multi-tenant grouping",
|
|
326
594
|
displayNameField: "name",
|
|
327
595
|
titleFormat: "{name}",
|
|
328
596
|
compactLayout: ["name", "slug"],
|
|
597
|
+
// Custom actions — generic CRUD is suppressed (better-auth-managed),
|
|
598
|
+
// but admins still need to create new orgs from the Setup app.
|
|
599
|
+
actions: [
|
|
600
|
+
{
|
|
601
|
+
name: "create_organization",
|
|
602
|
+
label: "Create Organization",
|
|
603
|
+
icon: "plus",
|
|
604
|
+
variant: "primary",
|
|
605
|
+
locations: ["list_toolbar"],
|
|
606
|
+
type: "api",
|
|
607
|
+
target: "/api/v1/auth/organization/create",
|
|
608
|
+
successMessage: "Organization created",
|
|
609
|
+
refreshAfter: true,
|
|
610
|
+
params: [
|
|
611
|
+
{ field: "name", required: true },
|
|
612
|
+
{ field: "slug", required: true },
|
|
613
|
+
{ field: "logo" }
|
|
614
|
+
]
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
name: "update_organization",
|
|
618
|
+
label: "Edit Organization",
|
|
619
|
+
icon: "pencil",
|
|
620
|
+
mode: "edit",
|
|
621
|
+
locations: ["list_item"],
|
|
622
|
+
type: "api",
|
|
623
|
+
target: "/api/v1/auth/organization/update",
|
|
624
|
+
recordIdParam: "organizationId",
|
|
625
|
+
// better-auth `organization/update` nests editable fields under `data`.
|
|
626
|
+
bodyShape: { wrap: "data" },
|
|
627
|
+
successMessage: "Organization updated",
|
|
628
|
+
refreshAfter: true,
|
|
629
|
+
params: [
|
|
630
|
+
{ field: "name", required: true, defaultFromRow: true },
|
|
631
|
+
{ field: "slug", required: true, defaultFromRow: true },
|
|
632
|
+
{ field: "logo", defaultFromRow: true }
|
|
633
|
+
]
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
name: "delete_organization",
|
|
637
|
+
label: "Delete Organization",
|
|
638
|
+
icon: "trash-2",
|
|
639
|
+
variant: "danger",
|
|
640
|
+
mode: "delete",
|
|
641
|
+
locations: ["list_item"],
|
|
642
|
+
type: "api",
|
|
643
|
+
target: "/api/v1/auth/organization/delete",
|
|
644
|
+
recordIdParam: "organizationId",
|
|
645
|
+
confirmText: "Delete this organization? All members will lose access immediately. This cannot be undone.",
|
|
646
|
+
successMessage: "Organization deleted",
|
|
647
|
+
refreshAfter: true
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
// Switch the caller's active organization context. Standard
|
|
651
|
+
// better-auth endpoint; no extra params needed (org id ships as
|
|
652
|
+
// the row id). Used from the Setup list and the record header so
|
|
653
|
+
// admins can context-switch without leaving the page.
|
|
654
|
+
name: "set_active_organization",
|
|
655
|
+
label: "Set Active",
|
|
656
|
+
icon: "check-circle-2",
|
|
657
|
+
variant: "secondary",
|
|
658
|
+
mode: "custom",
|
|
659
|
+
locations: ["list_item", "record_header"],
|
|
660
|
+
type: "api",
|
|
661
|
+
target: "/api/v1/auth/organization/set-active",
|
|
662
|
+
recordIdParam: "organizationId",
|
|
663
|
+
successMessage: "Active organization switched",
|
|
664
|
+
refreshAfter: true
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
// Current user leaves the org. Distinct from `delete_organization`
|
|
668
|
+
// (admin-only, destroys the org) — `leave` only removes the caller's
|
|
669
|
+
// own membership. Better-auth: `organization/leave { organizationId }`.
|
|
670
|
+
name: "leave_organization",
|
|
671
|
+
label: "Leave Organization",
|
|
672
|
+
icon: "log-out",
|
|
673
|
+
variant: "danger",
|
|
674
|
+
mode: "custom",
|
|
675
|
+
locations: ["list_item", "record_header"],
|
|
676
|
+
type: "api",
|
|
677
|
+
target: "/api/v1/auth/organization/leave",
|
|
678
|
+
recordIdParam: "organizationId",
|
|
679
|
+
confirmText: "Leave this organization? You will lose access to all of its resources.",
|
|
680
|
+
successMessage: "You have left the organization",
|
|
681
|
+
refreshAfter: true
|
|
682
|
+
}
|
|
683
|
+
],
|
|
684
|
+
listViews: {
|
|
685
|
+
all_orgs: {
|
|
686
|
+
type: "grid",
|
|
687
|
+
name: "all_orgs",
|
|
688
|
+
label: "All",
|
|
689
|
+
data: { provider: "object", object: "sys_organization" },
|
|
690
|
+
columns: ["name", "slug", "created_at", "updated_at"],
|
|
691
|
+
sort: [{ field: "name", order: "asc" }],
|
|
692
|
+
pagination: { pageSize: 50 }
|
|
693
|
+
}
|
|
694
|
+
},
|
|
329
695
|
fields: {
|
|
330
696
|
// ── Identity ─────────────────────────────────────────────────
|
|
331
697
|
name: data.Field.text({
|
|
@@ -395,9 +761,67 @@ var SysMember = data.ObjectSchema.create({
|
|
|
395
761
|
pluralLabel: "Members",
|
|
396
762
|
icon: "user-check",
|
|
397
763
|
isSystem: true,
|
|
764
|
+
managedBy: "better-auth",
|
|
398
765
|
description: "Organization membership records",
|
|
399
766
|
titleFormat: "{user_id} in {organization_id}",
|
|
400
767
|
compactLayout: ["user_id", "organization_id", "role"],
|
|
768
|
+
// Row-level actions: better-auth `organization/update-member-role` and
|
|
769
|
+
// `organization/remove-member`. Generic CRUD is suppressed on better-auth
|
|
770
|
+
// managed tables, so these are the canonical edit/delete entry points.
|
|
771
|
+
// The `add_member` toolbar action covers the admin "attach an existing
|
|
772
|
+
// user directly without sending an invitation" flow.
|
|
773
|
+
actions: [
|
|
774
|
+
{
|
|
775
|
+
// Admin-only: directly attach an existing user to the active org,
|
|
776
|
+
// bypassing the invite-accept flow. Better-auth:
|
|
777
|
+
// `organization/add-member { userId, role, organizationId?, teamId? }`.
|
|
778
|
+
// organizationId/teamId default to the caller's active org/team when
|
|
779
|
+
// omitted, so we leave them as optional params.
|
|
780
|
+
name: "add_member",
|
|
781
|
+
label: "Add Member",
|
|
782
|
+
icon: "user-plus",
|
|
783
|
+
variant: "primary",
|
|
784
|
+
locations: ["list_toolbar"],
|
|
785
|
+
type: "api",
|
|
786
|
+
target: "/api/v1/auth/organization/add-member",
|
|
787
|
+
successMessage: "Member added",
|
|
788
|
+
refreshAfter: true,
|
|
789
|
+
params: [
|
|
790
|
+
{ name: "userId", field: "user_id", required: true },
|
|
791
|
+
{ field: "role", required: true },
|
|
792
|
+
{ name: "organizationId", field: "organization_id" }
|
|
793
|
+
]
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
name: "update_member_role",
|
|
797
|
+
label: "Change Role",
|
|
798
|
+
icon: "shield",
|
|
799
|
+
mode: "edit",
|
|
800
|
+
locations: ["list_item"],
|
|
801
|
+
type: "api",
|
|
802
|
+
target: "/api/v1/auth/organization/update-member-role",
|
|
803
|
+
recordIdParam: "memberId",
|
|
804
|
+
successMessage: "Member role updated",
|
|
805
|
+
refreshAfter: true,
|
|
806
|
+
params: [
|
|
807
|
+
{ field: "role", required: true, defaultFromRow: true }
|
|
808
|
+
]
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
name: "remove_member",
|
|
812
|
+
label: "Remove Member",
|
|
813
|
+
icon: "user-minus",
|
|
814
|
+
variant: "danger",
|
|
815
|
+
mode: "delete",
|
|
816
|
+
locations: ["list_item"],
|
|
817
|
+
type: "api",
|
|
818
|
+
target: "/api/v1/auth/organization/remove-member",
|
|
819
|
+
recordIdParam: "memberIdOrEmail",
|
|
820
|
+
confirmText: "Remove this member from the organization? They will lose access to all org resources.",
|
|
821
|
+
successMessage: "Member removed",
|
|
822
|
+
refreshAfter: true
|
|
823
|
+
}
|
|
824
|
+
],
|
|
401
825
|
fields: {
|
|
402
826
|
id: data.Field.text({
|
|
403
827
|
label: "Member ID",
|
|
@@ -417,11 +841,16 @@ var SysMember = data.ObjectSchema.create({
|
|
|
417
841
|
label: "User",
|
|
418
842
|
required: true
|
|
419
843
|
}),
|
|
420
|
-
role: data.Field.
|
|
844
|
+
role: data.Field.select({
|
|
421
845
|
label: "Role",
|
|
422
846
|
required: false,
|
|
423
|
-
description: "Member role within the organization
|
|
424
|
-
|
|
847
|
+
description: "Member role within the organization",
|
|
848
|
+
options: [
|
|
849
|
+
{ label: "Owner", value: "owner" },
|
|
850
|
+
{ label: "Admin", value: "admin" },
|
|
851
|
+
{ label: "Member", value: "member" }
|
|
852
|
+
],
|
|
853
|
+
defaultValue: "member"
|
|
425
854
|
})
|
|
426
855
|
},
|
|
427
856
|
indexes: [
|
|
@@ -443,9 +872,101 @@ var SysInvitation = data.ObjectSchema.create({
|
|
|
443
872
|
pluralLabel: "Invitations",
|
|
444
873
|
icon: "mail",
|
|
445
874
|
isSystem: true,
|
|
875
|
+
managedBy: "better-auth",
|
|
446
876
|
description: "Organization invitations for user onboarding",
|
|
447
877
|
titleFormat: "Invitation to {organization_id}",
|
|
448
878
|
compactLayout: ["email", "organization_id", "status"],
|
|
879
|
+
// Custom actions — generic CRUD is suppressed (better-auth-managed).
|
|
880
|
+
// Mirror the `invite_user` toolbar action from sys_user here so admins
|
|
881
|
+
// landing on the Invitations page get an obvious entry point.
|
|
882
|
+
actions: [
|
|
883
|
+
{
|
|
884
|
+
name: "invite_user",
|
|
885
|
+
label: "Invite User",
|
|
886
|
+
icon: "user-plus",
|
|
887
|
+
variant: "primary",
|
|
888
|
+
locations: ["list_toolbar"],
|
|
889
|
+
type: "api",
|
|
890
|
+
target: "/api/v1/auth/organization/invite-member",
|
|
891
|
+
successMessage: "Invitation sent",
|
|
892
|
+
refreshAfter: true,
|
|
893
|
+
params: [
|
|
894
|
+
{ field: "email", required: true },
|
|
895
|
+
{ field: "role", required: true }
|
|
896
|
+
]
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
name: "cancel_invitation",
|
|
900
|
+
label: "Cancel Invitation",
|
|
901
|
+
icon: "x-circle",
|
|
902
|
+
variant: "danger",
|
|
903
|
+
mode: "delete",
|
|
904
|
+
locations: ["list_item"],
|
|
905
|
+
type: "api",
|
|
906
|
+
target: "/api/v1/auth/organization/cancel-invitation",
|
|
907
|
+
recordIdParam: "invitationId",
|
|
908
|
+
confirmText: "Cancel this invitation? The recipient will no longer be able to accept it.",
|
|
909
|
+
successMessage: "Invitation canceled",
|
|
910
|
+
refreshAfter: true
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
name: "resend_invitation",
|
|
914
|
+
label: "Resend Invitation",
|
|
915
|
+
icon: "send",
|
|
916
|
+
variant: "secondary",
|
|
917
|
+
locations: ["list_item"],
|
|
918
|
+
type: "api",
|
|
919
|
+
target: "/api/v1/auth/organization/invite-member",
|
|
920
|
+
bodyExtra: { resend: true },
|
|
921
|
+
successMessage: "Invitation resent",
|
|
922
|
+
refreshAfter: true,
|
|
923
|
+
params: [
|
|
924
|
+
{ field: "email", required: true, defaultFromRow: true },
|
|
925
|
+
{ field: "role", required: true, defaultFromRow: true }
|
|
926
|
+
]
|
|
927
|
+
}
|
|
928
|
+
],
|
|
929
|
+
listViews: {
|
|
930
|
+
pending: {
|
|
931
|
+
type: "grid",
|
|
932
|
+
name: "pending",
|
|
933
|
+
label: "Pending",
|
|
934
|
+
data: { provider: "object", object: "sys_invitation" },
|
|
935
|
+
columns: ["email", "role", "organization_id", "inviter_id", "expires_at"],
|
|
936
|
+
filter: [{ field: "status", operator: "equals", value: "pending" }],
|
|
937
|
+
sort: [{ field: "expires_at", order: "asc" }],
|
|
938
|
+
pagination: { pageSize: 50 }
|
|
939
|
+
},
|
|
940
|
+
accepted: {
|
|
941
|
+
type: "grid",
|
|
942
|
+
name: "accepted",
|
|
943
|
+
label: "Accepted",
|
|
944
|
+
data: { provider: "object", object: "sys_invitation" },
|
|
945
|
+
columns: ["email", "role", "organization_id", "inviter_id", "created_at"],
|
|
946
|
+
filter: [{ field: "status", operator: "equals", value: "accepted" }],
|
|
947
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
948
|
+
pagination: { pageSize: 50 }
|
|
949
|
+
},
|
|
950
|
+
expired: {
|
|
951
|
+
type: "grid",
|
|
952
|
+
name: "expired",
|
|
953
|
+
label: "Expired / Canceled",
|
|
954
|
+
data: { provider: "object", object: "sys_invitation" },
|
|
955
|
+
columns: ["email", "status", "organization_id", "expires_at"],
|
|
956
|
+
filter: [{ field: "status", operator: "in", value: ["expired", "rejected", "canceled"] }],
|
|
957
|
+
sort: [{ field: "expires_at", order: "desc" }],
|
|
958
|
+
pagination: { pageSize: 50 }
|
|
959
|
+
},
|
|
960
|
+
all_invitations: {
|
|
961
|
+
type: "grid",
|
|
962
|
+
name: "all_invitations",
|
|
963
|
+
label: "All",
|
|
964
|
+
data: { provider: "object", object: "sys_invitation" },
|
|
965
|
+
columns: ["email", "status", "role", "organization_id", "inviter_id", "created_at"],
|
|
966
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
967
|
+
pagination: { pageSize: 50 }
|
|
968
|
+
}
|
|
969
|
+
},
|
|
449
970
|
fields: {
|
|
450
971
|
id: data.Field.text({
|
|
451
972
|
label: "Invitation ID",
|
|
@@ -466,11 +987,16 @@ var SysInvitation = data.ObjectSchema.create({
|
|
|
466
987
|
required: true,
|
|
467
988
|
description: "Email address of the invited user"
|
|
468
989
|
}),
|
|
469
|
-
role: data.Field.
|
|
990
|
+
role: data.Field.select({
|
|
470
991
|
label: "Role",
|
|
471
992
|
required: false,
|
|
472
|
-
|
|
473
|
-
|
|
993
|
+
description: "Role to assign upon acceptance",
|
|
994
|
+
options: [
|
|
995
|
+
{ label: "Owner", value: "owner" },
|
|
996
|
+
{ label: "Admin", value: "admin" },
|
|
997
|
+
{ label: "Member", value: "member" }
|
|
998
|
+
],
|
|
999
|
+
defaultValue: "member"
|
|
474
1000
|
}),
|
|
475
1001
|
status: data.Field.select(["pending", "accepted", "rejected", "expired", "canceled"], {
|
|
476
1002
|
label: "Status",
|
|
@@ -512,10 +1038,89 @@ var SysTeam = data.ObjectSchema.create({
|
|
|
512
1038
|
pluralLabel: "Teams",
|
|
513
1039
|
icon: "users",
|
|
514
1040
|
isSystem: true,
|
|
1041
|
+
managedBy: "better-auth",
|
|
515
1042
|
description: "Teams within organizations for fine-grained grouping",
|
|
516
1043
|
displayNameField: "name",
|
|
517
1044
|
titleFormat: "{name}",
|
|
518
1045
|
compactLayout: ["name", "organization_id"],
|
|
1046
|
+
// Custom actions calling better-auth's team endpoints. Generic CRUD is
|
|
1047
|
+
// suppressed (managedBy: 'better-auth'), so these are the canonical
|
|
1048
|
+
// entry points for create/update/delete.
|
|
1049
|
+
actions: [
|
|
1050
|
+
{
|
|
1051
|
+
// Better-auth: `organization/create-team { name, organizationId? }`.
|
|
1052
|
+
// organizationId defaults to the caller's active org when omitted.
|
|
1053
|
+
name: "create_team",
|
|
1054
|
+
label: "Create Team",
|
|
1055
|
+
icon: "plus",
|
|
1056
|
+
variant: "primary",
|
|
1057
|
+
locations: ["list_toolbar"],
|
|
1058
|
+
type: "api",
|
|
1059
|
+
target: "/api/v1/auth/organization/create-team",
|
|
1060
|
+
successMessage: "Team created",
|
|
1061
|
+
refreshAfter: true,
|
|
1062
|
+
params: [
|
|
1063
|
+
{ field: "name", required: true },
|
|
1064
|
+
{ name: "organizationId", field: "organization_id" }
|
|
1065
|
+
]
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
// Better-auth: `organization/update-team { teamId, data: { name } }`.
|
|
1069
|
+
// teamId stays flat (top-level); the user-editable params nest under
|
|
1070
|
+
// `data` via bodyShape.
|
|
1071
|
+
name: "update_team",
|
|
1072
|
+
label: "Edit Team",
|
|
1073
|
+
icon: "pencil",
|
|
1074
|
+
mode: "edit",
|
|
1075
|
+
locations: ["list_item"],
|
|
1076
|
+
type: "api",
|
|
1077
|
+
target: "/api/v1/auth/organization/update-team",
|
|
1078
|
+
recordIdParam: "teamId",
|
|
1079
|
+
bodyShape: { wrap: "data" },
|
|
1080
|
+
successMessage: "Team updated",
|
|
1081
|
+
refreshAfter: true,
|
|
1082
|
+
params: [
|
|
1083
|
+
{ field: "name", required: true, defaultFromRow: true }
|
|
1084
|
+
]
|
|
1085
|
+
},
|
|
1086
|
+
{
|
|
1087
|
+
// Better-auth: `organization/remove-team { teamId, organizationId? }`.
|
|
1088
|
+
// organizationId defaults to the caller's active org when omitted.
|
|
1089
|
+
name: "remove_team",
|
|
1090
|
+
label: "Delete Team",
|
|
1091
|
+
icon: "trash-2",
|
|
1092
|
+
variant: "danger",
|
|
1093
|
+
mode: "delete",
|
|
1094
|
+
locations: ["list_item"],
|
|
1095
|
+
type: "api",
|
|
1096
|
+
target: "/api/v1/auth/organization/remove-team",
|
|
1097
|
+
recordIdParam: "teamId",
|
|
1098
|
+
confirmText: "Delete this team? Members will lose any team-scoped access. This cannot be undone.",
|
|
1099
|
+
successMessage: "Team deleted",
|
|
1100
|
+
refreshAfter: true
|
|
1101
|
+
}
|
|
1102
|
+
],
|
|
1103
|
+
listViews: {
|
|
1104
|
+
by_org: {
|
|
1105
|
+
type: "grid",
|
|
1106
|
+
name: "by_org",
|
|
1107
|
+
label: "By Organization",
|
|
1108
|
+
data: { provider: "object", object: "sys_team" },
|
|
1109
|
+
columns: ["organization_id", "name", "created_at", "updated_at"],
|
|
1110
|
+
sort: [{ field: "organization_id", order: "asc" }, { field: "name", order: "asc" }],
|
|
1111
|
+
grouping: { fields: [{ field: "organization_id", order: "asc", collapsed: false }] },
|
|
1112
|
+
pagination: { pageSize: 100 }
|
|
1113
|
+
},
|
|
1114
|
+
all_teams: {
|
|
1115
|
+
type: "grid",
|
|
1116
|
+
name: "all_teams",
|
|
1117
|
+
label: "All",
|
|
1118
|
+
data: { provider: "object", object: "sys_team" },
|
|
1119
|
+
columns: ["name", "organization_id", "created_at", "updated_at"],
|
|
1120
|
+
sort: [{ field: "name", order: "asc" }],
|
|
1121
|
+
pagination: { pageSize: 50 }
|
|
1122
|
+
}
|
|
1123
|
+
},
|
|
519
1124
|
fields: {
|
|
520
1125
|
// ── Identity ─────────────────────────────────────────────────
|
|
521
1126
|
name: data.Field.text({
|
|
@@ -570,9 +1175,52 @@ var SysTeamMember = data.ObjectSchema.create({
|
|
|
570
1175
|
pluralLabel: "Team Members",
|
|
571
1176
|
icon: "user-plus",
|
|
572
1177
|
isSystem: true,
|
|
1178
|
+
managedBy: "better-auth",
|
|
573
1179
|
description: "Team membership records linking users to teams",
|
|
574
1180
|
titleFormat: "{user_id} in {team_id}",
|
|
575
1181
|
compactLayout: ["user_id", "team_id", "created_at"],
|
|
1182
|
+
// Custom actions calling better-auth's team-member endpoints. Generic
|
|
1183
|
+
// CRUD is suppressed (managedBy: 'better-auth') so these are the
|
|
1184
|
+
// canonical add/remove entry points.
|
|
1185
|
+
actions: [
|
|
1186
|
+
{
|
|
1187
|
+
// Better-auth: `organization/add-team-member { teamId, userId }`.
|
|
1188
|
+
name: "add_team_member",
|
|
1189
|
+
label: "Add Member",
|
|
1190
|
+
icon: "user-plus",
|
|
1191
|
+
variant: "primary",
|
|
1192
|
+
locations: ["list_toolbar"],
|
|
1193
|
+
type: "api",
|
|
1194
|
+
target: "/api/v1/auth/organization/add-team-member",
|
|
1195
|
+
successMessage: "Team member added",
|
|
1196
|
+
refreshAfter: true,
|
|
1197
|
+
params: [
|
|
1198
|
+
{ name: "teamId", field: "team_id", required: true },
|
|
1199
|
+
{ name: "userId", field: "user_id", required: true }
|
|
1200
|
+
]
|
|
1201
|
+
},
|
|
1202
|
+
{
|
|
1203
|
+
// Better-auth: `organization/remove-team-member { teamId, userId }`.
|
|
1204
|
+
// The endpoint identifies the membership by the (teamId, userId)
|
|
1205
|
+
// pair rather than the join-row id, so we pull both from the row
|
|
1206
|
+
// via `defaultFromRow` instead of using `recordIdParam`.
|
|
1207
|
+
name: "remove_team_member",
|
|
1208
|
+
label: "Remove from Team",
|
|
1209
|
+
icon: "user-minus",
|
|
1210
|
+
variant: "danger",
|
|
1211
|
+
mode: "delete",
|
|
1212
|
+
locations: ["list_item"],
|
|
1213
|
+
type: "api",
|
|
1214
|
+
target: "/api/v1/auth/organization/remove-team-member",
|
|
1215
|
+
confirmText: "Remove this user from the team? They will lose any team-scoped access.",
|
|
1216
|
+
successMessage: "Team member removed",
|
|
1217
|
+
refreshAfter: true,
|
|
1218
|
+
params: [
|
|
1219
|
+
{ name: "teamId", field: "team_id", required: true, defaultFromRow: true },
|
|
1220
|
+
{ name: "userId", field: "user_id", required: true, defaultFromRow: true }
|
|
1221
|
+
]
|
|
1222
|
+
}
|
|
1223
|
+
],
|
|
576
1224
|
fields: {
|
|
577
1225
|
id: data.Field.text({
|
|
578
1226
|
label: "Team Member ID",
|
|
@@ -606,16 +1254,338 @@ var SysTeamMember = data.ObjectSchema.create({
|
|
|
606
1254
|
mru: false
|
|
607
1255
|
}
|
|
608
1256
|
});
|
|
1257
|
+
var SysDepartment = data.ObjectSchema.create({
|
|
1258
|
+
name: "sys_department",
|
|
1259
|
+
label: "Department",
|
|
1260
|
+
pluralLabel: "Departments",
|
|
1261
|
+
icon: "building",
|
|
1262
|
+
isSystem: true,
|
|
1263
|
+
managedBy: "platform",
|
|
1264
|
+
description: "Hierarchical org-skeleton node (department / division / business unit / office).",
|
|
1265
|
+
displayNameField: "name",
|
|
1266
|
+
titleFormat: "{name}",
|
|
1267
|
+
compactLayout: ["name", "kind", "parent_department_id", "manager_user_id"],
|
|
1268
|
+
listViews: {
|
|
1269
|
+
active: {
|
|
1270
|
+
type: "grid",
|
|
1271
|
+
name: "active",
|
|
1272
|
+
label: "Active",
|
|
1273
|
+
data: { provider: "object", object: "sys_department" },
|
|
1274
|
+
columns: ["name", "code", "kind", "parent_department_id", "manager_user_id", "effective_from"],
|
|
1275
|
+
filter: [{ field: "active", operator: "equals", value: true }],
|
|
1276
|
+
sort: [{ field: "name", order: "asc" }],
|
|
1277
|
+
pagination: { pageSize: 100 }
|
|
1278
|
+
},
|
|
1279
|
+
inactive: {
|
|
1280
|
+
type: "grid",
|
|
1281
|
+
name: "inactive",
|
|
1282
|
+
label: "Inactive",
|
|
1283
|
+
data: { provider: "object", object: "sys_department" },
|
|
1284
|
+
columns: ["name", "code", "kind", "effective_to"],
|
|
1285
|
+
filter: [{ field: "active", operator: "equals", value: false }],
|
|
1286
|
+
sort: [{ field: "effective_to", order: "desc" }],
|
|
1287
|
+
pagination: { pageSize: 50 }
|
|
1288
|
+
},
|
|
1289
|
+
by_kind: {
|
|
1290
|
+
type: "grid",
|
|
1291
|
+
name: "by_kind",
|
|
1292
|
+
label: "By Kind",
|
|
1293
|
+
data: { provider: "object", object: "sys_department" },
|
|
1294
|
+
columns: ["kind", "name", "code", "parent_department_id", "manager_user_id", "active"],
|
|
1295
|
+
sort: [{ field: "kind", order: "asc" }, { field: "name", order: "asc" }],
|
|
1296
|
+
grouping: { fields: [{ field: "kind", order: "asc", collapsed: false }] },
|
|
1297
|
+
pagination: { pageSize: 100 }
|
|
1298
|
+
},
|
|
1299
|
+
all_departments: {
|
|
1300
|
+
type: "grid",
|
|
1301
|
+
name: "all_departments",
|
|
1302
|
+
label: "All",
|
|
1303
|
+
data: { provider: "object", object: "sys_department" },
|
|
1304
|
+
columns: ["name", "code", "kind", "parent_department_id", "manager_user_id", "active"],
|
|
1305
|
+
sort: [{ field: "name", order: "asc" }],
|
|
1306
|
+
pagination: { pageSize: 100 }
|
|
1307
|
+
}
|
|
1308
|
+
},
|
|
1309
|
+
fields: {
|
|
1310
|
+
// ── Identity ─────────────────────────────────────────────────
|
|
1311
|
+
name: data.Field.text({
|
|
1312
|
+
label: "Name",
|
|
1313
|
+
required: true,
|
|
1314
|
+
searchable: true,
|
|
1315
|
+
maxLength: 255,
|
|
1316
|
+
group: "Identity"
|
|
1317
|
+
}),
|
|
1318
|
+
code: data.Field.text({
|
|
1319
|
+
label: "Code",
|
|
1320
|
+
required: false,
|
|
1321
|
+
searchable: true,
|
|
1322
|
+
maxLength: 64,
|
|
1323
|
+
description: "Short stable code (e.g. EMEA-SALES). Unique within tenant.",
|
|
1324
|
+
group: "Identity"
|
|
1325
|
+
}),
|
|
1326
|
+
kind: data.Field.select(
|
|
1327
|
+
["company", "division", "department", "team", "office", "cost_center"],
|
|
1328
|
+
{
|
|
1329
|
+
label: "Kind",
|
|
1330
|
+
required: true,
|
|
1331
|
+
defaultValue: "department",
|
|
1332
|
+
description: "Categorisation hint \u2014 does not change graph semantics.",
|
|
1333
|
+
group: "Identity"
|
|
1334
|
+
}
|
|
1335
|
+
),
|
|
1336
|
+
// ── Hierarchy ────────────────────────────────────────────────
|
|
1337
|
+
parent_department_id: data.Field.lookup("sys_department", {
|
|
1338
|
+
label: "Parent Department",
|
|
1339
|
+
required: false,
|
|
1340
|
+
description: "Self-reference for the org tree. Null = root of tenant.",
|
|
1341
|
+
group: "Hierarchy"
|
|
1342
|
+
}),
|
|
1343
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
1344
|
+
label: "Organization",
|
|
1345
|
+
required: true,
|
|
1346
|
+
description: "Tenant scope.",
|
|
1347
|
+
group: "Hierarchy"
|
|
1348
|
+
}),
|
|
1349
|
+
// ── Leadership ───────────────────────────────────────────────
|
|
1350
|
+
manager_user_id: data.Field.lookup("sys_user", {
|
|
1351
|
+
label: "Department Head",
|
|
1352
|
+
required: false,
|
|
1353
|
+
description: "User responsible for this org unit (department head / lead).",
|
|
1354
|
+
group: "Leadership"
|
|
1355
|
+
}),
|
|
1356
|
+
// ── Lifecycle ────────────────────────────────────────────────
|
|
1357
|
+
active: data.Field.boolean({
|
|
1358
|
+
label: "Active",
|
|
1359
|
+
required: false,
|
|
1360
|
+
defaultValue: true,
|
|
1361
|
+
description: "When false, members are not expanded by graph queries.",
|
|
1362
|
+
group: "Lifecycle"
|
|
1363
|
+
}),
|
|
1364
|
+
effective_from: data.Field.datetime({
|
|
1365
|
+
label: "Effective From",
|
|
1366
|
+
required: false,
|
|
1367
|
+
description: "When this department came into existence (HRIS sync).",
|
|
1368
|
+
group: "Lifecycle"
|
|
1369
|
+
}),
|
|
1370
|
+
effective_to: data.Field.datetime({
|
|
1371
|
+
label: "Effective To",
|
|
1372
|
+
required: false,
|
|
1373
|
+
description: "When this department was retired (HRIS sync).",
|
|
1374
|
+
group: "Lifecycle"
|
|
1375
|
+
}),
|
|
1376
|
+
external_ref: data.Field.text({
|
|
1377
|
+
label: "External Reference",
|
|
1378
|
+
required: false,
|
|
1379
|
+
maxLength: 200,
|
|
1380
|
+
description: "ID in upstream HRIS (Workday / SAP HR / \u5317\u68EE).",
|
|
1381
|
+
group: "Lifecycle"
|
|
1382
|
+
}),
|
|
1383
|
+
// ── System ───────────────────────────────────────────────────
|
|
1384
|
+
id: data.Field.text({
|
|
1385
|
+
label: "Department ID",
|
|
1386
|
+
required: true,
|
|
1387
|
+
readonly: true,
|
|
1388
|
+
group: "System"
|
|
1389
|
+
}),
|
|
1390
|
+
created_at: data.Field.datetime({
|
|
1391
|
+
label: "Created At",
|
|
1392
|
+
defaultValue: "NOW()",
|
|
1393
|
+
readonly: true,
|
|
1394
|
+
group: "System"
|
|
1395
|
+
}),
|
|
1396
|
+
updated_at: data.Field.datetime({
|
|
1397
|
+
label: "Updated At",
|
|
1398
|
+
defaultValue: "NOW()",
|
|
1399
|
+
readonly: true,
|
|
1400
|
+
group: "System"
|
|
1401
|
+
})
|
|
1402
|
+
},
|
|
1403
|
+
indexes: [
|
|
1404
|
+
{ fields: ["organization_id"] },
|
|
1405
|
+
{ fields: ["parent_department_id"] },
|
|
1406
|
+
{ fields: ["code", "organization_id"], unique: true },
|
|
1407
|
+
{ fields: ["active"] }
|
|
1408
|
+
],
|
|
1409
|
+
enable: {
|
|
1410
|
+
trackHistory: true,
|
|
1411
|
+
searchable: true,
|
|
1412
|
+
apiEnabled: true,
|
|
1413
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
1414
|
+
trash: true,
|
|
1415
|
+
mru: false
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
var SysDepartmentMember = data.ObjectSchema.create({
|
|
1419
|
+
name: "sys_department_member",
|
|
1420
|
+
label: "Department Member",
|
|
1421
|
+
pluralLabel: "Department Members",
|
|
1422
|
+
icon: "user-cog",
|
|
1423
|
+
isSystem: true,
|
|
1424
|
+
managedBy: "platform",
|
|
1425
|
+
description: "User assignment to a department (matrix-org friendly, effective-dated).",
|
|
1426
|
+
titleFormat: "{user_id} in {department_id}",
|
|
1427
|
+
compactLayout: ["user_id", "department_id", "role_in_department", "is_primary"],
|
|
1428
|
+
fields: {
|
|
1429
|
+
id: data.Field.text({
|
|
1430
|
+
label: "Member ID",
|
|
1431
|
+
required: true,
|
|
1432
|
+
readonly: true,
|
|
1433
|
+
group: "System"
|
|
1434
|
+
}),
|
|
1435
|
+
department_id: data.Field.lookup("sys_department", {
|
|
1436
|
+
label: "Department",
|
|
1437
|
+
required: true,
|
|
1438
|
+
group: "Assignment"
|
|
1439
|
+
}),
|
|
1440
|
+
user_id: data.Field.lookup("sys_user", {
|
|
1441
|
+
label: "User",
|
|
1442
|
+
required: true,
|
|
1443
|
+
group: "Assignment"
|
|
1444
|
+
}),
|
|
1445
|
+
role_in_department: data.Field.select(
|
|
1446
|
+
["member", "lead", "deputy"],
|
|
1447
|
+
{
|
|
1448
|
+
label: "Role in Department",
|
|
1449
|
+
required: false,
|
|
1450
|
+
defaultValue: "member",
|
|
1451
|
+
description: "`lead` is the day-to-day head; `deputy` may stand in for the lead in approval routing.",
|
|
1452
|
+
group: "Assignment"
|
|
1453
|
+
}
|
|
1454
|
+
),
|
|
1455
|
+
is_primary: data.Field.boolean({
|
|
1456
|
+
label: "Primary Assignment",
|
|
1457
|
+
required: false,
|
|
1458
|
+
defaultValue: true,
|
|
1459
|
+
description: "When the user is in multiple departments, this marks the canonical one for reporting.",
|
|
1460
|
+
group: "Assignment"
|
|
1461
|
+
}),
|
|
1462
|
+
effective_from: data.Field.datetime({
|
|
1463
|
+
label: "Effective From",
|
|
1464
|
+
required: false,
|
|
1465
|
+
group: "Lifecycle"
|
|
1466
|
+
}),
|
|
1467
|
+
effective_to: data.Field.datetime({
|
|
1468
|
+
label: "Effective To",
|
|
1469
|
+
required: false,
|
|
1470
|
+
group: "Lifecycle"
|
|
1471
|
+
}),
|
|
1472
|
+
created_at: data.Field.datetime({
|
|
1473
|
+
label: "Created At",
|
|
1474
|
+
defaultValue: "NOW()",
|
|
1475
|
+
readonly: true,
|
|
1476
|
+
group: "System"
|
|
1477
|
+
}),
|
|
1478
|
+
updated_at: data.Field.datetime({
|
|
1479
|
+
label: "Updated At",
|
|
1480
|
+
defaultValue: "NOW()",
|
|
1481
|
+
readonly: true,
|
|
1482
|
+
group: "System"
|
|
1483
|
+
})
|
|
1484
|
+
},
|
|
1485
|
+
indexes: [
|
|
1486
|
+
{ fields: ["department_id", "user_id"], unique: true },
|
|
1487
|
+
{ fields: ["user_id"] },
|
|
1488
|
+
{ fields: ["is_primary"] }
|
|
1489
|
+
],
|
|
1490
|
+
enable: {
|
|
1491
|
+
trackHistory: true,
|
|
1492
|
+
searchable: true,
|
|
1493
|
+
apiEnabled: true,
|
|
1494
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
1495
|
+
trash: true,
|
|
1496
|
+
mru: false
|
|
1497
|
+
}
|
|
1498
|
+
});
|
|
609
1499
|
var SysApiKey = data.ObjectSchema.create({
|
|
610
1500
|
name: "sys_api_key",
|
|
611
1501
|
label: "API Key",
|
|
612
1502
|
pluralLabel: "API Keys",
|
|
613
1503
|
icon: "key-round",
|
|
614
1504
|
isSystem: true,
|
|
1505
|
+
managedBy: "better-auth",
|
|
615
1506
|
description: "API keys for programmatic access",
|
|
616
1507
|
displayNameField: "name",
|
|
617
1508
|
titleFormat: "{name}",
|
|
618
1509
|
compactLayout: ["name", "prefix", "user_id", "expires_at", "revoked"],
|
|
1510
|
+
// Custom actions — sys_api_key is managed-by 'better-auth' but the
|
|
1511
|
+
// `revoked` boolean is a column we control via the data API. These row
|
|
1512
|
+
// actions use the generic PATCH /api/v1/sys_api_key/{id} endpoint with
|
|
1513
|
+
// `bodyExtra` to set the `revoked` flag explicitly.
|
|
1514
|
+
actions: [
|
|
1515
|
+
{
|
|
1516
|
+
name: "revoke_api_key",
|
|
1517
|
+
label: "Revoke API Key",
|
|
1518
|
+
icon: "shield-off",
|
|
1519
|
+
variant: "danger",
|
|
1520
|
+
mode: "custom",
|
|
1521
|
+
locations: ["list_item"],
|
|
1522
|
+
type: "api",
|
|
1523
|
+
method: "PATCH",
|
|
1524
|
+
target: "/api/v1/data/sys_api_key/{id}",
|
|
1525
|
+
bodyExtra: { revoked: true },
|
|
1526
|
+
confirmText: "Revoke this API key? Any clients using it will immediately lose access.",
|
|
1527
|
+
successMessage: "API key revoked",
|
|
1528
|
+
refreshAfter: true
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
name: "restore_api_key",
|
|
1532
|
+
label: "Restore API Key",
|
|
1533
|
+
icon: "shield-check",
|
|
1534
|
+
variant: "secondary",
|
|
1535
|
+
mode: "custom",
|
|
1536
|
+
locations: ["list_item"],
|
|
1537
|
+
type: "api",
|
|
1538
|
+
method: "PATCH",
|
|
1539
|
+
target: "/api/v1/data/sys_api_key/{id}",
|
|
1540
|
+
bodyExtra: { revoked: false },
|
|
1541
|
+
confirmText: "Restore this revoked API key? Existing clients holding the key will regain access.",
|
|
1542
|
+
successMessage: "API key restored",
|
|
1543
|
+
refreshAfter: true
|
|
1544
|
+
}
|
|
1545
|
+
],
|
|
1546
|
+
listViews: {
|
|
1547
|
+
mine: {
|
|
1548
|
+
type: "grid",
|
|
1549
|
+
name: "mine",
|
|
1550
|
+
label: "My Keys",
|
|
1551
|
+
data: { provider: "object", object: "sys_api_key" },
|
|
1552
|
+
columns: ["name", "prefix", "expires_at", "last_used_at", "revoked"],
|
|
1553
|
+
filter: [
|
|
1554
|
+
{ field: "user_id", operator: "equals", value: "{current_user_id}" }
|
|
1555
|
+
],
|
|
1556
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
1557
|
+
pagination: { pageSize: 50 }
|
|
1558
|
+
},
|
|
1559
|
+
active: {
|
|
1560
|
+
type: "grid",
|
|
1561
|
+
name: "active",
|
|
1562
|
+
label: "Active",
|
|
1563
|
+
data: { provider: "object", object: "sys_api_key" },
|
|
1564
|
+
columns: ["name", "prefix", "user_id", "expires_at", "last_used_at"],
|
|
1565
|
+
filter: [{ field: "revoked", operator: "equals", value: false }],
|
|
1566
|
+
sort: [{ field: "last_used_at", order: "desc" }],
|
|
1567
|
+
pagination: { pageSize: 50 }
|
|
1568
|
+
},
|
|
1569
|
+
revoked: {
|
|
1570
|
+
type: "grid",
|
|
1571
|
+
name: "revoked",
|
|
1572
|
+
label: "Revoked",
|
|
1573
|
+
data: { provider: "object", object: "sys_api_key" },
|
|
1574
|
+
columns: ["name", "prefix", "user_id", "expires_at", "updated_at"],
|
|
1575
|
+
filter: [{ field: "revoked", operator: "equals", value: true }],
|
|
1576
|
+
sort: [{ field: "updated_at", order: "desc" }],
|
|
1577
|
+
pagination: { pageSize: 50 }
|
|
1578
|
+
},
|
|
1579
|
+
all_keys: {
|
|
1580
|
+
type: "grid",
|
|
1581
|
+
name: "all_keys",
|
|
1582
|
+
label: "All",
|
|
1583
|
+
data: { provider: "object", object: "sys_api_key" },
|
|
1584
|
+
columns: ["name", "prefix", "user_id", "expires_at", "last_used_at", "revoked"],
|
|
1585
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
1586
|
+
pagination: { pageSize: 50 }
|
|
1587
|
+
}
|
|
1588
|
+
},
|
|
619
1589
|
fields: {
|
|
620
1590
|
// ── Identity ─────────────────────────────────────────────────
|
|
621
1591
|
name: data.Field.text({
|
|
@@ -714,9 +1684,66 @@ var SysTwoFactor = data.ObjectSchema.create({
|
|
|
714
1684
|
pluralLabel: "Two Factor Credentials",
|
|
715
1685
|
icon: "smartphone",
|
|
716
1686
|
isSystem: true,
|
|
1687
|
+
managedBy: "better-auth",
|
|
717
1688
|
description: "Two-factor authentication credentials",
|
|
718
1689
|
titleFormat: "Two-factor for {user_id}",
|
|
719
1690
|
compactLayout: ["user_id", "created_at"],
|
|
1691
|
+
listViews: {
|
|
1692
|
+
mine: {
|
|
1693
|
+
type: "grid",
|
|
1694
|
+
name: "mine",
|
|
1695
|
+
label: "My Enrollment",
|
|
1696
|
+
data: { provider: "object", object: "sys_two_factor" },
|
|
1697
|
+
columns: ["created_at", "updated_at"],
|
|
1698
|
+
filter: [{ field: "user_id", operator: "equals", value: "{current_user_id}" }],
|
|
1699
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
1700
|
+
pagination: { pageSize: 50 }
|
|
1701
|
+
},
|
|
1702
|
+
all_enrollments: {
|
|
1703
|
+
type: "grid",
|
|
1704
|
+
name: "all_enrollments",
|
|
1705
|
+
label: "All",
|
|
1706
|
+
data: { provider: "object", object: "sys_two_factor" },
|
|
1707
|
+
columns: ["user_id", "created_at", "updated_at"],
|
|
1708
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
1709
|
+
pagination: { pageSize: 50 }
|
|
1710
|
+
}
|
|
1711
|
+
},
|
|
1712
|
+
// Toolbar actions for self-service 2FA enrollment. The actual TOTP secret
|
|
1713
|
+
// and backup codes returned by better-auth must be shown in the response
|
|
1714
|
+
// toast / dialog — the action runner surfaces successMessage; the raw
|
|
1715
|
+
// payload is logged client-side for now (TODO: dedicated 2FA setup wizard).
|
|
1716
|
+
actions: [
|
|
1717
|
+
{
|
|
1718
|
+
name: "enable_two_factor",
|
|
1719
|
+
label: "Enable 2FA",
|
|
1720
|
+
icon: "shield-check",
|
|
1721
|
+
variant: "primary",
|
|
1722
|
+
locations: ["list_toolbar"],
|
|
1723
|
+
type: "api",
|
|
1724
|
+
target: "/api/v1/auth/two-factor/enable",
|
|
1725
|
+
successMessage: "2FA enrollment started \u2014 check response for TOTP URI and backup codes",
|
|
1726
|
+
refreshAfter: true,
|
|
1727
|
+
params: [
|
|
1728
|
+
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
1729
|
+
]
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
name: "disable_two_factor",
|
|
1733
|
+
label: "Disable 2FA",
|
|
1734
|
+
icon: "shield-off",
|
|
1735
|
+
variant: "danger",
|
|
1736
|
+
locations: ["list_toolbar"],
|
|
1737
|
+
type: "api",
|
|
1738
|
+
target: "/api/v1/auth/two-factor/disable",
|
|
1739
|
+
confirmText: "Disable two-factor authentication on your account?",
|
|
1740
|
+
successMessage: "2FA disabled",
|
|
1741
|
+
refreshAfter: true,
|
|
1742
|
+
params: [
|
|
1743
|
+
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
1744
|
+
]
|
|
1745
|
+
}
|
|
1746
|
+
],
|
|
720
1747
|
fields: {
|
|
721
1748
|
id: data.Field.text({
|
|
722
1749
|
label: "Two Factor ID",
|
|
@@ -766,6 +1793,7 @@ var SysDeviceCode = data.ObjectSchema.create({
|
|
|
766
1793
|
pluralLabel: "Device Codes",
|
|
767
1794
|
icon: "key-round",
|
|
768
1795
|
isSystem: true,
|
|
1796
|
+
managedBy: "better-auth",
|
|
769
1797
|
description: "OAuth 2.0 Device Authorization Grant (RFC 8628) pending requests",
|
|
770
1798
|
titleFormat: "{user_code}",
|
|
771
1799
|
compactLayout: ["user_code", "status", "client_id", "expires_at"],
|
|
@@ -855,9 +1883,44 @@ var SysUserPreference = data.ObjectSchema.create({
|
|
|
855
1883
|
pluralLabel: "User Preferences",
|
|
856
1884
|
icon: "settings",
|
|
857
1885
|
isSystem: true,
|
|
1886
|
+
// managedBy: 'system' — preferences are per-user state authored from
|
|
1887
|
+
// the user's own settings page, never created by an admin. The list
|
|
1888
|
+
// surface in Setup is a support/diagnostic view only.
|
|
1889
|
+
managedBy: "system",
|
|
858
1890
|
description: "Per-user key-value preferences (theme, locale, etc.)",
|
|
859
1891
|
titleFormat: "{key}",
|
|
860
1892
|
compactLayout: ["user_id", "key"],
|
|
1893
|
+
listViews: {
|
|
1894
|
+
mine: {
|
|
1895
|
+
type: "grid",
|
|
1896
|
+
name: "mine",
|
|
1897
|
+
label: "My Preferences",
|
|
1898
|
+
data: { provider: "object", object: "sys_user_preference" },
|
|
1899
|
+
columns: ["key", "updated_at"],
|
|
1900
|
+
filter: [{ field: "user_id", operator: "equals", value: "{current_user_id}" }],
|
|
1901
|
+
sort: [{ field: "key", order: "asc" }],
|
|
1902
|
+
pagination: { pageSize: 100 }
|
|
1903
|
+
},
|
|
1904
|
+
by_user: {
|
|
1905
|
+
type: "grid",
|
|
1906
|
+
name: "by_user",
|
|
1907
|
+
label: "By User",
|
|
1908
|
+
data: { provider: "object", object: "sys_user_preference" },
|
|
1909
|
+
columns: ["user_id", "key", "updated_at"],
|
|
1910
|
+
sort: [{ field: "user_id", order: "asc" }, { field: "key", order: "asc" }],
|
|
1911
|
+
grouping: { fields: [{ field: "user_id", order: "asc", collapsed: true }] },
|
|
1912
|
+
pagination: { pageSize: 200 }
|
|
1913
|
+
},
|
|
1914
|
+
all_preferences: {
|
|
1915
|
+
type: "grid",
|
|
1916
|
+
name: "all_preferences",
|
|
1917
|
+
label: "All",
|
|
1918
|
+
data: { provider: "object", object: "sys_user_preference" },
|
|
1919
|
+
columns: ["user_id", "key", "created_at", "updated_at"],
|
|
1920
|
+
sort: [{ field: "updated_at", order: "desc" }],
|
|
1921
|
+
pagination: { pageSize: 100 }
|
|
1922
|
+
}
|
|
1923
|
+
},
|
|
861
1924
|
fields: {
|
|
862
1925
|
id: data.Field.text({
|
|
863
1926
|
label: "Preference ID",
|
|
@@ -909,10 +1972,42 @@ var SysOauthApplication = data.ObjectSchema.create({
|
|
|
909
1972
|
pluralLabel: "OAuth Applications",
|
|
910
1973
|
icon: "key-round",
|
|
911
1974
|
isSystem: true,
|
|
1975
|
+
managedBy: "better-auth",
|
|
912
1976
|
description: "Registered OAuth/OIDC client applications",
|
|
913
1977
|
displayNameField: "name",
|
|
914
1978
|
titleFormat: "{name}",
|
|
915
1979
|
compactLayout: ["name", "client_id", "type", "disabled"],
|
|
1980
|
+
listViews: {
|
|
1981
|
+
active: {
|
|
1982
|
+
type: "grid",
|
|
1983
|
+
name: "active",
|
|
1984
|
+
label: "Active",
|
|
1985
|
+
data: { provider: "object", object: "sys_oauth_application" },
|
|
1986
|
+
columns: ["name", "client_id", "type", "updated_at"],
|
|
1987
|
+
filter: [{ field: "disabled", operator: "equals", value: false }],
|
|
1988
|
+
sort: [{ field: "name", order: "asc" }],
|
|
1989
|
+
pagination: { pageSize: 50 }
|
|
1990
|
+
},
|
|
1991
|
+
disabled_apps: {
|
|
1992
|
+
type: "grid",
|
|
1993
|
+
name: "disabled_apps",
|
|
1994
|
+
label: "Disabled",
|
|
1995
|
+
data: { provider: "object", object: "sys_oauth_application" },
|
|
1996
|
+
columns: ["name", "client_id", "type", "updated_at"],
|
|
1997
|
+
filter: [{ field: "disabled", operator: "equals", value: true }],
|
|
1998
|
+
sort: [{ field: "updated_at", order: "desc" }],
|
|
1999
|
+
pagination: { pageSize: 50 }
|
|
2000
|
+
},
|
|
2001
|
+
all_apps: {
|
|
2002
|
+
type: "grid",
|
|
2003
|
+
name: "all_apps",
|
|
2004
|
+
label: "All",
|
|
2005
|
+
data: { provider: "object", object: "sys_oauth_application" },
|
|
2006
|
+
columns: ["name", "client_id", "type", "disabled", "created_at"],
|
|
2007
|
+
sort: [{ field: "name", order: "asc" }],
|
|
2008
|
+
pagination: { pageSize: 50 }
|
|
2009
|
+
}
|
|
2010
|
+
},
|
|
916
2011
|
fields: {
|
|
917
2012
|
// ── Identity ─────────────────────────────────────────────────
|
|
918
2013
|
id: data.Field.text({
|
|
@@ -1124,6 +2219,7 @@ var SysOauthAccessToken = data.ObjectSchema.create({
|
|
|
1124
2219
|
pluralLabel: "OAuth Access Tokens",
|
|
1125
2220
|
icon: "ticket",
|
|
1126
2221
|
isSystem: true,
|
|
2222
|
+
managedBy: "better-auth",
|
|
1127
2223
|
description: "Opaque OAuth access tokens issued to client applications",
|
|
1128
2224
|
compactLayout: ["client_id", "user_id", "expires_at"],
|
|
1129
2225
|
fields: {
|
|
@@ -1201,6 +2297,7 @@ var SysOauthRefreshToken = data.ObjectSchema.create({
|
|
|
1201
2297
|
pluralLabel: "OAuth Refresh Tokens",
|
|
1202
2298
|
icon: "refresh-cw",
|
|
1203
2299
|
isSystem: true,
|
|
2300
|
+
managedBy: "better-auth",
|
|
1204
2301
|
description: "Opaque OAuth refresh tokens (linked to a session)",
|
|
1205
2302
|
compactLayout: ["client_id", "user_id", "expires_at"],
|
|
1206
2303
|
fields: {
|
|
@@ -1282,6 +2379,7 @@ var SysOauthConsent = data.ObjectSchema.create({
|
|
|
1282
2379
|
pluralLabel: "OAuth Consents",
|
|
1283
2380
|
icon: "shield-check",
|
|
1284
2381
|
isSystem: true,
|
|
2382
|
+
managedBy: "better-auth",
|
|
1285
2383
|
description: "User consent records for OAuth client applications",
|
|
1286
2384
|
compactLayout: ["client_id", "user_id", "scopes"],
|
|
1287
2385
|
fields: {
|
|
@@ -1341,6 +2439,7 @@ var SysJwks = data.ObjectSchema.create({
|
|
|
1341
2439
|
pluralLabel: "JWKS Keys",
|
|
1342
2440
|
icon: "key",
|
|
1343
2441
|
isSystem: true,
|
|
2442
|
+
managedBy: "better-auth",
|
|
1344
2443
|
description: "Asymmetric key pairs used to sign and verify issued JWTs",
|
|
1345
2444
|
compactLayout: ["id", "created_at", "expires_at"],
|
|
1346
2445
|
fields: {
|
|
@@ -1384,6 +2483,8 @@ var SysJwks = data.ObjectSchema.create({
|
|
|
1384
2483
|
|
|
1385
2484
|
exports.SysAccount = SysAccount;
|
|
1386
2485
|
exports.SysApiKey = SysApiKey;
|
|
2486
|
+
exports.SysDepartment = SysDepartment;
|
|
2487
|
+
exports.SysDepartmentMember = SysDepartmentMember;
|
|
1387
2488
|
exports.SysDeviceCode = SysDeviceCode;
|
|
1388
2489
|
exports.SysInvitation = SysInvitation;
|
|
1389
2490
|
exports.SysJwks = SysJwks;
|