11// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22
3- import { detectLocale , t } from './i18n' ;
4-
5- /**
6- * Sentinel "package" id for this environment's runtime, DB-authored metadata —
7- * items with no code-package binding (`package_id IS NULL`). The metadata
8- * list/get API treats `?package=sys_metadata` as exactly that local scope on
9- * READ, and a WRITE under it persists `package_id = null` (matching the
10- * server's runtime-only provenance, see framework #2252).
11- *
12- * Why this exists: a self-hosted, metadata-customizable environment is
13- * single-tenant — there is no "org" dimension here; the real axis is
14- * code-package vs. runtime (DB-authored). Before this scope, the package
15- * selector only listed code packages, so metadata authored at runtime
16- * (`package_id = null`) was filtered out of every code-package view and became
17- * un-navigable (the route redirected to "new"). Surfacing the local scope as a
18- * first-class, always-present selector entry makes it discoverable and editable.
19- */
20- export const LOCAL_PACKAGE_ID = 'sys_metadata' ;
21-
223const SYSTEM_SCOPES = new Set ( [ 'system' , 'cloud' ] ) ;
234
245/**
25- * Build the Studio package-scope options from the raw `package` metadata list.
26- * Filters out system/cloud-scoped packages and appends a stable
27- * "Local / Custom (this environment)" scope so runtime metadata authored here
28- * is always selectable/visible — even when zero items exist yet.
6+ * Build the Studio package-scope options from the raw `package` metadata list:
7+ * the **writable bases** (project-scoped, DB-backed packages) only — the sole
8+ * valid authoring destinations (ADR-0070 D2). Code/installed (system|cloud)
9+ * packages are filtered out.
10+ *
11+ * There is no package-less "Local / Custom" scope: every runtime-authored item
12+ * lives in a writable base (ADR-0070 D1/D5 — the kernel rejects orphan creates
13+ * with `writable_package_required`, and legacy orphans are adopted into a base),
14+ * so the selector never offers an orphan bucket. The kernel keeps `null` /
15+ * `sys_metadata` provenance only as a read-side rehydration tag for legacy rows.
2916 */
3017export function buildPackageScopeOptions (
3118 rawList : unknown [ ] | null | undefined ,
@@ -46,28 +33,5 @@ export function buildPackageScopeOptions(
4633 } )
4734 . filter ( ( p ) => p . id && ! SYSTEM_SCOPES . has ( p . scope ) ) ;
4835 rows . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
49- const opts = rows . map ( ( p ) => ( { id : p . id , name : p . name } ) ) ;
50- // Append (never default) so the existing first-code-package default is
51- // preserved; the user opts into the local scope explicitly.
52- return [ ...opts , { id : LOCAL_PACKAGE_ID , name : t ( 'engine.package.local' , detectLocale ( ) ) } ] ;
53- }
54-
55- /**
56- * True for the runtime/null "Local / Custom" sentinel scope. Per ADR-0070 D5
57- * this is a *migration* surface (move loose items into a base), never a valid
58- * create destination — callers gate "create" on a real writable base.
59- */
60- export function isLocalScope ( id : string | null | undefined ) : boolean {
61- return ! id || id === LOCAL_PACKAGE_ID ;
62- }
63-
64- /**
65- * The writable bases (project-scoped DB packages) from the raw package list —
66- * the only valid authoring destinations (ADR-0070 D2). Excludes code/installed
67- * (system|cloud) packages AND the Local sentinel.
68- */
69- export function writableBaseOptions (
70- rawList : unknown [ ] | null | undefined ,
71- ) : { id : string ; name : string } [ ] {
72- return buildPackageScopeOptions ( rawList ) . filter ( ( o ) => o . id !== LOCAL_PACKAGE_ID ) ;
36+ return rows . map ( ( p ) => ( { id : p . id , name : p . name } ) ) ;
7337}
0 commit comments