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