@objectstack/platform-objects 12.6.0 → 14.3.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.
Files changed (41) hide show
  1. package/dist/apps/index.d.mts +1 -1
  2. package/dist/apps/index.d.ts +1 -1
  3. package/dist/apps/index.js +38 -17
  4. package/dist/apps/index.js.map +1 -1
  5. package/dist/apps/index.mjs +38 -17
  6. package/dist/apps/index.mjs.map +1 -1
  7. package/dist/audit/index.d.mts +90 -30
  8. package/dist/audit/index.d.ts +90 -30
  9. package/dist/identity/index.d.mts +1057 -280
  10. package/dist/identity/index.d.ts +1057 -280
  11. package/dist/identity/index.js +184 -29
  12. package/dist/identity/index.js.map +1 -1
  13. package/dist/identity/index.mjs +184 -29
  14. package/dist/identity/index.mjs.map +1 -1
  15. package/dist/index.d.mts +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +362 -335
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +362 -336
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/metadata-translations/index.js +20 -288
  22. package/dist/metadata-translations/index.js.map +1 -1
  23. package/dist/metadata-translations/index.mjs +20 -288
  24. package/dist/metadata-translations/index.mjs.map +1 -1
  25. package/dist/pages/index.d.mts +35 -4
  26. package/dist/pages/index.d.ts +35 -4
  27. package/dist/pages/index.js +112 -1
  28. package/dist/pages/index.js.map +1 -1
  29. package/dist/pages/index.mjs +112 -2
  30. package/dist/pages/index.mjs.map +1 -1
  31. package/dist/plugin.js +37 -300
  32. package/dist/plugin.js.map +1 -1
  33. package/dist/plugin.mjs +37 -300
  34. package/dist/plugin.mjs.map +1 -1
  35. package/dist/system/index.d.mts +30 -9
  36. package/dist/system/index.d.ts +30 -9
  37. package/dist/system/index.js +8 -0
  38. package/dist/system/index.js.map +1 -1
  39. package/dist/system/index.mjs +8 -0
  40. package/dist/system/index.mjs.map +1 -1
  41. package/package.json +3 -3
