From 24cadbfc37ba0e02633cfdd0ce3856ee5d08bfe0 Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Sat, 27 Jun 2026 22:51:04 +0800 Subject: [PATCH] feat(types)!: remove ObjectStack's own legacy env-var aliases (11.0, #2379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the framework's own renamed env names; keeps ubiquitous ecosystem conventions working (now silent, since they're permanent — not deprecated). Removed (rename required): - OS_MULTI_TENANT → OS_MULTI_ORG_ENABLED (resolveMultiOrgEnabled) - OBJECTSTACK_METADATA_WRITABLE → OS_METADATA_WRITABLE (sys-metadata-repository) - OS_AUTH_BASE_URL / AUTH_BASE_URL → OS_AUTH_URL (cli serve) Reclassified to silent (kept, no more nag): DATABASE_URL, AUTH_SECRET, BETTER_AUTH_SECRET, BETTER_AUTH_URL, CORS_*, LOG_LEVEL, ROOT_DOMAIN, MCP_SERVER_*, PORT. Also updated now-stale comments + plugin-org-scoping / plugin-security READMEs + object.zod / protocol.zod describe text to the canonical names. The generic readEnvWithDeprecation helper + env.test.ts (synthetic names) are unchanged. Verified: types env (7), cli (436), objectql (718), driver-sql (234), plugin-auth (175), mcp (53), plugin-hono-server (40) all green; spec api-surface check unchanged; 53 build tasks green. Co-Authored-By: Claude Opus 4.8 --- .changeset/v11-remove-env-aliases.md | 22 +++++++++++++++++++ packages/adapters/hono/src/index.ts | 8 +++---- packages/cli/src/commands/serve.ts | 6 ++--- packages/cli/src/commands/start.ts | 4 ++-- packages/cli/src/utils/log-level.ts | 2 +- packages/mcp/src/plugin.ts | 6 ++--- packages/objectql/src/registry.ts | 4 ++-- .../objectql/src/sys-metadata-repository.ts | 2 +- packages/plugins/driver-sql/src/sql-driver.ts | 5 ++--- .../plugins/plugin-auth/src/auth-manager.ts | 13 +++++------ .../plugin-hono-server/src/hono-plugin.ts | 8 +++---- packages/plugins/plugin-org-scoping/README.md | 4 ++-- packages/plugins/plugin-security/README.md | 2 +- packages/runtime/src/standalone-stack.ts | 2 +- packages/spec/src/api/protocol.zod.ts | 2 +- packages/spec/src/data/object.zod.ts | 2 +- packages/types/src/env.ts | 8 +++---- 17 files changed, 59 insertions(+), 41 deletions(-) create mode 100644 .changeset/v11-remove-env-aliases.md diff --git a/.changeset/v11-remove-env-aliases.md b/.changeset/v11-remove-env-aliases.md new file mode 100644 index 0000000000..1a0a298323 --- /dev/null +++ b/.changeset/v11-remove-env-aliases.md @@ -0,0 +1,22 @@ +--- +"@objectstack/types": major +"@objectstack/objectql": major +"@objectstack/cli": major +--- + +Remove ObjectStack's own legacy env-var aliases (11.0); ecosystem-standard names stay. + +The framework's renamed env vars no longer accept their old ObjectStack names — +rename them: + +| removed legacy name | use | +|---|---| +| `OS_MULTI_TENANT` | `OS_MULTI_ORG_ENABLED` | +| `OBJECTSTACK_METADATA_WRITABLE` | `OS_METADATA_WRITABLE` | +| `OS_AUTH_BASE_URL`, `AUTH_BASE_URL` | `OS_AUTH_URL` | + +**Ecosystem-standard names are NOT removed** — they remain accepted (and no longer +emit a deprecation warning, since they are permanent conventions, not legacy): +`DATABASE_URL`, `AUTH_SECRET`, `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`, `PORT`, +`CORS_*`, `LOG_LEVEL`, `ROOT_DOMAIN`, `MCP_SERVER_*`. The generic +`readEnvWithDeprecation` helper is unchanged. diff --git a/packages/adapters/hono/src/index.ts b/packages/adapters/hono/src/index.ts index d50601179c..9dd4469076 100644 --- a/packages/adapters/hono/src/index.ts +++ b/packages/adapters/hono/src/index.ts @@ -124,7 +124,7 @@ export function createHonoApp(options: ObjectStackHonoOptions): Hono { // OS_CORS_CREDENTIALS – "false" to disallow credentials (default: true) // OS_CORS_MAX_AGE – preflight cache seconds (default: 86400) // (legacy CORS_* names still honoured with a deprecation warning) - const corsDisabledByEnv = readEnvWithDeprecation('OS_CORS_ENABLED', 'CORS_ENABLED') === 'false'; + const corsDisabledByEnv = readEnvWithDeprecation('OS_CORS_ENABLED', 'CORS_ENABLED', { silent: true }) === 'false'; if (options.cors !== false && !corsDisabledByEnv) { const corsOpts = typeof options.cors === 'object' ? options.cors : {}; const enabled = corsOpts.enabled ?? true; @@ -132,7 +132,7 @@ export function createHonoApp(options: ObjectStackHonoOptions): Hono { if (enabled) { // Resolve origins: options > env > default '*' let configuredOrigin: string | string[]; - const corsOriginEnv = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN'); + const corsOriginEnv = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN', { silent: true }); if (corsOpts.origin) { configuredOrigin = corsOpts.origin; } else if (corsOriginEnv) { @@ -142,8 +142,8 @@ export function createHonoApp(options: ObjectStackHonoOptions): Hono { configuredOrigin = '*'; } - const credentials = corsOpts.credentials ?? (readEnvWithDeprecation('OS_CORS_CREDENTIALS', 'CORS_CREDENTIALS') !== 'false'); - const maxAgeEnv = readEnvWithDeprecation('OS_CORS_MAX_AGE', 'CORS_MAX_AGE'); + const credentials = corsOpts.credentials ?? (readEnvWithDeprecation('OS_CORS_CREDENTIALS', 'CORS_CREDENTIALS', { silent: true }) !== 'false'); + const maxAgeEnv = readEnvWithDeprecation('OS_CORS_MAX_AGE', 'CORS_MAX_AGE', { silent: true }); const maxAge = corsOpts.maxAge ?? (maxAgeEnv ? parseInt(maxAgeEnv, 10) : 86400); // When credentials is true, browsers reject wildcard '*' for Access-Control-Allow-Origin. diff --git a/packages/cli/src/commands/serve.ts b/packages/cli/src/commands/serve.ts index 4ec132454a..8a9486474e 100644 --- a/packages/cli/src/commands/serve.ts +++ b/packages/cli/src/commands/serve.ts @@ -1099,7 +1099,7 @@ export default class Serve extends Command { // In dev, fall back to a stable local secret so users don't have // to set OS_AUTH_SECRET just to try the login/register flow. - const secret = readEnvWithDeprecation('OS_AUTH_SECRET', ['AUTH_SECRET', 'BETTER_AUTH_SECRET']) + const secret = readEnvWithDeprecation('OS_AUTH_SECRET', ['AUTH_SECRET', 'BETTER_AUTH_SECRET'], { silent: true }) ?? (isDev ? 'dev-only-insecure-secret-change-me-in-production' : undefined); // Guard: in cloud-connected runtime mode (e.g. objectos worker) @@ -1128,7 +1128,7 @@ export default class Serve extends Command { } else if (!secret) { console.warn(chalk.yellow(' ⚠ AuthPlugin skipped — set OS_AUTH_SECRET to enable authentication in production')); } else { - const baseUrl = readEnvWithDeprecation('OS_AUTH_URL', ['OS_AUTH_BASE_URL', 'AUTH_BASE_URL', 'BETTER_AUTH_URL']) + const baseUrl = readEnvWithDeprecation('OS_AUTH_URL', 'BETTER_AUTH_URL', { silent: true }) ?? process.env.OS_BASE_URL ?? `http://localhost:${port}`; @@ -1184,7 +1184,7 @@ export default class Serve extends Command { // must be trusted by better-auth or sign-up/sign-in is // rejected with "Invalid origin". Mirrors the OS_COOKIE_DOMAIN // wildcard semantics — they are always set together. - const rootDomain = readEnvWithDeprecation('OS_ROOT_DOMAIN', 'ROOT_DOMAIN')?.trim(); + const rootDomain = readEnvWithDeprecation('OS_ROOT_DOMAIN', 'ROOT_DOMAIN', { silent: true })?.trim(); if (rootDomain) { const wildcard = `https://*.${rootDomain}`; if (!trustedOrigins.includes(wildcard)) trustedOrigins.push(wildcard); diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts index e4d842d7a6..fac1384487 100644 --- a/packages/cli/src/commands/start.ts +++ b/packages/cli/src/commands/start.ts @@ -179,7 +179,7 @@ export default class Start extends Command { // ── Database resolution ───────────────────────────────────────── // Priority: --database > $OS_DATABASE_URL > $DATABASE_URL (legacy) > file:/data/objectstack.db const databaseUrl = flags.database - ?? readEnvWithDeprecation('OS_DATABASE_URL', 'DATABASE_URL') + ?? readEnvWithDeprecation('OS_DATABASE_URL', 'DATABASE_URL', { silent: true }) ?? `file:${path.join(homeDir, 'data', 'objectstack.db')}`; const environmentId = flags['environment-id'] @@ -196,7 +196,7 @@ export default class Start extends Command { // Quick-start should "just work" without the user having to // export AUTH_SECRET. const authSecret = flags['auth-secret'] - ?? readEnvWithDeprecation('OS_AUTH_SECRET', ['AUTH_SECRET', 'BETTER_AUTH_SECRET']) + ?? readEnvWithDeprecation('OS_AUTH_SECRET', ['AUTH_SECRET', 'BETTER_AUTH_SECRET'], { silent: true }) ?? readOrCreateAuthSecret(homeDir); // ── Banner ────────────────────────────────────────────────────── diff --git a/packages/cli/src/utils/log-level.ts b/packages/cli/src/utils/log-level.ts index fcb29547a5..a3d91d3d40 100644 --- a/packages/cli/src/utils/log-level.ts +++ b/packages/cli/src/utils/log-level.ts @@ -50,5 +50,5 @@ export function resolveLogLevel(opts: { * environment, emitting the standard deprecation warning for the legacy name. */ export function readLogLevelEnv(): string | undefined { - return readEnvWithDeprecation('OS_LOG_LEVEL', 'LOG_LEVEL'); + return readEnvWithDeprecation('OS_LOG_LEVEL', 'LOG_LEVEL', { silent: true }); } diff --git a/packages/mcp/src/plugin.ts b/packages/mcp/src/plugin.ts index 6ce30dca0a..f32f5109fc 100644 --- a/packages/mcp/src/plugin.ts +++ b/packages/mcp/src/plugin.ts @@ -64,9 +64,9 @@ export class MCPServerPlugin implements Plugin { async init(ctx: PluginContext): Promise { const config: MCPServerRuntimeConfig = { - name: readEnvWithDeprecation('OS_MCP_SERVER_NAME', 'MCP_SERVER_NAME') ?? this.options.name ?? 'objectstack', + name: readEnvWithDeprecation('OS_MCP_SERVER_NAME', 'MCP_SERVER_NAME', { silent: true }) ?? this.options.name ?? 'objectstack', version: this.options.version ?? '1.0.0', - transport: (readEnvWithDeprecation('OS_MCP_SERVER_TRANSPORT', 'MCP_SERVER_TRANSPORT') as 'stdio' | 'http') ?? this.options.transport ?? 'stdio', + transport: (readEnvWithDeprecation('OS_MCP_SERVER_TRANSPORT', 'MCP_SERVER_TRANSPORT', { silent: true }) as 'stdio' | 'http') ?? this.options.transport ?? 'stdio', instructions: this.options.instructions, logger: ctx.logger, }; @@ -118,7 +118,7 @@ export class MCPServerPlugin implements Plugin { } // ── Auto-start if configured ── - const shouldStart = this.options.autoStart || readEnvWithDeprecation('OS_MCP_SERVER_ENABLED', 'MCP_SERVER_ENABLED') === 'true'; + const shouldStart = this.options.autoStart || readEnvWithDeprecation('OS_MCP_SERVER_ENABLED', 'MCP_SERVER_ENABLED', { silent: true }) === 'true'; if (shouldStart) { await this.runtime.start(); ctx.logger.info('[MCP] Server started automatically'); diff --git a/packages/objectql/src/registry.ts b/packages/objectql/src/registry.ts index ecf0124d78..01ec0a3a62 100644 --- a/packages/objectql/src/registry.ts +++ b/packages/objectql/src/registry.ts @@ -133,10 +133,10 @@ export interface SchemaRegistryOptions { * is additionally INDEXED — single-tenant stacks skip the index since * nothing ever filters by organization. * - * Sourced from the `OS_MULTI_TENANT` env var when not explicitly set — + * Sourced from the `OS_MULTI_ORG_ENABLED` env var when not explicitly set — * matches how the SecurityPlugin and CLI startup banner pick the mode. * Default is `false` (single-tenant) so local `dev`/`start` runs seed - * demo data inline at boot; set `OS_MULTI_TENANT=true` for cloud / + * demo data inline at boot; set `OS_MULTI_ORG_ENABLED=true` for cloud / * production multi-org deployments. Pass an explicit boolean to override * (useful in tests). */ diff --git a/packages/objectql/src/sys-metadata-repository.ts b/packages/objectql/src/sys-metadata-repository.ts index bd5e1bd033..d0bb22f21b 100644 --- a/packages/objectql/src/sys-metadata-repository.ts +++ b/packages/objectql/src/sys-metadata-repository.ts @@ -185,7 +185,7 @@ const RUNTIME_CREATE_ALLOWED_TYPES: ReadonlySet = new Set( let _envWritableMetadataTypes: Set | null = null; function envWritableMetadataTypes(): ReadonlySet { if (_envWritableMetadataTypes !== null) return _envWritableMetadataTypes; - const raw = readEnvWithDeprecation('OS_METADATA_WRITABLE', 'OBJECTSTACK_METADATA_WRITABLE') || ''; + const raw = readEnvWithDeprecation('OS_METADATA_WRITABLE', []) || ''; const set = new Set(); for (const tok of raw.split(',')) { const t = tok.trim(); diff --git a/packages/plugins/driver-sql/src/sql-driver.ts b/packages/plugins/driver-sql/src/sql-driver.ts index d3029a113c..ef7acf531f 100644 --- a/packages/plugins/driver-sql/src/sql-driver.ts +++ b/packages/plugins/driver-sql/src/sql-driver.ts @@ -2222,7 +2222,7 @@ export class SqlDriver implements IDataDriver { /** * Whether the host kernel runs in multi-tenant mode — read once from - * `OS_MULTI_ORG_ENABLED` (or the deprecated `OS_MULTI_TENANT`), matching how + * `OS_MULTI_ORG_ENABLED`, matching how * the SchemaRegistry / SecurityPlugin pick the mode. Used to gate the * tenant-audit warning: it's only meaningful where tenant isolation is * actually enforced (org-scoping installed). @@ -2231,8 +2231,7 @@ export class SqlDriver implements IDataDriver { protected isMultiTenantMode(): boolean { if (this._multiTenantMode === undefined) { // Single source of truth (shared with auth/registry/CLI) — previously - // this read `process.env` inline and so never emitted the - // `OS_MULTI_TENANT` deprecation warning the other sites do. + // this read `process.env` inline instead of the shared resolver. this._multiTenantMode = resolveMultiOrgEnabled(); } return this._multiTenantMode; diff --git a/packages/plugins/plugin-auth/src/auth-manager.ts b/packages/plugins/plugin-auth/src/auth-manager.ts index 29f556d5e4..32c7fc0de7 100644 --- a/packages/plugins/plugin-auth/src/auth-manager.ts +++ b/packages/plugins/plugin-auth/src/auth-manager.ts @@ -859,7 +859,7 @@ export class AuthManager { ...(() => { const origins: string[] = [...(this.config.trustedOrigins || [])]; // Sync with OS_CORS_ORIGIN env var (comma-separated) - const corsOrigin = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN'); + const corsOrigin = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN', { silent: true }); if (corsOrigin && corsOrigin !== '*') { corsOrigin.split(',').map(s => s.trim()).filter(Boolean).forEach(o => { if (!origins.includes(o)) origins.push(o); @@ -1137,9 +1137,8 @@ export class AuthManager { // The plugin itself is always installed (so list/update/invite endpoints // keep responding); only the `create` operation is denied when the // deployment is provisioned in single-org mode. Resolution order: - // 1. explicit `OS_MULTI_ORG_ENABLED` (wins for backwards compat), - // 2. else `OS_MULTI_TENANT` (multi-tenant deployments are always - // multi-org), default `'false'` → single-org / per-env runtime. + // `OS_MULTI_ORG_ENABLED` (default `'false'` → single-org / + // per-env runtime). beforeCreateOrganization: async () => { if (!resolveMultiOrgEnabled()) { const { APIError } = await import('better-auth/api'); @@ -1565,7 +1564,7 @@ export class AuthManager { * Generate a secure secret if not provided */ private generateSecret(): string { - const envSecret = readEnvWithDeprecation('OS_AUTH_SECRET', ['AUTH_SECRET', 'BETTER_AUTH_SECRET']); + const envSecret = readEnvWithDeprecation('OS_AUTH_SECRET', ['AUTH_SECRET', 'BETTER_AUTH_SECRET'], { silent: true }); if (envSecret) return envSecret; // No secret configured. In production this is FATAL: a predictable @@ -1863,9 +1862,7 @@ export class AuthManager { // Extract enabled features const pluginConfig: Partial = this.config.plugins ?? {}; // Multi-org capability (UI org-switcher, "create org" action, etc.). - // Resolution order: explicit `OS_MULTI_ORG_ENABLED` wins, else fall - // back to legacy `OS_MULTI_TENANT` (multi-tenant deployments are always - // multi-org); default `'false'` → single-org / per-env runtime. + // `OS_MULTI_ORG_ENABLED` (default `'false'` → single-org / per-env runtime). const multiOrgEnabled = resolveMultiOrgEnabled(); // Legal links shown beneath the login / register cards. Defaults to diff --git a/packages/plugins/plugin-hono-server/src/hono-plugin.ts b/packages/plugins/plugin-hono-server/src/hono-plugin.ts index b6a3e7507c..536ca4329c 100644 --- a/packages/plugins/plugin-hono-server/src/hono-plugin.ts +++ b/packages/plugins/plugin-hono-server/src/hono-plugin.ts @@ -112,14 +112,14 @@ export class HonoServerPlugin implements Plugin { // ─── CORS Middleware ────────────────────────────────────────────────── // Enabled by default. Controlled via options.cors or environment variables. - const corsDisabledByEnv = readEnvWithDeprecation('OS_CORS_ENABLED', 'CORS_ENABLED') === 'false'; + const corsDisabledByEnv = readEnvWithDeprecation('OS_CORS_ENABLED', 'CORS_ENABLED', { silent: true }) === 'false'; if (this.options.cors !== false && !corsDisabledByEnv) { const corsOpts = typeof this.options.cors === 'object' ? this.options.cors : {}; const enabled = corsOpts.enabled ?? true; if (enabled) { let configuredOrigin: string | string[]; - const corsOriginEnv = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN'); + const corsOriginEnv = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN', { silent: true }); if (corsOpts.origins) { configuredOrigin = corsOpts.origins; } else if (corsOriginEnv) { @@ -129,8 +129,8 @@ export class HonoServerPlugin implements Plugin { configuredOrigin = '*'; } - const credentials = corsOpts.credentials ?? (readEnvWithDeprecation('OS_CORS_CREDENTIALS', 'CORS_CREDENTIALS') !== 'false'); - const maxAgeEnv = readEnvWithDeprecation('OS_CORS_MAX_AGE', 'CORS_MAX_AGE'); + const credentials = corsOpts.credentials ?? (readEnvWithDeprecation('OS_CORS_CREDENTIALS', 'CORS_CREDENTIALS', { silent: true }) !== 'false'); + const maxAgeEnv = readEnvWithDeprecation('OS_CORS_MAX_AGE', 'CORS_MAX_AGE', { silent: true }); const maxAge = corsOpts.maxAge ?? (maxAgeEnv ? parseInt(maxAgeEnv, 10) : 86400); // Determine origin handler based on configuration. diff --git a/packages/plugins/plugin-org-scoping/README.md b/packages/plugins/plugin-org-scoping/README.md index 4d99d59a36..24fd320998 100644 --- a/packages/plugins/plugin-org-scoping/README.md +++ b/packages/plugins/plugin-org-scoping/README.md @@ -33,10 +33,10 @@ await kernel.use(new OrgScopingPlugin()); await kernel.use(new SecurityPlugin()); ``` -Or via the `OS_MULTI_TENANT` env switch when using `@objectstack/runtime` / `@objectstack/plugin-dev`: +Or via the `OS_MULTI_ORG_ENABLED` env switch when using `@objectstack/runtime` / `@objectstack/plugin-dev`: ```bash -OS_MULTI_TENANT=true objectstack serve +OS_MULTI_ORG_ENABLED=true objectstack serve ``` ## Options diff --git a/packages/plugins/plugin-security/README.md b/packages/plugins/plugin-security/README.md index 64d682cfec..22abc647a0 100644 --- a/packages/plugins/plugin-security/README.md +++ b/packages/plugins/plugin-security/README.md @@ -53,7 +53,7 @@ SecurityPlugin probes `getService('org-scoping')` at start time: `organization_id` auto-injection on insert is provided by OrgScopingPlugin; `owner_id` auto-injection always runs in SecurityPlugin regardless. -In CLI / dev-server mode the `OS_MULTI_TENANT` environment variable (default `false`) toggles whether the runtime registers `OrgScopingPlugin` alongside `SecurityPlugin`. Set `OS_MULTI_TENANT=true` before `objectstack serve` / `pnpm dev` to enable. +In CLI / dev-server mode the `OS_MULTI_ORG_ENABLED` environment variable (default `false`) toggles whether the runtime registers `OrgScopingPlugin` alongside `SecurityPlugin`. Set `OS_MULTI_ORG_ENABLED=true` before `objectstack serve` / `pnpm dev` to enable. ## Key Exports diff --git a/packages/runtime/src/standalone-stack.ts b/packages/runtime/src/standalone-stack.ts index 9c41a72dac..b8fe6650d6 100644 --- a/packages/runtime/src/standalone-stack.ts +++ b/packages/runtime/src/standalone-stack.ts @@ -148,7 +148,7 @@ export async function createStandaloneStack(config?: StandaloneStackConfig): Pro : resolvePath(cwd, artifactPathInput)); const dbUrl = cfg.databaseUrl - ?? readEnvWithDeprecation('OS_DATABASE_URL', 'DATABASE_URL')?.trim() + ?? readEnvWithDeprecation('OS_DATABASE_URL', 'DATABASE_URL', { silent: true })?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? (process.env.OS_HOME?.trim() ? `file:${resolvePath(resolveObjectStackHome(), 'data/standalone.db')}` diff --git a/packages/spec/src/api/protocol.zod.ts b/packages/spec/src/api/protocol.zod.ts index 6d658b3a9b..6fb43032d2 100644 --- a/packages/spec/src/api/protocol.zod.ts +++ b/packages/spec/src/api/protocol.zod.ts @@ -179,7 +179,7 @@ export const GetMetaTypesResponseSchema = lazySchema(() => z.object({ executionPinned: z.boolean().describe('Runtime transactions pin a specific historical version_hash (ADR-0009)'), loadOrder: z.number().int().describe('Loading priority (lower = earlier)'), domain: z.enum(['data', 'ui', 'automation', 'system', 'security', 'ai']).describe('Protocol domain'), - overrideSource: z.enum(['registry', 'env']).describe('Whether allowOrgOverride is set in the static registry or via OBJECTSTACK_METADATA_WRITABLE env var'), + overrideSource: z.enum(['registry', 'env']).describe('Whether allowOrgOverride is set in the static registry or via OS_METADATA_WRITABLE env var'), createSeed: z.unknown().optional().describe('Authoritative minimal valid create seed for this type — Studio/CLI/API derive create defaults from it (single source of truth in @objectstack/spec). Absent for canvas-create types whose shape is built interactively.'), })).optional().describe('Enriched per-type registry entries (Phase 3a)'), })); diff --git a/packages/spec/src/data/object.zod.ts b/packages/spec/src/data/object.zod.ts index 5576c10ab5..ca085aa5fc 100644 --- a/packages/spec/src/data/object.zod.ts +++ b/packages/spec/src/data/object.zod.ts @@ -439,7 +439,7 @@ const ObjectSchemaBase = z.object({ * declare them per-object (Salesforce-style). Currently injected: * * - `organization_id` — `lookup → sys_organization`. Injected only when - * the kernel runs in multi-tenant mode (`OS_MULTI_TENANT === 'true'`; + * the kernel runs in multi-tenant mode (`OS_MULTI_ORG_ENABLED === 'true'`; * default is off — single-tenant). * Required for the default `tenant_isolation` RLS policy and the * SecurityPlugin's auto-fill on insert to take effect. diff --git a/packages/types/src/env.ts b/packages/types/src/env.ts index 06c77679cc..885eb96d2a 100644 --- a/packages/types/src/env.ts +++ b/packages/types/src/env.ts @@ -83,9 +83,9 @@ export function readEnvWithDeprecation( * Resolve whether the deployment runs in multi-org (a.k.a. multi-tenant) mode. * * Single source of truth for the `OS_MULTI_ORG_ENABLED` flag. Resolution: the - * canonical `OS_MULTI_ORG_ENABLED` wins; else the deprecated `OS_MULTI_TENANT` - * (which fires the one-shot rename warning via {@link readEnvWithDeprecation}); - * else `false`. Any value other than a case-insensitive `'false'` enables it. + * canonical `OS_MULTI_ORG_ENABLED`; else `false`. Any value other than a + * case-insensitive `'false'` enables it. (The legacy `OS_MULTI_TENANT` alias was + * removed in 11.0.) * * Every site that needs to know "is this multi-org?" — the SQL driver's * tenant-audit gate, the auth manager's `/auth/config` feature flag and @@ -99,7 +99,7 @@ export function readEnvWithDeprecation( * result must be stable for the process lifetime. */ export function resolveMultiOrgEnabled(): boolean { - const raw = readEnvWithDeprecation('OS_MULTI_ORG_ENABLED', 'OS_MULTI_TENANT'); + const raw = readEnvWithDeprecation('OS_MULTI_ORG_ENABLED', []); return String(raw ?? 'false').toLowerCase() !== 'false'; }