@objectstack/platform-objects 6.5.0 → 6.6.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 +14 -0
- package/dist/apps/index.d.ts +14 -0
- package/dist/identity/index.d.mts +110 -1
- package/dist/identity/index.d.ts +110 -1
- package/dist/identity/index.js +120 -1
- package/dist/identity/index.js.map +1 -1
- package/dist/identity/index.mjs +120 -1
- package/dist/identity/index.mjs.map +1 -1
- package/dist/index.js +255 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +255 -1
- package/dist/index.mjs.map +1 -1
- package/dist/security/index.d.mts +150 -0
- package/dist/security/index.d.ts +150 -0
- package/dist/security/index.js +135 -0
- package/dist/security/index.js.map +1 -1
- package/dist/security/index.mjs +135 -0
- package/dist/security/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -423,6 +423,30 @@ var SysAccount = ObjectSchema.create({
|
|
|
423
423
|
description: "OAuth and authentication provider accounts",
|
|
424
424
|
titleFormat: "{provider_id} - {account_id}",
|
|
425
425
|
compactLayout: ["provider_id", "user_id", "account_id"],
|
|
426
|
+
// Custom actions — sysadmins routinely need to revoke a user's OAuth
|
|
427
|
+
// link (e.g. when an SSO provider is decommissioned or the user
|
|
428
|
+
// requests it). Better-auth exposes `/unlink-account { providerId,
|
|
429
|
+
// accountId }` for this. The form is locked to the row's values so
|
|
430
|
+
// it acts as a one-click confirmation rather than a free-form edit.
|
|
431
|
+
actions: [
|
|
432
|
+
{
|
|
433
|
+
name: "unlink_account",
|
|
434
|
+
label: "Unlink Account",
|
|
435
|
+
icon: "unlink",
|
|
436
|
+
variant: "danger",
|
|
437
|
+
mode: "delete",
|
|
438
|
+
locations: ["list_item", "record_header"],
|
|
439
|
+
type: "api",
|
|
440
|
+
target: "/api/v1/auth/unlink-account",
|
|
441
|
+
confirmText: "Unlink this identity link? The user will no longer be able to sign in with this provider until they re-link it from their account settings.",
|
|
442
|
+
successMessage: "Identity link removed",
|
|
443
|
+
refreshAfter: true,
|
|
444
|
+
params: [
|
|
445
|
+
{ name: "providerId", field: "provider_id", defaultFromRow: true, required: true },
|
|
446
|
+
{ name: "accountId", field: "account_id", defaultFromRow: true, required: true }
|
|
447
|
+
]
|
|
448
|
+
}
|
|
449
|
+
],
|
|
426
450
|
listViews: {
|
|
427
451
|
mine: {
|
|
428
452
|
type: "grid",
|
|
@@ -1977,6 +2001,96 @@ var SysOauthApplication = ObjectSchema.create({
|
|
|
1977
2001
|
displayNameField: "name",
|
|
1978
2002
|
titleFormat: "{name}",
|
|
1979
2003
|
compactLayout: ["name", "client_id", "type", "disabled"],
|
|
2004
|
+
// Custom actions — all OAuth-application mutations are routed through
|
|
2005
|
+
// better-auth's `@better-auth/oauth-provider` endpoints (and a thin
|
|
2006
|
+
// ObjectStack-added auth route for the enable/disable toggle) rather
|
|
2007
|
+
// than the generic data layer, so server-side validation, secret
|
|
2008
|
+
// hashing, and audit hooks all run. The generic `delete` API method
|
|
2009
|
+
// is intentionally dropped from `apiMethods` below so the only delete
|
|
2010
|
+
// path is the better-auth wrapper.
|
|
2011
|
+
//
|
|
2012
|
+
// Upstream gap (better-auth 1.6.11): the stock `/admin/oauth2/update-client`
|
|
2013
|
+
// endpoint's Zod body schema does NOT accept the `disabled` flag, even
|
|
2014
|
+
// though the column exists and the runtime honours it. We bridge the
|
|
2015
|
+
// gap with `POST /api/v1/auth/admin/oauth2/toggle-disabled`, registered
|
|
2016
|
+
// by plugin-auth, which writes through better-auth's own adapter under
|
|
2017
|
+
// the auth namespace (no generic data-layer bypass). When upstream
|
|
2018
|
+
// ships `disabled` support, retarget the enable/disable actions and
|
|
2019
|
+
// delete the bridge route.
|
|
2020
|
+
actions: [
|
|
2021
|
+
{
|
|
2022
|
+
name: "disable_oauth_application",
|
|
2023
|
+
label: "Disable OAuth Application",
|
|
2024
|
+
icon: "pause-circle",
|
|
2025
|
+
variant: "secondary",
|
|
2026
|
+
mode: "custom",
|
|
2027
|
+
locations: ["list_item", "record_header"],
|
|
2028
|
+
type: "api",
|
|
2029
|
+
method: "POST",
|
|
2030
|
+
target: "/api/v1/auth/admin/oauth2/toggle-disabled",
|
|
2031
|
+
confirmText: "Disable this OAuth application? Active access/refresh tokens issued to it will continue to be rejected at the token, authorize, and introspect endpoints. Existing integrations will stop working immediately.",
|
|
2032
|
+
successMessage: "OAuth application disabled",
|
|
2033
|
+
refreshAfter: true,
|
|
2034
|
+
visible: "!record.disabled",
|
|
2035
|
+
bodyExtra: { disabled: true },
|
|
2036
|
+
params: [
|
|
2037
|
+
{ name: "client_id", field: "client_id", defaultFromRow: true, required: true }
|
|
2038
|
+
]
|
|
2039
|
+
},
|
|
2040
|
+
{
|
|
2041
|
+
name: "enable_oauth_application",
|
|
2042
|
+
label: "Enable OAuth Application",
|
|
2043
|
+
icon: "play-circle",
|
|
2044
|
+
variant: "primary",
|
|
2045
|
+
mode: "custom",
|
|
2046
|
+
locations: ["list_item", "record_header"],
|
|
2047
|
+
type: "api",
|
|
2048
|
+
method: "POST",
|
|
2049
|
+
target: "/api/v1/auth/admin/oauth2/toggle-disabled",
|
|
2050
|
+
confirmText: "Re-enable this OAuth application? Token issuance, authorization, and introspection will resume immediately.",
|
|
2051
|
+
successMessage: "OAuth application enabled",
|
|
2052
|
+
refreshAfter: true,
|
|
2053
|
+
visible: "record.disabled",
|
|
2054
|
+
bodyExtra: { disabled: false },
|
|
2055
|
+
params: [
|
|
2056
|
+
{ name: "client_id", field: "client_id", defaultFromRow: true, required: true }
|
|
2057
|
+
]
|
|
2058
|
+
},
|
|
2059
|
+
{
|
|
2060
|
+
name: "rotate_client_secret",
|
|
2061
|
+
label: "Rotate Client Secret",
|
|
2062
|
+
icon: "refresh-cw",
|
|
2063
|
+
variant: "secondary",
|
|
2064
|
+
mode: "custom",
|
|
2065
|
+
locations: ["list_item", "record_header"],
|
|
2066
|
+
type: "api",
|
|
2067
|
+
method: "POST",
|
|
2068
|
+
target: "/api/v1/auth/oauth2/client/rotate-secret",
|
|
2069
|
+
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.",
|
|
2070
|
+
successMessage: "Client secret rotated \u2014 copy the new value from the response now.",
|
|
2071
|
+
refreshAfter: true,
|
|
2072
|
+
params: [
|
|
2073
|
+
{ name: "client_id", field: "client_id", defaultFromRow: true, required: true }
|
|
2074
|
+
]
|
|
2075
|
+
},
|
|
2076
|
+
{
|
|
2077
|
+
name: "delete_oauth_application",
|
|
2078
|
+
label: "Delete OAuth Application",
|
|
2079
|
+
icon: "trash-2",
|
|
2080
|
+
variant: "danger",
|
|
2081
|
+
mode: "delete",
|
|
2082
|
+
locations: ["list_item", "record_header"],
|
|
2083
|
+
type: "api",
|
|
2084
|
+
method: "POST",
|
|
2085
|
+
target: "/api/v1/auth/oauth2/delete-client",
|
|
2086
|
+
confirmText: "Permanently delete this OAuth application? All issued tokens and consents will be invalidated and integrations using this client_id will stop working immediately. This cannot be undone.",
|
|
2087
|
+
successMessage: "OAuth application deleted",
|
|
2088
|
+
refreshAfter: true,
|
|
2089
|
+
params: [
|
|
2090
|
+
{ name: "client_id", field: "client_id", defaultFromRow: true, required: true }
|
|
2091
|
+
]
|
|
2092
|
+
}
|
|
2093
|
+
],
|
|
1980
2094
|
listViews: {
|
|
1981
2095
|
active: {
|
|
1982
2096
|
type: "grid",
|
|
@@ -2208,7 +2322,12 @@ var SysOauthApplication = ObjectSchema.create({
|
|
|
2208
2322
|
trackHistory: true,
|
|
2209
2323
|
searchable: true,
|
|
2210
2324
|
apiEnabled: true,
|
|
2211
|
-
|
|
2325
|
+
// All mutations (create/update/delete) must go through better-auth's
|
|
2326
|
+
// oauth-provider endpoints under /api/v1/auth/{admin/,}oauth2/* — the
|
|
2327
|
+
// generic data layer is read-only for this object so sysadmins cannot
|
|
2328
|
+
// bypass server-side OAuth validation. The Delete row action above is
|
|
2329
|
+
// wired to /api/v1/auth/oauth2/delete-client.
|
|
2330
|
+
apiMethods: ["get", "list"],
|
|
2212
2331
|
trash: false,
|
|
2213
2332
|
mru: false
|
|
2214
2333
|
}
|
|
@@ -2491,6 +2610,83 @@ var SysRole = ObjectSchema.create({
|
|
|
2491
2610
|
displayNameField: "label",
|
|
2492
2611
|
titleFormat: "{label}",
|
|
2493
2612
|
compactLayout: ["label", "name", "active", "is_default"],
|
|
2613
|
+
// Custom actions — system roles drive RBAC and are edited rarely but
|
|
2614
|
+
// require the four high-frequency sysadmin affordances every IdP
|
|
2615
|
+
// (Salesforce, ServiceNow, Okta) ships: activate/deactivate (lifecycle
|
|
2616
|
+
// without losing assignments), mark default (auto-assign to new users),
|
|
2617
|
+
// and clone (template for new roles). All operations hit the generic
|
|
2618
|
+
// data CRUD endpoint exposed by `apiEnabled` — no custom server route
|
|
2619
|
+
// required because `managedBy: 'config'` allows direct mutation.
|
|
2620
|
+
actions: [
|
|
2621
|
+
{
|
|
2622
|
+
name: "activate_role",
|
|
2623
|
+
label: "Activate Role",
|
|
2624
|
+
icon: "circle-check",
|
|
2625
|
+
variant: "secondary",
|
|
2626
|
+
mode: "custom",
|
|
2627
|
+
locations: ["list_item", "record_header"],
|
|
2628
|
+
type: "api",
|
|
2629
|
+
method: "PATCH",
|
|
2630
|
+
target: "/api/v1/data/sys_role/{id}",
|
|
2631
|
+
bodyExtra: { active: true },
|
|
2632
|
+
successMessage: "Role activated",
|
|
2633
|
+
refreshAfter: true
|
|
2634
|
+
},
|
|
2635
|
+
{
|
|
2636
|
+
name: "deactivate_role",
|
|
2637
|
+
label: "Deactivate Role",
|
|
2638
|
+
icon: "circle-off",
|
|
2639
|
+
variant: "danger",
|
|
2640
|
+
mode: "custom",
|
|
2641
|
+
locations: ["list_item", "record_header"],
|
|
2642
|
+
type: "api",
|
|
2643
|
+
method: "PATCH",
|
|
2644
|
+
target: "/api/v1/data/sys_role/{id}",
|
|
2645
|
+
bodyExtra: { active: false },
|
|
2646
|
+
confirmText: "Deactivate this role? Users with the role keep their assignment but the role stops granting permissions until re-activated.",
|
|
2647
|
+
successMessage: "Role deactivated",
|
|
2648
|
+
refreshAfter: true
|
|
2649
|
+
},
|
|
2650
|
+
{
|
|
2651
|
+
name: "set_default_role",
|
|
2652
|
+
label: "Set as Default",
|
|
2653
|
+
icon: "star",
|
|
2654
|
+
variant: "secondary",
|
|
2655
|
+
mode: "custom",
|
|
2656
|
+
locations: ["list_item", "record_header"],
|
|
2657
|
+
type: "api",
|
|
2658
|
+
method: "PATCH",
|
|
2659
|
+
target: "/api/v1/data/sys_role/{id}",
|
|
2660
|
+
bodyExtra: { is_default: true },
|
|
2661
|
+
confirmText: "Make this the default role for new users? Existing users are unaffected.",
|
|
2662
|
+
successMessage: "Default role updated",
|
|
2663
|
+
refreshAfter: true
|
|
2664
|
+
},
|
|
2665
|
+
{
|
|
2666
|
+
// Clone — POST a new sys_role row pre-filled from the source. The
|
|
2667
|
+
// dialog asks only for the new API name / label so the operator
|
|
2668
|
+
// can rename atomically; permissions JSON is copied wholesale via
|
|
2669
|
+
// defaultFromRow.
|
|
2670
|
+
name: "clone_role",
|
|
2671
|
+
label: "Clone Role",
|
|
2672
|
+
icon: "copy",
|
|
2673
|
+
variant: "secondary",
|
|
2674
|
+
mode: "custom",
|
|
2675
|
+
locations: ["list_item", "record_header"],
|
|
2676
|
+
type: "api",
|
|
2677
|
+
method: "POST",
|
|
2678
|
+
target: "/api/v1/data/sys_role",
|
|
2679
|
+
bodyExtra: { is_default: false, active: true },
|
|
2680
|
+
successMessage: "Role cloned",
|
|
2681
|
+
refreshAfter: true,
|
|
2682
|
+
params: [
|
|
2683
|
+
{ name: "label", label: "New Display Name", type: "text", required: true },
|
|
2684
|
+
{ name: "name", label: "New API Name", type: "text", required: true, helpText: "Unique snake_case machine name" },
|
|
2685
|
+
{ field: "description", defaultFromRow: true },
|
|
2686
|
+
{ field: "permissions", defaultFromRow: true }
|
|
2687
|
+
]
|
|
2688
|
+
}
|
|
2689
|
+
],
|
|
2494
2690
|
listViews: {
|
|
2495
2691
|
active: {
|
|
2496
2692
|
type: "grid",
|
|
@@ -2617,6 +2813,64 @@ var SysPermissionSet = ObjectSchema.create({
|
|
|
2617
2813
|
displayNameField: "label",
|
|
2618
2814
|
titleFormat: "{label}",
|
|
2619
2815
|
compactLayout: ["label", "name", "active"],
|
|
2816
|
+
// Custom actions — permission sets are templates assigned to roles or
|
|
2817
|
+
// users (via sys_role_permission_set / sys_user_permission_set). The
|
|
2818
|
+
// sysadmin operations that don't live on the parent-detail tabs are
|
|
2819
|
+
// lifecycle (activate/deactivate without losing assignments) and
|
|
2820
|
+
// clone (build a new permset by tweaking an existing one). Both hit
|
|
2821
|
+
// the generic data CRUD endpoint — managedBy: 'config' permits it.
|
|
2822
|
+
actions: [
|
|
2823
|
+
{
|
|
2824
|
+
name: "activate_permission_set",
|
|
2825
|
+
label: "Activate",
|
|
2826
|
+
icon: "circle-check",
|
|
2827
|
+
variant: "secondary",
|
|
2828
|
+
mode: "custom",
|
|
2829
|
+
locations: ["list_item", "record_header"],
|
|
2830
|
+
type: "api",
|
|
2831
|
+
method: "PATCH",
|
|
2832
|
+
target: "/api/v1/data/sys_permission_set/{id}",
|
|
2833
|
+
bodyExtra: { active: true },
|
|
2834
|
+
successMessage: "Permission set activated",
|
|
2835
|
+
refreshAfter: true
|
|
2836
|
+
},
|
|
2837
|
+
{
|
|
2838
|
+
name: "deactivate_permission_set",
|
|
2839
|
+
label: "Deactivate",
|
|
2840
|
+
icon: "circle-off",
|
|
2841
|
+
variant: "danger",
|
|
2842
|
+
mode: "custom",
|
|
2843
|
+
locations: ["list_item", "record_header"],
|
|
2844
|
+
type: "api",
|
|
2845
|
+
method: "PATCH",
|
|
2846
|
+
target: "/api/v1/data/sys_permission_set/{id}",
|
|
2847
|
+
bodyExtra: { active: false },
|
|
2848
|
+
confirmText: "Deactivate this permission set? Existing assignments stay in place but stop granting access until re-activated.",
|
|
2849
|
+
successMessage: "Permission set deactivated",
|
|
2850
|
+
refreshAfter: true
|
|
2851
|
+
},
|
|
2852
|
+
{
|
|
2853
|
+
name: "clone_permission_set",
|
|
2854
|
+
label: "Clone",
|
|
2855
|
+
icon: "copy",
|
|
2856
|
+
variant: "secondary",
|
|
2857
|
+
mode: "custom",
|
|
2858
|
+
locations: ["list_item", "record_header"],
|
|
2859
|
+
type: "api",
|
|
2860
|
+
method: "POST",
|
|
2861
|
+
target: "/api/v1/data/sys_permission_set",
|
|
2862
|
+
bodyExtra: { active: true },
|
|
2863
|
+
successMessage: "Permission set cloned",
|
|
2864
|
+
refreshAfter: true,
|
|
2865
|
+
params: [
|
|
2866
|
+
{ name: "label", label: "New Display Name", type: "text", required: true },
|
|
2867
|
+
{ name: "name", label: "New API Name", type: "text", required: true, helpText: "Unique snake_case machine name" },
|
|
2868
|
+
{ field: "description", defaultFromRow: true },
|
|
2869
|
+
{ field: "object_permissions", defaultFromRow: true },
|
|
2870
|
+
{ field: "field_permissions", defaultFromRow: true }
|
|
2871
|
+
]
|
|
2872
|
+
}
|
|
2873
|
+
],
|
|
2620
2874
|
listViews: {
|
|
2621
2875
|
active: {
|
|
2622
2876
|
type: "grid",
|