@objectstack/platform-objects 6.9.0 → 7.0.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 +30 -1
- package/dist/apps/index.d.ts +30 -1
- package/dist/apps/index.js +994 -37
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/index.mjs +994 -38
- package/dist/apps/index.mjs.map +1 -1
- package/dist/audit/index.d.mts +192 -16
- package/dist/audit/index.d.ts +192 -16
- package/dist/identity/index.d.mts +840 -22
- package/dist/identity/index.d.ts +840 -22
- package/dist/identity/index.js +384 -8
- package/dist/identity/index.js.map +1 -1
- package/dist/identity/index.mjs +384 -8
- package/dist/identity/index.mjs.map +1 -1
- package/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +6815 -104
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6810 -105
- package/dist/index.mjs.map +1 -1
- package/dist/integration/index.d.mts +12 -1
- package/dist/integration/index.d.ts +12 -1
- package/dist/metadata/index.d.mts +24 -2
- package/dist/metadata/index.d.ts +24 -2
- package/dist/metadata-translations/index.d.mts +20 -0
- package/dist/metadata-translations/index.d.ts +20 -0
- package/dist/metadata-translations/index.js +4777 -0
- package/dist/metadata-translations/index.js.map +1 -0
- package/dist/metadata-translations/index.mjs +4775 -0
- package/dist/metadata-translations/index.mjs.map +1 -0
- package/dist/pages/index.d.mts +68 -0
- package/dist/pages/index.d.ts +68 -0
- package/dist/pages/index.js +371 -0
- package/dist/pages/index.js.map +1 -0
- package/dist/pages/index.mjs +368 -0
- package/dist/pages/index.mjs.map +1 -0
- package/dist/plugin.d.mts +35 -0
- package/dist/plugin.d.ts +35 -0
- package/dist/plugin.js +17566 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugin.mjs +17563 -0
- package/dist/plugin.mjs.map +1 -0
- package/dist/security/index.d.mts +785 -183
- package/dist/security/index.d.ts +785 -183
- package/dist/security/index.js +188 -1
- package/dist/security/index.js.map +1 -1
- package/dist/security/index.mjs +188 -1
- package/dist/security/index.mjs.map +1 -1
- package/dist/system/index.d.mts +36 -3
- package/dist/system/index.d.ts +36 -3
- package/package.json +17 -2
package/dist/identity/index.js
CHANGED
|
@@ -114,9 +114,166 @@ var SysUser = data.ObjectSchema.create({
|
|
|
114
114
|
successMessage: "Now impersonating user",
|
|
115
115
|
refreshAfter: true,
|
|
116
116
|
confirmText: "Start an impersonation session for this user? Use only for legitimate support cases \u2014 actions will be logged."
|
|
117
|
+
},
|
|
118
|
+
// ── Self-service actions (the row owner only) ─────────────────────
|
|
119
|
+
//
|
|
120
|
+
// These four actions are the "account settings" surfaces the standalone
|
|
121
|
+
// Account SPA used to own (`/account/profile`, `/account/security`).
|
|
122
|
+
// They are visible only when the current row is the signed-in user —
|
|
123
|
+
// i.e. opened from the user's own detail page or a "My Account" view —
|
|
124
|
+
// via the `visible` CEL predicate. Admin equivalents (set_user_password
|
|
125
|
+
// for any account) are above and stay separate.
|
|
126
|
+
{
|
|
127
|
+
name: "update_my_profile",
|
|
128
|
+
label: "Update Profile",
|
|
129
|
+
icon: "user-pen",
|
|
130
|
+
variant: "primary",
|
|
131
|
+
mode: "edit",
|
|
132
|
+
locations: ["record_header"],
|
|
133
|
+
type: "api",
|
|
134
|
+
target: "/api/v1/auth/update-user",
|
|
135
|
+
visible: "record.id == ctx.user.id",
|
|
136
|
+
successMessage: "Profile updated",
|
|
137
|
+
refreshAfter: true,
|
|
138
|
+
params: [
|
|
139
|
+
{ field: "name", required: false, defaultFromRow: true },
|
|
140
|
+
{ field: "image", required: false, defaultFromRow: true }
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: "change_my_password",
|
|
145
|
+
label: "Change Password",
|
|
146
|
+
icon: "key",
|
|
147
|
+
variant: "secondary",
|
|
148
|
+
locations: ["record_header", "record_more", "record_section"],
|
|
149
|
+
type: "api",
|
|
150
|
+
target: "/api/v1/auth/change-password",
|
|
151
|
+
visible: "record.id == ctx.user.id",
|
|
152
|
+
successMessage: "Password changed",
|
|
153
|
+
refreshAfter: false,
|
|
154
|
+
params: [
|
|
155
|
+
{ name: "currentPassword", label: "Current Password", type: "text", required: true },
|
|
156
|
+
{ name: "newPassword", label: "New Password", type: "text", required: true },
|
|
157
|
+
{ name: "revokeOtherSessions", label: "Sign out other devices", type: "boolean", required: false, defaultValue: true }
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "change_my_email",
|
|
162
|
+
label: "Change Email",
|
|
163
|
+
icon: "mail",
|
|
164
|
+
variant: "secondary",
|
|
165
|
+
locations: ["record_header", "record_more", "record_section"],
|
|
166
|
+
type: "api",
|
|
167
|
+
target: "/api/v1/auth/change-email",
|
|
168
|
+
visible: "record.id == ctx.user.id",
|
|
169
|
+
successMessage: "Verification email sent \u2014 check the new address to confirm.",
|
|
170
|
+
refreshAfter: false,
|
|
171
|
+
params: [
|
|
172
|
+
{ name: "newEmail", label: "New Email", type: "email", required: true }
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "resend_verification_email",
|
|
177
|
+
label: "Resend Verification Email",
|
|
178
|
+
icon: "mail-check",
|
|
179
|
+
variant: "secondary",
|
|
180
|
+
locations: ["record_header", "record_more", "record_section"],
|
|
181
|
+
type: "api",
|
|
182
|
+
target: "/api/v1/auth/send-verification-email",
|
|
183
|
+
// Only render for the row owner AND when their email is still
|
|
184
|
+
// unverified — there's nothing to resend once verified.
|
|
185
|
+
visible: "record.id == ctx.user.id && record.email_verified == false",
|
|
186
|
+
successMessage: "Verification email sent \u2014 check your inbox.",
|
|
187
|
+
refreshAfter: false,
|
|
188
|
+
params: []
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: "delete_my_account",
|
|
192
|
+
label: "Delete My Account",
|
|
193
|
+
icon: "user-x",
|
|
194
|
+
variant: "danger",
|
|
195
|
+
mode: "delete",
|
|
196
|
+
locations: ["record_more", "record_section"],
|
|
197
|
+
type: "api",
|
|
198
|
+
target: "/api/v1/auth/delete-user",
|
|
199
|
+
visible: "record.id == ctx.user.id",
|
|
200
|
+
confirmText: "Permanently delete your account? This cannot be undone \u2014 all your sessions will be terminated and all data you own will be removed per the configured retention policy.",
|
|
201
|
+
successMessage: "Account deleted",
|
|
202
|
+
refreshAfter: false,
|
|
203
|
+
params: [
|
|
204
|
+
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
205
|
+
]
|
|
206
|
+
},
|
|
207
|
+
// ── Two-factor authentication ─────────────────────────────────
|
|
208
|
+
// Enable flow returns { totpURI, backupCodes } — surfacing those
|
|
209
|
+
// safely needs a QR + verify UI that the generic action engine
|
|
210
|
+
// can't render yet. We still expose it so the API call works
|
|
211
|
+
// and the success toast displays the otpauth:// URI that users
|
|
212
|
+
// can manually add to an authenticator app as a fallback.
|
|
213
|
+
{
|
|
214
|
+
name: "enable_two_factor",
|
|
215
|
+
label: "Enable Two-Factor Auth",
|
|
216
|
+
icon: "shield-plus",
|
|
217
|
+
variant: "primary",
|
|
218
|
+
locations: ["record_section"],
|
|
219
|
+
type: "api",
|
|
220
|
+
target: "/api/v1/auth/two-factor/enable",
|
|
221
|
+
visible: "record.id == ctx.user.id && record.two_factor_enabled != true",
|
|
222
|
+
successMessage: "Two-factor authentication enabled. Scan the QR code or paste the otpauth URI into your authenticator app, then verify a code to complete setup.",
|
|
223
|
+
refreshAfter: true,
|
|
224
|
+
params: [
|
|
225
|
+
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: "disable_two_factor",
|
|
230
|
+
label: "Disable Two-Factor Auth",
|
|
231
|
+
icon: "shield-off",
|
|
232
|
+
variant: "danger",
|
|
233
|
+
locations: ["record_section"],
|
|
234
|
+
type: "api",
|
|
235
|
+
target: "/api/v1/auth/two-factor/disable",
|
|
236
|
+
visible: "record.id == ctx.user.id && record.two_factor_enabled == true",
|
|
237
|
+
confirmText: "Turn off two-factor authentication? Your account will be less secure.",
|
|
238
|
+
successMessage: "Two-factor authentication disabled.",
|
|
239
|
+
refreshAfter: true,
|
|
240
|
+
params: [
|
|
241
|
+
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: "generate_backup_codes",
|
|
246
|
+
label: "Regenerate Backup Codes",
|
|
247
|
+
icon: "list-restart",
|
|
248
|
+
variant: "secondary",
|
|
249
|
+
locations: ["record_section"],
|
|
250
|
+
type: "api",
|
|
251
|
+
target: "/api/v1/auth/two-factor/generate-backup-codes",
|
|
252
|
+
visible: "record.id == ctx.user.id && record.two_factor_enabled == true",
|
|
253
|
+
confirmText: "Generate a new set of backup codes? Any previously generated codes will stop working.",
|
|
254
|
+
successMessage: "New backup codes generated \u2014 save them somewhere safe.",
|
|
255
|
+
refreshAfter: false,
|
|
256
|
+
params: [
|
|
257
|
+
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
258
|
+
]
|
|
117
259
|
}
|
|
118
260
|
],
|
|
119
261
|
listViews: {
|
|
262
|
+
// Self-service profile entry — surfaced by the Account App so every
|
|
263
|
+
// authenticated user can view / edit their own basic profile (name,
|
|
264
|
+
// email, avatar). Filtered to a single row (the caller) via the
|
|
265
|
+
// `{current_user_id}` template variable; RLS additionally enforces
|
|
266
|
+
// that non-admins cannot read other users' rows.
|
|
267
|
+
me: {
|
|
268
|
+
type: "grid",
|
|
269
|
+
name: "me",
|
|
270
|
+
label: "My Profile",
|
|
271
|
+
data: { provider: "object", object: "sys_user" },
|
|
272
|
+
columns: ["name", "email", "email_verified", "two_factor_enabled", "updated_at"],
|
|
273
|
+
filter: [{ field: "id", operator: "equals", value: "{current_user_id}" }],
|
|
274
|
+
sort: [{ field: "name", order: "asc" }],
|
|
275
|
+
pagination: { pageSize: 1 }
|
|
276
|
+
},
|
|
120
277
|
all_users: {
|
|
121
278
|
type: "grid",
|
|
122
279
|
name: "all_users",
|
|
@@ -428,7 +585,41 @@ var SysAccount = data.ObjectSchema.create({
|
|
|
428
585
|
// requests it). Better-auth exposes `/unlink-account { providerId,
|
|
429
586
|
// accountId }` for this. The form is locked to the row's values so
|
|
430
587
|
// it acts as a one-click confirmation rather than a free-form edit.
|
|
588
|
+
//
|
|
589
|
+
// `link_social` is the self-service counterpart — a toolbar action
|
|
590
|
+
// that redirects the browser to better-auth's social sign-in endpoint
|
|
591
|
+
// with a callbackURL pointing back to the linked-accounts view. The
|
|
592
|
+
// endpoint sets the link cookie and OAuth-dances through the provider,
|
|
593
|
+
// which is why it's `type: 'url'` (full page navigation) rather than
|
|
594
|
+
// `type: 'api'` (XHR — would block on CORS / 302).
|
|
431
595
|
actions: [
|
|
596
|
+
{
|
|
597
|
+
name: "link_social",
|
|
598
|
+
label: "Link Social Account",
|
|
599
|
+
icon: "link-2",
|
|
600
|
+
variant: "primary",
|
|
601
|
+
mode: "create",
|
|
602
|
+
locations: ["list_toolbar"],
|
|
603
|
+
type: "url",
|
|
604
|
+
target: "/api/v1/auth/sign-in/social?provider=${param.provider}&callbackURL=${ctx.origin}/apps/account/sys_account",
|
|
605
|
+
params: [
|
|
606
|
+
{
|
|
607
|
+
name: "provider",
|
|
608
|
+
label: "Provider",
|
|
609
|
+
type: "select",
|
|
610
|
+
required: true,
|
|
611
|
+
options: [
|
|
612
|
+
{ label: "Google", value: "google" },
|
|
613
|
+
{ label: "GitHub", value: "github" },
|
|
614
|
+
{ label: "Microsoft", value: "microsoft" },
|
|
615
|
+
{ label: "Apple", value: "apple" },
|
|
616
|
+
{ label: "Facebook", value: "facebook" },
|
|
617
|
+
{ label: "GitLab", value: "gitlab" },
|
|
618
|
+
{ label: "Discord", value: "discord" }
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
]
|
|
622
|
+
},
|
|
432
623
|
{
|
|
433
624
|
name: "unlink_account",
|
|
434
625
|
label: "Unlink Account",
|
|
@@ -709,6 +900,30 @@ var SysOrganization = data.ObjectSchema.create({
|
|
|
709
900
|
confirmText: "Leave this organization? You will lose access to all of its resources.",
|
|
710
901
|
successMessage: "You have left the organization",
|
|
711
902
|
refreshAfter: true
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
// Rename the organization slug (URL prefix). Backed by the cloud
|
|
906
|
+
// orchestrator at /api/v1/cloud/organizations/{id}/change-slug,
|
|
907
|
+
// which atomically updates sys_organization.slug, rewrites
|
|
908
|
+
// platform_subdomain sys_domain rows under the new slug, soft-
|
|
909
|
+
// retires the old rows with a redirect window, parks the old
|
|
910
|
+
// slug in sys_slug_reservation, and refreshes the registry
|
|
911
|
+
// mirror. See cloud `docs/design/sys-domain.md` §6.
|
|
912
|
+
name: "change_slug",
|
|
913
|
+
label: "Change Slug",
|
|
914
|
+
icon: "edit-3",
|
|
915
|
+
variant: "secondary",
|
|
916
|
+
mode: "custom",
|
|
917
|
+
locations: ["record_header"],
|
|
918
|
+
type: "api",
|
|
919
|
+
target: "/api/v1/cloud/organizations/{id}/change-slug",
|
|
920
|
+
method: "POST",
|
|
921
|
+
confirmText: "Renaming the slug rewrites every platform subdomain for this org and parks the old slug for 90 days. Continue?",
|
|
922
|
+
successMessage: "Organization slug changed",
|
|
923
|
+
refreshAfter: true,
|
|
924
|
+
params: [
|
|
925
|
+
{ field: "slug", required: true, defaultFromRow: true }
|
|
926
|
+
]
|
|
712
927
|
}
|
|
713
928
|
],
|
|
714
929
|
listViews: {
|
|
@@ -850,8 +1065,46 @@ var SysMember = data.ObjectSchema.create({
|
|
|
850
1065
|
confirmText: "Remove this member from the organization? They will lose access to all org resources.",
|
|
851
1066
|
successMessage: "Member removed",
|
|
852
1067
|
refreshAfter: true
|
|
1068
|
+
},
|
|
1069
|
+
// Transfer ownership is modeled as `update-member-role` with role=owner
|
|
1070
|
+
// (better-auth's organization plugin auto-demotes the previous owner
|
|
1071
|
+
// to admin). Kept as a separate action so the row menu can present a
|
|
1072
|
+
// distinct destructive-style affordance with the right confirm copy —
|
|
1073
|
+
// mixing it into `update_member_role` would hide the ownership-handoff
|
|
1074
|
+
// semantics behind a generic role dropdown.
|
|
1075
|
+
{
|
|
1076
|
+
name: "transfer_ownership",
|
|
1077
|
+
label: "Transfer Ownership",
|
|
1078
|
+
icon: "crown",
|
|
1079
|
+
variant: "danger",
|
|
1080
|
+
mode: "custom",
|
|
1081
|
+
locations: ["list_item"],
|
|
1082
|
+
type: "api",
|
|
1083
|
+
target: "/api/v1/auth/organization/update-member-role",
|
|
1084
|
+
recordIdParam: "memberId",
|
|
1085
|
+
bodyExtra: { role: "owner" },
|
|
1086
|
+
visible: "record.role != 'owner'",
|
|
1087
|
+
confirmText: "Transfer ownership of this organization to the selected member? You will be demoted to admin and lose owner-only privileges.",
|
|
1088
|
+
successMessage: "Ownership transferred",
|
|
1089
|
+
refreshAfter: true
|
|
853
1090
|
}
|
|
854
1091
|
],
|
|
1092
|
+
listViews: {
|
|
1093
|
+
mine: {
|
|
1094
|
+
type: "grid",
|
|
1095
|
+
name: "mine",
|
|
1096
|
+
label: "My Memberships",
|
|
1097
|
+
data: { provider: "object", object: "sys_member" },
|
|
1098
|
+
columns: ["organization_id", "role", "created_at"],
|
|
1099
|
+
filter: [{ field: "user_id", operator: "equals", value: "{current_user_id}" }],
|
|
1100
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
1101
|
+
pagination: { pageSize: 50 },
|
|
1102
|
+
emptyState: {
|
|
1103
|
+
title: "No organizations yet",
|
|
1104
|
+
message: "You haven't joined any organizations."
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
855
1108
|
fields: {
|
|
856
1109
|
id: data.Field.text({
|
|
857
1110
|
label: "Member ID",
|
|
@@ -954,6 +1207,40 @@ var SysInvitation = data.ObjectSchema.create({
|
|
|
954
1207
|
{ field: "email", required: true, defaultFromRow: true },
|
|
955
1208
|
{ field: "role", required: true, defaultFromRow: true }
|
|
956
1209
|
]
|
|
1210
|
+
},
|
|
1211
|
+
// ── Recipient-side actions (the invited user) ────────────────────
|
|
1212
|
+
//
|
|
1213
|
+
// These two are the counterpart to invite/cancel/resend: they are
|
|
1214
|
+
// visible only on invitations addressed to the current user. Used
|
|
1215
|
+
// by an "Inbox / Pending invitations" list opened from the user's
|
|
1216
|
+
// own account page. The recipient-only `visible` predicate keeps
|
|
1217
|
+
// them out of the admin org-management view.
|
|
1218
|
+
{
|
|
1219
|
+
name: "accept_invitation",
|
|
1220
|
+
label: "Accept Invitation",
|
|
1221
|
+
icon: "check",
|
|
1222
|
+
variant: "primary",
|
|
1223
|
+
locations: ["list_item", "record_header"],
|
|
1224
|
+
type: "api",
|
|
1225
|
+
target: "/api/v1/auth/organization/accept-invitation",
|
|
1226
|
+
recordIdParam: "invitationId",
|
|
1227
|
+
visible: "record.email == ctx.user.email && record.status == 'pending'",
|
|
1228
|
+
successMessage: "Invitation accepted",
|
|
1229
|
+
refreshAfter: true
|
|
1230
|
+
},
|
|
1231
|
+
{
|
|
1232
|
+
name: "reject_invitation",
|
|
1233
|
+
label: "Decline Invitation",
|
|
1234
|
+
icon: "x",
|
|
1235
|
+
variant: "ghost",
|
|
1236
|
+
locations: ["list_item", "record_header"],
|
|
1237
|
+
type: "api",
|
|
1238
|
+
target: "/api/v1/auth/organization/reject-invitation",
|
|
1239
|
+
recordIdParam: "invitationId",
|
|
1240
|
+
visible: "record.email == ctx.user.email && record.status == 'pending'",
|
|
1241
|
+
confirmText: "Decline this invitation? The inviter will be notified and you will need a new invitation to join.",
|
|
1242
|
+
successMessage: "Invitation declined",
|
|
1243
|
+
refreshAfter: true
|
|
957
1244
|
}
|
|
958
1245
|
],
|
|
959
1246
|
listViews: {
|
|
@@ -1739,10 +2026,12 @@ var SysTwoFactor = data.ObjectSchema.create({
|
|
|
1739
2026
|
pagination: { pageSize: 50 }
|
|
1740
2027
|
}
|
|
1741
2028
|
},
|
|
1742
|
-
// Toolbar actions for self-service 2FA enrollment.
|
|
1743
|
-
//
|
|
1744
|
-
//
|
|
1745
|
-
//
|
|
2029
|
+
// Toolbar actions for self-service 2FA enrollment. Better-auth's
|
|
2030
|
+
// `/two-factor/enable` returns `{ totpURI, backupCodes }` — the user must
|
|
2031
|
+
// scan the URI into an authenticator app and save the backup codes NOW;
|
|
2032
|
+
// they are never recoverable afterward. The `resultDialog` field tells
|
|
2033
|
+
// the renderer to open a one-shot reveal dialog instead of toasting the
|
|
2034
|
+
// success message. Same shape used by `regenerate_backup_codes`.
|
|
1746
2035
|
actions: [
|
|
1747
2036
|
{
|
|
1748
2037
|
name: "enable_two_factor",
|
|
@@ -1752,11 +2041,19 @@ var SysTwoFactor = data.ObjectSchema.create({
|
|
|
1752
2041
|
locations: ["list_toolbar"],
|
|
1753
2042
|
type: "api",
|
|
1754
2043
|
target: "/api/v1/auth/two-factor/enable",
|
|
1755
|
-
successMessage: "2FA enrollment started \u2014 check response for TOTP URI and backup codes",
|
|
1756
2044
|
refreshAfter: true,
|
|
1757
2045
|
params: [
|
|
1758
2046
|
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
1759
|
-
]
|
|
2047
|
+
],
|
|
2048
|
+
resultDialog: {
|
|
2049
|
+
title: "Two-factor authentication enabled",
|
|
2050
|
+
description: "Scan the QR code with your authenticator app, then save the backup codes somewhere safe. The backup codes are shown only once.",
|
|
2051
|
+
acknowledge: "I have saved my backup codes",
|
|
2052
|
+
fields: [
|
|
2053
|
+
{ path: "totpURI", label: "Authenticator URI", format: "qrcode" },
|
|
2054
|
+
{ path: "backupCodes", label: "Backup Codes", format: "code-list" }
|
|
2055
|
+
]
|
|
2056
|
+
}
|
|
1760
2057
|
},
|
|
1761
2058
|
{
|
|
1762
2059
|
name: "disable_two_factor",
|
|
@@ -1772,6 +2069,28 @@ var SysTwoFactor = data.ObjectSchema.create({
|
|
|
1772
2069
|
params: [
|
|
1773
2070
|
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
1774
2071
|
]
|
|
2072
|
+
},
|
|
2073
|
+
{
|
|
2074
|
+
name: "regenerate_backup_codes",
|
|
2075
|
+
label: "Regenerate Backup Codes",
|
|
2076
|
+
icon: "refresh-cw",
|
|
2077
|
+
variant: "secondary",
|
|
2078
|
+
locations: ["list_toolbar", "list_item"],
|
|
2079
|
+
type: "api",
|
|
2080
|
+
target: "/api/v1/auth/two-factor/generate-backup-codes",
|
|
2081
|
+
confirmText: "Regenerate backup codes? All previous backup codes will stop working immediately.",
|
|
2082
|
+
refreshAfter: true,
|
|
2083
|
+
params: [
|
|
2084
|
+
{ name: "password", label: "Current Password", type: "text", required: true }
|
|
2085
|
+
],
|
|
2086
|
+
resultDialog: {
|
|
2087
|
+
title: "New backup codes generated",
|
|
2088
|
+
description: "Previous backup codes are now invalid. Save these new codes somewhere safe \u2014 they are shown only once.",
|
|
2089
|
+
acknowledge: "I have saved the new codes",
|
|
2090
|
+
fields: [
|
|
2091
|
+
{ path: "backupCodes", label: "Backup Codes", format: "code-list" }
|
|
2092
|
+
]
|
|
2093
|
+
}
|
|
1775
2094
|
}
|
|
1776
2095
|
],
|
|
1777
2096
|
fields: {
|
|
@@ -1803,6 +2122,11 @@ var SysTwoFactor = data.ObjectSchema.create({
|
|
|
1803
2122
|
label: "Backup Codes",
|
|
1804
2123
|
required: false,
|
|
1805
2124
|
description: "JSON-serialized backup recovery codes"
|
|
2125
|
+
}),
|
|
2126
|
+
verified: data.Field.boolean({
|
|
2127
|
+
label: "Verified",
|
|
2128
|
+
defaultValue: true,
|
|
2129
|
+
description: "Whether the enrollment was confirmed with a valid TOTP code (managed by better-auth)"
|
|
1806
2130
|
})
|
|
1807
2131
|
},
|
|
1808
2132
|
indexes: [
|
|
@@ -2062,6 +2386,37 @@ var SysOauthApplication = data.ObjectSchema.create({
|
|
|
2062
2386
|
{ name: "client_id", field: "client_id", defaultFromRow: true, required: true }
|
|
2063
2387
|
]
|
|
2064
2388
|
},
|
|
2389
|
+
{
|
|
2390
|
+
name: "create_oauth_application",
|
|
2391
|
+
label: "Register OAuth Application",
|
|
2392
|
+
icon: "plus-circle",
|
|
2393
|
+
variant: "primary",
|
|
2394
|
+
mode: "create",
|
|
2395
|
+
locations: ["list_toolbar"],
|
|
2396
|
+
type: "api",
|
|
2397
|
+
method: "POST",
|
|
2398
|
+
target: "/api/v1/auth/oauth2/register",
|
|
2399
|
+
refreshAfter: true,
|
|
2400
|
+
params: [
|
|
2401
|
+
{ name: "name", label: "Application Name", type: "text", required: true },
|
|
2402
|
+
{ name: "redirectURLs", label: "Redirect URLs", type: "textarea", required: true, helpText: "One URL per line. Must use https:// in production." },
|
|
2403
|
+
{ name: "type", label: "Application Type", type: "select", required: true, defaultValue: "web", options: [
|
|
2404
|
+
{ label: "Web", value: "web" },
|
|
2405
|
+
{ label: "Native", value: "native" },
|
|
2406
|
+
{ label: "User-agent based", value: "user-agent-based" },
|
|
2407
|
+
{ label: "Public", value: "public" }
|
|
2408
|
+
] }
|
|
2409
|
+
],
|
|
2410
|
+
resultDialog: {
|
|
2411
|
+
title: "OAuth application registered",
|
|
2412
|
+
description: "Save the client_secret now \u2014 it is shown only once and cannot be recovered. You can rotate it later if it leaks.",
|
|
2413
|
+
acknowledge: "I have saved the client secret",
|
|
2414
|
+
fields: [
|
|
2415
|
+
{ path: "client.client_id", label: "Client ID", format: "text" },
|
|
2416
|
+
{ path: "client.client_secret", label: "Client Secret", format: "secret" }
|
|
2417
|
+
]
|
|
2418
|
+
}
|
|
2419
|
+
},
|
|
2065
2420
|
{
|
|
2066
2421
|
name: "rotate_client_secret",
|
|
2067
2422
|
label: "Rotate Client Secret",
|
|
@@ -2073,11 +2428,18 @@ var SysOauthApplication = data.ObjectSchema.create({
|
|
|
2073
2428
|
method: "POST",
|
|
2074
2429
|
target: "/api/v1/auth/oauth2/client/rotate-secret",
|
|
2075
2430
|
confirmText: "Rotate this OAuth client's secret? The previous secret will stop working immediately and any integrations using it will break until they are updated with the new secret. The new secret is shown only once.",
|
|
2076
|
-
successMessage: "Client secret rotated \u2014 copy the new value from the response now.",
|
|
2077
2431
|
refreshAfter: true,
|
|
2078
2432
|
params: [
|
|
2079
2433
|
{ name: "client_id", field: "client_id", defaultFromRow: true, required: true }
|
|
2080
|
-
]
|
|
2434
|
+
],
|
|
2435
|
+
resultDialog: {
|
|
2436
|
+
title: "Client secret rotated",
|
|
2437
|
+
description: "Save the new secret now \u2014 it is shown only once. Update every integration before the previous secret's grace period ends.",
|
|
2438
|
+
acknowledge: "I have updated my integrations",
|
|
2439
|
+
fields: [
|
|
2440
|
+
{ path: "client_secret", label: "New Client Secret", format: "secret" }
|
|
2441
|
+
]
|
|
2442
|
+
}
|
|
2081
2443
|
},
|
|
2082
2444
|
{
|
|
2083
2445
|
name: "delete_oauth_application",
|
|
@@ -2098,6 +2460,20 @@ var SysOauthApplication = data.ObjectSchema.create({
|
|
|
2098
2460
|
}
|
|
2099
2461
|
],
|
|
2100
2462
|
listViews: {
|
|
2463
|
+
mine: {
|
|
2464
|
+
type: "grid",
|
|
2465
|
+
name: "mine",
|
|
2466
|
+
label: "My Applications",
|
|
2467
|
+
data: { provider: "object", object: "sys_oauth_application" },
|
|
2468
|
+
columns: ["name", "client_id", "type", "disabled", "created_at"],
|
|
2469
|
+
// Self-service Account view — scope to the signed-in user's own
|
|
2470
|
+
// registrations so they don't see other developers' apps. Admins
|
|
2471
|
+
// get the unfiltered `active` / `disabled_apps` / `all_apps` views
|
|
2472
|
+
// via the Setup → OAuth Applications nav.
|
|
2473
|
+
filter: [{ field: "user_id", operator: "equals", value: "{current_user_id}" }],
|
|
2474
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
2475
|
+
pagination: { pageSize: 50 }
|
|
2476
|
+
},
|
|
2101
2477
|
active: {
|
|
2102
2478
|
type: "grid",
|
|
2103
2479
|
name: "active",
|