@objectstack/service-settings 6.6.0 → 6.7.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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/crypto-adapter.ts","../src/settings-service.types.ts","../src/settings-service.ts","../src/in-memory-crypto-provider.ts","../src/settings-routes.ts","../src/manifest.ts","../src/manifests/mail.manifest.ts","../src/manifests/branding.manifest.ts","../src/manifests/feature-flags.manifest.ts","../src/manifests/storage.manifest.ts","../src/manifests/index.ts","../src/translations/en.ts","../src/translations/zh-CN.ts","../src/translations/ja-JP.ts","../src/translations/index.ts","../src/settings-service-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Pluggable adapter for at-rest encryption of `Specifier.encrypted: true`\n * values. The default {@link NoopCryptoAdapter} provides a transparent\n * base64 wrapping suitable for development and tests; production\n * deployments MUST inject a real KMS-backed adapter.\n *\n * encrypt/decrypt are async to leave room for KMS round-trips.\n */\nexport interface CryptoAdapter {\n /** Returns the ciphertext blob to store in `sys_setting.value_enc`. */\n encrypt(plaintext: string, ctx: { namespace: string; key: string }): Promise<string>;\n /** Returns the plaintext used by the resolver. */\n decrypt(ciphertext: string, ctx: { namespace: string; key: string }): Promise<string>;\n /**\n * Stable, short, non-reversible digest used for audit-log entries so\n * operators can correlate value changes without leaking secrets.\n */\n digest(plaintext: string): string;\n}\n\n/**\n * Development / test default. Base64-wraps the plaintext so the column\n * isn't a literal mirror but provides no real confidentiality.\n *\n * Operators are expected to override this via\n * `SettingsServicePluginOptions.crypto`.\n */\nexport class NoopCryptoAdapter implements CryptoAdapter {\n async encrypt(plaintext: string): Promise<string> {\n return 'b64:' + Buffer.from(plaintext, 'utf8').toString('base64');\n }\n async decrypt(ciphertext: string): Promise<string> {\n if (!ciphertext.startsWith('b64:')) {\n // Tolerate legacy plaintext rows during the dev rollout.\n return ciphertext;\n }\n return Buffer.from(ciphertext.slice(4), 'base64').toString('utf8');\n }\n digest(plaintext: string): string {\n // FNV-1a 32-bit — short, stable, non-cryptographic. Audit-only.\n let h = 0x811c9dc5;\n for (let i = 0; i < plaintext.length; i++) {\n h ^= plaintext.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return 'fnv32:' + h.toString(16).padStart(8, '0');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * SettingsService — the runtime implementation of ADR-0007.\n *\n * Responsibilities:\n * - Maintain an in-memory registry of `SettingsManifest` instances.\n * - Read/write values from the shared `sys_setting` K/V table via the\n * `objectql` data engine, with an in-memory fallback so the service\n * is usable before a real persistence layer is wired up (e.g. unit\n * tests, bootstrap, control-plane mock).\n * - Resolve effective values with `Env > Tenant > User > Default`\n * precedence and tag every value with provenance.\n * - Encrypt-at-rest for `encrypted: true` specifiers using a pluggable\n * {@link CryptoAdapter}.\n * - Emit `sys_audit_log` rows for every successful write (encrypted\n * values are masked).\n * - Dispatch `runAction` for `action_button` specifiers — used by\n * \"Test connection\" / \"Send test email\" etc.\n *\n * The service is intentionally framework-agnostic: it doesn't import\n * the HTTP server, the plugin context, or the audit object schema. The\n * plugin wires those pieces up.\n */\n\nimport type { SettingsActionResult, SpecifierScope } from '@objectstack/spec/system';\nimport { type CryptoAdapter } from './crypto-adapter.js';\n\n/** Caller identity used by the resolver and audit log. */\nexport interface SettingsContext {\n /** Calling user id, when known. Required for `scope: 'user'` reads. */\n userId?: string;\n /** Tenant / project id. Reserved for multi-tenant deployments. */\n tenantId?: string;\n /** Permissions held by the caller (used by REST authz). */\n permissions?: string[];\n /** Source IP / request id for audit correlation. */\n requestId?: string;\n}\n\n/** Storage row shape used by both the engine and the in-memory store. */\nexport interface SettingsRow {\n namespace: string;\n key: string;\n scope: SpecifierScope;\n user_id: string | null;\n value: unknown | null;\n value_enc: string | null;\n encrypted: boolean;\n /**\n * When true, lower-scope rows for the same (namespace, key) are\n * read-only — the resolver still returns this row's value and the\n * mutation API throws `SettingsLockedError`. Only meaningful on\n * upper-scope rows (`global`, `tenant`). (Phase 2)\n */\n locked?: boolean;\n /** Human-readable reason the lock was applied (UI tooltip). */\n locked_reason?: string | null;\n updated_at?: string;\n updated_by?: string | null;\n}\n\n/**\n * Minimal data-engine surface used by the SettingsService. Mirrors the\n * methods we actually call so we can stub it cleanly in tests without\n * pulling the whole `IDataEngine`.\n */\nexport interface SettingsEngine {\n find(\n objectName: string,\n opts: { where?: Record<string, unknown>; limit?: number; bypassTenantAudit?: boolean },\n ): Promise<any[]>;\n insert(\n objectName: string,\n data: Record<string, unknown>,\n opts?: { bypassTenantAudit?: boolean },\n ): Promise<any>;\n update(\n objectName: string,\n opts: {\n where: Record<string, unknown>;\n data: Record<string, unknown>;\n bypassTenantAudit?: boolean;\n },\n ): Promise<any>;\n delete?(objectName: string, opts: { where: Record<string, unknown> }): Promise<any>;\n}\n\n/** Optional audit hook — service-settings won't crash if absent. */\nexport interface SettingsAuditSink {\n record(entry: {\n namespace: string;\n key: string;\n scope: SpecifierScope;\n userId?: string;\n actor?: string;\n action: 'set' | 'reset';\n valueDigest: string;\n encrypted: boolean;\n requestId?: string;\n }): Promise<void> | void;\n}\n\n/**\n * Persistence hook for the `sys_secret` object — used by the secret\n * split introduced in Phase 3. When provided, `SettingsService` writes\n * encrypted specifier values via `ICryptoProvider` into `sys_secret`\n * and stores only the handle id in `sys_setting.value_enc`. When\n * absent, the legacy inline `crypto.encrypt → value_enc` path is used.\n */\nexport interface SettingsSecretStore {\n /** Insert a new secret row; returns the row id (handle id). */\n insert(row: {\n id: string;\n namespace: string;\n key: string;\n kms_key_id: string;\n alg: string;\n version: number;\n ciphertext: string;\n }): Promise<{ id: string }>;\n /** Look up the latest ciphertext for a handle id; null when missing. */\n get(id: string): Promise<{\n id: string;\n namespace: string;\n key: string;\n kms_key_id: string;\n alg: string;\n version: number;\n ciphertext: string;\n } | null>;\n /** Replace an existing secret row (used by rotateKey). */\n update(id: string, patch: {\n kms_key_id?: string;\n alg?: string;\n version?: number;\n ciphertext?: string;\n }): Promise<void>;\n}\n\n/**\n * Append-only writer for the `sys_setting_audit` object — Phase 3\n * audit trail. Distinct from `SettingsAuditSink` (which still writes\n * to the generic `sys_audit_log`) so audit consumers can subscribe\n * to settings activity without scanning the firehose.\n */\nexport interface SettingsAuditWriter {\n write(entry: {\n namespace: string;\n key: string;\n scope: SpecifierScope;\n action: 'set' | 'reset' | 'lock' | 'unlock' | 'rotate';\n source?: 'ui' | 'api' | 'migration' | 'import' | 'system';\n actorId?: string;\n oldHash?: string | null;\n newHash?: string | null;\n encrypted: boolean;\n requestId?: string;\n reason?: string;\n }): Promise<void> | void;\n}\n\n/** Action handler signature for `Specifier.type === 'action_button'`. */\nexport type SettingsActionHandler = (input: {\n namespace: string;\n actionId: string;\n values: Record<string, unknown>;\n payload?: unknown;\n ctx: SettingsContext;\n}) => Promise<SettingsActionResult> | SettingsActionResult;\n\nexport interface SettingsServiceOptions {\n /** Persistence engine. When undefined, an in-memory store is used. */\n engine?: SettingsEngine;\n /** Crypto adapter for `encrypted` values. Defaults to NoopCryptoAdapter. */\n crypto?: CryptoAdapter;\n /**\n * Phase 3 ICryptoProvider used together with `secretStore`. When both\n * are wired, encrypted writes flow to `sys_secret` and `value_enc`\n * holds the handle id. When omitted, the legacy inline `crypto`\n * adapter path remains in effect (back-compat).\n */\n cryptoProvider?: import('@objectstack/spec/contracts').ICryptoProvider;\n /** Phase 3 secret store backing the `sys_secret` object. */\n secretStore?: SettingsSecretStore;\n /** Audit sink. When undefined, writes still succeed but are not logged. */\n audit?: SettingsAuditSink;\n /** Phase 3 dedicated writer for `sys_setting_audit`. */\n auditWriter?: SettingsAuditWriter;\n /**\n * `process.env`-like map. Defaults to `process.env`. Injected so\n * unit tests can simulate locked values without polluting the host\n * environment.\n */\n env?: Record<string, string | undefined>;\n /** Object name backing the K/V store. Defaults to 'sys_setting'. */\n objectName?: string;\n}\n\n/**\n * Convert `(namespace, key)` to the env var convention defined in\n * ADR-0007: uppercase, dots → underscores, hyphens → underscores.\n */\nexport function envKeyOf(namespace: string, key: string): string {\n const slug = `${namespace}_${key}`.replace(/[.-]/g, '_').toUpperCase();\n return slug;\n}\n\n/** Thrown when a caller tries to write a value pinned by env. */\nexport class SettingsLockedError extends Error {\n readonly code = 'SETTINGS_LOCKED' as const;\n constructor(\n readonly namespace: string,\n readonly key: string,\n readonly reason = 'locked-by-env',\n ) {\n super(`Setting '${namespace}.${key}' is locked (${reason}).`);\n }\n}\n\n/** Thrown when the requested namespace has no registered manifest. */\nexport class UnknownNamespaceError extends Error {\n readonly code = 'SETTINGS_UNKNOWN_NAMESPACE' as const;\n constructor(readonly namespace: string) {\n super(`No settings manifest registered for namespace '${namespace}'.`);\n }\n}\n\n/** Thrown when a key isn't declared by the namespace's manifest. */\nexport class UnknownKeyError extends Error {\n readonly code = 'SETTINGS_UNKNOWN_KEY' as const;\n constructor(readonly namespace: string, readonly key: string) {\n super(`Key '${key}' is not declared in manifest '${namespace}'.`);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n SettingsManifest,\n ResolvedSettingValue,\n SettingsNamespacePayload,\n SettingsActionResult,\n SpecifierScope,\n SettingsChangeEvent,\n SettingsChangeHandler,\n SettingsUnsubscribe,\n} from '@objectstack/spec/system';\nimport {\n type CryptoAdapter,\n NoopCryptoAdapter,\n} from './crypto-adapter.js';\nimport {\n type SettingsActionHandler,\n type SettingsAuditSink,\n type SettingsContext,\n type SettingsEngine,\n type SettingsRow,\n type SettingsServiceOptions,\n envKeyOf,\n SettingsLockedError,\n UnknownKeyError,\n UnknownNamespaceError,\n} from './settings-service.types.js';\n\nconst DEFAULT_OBJECT = 'sys_setting';\n\n/**\n * Value-bearing specifier types — drives which entries we expect to\n * find in the K/V store. Keeps the resolver in sync with the spec\n * without importing the (large) Zod enum at runtime.\n */\nconst LAYOUT_ONLY_TYPES = new Set([\n 'group',\n 'info_banner',\n 'child_pane',\n 'title_value',\n 'action_button',\n]);\n\ninterface RegisteredManifest {\n manifest: SettingsManifest;\n /** Resolved specifier scopes for fast lookup. */\n scopes: Map<string, SpecifierScope>;\n /** Specifiers marked encrypted (or implicit for `password`). */\n encryptedKeys: Set<string>;\n /** Default values from the manifest, keyed by specifier key. */\n defaults: Map<string, unknown>;\n /** Action handlers registered alongside this manifest. */\n actions: Map<string, SettingsActionHandler>;\n}\n\n/**\n * Concrete SettingsService. See `src/settings-service.types.ts` for\n * the supporting types and `README.md` for the high-level contract.\n */\nexport class SettingsService {\n private engine?: SettingsEngine;\n private readonly crypto: CryptoAdapter;\n private cryptoProvider?: import('@objectstack/spec/contracts').ICryptoProvider;\n private secretStore?: import('./settings-service.types.js').SettingsSecretStore;\n private audit?: SettingsAuditSink;\n private auditWriter?: import('./settings-service.types.js').SettingsAuditWriter;\n private readonly env: Record<string, string | undefined>;\n private readonly objectName: string;\n private readonly registry = new Map<string, RegisteredManifest>();\n /** In-memory fallback when no engine is wired. */\n private readonly memory: SettingsRow[] = [];\n /** Change subscribers, optionally scoped to a namespace. */\n private readonly subscribers = new Set<{\n ns?: string;\n handler: SettingsChangeHandler;\n }>();\n\n constructor(opts: SettingsServiceOptions = {}) {\n this.engine = opts.engine;\n this.crypto = opts.crypto ?? new NoopCryptoAdapter();\n this.cryptoProvider = opts.cryptoProvider;\n this.secretStore = opts.secretStore;\n this.audit = opts.audit;\n this.auditWriter = opts.auditWriter;\n this.env = opts.env ?? (typeof process !== 'undefined' ? process.env : {});\n this.objectName = opts.objectName ?? DEFAULT_OBJECT;\n }\n\n /**\n * Late-bind a data engine and (optionally) an audit sink. Plugins\n * call this from `kernel:ready` once `objectql` is wired so the\n * SettingsService swaps from its in-memory fallback to the real\n * `sys_setting` table without re-registering the service.\n */\n bindEngine(\n engine: SettingsEngine,\n audit?: SettingsAuditSink,\n extras?: {\n secretStore?: import('./settings-service.types.js').SettingsSecretStore;\n auditWriter?: import('./settings-service.types.js').SettingsAuditWriter;\n cryptoProvider?: import('@objectstack/spec/contracts').ICryptoProvider;\n },\n ): void {\n this.engine = engine;\n if (audit) this.audit = audit;\n if (extras?.secretStore) this.secretStore = extras.secretStore;\n if (extras?.auditWriter) this.auditWriter = extras.auditWriter;\n if (extras?.cryptoProvider) this.cryptoProvider = extras.cryptoProvider;\n }\n\n /**\n * Cascade priority ranks for lock comparisons (lower = higher\n * precedence). env<global<tenant<user<default. A locked row at a\n * lower rank blocks writes at all higher ranks.\n */\n private scopeRank(scope: SpecifierScope | 'env' | 'default'): number {\n switch (scope) {\n case 'global': return 1;\n case 'tenant': return 2;\n case 'user': return 3;\n default: return 99;\n }\n }\n\n // ---------------------------------------------------------------------\n // Change events (Phase 1)\n // ---------------------------------------------------------------------\n\n /**\n * Subscribe to `settings:changed` events. When `namespace` is set the\n * handler only fires for that namespace, otherwise it fires for every\n * mutation across the service.\n *\n * Returns an idempotent unsubscribe handle — call it from the\n * consumer's shutdown hook to avoid leaks.\n */\n subscribe(\n namespace: string | undefined,\n handler: SettingsChangeHandler,\n ): SettingsUnsubscribe {\n const entry = { ns: namespace, handler };\n this.subscribers.add(entry);\n return () => {\n this.subscribers.delete(entry);\n };\n }\n\n /**\n * Dispatch a change event to all matching subscribers. Errors thrown\n * by a handler are swallowed to keep the bus crash-safe — handlers\n * are expected to enqueue async work themselves.\n */\n private emitChange(event: SettingsChangeEvent): void {\n if (this.subscribers.size === 0) return;\n for (const sub of this.subscribers) {\n if (sub.ns && sub.ns !== event.namespace) continue;\n try {\n sub.handler(event);\n } catch {\n // Swallow — never break the writer because a listener misbehaves.\n }\n }\n }\n\n // ---------------------------------------------------------------------\n // Manifest registry\n // ---------------------------------------------------------------------\n\n /** Register (or replace) a manifest. Idempotent. */\n registerManifest(manifest: SettingsManifest): void {\n const scopes = new Map<string, SpecifierScope>();\n const encryptedKeys = new Set<string>();\n const defaults = new Map<string, unknown>();\n const defaultScope = manifest.scope ?? 'tenant';\n for (const spec of manifest.specifiers) {\n if (!spec.key || LAYOUT_ONLY_TYPES.has(spec.type)) continue;\n scopes.set(spec.key, spec.scope ?? defaultScope);\n if (spec.encrypted || spec.type === 'password') encryptedKeys.add(spec.key);\n if (typeof spec.default !== 'undefined') defaults.set(spec.key, spec.default);\n }\n const prev = this.registry.get(manifest.namespace);\n const actions = prev?.actions ?? new Map<string, SettingsActionHandler>();\n this.registry.set(manifest.namespace, { manifest, scopes, encryptedKeys, defaults, actions });\n }\n\n /** Look up a manifest, or throw `UnknownNamespaceError`. */\n getManifest(namespace: string): SettingsManifest {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n return reg.manifest;\n }\n\n /** List all registered manifests, optionally filtered by permission. */\n listManifests(ctx: SettingsContext = {}): SettingsManifest[] {\n const perms = new Set(ctx.permissions ?? []);\n const all = Array.from(this.registry.values()).map((r) => r.manifest);\n // Empty permissions ⇒ pass-through (server-side trust, e.g. boot tests).\n if (perms.size === 0) return all;\n return all.filter((m) => perms.has(m.readPermission ?? 'setup.access'));\n }\n\n /** Register a handler for an `action_button` declared in a manifest. */\n registerAction(namespace: string, actionId: string, handler: SettingsActionHandler): void {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n reg.actions.set(actionId, handler);\n }\n\n // ---------------------------------------------------------------------\n // Resolver\n // ---------------------------------------------------------------------\n\n /** Resolve a single key. */\n async get<T = unknown>(\n namespace: string,\n key: string,\n ctx: SettingsContext = {},\n ): Promise<ResolvedSettingValue<T>> {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n if (!reg.scopes.has(key)) throw new UnknownKeyError(namespace, key);\n\n // 1. env\n const envName = envKeyOf(namespace, key);\n const envRaw = this.env[envName];\n if (typeof envRaw === 'string') {\n const def = reg.defaults.get(key);\n const value = coerceEnvValue(envRaw, def);\n return {\n value: value as T,\n source: 'env',\n locked: true,\n lockedReason: `Set via env: ${envName}`,\n cascadeChain: [\n { scope: 'env', value, locked: true, lockedReason: `Set via env: ${envName}`, effective: true },\n ],\n };\n }\n\n const scope = reg.scopes.get(key)!;\n // For 'user' scope we pre-filter by user_id; for 'tenant' and 'global'\n // we load everything for the namespace and pick the right row below.\n const rows = await this.loadRows(namespace, scope === 'user' ? ctx.userId ?? null : null);\n\n // 2. cascade walk — env (handled above) > global > tenant > user > default\n //\n // Build the full chain in declared order so the UI can render\n // \"Inherited from Global / Locked by Global / Overrides tenant\"\n // badges. The first non-null entry wins as `source`.\n const chain: NonNullable<ResolvedSettingValue['cascadeChain']> = [];\n\n const globalRow = rows.find((r) => r.key === key && r.scope === 'global');\n if (globalRow) {\n const value = await this.materialiseRow(globalRow);\n chain.push({\n scope: 'global',\n value,\n locked: !!globalRow.locked,\n lockedReason: globalRow.locked_reason ?? undefined,\n });\n }\n\n if (scope === 'tenant' || scope === 'user') {\n const tenantRow = rows.find((r) => r.key === key && r.scope === 'tenant');\n if (tenantRow) {\n chain.push({\n scope: 'tenant',\n value: await this.materialiseRow(tenantRow),\n locked: !!tenantRow.locked,\n lockedReason: tenantRow.locked_reason ?? undefined,\n });\n }\n }\n\n if (scope === 'user') {\n const userRow = rows.find((r) => r.key === key && r.scope === 'user');\n if (userRow) {\n chain.push({\n scope: 'user',\n value: await this.materialiseRow(userRow),\n });\n }\n }\n\n const def = reg.defaults.get(key);\n chain.push({ scope: 'default', value: def ?? null });\n\n // Effective row: highest priority entry. Lock anywhere up the chain\n // locks the effective value (lower scopes can't shadow it).\n const lockedEntry = chain.find((e) => e.locked === true);\n const effective = chain.find((e) => e.value !== null && e.value !== undefined) ?? chain[chain.length - 1];\n effective.effective = true;\n\n return {\n value: effective.value as T,\n source: effective.scope as ResolvedSettingValue['source'],\n locked: !!lockedEntry,\n lockedReason: lockedEntry?.lockedReason,\n cascadeChain: chain,\n };\n }\n\n /** Resolve every value in a namespace + return the manifest. */\n async getNamespace(\n namespace: string,\n ctx: SettingsContext = {},\n ): Promise<SettingsNamespacePayload> {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n\n const values: Record<string, ResolvedSettingValue> = {};\n for (const [key] of reg.scopes) {\n values[key] = await this.get(namespace, key, ctx);\n }\n return { manifest: reg.manifest, values };\n }\n\n // ---------------------------------------------------------------------\n // Reactive client (Phase 1)\n // ---------------------------------------------------------------------\n\n /**\n * Build a reactive `ISettingsClient` for a namespace.\n *\n * The client maintains an internal snapshot of the resolved values,\n * refreshing on every `settings:changed` event for the namespace.\n * Consumers call `current` / `get(key)` for synchronous reads and\n * register handlers via `onChange()`.\n *\n * `schema` is optional. When supplied, the snapshot is parsed (and\n * defaulted) through the Zod schema on each refresh — this gives\n * plugins strong types and runtime validation in one call. When\n * absent, raw resolved values flow through unchanged (used by the\n * dynamic console UI which validates per-field).\n */\n async createClient<T extends Record<string, unknown> = Record<string, unknown>>(\n namespace: string,\n opts: {\n ctx?: SettingsContext;\n parse?: (raw: Record<string, unknown>) => T;\n } = {},\n ): Promise<{\n readonly namespace: string;\n readonly current: T;\n get<K extends keyof T>(key: K): T[K];\n onChange(handler: SettingsChangeHandler): SettingsUnsubscribe;\n refresh(): Promise<void>;\n dispose(): void;\n }> {\n const ctx = opts.ctx ?? {};\n let snapshot: T = await this.snapshotOf<T>(namespace, ctx, opts.parse);\n\n const off = this.subscribe(namespace, () => {\n // Fire-and-forget refresh; new readers see the latest snapshot.\n void this.snapshotOf<T>(namespace, ctx, opts.parse).then((next) => {\n snapshot = next;\n });\n });\n\n return {\n namespace,\n get current() {\n return snapshot;\n },\n get<K extends keyof T>(key: K): T[K] {\n return snapshot[key];\n },\n onChange: (handler) => this.subscribe(namespace, handler),\n refresh: async () => {\n snapshot = await this.snapshotOf<T>(namespace, ctx, opts.parse);\n },\n dispose: off,\n };\n }\n\n private async snapshotOf<T>(\n namespace: string,\n ctx: SettingsContext,\n parse?: (raw: Record<string, unknown>) => T,\n ): Promise<T> {\n const payload = await this.getNamespace(namespace, ctx);\n const raw: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(payload.values)) raw[k] = v.value;\n return parse ? parse(raw) : (raw as T);\n }\n\n // ---------------------------------------------------------------------\n // Mutations\n // ---------------------------------------------------------------------\n\n /** Persist a single key. Throws SettingsLockedError when env-locked. */\n async set(\n namespace: string,\n key: string,\n value: unknown,\n ctx: SettingsContext = {},\n ): Promise<ResolvedSettingValue> {\n return (await this.setMany(namespace, { [key]: value }, ctx))[key];\n }\n\n /** Persist multiple keys atomically (best-effort). */\n async setMany(\n namespace: string,\n patch: Record<string, unknown>,\n ctx: SettingsContext = {},\n ): Promise<Record<string, ResolvedSettingValue>> {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n\n // Pre-flight: reject the whole batch if any key is locked or unknown.\n for (const key of Object.keys(patch)) {\n if (!reg.scopes.has(key)) throw new UnknownKeyError(namespace, key);\n const envRaw = this.env[envKeyOf(namespace, key)];\n if (typeof envRaw === 'string') throw new SettingsLockedError(namespace, key);\n\n // Phase 2 lock: a row at an upper scope marked locked=true\n // refuses writes at this (lower) scope. Writing AT the same\n // scope as the lock is still permitted (i.e. a platform admin\n // can edit a globally-locked value; a tenant admin cannot).\n const scope = reg.scopes.get(key)!;\n const rows = await this.loadRows(namespace, scope === 'user' ? ctx.userId ?? null : null);\n const upper = rows.find(\n (r) =>\n r.key === key &&\n r.locked === true &&\n this.scopeRank(r.scope) < this.scopeRank(scope),\n );\n if (upper) {\n throw new SettingsLockedError(namespace, key, `locked-by-${upper.scope}`);\n }\n }\n\n for (const [key, rawValue] of Object.entries(patch)) {\n const scope = reg.scopes.get(key)!;\n // global rows are platform-wide (tenant_id=null, user_id=null);\n // user rows pin to ctx.userId; tenant rows leave user_id null and\n // let the engine's tenant scoping fill in tenant_id from ctx.\n const userId = scope === 'user' ? ctx.userId ?? null : null;\n const isEncrypted = reg.encryptedKeys.has(key);\n const isNull = rawValue === null || typeof rawValue === 'undefined';\n\n let storedValue: unknown | null = null;\n let storedEnc: string | null = null;\n let digest = '';\n\n if (!isNull) {\n if (isEncrypted) {\n const plain = typeof rawValue === 'string' ? rawValue : JSON.stringify(rawValue);\n // Phase 3 split: when a sys_secret store + ICryptoProvider are\n // wired, persist the ciphertext in sys_secret and keep the\n // handle id in sys_setting.value_enc. Otherwise fall back to\n // the legacy inline crypto adapter path for back-compat.\n if (this.cryptoProvider && this.secretStore) {\n const handle = await this.cryptoProvider.encrypt(plain, {\n namespace,\n key,\n tenantId: ctx.tenantId,\n });\n await this.secretStore.insert({\n id: handle.id,\n namespace,\n key,\n kms_key_id: handle.kmsKeyId,\n alg: handle.alg,\n version: handle.version,\n ciphertext: handle.ciphertext,\n });\n storedEnc = handle.id;\n digest = this.cryptoProvider.digest(plain);\n } else {\n storedEnc = await this.crypto.encrypt(plain, { namespace, key });\n digest = this.crypto.digest(plain);\n }\n } else {\n storedValue = rawValue;\n digest = this.crypto.digest(stableStringify(rawValue));\n }\n }\n\n await this.upsertRow({\n namespace,\n key,\n scope,\n user_id: userId,\n value: storedValue,\n value_enc: storedEnc,\n encrypted: isEncrypted,\n updated_at: new Date().toISOString(),\n updated_by: ctx.userId ?? null,\n });\n\n if (this.audit) {\n await this.audit.record({\n namespace,\n key,\n scope,\n userId: ctx.userId,\n action: isNull ? 'reset' : 'set',\n valueDigest: isEncrypted ? '<encrypted:' + digest + '>' : digest,\n encrypted: isEncrypted,\n requestId: ctx.requestId,\n });\n }\n\n if (this.auditWriter) {\n try {\n await this.auditWriter.write({\n namespace,\n key,\n scope,\n action: isNull ? 'reset' : 'set',\n source: 'api',\n actorId: ctx.userId,\n oldHash: null,\n newHash: isNull ? null : digest,\n encrypted: isEncrypted,\n requestId: ctx.requestId,\n });\n } catch {\n // never fail a write because the audit table is unhappy.\n }\n }\n\n this.emitChange({\n namespace,\n key,\n scope,\n action: isNull ? 'reset' : 'set',\n at: new Date().toISOString(),\n });\n }\n\n // Re-resolve so callers see the post-write effective values.\n const out: Record<string, ResolvedSettingValue> = {};\n for (const key of Object.keys(patch)) {\n out[key] = await this.get(namespace, key, ctx);\n }\n return out;\n }\n\n /** Invoke a declared action (test connection, rotate, …). */\n async runAction(\n namespace: string,\n actionId: string,\n payload: unknown,\n ctx: SettingsContext = {},\n ): Promise<SettingsActionResult> {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n const handler = reg.actions.get(actionId);\n if (!handler) {\n return {\n ok: false,\n severity: 'error',\n message: `No handler registered for action '${actionId}' in '${namespace}'.`,\n };\n }\n const values: Record<string, unknown> = {};\n for (const [key] of reg.scopes) {\n values[key] = (await this.get(namespace, key, ctx)).value;\n }\n try {\n return await handler({ namespace, actionId, values, payload, ctx });\n } catch (err: any) {\n return {\n ok: false,\n severity: 'error',\n message: err?.message ?? 'Action handler threw.',\n };\n }\n }\n\n // ---------------------------------------------------------------------\n // Persistence helpers (engine or in-memory)\n // ---------------------------------------------------------------------\n\n private async loadRows(namespace: string, userId: string | null): Promise<SettingsRow[]> {\n if (this.engine) {\n const where: Record<string, unknown> = { namespace };\n if (userId !== null) where.user_id = userId;\n // Settings rows include platform-wide (`global` scope, tenant_id=null)\n // entries; bypass the tenant-scoping audit warning so loads work\n // uniformly across global/tenant/user without log noise. Per-tenant\n // isolation for `tenant`-scope rows is still enforced by the engine\n // once an ExecutionContext.tenantId is plumbed through (Phase 2+).\n const rows = await this.engine.find(this.objectName, {\n where,\n bypassTenantAudit: true,\n } as any);\n return rows.map((r) => ({\n namespace: r.namespace,\n key: r.key,\n scope: r.scope as SpecifierScope,\n user_id: r.user_id ?? null,\n value: r.value ?? null,\n value_enc: r.value_enc ?? null,\n encrypted: Boolean(r.encrypted),\n locked: Boolean(r.locked),\n locked_reason: r.locked_reason ?? null,\n updated_at: r.updated_at,\n updated_by: r.updated_by ?? null,\n }));\n }\n return this.memory.filter(\n (r) =>\n r.namespace === namespace &&\n (userId === null || r.user_id === userId || r.scope === 'tenant' || r.scope === 'global'),\n );\n }\n\n private async upsertRow(row: SettingsRow): Promise<void> {\n if (this.engine) {\n const where: Record<string, unknown> = {\n namespace: row.namespace,\n key: row.key,\n scope: row.scope,\n user_id: row.user_id ?? null,\n };\n // global rows are platform-wide — bypass the tenant audit warning\n // (we intentionally write tenant_id=null). tenant/user rows still\n // benefit from the warning when ctx.tenantId is missing.\n const bypass = row.scope === 'global' ? { bypassTenantAudit: true } : {};\n const existing = await this.engine.find(this.objectName, {\n where,\n limit: 1,\n ...bypass,\n } as any);\n if (existing[0]) {\n await this.engine.update(this.objectName, {\n where,\n data: { ...row },\n ...bypass,\n } as any);\n } else {\n await this.engine.insert(this.objectName, { ...row }, bypass as any);\n }\n return;\n }\n const idx = this.memory.findIndex(\n (r) =>\n r.namespace === row.namespace &&\n r.key === row.key &&\n r.scope === row.scope &&\n (r.user_id ?? null) === (row.user_id ?? null),\n );\n if (idx >= 0) this.memory[idx] = row;\n else this.memory.push(row);\n }\n\n private async materialiseRow(row: SettingsRow): Promise<unknown> {\n if (row.encrypted) {\n if (!row.value_enc) return null;\n let plain: string;\n // Phase 3: when the value_enc looks like a sys_secret handle and\n // both the secretStore + cryptoProvider are wired, dereference\n // through sys_secret. Otherwise (legacy rows or in-memory tests)\n // fall back to inline crypto-adapter decryption.\n if (\n this.cryptoProvider &&\n this.secretStore &&\n typeof row.value_enc === 'string' &&\n row.value_enc.startsWith('sec_')\n ) {\n const secret = await this.secretStore.get(row.value_enc);\n if (!secret) return null;\n plain = await this.cryptoProvider.decrypt(\n {\n id: secret.id,\n kmsKeyId: secret.kms_key_id,\n alg: secret.alg,\n version: secret.version,\n ciphertext: secret.ciphertext,\n },\n { namespace: row.namespace, key: row.key },\n );\n } else {\n plain = await this.crypto.decrypt(row.value_enc, {\n namespace: row.namespace,\n key: row.key,\n });\n }\n // Try JSON parse so non-string secrets round-trip.\n try {\n return JSON.parse(plain);\n } catch {\n return plain;\n }\n }\n return row.value ?? null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Local helpers\n// ---------------------------------------------------------------------------\n\n/** Stable stringify so the audit digest is order-independent. */\nfunction stableStringify(input: unknown): string {\n if (input === null || typeof input !== 'object') return JSON.stringify(input);\n if (Array.isArray(input)) return '[' + input.map(stableStringify).join(',') + ']';\n const obj = input as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n return '{' + keys.map((k) => JSON.stringify(k) + ':' + stableStringify(obj[k])).join(',') + '}';\n}\n\n/** Re-typed env coercer (the canonical one lives in settings-service.types). */\nfunction coerceEnvValue(raw: string, hint: unknown): unknown {\n if (typeof hint === 'boolean') return raw === 'true' || raw === '1' || raw === 'yes';\n if (typeof hint === 'number') {\n const n = Number(raw);\n return Number.isFinite(n) ? n : raw;\n }\n if (Array.isArray(hint) || (hint && typeof hint === 'object')) {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n }\n return raw;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n CryptoContext,\n CryptoHandle,\n ICryptoProvider,\n} from '@objectstack/spec/contracts';\nimport { createHash, randomBytes, createCipheriv, createDecipheriv } from 'node:crypto';\n\n/**\n * InMemoryCryptoProvider — default ICryptoProvider used by the\n * SettingsService when the host application does not wire a real KMS.\n *\n * Encryption: AES-256-GCM with a per-process random data key. The data\n * key lives only in memory; restarting the process loses the ability\n * to decrypt previously-written rows. This is intentional — operators\n * MUST replace this with a KMS-backed provider before relying on\n * `sys_secret` for production secrets. The provider's purpose is to:\n *\n * - exercise the round-trip in unit tests and dev kernels;\n * - provide a \"real-looking\" handle format so consumers don't depend\n * on accidental implementation details of a no-op adapter;\n * - serve as a reference for what AwsKmsCryptoProvider /\n * GcpKmsCryptoProvider implementations need to satisfy.\n *\n * Handle format:\n * id — `sec_` + 32 hex chars (122 bits of entropy)\n * kmsKeyId — `local:in-memory:v<version>`\n * alg — `aes-256-gcm`\n * version — bumps on rotateKey()\n * ciphertext— base64(iv (12) || authTag (16) || cipher)\n *\n * AAD binding: the CryptoContext (namespace + key + tenantId) is\n * folded into AES-GCM AAD so a ciphertext rewrapped from a different\n * (ns, key) tuple fails decryption — guards against operators\n * accidentally copying rows between namespaces.\n *\n * WebContainer (StackBlitz) note: `node:crypto.createCipheriv('aes-256-gcm', …)`\n * is not implemented in WebContainer. When we detect that runtime, we\n * swap to a pure-JS AES-GCM from `@noble/ciphers/aes.js`, producing the\n * same `iv || tag || ciphertext` byte layout so the handle shape is\n * unchanged. The swap is best-effort: if the dependency is missing,\n * we fall back to the Node implementation and let it throw, surfacing\n * the configuration problem clearly.\n */\nconst isWebContainerRuntime = (): boolean => {\n const g = globalThis as any;\n return (\n typeof g !== 'undefined' &&\n (Boolean(g.process?.versions?.webcontainer) ||\n Boolean(g.process?.env?.SHELL?.includes?.('jsh')) ||\n Boolean(g.process?.env?.STACKBLITZ))\n );\n};\n\ntype GcmFactory = (key: Uint8Array, nonce: Uint8Array, aad?: Uint8Array) => {\n encrypt: (plain: Uint8Array) => Uint8Array;\n decrypt: (cipher: Uint8Array) => Uint8Array;\n};\n\nlet nobleGcmPromise: Promise<GcmFactory | undefined> | undefined;\nconst loadNobleGcm = (): Promise<GcmFactory | undefined> => {\n if (!nobleGcmPromise) {\n nobleGcmPromise = (async () => {\n try {\n const mod = await import('@noble/ciphers/aes.js');\n return mod.gcm as unknown as GcmFactory;\n } catch (err: any) {\n console.warn(\n `[InMemoryCryptoProvider] WebContainer detected but @noble/ciphers not installed: ${err?.message ?? err}. Falling back to node:crypto (will throw).`,\n );\n return undefined;\n }\n })();\n }\n return nobleGcmPromise;\n};\n\nexport class InMemoryCryptoProvider implements ICryptoProvider {\n private readonly key: Buffer;\n private readonly useNoble: boolean;\n\n constructor(opts: { key?: Buffer } = {}) {\n this.key = opts.key ?? randomBytes(32);\n this.useNoble = isWebContainerRuntime();\n }\n\n async encrypt(plain: string, ctx: CryptoContext): Promise<CryptoHandle> {\n const iv = randomBytes(12);\n const aad = Buffer.from(this.aadOf(ctx), 'utf8');\n const plainBytes = Buffer.from(plain, 'utf8');\n\n let blob: string;\n if (this.useNoble) {\n const gcm = await loadNobleGcm();\n if (gcm) {\n const cipher = gcm(this.key, iv, aad);\n const ctWithTag = cipher.encrypt(plainBytes); // ciphertext || tag(16)\n const ct = ctWithTag.subarray(0, ctWithTag.length - 16);\n const tag = ctWithTag.subarray(ctWithTag.length - 16);\n blob = Buffer.concat([iv, Buffer.from(tag), Buffer.from(ct)]).toString('base64');\n } else {\n blob = this.encryptNode(plainBytes, iv, aad);\n }\n } else {\n blob = this.encryptNode(plainBytes, iv, aad);\n }\n\n return {\n id: 'sec_' + randomBytes(16).toString('hex'),\n kmsKeyId: 'local:in-memory:v1',\n alg: 'aes-256-gcm',\n version: 1,\n ciphertext: blob,\n };\n }\n\n async decrypt(handle: CryptoHandle, ctx: CryptoContext): Promise<string> {\n const buf = Buffer.from(handle.ciphertext, 'base64');\n const iv = buf.subarray(0, 12);\n const tag = buf.subarray(12, 28);\n const data = buf.subarray(28);\n const aad = Buffer.from(this.aadOf(ctx), 'utf8');\n\n if (this.useNoble) {\n const gcm = await loadNobleGcm();\n if (gcm) {\n const cipher = gcm(this.key, iv, aad);\n const ctWithTag = Buffer.concat([data, tag]); // noble expects ciphertext || tag\n const out = cipher.decrypt(ctWithTag);\n return Buffer.from(out).toString('utf8');\n }\n }\n const decipher = createDecipheriv('aes-256-gcm', this.key, iv);\n decipher.setAAD(aad);\n decipher.setAuthTag(tag);\n return Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8');\n }\n\n async rotateKey(handle: CryptoHandle, ctx: CryptoContext): Promise<CryptoHandle> {\n const plain = await this.decrypt(handle, ctx);\n const next = await this.encrypt(plain, ctx);\n return {\n ...next,\n id: handle.id,\n kmsKeyId: `local:in-memory:v${handle.version + 1}`,\n version: handle.version + 1,\n };\n }\n\n digest(plain: string): string {\n return 'sha256:' + createHash('sha256').update(plain, 'utf8').digest('hex');\n }\n\n private encryptNode(plainBytes: Buffer, iv: Buffer, aad: Buffer): string {\n const cipher = createCipheriv('aes-256-gcm', this.key, iv);\n cipher.setAAD(aad);\n const enc = Buffer.concat([cipher.update(plainBytes), cipher.final()]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, enc]).toString('base64');\n }\n\n private aadOf(ctx: CryptoContext): string {\n // Bind ciphertext to (namespace,key) so a row cannot be moved across\n // specifiers. Tenant binding is intentionally omitted because the\n // handle is dereferenced from a `sys_setting` row already scoped to\n // its tenant — adding tenant here would force the decrypt path to\n // re-read that scope.\n return [ctx.namespace, ctx.key].join('|');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * REST surface for the SettingsService — see ADR-0007 §REST.\n *\n * GET /api/settings → visible manifests\n * GET /api/settings/:namespace → { manifest, values }\n * PUT /api/settings/:namespace → batch upsert\n * POST /api/settings/:namespace/:actionId → invoke declared action\n *\n * The route layer is a thin wrapper that maps thrown service errors\n * into proper HTTP status codes; all business logic lives in\n * `SettingsService`.\n */\n\nimport type { IHttpServer, IHttpRequest, IHttpResponse, RouteHandler } from '@objectstack/spec/contracts';\nimport { SettingsService } from './settings-service.js';\nimport {\n SettingsLockedError,\n UnknownKeyError,\n UnknownNamespaceError,\n type SettingsContext,\n} from './settings-service.types.js';\n\nexport interface SettingsRoutesOptions {\n /** Base path. Default `/api/settings`. */\n basePath?: string;\n /**\n * Extract caller identity from the request. The default reads\n * `x-user-id` / `x-tenant-id` headers and parses\n * `x-permissions` as a comma-separated list — fine for dev and\n * straightforward to override in production wiring.\n */\n contextFromRequest?: (req: IHttpRequest) => SettingsContext;\n}\n\nconst defaultContext = (req: IHttpRequest): SettingsContext => {\n const header = (name: string): string | undefined => {\n const v = req.headers?.[name];\n return Array.isArray(v) ? v[0] : v;\n };\n const perms = header('x-permissions');\n return {\n userId: header('x-user-id'),\n tenantId: header('x-tenant-id'),\n permissions: perms ? perms.split(',').map((s) => s.trim()).filter(Boolean) : undefined,\n requestId: header('x-request-id'),\n };\n};\n\nfunction sendError(res: IHttpResponse, status: number, code: string, message: string, extra?: Record<string, unknown>) {\n res.status(status).json({ error: { code, message, ...extra } });\n}\n\nexport function registerSettingsRoutes(\n http: IHttpServer,\n service: SettingsService,\n opts: SettingsRoutesOptions = {},\n): void {\n const base = opts.basePath ?? '/api/settings';\n const ctxOf = opts.contextFromRequest ?? defaultContext;\n\n http.get(base, (async (req, res) => {\n try {\n const ctx = ctxOf(req);\n const manifests = service.listManifests(ctx);\n await res.json({ manifests });\n } catch (err: any) {\n sendError(res, 500, 'INTERNAL', err?.message ?? 'Failed to list manifests');\n }\n }) satisfies RouteHandler);\n\n http.get(`${base}/:namespace`, (async (req, res) => {\n const ns = req.params.namespace;\n try {\n const ctx = ctxOf(req);\n const payload = await service.getNamespace(ns, ctx);\n await res.json(payload);\n } catch (err: any) {\n if (err instanceof UnknownNamespaceError) {\n sendError(res, 404, 'UNKNOWN_NAMESPACE', err.message);\n } else {\n sendError(res, 500, 'INTERNAL', err?.message ?? 'Failed to read namespace');\n }\n }\n }) satisfies RouteHandler);\n\n http.put(`${base}/:namespace`, (async (req, res) => {\n const ns = req.params.namespace;\n const body = (req.body ?? {}) as Record<string, unknown>;\n try {\n const ctx = ctxOf(req);\n const result = await service.setMany(ns, body, ctx);\n await res.json({ values: result });\n } catch (err: any) {\n if (err instanceof SettingsLockedError) {\n sendError(res, 409, 'SETTINGS_LOCKED', err.message, {\n namespace: err.namespace,\n key: err.key,\n reason: err.reason,\n });\n } else if (err instanceof UnknownNamespaceError) {\n sendError(res, 404, 'UNKNOWN_NAMESPACE', err.message);\n } else if (err instanceof UnknownKeyError) {\n sendError(res, 400, 'UNKNOWN_KEY', err.message, { namespace: err.namespace, key: err.key });\n } else {\n sendError(res, 500, 'INTERNAL', err?.message ?? 'Failed to write namespace');\n }\n }\n }) satisfies RouteHandler);\n\n http.post(`${base}/:namespace/:actionId`, (async (req, res) => {\n const { namespace, actionId } = req.params;\n try {\n const ctx = ctxOf(req);\n const result = await service.runAction(namespace, actionId, req.body, ctx);\n const status = result.ok ? 200 : 400;\n await res.status(status).json(result);\n } catch (err: any) {\n if (err instanceof UnknownNamespaceError) {\n sendError(res, 404, 'UNKNOWN_NAMESPACE', err.message);\n } else {\n sendError(res, 500, 'INTERNAL', err?.message ?? 'Action failed');\n }\n }\n }) satisfies RouteHandler);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { SysSetting, SysSecret, SysSettingAudit } from '@objectstack/platform-objects/system';\n\nexport const SETTINGS_PLUGIN_ID = 'com.objectstack.service.settings';\nexport const SETTINGS_PLUGIN_VERSION = '0.1.0';\n\n/** Objects owned by service-settings. Currently just the K/V store. */\nexport const settingsObjects: any[] = [SysSetting, SysSecret, SysSettingAudit];\n\n/** Manifest header shared by compile-time config and runtime registration. */\nexport const settingsPluginManifestHeader = {\n id: SETTINGS_PLUGIN_ID,\n namespace: 'sys',\n version: SETTINGS_PLUGIN_VERSION,\n type: 'plugin' as const,\n scope: 'project' as const,\n name: 'Settings Service',\n description:\n 'Generic settings registry + K/V resolver with Env > Tenant > User > Default precedence. ADR-0007.',\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\nimport type { SettingsActionHandler } from '../settings-service.types.js';\n\n// Visibility expressions are written as inline strings here for\n// readability. The spec's ExpressionInputSchema accepts a bare string\n// and normalises it at parse time, but the inferred TypeScript output\n// type expects `{ dialect, source }` objects. Build the manifest as\n// `unknown` first, then cast — keeps the manifest source compact.\nconst manifest = {\n namespace: 'mail',\n version: 1,\n label: 'Mail Delivery',\n icon: 'Mail',\n description: 'SMTP and transactional email provider configuration.',\n scope: 'global',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Communication',\n order: 10,\n specifiers: [\n { type: 'group', id: 'provider', label: 'Provider', required: false,\n description: 'Choose how this workspace sends outbound email.' },\n\n { type: 'select', key: 'provider', label: 'Provider', required: true, default: 'smtp',\n options: [\n { value: 'smtp', label: 'SMTP' },\n { value: 'sendgrid', label: 'SendGrid' },\n { value: 'ses', label: 'Amazon SES' },\n { value: 'postmark', label: 'Postmark' },\n ],\n },\n\n { type: 'group', id: 'smtp', label: 'SMTP', required: false, visible: \"${data.provider === 'smtp'}\" },\n { type: 'text', key: 'smtp_host', label: 'Host', required: true,\n description: 'Example: smtp.example.com', visible: \"${data.provider === 'smtp'}\" },\n { type: 'number', key: 'smtp_port', label: 'Port', required: false, default: 587,\n min: 1, max: 65535, visible: \"${data.provider === 'smtp'}\" },\n { type: 'toggle', key: 'smtp_secure', label: 'Use TLS', required: false, default: true,\n visible: \"${data.provider === 'smtp'}\" },\n { type: 'text', key: 'smtp_user', label: 'Username', required: false,\n visible: \"${data.provider === 'smtp'}\" },\n { type: 'password', key: 'smtp_password', label: 'Password', required: false,\n visible: \"${data.provider === 'smtp'}\" },\n\n { type: 'group', id: 'api_key', label: 'API key', required: false, visible: \"${data.provider !== 'smtp'}\" },\n { type: 'password', key: 'api_key', label: 'API key', required: true, encrypted: true,\n visible: \"${data.provider !== 'smtp'}\" },\n\n { type: 'group', id: 'from_address', label: 'From address', required: false },\n { type: 'email', key: 'from_email', label: 'From email', required: true,\n description: 'Example: no-reply@example.com' },\n { type: 'text', key: 'from_name', label: 'From name', required: false, default: 'ObjectStack' },\n\n { type: 'action_button', id: 'test', label: 'Send test email', required: false, icon: 'Send',\n handler: { kind: 'http', method: 'POST', url: '/api/settings/mail/test' } },\n ],\n};\n\n/** Mail Delivery — SMTP / API provider configuration. */\nexport const mailSettingsManifest = manifest as unknown as SettingsManifest;\n\n/** Built-in action handler stub for `mail/test`. */\nexport const mailTestActionHandler: SettingsActionHandler = async ({ values }) => {\n const provider = String(values.provider ?? 'smtp');\n const fromEmail = values.from_email as string | undefined;\n if (!fromEmail) {\n return { ok: false, severity: 'error', message: 'Configure a from address before testing.' };\n }\n if (provider === 'smtp' && !values.smtp_host) {\n return { ok: false, severity: 'error', message: 'SMTP host is required.' };\n }\n if (provider !== 'smtp' && !values.api_key) {\n return { ok: false, severity: 'error', message: 'API key is required.' };\n }\n return {\n ok: true,\n severity: 'info',\n message: `Configuration looks valid (provider=${provider}). Wire @objectstack/plugin-mail for actual delivery.`,\n };\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\n\n/** Branding — workspace identity (name, logo, theme). */\nexport const brandingSettingsManifest: SettingsManifest = {\n namespace: 'branding',\n version: 1,\n label: 'Branding',\n icon: 'Palette',\n description: 'Workspace name, logo, and accent colour.',\n scope: 'tenant',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Workspace',\n order: 5,\n specifiers: [\n { type: 'group', id: 'identity', label: 'Identity', required: false },\n { type: 'text', key: 'workspace_name', label: 'Workspace name', required: true,\n default: 'ObjectStack', minLength: 1, maxLength: 60 },\n { type: 'email', key: 'support_email', label: 'Support email', required: false,\n description: 'Example: support@example.com' },\n\n { type: 'group', id: 'appearance', label: 'Appearance', required: false },\n { type: 'select', key: 'theme_mode', label: 'Default theme', required: false, default: 'system',\n options: [\n { value: 'light', label: 'Light' },\n { value: 'dark', label: 'Dark' },\n { value: 'system', label: 'Match system' },\n ],\n },\n { type: 'color', key: 'accent_color', label: 'Accent colour', required: false, default: '#6366f1' },\n { type: 'url', key: 'logo_url', label: 'Logo URL', required: false,\n description: 'Example: https://…/logo.svg' },\n ],\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\n\n/** Feature Flags — opt into experimental capabilities. */\nexport const featureFlagsSettingsManifest: SettingsManifest = {\n namespace: 'feature_flags',\n version: 1,\n label: 'Feature Flags',\n icon: 'FlaskConical',\n description: 'Toggle experimental and beta features for this workspace.',\n scope: 'tenant',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Beta',\n order: 100,\n beta: true,\n specifiers: [\n { type: 'info_banner', id: 'beta_notice', label: 'Heads up', required: false,\n bannerText:\n 'Beta features may change without notice. Pin via env vars (e.g. `FEATURE_FLAGS_AI_ENABLED=true`) to lock for the whole deployment.',\n bannerSeverity: 'warning' },\n\n { type: 'group', id: 'productivity', label: 'Productivity', required: false },\n { type: 'toggle', key: 'ai_enabled', label: 'AI Assistant', required: false, default: false,\n description: 'Enables the in-app AI assistant panel.' },\n { type: 'toggle', key: 'kanban_swimlanes', label: 'Kanban swimlanes', required: false, default: false },\n\n { type: 'group', id: 'collaboration', label: 'Collaboration', required: false },\n { type: 'toggle', key: 'realtime_cursors', label: 'Realtime cursors', required: false, default: false },\n { type: 'toggle', key: 'inline_comments', label: 'Inline comments', required: false, default: true },\n ],\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\nimport type { SettingsActionHandler } from '../settings-service.types.js';\n\n// Mirrors the shape of `mail.manifest.ts`. The actual adapter rebuild\n// + `storage/test` probe live in `@objectstack/service-storage`; this\n// manifest only declares the form + acts as a safe fallback when the\n// storage plugin is not present.\nconst manifest = {\n namespace: 'storage',\n version: 1,\n label: 'File Storage',\n icon: 'HardDrive',\n description:\n 'Backend used for attachments, exports, and user uploads. ' +\n '⚠ Switching adapter does not migrate existing files — files ' +\n 'uploaded under the previous adapter become unreachable through ' +\n 'the new one.',\n scope: 'global',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Infrastructure',\n order: 20,\n specifiers: [\n { type: 'group', id: 'adapter', label: 'Backend', required: false,\n description: 'Choose where uploaded files are stored.' },\n { type: 'select', key: 'adapter', label: 'Adapter', required: true, default: 'local',\n options: [\n { value: 'local', label: 'Local filesystem' },\n { value: 's3', label: 'S3 / S3-compatible' },\n ],\n },\n\n { type: 'group', id: 'local', label: 'Local', required: false,\n visible: \"${data.adapter === 'local'}\" },\n { type: 'text', key: 'local_root', label: 'Root directory', required: false,\n default: './.objectstack/data/uploads',\n description: 'Filesystem path under which files are stored. Relative paths resolve from the server CWD.',\n visible: \"${data.adapter === 'local'}\" },\n\n { type: 'group', id: 's3', label: 'S3', required: false,\n visible: \"${data.adapter === 's3'}\" },\n { type: 'text', key: 's3_bucket', label: 'Bucket', required: true,\n description: 'Shared host bucket. Per-environment files are namespaced via the projects/<environmentId>/ prefix.',\n visible: \"${data.adapter === 's3'}\" },\n { type: 'text', key: 's3_region', label: 'Region', required: true,\n description: 'Example: us-east-1',\n visible: \"${data.adapter === 's3'}\" },\n { type: 'text', key: 's3_endpoint', label: 'Endpoint', required: false,\n description: 'Custom endpoint for S3-compatible providers (R2, MinIO, Wasabi). Leave blank for AWS S3.',\n visible: \"${data.adapter === 's3'}\" },\n { type: 'text', key: 's3_access_key_id', label: 'Access key ID', required: true,\n visible: \"${data.adapter === 's3'}\" },\n { type: 'password', key: 's3_secret_access_key', label: 'Secret access key',\n required: true, encrypted: true,\n visible: \"${data.adapter === 's3'}\" },\n { type: 'toggle', key: 's3_force_path_style', label: 'Force path-style URLs',\n required: false, default: false,\n description: 'Enable for MinIO and most S3-compatible providers; disable for AWS S3.',\n visible: \"${data.adapter === 's3'}\" },\n\n { type: 'group', id: 'limits', label: 'Limits', required: false },\n { type: 'number', key: 'presigned_ttl', label: 'Presigned URL TTL (seconds)',\n required: false, default: 3600, min: 60, max: 604800 },\n { type: 'number', key: 'session_ttl', label: 'Upload session TTL (seconds)',\n required: false, default: 86400, min: 300, max: 604800,\n description: 'How long a chunked-upload session stays resumable.' },\n { type: 'number', key: 'max_upload_mb', label: 'Max upload size (MB)',\n required: false, default: 100, min: 1, max: 10240 },\n\n { type: 'action_button', id: 'test', label: 'Test connection',\n required: false, icon: 'Plug',\n handler: { kind: 'http', method: 'POST', url: '/api/settings/storage/test' } },\n ],\n};\n\n/** File Storage — local FS / S3-compatible backend configuration. */\nexport const storageSettingsManifest = manifest as unknown as SettingsManifest;\n\n/**\n * Built-in fallback action handler for `storage/test`. The real\n * implementation lives in `@objectstack/service-storage` and is\n * registered by `StorageServicePlugin` on `kernel:ready` (it overrides\n * this stub via `registerAction`). This fallback only validates the\n * form so the button is still useful when the storage plugin is\n * absent (e.g. in a unit-test kernel that mounts settings only).\n */\nexport const storageTestActionHandler: SettingsActionHandler = async ({ values }) => {\n const adapter = String(values.adapter ?? 'local');\n if (adapter === 'local') {\n const root = values.local_root as string | undefined;\n if (!root) {\n return { ok: false, severity: 'error', message: 'Configure a root directory before testing.' };\n }\n return {\n ok: true,\n severity: 'info',\n message: `Local adapter configured (root=${root}). Mount @objectstack/service-storage to exercise live I/O.`,\n };\n }\n if (adapter === 's3') {\n const missing: string[] = [];\n if (!values.s3_bucket) missing.push('s3_bucket');\n if (!values.s3_region) missing.push('s3_region');\n if (!values.s3_access_key_id) missing.push('s3_access_key_id');\n if (!values.s3_secret_access_key) missing.push('s3_secret_access_key');\n if (missing.length) {\n return { ok: false, severity: 'error', message: `Missing required field${missing.length > 1 ? 's' : ''}: ${missing.join(', ')}` };\n }\n return {\n ok: true,\n severity: 'info',\n message: `S3 adapter configured (bucket=${values.s3_bucket}, region=${values.s3_region}). Mount @objectstack/service-storage to exercise live I/O.`,\n };\n }\n return { ok: false, severity: 'error', message: `Unknown adapter: ${adapter}` };\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/** Reference manifests bundled with service-settings. */\nexport { mailSettingsManifest, mailTestActionHandler } from './mail.manifest.js';\nexport { brandingSettingsManifest } from './branding.manifest.js';\nexport { featureFlagsSettingsManifest } from './feature-flags.manifest.js';\nexport { storageSettingsManifest, storageTestActionHandler } from './storage.manifest.js';\n\nimport { mailSettingsManifest } from './mail.manifest.js';\nimport { brandingSettingsManifest } from './branding.manifest.js';\nimport { featureFlagsSettingsManifest } from './feature-flags.manifest.js';\nimport { storageSettingsManifest } from './storage.manifest.js';\n\n/** Convenience aggregate — pass to `SettingsServicePlugin({ manifests })`. */\nexport const builtinSettingsManifests = [\n brandingSettingsManifest,\n mailSettingsManifest,\n storageSettingsManifest,\n featureFlagsSettingsManifest,\n];\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\n/**\n * English (en) — built-in settings manifest translations.\n *\n * Mirrors literals in `manifests/{mail,branding,feature-flags,storage}.manifest.ts`.\n * Keeping them explicit here lets the resolver chain (locale → fallback → literal)\n * always have at least an English entry to fall back to.\n */\nexport const en: TranslationData = {\n settingsCommon: {\n sourceLabels: {\n env: 'Env',\n global: 'Global',\n tenant: 'Tenant',\n user: 'User',\n default: 'Default',\n },\n },\n settings: {\n mail: {\n title: 'Mail Delivery',\n description: 'SMTP and transactional email provider configuration.',\n groups: {\n provider: { title: 'Provider', description: 'Choose how this workspace sends outbound email.' },\n smtp: { title: 'SMTP' },\n api_key: { title: 'API key' },\n from_address: { title: 'From address' },\n },\n keys: {\n provider: {\n label: 'Provider',\n options: {\n smtp: 'SMTP',\n sendgrid: 'SendGrid',\n ses: 'Amazon SES',\n postmark: 'Postmark',\n },\n },\n smtp_host: { label: 'Host', help: 'Example: smtp.example.com' },\n smtp_port: { label: 'Port' },\n smtp_secure: { label: 'Use TLS' },\n smtp_user: { label: 'Username' },\n smtp_password: { label: 'Password' },\n api_key: { label: 'API key' },\n from_email: { label: 'From email', help: 'Example: no-reply@example.com' },\n from_name: { label: 'From name' },\n },\n actions: {\n test: { label: 'Send test email' },\n },\n },\n\n branding: {\n title: 'Branding',\n description: 'Workspace name, logo, and accent colour.',\n groups: {\n identity: { title: 'Identity' },\n appearance: { title: 'Appearance' },\n },\n keys: {\n workspace_name: { label: 'Workspace name' },\n support_email: { label: 'Support email', help: 'Example: support@example.com' },\n theme_mode: {\n label: 'Default theme',\n options: { light: 'Light', dark: 'Dark', system: 'Match system' },\n },\n accent_color: { label: 'Accent colour' },\n logo_url: { label: 'Logo URL', help: 'Example: https://…/logo.svg' },\n },\n },\n\n feature_flags: {\n title: 'Feature Flags',\n description: 'Toggle experimental and beta features for this workspace.',\n groups: {\n productivity: { title: 'Productivity' },\n collaboration: { title: 'Collaboration' },\n },\n keys: {\n ai_enabled: {\n label: 'AI Assistant',\n help: 'Enables the in-app AI assistant panel.',\n },\n kanban_swimlanes: { label: 'Kanban swimlanes' },\n realtime_cursors: { label: 'Realtime cursors' },\n inline_comments: { label: 'Inline comments' },\n },\n },\n\n storage: {\n title: 'File Storage',\n description:\n 'Backend used for attachments, exports, and user uploads. ' +\n '⚠ Switching adapter does not migrate existing files — files ' +\n 'uploaded under the previous adapter become unreachable through ' +\n 'the new one.',\n groups: {\n adapter: { title: 'Backend', description: 'Choose where uploaded files are stored.' },\n local: { title: 'Local' },\n s3: { title: 'S3' },\n limits: { title: 'Limits' },\n },\n keys: {\n adapter: {\n label: 'Adapter',\n options: { local: 'Local filesystem', s3: 'S3 / S3-compatible' },\n },\n local_root: { label: 'Root directory',\n help: 'Filesystem path under which files are stored. Relative paths resolve from the server CWD.' },\n s3_bucket: { label: 'Bucket',\n help: 'Shared host bucket. Per-environment files are namespaced via the projects/<environmentId>/ prefix.' },\n s3_region: { label: 'Region', help: 'Example: us-east-1' },\n s3_endpoint: { label: 'Endpoint',\n help: 'Custom endpoint for S3-compatible providers (R2, MinIO, Wasabi). Leave blank for AWS S3.' },\n s3_access_key_id: { label: 'Access key ID' },\n s3_secret_access_key: { label: 'Secret access key' },\n s3_force_path_style: { label: 'Force path-style URLs',\n help: 'Enable for MinIO and most S3-compatible providers; disable for AWS S3.' },\n presigned_ttl: { label: 'Presigned URL TTL (seconds)' },\n session_ttl: { label: 'Upload session TTL (seconds)',\n help: 'How long a chunked-upload session stays resumable.' },\n max_upload_mb: { label: 'Max upload size (MB)' },\n },\n actions: {\n test: { label: 'Test connection' },\n },\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\n/**\n * 简体中文 (zh-CN) — built-in settings manifest translations.\n */\nexport const zhCN: TranslationData = {\n settingsCommon: {\n sourceLabels: {\n env: '环境变量',\n global: '全局',\n tenant: '租户',\n user: '用户',\n default: '默认',\n },\n },\n settings: {\n mail: {\n title: '邮件投递',\n description: 'SMTP 与事务性邮件服务商配置。',\n groups: {\n provider: { title: '服务商', description: '选择此工作区如何发送邮件。' },\n smtp: { title: 'SMTP' },\n api_key: { title: 'API 密钥' },\n from_address: { title: '发件地址' },\n },\n keys: {\n provider: {\n label: '服务商',\n options: {\n smtp: 'SMTP',\n sendgrid: 'SendGrid',\n ses: 'Amazon SES',\n postmark: 'Postmark',\n },\n },\n smtp_host: { label: '主机', help: '示例:smtp.example.com' },\n smtp_port: { label: '端口' },\n smtp_secure: { label: '启用 TLS' },\n smtp_user: { label: '用户名' },\n smtp_password: { label: '密码' },\n api_key: { label: 'API 密钥' },\n from_email: { label: '发件地址', help: '示例:no-reply@example.com' },\n from_name: { label: '发件人名称' },\n },\n actions: {\n test: { label: '发送测试邮件' },\n },\n },\n\n branding: {\n title: '品牌',\n description: '工作区名称、Logo 与主题色。',\n groups: {\n identity: { title: '身份' },\n appearance: { title: '外观' },\n },\n keys: {\n workspace_name: { label: '工作区名称' },\n support_email: { label: '客服邮箱', help: '示例:support@example.com' },\n theme_mode: {\n label: '默认主题',\n options: { light: '浅色', dark: '深色', system: '跟随系统' },\n },\n accent_color: { label: '主题色' },\n logo_url: { label: 'Logo 链接', help: '示例:https://…/logo.svg' },\n },\n },\n\n feature_flags: {\n title: '功能开关',\n description: '为当前工作区开启实验性与测试功能。',\n groups: {\n productivity: { title: '生产力' },\n collaboration: { title: '协作' },\n },\n keys: {\n ai_enabled: {\n label: 'AI 助手',\n help: '启用应用内 AI 助手面板。',\n },\n kanban_swimlanes: { label: '看板泳道' },\n realtime_cursors: { label: '实时光标' },\n inline_comments: { label: '行内评论' },\n },\n },\n\n storage: {\n title: '文件存储',\n description:\n '附件、导出文件与用户上传所使用的存储后端。' +\n '⚠ 切换适配器不会迁移已有文件 —— 通过旧适配器上传的文件,在新适配器中将不可访问。',\n groups: {\n adapter: { title: '存储后端', description: '选择上传文件的存放位置。' },\n local: { title: '本地' },\n s3: { title: 'S3' },\n limits: { title: '限制' },\n },\n keys: {\n adapter: {\n label: '适配器',\n options: { local: '本地文件系统', s3: 'S3 / S3 兼容' },\n },\n local_root: { label: '根目录',\n help: '文件存放的文件系统路径。相对路径相对于服务进程的工作目录。' },\n s3_bucket: { label: 'Bucket',\n help: '共享主机 Bucket。各项目的文件通过 projects/<environmentId>/ 前缀进行隔离。' },\n s3_region: { label: '区域', help: '示例:us-east-1' },\n s3_endpoint: { label: 'Endpoint',\n help: 'S3 兼容服务(R2、MinIO、Wasabi)的自定义 Endpoint;AWS S3 请留空。' },\n s3_access_key_id: { label: 'Access Key ID' },\n s3_secret_access_key: { label: 'Secret Access Key' },\n s3_force_path_style: { label: '强制路径风格 URL',\n help: 'MinIO 与大多数 S3 兼容服务请开启;AWS S3 请关闭。' },\n presigned_ttl: { label: '预签名 URL 有效期(秒)' },\n session_ttl: { label: '分片上传会话有效期(秒)',\n help: '分片上传会话保持可续传的时长。' },\n max_upload_mb: { label: '单文件最大上传(MB)' },\n },\n actions: {\n test: { label: '测试连接' },\n },\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\n/**\n * 日本語 (ja-JP) — built-in settings manifest translations.\n */\nexport const jaJP: TranslationData = {\n settingsCommon: {\n sourceLabels: {\n env: '環境変数',\n global: 'グローバル',\n tenant: 'テナント',\n user: 'ユーザー',\n default: 'デフォルト',\n },\n },\n settings: {\n mail: {\n title: 'メール配信',\n description: 'SMTP およびトランザクションメールプロバイダー設定。',\n groups: {\n provider: { title: 'プロバイダー', description: 'このワークスペースの送信方法を選択します。' },\n smtp: { title: 'SMTP' },\n api_key: { title: 'API キー' },\n from_address: { title: '差出人アドレス' },\n },\n keys: {\n provider: {\n label: 'プロバイダー',\n options: {\n smtp: 'SMTP',\n sendgrid: 'SendGrid',\n ses: 'Amazon SES',\n postmark: 'Postmark',\n },\n },\n smtp_host: { label: 'ホスト', help: '例: smtp.example.com' },\n smtp_port: { label: 'ポート' },\n smtp_secure: { label: 'TLS を使用' },\n smtp_user: { label: 'ユーザー名' },\n smtp_password: { label: 'パスワード' },\n api_key: { label: 'API キー' },\n from_email: { label: '差出人アドレス', help: '例: no-reply@example.com' },\n from_name: { label: '差出人名' },\n },\n actions: {\n test: { label: 'テストメール送信' },\n },\n },\n\n branding: {\n title: 'ブランディング',\n description: 'ワークスペース名・ロゴ・アクセントカラー。',\n groups: {\n identity: { title: 'アイデンティティ' },\n appearance: { title: '外観' },\n },\n keys: {\n workspace_name: { label: 'ワークスペース名' },\n support_email: { label: 'サポートメール', help: '例: support@example.com' },\n theme_mode: {\n label: 'デフォルトテーマ',\n options: { light: 'ライト', dark: 'ダーク', system: 'システムに従う' },\n },\n accent_color: { label: 'アクセントカラー' },\n logo_url: { label: 'ロゴ URL', help: '例: https://…/logo.svg' },\n },\n },\n\n feature_flags: {\n title: '機能フラグ',\n description: 'このワークスペースで実験的・ベータ機能を切替えます。',\n groups: {\n productivity: { title: '生産性' },\n collaboration: { title: 'コラボレーション' },\n },\n keys: {\n ai_enabled: {\n label: 'AI アシスタント',\n help: 'アプリ内 AI アシスタントパネルを有効化します。',\n },\n kanban_swimlanes: { label: 'カンバンのスイムレーン' },\n realtime_cursors: { label: 'リアルタイムカーソル' },\n inline_comments: { label: 'インラインコメント' },\n },\n },\n\n storage: {\n title: 'ファイルストレージ',\n description:\n '添付ファイル・エクスポート・ユーザーアップロードに使用するバックエンド。' +\n '⚠ アダプターを切替えても既存ファイルは移行されません。以前のアダプターでアップロードされたファイルは新しいアダプターからアクセスできなくなります。',\n groups: {\n adapter: { title: 'バックエンド', description: 'アップロードファイルの保存先を選択します。' },\n local: { title: 'ローカル' },\n s3: { title: 'S3' },\n limits: { title: '制限' },\n },\n keys: {\n adapter: {\n label: 'アダプター',\n options: { local: 'ローカルファイルシステム', s3: 'S3 / S3 互換' },\n },\n local_root: { label: 'ルートディレクトリ',\n help: 'ファイルを保存するファイルシステムパス。相対パスはサーバーの CWD から解決されます。' },\n s3_bucket: { label: 'バケット',\n help: '共有ホストバケット。プロジェクト毎のファイルは projects/<environmentId>/ プレフィックスで分離されます。' },\n s3_region: { label: 'リージョン', help: '例: us-east-1' },\n s3_endpoint: { label: 'エンドポイント',\n help: 'S3 互換プロバイダ (R2, MinIO, Wasabi) のカスタムエンドポイント。AWS S3 の場合は空欄。' },\n s3_access_key_id: { label: 'アクセスキー ID' },\n s3_secret_access_key: { label: 'シークレットアクセスキー' },\n s3_force_path_style: { label: 'パススタイル URL を強制',\n help: 'MinIO や多くの S3 互換プロバイダで有効化。AWS S3 では無効化。' },\n presigned_ttl: { label: '署名付き URL の有効期間 (秒)' },\n session_ttl: { label: 'アップロードセッション TTL (秒)',\n help: 'チャンクアップロードの再開可能期間。' },\n max_upload_mb: { label: '最大アップロードサイズ (MB)' },\n },\n actions: {\n test: { label: '接続テスト' },\n },\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Built-in Settings translations.\n *\n * Mirrors the CRM example's `src/translations/{en,zh-CN,ja-JP}.ts` convention —\n * one file per locale, aggregated into a `TranslationBundle` here.\n *\n * Hosts merge `settingsBuiltinTranslations` into the i18next resource tree\n * under whatever namespace makes sense (the console wires it as `system`),\n * making keys resolvable as `<ns>.settings.<namespace>.{title,description,...}`.\n */\n\nimport type { TranslationBundle } from '@objectstack/spec/system';\nimport { en } from './en.js';\nimport { zhCN } from './zh-CN.js';\nimport { jaJP } from './ja-JP.js';\n\nexport { en, zhCN, jaJP };\n\nexport const settingsBuiltinTranslations: TranslationBundle = {\n en,\n 'zh-CN': zhCN,\n 'ja-JP': jaJP,\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { IHttpServer, IDataEngine } from '@objectstack/spec/contracts';\nimport type { SettingsManifest } from '@objectstack/spec/system';\nimport { SettingsService } from './settings-service.js';\nimport type { ICryptoProvider } from '@objectstack/spec/contracts';\nimport type { SettingsAuditSink, SettingsAuditWriter, SettingsEngine, SettingsSecretStore } from './settings-service.types.js';\nimport type { CryptoAdapter } from './crypto-adapter.js';\nimport { InMemoryCryptoProvider } from './in-memory-crypto-provider.js';\nimport { registerSettingsRoutes } from './settings-routes.js';\nimport {\n settingsObjects,\n settingsPluginManifestHeader,\n SETTINGS_PLUGIN_ID,\n SETTINGS_PLUGIN_VERSION,\n} from './manifest.js';\nimport {\n builtinSettingsManifests,\n mailTestActionHandler,\n storageTestActionHandler,\n} from './manifests/index.js';\nimport { settingsBuiltinTranslations } from './translations/index.js';\n\n/** Configuration options for the SettingsServicePlugin. */\nexport interface SettingsServicePluginOptions {\n /**\n * Pre-register these manifests at boot. When omitted, the bundled\n * builtin manifests (mail / branding / feature_flags) are loaded so\n * a host gets a working Settings hub out of the box. Pass an empty\n * array to opt out entirely.\n */\n manifests?: SettingsManifest[];\n /** Override the default crypto adapter. */\n crypto?: CryptoAdapter;\n\n /**\n * Phase 3 KMS hook. When provided, encrypted specifier values are\n * routed through this provider into `sys_secret`; `sys_setting.value_enc`\n * holds the handle id only. Defaults to `InMemoryCryptoProvider`\n * (NOT suitable for production secrets — replace with an AWS / GCP\n * KMS-backed implementation).\n */\n cryptoProvider?: ICryptoProvider;\n /** Override the default base path (`/api/settings`). */\n basePath?: string;\n /** Disable REST route registration. */\n registerRoutes?: boolean;\n /** Override the env source. Defaults to `process.env`. */\n env?: Record<string, string | undefined>;\n /**\n * Action handlers to register at boot, keyed by namespace and action\n * id. The bundled `mail.test` handler is registered automatically\n * unless this object is provided.\n */\n actionHandlers?: Record<string, Record<string, import('./settings-service.types.js').SettingsActionHandler>>;\n}\n\n/**\n * SettingsServicePlugin — wires the SettingsService into the kernel.\n *\n * 1. `init`: instantiate the service, register it under `'settings'`,\n * and ship `sys_setting` to the manifest service so the engine\n * auto-provisions the table.\n * 2. `start` → `kernel:ready`: bind the data engine (when present),\n * wire the audit sink (when present), mount REST routes.\n */\nexport class SettingsServicePlugin implements Plugin {\n name = SETTINGS_PLUGIN_ID;\n version = SETTINGS_PLUGIN_VERSION;\n type = 'standard' as const;\n\n private readonly opts: SettingsServicePluginOptions;\n private service: SettingsService | null = null;\n\n constructor(opts: SettingsServicePluginOptions = {}) {\n this.opts = {\n ...opts,\n manifests: opts.manifests ?? builtinSettingsManifests,\n actionHandlers: opts.actionHandlers ?? {\n mail: { test: mailTestActionHandler },\n storage: { test: storageTestActionHandler },\n },\n };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n this.service = new SettingsService({\n crypto: this.opts.crypto,\n env: this.opts.env,\n });\n for (const m of this.opts.manifests ?? []) this.service.registerManifest(m);\n for (const [ns, handlers] of Object.entries(this.opts.actionHandlers ?? {})) {\n for (const [id, fn] of Object.entries(handlers)) {\n this.service.registerAction(ns, id, fn);\n }\n }\n\n ctx.registerService('settings', this.service);\n ctx.logger?.info?.(\n `SettingsServicePlugin: registered (manifests=${this.opts.manifests?.length ?? 0})`,\n );\n\n // Register the K/V object so the engine creates the table.\n try {\n ctx.getService<{ register(m: any): void }>('manifest').register({\n ...settingsPluginManifestHeader,\n objects: settingsObjects,\n });\n } catch {\n // manifest service is optional — skip in lean test kernels.\n }\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (!this.service) return;\n\n ctx.hook('kernel:ready', async () => {\n // Contribute built-in settings translations into the i18n service.\n // Done in `kernel:ready` (not `init`) because the i18n service plugin\n // is typically registered AFTER capability-loaded service plugins.\n try {\n const i18n = ctx.getService<{\n loadTranslations: (locale: string, data: Record<string, unknown>) => void;\n }>('i18n');\n let loaded = 0;\n for (const [locale, data] of Object.entries(settingsBuiltinTranslations)) {\n if (data && typeof data === 'object') {\n try {\n i18n.loadTranslations(locale, data as Record<string, unknown>);\n loaded++;\n } catch (err: any) {\n ctx.logger?.warn?.(\n `SettingsServicePlugin: failed to load translations for '${locale}': ${err?.message ?? err}`,\n );\n }\n }\n }\n if (loaded > 0) {\n ctx.logger?.info?.(\n `SettingsServicePlugin: contributed built-in translations (${loaded} locale${loaded > 1 ? 's' : ''})`,\n );\n }\n } catch {\n // i18n service not registered — manifest literals remain authoritative.\n }\n\n // Late-bind the data engine.\n let engine: IDataEngine | null = null;\n try {\n engine = ctx.getService<IDataEngine>('objectql');\n } catch {\n // ok — fall back to in-memory.\n }\n if (engine) {\n // Late-bind the engine + audit sink on the existing service\n // instance. We avoid re-registering the service because the\n // kernel disallows `registerService` for an already-registered\n // name.\n this.service!.bindEngine(\n engine as unknown as SettingsEngine,\n this.buildAuditSink(ctx, engine),\n {\n secretStore: this.buildSecretStore(engine),\n auditWriter: this.buildAuditWriter(ctx, engine),\n cryptoProvider: this.opts.cryptoProvider ?? new InMemoryCryptoProvider(),\n },\n );\n }\n\n if (this.opts.registerRoutes === false) return;\n\n let http: IHttpServer | null = null;\n try {\n http = ctx.getService<IHttpServer>('http-server');\n } catch {\n // ok — no HTTP server in this deployment.\n }\n if (!http) {\n ctx.logger?.warn?.(\n 'SettingsServicePlugin: no HTTP server available — REST routes not registered. ' +\n 'SettingsService is still reachable via kernel.getService(\"settings\").',\n );\n return;\n }\n registerSettingsRoutes(http, this.service!, { basePath: this.opts.basePath });\n ctx.logger?.info?.(\n 'SettingsServicePlugin: REST routes registered at ' + (this.opts.basePath ?? '/api/settings'),\n );\n });\n }\n\n /** Glue an `engine.insert('sys_audit_log', …)` audit sink. */\n private buildAuditSink(ctx: PluginContext, engine: IDataEngine): SettingsAuditSink {\n return {\n record: async (entry) => {\n try {\n await (engine as any).insert?.('sys_audit_log', {\n actor_id: entry.userId ?? null,\n entity_type: 'sys_setting',\n entity_id: `${entry.namespace}.${entry.key}`,\n action: entry.action,\n payload: {\n namespace: entry.namespace,\n key: entry.key,\n scope: entry.scope,\n encrypted: entry.encrypted,\n digest: entry.valueDigest,\n },\n request_id: entry.requestId ?? null,\n occurred_at: new Date().toISOString(),\n });\n } catch (err: any) {\n ctx.logger?.warn?.('SettingsServicePlugin: audit record failed: ' + (err?.message ?? err));\n }\n },\n };\n }\n\n /**\n * Phase 3: build a `sys_secret`-backed implementation of\n * `SettingsSecretStore`. The store bypasses the tenant audit\n * warning because secrets are scoped through their owning\n * `sys_setting` row (which already carries the tenant context).\n */\n private buildSecretStore(engine: IDataEngine): SettingsSecretStore {\n const eng: any = engine;\n return {\n async insert(row) {\n await eng.insert('sys_secret', row, { bypassTenantAudit: true });\n return { id: row.id };\n },\n async get(id) {\n const rows = await eng.find('sys_secret', {\n where: { id },\n limit: 1,\n bypassTenantAudit: true,\n });\n const row = Array.isArray(rows) ? rows[0] : rows?.data?.[0];\n return row ?? null;\n },\n async update(id, patch) {\n await eng.update('sys_secret', {\n where: { id },\n data: patch,\n bypassTenantAudit: true,\n });\n },\n };\n }\n\n /**\n * Phase 3: append-only writer for `sys_setting_audit`. Failures here\n * MUST NOT abort the settings write, so all calls are wrapped in a\n * try/catch and reported through the plugin logger.\n */\n private buildAuditWriter(ctx: PluginContext, engine: IDataEngine): SettingsAuditWriter {\n const eng: any = engine;\n return {\n write: async (entry) => {\n try {\n await eng.insert('sys_setting_audit', {\n namespace: entry.namespace,\n key: entry.key,\n scope: entry.scope,\n action: entry.action,\n source: entry.source ?? 'api',\n actor_id: entry.actorId ?? null,\n old_hash: entry.oldHash ?? null,\n new_hash: entry.newHash ?? null,\n encrypted: !!entry.encrypted,\n request_id: entry.requestId ?? null,\n reason: entry.reason ?? null,\n created_at: new Date().toISOString(),\n }, { bypassTenantAudit: true });\n } catch (err: any) {\n ctx.logger?.warn?.('SettingsServicePlugin: setting-audit write failed: ' + (err?.message ?? err));\n }\n },\n };\n }\n}\n"],"mappings":"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","names":["manifest","def","manifest"]}
1
+ {"version":3,"sources":["../src/crypto-adapter.ts","../src/settings-service.types.ts","../src/settings-service.ts","../src/in-memory-crypto-provider.ts","../src/settings-routes.ts","../src/manifest.ts","../src/manifests/mail.manifest.ts","../src/manifests/branding.manifest.ts","../src/manifests/feature-flags.manifest.ts","../src/manifests/storage.manifest.ts","../src/manifests/ai.manifest.ts","../src/manifests/knowledge.manifest.ts","../src/manifests/index.ts","../src/translations/en.ts","../src/translations/zh-CN.ts","../src/translations/ja-JP.ts","../src/translations/index.ts","../src/settings-service-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Pluggable adapter for at-rest encryption of `Specifier.encrypted: true`\n * values. The default {@link NoopCryptoAdapter} provides a transparent\n * base64 wrapping suitable for development and tests; production\n * deployments MUST inject a real KMS-backed adapter.\n *\n * encrypt/decrypt are async to leave room for KMS round-trips.\n */\nexport interface CryptoAdapter {\n /** Returns the ciphertext blob to store in `sys_setting.value_enc`. */\n encrypt(plaintext: string, ctx: { namespace: string; key: string }): Promise<string>;\n /** Returns the plaintext used by the resolver. */\n decrypt(ciphertext: string, ctx: { namespace: string; key: string }): Promise<string>;\n /**\n * Stable, short, non-reversible digest used for audit-log entries so\n * operators can correlate value changes without leaking secrets.\n */\n digest(plaintext: string): string;\n}\n\n/**\n * Development / test default. Base64-wraps the plaintext so the column\n * isn't a literal mirror but provides no real confidentiality.\n *\n * Operators are expected to override this via\n * `SettingsServicePluginOptions.crypto`.\n */\nexport class NoopCryptoAdapter implements CryptoAdapter {\n async encrypt(plaintext: string): Promise<string> {\n return 'b64:' + Buffer.from(plaintext, 'utf8').toString('base64');\n }\n async decrypt(ciphertext: string): Promise<string> {\n if (!ciphertext.startsWith('b64:')) {\n // Tolerate legacy plaintext rows during the dev rollout.\n return ciphertext;\n }\n return Buffer.from(ciphertext.slice(4), 'base64').toString('utf8');\n }\n digest(plaintext: string): string {\n // FNV-1a 32-bit — short, stable, non-cryptographic. Audit-only.\n let h = 0x811c9dc5;\n for (let i = 0; i < plaintext.length; i++) {\n h ^= plaintext.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return 'fnv32:' + h.toString(16).padStart(8, '0');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * SettingsService — the runtime implementation of ADR-0007.\n *\n * Responsibilities:\n * - Maintain an in-memory registry of `SettingsManifest` instances.\n * - Read/write values from the shared `sys_setting` K/V table via the\n * `objectql` data engine, with an in-memory fallback so the service\n * is usable before a real persistence layer is wired up (e.g. unit\n * tests, bootstrap, control-plane mock).\n * - Resolve effective values with `Env > Tenant > User > Default`\n * precedence and tag every value with provenance.\n * - Encrypt-at-rest for `encrypted: true` specifiers using a pluggable\n * {@link CryptoAdapter}.\n * - Emit `sys_audit_log` rows for every successful write (encrypted\n * values are masked).\n * - Dispatch `runAction` for `action_button` specifiers — used by\n * \"Test connection\" / \"Send test email\" etc.\n *\n * The service is intentionally framework-agnostic: it doesn't import\n * the HTTP server, the plugin context, or the audit object schema. The\n * plugin wires those pieces up.\n */\n\nimport type { SettingsActionResult, SpecifierScope } from '@objectstack/spec/system';\nimport { type CryptoAdapter } from './crypto-adapter.js';\n\n/** Caller identity used by the resolver and audit log. */\nexport interface SettingsContext {\n /** Calling user id, when known. Required for `scope: 'user'` reads. */\n userId?: string;\n /** Tenant / project id. Reserved for multi-tenant deployments. */\n tenantId?: string;\n /** Permissions held by the caller (used by REST authz). */\n permissions?: string[];\n /** Source IP / request id for audit correlation. */\n requestId?: string;\n}\n\n/** Storage row shape used by both the engine and the in-memory store. */\nexport interface SettingsRow {\n namespace: string;\n key: string;\n scope: SpecifierScope;\n user_id: string | null;\n value: unknown | null;\n value_enc: string | null;\n encrypted: boolean;\n /**\n * When true, lower-scope rows for the same (namespace, key) are\n * read-only — the resolver still returns this row's value and the\n * mutation API throws `SettingsLockedError`. Only meaningful on\n * upper-scope rows (`global`, `tenant`). (Phase 2)\n */\n locked?: boolean;\n /** Human-readable reason the lock was applied (UI tooltip). */\n locked_reason?: string | null;\n updated_at?: string;\n updated_by?: string | null;\n}\n\n/**\n * Minimal data-engine surface used by the SettingsService. Mirrors the\n * methods we actually call so we can stub it cleanly in tests without\n * pulling the whole `IDataEngine`.\n */\nexport interface SettingsEngine {\n find(\n objectName: string,\n opts: { where?: Record<string, unknown>; limit?: number; bypassTenantAudit?: boolean },\n ): Promise<any[]>;\n insert(\n objectName: string,\n data: Record<string, unknown>,\n opts?: { bypassTenantAudit?: boolean },\n ): Promise<any>;\n update(\n objectName: string,\n opts: {\n where: Record<string, unknown>;\n data: Record<string, unknown>;\n bypassTenantAudit?: boolean;\n },\n ): Promise<any>;\n delete?(objectName: string, opts: { where: Record<string, unknown> }): Promise<any>;\n}\n\n/** Optional audit hook — service-settings won't crash if absent. */\nexport interface SettingsAuditSink {\n record(entry: {\n namespace: string;\n key: string;\n scope: SpecifierScope;\n userId?: string;\n actor?: string;\n action: 'set' | 'reset';\n valueDigest: string;\n encrypted: boolean;\n requestId?: string;\n }): Promise<void> | void;\n}\n\n/**\n * Persistence hook for the `sys_secret` object — used by the secret\n * split introduced in Phase 3. When provided, `SettingsService` writes\n * encrypted specifier values via `ICryptoProvider` into `sys_secret`\n * and stores only the handle id in `sys_setting.value_enc`. When\n * absent, the legacy inline `crypto.encrypt → value_enc` path is used.\n */\nexport interface SettingsSecretStore {\n /** Insert a new secret row; returns the row id (handle id). */\n insert(row: {\n id: string;\n namespace: string;\n key: string;\n kms_key_id: string;\n alg: string;\n version: number;\n ciphertext: string;\n }): Promise<{ id: string }>;\n /** Look up the latest ciphertext for a handle id; null when missing. */\n get(id: string): Promise<{\n id: string;\n namespace: string;\n key: string;\n kms_key_id: string;\n alg: string;\n version: number;\n ciphertext: string;\n } | null>;\n /** Replace an existing secret row (used by rotateKey). */\n update(id: string, patch: {\n kms_key_id?: string;\n alg?: string;\n version?: number;\n ciphertext?: string;\n }): Promise<void>;\n}\n\n/**\n * Append-only writer for the `sys_setting_audit` object — Phase 3\n * audit trail. Distinct from `SettingsAuditSink` (which still writes\n * to the generic `sys_audit_log`) so audit consumers can subscribe\n * to settings activity without scanning the firehose.\n */\nexport interface SettingsAuditWriter {\n write(entry: {\n namespace: string;\n key: string;\n scope: SpecifierScope;\n action: 'set' | 'reset' | 'lock' | 'unlock' | 'rotate';\n source?: 'ui' | 'api' | 'migration' | 'import' | 'system';\n actorId?: string;\n oldHash?: string | null;\n newHash?: string | null;\n encrypted: boolean;\n requestId?: string;\n reason?: string;\n }): Promise<void> | void;\n}\n\n/** Action handler signature for `Specifier.type === 'action_button'`. */\nexport type SettingsActionHandler = (input: {\n namespace: string;\n actionId: string;\n values: Record<string, unknown>;\n payload?: unknown;\n ctx: SettingsContext;\n}) => Promise<SettingsActionResult> | SettingsActionResult;\n\nexport interface SettingsServiceOptions {\n /** Persistence engine. When undefined, an in-memory store is used. */\n engine?: SettingsEngine;\n /** Crypto adapter for `encrypted` values. Defaults to NoopCryptoAdapter. */\n crypto?: CryptoAdapter;\n /**\n * Phase 3 ICryptoProvider used together with `secretStore`. When both\n * are wired, encrypted writes flow to `sys_secret` and `value_enc`\n * holds the handle id. When omitted, the legacy inline `crypto`\n * adapter path remains in effect (back-compat).\n */\n cryptoProvider?: import('@objectstack/spec/contracts').ICryptoProvider;\n /** Phase 3 secret store backing the `sys_secret` object. */\n secretStore?: SettingsSecretStore;\n /** Audit sink. When undefined, writes still succeed but are not logged. */\n audit?: SettingsAuditSink;\n /** Phase 3 dedicated writer for `sys_setting_audit`. */\n auditWriter?: SettingsAuditWriter;\n /**\n * `process.env`-like map. Defaults to `process.env`. Injected so\n * unit tests can simulate locked values without polluting the host\n * environment.\n */\n env?: Record<string, string | undefined>;\n /** Object name backing the K/V store. Defaults to 'sys_setting'. */\n objectName?: string;\n}\n\n/**\n * Convert `(namespace, key)` to the env var convention defined in\n * ADR-0007: uppercase, dots → underscores, hyphens → underscores.\n */\nexport function envKeyOf(namespace: string, key: string): string {\n const slug = `${namespace}_${key}`.replace(/[.-]/g, '_').toUpperCase();\n return slug;\n}\n\n/** Thrown when a caller tries to write a value pinned by env. */\nexport class SettingsLockedError extends Error {\n readonly code = 'SETTINGS_LOCKED' as const;\n constructor(\n readonly namespace: string,\n readonly key: string,\n readonly reason = 'locked-by-env',\n ) {\n super(`Setting '${namespace}.${key}' is locked (${reason}).`);\n }\n}\n\n/** Thrown when the requested namespace has no registered manifest. */\nexport class UnknownNamespaceError extends Error {\n readonly code = 'SETTINGS_UNKNOWN_NAMESPACE' as const;\n constructor(readonly namespace: string) {\n super(`No settings manifest registered for namespace '${namespace}'.`);\n }\n}\n\n/** Thrown when a key isn't declared by the namespace's manifest. */\nexport class UnknownKeyError extends Error {\n readonly code = 'SETTINGS_UNKNOWN_KEY' as const;\n constructor(readonly namespace: string, readonly key: string) {\n super(`Key '${key}' is not declared in manifest '${namespace}'.`);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n SettingsManifest,\n ResolvedSettingValue,\n SettingsNamespacePayload,\n SettingsActionResult,\n SpecifierScope,\n SettingsChangeEvent,\n SettingsChangeHandler,\n SettingsUnsubscribe,\n} from '@objectstack/spec/system';\nimport {\n type CryptoAdapter,\n NoopCryptoAdapter,\n} from './crypto-adapter.js';\nimport {\n type SettingsActionHandler,\n type SettingsAuditSink,\n type SettingsContext,\n type SettingsEngine,\n type SettingsRow,\n type SettingsServiceOptions,\n envKeyOf,\n SettingsLockedError,\n UnknownKeyError,\n UnknownNamespaceError,\n} from './settings-service.types.js';\n\nconst DEFAULT_OBJECT = 'sys_setting';\n\n/**\n * Value-bearing specifier types — drives which entries we expect to\n * find in the K/V store. Keeps the resolver in sync with the spec\n * without importing the (large) Zod enum at runtime.\n */\nconst LAYOUT_ONLY_TYPES = new Set([\n 'group',\n 'info_banner',\n 'child_pane',\n 'title_value',\n 'action_button',\n]);\n\ninterface RegisteredManifest {\n manifest: SettingsManifest;\n /** Resolved specifier scopes for fast lookup. */\n scopes: Map<string, SpecifierScope>;\n /** Specifiers marked encrypted (or implicit for `password`). */\n encryptedKeys: Set<string>;\n /** Default values from the manifest, keyed by specifier key. */\n defaults: Map<string, unknown>;\n /** Action handlers registered alongside this manifest. */\n actions: Map<string, SettingsActionHandler>;\n}\n\n/**\n * Concrete SettingsService. See `src/settings-service.types.ts` for\n * the supporting types and `README.md` for the high-level contract.\n */\nexport class SettingsService {\n private engine?: SettingsEngine;\n private readonly crypto: CryptoAdapter;\n private cryptoProvider?: import('@objectstack/spec/contracts').ICryptoProvider;\n private secretStore?: import('./settings-service.types.js').SettingsSecretStore;\n private audit?: SettingsAuditSink;\n private auditWriter?: import('./settings-service.types.js').SettingsAuditWriter;\n private readonly env: Record<string, string | undefined>;\n private readonly objectName: string;\n private readonly registry = new Map<string, RegisteredManifest>();\n /** In-memory fallback when no engine is wired. */\n private readonly memory: SettingsRow[] = [];\n /** Change subscribers, optionally scoped to a namespace. */\n private readonly subscribers = new Set<{\n ns?: string;\n handler: SettingsChangeHandler;\n }>();\n\n constructor(opts: SettingsServiceOptions = {}) {\n this.engine = opts.engine;\n this.crypto = opts.crypto ?? new NoopCryptoAdapter();\n this.cryptoProvider = opts.cryptoProvider;\n this.secretStore = opts.secretStore;\n this.audit = opts.audit;\n this.auditWriter = opts.auditWriter;\n this.env = opts.env ?? (typeof process !== 'undefined' ? process.env : {});\n this.objectName = opts.objectName ?? DEFAULT_OBJECT;\n }\n\n /**\n * Late-bind a data engine and (optionally) an audit sink. Plugins\n * call this from `kernel:ready` once `objectql` is wired so the\n * SettingsService swaps from its in-memory fallback to the real\n * `sys_setting` table without re-registering the service.\n */\n bindEngine(\n engine: SettingsEngine,\n audit?: SettingsAuditSink,\n extras?: {\n secretStore?: import('./settings-service.types.js').SettingsSecretStore;\n auditWriter?: import('./settings-service.types.js').SettingsAuditWriter;\n cryptoProvider?: import('@objectstack/spec/contracts').ICryptoProvider;\n },\n ): void {\n this.engine = engine;\n if (audit) this.audit = audit;\n if (extras?.secretStore) this.secretStore = extras.secretStore;\n if (extras?.auditWriter) this.auditWriter = extras.auditWriter;\n if (extras?.cryptoProvider) this.cryptoProvider = extras.cryptoProvider;\n }\n\n /**\n * Cascade priority ranks for lock comparisons (lower = higher\n * precedence). env<global<tenant<user<default. A locked row at a\n * lower rank blocks writes at all higher ranks.\n */\n private scopeRank(scope: SpecifierScope | 'env' | 'default'): number {\n switch (scope) {\n case 'global': return 1;\n case 'tenant': return 2;\n case 'user': return 3;\n default: return 99;\n }\n }\n\n // ---------------------------------------------------------------------\n // Change events (Phase 1)\n // ---------------------------------------------------------------------\n\n /**\n * Subscribe to `settings:changed` events. When `namespace` is set the\n * handler only fires for that namespace, otherwise it fires for every\n * mutation across the service.\n *\n * Returns an idempotent unsubscribe handle — call it from the\n * consumer's shutdown hook to avoid leaks.\n */\n subscribe(\n namespace: string | undefined,\n handler: SettingsChangeHandler,\n ): SettingsUnsubscribe {\n const entry = { ns: namespace, handler };\n this.subscribers.add(entry);\n return () => {\n this.subscribers.delete(entry);\n };\n }\n\n /**\n * Dispatch a change event to all matching subscribers. Errors thrown\n * by a handler are swallowed to keep the bus crash-safe — handlers\n * are expected to enqueue async work themselves.\n */\n private emitChange(event: SettingsChangeEvent): void {\n if (this.subscribers.size === 0) return;\n for (const sub of this.subscribers) {\n if (sub.ns && sub.ns !== event.namespace) continue;\n try {\n sub.handler(event);\n } catch {\n // Swallow — never break the writer because a listener misbehaves.\n }\n }\n }\n\n // ---------------------------------------------------------------------\n // Manifest registry\n // ---------------------------------------------------------------------\n\n /** Register (or replace) a manifest. Idempotent. */\n registerManifest(manifest: SettingsManifest): void {\n const scopes = new Map<string, SpecifierScope>();\n const encryptedKeys = new Set<string>();\n const defaults = new Map<string, unknown>();\n const defaultScope = manifest.scope ?? 'tenant';\n for (const spec of manifest.specifiers) {\n if (!spec.key || LAYOUT_ONLY_TYPES.has(spec.type)) continue;\n scopes.set(spec.key, spec.scope ?? defaultScope);\n if (spec.encrypted || spec.type === 'password') encryptedKeys.add(spec.key);\n if (typeof spec.default !== 'undefined') defaults.set(spec.key, spec.default);\n }\n const prev = this.registry.get(manifest.namespace);\n const actions = prev?.actions ?? new Map<string, SettingsActionHandler>();\n this.registry.set(manifest.namespace, { manifest, scopes, encryptedKeys, defaults, actions });\n }\n\n /** Look up a manifest, or throw `UnknownNamespaceError`. */\n getManifest(namespace: string): SettingsManifest {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n return reg.manifest;\n }\n\n /** List all registered manifests, optionally filtered by permission. */\n listManifests(ctx: SettingsContext = {}): SettingsManifest[] {\n const perms = new Set(ctx.permissions ?? []);\n const all = Array.from(this.registry.values()).map((r) => r.manifest);\n // Empty permissions ⇒ pass-through (server-side trust, e.g. boot tests).\n if (perms.size === 0) return all;\n return all.filter((m) => perms.has(m.readPermission ?? 'setup.access'));\n }\n\n /** Register a handler for an `action_button` declared in a manifest. */\n registerAction(namespace: string, actionId: string, handler: SettingsActionHandler): void {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n reg.actions.set(actionId, handler);\n }\n\n // ---------------------------------------------------------------------\n // Resolver\n // ---------------------------------------------------------------------\n\n /** Resolve a single key. */\n async get<T = unknown>(\n namespace: string,\n key: string,\n ctx: SettingsContext = {},\n ): Promise<ResolvedSettingValue<T>> {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n if (!reg.scopes.has(key)) throw new UnknownKeyError(namespace, key);\n\n // 1. env\n const envName = envKeyOf(namespace, key);\n const envRaw = this.env[envName];\n if (typeof envRaw === 'string') {\n const def = reg.defaults.get(key);\n const value = coerceEnvValue(envRaw, def);\n return {\n value: value as T,\n source: 'env',\n locked: true,\n lockedReason: `Set via env: ${envName}`,\n cascadeChain: [\n { scope: 'env', value, locked: true, lockedReason: `Set via env: ${envName}`, effective: true },\n ],\n };\n }\n\n const scope = reg.scopes.get(key)!;\n // For 'user' scope we pre-filter by user_id; for 'tenant' and 'global'\n // we load everything for the namespace and pick the right row below.\n const rows = await this.loadRows(namespace, scope === 'user' ? ctx.userId ?? null : null);\n\n // 2. cascade walk — env (handled above) > global > tenant > user > default\n //\n // Build the full chain in declared order so the UI can render\n // \"Inherited from Global / Locked by Global / Overrides tenant\"\n // badges. The first non-null entry wins as `source`.\n const chain: NonNullable<ResolvedSettingValue['cascadeChain']> = [];\n\n const globalRow = rows.find((r) => r.key === key && r.scope === 'global');\n if (globalRow) {\n const value = await this.materialiseRow(globalRow);\n chain.push({\n scope: 'global',\n value,\n locked: !!globalRow.locked,\n lockedReason: globalRow.locked_reason ?? undefined,\n });\n }\n\n if (scope === 'tenant' || scope === 'user') {\n const tenantRow = rows.find((r) => r.key === key && r.scope === 'tenant');\n if (tenantRow) {\n chain.push({\n scope: 'tenant',\n value: await this.materialiseRow(tenantRow),\n locked: !!tenantRow.locked,\n lockedReason: tenantRow.locked_reason ?? undefined,\n });\n }\n }\n\n if (scope === 'user') {\n const userRow = rows.find((r) => r.key === key && r.scope === 'user');\n if (userRow) {\n chain.push({\n scope: 'user',\n value: await this.materialiseRow(userRow),\n });\n }\n }\n\n const def = reg.defaults.get(key);\n chain.push({ scope: 'default', value: def ?? null });\n\n // Effective row: highest priority entry. Lock anywhere up the chain\n // locks the effective value (lower scopes can't shadow it).\n const lockedEntry = chain.find((e) => e.locked === true);\n const effective = chain.find((e) => e.value !== null && e.value !== undefined) ?? chain[chain.length - 1];\n effective.effective = true;\n\n return {\n value: effective.value as T,\n source: effective.scope as ResolvedSettingValue['source'],\n locked: !!lockedEntry,\n lockedReason: lockedEntry?.lockedReason,\n cascadeChain: chain,\n };\n }\n\n /** Resolve every value in a namespace + return the manifest. */\n async getNamespace(\n namespace: string,\n ctx: SettingsContext = {},\n ): Promise<SettingsNamespacePayload> {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n\n const values: Record<string, ResolvedSettingValue> = {};\n for (const [key] of reg.scopes) {\n values[key] = await this.get(namespace, key, ctx);\n }\n return { manifest: reg.manifest, values };\n }\n\n // ---------------------------------------------------------------------\n // Reactive client (Phase 1)\n // ---------------------------------------------------------------------\n\n /**\n * Build a reactive `ISettingsClient` for a namespace.\n *\n * The client maintains an internal snapshot of the resolved values,\n * refreshing on every `settings:changed` event for the namespace.\n * Consumers call `current` / `get(key)` for synchronous reads and\n * register handlers via `onChange()`.\n *\n * `schema` is optional. When supplied, the snapshot is parsed (and\n * defaulted) through the Zod schema on each refresh — this gives\n * plugins strong types and runtime validation in one call. When\n * absent, raw resolved values flow through unchanged (used by the\n * dynamic console UI which validates per-field).\n */\n async createClient<T extends Record<string, unknown> = Record<string, unknown>>(\n namespace: string,\n opts: {\n ctx?: SettingsContext;\n parse?: (raw: Record<string, unknown>) => T;\n } = {},\n ): Promise<{\n readonly namespace: string;\n readonly current: T;\n get<K extends keyof T>(key: K): T[K];\n onChange(handler: SettingsChangeHandler): SettingsUnsubscribe;\n refresh(): Promise<void>;\n dispose(): void;\n }> {\n const ctx = opts.ctx ?? {};\n let snapshot: T = await this.snapshotOf<T>(namespace, ctx, opts.parse);\n\n const off = this.subscribe(namespace, () => {\n // Fire-and-forget refresh; new readers see the latest snapshot.\n void this.snapshotOf<T>(namespace, ctx, opts.parse).then((next) => {\n snapshot = next;\n });\n });\n\n return {\n namespace,\n get current() {\n return snapshot;\n },\n get<K extends keyof T>(key: K): T[K] {\n return snapshot[key];\n },\n onChange: (handler) => this.subscribe(namespace, handler),\n refresh: async () => {\n snapshot = await this.snapshotOf<T>(namespace, ctx, opts.parse);\n },\n dispose: off,\n };\n }\n\n private async snapshotOf<T>(\n namespace: string,\n ctx: SettingsContext,\n parse?: (raw: Record<string, unknown>) => T,\n ): Promise<T> {\n const payload = await this.getNamespace(namespace, ctx);\n const raw: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(payload.values)) raw[k] = v.value;\n return parse ? parse(raw) : (raw as T);\n }\n\n // ---------------------------------------------------------------------\n // Mutations\n // ---------------------------------------------------------------------\n\n /** Persist a single key. Throws SettingsLockedError when env-locked. */\n async set(\n namespace: string,\n key: string,\n value: unknown,\n ctx: SettingsContext = {},\n ): Promise<ResolvedSettingValue> {\n return (await this.setMany(namespace, { [key]: value }, ctx))[key];\n }\n\n /** Persist multiple keys atomically (best-effort). */\n async setMany(\n namespace: string,\n patch: Record<string, unknown>,\n ctx: SettingsContext = {},\n ): Promise<Record<string, ResolvedSettingValue>> {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n\n // Pre-flight: reject the whole batch if any key is locked or unknown.\n for (const key of Object.keys(patch)) {\n if (!reg.scopes.has(key)) throw new UnknownKeyError(namespace, key);\n const envRaw = this.env[envKeyOf(namespace, key)];\n if (typeof envRaw === 'string') throw new SettingsLockedError(namespace, key);\n\n // Phase 2 lock: a row at an upper scope marked locked=true\n // refuses writes at this (lower) scope. Writing AT the same\n // scope as the lock is still permitted (i.e. a platform admin\n // can edit a globally-locked value; a tenant admin cannot).\n const scope = reg.scopes.get(key)!;\n const rows = await this.loadRows(namespace, scope === 'user' ? ctx.userId ?? null : null);\n const upper = rows.find(\n (r) =>\n r.key === key &&\n r.locked === true &&\n this.scopeRank(r.scope) < this.scopeRank(scope),\n );\n if (upper) {\n throw new SettingsLockedError(namespace, key, `locked-by-${upper.scope}`);\n }\n }\n\n for (const [key, rawValue] of Object.entries(patch)) {\n const scope = reg.scopes.get(key)!;\n // global rows are platform-wide (tenant_id=null, user_id=null);\n // user rows pin to ctx.userId; tenant rows leave user_id null and\n // let the engine's tenant scoping fill in tenant_id from ctx.\n const userId = scope === 'user' ? ctx.userId ?? null : null;\n const isEncrypted = reg.encryptedKeys.has(key);\n const isNull = rawValue === null || typeof rawValue === 'undefined';\n\n let storedValue: unknown | null = null;\n let storedEnc: string | null = null;\n let digest = '';\n\n if (!isNull) {\n if (isEncrypted) {\n const plain = typeof rawValue === 'string' ? rawValue : JSON.stringify(rawValue);\n // Phase 3 split: when a sys_secret store + ICryptoProvider are\n // wired, persist the ciphertext in sys_secret and keep the\n // handle id in sys_setting.value_enc. Otherwise fall back to\n // the legacy inline crypto adapter path for back-compat.\n if (this.cryptoProvider && this.secretStore) {\n const handle = await this.cryptoProvider.encrypt(plain, {\n namespace,\n key,\n tenantId: ctx.tenantId,\n });\n await this.secretStore.insert({\n id: handle.id,\n namespace,\n key,\n kms_key_id: handle.kmsKeyId,\n alg: handle.alg,\n version: handle.version,\n ciphertext: handle.ciphertext,\n });\n storedEnc = handle.id;\n digest = this.cryptoProvider.digest(plain);\n } else {\n storedEnc = await this.crypto.encrypt(plain, { namespace, key });\n digest = this.crypto.digest(plain);\n }\n } else {\n storedValue = rawValue;\n digest = this.crypto.digest(stableStringify(rawValue));\n }\n }\n\n await this.upsertRow({\n namespace,\n key,\n scope,\n user_id: userId,\n value: storedValue,\n value_enc: storedEnc,\n encrypted: isEncrypted,\n updated_at: new Date().toISOString(),\n updated_by: ctx.userId ?? null,\n });\n\n if (this.audit) {\n await this.audit.record({\n namespace,\n key,\n scope,\n userId: ctx.userId,\n action: isNull ? 'reset' : 'set',\n valueDigest: isEncrypted ? '<encrypted:' + digest + '>' : digest,\n encrypted: isEncrypted,\n requestId: ctx.requestId,\n });\n }\n\n if (this.auditWriter) {\n try {\n await this.auditWriter.write({\n namespace,\n key,\n scope,\n action: isNull ? 'reset' : 'set',\n source: 'api',\n actorId: ctx.userId,\n oldHash: null,\n newHash: isNull ? null : digest,\n encrypted: isEncrypted,\n requestId: ctx.requestId,\n });\n } catch {\n // never fail a write because the audit table is unhappy.\n }\n }\n\n this.emitChange({\n namespace,\n key,\n scope,\n action: isNull ? 'reset' : 'set',\n at: new Date().toISOString(),\n });\n }\n\n // Re-resolve so callers see the post-write effective values.\n const out: Record<string, ResolvedSettingValue> = {};\n for (const key of Object.keys(patch)) {\n out[key] = await this.get(namespace, key, ctx);\n }\n return out;\n }\n\n /** Invoke a declared action (test connection, rotate, …). */\n async runAction(\n namespace: string,\n actionId: string,\n payload: unknown,\n ctx: SettingsContext = {},\n ): Promise<SettingsActionResult> {\n const reg = this.registry.get(namespace);\n if (!reg) throw new UnknownNamespaceError(namespace);\n const handler = reg.actions.get(actionId);\n if (!handler) {\n return {\n ok: false,\n severity: 'error',\n message: `No handler registered for action '${actionId}' in '${namespace}'.`,\n };\n }\n const values: Record<string, unknown> = {};\n for (const [key] of reg.scopes) {\n values[key] = (await this.get(namespace, key, ctx)).value;\n }\n try {\n return await handler({ namespace, actionId, values, payload, ctx });\n } catch (err: any) {\n return {\n ok: false,\n severity: 'error',\n message: err?.message ?? 'Action handler threw.',\n };\n }\n }\n\n // ---------------------------------------------------------------------\n // Persistence helpers (engine or in-memory)\n // ---------------------------------------------------------------------\n\n private async loadRows(namespace: string, userId: string | null): Promise<SettingsRow[]> {\n if (this.engine) {\n const where: Record<string, unknown> = { namespace };\n if (userId !== null) where.user_id = userId;\n // Settings rows include platform-wide (`global` scope, tenant_id=null)\n // entries; bypass the tenant-scoping audit warning so loads work\n // uniformly across global/tenant/user without log noise. Per-tenant\n // isolation for `tenant`-scope rows is still enforced by the engine\n // once an ExecutionContext.tenantId is plumbed through (Phase 2+).\n const rows = await this.engine.find(this.objectName, {\n where,\n bypassTenantAudit: true,\n } as any);\n return rows.map((r) => ({\n namespace: r.namespace,\n key: r.key,\n scope: r.scope as SpecifierScope,\n user_id: r.user_id ?? null,\n value: r.value ?? null,\n value_enc: r.value_enc ?? null,\n encrypted: Boolean(r.encrypted),\n locked: Boolean(r.locked),\n locked_reason: r.locked_reason ?? null,\n updated_at: r.updated_at,\n updated_by: r.updated_by ?? null,\n }));\n }\n return this.memory.filter(\n (r) =>\n r.namespace === namespace &&\n (userId === null || r.user_id === userId || r.scope === 'tenant' || r.scope === 'global'),\n );\n }\n\n private async upsertRow(row: SettingsRow): Promise<void> {\n if (this.engine) {\n const where: Record<string, unknown> = {\n namespace: row.namespace,\n key: row.key,\n scope: row.scope,\n user_id: row.user_id ?? null,\n };\n // global rows are platform-wide — bypass the tenant audit warning\n // (we intentionally write tenant_id=null). tenant/user rows still\n // benefit from the warning when ctx.tenantId is missing.\n const bypass = row.scope === 'global' ? { bypassTenantAudit: true } : {};\n const existing = await this.engine.find(this.objectName, {\n where,\n limit: 1,\n ...bypass,\n } as any);\n if (existing[0]) {\n await this.engine.update(this.objectName, {\n where,\n data: { ...row },\n ...bypass,\n } as any);\n } else {\n await this.engine.insert(this.objectName, { ...row }, bypass as any);\n }\n return;\n }\n const idx = this.memory.findIndex(\n (r) =>\n r.namespace === row.namespace &&\n r.key === row.key &&\n r.scope === row.scope &&\n (r.user_id ?? null) === (row.user_id ?? null),\n );\n if (idx >= 0) this.memory[idx] = row;\n else this.memory.push(row);\n }\n\n private async materialiseRow(row: SettingsRow): Promise<unknown> {\n if (row.encrypted) {\n if (!row.value_enc) return null;\n let plain: string;\n // Phase 3: when the value_enc looks like a sys_secret handle and\n // both the secretStore + cryptoProvider are wired, dereference\n // through sys_secret. Otherwise (legacy rows or in-memory tests)\n // fall back to inline crypto-adapter decryption.\n if (\n this.cryptoProvider &&\n this.secretStore &&\n typeof row.value_enc === 'string' &&\n row.value_enc.startsWith('sec_')\n ) {\n const secret = await this.secretStore.get(row.value_enc);\n if (!secret) return null;\n plain = await this.cryptoProvider.decrypt(\n {\n id: secret.id,\n kmsKeyId: secret.kms_key_id,\n alg: secret.alg,\n version: secret.version,\n ciphertext: secret.ciphertext,\n },\n { namespace: row.namespace, key: row.key },\n );\n } else {\n plain = await this.crypto.decrypt(row.value_enc, {\n namespace: row.namespace,\n key: row.key,\n });\n }\n // Try JSON parse so non-string secrets round-trip.\n try {\n return JSON.parse(plain);\n } catch {\n return plain;\n }\n }\n return row.value ?? null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Local helpers\n// ---------------------------------------------------------------------------\n\n/** Stable stringify so the audit digest is order-independent. */\nfunction stableStringify(input: unknown): string {\n if (input === null || typeof input !== 'object') return JSON.stringify(input);\n if (Array.isArray(input)) return '[' + input.map(stableStringify).join(',') + ']';\n const obj = input as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n return '{' + keys.map((k) => JSON.stringify(k) + ':' + stableStringify(obj[k])).join(',') + '}';\n}\n\n/** Re-typed env coercer (the canonical one lives in settings-service.types). */\nfunction coerceEnvValue(raw: string, hint: unknown): unknown {\n if (typeof hint === 'boolean') return raw === 'true' || raw === '1' || raw === 'yes';\n if (typeof hint === 'number') {\n const n = Number(raw);\n return Number.isFinite(n) ? n : raw;\n }\n if (Array.isArray(hint) || (hint && typeof hint === 'object')) {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n }\n return raw;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n CryptoContext,\n CryptoHandle,\n ICryptoProvider,\n} from '@objectstack/spec/contracts';\nimport { createHash, randomBytes, createCipheriv, createDecipheriv } from 'node:crypto';\n\n/**\n * InMemoryCryptoProvider — default ICryptoProvider used by the\n * SettingsService when the host application does not wire a real KMS.\n *\n * Encryption: AES-256-GCM with a per-process random data key. The data\n * key lives only in memory; restarting the process loses the ability\n * to decrypt previously-written rows. This is intentional — operators\n * MUST replace this with a KMS-backed provider before relying on\n * `sys_secret` for production secrets. The provider's purpose is to:\n *\n * - exercise the round-trip in unit tests and dev kernels;\n * - provide a \"real-looking\" handle format so consumers don't depend\n * on accidental implementation details of a no-op adapter;\n * - serve as a reference for what AwsKmsCryptoProvider /\n * GcpKmsCryptoProvider implementations need to satisfy.\n *\n * Handle format:\n * id — `sec_` + 32 hex chars (122 bits of entropy)\n * kmsKeyId — `local:in-memory:v<version>`\n * alg — `aes-256-gcm`\n * version — bumps on rotateKey()\n * ciphertext— base64(iv (12) || authTag (16) || cipher)\n *\n * AAD binding: the CryptoContext (namespace + key + tenantId) is\n * folded into AES-GCM AAD so a ciphertext rewrapped from a different\n * (ns, key) tuple fails decryption — guards against operators\n * accidentally copying rows between namespaces.\n *\n * WebContainer (StackBlitz) note: `node:crypto.createCipheriv('aes-256-gcm', …)`\n * is not implemented in WebContainer. When we detect that runtime, we\n * swap to a pure-JS AES-GCM from `@noble/ciphers/aes.js`, producing the\n * same `iv || tag || ciphertext` byte layout so the handle shape is\n * unchanged. The swap is best-effort: if the dependency is missing,\n * we fall back to the Node implementation and let it throw, surfacing\n * the configuration problem clearly.\n */\nconst isWebContainerRuntime = (): boolean => {\n const g = globalThis as any;\n return (\n typeof g !== 'undefined' &&\n (Boolean(g.process?.versions?.webcontainer) ||\n Boolean(g.process?.env?.SHELL?.includes?.('jsh')) ||\n Boolean(g.process?.env?.STACKBLITZ))\n );\n};\n\ntype GcmFactory = (key: Uint8Array, nonce: Uint8Array, aad?: Uint8Array) => {\n encrypt: (plain: Uint8Array) => Uint8Array;\n decrypt: (cipher: Uint8Array) => Uint8Array;\n};\n\nlet nobleGcmPromise: Promise<GcmFactory | undefined> | undefined;\nconst loadNobleGcm = (): Promise<GcmFactory | undefined> => {\n if (!nobleGcmPromise) {\n nobleGcmPromise = (async () => {\n try {\n const mod = await import('@noble/ciphers/aes.js');\n return mod.gcm as unknown as GcmFactory;\n } catch (err: any) {\n console.warn(\n `[InMemoryCryptoProvider] WebContainer detected but @noble/ciphers not installed: ${err?.message ?? err}. Falling back to node:crypto (will throw).`,\n );\n return undefined;\n }\n })();\n }\n return nobleGcmPromise;\n};\n\nexport class InMemoryCryptoProvider implements ICryptoProvider {\n private readonly key: Buffer;\n private readonly useNoble: boolean;\n\n constructor(opts: { key?: Buffer } = {}) {\n this.key = opts.key ?? randomBytes(32);\n this.useNoble = isWebContainerRuntime();\n }\n\n async encrypt(plain: string, ctx: CryptoContext): Promise<CryptoHandle> {\n const iv = randomBytes(12);\n const aad = Buffer.from(this.aadOf(ctx), 'utf8');\n const plainBytes = Buffer.from(plain, 'utf8');\n\n let blob: string;\n if (this.useNoble) {\n const gcm = await loadNobleGcm();\n if (gcm) {\n const cipher = gcm(this.key, iv, aad);\n const ctWithTag = cipher.encrypt(plainBytes); // ciphertext || tag(16)\n const ct = ctWithTag.subarray(0, ctWithTag.length - 16);\n const tag = ctWithTag.subarray(ctWithTag.length - 16);\n blob = Buffer.concat([iv, Buffer.from(tag), Buffer.from(ct)]).toString('base64');\n } else {\n blob = this.encryptNode(plainBytes, iv, aad);\n }\n } else {\n blob = this.encryptNode(plainBytes, iv, aad);\n }\n\n return {\n id: 'sec_' + randomBytes(16).toString('hex'),\n kmsKeyId: 'local:in-memory:v1',\n alg: 'aes-256-gcm',\n version: 1,\n ciphertext: blob,\n };\n }\n\n async decrypt(handle: CryptoHandle, ctx: CryptoContext): Promise<string> {\n const buf = Buffer.from(handle.ciphertext, 'base64');\n const iv = buf.subarray(0, 12);\n const tag = buf.subarray(12, 28);\n const data = buf.subarray(28);\n const aad = Buffer.from(this.aadOf(ctx), 'utf8');\n\n if (this.useNoble) {\n const gcm = await loadNobleGcm();\n if (gcm) {\n const cipher = gcm(this.key, iv, aad);\n const ctWithTag = Buffer.concat([data, tag]); // noble expects ciphertext || tag\n const out = cipher.decrypt(ctWithTag);\n return Buffer.from(out).toString('utf8');\n }\n }\n const decipher = createDecipheriv('aes-256-gcm', this.key, iv);\n decipher.setAAD(aad);\n decipher.setAuthTag(tag);\n return Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8');\n }\n\n async rotateKey(handle: CryptoHandle, ctx: CryptoContext): Promise<CryptoHandle> {\n const plain = await this.decrypt(handle, ctx);\n const next = await this.encrypt(plain, ctx);\n return {\n ...next,\n id: handle.id,\n kmsKeyId: `local:in-memory:v${handle.version + 1}`,\n version: handle.version + 1,\n };\n }\n\n digest(plain: string): string {\n return 'sha256:' + createHash('sha256').update(plain, 'utf8').digest('hex');\n }\n\n private encryptNode(plainBytes: Buffer, iv: Buffer, aad: Buffer): string {\n const cipher = createCipheriv('aes-256-gcm', this.key, iv);\n cipher.setAAD(aad);\n const enc = Buffer.concat([cipher.update(plainBytes), cipher.final()]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, enc]).toString('base64');\n }\n\n private aadOf(ctx: CryptoContext): string {\n // Bind ciphertext to (namespace,key) so a row cannot be moved across\n // specifiers. Tenant binding is intentionally omitted because the\n // handle is dereferenced from a `sys_setting` row already scoped to\n // its tenant — adding tenant here would force the decrypt path to\n // re-read that scope.\n return [ctx.namespace, ctx.key].join('|');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * REST surface for the SettingsService — see ADR-0007 §REST.\n *\n * GET /api/settings → visible manifests\n * GET /api/settings/:namespace → { manifest, values }\n * PUT /api/settings/:namespace → batch upsert\n * POST /api/settings/:namespace/:actionId → invoke declared action\n *\n * The route layer is a thin wrapper that maps thrown service errors\n * into proper HTTP status codes; all business logic lives in\n * `SettingsService`.\n */\n\nimport type { IHttpServer, IHttpRequest, IHttpResponse, RouteHandler } from '@objectstack/spec/contracts';\nimport { SettingsService } from './settings-service.js';\nimport {\n SettingsLockedError,\n UnknownKeyError,\n UnknownNamespaceError,\n type SettingsContext,\n} from './settings-service.types.js';\n\nexport interface SettingsRoutesOptions {\n /** Base path. Default `/api/settings`. */\n basePath?: string;\n /**\n * Extract caller identity from the request. The default reads\n * `x-user-id` / `x-tenant-id` headers and parses\n * `x-permissions` as a comma-separated list — fine for dev and\n * straightforward to override in production wiring.\n */\n contextFromRequest?: (req: IHttpRequest) => SettingsContext;\n}\n\nconst defaultContext = (req: IHttpRequest): SettingsContext => {\n const header = (name: string): string | undefined => {\n const v = req.headers?.[name];\n return Array.isArray(v) ? v[0] : v;\n };\n const perms = header('x-permissions');\n return {\n userId: header('x-user-id'),\n tenantId: header('x-tenant-id'),\n permissions: perms ? perms.split(',').map((s) => s.trim()).filter(Boolean) : undefined,\n requestId: header('x-request-id'),\n };\n};\n\nfunction sendError(res: IHttpResponse, status: number, code: string, message: string, extra?: Record<string, unknown>) {\n res.status(status).json({ error: { code, message, ...extra } });\n}\n\nexport function registerSettingsRoutes(\n http: IHttpServer,\n service: SettingsService,\n opts: SettingsRoutesOptions = {},\n): void {\n const base = opts.basePath ?? '/api/settings';\n const ctxOf = opts.contextFromRequest ?? defaultContext;\n\n http.get(base, (async (req, res) => {\n try {\n const ctx = ctxOf(req);\n const manifests = service.listManifests(ctx);\n await res.json({ manifests });\n } catch (err: any) {\n sendError(res, 500, 'INTERNAL', err?.message ?? 'Failed to list manifests');\n }\n }) satisfies RouteHandler);\n\n http.get(`${base}/:namespace`, (async (req, res) => {\n const ns = req.params.namespace;\n try {\n const ctx = ctxOf(req);\n const payload = await service.getNamespace(ns, ctx);\n await res.json(payload);\n } catch (err: any) {\n if (err instanceof UnknownNamespaceError) {\n sendError(res, 404, 'UNKNOWN_NAMESPACE', err.message);\n } else {\n sendError(res, 500, 'INTERNAL', err?.message ?? 'Failed to read namespace');\n }\n }\n }) satisfies RouteHandler);\n\n http.put(`${base}/:namespace`, (async (req, res) => {\n const ns = req.params.namespace;\n const body = (req.body ?? {}) as Record<string, unknown>;\n try {\n const ctx = ctxOf(req);\n const result = await service.setMany(ns, body, ctx);\n await res.json({ values: result });\n } catch (err: any) {\n if (err instanceof SettingsLockedError) {\n sendError(res, 409, 'SETTINGS_LOCKED', err.message, {\n namespace: err.namespace,\n key: err.key,\n reason: err.reason,\n });\n } else if (err instanceof UnknownNamespaceError) {\n sendError(res, 404, 'UNKNOWN_NAMESPACE', err.message);\n } else if (err instanceof UnknownKeyError) {\n sendError(res, 400, 'UNKNOWN_KEY', err.message, { namespace: err.namespace, key: err.key });\n } else {\n sendError(res, 500, 'INTERNAL', err?.message ?? 'Failed to write namespace');\n }\n }\n }) satisfies RouteHandler);\n\n http.post(`${base}/:namespace/:actionId`, (async (req, res) => {\n const { namespace, actionId } = req.params;\n try {\n const ctx = ctxOf(req);\n const result = await service.runAction(namespace, actionId, req.body, ctx);\n const status = result.ok ? 200 : 400;\n await res.status(status).json(result);\n } catch (err: any) {\n if (err instanceof UnknownNamespaceError) {\n sendError(res, 404, 'UNKNOWN_NAMESPACE', err.message);\n } else {\n sendError(res, 500, 'INTERNAL', err?.message ?? 'Action failed');\n }\n }\n }) satisfies RouteHandler);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { SysSetting, SysSecret, SysSettingAudit } from '@objectstack/platform-objects/system';\n\nexport const SETTINGS_PLUGIN_ID = 'com.objectstack.service.settings';\nexport const SETTINGS_PLUGIN_VERSION = '0.1.0';\n\n/** Objects owned by service-settings. Currently just the K/V store. */\nexport const settingsObjects: any[] = [SysSetting, SysSecret, SysSettingAudit];\n\n/** Manifest header shared by compile-time config and runtime registration. */\nexport const settingsPluginManifestHeader = {\n id: SETTINGS_PLUGIN_ID,\n namespace: 'sys',\n version: SETTINGS_PLUGIN_VERSION,\n type: 'plugin' as const,\n scope: 'project' as const,\n name: 'Settings Service',\n description:\n 'Generic settings registry + K/V resolver with Env > Tenant > User > Default precedence. ADR-0007.',\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\nimport type { SettingsActionHandler } from '../settings-service.types.js';\n\n// Visibility expressions are written as inline strings here for\n// readability. The spec's ExpressionInputSchema accepts a bare string\n// and normalises it at parse time, but the inferred TypeScript output\n// type expects `{ dialect, source }` objects. Build the manifest as\n// `unknown` first, then cast — keeps the manifest source compact.\nconst manifest = {\n namespace: 'mail',\n version: 1,\n label: 'Mail Delivery',\n icon: 'Mail',\n description: 'SMTP and transactional email provider configuration.',\n scope: 'global',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Communication',\n order: 10,\n specifiers: [\n { type: 'group', id: 'provider', label: 'Provider', required: false,\n description: 'Choose how this workspace sends outbound email.' },\n\n { type: 'select', key: 'provider', label: 'Provider', required: true, default: 'smtp',\n options: [\n { value: 'smtp', label: 'SMTP' },\n { value: 'sendgrid', label: 'SendGrid' },\n { value: 'ses', label: 'Amazon SES' },\n { value: 'postmark', label: 'Postmark' },\n ],\n },\n\n { type: 'group', id: 'smtp', label: 'SMTP', required: false, visible: \"${data.provider === 'smtp'}\" },\n { type: 'text', key: 'smtp_host', label: 'Host', required: true,\n description: 'Example: smtp.example.com', visible: \"${data.provider === 'smtp'}\" },\n { type: 'number', key: 'smtp_port', label: 'Port', required: false, default: 587,\n min: 1, max: 65535, visible: \"${data.provider === 'smtp'}\" },\n { type: 'toggle', key: 'smtp_secure', label: 'Use TLS', required: false, default: true,\n visible: \"${data.provider === 'smtp'}\" },\n { type: 'text', key: 'smtp_user', label: 'Username', required: false,\n visible: \"${data.provider === 'smtp'}\" },\n { type: 'password', key: 'smtp_password', label: 'Password', required: false,\n visible: \"${data.provider === 'smtp'}\" },\n\n { type: 'group', id: 'api_key', label: 'API key', required: false, visible: \"${data.provider !== 'smtp'}\" },\n { type: 'password', key: 'api_key', label: 'API key', required: true, encrypted: true,\n visible: \"${data.provider !== 'smtp'}\" },\n\n { type: 'group', id: 'from_address', label: 'From address', required: false },\n { type: 'email', key: 'from_email', label: 'From email', required: true,\n description: 'Example: no-reply@example.com' },\n { type: 'text', key: 'from_name', label: 'From name', required: false, default: 'ObjectStack' },\n\n { type: 'action_button', id: 'test', label: 'Send test email', required: false, icon: 'Send',\n handler: { kind: 'http', method: 'POST', url: '/api/settings/mail/test' } },\n ],\n};\n\n/** Mail Delivery — SMTP / API provider configuration. */\nexport const mailSettingsManifest = manifest as unknown as SettingsManifest;\n\n/** Built-in action handler stub for `mail/test`. */\nexport const mailTestActionHandler: SettingsActionHandler = async ({ values }) => {\n const provider = String(values.provider ?? 'smtp');\n const fromEmail = values.from_email as string | undefined;\n if (!fromEmail) {\n return { ok: false, severity: 'error', message: 'Configure a from address before testing.' };\n }\n if (provider === 'smtp' && !values.smtp_host) {\n return { ok: false, severity: 'error', message: 'SMTP host is required.' };\n }\n if (provider !== 'smtp' && !values.api_key) {\n return { ok: false, severity: 'error', message: 'API key is required.' };\n }\n return {\n ok: true,\n severity: 'info',\n message: `Configuration looks valid (provider=${provider}). Wire @objectstack/plugin-mail for actual delivery.`,\n };\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\n\n/** Branding — workspace identity (name, logo, theme). */\nexport const brandingSettingsManifest: SettingsManifest = {\n namespace: 'branding',\n version: 1,\n label: 'Branding',\n icon: 'Palette',\n description: 'Workspace name, logo, and accent colour.',\n scope: 'tenant',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Workspace',\n order: 5,\n specifiers: [\n { type: 'group', id: 'identity', label: 'Identity', required: false },\n { type: 'text', key: 'workspace_name', label: 'Workspace name', required: true,\n default: 'ObjectStack', minLength: 1, maxLength: 60 },\n { type: 'email', key: 'support_email', label: 'Support email', required: false,\n description: 'Example: support@example.com' },\n\n { type: 'group', id: 'appearance', label: 'Appearance', required: false },\n { type: 'select', key: 'theme_mode', label: 'Default theme', required: false, default: 'system',\n options: [\n { value: 'light', label: 'Light' },\n { value: 'dark', label: 'Dark' },\n { value: 'system', label: 'Match system' },\n ],\n },\n { type: 'color', key: 'accent_color', label: 'Accent colour', required: false, default: '#6366f1' },\n { type: 'url', key: 'logo_url', label: 'Logo URL', required: false,\n description: 'Example: https://…/logo.svg' },\n ],\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\n\n/** Feature Flags — opt into experimental capabilities. */\nexport const featureFlagsSettingsManifest: SettingsManifest = {\n namespace: 'feature_flags',\n version: 1,\n label: 'Feature Flags',\n icon: 'FlaskConical',\n description: 'Toggle experimental and beta features for this workspace.',\n scope: 'tenant',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Beta',\n order: 100,\n beta: true,\n specifiers: [\n { type: 'info_banner', id: 'beta_notice', label: 'Heads up', required: false,\n bannerText:\n 'Beta features may change without notice. Pin via env vars (e.g. `FEATURE_FLAGS_AI_ENABLED=true`) to lock for the whole deployment.',\n bannerSeverity: 'warning' },\n\n { type: 'group', id: 'productivity', label: 'Productivity', required: false },\n { type: 'toggle', key: 'ai_enabled', label: 'AI Assistant', required: false, default: false,\n description: 'Enables the in-app AI assistant panel.' },\n { type: 'toggle', key: 'kanban_swimlanes', label: 'Kanban swimlanes', required: false, default: false },\n\n { type: 'group', id: 'collaboration', label: 'Collaboration', required: false },\n { type: 'toggle', key: 'realtime_cursors', label: 'Realtime cursors', required: false, default: false },\n { type: 'toggle', key: 'inline_comments', label: 'Inline comments', required: false, default: true },\n ],\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\nimport type { SettingsActionHandler } from '../settings-service.types.js';\n\n// Mirrors the shape of `mail.manifest.ts`. The actual adapter rebuild\n// + `storage/test` probe live in `@objectstack/service-storage`; this\n// manifest only declares the form + acts as a safe fallback when the\n// storage plugin is not present.\nconst manifest = {\n namespace: 'storage',\n version: 1,\n label: 'File Storage',\n icon: 'HardDrive',\n description:\n 'Backend used for attachments, exports, and user uploads. ' +\n '⚠ Switching adapter does not migrate existing files — files ' +\n 'uploaded under the previous adapter become unreachable through ' +\n 'the new one.',\n scope: 'global',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Infrastructure',\n order: 20,\n specifiers: [\n { type: 'group', id: 'adapter', label: 'Backend', required: false,\n description: 'Choose where uploaded files are stored.' },\n { type: 'select', key: 'adapter', label: 'Adapter', required: true, default: 'local',\n options: [\n { value: 'local', label: 'Local filesystem' },\n { value: 's3', label: 'S3 / S3-compatible' },\n ],\n },\n\n { type: 'group', id: 'local', label: 'Local', required: false,\n visible: \"${data.adapter === 'local'}\" },\n { type: 'text', key: 'local_root', label: 'Root directory', required: false,\n default: './.objectstack/data/uploads',\n description: 'Filesystem path under which files are stored. Relative paths resolve from the server CWD.',\n visible: \"${data.adapter === 'local'}\" },\n\n { type: 'group', id: 's3', label: 'S3', required: false,\n visible: \"${data.adapter === 's3'}\" },\n { type: 'text', key: 's3_bucket', label: 'Bucket', required: true,\n description: 'Shared host bucket. Per-environment files are namespaced via the projects/<environmentId>/ prefix.',\n visible: \"${data.adapter === 's3'}\" },\n { type: 'text', key: 's3_region', label: 'Region', required: true,\n description: 'Example: us-east-1',\n visible: \"${data.adapter === 's3'}\" },\n { type: 'text', key: 's3_endpoint', label: 'Endpoint', required: false,\n description: 'Custom endpoint for S3-compatible providers (R2, MinIO, Wasabi). Leave blank for AWS S3.',\n visible: \"${data.adapter === 's3'}\" },\n { type: 'text', key: 's3_access_key_id', label: 'Access key ID', required: true,\n visible: \"${data.adapter === 's3'}\" },\n { type: 'password', key: 's3_secret_access_key', label: 'Secret access key',\n required: true, encrypted: true,\n visible: \"${data.adapter === 's3'}\" },\n { type: 'toggle', key: 's3_force_path_style', label: 'Force path-style URLs',\n required: false, default: false,\n description: 'Enable for MinIO and most S3-compatible providers; disable for AWS S3.',\n visible: \"${data.adapter === 's3'}\" },\n\n { type: 'group', id: 'limits', label: 'Limits', required: false },\n { type: 'number', key: 'presigned_ttl', label: 'Presigned URL TTL (seconds)',\n required: false, default: 3600, min: 60, max: 604800 },\n { type: 'number', key: 'session_ttl', label: 'Upload session TTL (seconds)',\n required: false, default: 86400, min: 300, max: 604800,\n description: 'How long a chunked-upload session stays resumable.' },\n { type: 'number', key: 'max_upload_mb', label: 'Max upload size (MB)',\n required: false, default: 100, min: 1, max: 10240 },\n\n { type: 'action_button', id: 'test', label: 'Test connection',\n required: false, icon: 'Plug',\n handler: { kind: 'http', method: 'POST', url: '/api/settings/storage/test' } },\n ],\n};\n\n/** File Storage — local FS / S3-compatible backend configuration. */\nexport const storageSettingsManifest = manifest as unknown as SettingsManifest;\n\n/**\n * Built-in fallback action handler for `storage/test`. The real\n * implementation lives in `@objectstack/service-storage` and is\n * registered by `StorageServicePlugin` on `kernel:ready` (it overrides\n * this stub via `registerAction`). This fallback only validates the\n * form so the button is still useful when the storage plugin is\n * absent (e.g. in a unit-test kernel that mounts settings only).\n */\nexport const storageTestActionHandler: SettingsActionHandler = async ({ values }) => {\n const adapter = String(values.adapter ?? 'local');\n if (adapter === 'local') {\n const root = values.local_root as string | undefined;\n if (!root) {\n return { ok: false, severity: 'error', message: 'Configure a root directory before testing.' };\n }\n return {\n ok: true,\n severity: 'info',\n message: `Local adapter configured (root=${root}). Mount @objectstack/service-storage to exercise live I/O.`,\n };\n }\n if (adapter === 's3') {\n const missing: string[] = [];\n if (!values.s3_bucket) missing.push('s3_bucket');\n if (!values.s3_region) missing.push('s3_region');\n if (!values.s3_access_key_id) missing.push('s3_access_key_id');\n if (!values.s3_secret_access_key) missing.push('s3_secret_access_key');\n if (missing.length) {\n return { ok: false, severity: 'error', message: `Missing required field${missing.length > 1 ? 's' : ''}: ${missing.join(', ')}` };\n }\n return {\n ok: true,\n severity: 'info',\n message: `S3 adapter configured (bucket=${values.s3_bucket}, region=${values.s3_region}). Mount @objectstack/service-storage to exercise live I/O.`,\n };\n }\n return { ok: false, severity: 'error', message: `Unknown adapter: ${adapter}` };\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\nimport type { SettingsActionHandler } from '../settings-service.types.js';\n\n// Visibility expressions are written as inline strings here for\n// readability. The spec's ExpressionInputSchema accepts a bare string\n// and normalises it at parse time, but the inferred TypeScript output\n// type expects `{ dialect, source }` objects. Build the manifest as\n// `unknown` first, then cast — keeps the manifest source compact.\n//\n// The actual LLM adapter selection still happens in\n// `@objectstack/service-ai`'s plugin (env-var driven by default).\n// This manifest gives operators a UI to inspect and override those\n// env-derived defaults without redeploying; the AIServicePlugin can\n// later prefer settings over env when implemented. Until then this\n// manifest is the canonical surface for \"what AI provider is wired,\n// and which API key is in use\" — a request operators repeatedly need\n// answered during onboarding and incident response.\nconst manifest = {\n namespace: 'ai',\n version: 1,\n label: 'AI',\n icon: 'Sparkles',\n description:\n 'LLM provider, model, credentials, and embedder configuration used by ' +\n 'the platform AI and knowledge services. Provider SDK packages (e.g. ' +\n '@ai-sdk/openai for chat, @objectstack/embedder-openai for embeddings) ' +\n 'must be installed on the host for the chosen provider to be loadable at runtime.',\n scope: 'global',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Infrastructure',\n order: 30,\n specifiers: [\n // ── Provider selection ────────────────────────────────────────\n { type: 'group', id: 'provider', label: 'Provider', required: false,\n description: 'Choose the LLM backend. Memory mode echoes input — useful for tests but never for production.' },\n { type: 'select', key: 'provider', label: 'Provider', required: true, default: 'memory',\n options: [\n { value: 'memory', label: 'Memory (echo — testing only)' },\n { value: 'gateway', label: 'Vercel AI Gateway' },\n { value: 'openai', label: 'OpenAI' },\n { value: 'anthropic', label: 'Anthropic' },\n { value: 'google', label: 'Google Generative AI' },\n ],\n },\n\n // ── Vercel AI Gateway ─────────────────────────────────────────\n { type: 'group', id: 'gateway', label: 'Vercel AI Gateway', required: false,\n visible: \"${data.provider === 'gateway'}\",\n description: 'Multi-provider router. The model spec follows `provider/model`, e.g. `openai/gpt-4o`.' },\n { type: 'text', key: 'gateway_model', label: 'Gateway model', required: true,\n description: 'Forwarded as AI_GATEWAY_MODEL. Example: openai/gpt-4o',\n visible: \"${data.provider === 'gateway'}\" },\n { type: 'password', key: 'gateway_api_key', label: 'Gateway API key',\n required: false, encrypted: true,\n description: 'Optional — required only if the gateway enforces auth.',\n visible: \"${data.provider === 'gateway'}\" },\n\n // ── OpenAI ───────────────────────────────────────────────────\n { type: 'group', id: 'openai', label: 'OpenAI', required: false,\n visible: \"${data.provider === 'openai'}\" },\n { type: 'password', key: 'openai_api_key', label: 'OpenAI API key',\n required: true, encrypted: true,\n description: 'Forwarded as OPENAI_API_KEY. Stored encrypted at rest.',\n visible: \"${data.provider === 'openai'}\" },\n { type: 'text', key: 'openai_model', label: 'Model', required: false, default: 'gpt-4o',\n description: 'Default model id. Per-agent overrides take precedence.',\n visible: \"${data.provider === 'openai'}\" },\n { type: 'text', key: 'openai_base_url', label: 'Base URL', required: false,\n description: 'Override for Azure OpenAI or self-hosted gateways. Leave blank for api.openai.com.',\n visible: \"${data.provider === 'openai'}\" },\n\n // ── Anthropic ────────────────────────────────────────────────\n { type: 'group', id: 'anthropic', label: 'Anthropic', required: false,\n visible: \"${data.provider === 'anthropic'}\" },\n { type: 'password', key: 'anthropic_api_key', label: 'Anthropic API key',\n required: true, encrypted: true,\n description: 'Forwarded as ANTHROPIC_API_KEY. Stored encrypted at rest.',\n visible: \"${data.provider === 'anthropic'}\" },\n { type: 'text', key: 'anthropic_model', label: 'Model', required: false,\n default: 'claude-sonnet-4-20250514',\n visible: \"${data.provider === 'anthropic'}\" },\n\n // ── Google Generative AI ─────────────────────────────────────\n { type: 'group', id: 'google', label: 'Google', required: false,\n visible: \"${data.provider === 'google'}\" },\n { type: 'password', key: 'google_api_key', label: 'Google API key',\n required: true, encrypted: true,\n description: 'Forwarded as GOOGLE_GENERATIVE_AI_API_KEY. Stored encrypted at rest.',\n visible: \"${data.provider === 'google'}\" },\n { type: 'text', key: 'google_model', label: 'Model', required: false,\n default: 'gemini-2.0-flash',\n visible: \"${data.provider === 'google'}\" },\n\n // ── Generation defaults ──────────────────────────────────────\n { type: 'group', id: 'defaults', label: 'Generation defaults', required: false,\n description: 'Applied when an agent or chat request does not specify its own value.',\n visible: \"${data.provider !== 'memory'}\" },\n { type: 'slider', key: 'temperature', label: 'Temperature',\n required: false, default: 0.7, min: 0, max: 2, step: 0.1,\n description: '0 = deterministic, 2 = highly creative.',\n visible: \"${data.provider !== 'memory'}\" },\n { type: 'number', key: 'max_tokens', label: 'Max output tokens',\n required: false, default: 4096, min: 1, max: 1048576,\n description: 'Hard cap on tokens generated per response.',\n visible: \"${data.provider !== 'memory'}\" },\n { type: 'number', key: 'request_timeout_ms', label: 'Request timeout (ms)',\n required: false, default: 60000, min: 1000, max: 600000,\n visible: \"${data.provider !== 'memory'}\" },\n\n // ── Observability ────────────────────────────────────────────\n { type: 'group', id: 'observability', label: 'Observability', required: false },\n { type: 'toggle', key: 'trace_enabled', label: 'Record traces',\n required: false, default: true,\n description: 'Persist prompt/response traces to sys_ai_trace for debugging and replay.' },\n { type: 'toggle', key: 'log_prompts', label: 'Log full prompts',\n required: false, default: false,\n description: 'Include rendered prompts (not just metadata) in trace rows. ⚠ May leak PII — disable in regulated environments.' },\n\n // ── Probe ────────────────────────────────────────────────────\n { type: 'action_button', id: 'test', label: 'Test connection',\n required: false, icon: 'Plug',\n handler: { kind: 'http', method: 'POST', url: '/api/settings/ai/test' } },\n\n // ════════════════════════════════════════════════════════════════\n // Embedder — text → vector provider used by knowledge / RAG.\n // Decoupled from the chat provider above so an organisation can\n // mix-and-match (e.g. OpenAI for chat + 阿里通义 for embeddings).\n //\n // The preset list mirrors @objectstack/embedder-openai's\n // OPENAI_COMPATIBLE_PRESETS so a UI dropdown maps 1:1 to a\n // runtime baseUrl. The \"none\" choice is the explicit opt-out\n // for instances that disable knowledge / RAG entirely.\n // ════════════════════════════════════════════════════════════════\n { type: 'group', id: 'embedder', label: 'Embedder', required: false,\n description:\n 'Text → vector provider used by knowledge sources and RAG. ' +\n 'Independent from the chat provider above — mix providers freely ' +\n '(e.g. OpenAI for chat + 阿里通义 for embeddings).' },\n { type: 'select', key: 'embedder_provider', label: 'Provider',\n required: false, default: 'none',\n options: [\n { value: 'none', label: 'Disabled (no embeddings)' },\n { value: 'openai', label: 'OpenAI' },\n { value: 'azure', label: 'Azure OpenAI' },\n { value: 'dashscope', label: '阿里通义 DashScope' },\n { value: 'zhipu', label: '智谱 BigModel' },\n { value: 'siliconflow', label: '硅基流动 SiliconFlow' },\n { value: 'doubao', label: '火山引擎 Doubao' },\n { value: 'minimax', label: 'MiniMax' },\n { value: 'ollama', label: 'Ollama (local)' },\n { value: 'custom', label: 'Custom (OpenAI-compatible)' },\n ],\n },\n { type: 'password', key: 'embedder_api_key', label: 'Embedder API key',\n required: false, encrypted: true,\n description: 'Bearer token sent as Authorization header. For Ollama any non-empty value works.',\n visible: \"${data.embedder_provider && data.embedder_provider !== 'none'}\" },\n { type: 'text', key: 'embedder_model', label: 'Model',\n required: false,\n description:\n 'Examples — OpenAI: text-embedding-3-small · 阿里通义: text-embedding-v3 · ' +\n '智谱: embedding-3 · 硅基流动: BAAI/bge-m3 · Ollama: bge-m3',\n visible: \"${data.embedder_provider && data.embedder_provider !== 'none'}\" },\n { type: 'text', key: 'embedder_base_url', label: 'Base URL',\n required: false,\n description:\n 'Endpoint root (without /embeddings). Auto-filled from preset; ' +\n 'override for proxies or self-hosted gateways.',\n visible: \"${data.embedder_provider === 'custom' || data.embedder_provider === 'azure'}\" },\n { type: 'number', key: 'embedder_dimensions', label: 'Dimensions',\n required: false, min: 1, max: 8192,\n description:\n 'Override output dimensionality (Matryoshka models only — OpenAI v3, 智谱 embedding-3, BGE-m3 dense). ' +\n 'Leave blank to use the model default.',\n visible: \"${data.embedder_provider && data.embedder_provider !== 'none'}\" },\n { type: 'number', key: 'embedder_batch_size', label: 'Batch size',\n required: false, default: 64, min: 1, max: 2048,\n description: 'Chunks per embed() call. Reduce if hitting provider rate / size limits.',\n visible: \"${data.embedder_provider && data.embedder_provider !== 'none'}\" },\n { type: 'action_button', id: 'test_embedder', label: 'Test embedder',\n required: false, icon: 'Plug',\n handler: { kind: 'http', method: 'POST', url: '/api/settings/ai/test_embedder' } },\n ],\n};\n\n/** AI — provider / model / credentials configuration. */\nexport const aiSettingsManifest = manifest as unknown as SettingsManifest;\n\n/**\n * Built-in fallback action handler for `ai/test`. The real\n * implementation that issues a live `chat()` round-trip lives in\n * `@objectstack/service-ai` and overrides this stub via\n * `registerAction` on `kernel:ready` (mirrors the storage pattern).\n *\n * This fallback only validates the form so the button is still useful\n * when the AI plugin is absent (e.g. in a unit-test kernel that mounts\n * settings only).\n */\nexport const aiTestActionHandler: SettingsActionHandler = async ({ values, payload }) => {\n // The Settings UI may POST the current (possibly unsaved) form state\n // as `{ values: {...} }`. Prefer those over the persisted snapshot so\n // operators can validate edits before hitting \"Save\".\n const overrides =\n payload && typeof payload === 'object' && payload !== null && 'values' in payload\n ? ((payload as { values?: Record<string, unknown> }).values ?? {})\n : {};\n const merged: Record<string, unknown> = { ...values, ...overrides };\n const provider = String(merged.provider ?? 'memory');\n values = merged;\n if (provider === 'memory') {\n return {\n ok: true,\n severity: 'warning',\n message: 'Memory provider is an echo stub — no external call to validate. Switch to a real provider for production.',\n };\n }\n if (provider === 'gateway') {\n if (!values.gateway_model) {\n return { ok: false, severity: 'error', message: 'Gateway model is required (e.g. openai/gpt-4o).' };\n }\n return {\n ok: true,\n severity: 'info',\n message: `Vercel AI Gateway configured (model=${values.gateway_model}). Mount @objectstack/service-ai to exercise live calls.`,\n };\n }\n const keyField = `${provider}_api_key`;\n if (!values[keyField]) {\n return { ok: false, severity: 'error', message: `${provider} API key is required.` };\n }\n const modelField = `${provider}_model`;\n const model = values[modelField] ?? '(default)';\n return {\n ok: true,\n severity: 'info',\n message: `${provider} configured (model=${model}). Mount @objectstack/service-ai to exercise live calls.`,\n };\n};\n\n/**\n * Built-in fallback handler for `ai/test_embedder`. Real implementation\n * with a live `embed()` round-trip lives in `@objectstack/service-ai` or\n * `@objectstack/service-knowledge` and overrides this stub at runtime.\n *\n * This fallback validates form completeness only — no network call —\n * so the button is useful even when no embedder plugin is mounted.\n */\nexport const aiTestEmbedderActionHandler: SettingsActionHandler = async ({ values, payload }) => {\n const overrides =\n payload && typeof payload === 'object' && payload !== null && 'values' in payload\n ? ((payload as { values?: Record<string, unknown> }).values ?? {})\n : {};\n const merged: Record<string, unknown> = { ...values, ...overrides };\n const provider = String(merged.embedder_provider ?? 'none');\n\n if (provider === 'none') {\n return {\n ok: false,\n severity: 'warning',\n message: 'Embedder is disabled. Pick a provider to enable knowledge / RAG.',\n };\n }\n\n // For Ollama, an API key is conventionally `ollama` but not enforced.\n if (provider !== 'ollama' && !merged.embedder_api_key) {\n return {\n ok: false,\n severity: 'error',\n message: `${provider} embedder requires an API key.`,\n };\n }\n\n if ((provider === 'custom' || provider === 'azure') && !merged.embedder_base_url) {\n return {\n ok: false,\n severity: 'error',\n message: `${provider} embedder requires a Base URL.`,\n };\n }\n\n const model = merged.embedder_model ?? '(provider default)';\n return {\n ok: true,\n severity: 'info',\n message:\n `${provider} embedder configured (model=${model}). ` +\n 'Mount @objectstack/embedder-openai + a knowledge adapter to exercise live calls.',\n };\n};\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SettingsManifest } from '@objectstack/spec/system';\nimport type { SettingsActionHandler } from '../settings-service.types.js';\n\n/**\n * Knowledge — RAG infrastructure: which adapter stores vectors, and\n * how big chunks are. The embedder itself is configured in the AI\n * namespace (see `ai.manifest.ts`) because it's shared between\n * knowledge sources and any future agent that needs to embed ad-hoc\n * inputs.\n *\n * Adapter list mirrors the plugin packages currently published:\n * - memory @objectstack/knowledge-memory (dev / test reference)\n * - turso @objectstack/knowledge-turso (libSQL native F32_BLOB —\n * works for cloud Turso AND\n * local file mode)\n * - ragflow @objectstack/knowledge-ragflow (external RAGFlow service)\n *\n * As with the AI manifest, the real adapter wiring happens in the\n * knowledge plugins; this manifest is the canonical settings surface\n * for \"what knowledge backend is wired\" and saves operators from\n * grepping defineStack() during onboarding / incident response.\n */\nconst manifest = {\n namespace: 'knowledge',\n version: 1,\n label: 'Knowledge',\n icon: 'BookOpen',\n description:\n 'Vector-store backend for RAG / knowledge sources. ' +\n '⚠ Switching adapter does NOT migrate existing indices — documents ' +\n 'indexed under the previous adapter become unreachable until ' +\n 're-indexed. The embedder is configured separately under AI.',\n scope: 'global',\n readPermission: 'setup.access',\n writePermission: 'setup.write',\n category: 'Infrastructure',\n order: 35,\n specifiers: [\n // ── Adapter selection ─────────────────────────────────────────\n { type: 'group', id: 'adapter', label: 'Backend', required: false,\n description: 'Choose where document chunks and their vectors are stored.' },\n { type: 'select', key: 'adapter', label: 'Adapter', required: true, default: 'memory',\n options: [\n { value: 'memory', label: 'In-memory (dev / test only)' },\n { value: 'turso', label: 'Turso / libSQL (cloud or local)' },\n { value: 'ragflow', label: 'RAGFlow (external)' },\n ],\n },\n\n // ── Turso / libSQL ────────────────────────────────────────────\n { type: 'group', id: 'turso', label: 'Turso / libSQL', required: false,\n visible: \"${data.adapter === 'turso'}\",\n description:\n 'Works against managed Turso (libsql://…), local file (file:./knowledge.db), ' +\n 'or in-memory (:memory:). For per-tenant cloud deployments, leave blank to ' +\n 'reuse the tenant\\'s primary libSQL connection.' },\n { type: 'text', key: 'turso_url', label: 'Connection URL', required: false,\n description: 'Examples: libsql://your-tenant.turso.io · file:./.objectstack/knowledge.db · :memory:',\n visible: \"${data.adapter === 'turso'}\" },\n { type: 'password', key: 'turso_auth_token', label: 'Auth token',\n required: false, encrypted: true,\n description: 'Only required for managed Turso URLs. Leave blank for local file / :memory:.',\n visible: \"${data.adapter === 'turso'}\" },\n\n // ── RAGFlow ───────────────────────────────────────────────────\n { type: 'group', id: 'ragflow', label: 'RAGFlow', required: false,\n visible: \"${data.adapter === 'ragflow'}\",\n description: 'External RAGFlow deployment. See https://ragflow.io for self-host instructions.' },\n { type: 'text', key: 'ragflow_base_url', label: 'Base URL', required: true,\n description: 'Example: http://localhost:9380',\n visible: \"${data.adapter === 'ragflow'}\" },\n { type: 'password', key: 'ragflow_api_key', label: 'API key',\n required: true, encrypted: true,\n visible: \"${data.adapter === 'ragflow'}\" },\n { type: 'text', key: 'ragflow_default_dataset', label: 'Default dataset id',\n required: false,\n description: 'Used when a KnowledgeSource does not specify its own RAGFlow dataset.',\n visible: \"${data.adapter === 'ragflow'}\" },\n\n // ── Indexing defaults ─────────────────────────────────────────\n { type: 'group', id: 'indexing', label: 'Indexing defaults', required: false,\n description: 'Per-source values on KnowledgeSource.adapterConfig take precedence.',\n visible: \"${data.adapter !== 'memory'}\" },\n { type: 'number', key: 'chunk_target', label: 'Target chunk size (chars)',\n required: false, default: 800, min: 64, max: 8192,\n description: 'Soft cap on chunk size in characters before token-aware splitting kicks in.',\n visible: \"${data.adapter !== 'memory'}\" },\n { type: 'number', key: 'chunk_overlap', label: 'Chunk overlap (chars)',\n required: false, default: 80, min: 0, max: 2048,\n description: 'Characters retained from the previous chunk so context survives the boundary.',\n visible: \"${data.adapter !== 'memory'}\" },\n { type: 'number', key: 'over_fetch', label: 'Over-fetch multiplier',\n required: false, default: 4, min: 1, max: 20,\n description: 'Internal `topK * overFetch` candidates fetched so JS-side metadata filtering still has rows to return.',\n visible: \"${data.adapter === 'turso'}\" },\n\n // ── Permissions ───────────────────────────────────────────────\n { type: 'group', id: 'permissions', label: 'Permissions', required: false },\n { type: 'toggle', key: 'enforce_rls', label: 'Enforce RLS on search',\n required: false, default: true,\n description:\n 'Re-check every hit against the caller\\'s record-level permissions via IDataEngine. ' +\n '⚠ Disabling skips the platform\\'s unique safeguard against vector-store data leakage — leave on in production.' },\n\n // ── Probe ─────────────────────────────────────────────────────\n { type: 'action_button', id: 'test', label: 'Test connection',\n required: false, icon: 'Plug',\n handler: { kind: 'http', method: 'POST', url: '/api/settings/knowledge/test' } },\n ],\n};\n\n/** Knowledge — RAG vector-store backend configuration. */\nexport const knowledgeSettingsManifest = manifest as unknown as SettingsManifest;\n\n/**\n * Built-in fallback handler for `knowledge/test`. The real probe with\n * a live `healthCheck()` round-trip lives in `@objectstack/service-knowledge`\n * and overrides this stub at runtime (mirrors the AI / storage patterns).\n *\n * This fallback only validates form completeness so the button is\n * usable when no knowledge adapter plugin is mounted.\n */\nexport const knowledgeTestActionHandler: SettingsActionHandler = async ({ values, payload }) => {\n const overrides =\n payload && typeof payload === 'object' && payload !== null && 'values' in payload\n ? ((payload as { values?: Record<string, unknown> }).values ?? {})\n : {};\n const merged: Record<string, unknown> = { ...values, ...overrides };\n const adapter = String(merged.adapter ?? 'memory');\n\n if (adapter === 'memory') {\n return {\n ok: true,\n severity: 'warning',\n message: 'In-memory adapter — no external service to probe. Indices are wiped on restart; do not use in production.',\n };\n }\n\n if (adapter === 'turso') {\n const url = merged.turso_url;\n if (!url) {\n return {\n ok: true,\n severity: 'info',\n message: 'No URL configured — adapter will reuse the tenant\\'s primary libSQL connection at runtime.',\n };\n }\n const u = String(url);\n if (u.startsWith('libsql://') && !merged.turso_auth_token) {\n return {\n ok: false,\n severity: 'error',\n message: 'Managed Turso URL requires an auth token.',\n };\n }\n return {\n ok: true,\n severity: 'info',\n message: `Turso adapter configured (${u}). Mount @objectstack/knowledge-turso to exercise live calls.`,\n };\n }\n\n if (adapter === 'ragflow') {\n if (!merged.ragflow_base_url) {\n return { ok: false, severity: 'error', message: 'RAGFlow requires a Base URL.' };\n }\n if (!merged.ragflow_api_key) {\n return { ok: false, severity: 'error', message: 'RAGFlow requires an API key.' };\n }\n return {\n ok: true,\n severity: 'info',\n message: `RAGFlow adapter configured (${merged.ragflow_base_url}). Mount @objectstack/knowledge-ragflow to exercise live calls.`,\n };\n }\n\n return { ok: false, severity: 'error', message: `Unknown adapter: ${adapter}` };\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/** Reference manifests bundled with service-settings. */\nexport { mailSettingsManifest, mailTestActionHandler } from './mail.manifest.js';\nexport { brandingSettingsManifest } from './branding.manifest.js';\nexport { featureFlagsSettingsManifest } from './feature-flags.manifest.js';\nexport { storageSettingsManifest, storageTestActionHandler } from './storage.manifest.js';\nexport {\n aiSettingsManifest,\n aiTestActionHandler,\n aiTestEmbedderActionHandler,\n} from './ai.manifest.js';\nexport { knowledgeSettingsManifest, knowledgeTestActionHandler } from './knowledge.manifest.js';\n\nimport { mailSettingsManifest } from './mail.manifest.js';\nimport { brandingSettingsManifest } from './branding.manifest.js';\nimport { featureFlagsSettingsManifest } from './feature-flags.manifest.js';\nimport { storageSettingsManifest } from './storage.manifest.js';\nimport { aiSettingsManifest } from './ai.manifest.js';\nimport { knowledgeSettingsManifest } from './knowledge.manifest.js';\n\n/** Convenience aggregate — pass to `SettingsServicePlugin({ manifests })`. */\nexport const builtinSettingsManifests = [\n brandingSettingsManifest,\n mailSettingsManifest,\n storageSettingsManifest,\n aiSettingsManifest,\n knowledgeSettingsManifest,\n featureFlagsSettingsManifest,\n];\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\n/**\n * English (en) — built-in settings manifest translations.\n *\n * Mirrors literals in `manifests/{mail,branding,feature-flags,storage}.manifest.ts`.\n * Keeping them explicit here lets the resolver chain (locale → fallback → literal)\n * always have at least an English entry to fall back to.\n */\nexport const en: TranslationData = {\n settingsCommon: {\n sourceLabels: {\n env: 'Env',\n global: 'Global',\n tenant: 'Tenant',\n user: 'User',\n default: 'Default',\n },\n },\n settings: {\n mail: {\n title: 'Mail Delivery',\n description: 'SMTP and transactional email provider configuration.',\n groups: {\n provider: { title: 'Provider', description: 'Choose how this workspace sends outbound email.' },\n smtp: { title: 'SMTP' },\n api_key: { title: 'API key' },\n from_address: { title: 'From address' },\n },\n keys: {\n provider: {\n label: 'Provider',\n options: {\n smtp: 'SMTP',\n sendgrid: 'SendGrid',\n ses: 'Amazon SES',\n postmark: 'Postmark',\n },\n },\n smtp_host: { label: 'Host', help: 'Example: smtp.example.com' },\n smtp_port: { label: 'Port' },\n smtp_secure: { label: 'Use TLS' },\n smtp_user: { label: 'Username' },\n smtp_password: { label: 'Password' },\n api_key: { label: 'API key' },\n from_email: { label: 'From email', help: 'Example: no-reply@example.com' },\n from_name: { label: 'From name' },\n },\n actions: {\n test: { label: 'Send test email' },\n },\n },\n\n branding: {\n title: 'Branding',\n description: 'Workspace name, logo, and accent colour.',\n groups: {\n identity: { title: 'Identity' },\n appearance: { title: 'Appearance' },\n },\n keys: {\n workspace_name: { label: 'Workspace name' },\n support_email: { label: 'Support email', help: 'Example: support@example.com' },\n theme_mode: {\n label: 'Default theme',\n options: { light: 'Light', dark: 'Dark', system: 'Match system' },\n },\n accent_color: { label: 'Accent colour' },\n logo_url: { label: 'Logo URL', help: 'Example: https://…/logo.svg' },\n },\n },\n\n feature_flags: {\n title: 'Feature Flags',\n description: 'Toggle experimental and beta features for this workspace.',\n groups: {\n productivity: { title: 'Productivity' },\n collaboration: { title: 'Collaboration' },\n },\n keys: {\n ai_enabled: {\n label: 'AI Assistant',\n help: 'Enables the in-app AI assistant panel.',\n },\n kanban_swimlanes: { label: 'Kanban swimlanes' },\n realtime_cursors: { label: 'Realtime cursors' },\n inline_comments: { label: 'Inline comments' },\n },\n },\n\n storage: {\n title: 'File Storage',\n description:\n 'Backend used for attachments, exports, and user uploads. ' +\n '⚠ Switching adapter does not migrate existing files — files ' +\n 'uploaded under the previous adapter become unreachable through ' +\n 'the new one.',\n groups: {\n adapter: { title: 'Backend', description: 'Choose where uploaded files are stored.' },\n local: { title: 'Local' },\n s3: { title: 'S3' },\n limits: { title: 'Limits' },\n },\n keys: {\n adapter: {\n label: 'Adapter',\n options: { local: 'Local filesystem', s3: 'S3 / S3-compatible' },\n },\n local_root: { label: 'Root directory',\n help: 'Filesystem path under which files are stored. Relative paths resolve from the server CWD.' },\n s3_bucket: { label: 'Bucket',\n help: 'Shared host bucket. Per-environment files are namespaced via the projects/<environmentId>/ prefix.' },\n s3_region: { label: 'Region', help: 'Example: us-east-1' },\n s3_endpoint: { label: 'Endpoint',\n help: 'Custom endpoint for S3-compatible providers (R2, MinIO, Wasabi). Leave blank for AWS S3.' },\n s3_access_key_id: { label: 'Access key ID' },\n s3_secret_access_key: { label: 'Secret access key' },\n s3_force_path_style: { label: 'Force path-style URLs',\n help: 'Enable for MinIO and most S3-compatible providers; disable for AWS S3.' },\n presigned_ttl: { label: 'Presigned URL TTL (seconds)' },\n session_ttl: { label: 'Upload session TTL (seconds)',\n help: 'How long a chunked-upload session stays resumable.' },\n max_upload_mb: { label: 'Max upload size (MB)' },\n },\n actions: {\n test: { label: 'Test connection' },\n },\n },\n\n ai: {\n title: 'AI & Embedder',\n description:\n 'LLM provider, model, credentials, and embedder configuration used by ' +\n 'the platform AI and knowledge services.',\n groups: {\n provider: { title: 'Provider',\n description: 'Choose the LLM backend. Memory mode echoes input — useful for tests but never for production.' },\n gateway: { title: 'Vercel AI Gateway',\n description: 'Multi-provider router. The model spec follows `provider/model`, e.g. `openai/gpt-4o`.' },\n openai: { title: 'OpenAI' },\n anthropic: { title: 'Anthropic' },\n google: { title: 'Google' },\n defaults: { title: 'Generation defaults',\n description: 'Applied when an agent or chat request does not specify its own value.' },\n observability: { title: 'Observability' },\n embedder: { title: 'Embedder',\n description:\n 'Text → vector provider used by knowledge sources and RAG. ' +\n 'Independent from the chat provider above.' },\n },\n keys: {\n provider: {\n label: 'Provider',\n options: {\n memory: 'Memory (echo — testing only)',\n gateway: 'Vercel AI Gateway',\n openai: 'OpenAI',\n anthropic: 'Anthropic',\n google: 'Google Generative AI',\n },\n },\n gateway_model: { label: 'Gateway model',\n help: 'Forwarded as AI_GATEWAY_MODEL. Example: openai/gpt-4o' },\n gateway_api_key: { label: 'Gateway API key',\n help: 'Optional — required only if the gateway enforces auth.' },\n openai_api_key: { label: 'OpenAI API key',\n help: 'Forwarded as OPENAI_API_KEY. Stored encrypted at rest.' },\n openai_model: { label: 'Model',\n help: 'Default model id. Per-agent overrides take precedence.' },\n openai_base_url: { label: 'Base URL',\n help: 'Override for Azure OpenAI or self-hosted gateways. Leave blank for api.openai.com.' },\n anthropic_api_key: { label: 'Anthropic API key',\n help: 'Forwarded as ANTHROPIC_API_KEY. Stored encrypted at rest.' },\n anthropic_model: { label: 'Model' },\n google_api_key: { label: 'Google API key',\n help: 'Forwarded as GOOGLE_GENERATIVE_AI_API_KEY. Stored encrypted at rest.' },\n google_model: { label: 'Model' },\n temperature: { label: 'Temperature',\n help: '0 = deterministic, 2 = highly creative.' },\n max_tokens: { label: 'Max output tokens',\n help: 'Hard cap on tokens generated per response.' },\n request_timeout_ms: { label: 'Request timeout (ms)' },\n trace_enabled: { label: 'Record traces',\n help: 'Persist prompt/response traces to sys_ai_trace for debugging and replay.' },\n log_prompts: { label: 'Log full prompts',\n help: 'Include rendered prompts (not just metadata) in trace rows. ⚠ May leak PII — disable in regulated environments.' },\n embedder_provider: {\n label: 'Provider',\n options: {\n none: 'Disabled (no embeddings)',\n openai: 'OpenAI',\n azure: 'Azure OpenAI',\n dashscope: '阿里通义 DashScope',\n zhipu: '智谱 BigModel',\n siliconflow: '硅基流动 SiliconFlow',\n doubao: '火山引擎 Doubao',\n minimax: 'MiniMax',\n ollama: 'Ollama (local)',\n custom: 'Custom (OpenAI-compatible)',\n },\n },\n embedder_api_key: { label: 'Embedder API key',\n help: 'Bearer token sent as Authorization header. For Ollama any non-empty value works.' },\n embedder_model: { label: 'Model',\n help: 'Examples — OpenAI: text-embedding-3-small · 阿里通义: text-embedding-v3 · 智谱: embedding-3 · 硅基流动: BAAI/bge-m3 · Ollama: bge-m3' },\n embedder_base_url: { label: 'Base URL',\n help: 'Endpoint root (without /embeddings). Auto-filled from preset; override for proxies or self-hosted gateways.' },\n embedder_dimensions: { label: 'Dimensions',\n help: 'Override output dimensionality (Matryoshka models only). Leave blank to use the model default.' },\n embedder_batch_size: { label: 'Batch size',\n help: 'Chunks per embed() call. Reduce if hitting provider rate / size limits.' },\n },\n actions: {\n test: { label: 'Test connection' },\n test_embedder: { label: 'Test embedder' },\n },\n },\n\n knowledge: {\n title: 'Knowledge',\n description:\n 'Vector-store backend for RAG / knowledge sources. ' +\n '⚠ Switching adapter does NOT migrate existing indices.',\n groups: {\n adapter: { title: 'Backend',\n description: 'Choose where document chunks and their vectors are stored.' },\n turso: { title: 'Turso / libSQL',\n description: 'Works against managed Turso, local file, or in-memory.' },\n ragflow: { title: 'RAGFlow',\n description: 'External RAGFlow deployment. See https://ragflow.io for self-host instructions.' },\n indexing: { title: 'Indexing defaults',\n description: 'Per-source values on KnowledgeSource.adapterConfig take precedence.' },\n permissions: { title: 'Permissions' },\n },\n keys: {\n adapter: {\n label: 'Adapter',\n options: {\n memory: 'In-memory (dev / test only)',\n turso: 'Turso / libSQL (cloud or local)',\n ragflow: 'RAGFlow (external)',\n },\n },\n turso_url: { label: 'Connection URL',\n help: 'Examples: libsql://your-tenant.turso.io · file:./.objectstack/knowledge.db · :memory:' },\n turso_auth_token: { label: 'Auth token',\n help: 'Only required for managed Turso URLs.' },\n ragflow_base_url: { label: 'Base URL', help: 'Example: http://localhost:9380' },\n ragflow_api_key: { label: 'API key' },\n ragflow_default_dataset: { label: 'Default dataset id',\n help: 'Used when a KnowledgeSource does not specify its own RAGFlow dataset.' },\n chunk_target: { label: 'Target chunk size (chars)',\n help: 'Soft cap on chunk size before token-aware splitting kicks in.' },\n chunk_overlap: { label: 'Chunk overlap (chars)',\n help: 'Characters retained from the previous chunk so context survives the boundary.' },\n over_fetch: { label: 'Over-fetch multiplier',\n help: 'Internal topK × overFetch candidates fetched so JS-side metadata filtering still has rows.' },\n enforce_rls: { label: 'Enforce RLS on search',\n help: 'Re-check every hit against the caller\\'s record-level permissions. ⚠ Disabling skips the platform\\'s unique safeguard.' },\n },\n actions: {\n test: { label: 'Test connection' },\n },\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\n/**\n * 简体中文 (zh-CN) — built-in settings manifest translations.\n */\nexport const zhCN: TranslationData = {\n settingsCommon: {\n sourceLabels: {\n env: '环境变量',\n global: '全局',\n tenant: '租户',\n user: '用户',\n default: '默认',\n },\n },\n settings: {\n mail: {\n title: '邮件投递',\n description: 'SMTP 与事务性邮件服务商配置。',\n groups: {\n provider: { title: '服务商', description: '选择此工作区如何发送邮件。' },\n smtp: { title: 'SMTP' },\n api_key: { title: 'API 密钥' },\n from_address: { title: '发件地址' },\n },\n keys: {\n provider: {\n label: '服务商',\n options: {\n smtp: 'SMTP',\n sendgrid: 'SendGrid',\n ses: 'Amazon SES',\n postmark: 'Postmark',\n },\n },\n smtp_host: { label: '主机', help: '示例:smtp.example.com' },\n smtp_port: { label: '端口' },\n smtp_secure: { label: '启用 TLS' },\n smtp_user: { label: '用户名' },\n smtp_password: { label: '密码' },\n api_key: { label: 'API 密钥' },\n from_email: { label: '发件地址', help: '示例:no-reply@example.com' },\n from_name: { label: '发件人名称' },\n },\n actions: {\n test: { label: '发送测试邮件' },\n },\n },\n\n branding: {\n title: '品牌',\n description: '工作区名称、Logo 与主题色。',\n groups: {\n identity: { title: '身份' },\n appearance: { title: '外观' },\n },\n keys: {\n workspace_name: { label: '工作区名称' },\n support_email: { label: '客服邮箱', help: '示例:support@example.com' },\n theme_mode: {\n label: '默认主题',\n options: { light: '浅色', dark: '深色', system: '跟随系统' },\n },\n accent_color: { label: '主题色' },\n logo_url: { label: 'Logo 链接', help: '示例:https://…/logo.svg' },\n },\n },\n\n feature_flags: {\n title: '功能开关',\n description: '为当前工作区开启实验性与测试功能。',\n groups: {\n productivity: { title: '生产力' },\n collaboration: { title: '协作' },\n },\n keys: {\n ai_enabled: {\n label: 'AI 助手',\n help: '启用应用内 AI 助手面板。',\n },\n kanban_swimlanes: { label: '看板泳道' },\n realtime_cursors: { label: '实时光标' },\n inline_comments: { label: '行内评论' },\n },\n },\n\n storage: {\n title: '文件存储',\n description:\n '附件、导出文件与用户上传所使用的存储后端。' +\n '⚠ 切换适配器不会迁移已有文件 —— 通过旧适配器上传的文件,在新适配器中将不可访问。',\n groups: {\n adapter: { title: '存储后端', description: '选择上传文件的存放位置。' },\n local: { title: '本地' },\n s3: { title: 'S3' },\n limits: { title: '限制' },\n },\n keys: {\n adapter: {\n label: '适配器',\n options: { local: '本地文件系统', s3: 'S3 / S3 兼容' },\n },\n local_root: { label: '根目录',\n help: '文件存放的文件系统路径。相对路径相对于服务进程的工作目录。' },\n s3_bucket: { label: 'Bucket',\n help: '共享主机 Bucket。各项目的文件通过 projects/<environmentId>/ 前缀进行隔离。' },\n s3_region: { label: '区域', help: '示例:us-east-1' },\n s3_endpoint: { label: 'Endpoint',\n help: 'S3 兼容服务(R2、MinIO、Wasabi)的自定义 Endpoint;AWS S3 请留空。' },\n s3_access_key_id: { label: 'Access Key ID' },\n s3_secret_access_key: { label: 'Secret Access Key' },\n s3_force_path_style: { label: '强制路径风格 URL',\n help: 'MinIO 与大多数 S3 兼容服务请开启;AWS S3 请关闭。' },\n presigned_ttl: { label: '预签名 URL 有效期(秒)' },\n session_ttl: { label: '分片上传会话有效期(秒)',\n help: '分片上传会话保持可续传的时长。' },\n max_upload_mb: { label: '单文件最大上传(MB)' },\n },\n actions: {\n test: { label: '测试连接' },\n },\n },\n\n ai: {\n title: 'AI 与 Embedder',\n description: '平台 AI 与知识库服务使用的 LLM 提供商、模型、凭据与向量化配置。',\n groups: {\n provider: { title: '提供商', description: '选择 LLM 后端。Memory 模式仅原样回显输入,仅用于测试,严禁用于生产。' },\n gateway: { title: 'Vercel AI Gateway', description: '多提供商路由器。模型规格遵循 `provider/model` 格式,例如 `openai/gpt-4o`。' },\n openai: { title: 'OpenAI' },\n anthropic: { title: 'Anthropic' },\n google: { title: 'Google' },\n defaults: { title: '生成默认值', description: '当 Agent 或聊天请求未指定时使用。' },\n observability: { title: '可观测性' },\n embedder: { title: 'Embedder', description: '知识库和 RAG 使用的文本→向量提供商,与上方聊天提供商相互独立。' },\n },\n keys: {\n provider: {\n label: '提供商',\n options: {\n memory: 'Memory(回显 — 仅测试)',\n gateway: 'Vercel AI Gateway',\n openai: 'OpenAI',\n anthropic: 'Anthropic',\n google: 'Google Generative AI',\n },\n },\n gateway_model: { label: 'Gateway 模型', help: '作为 AI_GATEWAY_MODEL 转发。示例:openai/gpt-4o' },\n gateway_api_key: { label: 'Gateway API Key', help: '可选 —— 仅当 Gateway 强制鉴权时需要。' },\n openai_api_key: { label: 'OpenAI API Key', help: '作为 OPENAI_API_KEY 转发,加密存储。' },\n openai_model: { label: '模型', help: '默认模型 ID。Agent 级覆盖优先生效。' },\n openai_base_url: { label: 'Base URL', help: '用于 Azure OpenAI 或自建网关。留空走 api.openai.com。' },\n anthropic_api_key: { label: 'Anthropic API Key', help: '作为 ANTHROPIC_API_KEY 转发,加密存储。' },\n anthropic_model: { label: '模型' },\n google_api_key: { label: 'Google API Key', help: '作为 GOOGLE_GENERATIVE_AI_API_KEY 转发,加密存储。' },\n google_model: { label: '模型' },\n temperature: { label: '温度', help: '0 = 确定性,2 = 高度发散。' },\n max_tokens: { label: '最大输出 tokens', help: '单次响应生成的硬上限。' },\n request_timeout_ms: { label: '请求超时(毫秒)' },\n trace_enabled: { label: '记录 Trace', help: '将 prompt/response 落入 sys_ai_trace,便于调试与回放。' },\n log_prompts: { label: '记录完整 Prompt', help: '在 trace 行中包含完整 prompt 而非仅元数据。⚠ 可能泄露 PII,合规场景请关闭。' },\n embedder_provider: {\n label: '提供商',\n options: {\n none: '禁用(不做向量化)',\n openai: 'OpenAI',\n azure: 'Azure OpenAI',\n dashscope: '阿里通义 DashScope',\n zhipu: '智谱 BigModel',\n siliconflow: '硅基流动 SiliconFlow',\n doubao: '火山引擎 Doubao',\n minimax: 'MiniMax',\n ollama: 'Ollama(本地)',\n custom: '自定义(OpenAI 兼容)',\n },\n },\n embedder_api_key: { label: 'Embedder API Key', help: '作为 Authorization Bearer 发送。Ollama 任意非空值均可。' },\n embedder_model: { label: '模型', help: '示例 — OpenAI: text-embedding-3-small · 阿里通义: text-embedding-v3 · 智谱: embedding-3 · 硅基流动: BAAI/bge-m3 · Ollama: bge-m3' },\n embedder_base_url: { label: 'Base URL', help: '端点根路径(不含 /embeddings)。预设会自动填充,可覆盖为代理或自建网关。' },\n embedder_dimensions: { label: '维度', help: '覆盖输出维度(仅 Matryoshka 模型支持)。留空使用模型默认值。' },\n embedder_batch_size: { label: '批量大小', help: '单次 embed() 调用的 chunk 数。命中速率/大小限制时调小。' },\n },\n actions: {\n test: { label: '测试连接' },\n test_embedder: { label: '测试 Embedder' },\n },\n },\n\n knowledge: {\n title: '知识库',\n description: 'RAG / 知识源使用的向量存储后端。⚠ 切换适配器不会迁移已有索引。',\n groups: {\n adapter: { title: '后端', description: '选择文档分块及其向量的存储位置。' },\n turso: { title: 'Turso / libSQL', description: '支持托管 Turso、本地文件、内存三种模式。' },\n ragflow: { title: 'RAGFlow', description: '外部 RAGFlow 部署。自部署文档见 https://ragflow.io 。' },\n indexing: { title: '索引默认值', description: 'KnowledgeSource.adapterConfig 上的逐源覆盖优先生效。' },\n permissions: { title: '权限' },\n },\n keys: {\n adapter: {\n label: '适配器',\n options: {\n memory: '内存(仅开发/测试)',\n turso: 'Turso / libSQL(云端或本地)',\n ragflow: 'RAGFlow(外部)',\n },\n },\n turso_url: { label: '连接 URL', help: '示例:libsql://your-tenant.turso.io · file:./.objectstack/knowledge.db · :memory:' },\n turso_auth_token: { label: 'Auth Token', help: '仅托管 Turso URL 需要。' },\n ragflow_base_url: { label: 'Base URL', help: '示例:http://localhost:9380' },\n ragflow_api_key: { label: 'API Key' },\n ragflow_default_dataset: { label: '默认 Dataset ID', help: 'KnowledgeSource 未指定时使用。' },\n chunk_target: { label: '目标 chunk 大小(字符)', help: '在按 token 切分之前的软上限。' },\n chunk_overlap: { label: 'Chunk 重叠(字符)', help: '保留上一个 chunk 末尾的字符,以保证跨界上下文。' },\n over_fetch: { label: '过取倍数', help: '内部按 topK × overFetch 拉取候选,以便 JS 端元数据过滤仍有行可返回。' },\n enforce_rls: { label: '搜索时强制 RLS', help: '对每条命中通过 IDataEngine 再次校验调用方的行级权限。⚠ 关闭将跳过平台对向量存储数据外泄的独有防护。' },\n },\n actions: {\n test: { label: '测试连接' },\n },\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\n/**\n * 日本語 (ja-JP) — built-in settings manifest translations.\n */\nexport const jaJP: TranslationData = {\n settingsCommon: {\n sourceLabels: {\n env: '環境変数',\n global: 'グローバル',\n tenant: 'テナント',\n user: 'ユーザー',\n default: 'デフォルト',\n },\n },\n settings: {\n mail: {\n title: 'メール配信',\n description: 'SMTP およびトランザクションメールプロバイダー設定。',\n groups: {\n provider: { title: 'プロバイダー', description: 'このワークスペースの送信方法を選択します。' },\n smtp: { title: 'SMTP' },\n api_key: { title: 'API キー' },\n from_address: { title: '差出人アドレス' },\n },\n keys: {\n provider: {\n label: 'プロバイダー',\n options: {\n smtp: 'SMTP',\n sendgrid: 'SendGrid',\n ses: 'Amazon SES',\n postmark: 'Postmark',\n },\n },\n smtp_host: { label: 'ホスト', help: '例: smtp.example.com' },\n smtp_port: { label: 'ポート' },\n smtp_secure: { label: 'TLS を使用' },\n smtp_user: { label: 'ユーザー名' },\n smtp_password: { label: 'パスワード' },\n api_key: { label: 'API キー' },\n from_email: { label: '差出人アドレス', help: '例: no-reply@example.com' },\n from_name: { label: '差出人名' },\n },\n actions: {\n test: { label: 'テストメール送信' },\n },\n },\n\n branding: {\n title: 'ブランディング',\n description: 'ワークスペース名・ロゴ・アクセントカラー。',\n groups: {\n identity: { title: 'アイデンティティ' },\n appearance: { title: '外観' },\n },\n keys: {\n workspace_name: { label: 'ワークスペース名' },\n support_email: { label: 'サポートメール', help: '例: support@example.com' },\n theme_mode: {\n label: 'デフォルトテーマ',\n options: { light: 'ライト', dark: 'ダーク', system: 'システムに従う' },\n },\n accent_color: { label: 'アクセントカラー' },\n logo_url: { label: 'ロゴ URL', help: '例: https://…/logo.svg' },\n },\n },\n\n feature_flags: {\n title: '機能フラグ',\n description: 'このワークスペースで実験的・ベータ機能を切替えます。',\n groups: {\n productivity: { title: '生産性' },\n collaboration: { title: 'コラボレーション' },\n },\n keys: {\n ai_enabled: {\n label: 'AI アシスタント',\n help: 'アプリ内 AI アシスタントパネルを有効化します。',\n },\n kanban_swimlanes: { label: 'カンバンのスイムレーン' },\n realtime_cursors: { label: 'リアルタイムカーソル' },\n inline_comments: { label: 'インラインコメント' },\n },\n },\n\n storage: {\n title: 'ファイルストレージ',\n description:\n '添付ファイル・エクスポート・ユーザーアップロードに使用するバックエンド。' +\n '⚠ アダプターを切替えても既存ファイルは移行されません。以前のアダプターでアップロードされたファイルは新しいアダプターからアクセスできなくなります。',\n groups: {\n adapter: { title: 'バックエンド', description: 'アップロードファイルの保存先を選択します。' },\n local: { title: 'ローカル' },\n s3: { title: 'S3' },\n limits: { title: '制限' },\n },\n keys: {\n adapter: {\n label: 'アダプター',\n options: { local: 'ローカルファイルシステム', s3: 'S3 / S3 互換' },\n },\n local_root: { label: 'ルートディレクトリ',\n help: 'ファイルを保存するファイルシステムパス。相対パスはサーバーの CWD から解決されます。' },\n s3_bucket: { label: 'バケット',\n help: '共有ホストバケット。プロジェクト毎のファイルは projects/<environmentId>/ プレフィックスで分離されます。' },\n s3_region: { label: 'リージョン', help: '例: us-east-1' },\n s3_endpoint: { label: 'エンドポイント',\n help: 'S3 互換プロバイダ (R2, MinIO, Wasabi) のカスタムエンドポイント。AWS S3 の場合は空欄。' },\n s3_access_key_id: { label: 'アクセスキー ID' },\n s3_secret_access_key: { label: 'シークレットアクセスキー' },\n s3_force_path_style: { label: 'パススタイル URL を強制',\n help: 'MinIO や多くの S3 互換プロバイダで有効化。AWS S3 では無効化。' },\n presigned_ttl: { label: '署名付き URL の有効期間 (秒)' },\n session_ttl: { label: 'アップロードセッション TTL (秒)',\n help: 'チャンクアップロードの再開可能期間。' },\n max_upload_mb: { label: '最大アップロードサイズ (MB)' },\n },\n actions: {\n test: { label: '接続テスト' },\n },\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Built-in Settings translations.\n *\n * Mirrors the CRM example's `src/translations/{en,zh-CN,ja-JP}.ts` convention —\n * one file per locale, aggregated into a `TranslationBundle` here.\n *\n * Hosts merge `settingsBuiltinTranslations` into the i18next resource tree\n * under whatever namespace makes sense (the console wires it as `system`),\n * making keys resolvable as `<ns>.settings.<namespace>.{title,description,...}`.\n */\n\nimport type { TranslationBundle } from '@objectstack/spec/system';\nimport { en } from './en.js';\nimport { zhCN } from './zh-CN.js';\nimport { jaJP } from './ja-JP.js';\n\nexport { en, zhCN, jaJP };\n\nexport const settingsBuiltinTranslations: TranslationBundle = {\n en,\n 'zh-CN': zhCN,\n 'ja-JP': jaJP,\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { IHttpServer, IDataEngine } from '@objectstack/spec/contracts';\nimport type { SettingsManifest } from '@objectstack/spec/system';\nimport { SettingsService } from './settings-service.js';\nimport type { ICryptoProvider } from '@objectstack/spec/contracts';\nimport type { SettingsAuditSink, SettingsAuditWriter, SettingsEngine, SettingsSecretStore } from './settings-service.types.js';\nimport type { CryptoAdapter } from './crypto-adapter.js';\nimport { InMemoryCryptoProvider } from './in-memory-crypto-provider.js';\nimport { registerSettingsRoutes } from './settings-routes.js';\nimport {\n settingsObjects,\n settingsPluginManifestHeader,\n SETTINGS_PLUGIN_ID,\n SETTINGS_PLUGIN_VERSION,\n} from './manifest.js';\nimport {\n builtinSettingsManifests,\n mailTestActionHandler,\n storageTestActionHandler,\n aiTestActionHandler,\n} from './manifests/index.js';\nimport { settingsBuiltinTranslations } from './translations/index.js';\n\n/** Configuration options for the SettingsServicePlugin. */\nexport interface SettingsServicePluginOptions {\n /**\n * Pre-register these manifests at boot. When omitted, the bundled\n * builtin manifests (mail / branding / feature_flags) are loaded so\n * a host gets a working Settings hub out of the box. Pass an empty\n * array to opt out entirely.\n */\n manifests?: SettingsManifest[];\n /** Override the default crypto adapter. */\n crypto?: CryptoAdapter;\n\n /**\n * Phase 3 KMS hook. When provided, encrypted specifier values are\n * routed through this provider into `sys_secret`; `sys_setting.value_enc`\n * holds the handle id only. Defaults to `InMemoryCryptoProvider`\n * (NOT suitable for production secrets — replace with an AWS / GCP\n * KMS-backed implementation).\n */\n cryptoProvider?: ICryptoProvider;\n /** Override the default base path (`/api/settings`). */\n basePath?: string;\n /** Disable REST route registration. */\n registerRoutes?: boolean;\n /** Override the env source. Defaults to `process.env`. */\n env?: Record<string, string | undefined>;\n /**\n * Action handlers to register at boot, keyed by namespace and action\n * id. The bundled `mail.test` handler is registered automatically\n * unless this object is provided.\n */\n actionHandlers?: Record<string, Record<string, import('./settings-service.types.js').SettingsActionHandler>>;\n}\n\n/**\n * SettingsServicePlugin — wires the SettingsService into the kernel.\n *\n * 1. `init`: instantiate the service, register it under `'settings'`,\n * and ship `sys_setting` to the manifest service so the engine\n * auto-provisions the table.\n * 2. `start` → `kernel:ready`: bind the data engine (when present),\n * wire the audit sink (when present), mount REST routes.\n */\nexport class SettingsServicePlugin implements Plugin {\n name = SETTINGS_PLUGIN_ID;\n version = SETTINGS_PLUGIN_VERSION;\n type = 'standard' as const;\n\n private readonly opts: SettingsServicePluginOptions;\n private service: SettingsService | null = null;\n\n constructor(opts: SettingsServicePluginOptions = {}) {\n this.opts = {\n ...opts,\n manifests: opts.manifests ?? builtinSettingsManifests,\n actionHandlers: opts.actionHandlers ?? {\n mail: { test: mailTestActionHandler },\n storage: { test: storageTestActionHandler },\n ai: { test: aiTestActionHandler },\n },\n };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n this.service = new SettingsService({\n crypto: this.opts.crypto,\n env: this.opts.env,\n });\n for (const m of this.opts.manifests ?? []) this.service.registerManifest(m);\n for (const [ns, handlers] of Object.entries(this.opts.actionHandlers ?? {})) {\n for (const [id, fn] of Object.entries(handlers)) {\n this.service.registerAction(ns, id, fn);\n }\n }\n\n ctx.registerService('settings', this.service);\n ctx.logger?.info?.(\n `SettingsServicePlugin: registered (manifests=${this.opts.manifests?.length ?? 0})`,\n );\n\n // Register the K/V object so the engine creates the table.\n try {\n ctx.getService<{ register(m: any): void }>('manifest').register({\n ...settingsPluginManifestHeader,\n objects: settingsObjects,\n });\n } catch {\n // manifest service is optional — skip in lean test kernels.\n }\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (!this.service) return;\n\n ctx.hook('kernel:ready', async () => {\n // Contribute built-in settings translations into the i18n service.\n // Done in `kernel:ready` (not `init`) because the i18n service plugin\n // is typically registered AFTER capability-loaded service plugins.\n try {\n const i18n = ctx.getService<{\n loadTranslations: (locale: string, data: Record<string, unknown>) => void;\n }>('i18n');\n let loaded = 0;\n for (const [locale, data] of Object.entries(settingsBuiltinTranslations)) {\n if (data && typeof data === 'object') {\n try {\n i18n.loadTranslations(locale, data as Record<string, unknown>);\n loaded++;\n } catch (err: any) {\n ctx.logger?.warn?.(\n `SettingsServicePlugin: failed to load translations for '${locale}': ${err?.message ?? err}`,\n );\n }\n }\n }\n if (loaded > 0) {\n ctx.logger?.info?.(\n `SettingsServicePlugin: contributed built-in translations (${loaded} locale${loaded > 1 ? 's' : ''})`,\n );\n }\n } catch {\n // i18n service not registered — manifest literals remain authoritative.\n }\n\n // Late-bind the data engine.\n let engine: IDataEngine | null = null;\n try {\n engine = ctx.getService<IDataEngine>('objectql');\n } catch {\n // ok — fall back to in-memory.\n }\n if (engine) {\n // Late-bind the engine + audit sink on the existing service\n // instance. We avoid re-registering the service because the\n // kernel disallows `registerService` for an already-registered\n // name.\n this.service!.bindEngine(\n engine as unknown as SettingsEngine,\n this.buildAuditSink(ctx, engine),\n {\n secretStore: this.buildSecretStore(engine),\n auditWriter: this.buildAuditWriter(ctx, engine),\n cryptoProvider: this.opts.cryptoProvider ?? new InMemoryCryptoProvider(),\n },\n );\n }\n\n if (this.opts.registerRoutes === false) return;\n\n let http: IHttpServer | null = null;\n try {\n http = ctx.getService<IHttpServer>('http-server');\n } catch {\n // ok — no HTTP server in this deployment.\n }\n if (!http) {\n ctx.logger?.warn?.(\n 'SettingsServicePlugin: no HTTP server available — REST routes not registered. ' +\n 'SettingsService is still reachable via kernel.getService(\"settings\").',\n );\n return;\n }\n registerSettingsRoutes(http, this.service!, { basePath: this.opts.basePath });\n ctx.logger?.info?.(\n 'SettingsServicePlugin: REST routes registered at ' + (this.opts.basePath ?? '/api/settings'),\n );\n });\n }\n\n /** Glue an `engine.insert('sys_audit_log', …)` audit sink. */\n private buildAuditSink(ctx: PluginContext, engine: IDataEngine): SettingsAuditSink {\n return {\n record: async (entry) => {\n try {\n await (engine as any).insert?.('sys_audit_log', {\n actor_id: entry.userId ?? null,\n entity_type: 'sys_setting',\n entity_id: `${entry.namespace}.${entry.key}`,\n action: entry.action,\n payload: {\n namespace: entry.namespace,\n key: entry.key,\n scope: entry.scope,\n encrypted: entry.encrypted,\n digest: entry.valueDigest,\n },\n request_id: entry.requestId ?? null,\n occurred_at: new Date().toISOString(),\n });\n } catch (err: any) {\n ctx.logger?.warn?.('SettingsServicePlugin: audit record failed: ' + (err?.message ?? err));\n }\n },\n };\n }\n\n /**\n * Phase 3: build a `sys_secret`-backed implementation of\n * `SettingsSecretStore`. The store bypasses the tenant audit\n * warning because secrets are scoped through their owning\n * `sys_setting` row (which already carries the tenant context).\n */\n private buildSecretStore(engine: IDataEngine): SettingsSecretStore {\n const eng: any = engine;\n return {\n async insert(row) {\n await eng.insert('sys_secret', row, { bypassTenantAudit: true });\n return { id: row.id };\n },\n async get(id) {\n const rows = await eng.find('sys_secret', {\n where: { id },\n limit: 1,\n bypassTenantAudit: true,\n });\n const row = Array.isArray(rows) ? rows[0] : rows?.data?.[0];\n return row ?? null;\n },\n async update(id, patch) {\n await eng.update('sys_secret', {\n where: { id },\n data: patch,\n bypassTenantAudit: true,\n });\n },\n };\n }\n\n /**\n * Phase 3: append-only writer for `sys_setting_audit`. Failures here\n * MUST NOT abort the settings write, so all calls are wrapped in a\n * try/catch and reported through the plugin logger.\n */\n private buildAuditWriter(ctx: PluginContext, engine: IDataEngine): SettingsAuditWriter {\n const eng: any = engine;\n return {\n write: async (entry) => {\n try {\n await eng.insert('sys_setting_audit', {\n namespace: entry.namespace,\n key: entry.key,\n scope: entry.scope,\n action: entry.action,\n source: entry.source ?? 'api',\n actor_id: entry.actorId ?? null,\n old_hash: entry.oldHash ?? null,\n new_hash: entry.newHash ?? null,\n encrypted: !!entry.encrypted,\n request_id: entry.requestId ?? null,\n reason: entry.reason ?? null,\n created_at: new Date().toISOString(),\n }, { bypassTenantAudit: true });\n } catch (err: any) {\n ctx.logger?.warn?.('SettingsServicePlugin: setting-audit write failed: ' + (err?.message ?? err));\n }\n },\n };\n }\n}\n"],"mappings":"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","names":["manifest","def","manifest","manifest","manifest"]}