@objectstack/platform-objects 11.0.0 → 11.2.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/index.js CHANGED
@@ -20,6 +20,8 @@ var SysUser = data.ObjectSchema.create({
20
20
  },
21
21
  description: "User accounts for authentication",
22
22
  displayNameField: "name",
23
+ nameField: "name",
24
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
23
25
  titleFormat: "{name}",
24
26
  compactLayout: ["name", "email", "email_verified"],
25
27
  // Custom actions — generic CRUD is suppressed because user accounts are
@@ -424,6 +426,25 @@ var SysUser = data.ObjectSchema.create({
424
426
  group: "Admin",
425
427
  description: "When set and in the future, sign-in is rejected (brute-force lockout). Auto-clears past this time; an admin can clear it early via Unlock."
426
428
  }),
429
+ // ADR-0069 D1 — last password change; drives password-expiry enforcement.
430
+ // Stamped on sign-up / change-password / reset-password. Null = never
431
+ // expires (until the user next changes their password).
432
+ password_changed_at: data.Field.datetime({
433
+ label: "Password Changed At",
434
+ required: false,
435
+ readonly: true,
436
+ group: "Admin",
437
+ description: "Timestamp of the last password change. Backs password_expiry_days; system-managed."
438
+ }),
439
+ // ADR-0069 D3 — when enforced MFA first applied to this user; starts the
440
+ // grace clock. Stamped lazily at session validation; system-managed.
441
+ mfa_required_at: data.Field.datetime({
442
+ label: "MFA Required At",
443
+ required: false,
444
+ readonly: true,
445
+ group: "Admin",
446
+ description: "When enforced MFA first applied to this user (grace-period clock). Backs mfa_required; system-managed."
447
+ }),
427
448
  ai_access: data.Field.boolean({
428
449
  label: "AI Access",
429
450
  defaultValue: false,
@@ -525,6 +546,8 @@ var SysSession = data.ObjectSchema.create({
525
546
  },
526
547
  description: "Active user sessions",
527
548
  displayNameField: "user_id",
549
+ nameField: "user_id",
550
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
528
551
  titleFormat: "Session \u2014 {user_id}",
529
552
  compactLayout: ["user_id", "ip_address", "expires_at"],
530
553
  // Custom actions — sessions are managed by better-auth (generic CRUD
@@ -596,6 +619,29 @@ var SysSession = data.ObjectSchema.create({
596
619
  required: true,
597
620
  group: "Session"
598
621
  }),
622
+ // ── ADR-0069 D4 — session controls (idle / absolute / revoke) ──
623
+ last_activity_at: data.Field.datetime({
624
+ label: "Last Activity At",
625
+ required: false,
626
+ readonly: true,
627
+ group: "Session",
628
+ description: "Timestamp of the last request on this session; drives idle-timeout. System-managed."
629
+ }),
630
+ revoked_at: data.Field.datetime({
631
+ label: "Revoked At",
632
+ required: false,
633
+ readonly: true,
634
+ group: "Session",
635
+ description: "When set, this session was revoked (idle / absolute-max / concurrent-cap / admin). System-managed."
636
+ }),
637
+ revoke_reason: data.Field.text({
638
+ label: "Revoke Reason",
639
+ required: false,
640
+ maxLength: 64,
641
+ readonly: true,
642
+ group: "Session",
643
+ description: "Why the session was revoked (idle_timeout, absolute_max, concurrent_cap, \u2026)."
644
+ }),
599
645
  // ── Active context (multi-org/team) ──────────────────────────
600
646
  active_organization_id: data.Field.lookup("sys_organization", {
601
647
  label: "Active Organization",
@@ -948,6 +994,8 @@ var SysOrganization = data.ObjectSchema.create({
948
994
  },
949
995
  description: "Organizations for multi-tenant grouping",
950
996
  displayNameField: "name",
997
+ nameField: "name",
998
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
951
999
  titleFormat: "{name}",
952
1000
  compactLayout: ["name", "slug"],
953
1001
  // Custom actions — generic CRUD is suppressed (better-auth-managed),
@@ -1116,6 +1164,17 @@ var SysOrganization = data.ObjectSchema.create({
1116
1164
  description: "JSON-serialized organization metadata",
1117
1165
  group: "Configuration"
1118
1166
  }),
1167
+ // ADR-0069 D3 — per-org MFA tightening above the global floor. When true,
1168
+ // members of this org must enrol TOTP to access data (enforced at the
1169
+ // session-validation gate). An org can only tighten, never loosen, the
1170
+ // global `mfa_required` setting.
1171
+ require_mfa: data.Field.boolean({
1172
+ label: "Require Multi-Factor Auth",
1173
+ required: false,
1174
+ defaultValue: false,
1175
+ group: "Configuration",
1176
+ description: "When true, every member of this organization must enroll an authenticator app to access data."
1177
+ }),
1119
1178
  // ── System ───────────────────────────────────────────────────
1120
1179
  id: data.Field.text({
1121
1180
  label: "Organization ID",
@@ -1559,6 +1618,8 @@ var SysTeam = data.ObjectSchema.create({
1559
1618
  },
1560
1619
  description: "Teams within organizations for fine-grained grouping",
1561
1620
  displayNameField: "name",
1621
+ nameField: "name",
1622
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
1562
1623
  titleFormat: "{name}",
1563
1624
  compactLayout: ["name", "organization_id"],
1564
1625
  // Custom actions calling better-auth's team endpoints. Generic CRUD is
@@ -1805,6 +1866,8 @@ var SysBusinessUnit = data.ObjectSchema.create({
1805
1866
  managedBy: "platform",
1806
1867
  description: "Canonical Business Unit tree \u2014 hierarchical org/data-partition node (company / division / department / region / office). ADR-0057 D2.",
1807
1868
  displayNameField: "name",
1869
+ nameField: "name",
1870
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
1808
1871
  titleFormat: "{name}",
1809
1872
  compactLayout: ["name", "kind", "parent_business_unit_id", "manager_user_id"],
1810
1873
  listViews: {
@@ -2078,6 +2141,8 @@ var SysApiKey = data.ObjectSchema.create({
2078
2141
  },
2079
2142
  description: "API keys for programmatic access",
2080
2143
  displayNameField: "name",
2144
+ nameField: "name",
2145
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
2081
2146
  titleFormat: "{name}",
2082
2147
  compactLayout: ["name", "prefix", "user_id", "expires_at", "revoked"],
2083
2148
  // Custom actions — sys_api_key is managed-by 'better-auth' but the
@@ -2421,6 +2486,8 @@ var SysDeviceCode = data.ObjectSchema.create({
2421
2486
  docsUrl: "https://docs.objectstack.ai/adr/0010-metadata-protection"
2422
2487
  },
2423
2488
  description: "OAuth 2.0 Device Authorization Grant (RFC 8628) pending requests",
2489
+ nameField: "user_code",
2490
+ // [ADR-0079] canonical primary-title pointer (single-field titleFormat)
2424
2491
  titleFormat: "{user_code}",
2425
2492
  compactLayout: ["user_code", "status", "client_id", "expires_at"],
2426
2493
  fields: {
@@ -2514,6 +2581,8 @@ var SysUserPreference = data.ObjectSchema.create({
2514
2581
  // surface in Setup is a support/diagnostic view only.
2515
2582
  managedBy: "system",
2516
2583
  description: "Per-user key-value preferences (theme, locale, etc.)",
2584
+ nameField: "key",
2585
+ // [ADR-0079] canonical primary-title pointer (single-field titleFormat)
2517
2586
  titleFormat: "{key}",
2518
2587
  compactLayout: ["user_id", "key"],
2519
2588
  listViews: {
@@ -2609,6 +2678,8 @@ var SysOauthApplication = data.ObjectSchema.create({
2609
2678
  },
2610
2679
  description: "Registered OAuth/OIDC client applications",
2611
2680
  displayNameField: "name",
2681
+ nameField: "name",
2682
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
2612
2683
  titleFormat: "{name}",
2613
2684
  compactLayout: ["name", "client_id", "type", "disabled"],
2614
2685
  // Custom actions — all OAuth-application mutations are routed through
@@ -3300,6 +3371,22 @@ var SysSsoProvider = data.ObjectSchema.create({
3300
3371
  icon: "shield-check",
3301
3372
  isSystem: true,
3302
3373
  managedBy: "better-auth",
3374
+ // ADR-0024 — env-global, ADMIN-ONLY identity config. Two orthogonal controls:
3375
+ // • `tenancy.enabled: false` — the env IS the tenant; providers are env-wide,
3376
+ // not org-partitioned. Opting out of multi-tenancy lets a platform admin's
3377
+ // `viewAllRecords` superuser bypass see every provider (without it, the
3378
+ // `member_default` wildcard `tenant_isolation` RLS denies every row, since
3379
+ // better-auth writes via its adapter with no tenantId → `organization_id`
3380
+ // is never stamped).
3381
+ // • `requiredPermissions: ['manage_platform_settings']` — object-level
3382
+ // capability gate (ADR-0066 D3) so ordinary members are denied entirely
3383
+ // (without it, tenancy-disabled + `member_default`'s `'*': allowRead` would
3384
+ // leak providers to every authenticated user).
3385
+ // Together: admins see all env providers; non-admins get 403. better-auth's
3386
+ // own endpoints already read via a system context. (Env-only object — no
3387
+ // control-plane cross-tenant risk.)
3388
+ tenancy: { enabled: false, strategy: "shared" },
3389
+ requiredPermissions: ["manage_platform_settings"],
3303
3390
  // ADR-0010 §3.7 — managed by better-auth; tenants may not edit schema.
3304
3391
  protection: {
3305
3392
  lock: "full",
@@ -3308,6 +3395,8 @@ var SysSsoProvider = data.ObjectSchema.create({
3308
3395
  },
3309
3396
  description: "External SSO identity providers (OIDC / SAML) this environment federates login to",
3310
3397
  displayNameField: "provider_id",
3398
+ nameField: "provider_id",
3399
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
3311
3400
  titleFormat: "{provider_id}",
3312
3401
  compactLayout: ["provider_id", "issuer", "domain"],
3313
3402
  // All mutations go through @better-auth/sso's endpoints under
@@ -3323,14 +3412,101 @@ var SysSsoProvider = data.ObjectSchema.create({
3323
3412
  locations: ["list_toolbar"],
3324
3413
  type: "api",
3325
3414
  method: "POST",
3326
- target: "/api/v1/auth/sso/register",
3415
+ // Routed through the env-side bridge (plugin-auth `auth-plugin.ts`), which
3416
+ // reshapes these FLAT form fields into the nested `oidcConfig` body that
3417
+ // `@better-auth/sso`'s /sso/register requires, then re-dispatches to it
3418
+ // (so the admin gate + discovery hydration run). Posting straight to
3419
+ // /sso/register would drop clientId/clientSecret (top-level → Zod-stripped)
3420
+ // and persist an unusable `oidc_config = null` provider.
3421
+ target: "/api/v1/auth/admin/sso/register",
3327
3422
  refreshAfter: true,
3328
3423
  params: [
3329
3424
  { name: "providerId", label: "Provider ID", type: "text", required: true, helpText: 'Stable identifier, e.g. "okta" or "acme-entra".' },
3330
- { name: "issuer", label: "Issuer URL", type: "text", required: true, helpText: "IdP issuer / discovery base, e.g. https://acme.okta.com." },
3331
- { name: "domain", label: "Email Domain", type: "text", required: true, helpText: "Users with this email domain are routed to this IdP." },
3332
- { name: "clientId", label: "Client ID", type: "text", required: true },
3333
- { name: "clientSecret", label: "Client Secret", type: "text", required: true }
3425
+ { name: "issuer", label: "Issuer URL", type: "text", required: true, helpText: "IdP issuer, e.g. https://acme.okta.com. Discovery is fetched from here unless an explicit URL is given below." },
3426
+ { name: "domain", label: "Email Domain", type: "text", required: true, helpText: "Users with this email domain are routed to this IdP, e.g. acme.com." },
3427
+ { name: "clientId", label: "Client ID", type: "text", required: true, helpText: "OAuth client ID issued by the IdP for this environment." },
3428
+ { name: "clientSecret", label: "Client Secret", type: "text", required: true, helpText: "OAuth client secret (stored encrypted by better-auth)." },
3429
+ { name: "discoveryEndpoint", label: "Discovery URL", type: "text", required: false, helpText: "Optional. OIDC discovery document URL. Leave blank to derive `<issuer>/.well-known/openid-configuration`." },
3430
+ { name: "scopes", label: "Scopes", type: "text", required: false, placeholder: "openid email profile", helpText: 'Optional. Space- or comma-separated OAuth scopes. Defaults to "openid email profile".' },
3431
+ { name: "mapId", label: "Map: User ID claim", type: "text", required: false, placeholder: "sub", helpText: 'Optional. ID-token claim mapped to the user ID. Defaults to "sub".' },
3432
+ { name: "mapEmail", label: "Map: Email claim", type: "text", required: false, placeholder: "email", helpText: 'Optional. Claim mapped to email. Defaults to "email".' },
3433
+ { name: "mapName", label: "Map: Name claim", type: "text", required: false, placeholder: "name", helpText: 'Optional. Claim mapped to display name. Defaults to "name".' }
3434
+ ]
3435
+ },
3436
+ {
3437
+ name: "register_saml_provider",
3438
+ label: "Register SAML Provider",
3439
+ icon: "shield",
3440
+ variant: "primary",
3441
+ mode: "create",
3442
+ locations: ["list_toolbar"],
3443
+ type: "api",
3444
+ method: "POST",
3445
+ // SAML 2.0 via @better-auth/sso (samlify-backed). Routed through the
3446
+ // env-side bridge (plugin-auth `auth-plugin.ts` → register-saml), which
3447
+ // reshapes these FLAT IdP fields into the nested `samlConfig` body that
3448
+ // @better-auth/sso's /sso/register requires (entryPoint/cert/callbackUrl/
3449
+ // spMetadata/identifierFormat), derives the per-provider ACS URL, and
3450
+ // re-dispatches to /sso/register (admin gate runs). The response returns
3451
+ // the SP ACS + metadata URLs to configure on the IdP.
3452
+ target: "/api/v1/auth/admin/sso/register-saml",
3453
+ refreshAfter: true,
3454
+ params: [
3455
+ { name: "providerId", label: "Provider ID", type: "text", required: true, helpText: 'Stable identifier, e.g. "acme-saml".' },
3456
+ { name: "issuer", label: "IdP Entity ID", type: "text", required: true, helpText: "The IdP\u2019s SAML EntityID (issuer), e.g. https://saml.acme.com/entityid." },
3457
+ { name: "domain", label: "Email Domain", type: "text", required: true, helpText: "Users with this email domain are routed to this IdP, e.g. acme.com." },
3458
+ { name: "entryPoint", label: "IdP SSO URL", type: "text", required: true, helpText: "The IdP\u2019s SAML single sign-on (redirect) endpoint that receives the SAMLRequest." },
3459
+ { name: "cert", label: "IdP Signing Certificate", type: "textarea", required: true, helpText: "The IdP\u2019s X.509 signing certificate (PEM body). Used to verify assertion signatures." },
3460
+ { name: "identifierFormat", label: "NameID Format", type: "text", required: false, placeholder: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", helpText: "Optional. Requested SAML NameID format. Defaults to the IdP\u2019s configured format." }
3461
+ ]
3462
+ },
3463
+ {
3464
+ name: "request_domain_verification",
3465
+ label: "Request Domain Verification",
3466
+ icon: "globe",
3467
+ variant: "secondary",
3468
+ locations: ["list_item", "record_header"],
3469
+ type: "api",
3470
+ method: "POST",
3471
+ // ADR-0024 ② (opt-in OS_SSO_DOMAIN_VERIFICATION). Asks @better-auth/sso
3472
+ // for a one-time DNS-TXT challenge and reveals the ready-to-paste record
3473
+ // ONCE via `resultDialog`. Routed through the env bridge (plugin-auth /
3474
+ // cloud AuthProxyPlugin) which reshapes the `{domainVerificationToken}`
3475
+ // response into the `{ data: { dnsRecordName, dnsRecordValue } }` envelope
3476
+ // the dialog reads. When the feature is OFF the bridge returns a clear
3477
+ // "not enabled for this environment" error instead of a bare 404.
3478
+ target: "/api/v1/auth/admin/sso/request-domain-verification",
3479
+ params: [
3480
+ { name: "providerId", field: "provider_id", defaultFromRow: true, required: true },
3481
+ { name: "domain", field: "domain", defaultFromRow: true, required: false }
3482
+ ],
3483
+ resultDialog: {
3484
+ title: "Verify your domain",
3485
+ description: "Add the DNS TXT record below at your domain\u2019s DNS provider, then run \u201CVerify Domain\u201D. The token is shown once.",
3486
+ acknowledge: "Done",
3487
+ fields: [
3488
+ { path: "data.dnsRecordType", label: "Record type", format: "text" },
3489
+ { path: "data.dnsRecordName", label: "Name / Host", format: "secret" },
3490
+ { path: "data.dnsRecordValue", label: "Value", format: "secret" }
3491
+ ]
3492
+ }
3493
+ },
3494
+ {
3495
+ name: "verify_domain",
3496
+ label: "Verify Domain",
3497
+ icon: "shield-check",
3498
+ variant: "secondary",
3499
+ locations: ["list_item", "record_header"],
3500
+ type: "api",
3501
+ method: "POST",
3502
+ // ADR-0024 ②. Re-checks the DNS-TXT record and flips `domain_verified`
3503
+ // on success. Routed through the env bridge, which maps @better-auth/sso's
3504
+ // empty 204 / 502 into a clear success/error toast.
3505
+ target: "/api/v1/auth/admin/sso/verify-domain",
3506
+ successMessage: "Domain ownership verified",
3507
+ refreshAfter: true,
3508
+ params: [
3509
+ { name: "providerId", field: "provider_id", defaultFromRow: true, required: true }
3334
3510
  ]
3335
3511
  },
3336
3512
  {
@@ -3357,9 +3533,17 @@ var SysSsoProvider = data.ObjectSchema.create({
3357
3533
  name: "all",
3358
3534
  label: "All",
3359
3535
  data: { provider: "object", object: "sys_sso_provider" },
3360
- columns: ["provider_id", "issuer", "domain", "created_at"],
3536
+ columns: ["provider_id", "issuer", "domain", "domain_verified", "created_at"],
3361
3537
  sort: [{ field: "provider_id", order: "asc" }],
3362
- pagination: { pageSize: 50 }
3538
+ pagination: { pageSize: 50 },
3539
+ // Per-object empty state — the shared identity-object copy ("created
3540
+ // automatically … cannot be added here") is wrong for this object, which
3541
+ // HAS a "Register SSO Provider" action. Point admins at it instead.
3542
+ emptyState: {
3543
+ title: "No SSO providers yet",
3544
+ message: "Register your organization\u2019s external IdP \u2014 OIDC (Okta, Entra, Auth0, \u2026) with \u201CRegister SSO Provider\u201D, or SAML 2.0 with \u201CRegister SAML Provider\u201D. Members whose email domain matches can then sign in through it.",
3545
+ icon: "log-in"
3546
+ }
3363
3547
  }
3364
3548
  },
3365
3549
  fields: {
@@ -3386,6 +3570,13 @@ var SysSsoProvider = data.ObjectSchema.create({
3386
3570
  description: "Email domain routed to this IdP (e.g. acme.com)",
3387
3571
  group: "Identity"
3388
3572
  }),
3573
+ domain_verified: data.Field.boolean({
3574
+ label: "Domain Verified",
3575
+ defaultValue: false,
3576
+ readonly: true,
3577
+ description: "Whether DNS ownership of the email domain has been proven (ADR-0024 \u2461). Set by \u201CVerify Domain\u201D after the DNS TXT record resolves. Managed by better-auth \u2014 not directly editable. Only enforced when domain verification is enabled for the environment.",
3578
+ group: "Identity"
3579
+ }),
3389
3580
  oidc_config: data.Field.textarea({
3390
3581
  label: "OIDC Config",
3391
3582
  required: false,
@@ -3446,6 +3637,8 @@ var SysScimProvider = data.ObjectSchema.create({
3446
3637
  },
3447
3638
  description: "SCIM 2.0 connections (bearer tokens) external IdPs use to provision/deprovision this environment's users",
3448
3639
  displayNameField: "provider_id",
3640
+ nameField: "provider_id",
3641
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
3449
3642
  titleFormat: "{provider_id}",
3450
3643
  compactLayout: ["provider_id", "organization_id"],
3451
3644
  listViews: {
@@ -3520,6 +3713,8 @@ var SysNotification = data.ObjectSchema.create({
3520
3713
  managedBy: "system",
3521
3714
  description: "Notification events \u2014 one row per emit() (ADR-0030 Layer 2 ingress)",
3522
3715
  displayNameField: "topic",
3716
+ nameField: "topic",
3717
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
3523
3718
  titleFormat: "{topic}",
3524
3719
  compactLayout: ["topic", "severity", "source_object", "created_at"],
3525
3720
  listViews: {
@@ -3746,6 +3941,8 @@ var SysEmail = data.ObjectSchema.create({
3746
3941
  managedBy: "append-only",
3747
3942
  description: "Outbound email delivery log",
3748
3943
  displayNameField: "subject",
3944
+ nameField: "subject",
3945
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
3749
3946
  titleFormat: "{subject}",
3750
3947
  compactLayout: ["subject", "to", "status", "sent_at"],
3751
3948
  fields: {
@@ -3894,6 +4091,8 @@ var SysEmailTemplate = data.ObjectSchema.create({
3894
4091
  managedBy: "config",
3895
4092
  description: "Outbound email template (subject + body + variables) resolved by name+locale",
3896
4093
  displayNameField: "label",
4094
+ nameField: "label",
4095
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
3897
4096
  titleFormat: "{label}",
3898
4097
  compactLayout: ["name", "label", "category", "locale", "active"],
3899
4098
  fields: {
@@ -4030,6 +4229,8 @@ var SysSavedReport = data.ObjectSchema.create({
4030
4229
  managedBy: "platform",
4031
4230
  description: "Persisted ObjectQL report definition \u2014 re-runnable and schedulable",
4032
4231
  displayNameField: "name",
4232
+ nameField: "name",
4233
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
4033
4234
  titleFormat: "{name}",
4034
4235
  compactLayout: ["name", "object_name", "format", "owner_id", "updated_at"],
4035
4236
  fields: {
@@ -4248,6 +4449,8 @@ var SysJob = data.ObjectSchema.create({
4248
4449
  managedBy: "system",
4249
4450
  description: "Catalogue of registered background jobs",
4250
4451
  displayNameField: "name",
4452
+ nameField: "name",
4453
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
4251
4454
  titleFormat: "{name}",
4252
4455
  compactLayout: ["name", "schedule_type", "active", "last_run_at", "last_status"],
4253
4456
  fields: {
@@ -4316,6 +4519,8 @@ var SysJobRun = data.ObjectSchema.create({
4316
4519
  managedBy: "append-only",
4317
4520
  description: "Background job execution audit trail",
4318
4521
  displayNameField: "job_name",
4522
+ nameField: "job_name",
4523
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
4319
4524
  titleFormat: "{job_name} @ {started_at}",
4320
4525
  compactLayout: ["job_name", "status", "started_at", "duration_ms", "attempt"],
4321
4526
  fields: {
@@ -4368,6 +4573,8 @@ var SysJobQueue = data.ObjectSchema.create({
4368
4573
  managedBy: "system",
4369
4574
  description: "Durable job/message queue including dead letters",
4370
4575
  displayNameField: "queue",
4576
+ nameField: "queue",
4577
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
4371
4578
  titleFormat: "{queue} #{id}",
4372
4579
  compactLayout: ["queue", "status", "attempts", "scheduled_for", "last_error"],
4373
4580
  fields: {
@@ -4478,6 +4685,8 @@ var SysSetting = data.ObjectSchema.create({
4478
4685
  managedBy: "system",
4479
4686
  description: "Generic K/V store backing the SettingsManifest contract.",
4480
4687
  displayNameField: "key",
4688
+ nameField: "key",
4689
+ // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)
4481
4690
  titleFormat: "{namespace}.{key}",
4482
4691
  compactLayout: ["namespace", "key", "scope", "updated_at"],
4483
4692
  listViews: {