@@ -325,7 +325,12 @@ declare const SysSetting: Omit<{
325
325
  access?: {
326
326
  default: "public" | "private";
327
327
  } | undefined;
328
- requiredPermissions?: string[] | undefined;
328
+ requiredPermissions?: string[] | {
329
+ read?: string[] | undefined;
330
+ create?: string[] | undefined;
331
+ update?: string[] | undefined;
332
+ delete?: string[] | undefined;
333
+ } | undefined;
329
334
  softDelete?: {
330
335
  enabled: boolean;
331
336
  field: string;
@@ -671,9 +676,10 @@ declare const SysSetting: Omit<{
671
676
  trash: boolean;
672
677
  mru: boolean;
673
678
  clone: boolean;
674
- apiMethods?: ("search" | "create" | "import" | "delete" | "get" | "update" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
679
+ apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
675
680
  } | undefined;
676
- sharingModel?: "full" | "private" | "read" | "public_read" | "public_read_write" | "controlled_by_parent" | "read_write" | undefined;
681
+ sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
682
+ externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
677
683
  publicSharing?: {
678
684
  enabled: boolean;
679
685
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -3625,7 +3631,12 @@ declare const SysSecret: Omit<{
3625
3631
  access?: {
3626
3632
  default: "public" | "private";
3627
3633
  } | undefined;
3628
- requiredPermissions?: string[] | undefined;
3634
+ requiredPermissions?: string[] | {
3635
+ read?: string[] | undefined;
3636
+ create?: string[] | undefined;
3637
+ update?: string[] | undefined;
3638
+ delete?: string[] | undefined;
3639
+ } | undefined;
3629
3640
  softDelete?: {
3630
3641
  enabled: boolean;
3631
3642
  field: string;
@@ -3971,9 +3982,10 @@ declare const SysSecret: Omit<{
3971
3982
  trash: boolean;
3972
3983
  mru: boolean;
3973
3984
  clone: boolean;
3974
- apiMethods?: ("search" | "create" | "import" | "delete" | "get" | "update" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
3985
+ apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
3975
3986
  } | undefined;
3976
- sharingModel?: "full" | "private" | "read" | "public_read" | "public_read_write" | "controlled_by_parent" | "read_write" | undefined;
3987
+ sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
3988
+ externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
3977
3989
  publicSharing?: {
3978
3990
  enabled: boolean;
3979
3991
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -4100,6 +4112,9 @@ declare const SysSecret: Omit<{
4100
4112
  readonly icon: "key";
4101
4113
  readonly isSystem: true;
4102
4114
  readonly managedBy: "system";
4115
+ readonly access: {
4116
+ readonly default: "private";
4117
+ };
4103
4118
  readonly description: "Cipher store referenced by sys_setting handles. Never holds plaintext.";
4104
4119
  readonly highlightFields: ["namespace", "key", "kms_key_id", "version", "rotated_at"];
4105
4120
  readonly listViews: {
@@ -6101,7 +6116,12 @@ declare const SysSettingAudit: Omit<{
6101
6116
  access?: {
6102
6117
  default: "public" | "private";
6103
6118
  } | undefined;
6104
- requiredPermissions?: string[] | undefined;
6119
+ requiredPermissions?: string[] | {
6120
+ read?: string[] | undefined;
6121
+ create?: string[] | undefined;
6122
+ update?: string[] | undefined;
6123
+ delete?: string[] | undefined;
6124
+ } | undefined;
6105
6125
  softDelete?: {
6106
6126
  enabled: boolean;
6107
6127
  field: string;
@@ -6447,9 +6467,10 @@ declare const SysSettingAudit: Omit<{
6447
6467
  trash: boolean;
6448
6468
  mru: boolean;
6449
6469
  clone: boolean;
6450
- apiMethods?: ("search" | "create" | "import" | "delete" | "get" | "update" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
6470
+ apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
6451
6471
  } | undefined;
6452
- sharingModel?: "full" | "private" | "read" | "public_read" | "public_read_write" | "controlled_by_parent" | "read_write" | undefined;
6472
+ sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
6473
+ externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
6453
6474
  publicSharing?: {
6454
6475
  enabled: boolean;
6455
6476
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -325,7 +325,12 @@ declare const SysSetting: Omit<{
325
325
  access?: {
326
326
  default: "public" | "private";
327
327
  } | undefined;
328
- requiredPermissions?: string[] | undefined;
328
+ requiredPermissions?: string[] | {
329
+ read?: string[] | undefined;
330
+ create?: string[] | undefined;
331
+ update?: string[] | undefined;
332
+ delete?: string[] | undefined;
333
+ } | undefined;
329
334
  softDelete?: {
330
335
  enabled: boolean;
331
336
  field: string;
@@ -671,9 +676,10 @@ declare const SysSetting: Omit<{
671
676
  trash: boolean;
672
677
  mru: boolean;
673
678
  clone: boolean;
674
- apiMethods?: ("search" | "create" | "import" | "delete" | "get" | "update" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
679
+ apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
675
680
  } | undefined;
676
- sharingModel?: "full" | "private" | "read" | "public_read" | "public_read_write" | "controlled_by_parent" | "read_write" | undefined;
681
+ sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
682
+ externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
677
683
  publicSharing?: {
678
684
  enabled: boolean;
679
685
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -3625,7 +3631,12 @@ declare const SysSecret: Omit<{
3625
3631
  access?: {
3626
3632
  default: "public" | "private";
3627
3633
  } | undefined;
3628
- requiredPermissions?: string[] | undefined;
3634
+ requiredPermissions?: string[] | {
3635
+ read?: string[] | undefined;
3636
+ create?: string[] | undefined;
3637
+ update?: string[] | undefined;
3638
+ delete?: string[] | undefined;
3639
+ } | undefined;
3629
3640
  softDelete?: {
3630
3641
  enabled: boolean;
3631
3642
  field: string;
@@ -3971,9 +3982,10 @@ declare const SysSecret: Omit<{
3971
3982
  trash: boolean;
3972
3983
  mru: boolean;
3973
3984
  clone: boolean;
3974
- apiMethods?: ("search" | "create" | "import" | "delete" | "get" | "update" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
3985
+ apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
3975
3986
  } | undefined;
3976
- sharingModel?: "full" | "private" | "read" | "public_read" | "public_read_write" | "controlled_by_parent" | "read_write" | undefined;
3987
+ sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
3988
+ externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
3977
3989
  publicSharing?: {
3978
3990
  enabled: boolean;
3979
3991
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -4100,6 +4112,9 @@ declare const SysSecret: Omit<{
4100
4112
  readonly icon: "key";
4101
4113
  readonly isSystem: true;
4102
4114
  readonly managedBy: "system";
4115
+ readonly access: {
4116
+ readonly default: "private";
4117
+ };
4103
4118
  readonly description: "Cipher store referenced by sys_setting handles. Never holds plaintext.";
4104
4119
  readonly highlightFields: ["namespace", "key", "kms_key_id", "version", "rotated_at"];
4105
4120
  readonly listViews: {
@@ -6101,7 +6116,12 @@ declare const SysSettingAudit: Omit<{
6101
6116
  access?: {
6102
6117
  default: "public" | "private";
6103
6118
  } | undefined;
6104
- requiredPermissions?: string[] | undefined;
6119
+ requiredPermissions?: string[] | {
6120
+ read?: string[] | undefined;
6121
+ create?: string[] | undefined;
6122
+ update?: string[] | undefined;
6123
+ delete?: string[] | undefined;
6124
+ } | undefined;
6105
6125
  softDelete?: {
6106
6126
  enabled: boolean;
6107
6127
  field: string;
@@ -6447,9 +6467,10 @@ declare const SysSettingAudit: Omit<{
6447
6467
  trash: boolean;
6448
6468
  mru: boolean;
6449
6469
  clone: boolean;
6450
- apiMethods?: ("search" | "create" | "import" | "delete" | "get" | "update" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
6470
+ apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
6451
6471
  } | undefined;
6452
- sharingModel?: "full" | "private" | "read" | "public_read" | "public_read_write" | "controlled_by_parent" | "read_write" | undefined;
6472
+ sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
6473
+ externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
6453
6474
  publicSharing?: {
6454
6475
  enabled: boolean;
6455
6476
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -164,6 +164,14 @@ var SysSecret = data.ObjectSchema.create({
164
164
  icon: "key",
165
165
  isSystem: true,
166
166
  managedBy: "system",
167
+ // [ADR-0066 D2/④] Secure-by-default: the environment's encrypted-secrets
168
+ // store (settings/datasource credentials). Not covered by the wildcard `'*'`
169
+ // grant — ordinary members get 403 from the generic data layer. Platform
170
+ // admins retain access via the posture-gated superuser bypass. Internal
171
+ // readers are unaffected: `engine.resolveSecret` reads at DRIVER level,
172
+ // SettingsService / the datasource secret-binder read with no principal
173
+ // (middleware falls open for principal-less internal calls).
174
+ access: { default: "private" },
167
175
  description: "Cipher store referenced by sys_setting handles. Never holds plaintext.",
168
176
  highlightFields: ["namespace", "key", "kms_key_id", "version", "rotated_at"],
169
177
  listViews: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/system/sys-setting.object.ts","../../src/system/sys-secret.object.ts","../../src/system/sys-setting-audit.object.ts"],"names":["ObjectSchema","Field"],"mappings":"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","file":"index.js","sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting — Generic K/V store backing the SettingsManifest contract\n *\n * Single physical table that holds *every* value for *every* settings\n * namespace declared by a `SettingsManifest`. Plugins MUST NOT define\n * per-namespace tables (e.g. `sys_mail_config`); they declare a manifest\n * and the value persists here.\n *\n * Row identity: (namespace, key, scope, user_id?).\n *\n * Resolution order (handled by `SettingsService.get`):\n * 1. process.env override (source='env', locked=true)\n * 2. sys_setting WHERE scope='global' (source='global')\n * 3. sys_setting WHERE scope='tenant' (source='tenant')\n * 4. sys_setting WHERE scope='user' (source='user')\n * 5. manifest specifier.default (source='default')\n *\n * Encryption: rows with `encrypted=true` store ciphertext in `value_enc`\n * and leave `value` null. The plain value is never written to audit log\n * or history snapshots — only an `'<encrypted>'` placeholder + a digest.\n *\n * managedBy: 'system' — the admin grid in Setup is a diagnostic surface\n * only; all writes flow through `SettingsService.set()` so the resolver\n * stays the single source of truth.\n *\n * See ADR-0007 (Settings Manifest + K/V Store + Resolver).\n *\n * @namespace sys\n */\nexport const SysSetting = ObjectSchema.create({\n name: 'sys_setting',\n label: 'Setting',\n pluralLabel: 'Settings',\n icon: 'sliders',\n isSystem: true,\n managedBy: 'system',\n description: 'Generic K/V store backing the SettingsManifest contract.',\n displayNameField: 'key',\n nameField: 'key', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{namespace}.{key}',\n highlightFields: ['namespace', 'key', 'scope', 'updated_at'],\n\n listViews: {\n by_namespace: {\n type: 'grid',\n name: 'by_namespace',\n label: 'By Namespace',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'encrypted', 'updated_by', 'updated_at'],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n grouping: { fields: [{ field: 'namespace', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 200 },\n },\n tenant_only: {\n type: 'grid',\n name: 'tenant_only',\n label: 'Tenant',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'encrypted', 'updated_by', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'tenant' }],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n user_only: {\n type: 'grid',\n name: 'user_only',\n label: 'User',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['user_id', 'namespace', 'key', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'user' }],\n sort: [{ field: 'user_id', order: 'asc' }, { field: 'namespace', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n all_settings: {\n type: 'grid',\n name: 'all_settings',\n label: 'All',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'user_id', 'encrypted', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({\n label: 'Setting ID',\n required: true,\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 64,\n description: 'Manifest namespace (e.g. mail, branding, feature_flags).',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key inside the namespace (snake_case).',\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n { label: 'Runtime',value: 'runtime' },\n ],\n {\n label: 'Scope',\n required: true,\n defaultValue: 'tenant',\n description: 'Which layer of the config-resolution hierarchy this row belongs to.',\n },\n ),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n description: 'Owning user when scope=user; null otherwise.',\n }),\n\n value: Field.json({\n label: 'Value',\n description: 'JSON-encoded value. Null when encrypted=true (see value_enc).',\n }),\n\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'When true, the value is stored encrypted-at-rest in value_enc; value column is null.',\n }),\n\n locked: Field.boolean({\n label: 'Locked',\n defaultValue: false,\n description:\n 'When true, lower-scope rows cannot override this value; writes against lower scopes return 409. ' +\n 'Used by platform administrators to pin a global value for all tenants (Phase 2 cascade).',\n }),\n\n locked_reason: Field.text({\n label: 'Lock Reason',\n description: 'Human-readable explanation surfaced in the UI tooltip when locked=true.',\n }),\n\n value_enc: Field.text({\n label: 'Encrypted Value',\n readonly: true,\n description: 'Ciphertext payload (KMS-wrapped). Set only when encrypted=true.',\n }),\n\n updated_by: Field.lookup('sys_user', {\n label: 'Updated By',\n readonly: true,\n description: 'Last actor who wrote this row via SettingsService.set().',\n }),\n },\n\n indexes: [\n // Primary lookup path: (namespace, key, scope, user_id?) is what\n // SettingsService.get hits on every resolve. The composite UNIQUE\n // covers both the row-identity constraint and the read path.\n { fields: ['namespace', 'key', 'scope', 'user_id'], unique: true },\n // Common range read: full namespace dump for SettingsService.getNamespace.\n { fields: ['namespace', 'scope'], unique: false },\n // Per-user listing on the user-prefs scope.\n { fields: ['user_id', 'namespace'], unique: false },\n ],\n\n enable: {\n // History on settings is opt-in per namespace (handled at service\n // layer when needed) to avoid bloating sys_history with churn from\n // feature flags and similar high-frequency toggles.\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n // Direct data API exposed for the admin grid view, but writes from\n // the UI MUST go through /api/settings/:namespace so the resolver\n // and audit hooks fire. The grid is diagnostic-only.\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_secret — Separated cipher store for sensitive settings values.\n *\n * Phase 3 of the settings roadmap splits secret material out of\n * `sys_setting` so they can carry their own retention/rotation/KMS\n * policies without bloating the regular settings audit trail. The\n * value column in `sys_setting` for an encrypted specifier holds a\n * *handle* (the `id` of a row here), never the ciphertext itself —\n * the resolver dereferences on read.\n *\n * Why split:\n * 1. **Key rotation.** KMS adapters (AWS/GCP) rotate keys on a\n * different cadence than user-visible settings; tracking\n * `kms_key_id` + `version` per cipher lets us re-wrap without\n * touching the value lifecycle.\n * 2. **Backup hygiene.** Operators can replicate `sys_setting` to\n * analytics/lower environments while keeping `sys_secret` pinned\n * to the primary KMS region.\n * 3. **Audit symmetry.** Every secret read can record an access row\n * (Phase 4) without polluting `sys_setting_audit` with plaintext\n * reads of e.g. feature flags.\n *\n * managedBy: 'system' — never edited from a generic Object grid. All\n * writes flow through `SettingsService` and an `ICryptoProvider`.\n *\n * @namespace sys\n */\nexport const SysSecret = ObjectSchema.create({\n name: 'sys_secret',\n label: 'Secret',\n pluralLabel: 'Secrets',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n description: 'Cipher store referenced by sys_setting handles. Never holds plaintext.',\n highlightFields: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at'],\n listViews: {\n all: {\n type: 'grid',\n name: 'all',\n label: 'All Secrets',\n columns: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at', 'created_at'],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n description: 'Opaque handle referenced by `sys_setting.value_enc`.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the cipher was first written.',\n }),\n\n rotated_at: Field.datetime({\n label: 'Rotated At',\n readonly: true,\n description: 'When the cipher was last re-wrapped under a new KMS key.',\n }),\n\n /**\n * Namespace/key duplicated from `sys_setting` for forensic\n * convenience — lets operators answer \"which secret backs\n * mail.api_key right now?\" without joining the K/V table.\n * The authoritative link is `sys_setting.value_enc → sys_secret.id`.\n */\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n description: 'Settings namespace this secret belongs to.',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key within the namespace.',\n }),\n\n /** Identifier of the KMS key used to wrap `ciphertext`. */\n kms_key_id: Field.text({\n label: 'KMS Key ID',\n required: true,\n maxLength: 256,\n description: 'External KMS handle (ARN, GCP resource id, or `local`).',\n }),\n\n /** Algorithm tag (e.g. `aes-256-gcm`). Used by the provider on decrypt. */\n alg: Field.text({\n label: 'Algorithm',\n required: true,\n defaultValue: 'aes-256-gcm',\n maxLength: 64,\n description: 'Cipher/AEAD algorithm tag.',\n }),\n\n /** Wrapping version — bumps on every rotate(). */\n version: Field.number({\n label: 'Version',\n required: true,\n defaultValue: 1,\n description: 'Bumps each time rotateKey() re-wraps this row.',\n }),\n\n ciphertext: Field.text({\n label: 'Ciphertext',\n required: true,\n readonly: true,\n description:\n 'Provider-encoded ciphertext blob (base64 / JSON). Implementation-defined; only the matching ICryptoProvider can read it.',\n }),\n },\n\n indexes: [\n // Operators frequently look up by (namespace, key) to inspect or rotate.\n { fields: ['namespace', 'key'], unique: false },\n { fields: ['kms_key_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false, // rotation events are recorded by sys_setting_audit\n audit: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting_audit — Append-only audit trail for every settings mutation.\n *\n * Phase 3 of the settings roadmap. Each call to `SettingsService.set()`\n * (and any other mutation hook) writes a row here BEFORE returning to\n * the caller. The row records who, when, where (scope), and what\n * changed — but never the plaintext value of an encrypted field; only\n * a content digest is stored so an operator can verify \"this is the\n * same value as last week\" without exposing the secret.\n *\n * Why separate from `sys_audit_log`:\n * - The generic audit log is a high-traffic firehose (every CRUD\n * on every business object). Settings rows are low-traffic and\n * operationally critical, so they deserve dedicated retention and\n * indexing.\n * - The schema here carries settings-specific fields (`scope`,\n * `cascade_source`) that don't make sense on a generic row.\n *\n * Append-only contract: enforced at the application layer (the only\n * writer is SettingsService). Operators MUST NOT delete rows; instead\n * use lifecycle policies to archive cold rows to a separate bucket.\n *\n * @namespace sys\n */\nexport const SysSettingAudit = ObjectSchema.create({\n name: 'sys_setting_audit',\n label: 'Setting Audit Entry',\n pluralLabel: 'Setting Audit',\n icon: 'history',\n isSystem: true,\n managedBy: 'system',\n description: 'Append-only audit trail for SettingsService mutations.',\n highlightFields: ['namespace', 'key', 'scope', 'action', 'actor_id', 'created_at'],\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n columns: ['created_at', 'namespace', 'key', 'scope', 'action', 'actor_id', 'source'],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the mutation was recorded.',\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n ],\n {\n label: 'Scope',\n required: true,\n description: 'Cascade layer the row was written to.',\n },\n ),\n\n action: Field.select(\n [\n { label: 'Set', value: 'set' },\n { label: 'Reset', value: 'reset' },\n { label: 'Lock', value: 'lock' },\n { label: 'Unlock', value: 'unlock' },\n { label: 'Rotate', value: 'rotate' },\n ],\n {\n label: 'Action',\n required: true,\n description: 'Mutation kind.',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n description: 'User who performed the mutation; null for system jobs.',\n }),\n\n /**\n * Where the write originated. Lets operators distinguish admin UI\n * activity from migration jobs and bulk imports during incident\n * analysis.\n */\n source: Field.select(\n [\n { label: 'UI', value: 'ui' },\n { label: 'API', value: 'api' },\n { label: 'Migration', value: 'migration' },\n { label: 'Import', value: 'import' },\n { label: 'System', value: 'system' },\n ],\n {\n label: 'Source',\n required: true,\n defaultValue: 'api',\n description: 'Mutation entry-point.',\n },\n ),\n\n /** Optional free-text reason (Phase 3+ change-management hook). */\n reason: Field.text({\n label: 'Reason',\n description: 'Free-text justification provided by the actor (optional).',\n }),\n\n /**\n * Content digest of the previous value. Never the plaintext —\n * lets operators detect duplicate writes without leaking secrets.\n * Format: hex SHA-256 of the canonicalised JSON, or null when\n * the previous value was unset.\n */\n old_hash: Field.text({\n label: 'Old Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the previous value (canonicalised). Null when previously unset.',\n }),\n\n /** Content digest of the new value. Null on `reset`. */\n new_hash: Field.text({\n label: 'New Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the new value (canonicalised). Null on reset.',\n }),\n\n /** True when the field is encrypted — flags secret rotation events. */\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'True when the field carries secret material (rotation is interesting).',\n }),\n\n /** Request id from the originating HTTP/CLI invocation. */\n request_id: Field.text({\n label: 'Request ID',\n maxLength: 128,\n description: 'Correlates with sys_audit_log / tracing.',\n }),\n },\n\n indexes: [\n // Most common query: \"what changed for namespace X in the last 7 days?\"\n { fields: ['namespace', 'created_at'], unique: false },\n // Per-actor lookup for compliance reviews.\n { fields: ['actor_id', 'created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n audit: false, // this IS the audit; no recursion\n },\n});\n"]}
1
+ {"version":3,"sources":["../../src/system/sys-setting.object.ts","../../src/system/sys-secret.object.ts","../../src/system/sys-setting-audit.object.ts"],"names":["ObjectSchema","Field"],"mappings":";;;;;AAiCO,IAAM,UAAA,GAAaA,kBAAa,MAAA,CAAO;AAAA,EAC5C,IAAA,EAAM,aAAA;AAAA,EACN,KAAA,EAAO,SAAA;AAAA,EACP,WAAA,EAAa,UAAA;AAAA,EACb,IAAA,EAAM,SAAA;AAAA,EACN,QAAA,EAAU,IAAA;AAAA,EACV,SAAA,EAAW,QAAA;AAAA,EACX,WAAA,EAAa,0DAAA;AAAA,EACb,gBAAA,EAAkB,KAAA;AAAA,EAClB,SAAA,EAAW,KAAA;AAAA;AAAA,EACX,WAAA,EAAa,mBAAA;AAAA,EACb,eAAA,EAAiB,CAAC,WAAA,EAAa,KAAA,EAAO,SAAS,YAAY,CAAA;AAAA,EAE3D,SAAA,EAAW;AAAA,IACT,YAAA,EAAc;AAAA,MACZ,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,cAAA;AAAA,MACN,KAAA,EAAO,cAAA;AAAA,MACP,IAAA,EAAM,EAAE,QAAA,EAAU,QAAA,EAAU,QAAQ,aAAA,EAAc;AAAA,MAClD,SAAS,CAAC,WAAA,EAAa,OAAO,OAAA,EAAS,WAAA,EAAa,cAAc,YAAY,CAAA;AAAA,MAC9E,IAAA,EAAM,CAAC,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,KAAA,EAAM,EAAG,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,OAAO,CAAA;AAAA,MAC3E,QAAA,EAAU,EAAE,MAAA,EAAQ,CAAC,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,CAAA,EAAE;AAAA,MAC7E,UAAA,EAAY,EAAE,QAAA,EAAU,GAAA;AAAI,KAC9B;AAAA,IACA,WAAA,EAAa;AAAA,MACX,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,aAAA;AAAA,MACN,KAAA,EAAO,QAAA;AAAA,MACP,IAAA,EAAM,EAAE,QAAA,EAAU,QAAA,EAAU,QAAQ,aAAA,EAAc;AAAA,MAClD,SAAS,CAAC,WAAA,EAAa,KAAA,EAAO,WAAA,EAAa,cAAc,YAAY,CAAA;AAAA,MACrE,MAAA,EAAQ,CAAC,EAAE,KAAA,EAAO,SAAS,QAAA,EAAU,QAAA,EAAU,KAAA,EAAO,QAAA,EAAU,CAAA;AAAA,MAChE,IAAA,EAAM,CAAC,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,KAAA,EAAM,EAAG,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,OAAO,CAAA;AAAA,MAC3E,UAAA,EAAY,EAAE,QAAA,EAAU,GAAA;AAAI,KAC9B;AAAA,IACA,SAAA,EAAW;AAAA,MACT,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,WAAA;AAAA,MACN,KAAA,EAAO,MAAA;AAAA,MACP,IAAA,EAAM,EAAE,QAAA,EAAU,QAAA,EAAU,QAAQ,aAAA,EAAc;AAAA,MAClD,OAAA,EAAS,CAAC,SAAA,EAAW,WAAA,EAAa,OAAO,YAAY,CAAA;AAAA,MACrD,MAAA,EAAQ,CAAC,EAAE,KAAA,EAAO,SAAS,QAAA,EAAU,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,CAAA;AAAA,MAC9D,IAAA,EAAM,CAAC,EAAE,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,KAAA,EAAM,EAAG,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,OAAO,CAAA;AAAA,MAC/E,UAAA,EAAY,EAAE,QAAA,EAAU,GAAA;AAAI,KAC9B;AAAA,IACA,YAAA,EAAc;AAAA,MACZ,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,cAAA;AAAA,MACN,KAAA,EAAO,KAAA;AAAA,MACP,IAAA,EAAM,EAAE,QAAA,EAAU,QAAA,EAAU,QAAQ,aAAA,EAAc;AAAA,MAClD,SAAS,CAAC,WAAA,EAAa,OAAO,OAAA,EAAS,SAAA,EAAW,aAAa,YAAY,CAAA;AAAA,MAC3E,MAAM,CAAC,EAAE,OAAO,YAAA,EAAc,KAAA,EAAO,QAAQ,CAAA;AAAA,MAC7C,UAAA,EAAY,EAAE,QAAA,EAAU,GAAA;AAAI;AAC9B,GACF;AAAA,EAEA,MAAA,EAAQ;AAAA,IACN,EAAA,EAAIC,WAAM,IAAA,CAAK;AAAA,MACb,KAAA,EAAO,YAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,IAED,UAAA,EAAYA,WAAM,QAAA,CAAS;AAAA,MACzB,KAAA,EAAO,YAAA;AAAA,MACP,YAAA,EAAc,OAAA;AAAA,MACd,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,IAED,UAAA,EAAYA,WAAM,QAAA,CAAS;AAAA,MACzB,KAAA,EAAO,YAAA;AAAA,MACP,YAAA,EAAc,OAAA;AAAA,MACd,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,IAED,SAAA,EAAWA,WAAM,IAAA,CAAK;AAAA,MACpB,KAAA,EAAO,WAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,GAAA,EAAKA,WAAM,IAAA,CAAK;AAAA,MACd,KAAA,EAAO,KAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,GAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,OAAOA,UAAA,CAAM,MAAA;AAAA,MACX;AAAA,QACE,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,QAAA,EAAS;AAAA,QACnC,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,QAAA,EAAS;AAAA,QACnC,EAAE,KAAA,EAAO,MAAA,EAAU,KAAA,EAAO,MAAA,EAAO;AAAA,QACjC,EAAE,KAAA,EAAO,SAAA,EAAU,KAAA,EAAO,SAAA;AAAU,OACtC;AAAA,MACA;AAAA,QACE,KAAA,EAAO,OAAA;AAAA,QACP,QAAA,EAAU,IAAA;AAAA,QACV,YAAA,EAAc,QAAA;AAAA,QACd,WAAA,EAAa;AAAA;AACf,KACF;AAAA,IAEA,OAAA,EAASA,UAAA,CAAM,MAAA,CAAO,UAAA,EAAY;AAAA,MAChC,KAAA,EAAO,MAAA;AAAA,MACP,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,KAAA,EAAOA,WAAM,IAAA,CAAK;AAAA,MAChB,KAAA,EAAO,OAAA;AAAA,MACP,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,SAAA,EAAWA,WAAM,OAAA,CAAQ;AAAA,MACvB,KAAA,EAAO,WAAA;AAAA,MACP,YAAA,EAAc,KAAA;AAAA,MACd,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,MAAA,EAAQA,WAAM,OAAA,CAAQ;AAAA,MACpB,KAAA,EAAO,QAAA;AAAA,MACP,YAAA,EAAc,KAAA;AAAA,MACd,WAAA,EACE;AAAA,KAEH,CAAA;AAAA,IAED,aAAA,EAAeA,WAAM,IAAA,CAAK;AAAA,MACxB,KAAA,EAAO,aAAA;AAAA,MACP,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,SAAA,EAAWA,WAAM,IAAA,CAAK;AAAA,MACpB,KAAA,EAAO,iBAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,UAAA,EAAYA,UAAA,CAAM,MAAA,CAAO,UAAA,EAAY;AAAA,MACnC,KAAA,EAAO,YAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,WAAA,EAAa;AAAA,KACd;AAAA,GACH;AAAA,EAEA,OAAA,EAAS;AAAA;AAAA;AAAA;AAAA,IAIP,EAAE,QAAQ,CAAC,WAAA,EAAa,OAAO,OAAA,EAAS,SAAS,CAAA,EAAG,MAAA,EAAQ,IAAA,EAAK;AAAA;AAAA,IAEjE,EAAE,MAAA,EAAQ,CAAC,aAAa,OAAO,CAAA,EAAG,QAAQ,KAAA,EAAM;AAAA;AAAA,IAEhD,EAAE,MAAA,EAAQ,CAAC,WAAW,WAAW,CAAA,EAAG,QAAQ,KAAA;AAAM,GACpD;AAAA,EAEA,MAAA,EAAQ;AAAA;AAAA;AAAA;AAAA,IAIN,YAAA,EAAc,KAAA;AAAA,IACd,UAAA,EAAY,KAAA;AAAA,IACZ,UAAA,EAAY,IAAA;AAAA;AAAA;AAAA;AAAA,IAIZ,UAAA,EAAY,CAAC,KAAA,EAAO,MAAM,CAAA;AAAA,IAC1B,KAAA,EAAO,KAAA;AAAA,IACP,GAAA,EAAK;AAAA;AAET,CAAC;AC5KM,IAAM,SAAA,GAAYD,kBAAa,MAAA,CAAO;AAAA,EAC3C,IAAA,EAAM,YAAA;AAAA,EACN,KAAA,EAAO,QAAA;AAAA,EACP,WAAA,EAAa,SAAA;AAAA,EACb,IAAA,EAAM,KAAA;AAAA,EACN,QAAA,EAAU,IAAA;AAAA,EACV,SAAA,EAAW,QAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQX,MAAA,EAAQ,EAAE,OAAA,EAAS,SAAA,EAAU;AAAA,EAC7B,WAAA,EAAa,wEAAA;AAAA,EACb,iBAAiB,CAAC,WAAA,EAAa,KAAA,EAAO,YAAA,EAAc,WAAW,YAAY,CAAA;AAAA,EAC3E,SAAA,EAAW;AAAA,IACT,GAAA,EAAK;AAAA,MACH,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,KAAA;AAAA,MACN,KAAA,EAAO,aAAA;AAAA,MACP,SAAS,CAAC,WAAA,EAAa,OAAO,YAAA,EAAc,SAAA,EAAW,cAAc,YAAY;AAAA;AACnF,GACF;AAAA,EAEA,MAAA,EAAQ;AAAA,IACN,EAAA,EAAIC,WAAM,IAAA,CAAK;AAAA,MACb,KAAA,EAAO,IAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,UAAA,EAAYA,WAAM,QAAA,CAAS;AAAA,MACzB,KAAA,EAAO,YAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,UAAA,EAAYA,WAAM,QAAA,CAAS;AAAA,MACzB,KAAA,EAAO,YAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQD,SAAA,EAAWA,WAAM,IAAA,CAAK;AAAA,MACpB,KAAA,EAAO,WAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,GAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,GAAA,EAAKA,WAAM,IAAA,CAAK;AAAA,MACd,KAAA,EAAO,KAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,GAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA,IAGD,UAAA,EAAYA,WAAM,IAAA,CAAK;AAAA,MACrB,KAAA,EAAO,YAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,GAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA,IAGD,GAAA,EAAKA,WAAM,IAAA,CAAK;AAAA,MACd,KAAA,EAAO,WAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,YAAA,EAAc,aAAA;AAAA,MACd,SAAA,EAAW,EAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA,IAGD,OAAA,EAASA,WAAM,MAAA,CAAO;AAAA,MACpB,KAAA,EAAO,SAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,YAAA,EAAc,CAAA;AAAA,MACd,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,UAAA,EAAYA,WAAM,IAAA,CAAK;AAAA,MACrB,KAAA,EAAO,YAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,QAAA,EAAU,IAAA;AAAA,MACV,WAAA,EACE;AAAA,KACH;AAAA,GACH;AAAA,EAEA,OAAA,EAAS;AAAA;AAAA,IAEP,EAAE,MAAA,EAAQ,CAAC,aAAa,KAAK,CAAA,EAAG,QAAQ,KAAA,EAAM;AAAA,IAC9C,EAAE,MAAA,EAAQ,CAAC,YAAY,CAAA,EAAG,QAAQ,KAAA;AAAM,GAC1C;AAAA,EAEA,MAAA,EAAQ;AAAA,IACN,YAAA,EAAc,KAAA;AAAA;AAAA,IACd,KAAA,EAAO;AAAA;AAEX,CAAC;AChHM,IAAM,eAAA,GAAkBD,kBAAa,MAAA,CAAO;AAAA,EACjD,IAAA,EAAM,mBAAA;AAAA,EACN,KAAA,EAAO,qBAAA;AAAA,EACP,WAAA,EAAa,eAAA;AAAA,EACb,IAAA,EAAM,SAAA;AAAA,EACN,QAAA,EAAU,IAAA;AAAA,EACV,SAAA,EAAW,QAAA;AAAA,EACX,WAAA,EAAa,wDAAA;AAAA,EACb,iBAAiB,CAAC,WAAA,EAAa,OAAO,OAAA,EAAS,QAAA,EAAU,YAAY,YAAY,CAAA;AAAA,EACjF,SAAA,EAAW;AAAA,IACT,MAAA,EAAQ;AAAA,MACN,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO,QAAA;AAAA,MACP,OAAA,EAAS,CAAC,YAAA,EAAc,WAAA,EAAa,OAAO,OAAA,EAAS,QAAA,EAAU,YAAY,QAAQ,CAAA;AAAA,MACnF,MAAM,CAAC,EAAE,OAAO,YAAA,EAAc,KAAA,EAAO,QAAQ;AAAA;AAC/C,GACF;AAAA,EAEA,MAAA,EAAQ;AAAA,IACN,EAAA,EAAIC,WAAM,IAAA,CAAK;AAAA,MACb,KAAA,EAAO,IAAA;AAAA,MACP,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,IAED,UAAA,EAAYA,WAAM,QAAA,CAAS;AAAA,MACzB,KAAA,EAAO,YAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,IAED,SAAA,EAAWA,WAAM,IAAA,CAAK;AAAA,MACpB,KAAA,EAAO,WAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA,IAED,GAAA,EAAKA,WAAM,IAAA,CAAK;AAAA,MACd,KAAA,EAAO,KAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA,IAED,OAAOA,UAAAA,CAAM,MAAA;AAAA,MACX;AAAA,QACE,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,QAAA,EAAS;AAAA,QACnC,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,QAAA,EAAS;AAAA,QACnC,EAAE,KAAA,EAAO,MAAA,EAAU,KAAA,EAAO,MAAA;AAAO,OACnC;AAAA,MACA;AAAA,QACE,KAAA,EAAO,OAAA;AAAA,QACP,QAAA,EAAU,IAAA;AAAA,QACV,WAAA,EAAa;AAAA;AACf,KACF;AAAA,IAEA,QAAQA,UAAAA,CAAM,MAAA;AAAA,MACZ;AAAA,QACE,EAAE,KAAA,EAAO,KAAA,EAAW,KAAA,EAAO,KAAA,EAAM;AAAA,QACjC,EAAE,KAAA,EAAO,OAAA,EAAW,KAAA,EAAO,OAAA,EAAQ;AAAA,QACnC,EAAE,KAAA,EAAO,MAAA,EAAW,KAAA,EAAO,MAAA,EAAO;AAAA,QAClC,EAAE,KAAA,EAAO,QAAA,EAAW,KAAA,EAAO,QAAA,EAAS;AAAA,QACpC,EAAE,KAAA,EAAO,QAAA,EAAW,KAAA,EAAO,QAAA;AAAS,OACtC;AAAA,MACA;AAAA,QACE,KAAA,EAAO,QAAA;AAAA,QACP,QAAA,EAAU,IAAA;AAAA,QACV,WAAA,EAAa;AAAA;AACf,KACF;AAAA,IAEA,QAAA,EAAUA,UAAAA,CAAM,MAAA,CAAO,UAAA,EAAY;AAAA,MACjC,KAAA,EAAO,OAAA;AAAA,MACP,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOD,QAAQA,UAAAA,CAAM,MAAA;AAAA,MACZ;AAAA,QACE,EAAE,KAAA,EAAO,IAAA,EAAc,KAAA,EAAO,IAAA,EAAK;AAAA,QACnC,EAAE,KAAA,EAAO,KAAA,EAAc,KAAA,EAAO,KAAA,EAAM;AAAA,QACpC,EAAE,KAAA,EAAO,WAAA,EAAc,KAAA,EAAO,WAAA,EAAY;AAAA,QAC1C,EAAE,KAAA,EAAO,QAAA,EAAc,KAAA,EAAO,QAAA,EAAS;AAAA,QACvC,EAAE,KAAA,EAAO,QAAA,EAAc,KAAA,EAAO,QAAA;AAAS,OACzC;AAAA,MACA;AAAA,QACE,KAAA,EAAO,QAAA;AAAA,QACP,QAAA,EAAU,IAAA;AAAA,QACV,YAAA,EAAc,KAAA;AAAA,QACd,WAAA,EAAa;AAAA;AACf,KACF;AAAA;AAAA,IAGA,MAAA,EAAQA,WAAM,IAAA,CAAK;AAAA,MACjB,KAAA,EAAO,QAAA;AAAA,MACP,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQD,QAAA,EAAUA,WAAM,IAAA,CAAK;AAAA,MACnB,KAAA,EAAO,UAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,GAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA,IAGD,QAAA,EAAUA,WAAM,IAAA,CAAK;AAAA,MACnB,KAAA,EAAO,UAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,GAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA,IAGD,SAAA,EAAWA,WAAM,OAAA,CAAQ;AAAA,MACvB,KAAA,EAAO,WAAA;AAAA,MACP,YAAA,EAAc,KAAA;AAAA,MACd,WAAA,EAAa;AAAA,KACd,CAAA;AAAA;AAAA,IAGD,UAAA,EAAYA,WAAM,IAAA,CAAK;AAAA,MACrB,KAAA,EAAO,YAAA;AAAA,MACP,SAAA,EAAW,GAAA;AAAA,MACX,WAAA,EAAa;AAAA,KACd;AAAA,GACH;AAAA,EAEA,OAAA,EAAS;AAAA;AAAA,IAEP,EAAE,MAAA,EAAQ,CAAC,aAAa,YAAY,CAAA,EAAG,QAAQ,KAAA,EAAM;AAAA;AAAA,IAErD,EAAE,MAAA,EAAQ,CAAC,YAAY,YAAY,CAAA,EAAG,QAAQ,KAAA;AAAM,GACtD;AAAA,EAEA,MAAA,EAAQ;AAAA,IACN,YAAA,EAAc,KAAA;AAAA,IACd,KAAA,EAAO;AAAA;AAAA;AAEX,CAAC","file":"index.js","sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting — Generic K/V store backing the SettingsManifest contract\n *\n * Single physical table that holds *every* value for *every* settings\n * namespace declared by a `SettingsManifest`. Plugins MUST NOT define\n * per-namespace tables (e.g. `sys_mail_config`); they declare a manifest\n * and the value persists here.\n *\n * Row identity: (namespace, key, scope, user_id?).\n *\n * Resolution order (handled by `SettingsService.get`):\n * 1. process.env override (source='env', locked=true)\n * 2. sys_setting WHERE scope='global' (source='global')\n * 3. sys_setting WHERE scope='tenant' (source='tenant')\n * 4. sys_setting WHERE scope='user' (source='user')\n * 5. manifest specifier.default (source='default')\n *\n * Encryption: rows with `encrypted=true` store ciphertext in `value_enc`\n * and leave `value` null. The plain value is never written to audit log\n * or history snapshots — only an `'<encrypted>'` placeholder + a digest.\n *\n * managedBy: 'system' — the admin grid in Setup is a diagnostic surface\n * only; all writes flow through `SettingsService.set()` so the resolver\n * stays the single source of truth.\n *\n * See ADR-0007 (Settings Manifest + K/V Store + Resolver).\n *\n * @namespace sys\n */\nexport const SysSetting = ObjectSchema.create({\n name: 'sys_setting',\n label: 'Setting',\n pluralLabel: 'Settings',\n icon: 'sliders',\n isSystem: true,\n managedBy: 'system',\n description: 'Generic K/V store backing the SettingsManifest contract.',\n displayNameField: 'key',\n nameField: 'key', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{namespace}.{key}',\n highlightFields: ['namespace', 'key', 'scope', 'updated_at'],\n\n listViews: {\n by_namespace: {\n type: 'grid',\n name: 'by_namespace',\n label: 'By Namespace',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'encrypted', 'updated_by', 'updated_at'],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n grouping: { fields: [{ field: 'namespace', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 200 },\n },\n tenant_only: {\n type: 'grid',\n name: 'tenant_only',\n label: 'Tenant',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'encrypted', 'updated_by', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'tenant' }],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n user_only: {\n type: 'grid',\n name: 'user_only',\n label: 'User',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['user_id', 'namespace', 'key', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'user' }],\n sort: [{ field: 'user_id', order: 'asc' }, { field: 'namespace', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n all_settings: {\n type: 'grid',\n name: 'all_settings',\n label: 'All',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'user_id', 'encrypted', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({\n label: 'Setting ID',\n required: true,\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 64,\n description: 'Manifest namespace (e.g. mail, branding, feature_flags).',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key inside the namespace (snake_case).',\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n { label: 'Runtime',value: 'runtime' },\n ],\n {\n label: 'Scope',\n required: true,\n defaultValue: 'tenant',\n description: 'Which layer of the config-resolution hierarchy this row belongs to.',\n },\n ),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n description: 'Owning user when scope=user; null otherwise.',\n }),\n\n value: Field.json({\n label: 'Value',\n description: 'JSON-encoded value. Null when encrypted=true (see value_enc).',\n }),\n\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'When true, the value is stored encrypted-at-rest in value_enc; value column is null.',\n }),\n\n locked: Field.boolean({\n label: 'Locked',\n defaultValue: false,\n description:\n 'When true, lower-scope rows cannot override this value; writes against lower scopes return 409. ' +\n 'Used by platform administrators to pin a global value for all tenants (Phase 2 cascade).',\n }),\n\n locked_reason: Field.text({\n label: 'Lock Reason',\n description: 'Human-readable explanation surfaced in the UI tooltip when locked=true.',\n }),\n\n value_enc: Field.text({\n label: 'Encrypted Value',\n readonly: true,\n description: 'Ciphertext payload (KMS-wrapped). Set only when encrypted=true.',\n }),\n\n updated_by: Field.lookup('sys_user', {\n label: 'Updated By',\n readonly: true,\n description: 'Last actor who wrote this row via SettingsService.set().',\n }),\n },\n\n indexes: [\n // Primary lookup path: (namespace, key, scope, user_id?) is what\n // SettingsService.get hits on every resolve. The composite UNIQUE\n // covers both the row-identity constraint and the read path.\n { fields: ['namespace', 'key', 'scope', 'user_id'], unique: true },\n // Common range read: full namespace dump for SettingsService.getNamespace.\n { fields: ['namespace', 'scope'], unique: false },\n // Per-user listing on the user-prefs scope.\n { fields: ['user_id', 'namespace'], unique: false },\n ],\n\n enable: {\n // History on settings is opt-in per namespace (handled at service\n // layer when needed) to avoid bloating sys_history with churn from\n // feature flags and similar high-frequency toggles.\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n // Direct data API exposed for the admin grid view, but writes from\n // the UI MUST go through /api/settings/:namespace so the resolver\n // and audit hooks fire. The grid is diagnostic-only.\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_secret — Separated cipher store for sensitive settings values.\n *\n * Phase 3 of the settings roadmap splits secret material out of\n * `sys_setting` so they can carry their own retention/rotation/KMS\n * policies without bloating the regular settings audit trail. The\n * value column in `sys_setting` for an encrypted specifier holds a\n * *handle* (the `id` of a row here), never the ciphertext itself —\n * the resolver dereferences on read.\n *\n * Why split:\n * 1. **Key rotation.** KMS adapters (AWS/GCP) rotate keys on a\n * different cadence than user-visible settings; tracking\n * `kms_key_id` + `version` per cipher lets us re-wrap without\n * touching the value lifecycle.\n * 2. **Backup hygiene.** Operators can replicate `sys_setting` to\n * analytics/lower environments while keeping `sys_secret` pinned\n * to the primary KMS region.\n * 3. **Audit symmetry.** Every secret read can record an access row\n * (Phase 4) without polluting `sys_setting_audit` with plaintext\n * reads of e.g. feature flags.\n *\n * managedBy: 'system' — never edited from a generic Object grid. All\n * writes flow through `SettingsService` and an `ICryptoProvider`.\n *\n * @namespace sys\n */\nexport const SysSecret = ObjectSchema.create({\n name: 'sys_secret',\n label: 'Secret',\n pluralLabel: 'Secrets',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n // [ADR-0066 D2/④] Secure-by-default: the environment's encrypted-secrets\n // store (settings/datasource credentials). Not covered by the wildcard `'*'`\n // grant — ordinary members get 403 from the generic data layer. Platform\n // admins retain access via the posture-gated superuser bypass. Internal\n // readers are unaffected: `engine.resolveSecret` reads at DRIVER level,\n // SettingsService / the datasource secret-binder read with no principal\n // (middleware falls open for principal-less internal calls).\n access: { default: 'private' },\n description: 'Cipher store referenced by sys_setting handles. Never holds plaintext.',\n highlightFields: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at'],\n listViews: {\n all: {\n type: 'grid',\n name: 'all',\n label: 'All Secrets',\n columns: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at', 'created_at'],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n description: 'Opaque handle referenced by `sys_setting.value_enc`.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the cipher was first written.',\n }),\n\n rotated_at: Field.datetime({\n label: 'Rotated At',\n readonly: true,\n description: 'When the cipher was last re-wrapped under a new KMS key.',\n }),\n\n /**\n * Namespace/key duplicated from `sys_setting` for forensic\n * convenience — lets operators answer \"which secret backs\n * mail.api_key right now?\" without joining the K/V table.\n * The authoritative link is `sys_setting.value_enc → sys_secret.id`.\n */\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n description: 'Settings namespace this secret belongs to.',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key within the namespace.',\n }),\n\n /** Identifier of the KMS key used to wrap `ciphertext`. */\n kms_key_id: Field.text({\n label: 'KMS Key ID',\n required: true,\n maxLength: 256,\n description: 'External KMS handle (ARN, GCP resource id, or `local`).',\n }),\n\n /** Algorithm tag (e.g. `aes-256-gcm`). Used by the provider on decrypt. */\n alg: Field.text({\n label: 'Algorithm',\n required: true,\n defaultValue: 'aes-256-gcm',\n maxLength: 64,\n description: 'Cipher/AEAD algorithm tag.',\n }),\n\n /** Wrapping version — bumps on every rotate(). */\n version: Field.number({\n label: 'Version',\n required: true,\n defaultValue: 1,\n description: 'Bumps each time rotateKey() re-wraps this row.',\n }),\n\n ciphertext: Field.text({\n label: 'Ciphertext',\n required: true,\n readonly: true,\n description:\n 'Provider-encoded ciphertext blob (base64 / JSON). Implementation-defined; only the matching ICryptoProvider can read it.',\n }),\n },\n\n indexes: [\n // Operators frequently look up by (namespace, key) to inspect or rotate.\n { fields: ['namespace', 'key'], unique: false },\n { fields: ['kms_key_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false, // rotation events are recorded by sys_setting_audit\n audit: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting_audit — Append-only audit trail for every settings mutation.\n *\n * Phase 3 of the settings roadmap. Each call to `SettingsService.set()`\n * (and any other mutation hook) writes a row here BEFORE returning to\n * the caller. The row records who, when, where (scope), and what\n * changed — but never the plaintext value of an encrypted field; only\n * a content digest is stored so an operator can verify \"this is the\n * same value as last week\" without exposing the secret.\n *\n * Why separate from `sys_audit_log`:\n * - The generic audit log is a high-traffic firehose (every CRUD\n * on every business object). Settings rows are low-traffic and\n * operationally critical, so they deserve dedicated retention and\n * indexing.\n * - The schema here carries settings-specific fields (`scope`,\n * `cascade_source`) that don't make sense on a generic row.\n *\n * Append-only contract: enforced at the application layer (the only\n * writer is SettingsService). Operators MUST NOT delete rows; instead\n * use lifecycle policies to archive cold rows to a separate bucket.\n *\n * @namespace sys\n */\nexport const SysSettingAudit = ObjectSchema.create({\n name: 'sys_setting_audit',\n label: 'Setting Audit Entry',\n pluralLabel: 'Setting Audit',\n icon: 'history',\n isSystem: true,\n managedBy: 'system',\n description: 'Append-only audit trail for SettingsService mutations.',\n highlightFields: ['namespace', 'key', 'scope', 'action', 'actor_id', 'created_at'],\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n columns: ['created_at', 'namespace', 'key', 'scope', 'action', 'actor_id', 'source'],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the mutation was recorded.',\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n ],\n {\n label: 'Scope',\n required: true,\n description: 'Cascade layer the row was written to.',\n },\n ),\n\n action: Field.select(\n [\n { label: 'Set', value: 'set' },\n { label: 'Reset', value: 'reset' },\n { label: 'Lock', value: 'lock' },\n { label: 'Unlock', value: 'unlock' },\n { label: 'Rotate', value: 'rotate' },\n ],\n {\n label: 'Action',\n required: true,\n description: 'Mutation kind.',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n description: 'User who performed the mutation; null for system jobs.',\n }),\n\n /**\n * Where the write originated. Lets operators distinguish admin UI\n * activity from migration jobs and bulk imports during incident\n * analysis.\n */\n source: Field.select(\n [\n { label: 'UI', value: 'ui' },\n { label: 'API', value: 'api' },\n { label: 'Migration', value: 'migration' },\n { label: 'Import', value: 'import' },\n { label: 'System', value: 'system' },\n ],\n {\n label: 'Source',\n required: true,\n defaultValue: 'api',\n description: 'Mutation entry-point.',\n },\n ),\n\n /** Optional free-text reason (Phase 3+ change-management hook). */\n reason: Field.text({\n label: 'Reason',\n description: 'Free-text justification provided by the actor (optional).',\n }),\n\n /**\n * Content digest of the previous value. Never the plaintext —\n * lets operators detect duplicate writes without leaking secrets.\n * Format: hex SHA-256 of the canonicalised JSON, or null when\n * the previous value was unset.\n */\n old_hash: Field.text({\n label: 'Old Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the previous value (canonicalised). Null when previously unset.',\n }),\n\n /** Content digest of the new value. Null on `reset`. */\n new_hash: Field.text({\n label: 'New Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the new value (canonicalised). Null on reset.',\n }),\n\n /** True when the field is encrypted — flags secret rotation events. */\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'True when the field carries secret material (rotation is interesting).',\n }),\n\n /** Request id from the originating HTTP/CLI invocation. */\n request_id: Field.text({\n label: 'Request ID',\n maxLength: 128,\n description: 'Correlates with sys_audit_log / tracing.',\n }),\n },\n\n indexes: [\n // Most common query: \"what changed for namespace X in the last 7 days?\"\n { fields: ['namespace', 'created_at'], unique: false },\n // Per-actor lookup for compliance reviews.\n { fields: ['actor_id', 'created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n audit: false, // this IS the audit; no recursion\n },\n});\n"]}
@@ -162,6 +162,14 @@ var SysSecret = ObjectSchema.create({
162
162
  icon: "key",
163
163
  isSystem: true,
164
164
  managedBy: "system",
165
+ // [ADR-0066 D2/④] Secure-by-default: the environment's encrypted-secrets
166
+ // store (settings/datasource credentials). Not covered by the wildcard `'*'`
167
+ // grant — ordinary members get 403 from the generic data layer. Platform
168
+ // admins retain access via the posture-gated superuser bypass. Internal
169
+ // readers are unaffected: `engine.resolveSecret` reads at DRIVER level,
170
+ // SettingsService / the datasource secret-binder read with no principal
171
+ // (middleware falls open for principal-less internal calls).
172
+ access: { default: "private" },
165
173
  description: "Cipher store referenced by sys_setting handles. Never holds plaintext.",
166
174
  highlightFields: ["namespace", "key", "kms_key_id", "version", "rotated_at"],
167
175
  listViews: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/system/sys-setting.object.ts","../../src/system/sys-secret.object.ts","../../src/system/sys-setting-audit.object.ts"],"names":["ObjectSchema","Field"],"mappings":"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","file":"index.mjs","sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting — Generic K/V store backing the SettingsManifest contract\n *\n * Single physical table that holds *every* value for *every* settings\n * namespace declared by a `SettingsManifest`. Plugins MUST NOT define\n * per-namespace tables (e.g. `sys_mail_config`); they declare a manifest\n * and the value persists here.\n *\n * Row identity: (namespace, key, scope, user_id?).\n *\n * Resolution order (handled by `SettingsService.get`):\n * 1. process.env override (source='env', locked=true)\n * 2. sys_setting WHERE scope='global' (source='global')\n * 3. sys_setting WHERE scope='tenant' (source='tenant')\n * 4. sys_setting WHERE scope='user' (source='user')\n * 5. manifest specifier.default (source='default')\n *\n * Encryption: rows with `encrypted=true` store ciphertext in `value_enc`\n * and leave `value` null. The plain value is never written to audit log\n * or history snapshots — only an `'<encrypted>'` placeholder + a digest.\n *\n * managedBy: 'system' — the admin grid in Setup is a diagnostic surface\n * only; all writes flow through `SettingsService.set()` so the resolver\n * stays the single source of truth.\n *\n * See ADR-0007 (Settings Manifest + K/V Store + Resolver).\n *\n * @namespace sys\n */\nexport const SysSetting = ObjectSchema.create({\n name: 'sys_setting',\n label: 'Setting',\n pluralLabel: 'Settings',\n icon: 'sliders',\n isSystem: true,\n managedBy: 'system',\n description: 'Generic K/V store backing the SettingsManifest contract.',\n displayNameField: 'key',\n nameField: 'key', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{namespace}.{key}',\n highlightFields: ['namespace', 'key', 'scope', 'updated_at'],\n\n listViews: {\n by_namespace: {\n type: 'grid',\n name: 'by_namespace',\n label: 'By Namespace',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'encrypted', 'updated_by', 'updated_at'],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n grouping: { fields: [{ field: 'namespace', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 200 },\n },\n tenant_only: {\n type: 'grid',\n name: 'tenant_only',\n label: 'Tenant',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'encrypted', 'updated_by', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'tenant' }],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n user_only: {\n type: 'grid',\n name: 'user_only',\n label: 'User',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['user_id', 'namespace', 'key', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'user' }],\n sort: [{ field: 'user_id', order: 'asc' }, { field: 'namespace', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n all_settings: {\n type: 'grid',\n name: 'all_settings',\n label: 'All',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'user_id', 'encrypted', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({\n label: 'Setting ID',\n required: true,\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 64,\n description: 'Manifest namespace (e.g. mail, branding, feature_flags).',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key inside the namespace (snake_case).',\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n { label: 'Runtime',value: 'runtime' },\n ],\n {\n label: 'Scope',\n required: true,\n defaultValue: 'tenant',\n description: 'Which layer of the config-resolution hierarchy this row belongs to.',\n },\n ),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n description: 'Owning user when scope=user; null otherwise.',\n }),\n\n value: Field.json({\n label: 'Value',\n description: 'JSON-encoded value. Null when encrypted=true (see value_enc).',\n }),\n\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'When true, the value is stored encrypted-at-rest in value_enc; value column is null.',\n }),\n\n locked: Field.boolean({\n label: 'Locked',\n defaultValue: false,\n description:\n 'When true, lower-scope rows cannot override this value; writes against lower scopes return 409. ' +\n 'Used by platform administrators to pin a global value for all tenants (Phase 2 cascade).',\n }),\n\n locked_reason: Field.text({\n label: 'Lock Reason',\n description: 'Human-readable explanation surfaced in the UI tooltip when locked=true.',\n }),\n\n value_enc: Field.text({\n label: 'Encrypted Value',\n readonly: true,\n description: 'Ciphertext payload (KMS-wrapped). Set only when encrypted=true.',\n }),\n\n updated_by: Field.lookup('sys_user', {\n label: 'Updated By',\n readonly: true,\n description: 'Last actor who wrote this row via SettingsService.set().',\n }),\n },\n\n indexes: [\n // Primary lookup path: (namespace, key, scope, user_id?) is what\n // SettingsService.get hits on every resolve. The composite UNIQUE\n // covers both the row-identity constraint and the read path.\n { fields: ['namespace', 'key', 'scope', 'user_id'], unique: true },\n // Common range read: full namespace dump for SettingsService.getNamespace.\n { fields: ['namespace', 'scope'], unique: false },\n // Per-user listing on the user-prefs scope.\n { fields: ['user_id', 'namespace'], unique: false },\n ],\n\n enable: {\n // History on settings is opt-in per namespace (handled at service\n // layer when needed) to avoid bloating sys_history with churn from\n // feature flags and similar high-frequency toggles.\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n // Direct data API exposed for the admin grid view, but writes from\n // the UI MUST go through /api/settings/:namespace so the resolver\n // and audit hooks fire. The grid is diagnostic-only.\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_secret — Separated cipher store for sensitive settings values.\n *\n * Phase 3 of the settings roadmap splits secret material out of\n * `sys_setting` so they can carry their own retention/rotation/KMS\n * policies without bloating the regular settings audit trail. The\n * value column in `sys_setting` for an encrypted specifier holds a\n * *handle* (the `id` of a row here), never the ciphertext itself —\n * the resolver dereferences on read.\n *\n * Why split:\n * 1. **Key rotation.** KMS adapters (AWS/GCP) rotate keys on a\n * different cadence than user-visible settings; tracking\n * `kms_key_id` + `version` per cipher lets us re-wrap without\n * touching the value lifecycle.\n * 2. **Backup hygiene.** Operators can replicate `sys_setting` to\n * analytics/lower environments while keeping `sys_secret` pinned\n * to the primary KMS region.\n * 3. **Audit symmetry.** Every secret read can record an access row\n * (Phase 4) without polluting `sys_setting_audit` with plaintext\n * reads of e.g. feature flags.\n *\n * managedBy: 'system' — never edited from a generic Object grid. All\n * writes flow through `SettingsService` and an `ICryptoProvider`.\n *\n * @namespace sys\n */\nexport const SysSecret = ObjectSchema.create({\n name: 'sys_secret',\n label: 'Secret',\n pluralLabel: 'Secrets',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n description: 'Cipher store referenced by sys_setting handles. Never holds plaintext.',\n highlightFields: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at'],\n listViews: {\n all: {\n type: 'grid',\n name: 'all',\n label: 'All Secrets',\n columns: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at', 'created_at'],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n description: 'Opaque handle referenced by `sys_setting.value_enc`.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the cipher was first written.',\n }),\n\n rotated_at: Field.datetime({\n label: 'Rotated At',\n readonly: true,\n description: 'When the cipher was last re-wrapped under a new KMS key.',\n }),\n\n /**\n * Namespace/key duplicated from `sys_setting` for forensic\n * convenience — lets operators answer \"which secret backs\n * mail.api_key right now?\" without joining the K/V table.\n * The authoritative link is `sys_setting.value_enc → sys_secret.id`.\n */\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n description: 'Settings namespace this secret belongs to.',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key within the namespace.',\n }),\n\n /** Identifier of the KMS key used to wrap `ciphertext`. */\n kms_key_id: Field.text({\n label: 'KMS Key ID',\n required: true,\n maxLength: 256,\n description: 'External KMS handle (ARN, GCP resource id, or `local`).',\n }),\n\n /** Algorithm tag (e.g. `aes-256-gcm`). Used by the provider on decrypt. */\n alg: Field.text({\n label: 'Algorithm',\n required: true,\n defaultValue: 'aes-256-gcm',\n maxLength: 64,\n description: 'Cipher/AEAD algorithm tag.',\n }),\n\n /** Wrapping version — bumps on every rotate(). */\n version: Field.number({\n label: 'Version',\n required: true,\n defaultValue: 1,\n description: 'Bumps each time rotateKey() re-wraps this row.',\n }),\n\n ciphertext: Field.text({\n label: 'Ciphertext',\n required: true,\n readonly: true,\n description:\n 'Provider-encoded ciphertext blob (base64 / JSON). Implementation-defined; only the matching ICryptoProvider can read it.',\n }),\n },\n\n indexes: [\n // Operators frequently look up by (namespace, key) to inspect or rotate.\n { fields: ['namespace', 'key'], unique: false },\n { fields: ['kms_key_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false, // rotation events are recorded by sys_setting_audit\n audit: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting_audit — Append-only audit trail for every settings mutation.\n *\n * Phase 3 of the settings roadmap. Each call to `SettingsService.set()`\n * (and any other mutation hook) writes a row here BEFORE returning to\n * the caller. The row records who, when, where (scope), and what\n * changed — but never the plaintext value of an encrypted field; only\n * a content digest is stored so an operator can verify \"this is the\n * same value as last week\" without exposing the secret.\n *\n * Why separate from `sys_audit_log`:\n * - The generic audit log is a high-traffic firehose (every CRUD\n * on every business object). Settings rows are low-traffic and\n * operationally critical, so they deserve dedicated retention and\n * indexing.\n * - The schema here carries settings-specific fields (`scope`,\n * `cascade_source`) that don't make sense on a generic row.\n *\n * Append-only contract: enforced at the application layer (the only\n * writer is SettingsService). Operators MUST NOT delete rows; instead\n * use lifecycle policies to archive cold rows to a separate bucket.\n *\n * @namespace sys\n */\nexport const SysSettingAudit = ObjectSchema.create({\n name: 'sys_setting_audit',\n label: 'Setting Audit Entry',\n pluralLabel: 'Setting Audit',\n icon: 'history',\n isSystem: true,\n managedBy: 'system',\n description: 'Append-only audit trail for SettingsService mutations.',\n highlightFields: ['namespace', 'key', 'scope', 'action', 'actor_id', 'created_at'],\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n columns: ['created_at', 'namespace', 'key', 'scope', 'action', 'actor_id', 'source'],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the mutation was recorded.',\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n ],\n {\n label: 'Scope',\n required: true,\n description: 'Cascade layer the row was written to.',\n },\n ),\n\n action: Field.select(\n [\n { label: 'Set', value: 'set' },\n { label: 'Reset', value: 'reset' },\n { label: 'Lock', value: 'lock' },\n { label: 'Unlock', value: 'unlock' },\n { label: 'Rotate', value: 'rotate' },\n ],\n {\n label: 'Action',\n required: true,\n description: 'Mutation kind.',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n description: 'User who performed the mutation; null for system jobs.',\n }),\n\n /**\n * Where the write originated. Lets operators distinguish admin UI\n * activity from migration jobs and bulk imports during incident\n * analysis.\n */\n source: Field.select(\n [\n { label: 'UI', value: 'ui' },\n { label: 'API', value: 'api' },\n { label: 'Migration', value: 'migration' },\n { label: 'Import', value: 'import' },\n { label: 'System', value: 'system' },\n ],\n {\n label: 'Source',\n required: true,\n defaultValue: 'api',\n description: 'Mutation entry-point.',\n },\n ),\n\n /** Optional free-text reason (Phase 3+ change-management hook). */\n reason: Field.text({\n label: 'Reason',\n description: 'Free-text justification provided by the actor (optional).',\n }),\n\n /**\n * Content digest of the previous value. Never the plaintext —\n * lets operators detect duplicate writes without leaking secrets.\n * Format: hex SHA-256 of the canonicalised JSON, or null when\n * the previous value was unset.\n */\n old_hash: Field.text({\n label: 'Old Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the previous value (canonicalised). Null when previously unset.',\n }),\n\n /** Content digest of the new value. Null on `reset`. */\n new_hash: Field.text({\n label: 'New Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the new value (canonicalised). Null on reset.',\n }),\n\n /** True when the field is encrypted — flags secret rotation events. */\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'True when the field carries secret material (rotation is interesting).',\n }),\n\n /** Request id from the originating HTTP/CLI invocation. */\n request_id: Field.text({\n label: 'Request ID',\n maxLength: 128,\n description: 'Correlates with sys_audit_log / tracing.',\n }),\n },\n\n indexes: [\n // Most common query: \"what changed for namespace X in the last 7 days?\"\n { fields: ['namespace', 'created_at'], unique: false },\n // Per-actor lookup for compliance reviews.\n { fields: ['actor_id', 'created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n audit: false, // this IS the audit; no recursion\n },\n});\n"]}
1
+ {"version":3,"sources":["../../src/system/sys-setting.object.ts","../../src/system/sys-secret.object.ts","../../src/system/sys-setting-audit.object.ts"],"names":["ObjectSchema","Field"],"mappings":"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","file":"index.mjs","sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting — Generic K/V store backing the SettingsManifest contract\n *\n * Single physical table that holds *every* value for *every* settings\n * namespace declared by a `SettingsManifest`. Plugins MUST NOT define\n * per-namespace tables (e.g. `sys_mail_config`); they declare a manifest\n * and the value persists here.\n *\n * Row identity: (namespace, key, scope, user_id?).\n *\n * Resolution order (handled by `SettingsService.get`):\n * 1. process.env override (source='env', locked=true)\n * 2. sys_setting WHERE scope='global' (source='global')\n * 3. sys_setting WHERE scope='tenant' (source='tenant')\n * 4. sys_setting WHERE scope='user' (source='user')\n * 5. manifest specifier.default (source='default')\n *\n * Encryption: rows with `encrypted=true` store ciphertext in `value_enc`\n * and leave `value` null. The plain value is never written to audit log\n * or history snapshots — only an `'<encrypted>'` placeholder + a digest.\n *\n * managedBy: 'system' — the admin grid in Setup is a diagnostic surface\n * only; all writes flow through `SettingsService.set()` so the resolver\n * stays the single source of truth.\n *\n * See ADR-0007 (Settings Manifest + K/V Store + Resolver).\n *\n * @namespace sys\n */\nexport const SysSetting = ObjectSchema.create({\n name: 'sys_setting',\n label: 'Setting',\n pluralLabel: 'Settings',\n icon: 'sliders',\n isSystem: true,\n managedBy: 'system',\n description: 'Generic K/V store backing the SettingsManifest contract.',\n displayNameField: 'key',\n nameField: 'key', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{namespace}.{key}',\n highlightFields: ['namespace', 'key', 'scope', 'updated_at'],\n\n listViews: {\n by_namespace: {\n type: 'grid',\n name: 'by_namespace',\n label: 'By Namespace',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'encrypted', 'updated_by', 'updated_at'],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n grouping: { fields: [{ field: 'namespace', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 200 },\n },\n tenant_only: {\n type: 'grid',\n name: 'tenant_only',\n label: 'Tenant',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'encrypted', 'updated_by', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'tenant' }],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n user_only: {\n type: 'grid',\n name: 'user_only',\n label: 'User',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['user_id', 'namespace', 'key', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'user' }],\n sort: [{ field: 'user_id', order: 'asc' }, { field: 'namespace', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n all_settings: {\n type: 'grid',\n name: 'all_settings',\n label: 'All',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'user_id', 'encrypted', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({\n label: 'Setting ID',\n required: true,\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 64,\n description: 'Manifest namespace (e.g. mail, branding, feature_flags).',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key inside the namespace (snake_case).',\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n { label: 'Runtime',value: 'runtime' },\n ],\n {\n label: 'Scope',\n required: true,\n defaultValue: 'tenant',\n description: 'Which layer of the config-resolution hierarchy this row belongs to.',\n },\n ),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n description: 'Owning user when scope=user; null otherwise.',\n }),\n\n value: Field.json({\n label: 'Value',\n description: 'JSON-encoded value. Null when encrypted=true (see value_enc).',\n }),\n\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'When true, the value is stored encrypted-at-rest in value_enc; value column is null.',\n }),\n\n locked: Field.boolean({\n label: 'Locked',\n defaultValue: false,\n description:\n 'When true, lower-scope rows cannot override this value; writes against lower scopes return 409. ' +\n 'Used by platform administrators to pin a global value for all tenants (Phase 2 cascade).',\n }),\n\n locked_reason: Field.text({\n label: 'Lock Reason',\n description: 'Human-readable explanation surfaced in the UI tooltip when locked=true.',\n }),\n\n value_enc: Field.text({\n label: 'Encrypted Value',\n readonly: true,\n description: 'Ciphertext payload (KMS-wrapped). Set only when encrypted=true.',\n }),\n\n updated_by: Field.lookup('sys_user', {\n label: 'Updated By',\n readonly: true,\n description: 'Last actor who wrote this row via SettingsService.set().',\n }),\n },\n\n indexes: [\n // Primary lookup path: (namespace, key, scope, user_id?) is what\n // SettingsService.get hits on every resolve. The composite UNIQUE\n // covers both the row-identity constraint and the read path.\n { fields: ['namespace', 'key', 'scope', 'user_id'], unique: true },\n // Common range read: full namespace dump for SettingsService.getNamespace.\n { fields: ['namespace', 'scope'], unique: false },\n // Per-user listing on the user-prefs scope.\n { fields: ['user_id', 'namespace'], unique: false },\n ],\n\n enable: {\n // History on settings is opt-in per namespace (handled at service\n // layer when needed) to avoid bloating sys_history with churn from\n // feature flags and similar high-frequency toggles.\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n // Direct data API exposed for the admin grid view, but writes from\n // the UI MUST go through /api/settings/:namespace so the resolver\n // and audit hooks fire. The grid is diagnostic-only.\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_secret — Separated cipher store for sensitive settings values.\n *\n * Phase 3 of the settings roadmap splits secret material out of\n * `sys_setting` so they can carry their own retention/rotation/KMS\n * policies without bloating the regular settings audit trail. The\n * value column in `sys_setting` for an encrypted specifier holds a\n * *handle* (the `id` of a row here), never the ciphertext itself —\n * the resolver dereferences on read.\n *\n * Why split:\n * 1. **Key rotation.** KMS adapters (AWS/GCP) rotate keys on a\n * different cadence than user-visible settings; tracking\n * `kms_key_id` + `version` per cipher lets us re-wrap without\n * touching the value lifecycle.\n * 2. **Backup hygiene.** Operators can replicate `sys_setting` to\n * analytics/lower environments while keeping `sys_secret` pinned\n * to the primary KMS region.\n * 3. **Audit symmetry.** Every secret read can record an access row\n * (Phase 4) without polluting `sys_setting_audit` with plaintext\n * reads of e.g. feature flags.\n *\n * managedBy: 'system' — never edited from a generic Object grid. All\n * writes flow through `SettingsService` and an `ICryptoProvider`.\n *\n * @namespace sys\n */\nexport const SysSecret = ObjectSchema.create({\n name: 'sys_secret',\n label: 'Secret',\n pluralLabel: 'Secrets',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n // [ADR-0066 D2/④] Secure-by-default: the environment's encrypted-secrets\n // store (settings/datasource credentials). Not covered by the wildcard `'*'`\n // grant — ordinary members get 403 from the generic data layer. Platform\n // admins retain access via the posture-gated superuser bypass. Internal\n // readers are unaffected: `engine.resolveSecret` reads at DRIVER level,\n // SettingsService / the datasource secret-binder read with no principal\n // (middleware falls open for principal-less internal calls).\n access: { default: 'private' },\n description: 'Cipher store referenced by sys_setting handles. Never holds plaintext.',\n highlightFields: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at'],\n listViews: {\n all: {\n type: 'grid',\n name: 'all',\n label: 'All Secrets',\n columns: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at', 'created_at'],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n description: 'Opaque handle referenced by `sys_setting.value_enc`.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the cipher was first written.',\n }),\n\n rotated_at: Field.datetime({\n label: 'Rotated At',\n readonly: true,\n description: 'When the cipher was last re-wrapped under a new KMS key.',\n }),\n\n /**\n * Namespace/key duplicated from `sys_setting` for forensic\n * convenience — lets operators answer \"which secret backs\n * mail.api_key right now?\" without joining the K/V table.\n * The authoritative link is `sys_setting.value_enc → sys_secret.id`.\n */\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n description: 'Settings namespace this secret belongs to.',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key within the namespace.',\n }),\n\n /** Identifier of the KMS key used to wrap `ciphertext`. */\n kms_key_id: Field.text({\n label: 'KMS Key ID',\n required: true,\n maxLength: 256,\n description: 'External KMS handle (ARN, GCP resource id, or `local`).',\n }),\n\n /** Algorithm tag (e.g. `aes-256-gcm`). Used by the provider on decrypt. */\n alg: Field.text({\n label: 'Algorithm',\n required: true,\n defaultValue: 'aes-256-gcm',\n maxLength: 64,\n description: 'Cipher/AEAD algorithm tag.',\n }),\n\n /** Wrapping version — bumps on every rotate(). */\n version: Field.number({\n label: 'Version',\n required: true,\n defaultValue: 1,\n description: 'Bumps each time rotateKey() re-wraps this row.',\n }),\n\n ciphertext: Field.text({\n label: 'Ciphertext',\n required: true,\n readonly: true,\n description:\n 'Provider-encoded ciphertext blob (base64 / JSON). Implementation-defined; only the matching ICryptoProvider can read it.',\n }),\n },\n\n indexes: [\n // Operators frequently look up by (namespace, key) to inspect or rotate.\n { fields: ['namespace', 'key'], unique: false },\n { fields: ['kms_key_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false, // rotation events are recorded by sys_setting_audit\n audit: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting_audit — Append-only audit trail for every settings mutation.\n *\n * Phase 3 of the settings roadmap. Each call to `SettingsService.set()`\n * (and any other mutation hook) writes a row here BEFORE returning to\n * the caller. The row records who, when, where (scope), and what\n * changed — but never the plaintext value of an encrypted field; only\n * a content digest is stored so an operator can verify \"this is the\n * same value as last week\" without exposing the secret.\n *\n * Why separate from `sys_audit_log`:\n * - The generic audit log is a high-traffic firehose (every CRUD\n * on every business object). Settings rows are low-traffic and\n * operationally critical, so they deserve dedicated retention and\n * indexing.\n * - The schema here carries settings-specific fields (`scope`,\n * `cascade_source`) that don't make sense on a generic row.\n *\n * Append-only contract: enforced at the application layer (the only\n * writer is SettingsService). Operators MUST NOT delete rows; instead\n * use lifecycle policies to archive cold rows to a separate bucket.\n *\n * @namespace sys\n */\nexport const SysSettingAudit = ObjectSchema.create({\n name: 'sys_setting_audit',\n label: 'Setting Audit Entry',\n pluralLabel: 'Setting Audit',\n icon: 'history',\n isSystem: true,\n managedBy: 'system',\n description: 'Append-only audit trail for SettingsService mutations.',\n highlightFields: ['namespace', 'key', 'scope', 'action', 'actor_id', 'created_at'],\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n columns: ['created_at', 'namespace', 'key', 'scope', 'action', 'actor_id', 'source'],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the mutation was recorded.',\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n ],\n {\n label: 'Scope',\n required: true,\n description: 'Cascade layer the row was written to.',\n },\n ),\n\n action: Field.select(\n [\n { label: 'Set', value: 'set' },\n { label: 'Reset', value: 'reset' },\n { label: 'Lock', value: 'lock' },\n { label: 'Unlock', value: 'unlock' },\n { label: 'Rotate', value: 'rotate' },\n ],\n {\n label: 'Action',\n required: true,\n description: 'Mutation kind.',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n description: 'User who performed the mutation; null for system jobs.',\n }),\n\n /**\n * Where the write originated. Lets operators distinguish admin UI\n * activity from migration jobs and bulk imports during incident\n * analysis.\n */\n source: Field.select(\n [\n { label: 'UI', value: 'ui' },\n { label: 'API', value: 'api' },\n { label: 'Migration', value: 'migration' },\n { label: 'Import', value: 'import' },\n { label: 'System', value: 'system' },\n ],\n {\n label: 'Source',\n required: true,\n defaultValue: 'api',\n description: 'Mutation entry-point.',\n },\n ),\n\n /** Optional free-text reason (Phase 3+ change-management hook). */\n reason: Field.text({\n label: 'Reason',\n description: 'Free-text justification provided by the actor (optional).',\n }),\n\n /**\n * Content digest of the previous value. Never the plaintext —\n * lets operators detect duplicate writes without leaking secrets.\n * Format: hex SHA-256 of the canonicalised JSON, or null when\n * the previous value was unset.\n */\n old_hash: Field.text({\n label: 'Old Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the previous value (canonicalised). Null when previously unset.',\n }),\n\n /** Content digest of the new value. Null on `reset`. */\n new_hash: Field.text({\n label: 'New Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the new value (canonicalised). Null on reset.',\n }),\n\n /** True when the field is encrypted — flags secret rotation events. */\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'True when the field carries secret material (rotation is interesting).',\n }),\n\n /** Request id from the originating HTTP/CLI invocation. */\n request_id: Field.text({\n label: 'Request ID',\n maxLength: 128,\n description: 'Correlates with sys_audit_log / tracing.',\n }),\n },\n\n indexes: [\n // Most common query: \"what changed for namespace X in the last 7 days?\"\n { fields: ['namespace', 'created_at'], unique: false },\n // Per-actor lookup for compliance reviews.\n { fields: ['actor_id', 'created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n audit: false, // this IS the audit; no recursion\n },\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/platform-objects",
3
- "version": "12.6.0",
3
+ "version": "14.3.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Core platform object schemas for ObjectStack — identity, security, audit, tenant, and metadata objects",
6
6
  "main": "dist/index.js",
@@ -63,8 +63,8 @@
63
63
  }
64
64
  },
65
65
  "dependencies": {
66
- "@objectstack/spec": "12.6.0",
67
- "@objectstack/metadata-core": "12.6.0"
66
+ "@objectstack/metadata-core": "14.3.0",
67
+ "@objectstack/spec": "14.3.0"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@types/node": "^26.1.0",