@objectstack/platform-objects 6.5.1 → 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.
@@ -87,6 +87,9 @@ declare const SystemOverviewDashboard: {
87
87
  type?: "table" | "bar" | "line" | "pie" | "area" | "scatter" | "horizontal-bar" | "column" | "grouped-bar" | "stacked-bar" | "bi-polar-bar" | "stacked-area" | "step-line" | "spline" | "donut" | "funnel" | "pyramid" | "bubble" | "treemap" | "sunburst" | "sankey" | "word-cloud" | "gauge" | "solid-gauge" | "metric" | "kpi" | "bullet" | "choropleth" | "bubble-map" | "gl-map" | "heatmap" | "radar" | "waterfall" | "box-plot" | "violin" | "candlestick" | "stock" | "pivot" | undefined;
88
88
  color?: string | undefined;
89
89
  stack?: string | undefined;
90
+ variant?: "primary" | "comparison" | undefined;
91
+ dashArray?: string | undefined;
92
+ opacity?: number | undefined;
90
93
  }[] | undefined;
91
94
  colors?: string[] | undefined;
92
95
  height?: number | undefined;
@@ -119,7 +122,11 @@ declare const SystemOverviewDashboard: {
119
122
  actionIcon?: string | undefined;
120
123
  object?: string | undefined;
121
124
  filter?: _objectstack_spec_data.FilterCondition | undefined;
125
+ compareTo?: "previousPeriod" | "previousYear" | {
126
+ offset: string;
127
+ } | undefined;
122
128
  categoryField?: string | undefined;
129
+ categoryGranularity?: "day" | "week" | "month" | "quarter" | "year" | undefined;
123
130
  valueField?: string | undefined;
124
131
  measures?: {
125
132
  valueField: string;
@@ -270,6 +277,9 @@ declare const SecurityOverviewDashboard: {
270
277
  type?: "table" | "bar" | "line" | "pie" | "area" | "scatter" | "horizontal-bar" | "column" | "grouped-bar" | "stacked-bar" | "bi-polar-bar" | "stacked-area" | "step-line" | "spline" | "donut" | "funnel" | "pyramid" | "bubble" | "treemap" | "sunburst" | "sankey" | "word-cloud" | "gauge" | "solid-gauge" | "metric" | "kpi" | "bullet" | "choropleth" | "bubble-map" | "gl-map" | "heatmap" | "radar" | "waterfall" | "box-plot" | "violin" | "candlestick" | "stock" | "pivot" | undefined;
271
278
  color?: string | undefined;
272
279
  stack?: string | undefined;
280
+ variant?: "primary" | "comparison" | undefined;
281
+ dashArray?: string | undefined;
282
+ opacity?: number | undefined;
273
283
  }[] | undefined;
274
284
  colors?: string[] | undefined;
275
285
  height?: number | undefined;
@@ -302,7 +312,11 @@ declare const SecurityOverviewDashboard: {
302
312
  actionIcon?: string | undefined;
303
313
  object?: string | undefined;
304
314
  filter?: _objectstack_spec_data.FilterCondition | undefined;
315
+ compareTo?: "previousPeriod" | "previousYear" | {
316
+ offset: string;
317
+ } | undefined;
305
318
  categoryField?: string | undefined;
319
+ categoryGranularity?: "day" | "week" | "month" | "quarter" | "year" | undefined;
306
320
  valueField?: string | undefined;
307
321
  measures?: {
308
322
  valueField: string;
@@ -87,6 +87,9 @@ declare const SystemOverviewDashboard: {
87
87
  type?: "table" | "bar" | "line" | "pie" | "area" | "scatter" | "horizontal-bar" | "column" | "grouped-bar" | "stacked-bar" | "bi-polar-bar" | "stacked-area" | "step-line" | "spline" | "donut" | "funnel" | "pyramid" | "bubble" | "treemap" | "sunburst" | "sankey" | "word-cloud" | "gauge" | "solid-gauge" | "metric" | "kpi" | "bullet" | "choropleth" | "bubble-map" | "gl-map" | "heatmap" | "radar" | "waterfall" | "box-plot" | "violin" | "candlestick" | "stock" | "pivot" | undefined;
88
88
  color?: string | undefined;
89
89
  stack?: string | undefined;
90
+ variant?: "primary" | "comparison" | undefined;
91
+ dashArray?: string | undefined;
92
+ opacity?: number | undefined;
90
93
  }[] | undefined;
91
94
  colors?: string[] | undefined;
92
95
  height?: number | undefined;
@@ -119,7 +122,11 @@ declare const SystemOverviewDashboard: {
119
122
  actionIcon?: string | undefined;
120
123
  object?: string | undefined;
121
124
  filter?: _objectstack_spec_data.FilterCondition | undefined;
125
+ compareTo?: "previousPeriod" | "previousYear" | {
126
+ offset: string;
127
+ } | undefined;
122
128
  categoryField?: string | undefined;
129
+ categoryGranularity?: "day" | "week" | "month" | "quarter" | "year" | undefined;
123
130
  valueField?: string | undefined;
124
131
  measures?: {
125
132
  valueField: string;
@@ -270,6 +277,9 @@ declare const SecurityOverviewDashboard: {
270
277
  type?: "table" | "bar" | "line" | "pie" | "area" | "scatter" | "horizontal-bar" | "column" | "grouped-bar" | "stacked-bar" | "bi-polar-bar" | "stacked-area" | "step-line" | "spline" | "donut" | "funnel" | "pyramid" | "bubble" | "treemap" | "sunburst" | "sankey" | "word-cloud" | "gauge" | "solid-gauge" | "metric" | "kpi" | "bullet" | "choropleth" | "bubble-map" | "gl-map" | "heatmap" | "radar" | "waterfall" | "box-plot" | "violin" | "candlestick" | "stock" | "pivot" | undefined;
271
278
  color?: string | undefined;
272
279
  stack?: string | undefined;
280
+ variant?: "primary" | "comparison" | undefined;
281
+ dashArray?: string | undefined;
282
+ opacity?: number | undefined;
273
283
  }[] | undefined;
274
284
  colors?: string[] | undefined;
275
285
  height?: number | undefined;
@@ -302,7 +312,11 @@ declare const SecurityOverviewDashboard: {
302
312
  actionIcon?: string | undefined;
303
313
  object?: string | undefined;
304
314
  filter?: _objectstack_spec_data.FilterCondition | undefined;
315
+ compareTo?: "previousPeriod" | "previousYear" | {
316
+ offset: string;
317
+ } | undefined;
305
318
  categoryField?: string | undefined;
319
+ categoryGranularity?: "day" | "week" | "month" | "quarter" | "year" | undefined;
306
320
  valueField?: string | undefined;
307
321
  measures?: {
308
322
  valueField: string;
@@ -6384,6 +6384,30 @@ declare const SysAccount: Omit<{
6384
6384
  readonly description: "OAuth and authentication provider accounts";
6385
6385
  readonly titleFormat: "{provider_id} - {account_id}";
6386
6386
  readonly compactLayout: ["provider_id", "user_id", "account_id"];
6387
+ readonly actions: [{
6388
+ readonly name: "unlink_account";
6389
+ readonly label: "Unlink Account";
6390
+ readonly icon: "unlink";
6391
+ readonly variant: "danger";
6392
+ readonly mode: "delete";
6393
+ readonly locations: ["list_item", "record_header"];
6394
+ readonly type: "api";
6395
+ readonly target: "/api/v1/auth/unlink-account";
6396
+ readonly 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.";
6397
+ readonly successMessage: "Identity link removed";
6398
+ readonly refreshAfter: true;
6399
+ readonly params: [{
6400
+ readonly name: "providerId";
6401
+ readonly field: "provider_id";
6402
+ readonly defaultFromRow: true;
6403
+ readonly required: true;
6404
+ }, {
6405
+ readonly name: "accountId";
6406
+ readonly field: "account_id";
6407
+ readonly defaultFromRow: true;
6408
+ readonly required: true;
6409
+ }];
6410
+ }];
6387
6411
  readonly listViews: {
6388
6412
  readonly mine: {
6389
6413
  readonly type: "grid";
@@ -34977,6 +35001,91 @@ declare const SysOauthApplication: Omit<{
34977
35001
  readonly displayNameField: "name";
34978
35002
  readonly titleFormat: "{name}";
34979
35003
  readonly compactLayout: ["name", "client_id", "type", "disabled"];
35004
+ readonly actions: [{
35005
+ readonly name: "disable_oauth_application";
35006
+ readonly label: "Disable OAuth Application";
35007
+ readonly icon: "pause-circle";
35008
+ readonly variant: "secondary";
35009
+ readonly mode: "custom";
35010
+ readonly locations: ["list_item", "record_header"];
35011
+ readonly type: "api";
35012
+ readonly method: "POST";
35013
+ readonly target: "/api/v1/auth/admin/oauth2/toggle-disabled";
35014
+ readonly 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.";
35015
+ readonly successMessage: "OAuth application disabled";
35016
+ readonly refreshAfter: true;
35017
+ readonly visible: "!record.disabled";
35018
+ readonly bodyExtra: {
35019
+ readonly disabled: true;
35020
+ };
35021
+ readonly params: [{
35022
+ readonly name: "client_id";
35023
+ readonly field: "client_id";
35024
+ readonly defaultFromRow: true;
35025
+ readonly required: true;
35026
+ }];
35027
+ }, {
35028
+ readonly name: "enable_oauth_application";
35029
+ readonly label: "Enable OAuth Application";
35030
+ readonly icon: "play-circle";
35031
+ readonly variant: "primary";
35032
+ readonly mode: "custom";
35033
+ readonly locations: ["list_item", "record_header"];
35034
+ readonly type: "api";
35035
+ readonly method: "POST";
35036
+ readonly target: "/api/v1/auth/admin/oauth2/toggle-disabled";
35037
+ readonly confirmText: "Re-enable this OAuth application? Token issuance, authorization, and introspection will resume immediately.";
35038
+ readonly successMessage: "OAuth application enabled";
35039
+ readonly refreshAfter: true;
35040
+ readonly visible: "record.disabled";
35041
+ readonly bodyExtra: {
35042
+ readonly disabled: false;
35043
+ };
35044
+ readonly params: [{
35045
+ readonly name: "client_id";
35046
+ readonly field: "client_id";
35047
+ readonly defaultFromRow: true;
35048
+ readonly required: true;
35049
+ }];
35050
+ }, {
35051
+ readonly name: "rotate_client_secret";
35052
+ readonly label: "Rotate Client Secret";
35053
+ readonly icon: "refresh-cw";
35054
+ readonly variant: "secondary";
35055
+ readonly mode: "custom";
35056
+ readonly locations: ["list_item", "record_header"];
35057
+ readonly type: "api";
35058
+ readonly method: "POST";
35059
+ readonly target: "/api/v1/auth/oauth2/client/rotate-secret";
35060
+ readonly 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.";
35061
+ readonly successMessage: "Client secret rotated — copy the new value from the response now.";
35062
+ readonly refreshAfter: true;
35063
+ readonly params: [{
35064
+ readonly name: "client_id";
35065
+ readonly field: "client_id";
35066
+ readonly defaultFromRow: true;
35067
+ readonly required: true;
35068
+ }];
35069
+ }, {
35070
+ readonly name: "delete_oauth_application";
35071
+ readonly label: "Delete OAuth Application";
35072
+ readonly icon: "trash-2";
35073
+ readonly variant: "danger";
35074
+ readonly mode: "delete";
35075
+ readonly locations: ["list_item", "record_header"];
35076
+ readonly type: "api";
35077
+ readonly method: "POST";
35078
+ readonly target: "/api/v1/auth/oauth2/delete-client";
35079
+ readonly 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.";
35080
+ readonly successMessage: "OAuth application deleted";
35081
+ readonly refreshAfter: true;
35082
+ readonly params: [{
35083
+ readonly name: "client_id";
35084
+ readonly field: "client_id";
35085
+ readonly defaultFromRow: true;
35086
+ readonly required: true;
35087
+ }];
35088
+ }];
34980
35089
  readonly listViews: {
34981
35090
  readonly active: {
34982
35091
  readonly type: "grid";
@@ -40304,7 +40413,7 @@ declare const SysOauthApplication: Omit<{
40304
40413
  readonly trackHistory: true;
40305
40414
  readonly searchable: true;
40306
40415
  readonly apiEnabled: true;
40307
- readonly apiMethods: ["get", "list", "delete"];
40416
+ readonly apiMethods: ["get", "list"];
40308
40417
  readonly trash: false;
40309
40418
  readonly mru: false;
40310
40419
  };
@@ -6384,6 +6384,30 @@ declare const SysAccount: Omit<{
6384
6384
  readonly description: "OAuth and authentication provider accounts";
6385
6385
  readonly titleFormat: "{provider_id} - {account_id}";
6386
6386
  readonly compactLayout: ["provider_id", "user_id", "account_id"];
6387
+ readonly actions: [{
6388
+ readonly name: "unlink_account";
6389
+ readonly label: "Unlink Account";
6390
+ readonly icon: "unlink";
6391
+ readonly variant: "danger";
6392
+ readonly mode: "delete";
6393
+ readonly locations: ["list_item", "record_header"];
6394
+ readonly type: "api";
6395
+ readonly target: "/api/v1/auth/unlink-account";
6396
+ readonly 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.";
6397
+ readonly successMessage: "Identity link removed";
6398
+ readonly refreshAfter: true;
6399
+ readonly params: [{
6400
+ readonly name: "providerId";
6401
+ readonly field: "provider_id";
6402
+ readonly defaultFromRow: true;
6403
+ readonly required: true;
6404
+ }, {
6405
+ readonly name: "accountId";
6406
+ readonly field: "account_id";
6407
+ readonly defaultFromRow: true;
6408
+ readonly required: true;
6409
+ }];
6410
+ }];
6387
6411
  readonly listViews: {
6388
6412
  readonly mine: {
6389
6413
  readonly type: "grid";
@@ -34977,6 +35001,91 @@ declare const SysOauthApplication: Omit<{
34977
35001
  readonly displayNameField: "name";
34978
35002
  readonly titleFormat: "{name}";
34979
35003
  readonly compactLayout: ["name", "client_id", "type", "disabled"];
35004
+ readonly actions: [{
35005
+ readonly name: "disable_oauth_application";
35006
+ readonly label: "Disable OAuth Application";
35007
+ readonly icon: "pause-circle";
35008
+ readonly variant: "secondary";
35009
+ readonly mode: "custom";
35010
+ readonly locations: ["list_item", "record_header"];
35011
+ readonly type: "api";
35012
+ readonly method: "POST";
35013
+ readonly target: "/api/v1/auth/admin/oauth2/toggle-disabled";
35014
+ readonly 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.";
35015
+ readonly successMessage: "OAuth application disabled";
35016
+ readonly refreshAfter: true;
35017
+ readonly visible: "!record.disabled";
35018
+ readonly bodyExtra: {
35019
+ readonly disabled: true;
35020
+ };
35021
+ readonly params: [{
35022
+ readonly name: "client_id";
35023
+ readonly field: "client_id";
35024
+ readonly defaultFromRow: true;
35025
+ readonly required: true;
35026
+ }];
35027
+ }, {
35028
+ readonly name: "enable_oauth_application";
35029
+ readonly label: "Enable OAuth Application";
35030
+ readonly icon: "play-circle";
35031
+ readonly variant: "primary";
35032
+ readonly mode: "custom";
35033
+ readonly locations: ["list_item", "record_header"];
35034
+ readonly type: "api";
35035
+ readonly method: "POST";
35036
+ readonly target: "/api/v1/auth/admin/oauth2/toggle-disabled";
35037
+ readonly confirmText: "Re-enable this OAuth application? Token issuance, authorization, and introspection will resume immediately.";
35038
+ readonly successMessage: "OAuth application enabled";
35039
+ readonly refreshAfter: true;
35040
+ readonly visible: "record.disabled";
35041
+ readonly bodyExtra: {
35042
+ readonly disabled: false;
35043
+ };
35044
+ readonly params: [{
35045
+ readonly name: "client_id";
35046
+ readonly field: "client_id";
35047
+ readonly defaultFromRow: true;
35048
+ readonly required: true;
35049
+ }];
35050
+ }, {
35051
+ readonly name: "rotate_client_secret";
35052
+ readonly label: "Rotate Client Secret";
35053
+ readonly icon: "refresh-cw";
35054
+ readonly variant: "secondary";
35055
+ readonly mode: "custom";
35056
+ readonly locations: ["list_item", "record_header"];
35057
+ readonly type: "api";
35058
+ readonly method: "POST";
35059
+ readonly target: "/api/v1/auth/oauth2/client/rotate-secret";
35060
+ readonly 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.";
35061
+ readonly successMessage: "Client secret rotated — copy the new value from the response now.";
35062
+ readonly refreshAfter: true;
35063
+ readonly params: [{
35064
+ readonly name: "client_id";
35065
+ readonly field: "client_id";
35066
+ readonly defaultFromRow: true;
35067
+ readonly required: true;
35068
+ }];
35069
+ }, {
35070
+ readonly name: "delete_oauth_application";
35071
+ readonly label: "Delete OAuth Application";
35072
+ readonly icon: "trash-2";
35073
+ readonly variant: "danger";
35074
+ readonly mode: "delete";
35075
+ readonly locations: ["list_item", "record_header"];
35076
+ readonly type: "api";
35077
+ readonly method: "POST";
35078
+ readonly target: "/api/v1/auth/oauth2/delete-client";
35079
+ readonly 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.";
35080
+ readonly successMessage: "OAuth application deleted";
35081
+ readonly refreshAfter: true;
35082
+ readonly params: [{
35083
+ readonly name: "client_id";
35084
+ readonly field: "client_id";
35085
+ readonly defaultFromRow: true;
35086
+ readonly required: true;
35087
+ }];
35088
+ }];
34980
35089
  readonly listViews: {
34981
35090
  readonly active: {
34982
35091
  readonly type: "grid";
@@ -40304,7 +40413,7 @@ declare const SysOauthApplication: Omit<{
40304
40413
  readonly trackHistory: true;
40305
40414
  readonly searchable: true;
40306
40415
  readonly apiEnabled: true;
40307
- readonly apiMethods: ["get", "list", "delete"];
40416
+ readonly apiMethods: ["get", "list"];
40308
40417
  readonly trash: false;
40309
40418
  readonly mru: false;
40310
40419
  };
@@ -423,6 +423,30 @@ var SysAccount = data.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 = data.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 = data.ObjectSchema.create({
2208
2322
  trackHistory: true,
2209
2323
  searchable: true,
2210
2324
  apiEnabled: true,
2211
- apiMethods: ["get", "list", "delete"],
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
  }