@object-ui/core 11.2.0 → 11.4.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/CHANGELOG.md +35 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/runtime/capabilities.d.ts +35 -0
- package/dist/runtime/capabilities.js +72 -0
- package/dist/utils/record-title.d.ts +98 -0
- package/dist/utils/record-title.js +0 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @object-ui/core
|
|
2
2
|
|
|
3
|
+
## 11.4.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [8bf6295]
|
|
8
|
+
- Updated dependencies [1948c5b]
|
|
9
|
+
- Updated dependencies [c38d107]
|
|
10
|
+
- @object-ui/types@11.4.0
|
|
11
|
+
|
|
12
|
+
## 11.3.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- d23d6eb: Three-tier AI page authoring: `kind:'html'` and a trusted `kind:'react'` tier.
|
|
17
|
+
|
|
18
|
+
- **`@object-ui/react-runtime`** (new) — the trusted runtime-React tier for
|
|
19
|
+
`kind:'react'` pages (vendored react-runner: Sucrase transpile + scope-eval,
|
|
20
|
+
no sandbox). Renders real JSX/TSX (any HTML + JS + hooks/useState/map/onClick)
|
|
21
|
+
in the main React tree with an injected scope (React, the public data blocks,
|
|
22
|
+
page data) and a built-in error boundary.
|
|
23
|
+
- **`@object-ui/core`** — new runtime capability gate (`enableCapability` /
|
|
24
|
+
`disableCapability` / `isCapabilityEnabled`, `CAP_REACT_PAGES`). `react-pages`
|
|
25
|
+
defaults **ON** (the platform trusts reviewed, draft-gated authors); a
|
|
26
|
+
deployment turns it OFF server-side (the runtime injects the disable global
|
|
27
|
+
when `OS_DISABLE_REACT_PAGES` is set). Never controlled from authored metadata.
|
|
28
|
+
- **`@object-ui/components`** — PageRenderer now routes `kind:'react'`
|
|
29
|
+
(capability-gated, lazy-loads the runtime) and renders `kind:'html'` (the
|
|
30
|
+
former `kind:'jsx'`, still accepted as a deprecated alias). The `html` tier
|
|
31
|
+
now resolves the full safe native HTML tag set (h1–h6, p, a, ul/ol/li, img,
|
|
32
|
+
blockquote, pre, strong/em, …) so authored HTML lives up to its name.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- @object-ui/types@11.3.0
|
|
37
|
+
|
|
3
38
|
## 11.2.0
|
|
4
39
|
|
|
5
40
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export * from './utils/merge-views-into-objects.js';
|
|
|
29
29
|
export * from './utils/freeze-schema.js';
|
|
30
30
|
export * from './protocols/index.js';
|
|
31
31
|
export * from './styling/scoped-styles.js';
|
|
32
|
+
export * from './runtime/capabilities.js';
|
|
32
33
|
/**
|
|
33
34
|
* @deprecated Import `composeStacks` from `@objectstack/spec` instead.
|
|
34
35
|
*
|
|
@@ -41,3 +42,4 @@ export * from './utils/date-macros.js';
|
|
|
41
42
|
export * from './utils/compare-to.js';
|
|
42
43
|
export * from './utils/chart-series.js';
|
|
43
44
|
export * from './utils/dataset-format.js';
|
|
45
|
+
export * from './utils/record-title.js';
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ export * from './utils/merge-views-into-objects.js';
|
|
|
28
28
|
export * from './utils/freeze-schema.js';
|
|
29
29
|
export * from './protocols/index.js';
|
|
30
30
|
export * from './styling/scoped-styles.js';
|
|
31
|
+
export * from './runtime/capabilities.js';
|
|
31
32
|
/**
|
|
32
33
|
* @deprecated Import `composeStacks` from `@objectstack/spec` instead.
|
|
33
34
|
*
|
|
@@ -40,3 +41,4 @@ export * from './utils/date-macros.js';
|
|
|
40
41
|
export * from './utils/compare-to.js';
|
|
41
42
|
export * from './utils/chart-series.js';
|
|
42
43
|
export * from './utils/dataset-format.js';
|
|
44
|
+
export * from './utils/record-title.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* Runtime capability gates — switches a *host* controls, never authored
|
|
9
|
+
* metadata. Each capability has a default; a host can flip it explicitly
|
|
10
|
+
* (`enableCapability`/`disableCapability`) or seed it from globals before any
|
|
11
|
+
* bundle code runs.
|
|
12
|
+
*
|
|
13
|
+
* {@link CAP_REACT_PAGES} (`kind:'react'` — execute author JavaScript in the
|
|
14
|
+
* main React tree) defaults **ON**: ObjectStack pages are authored by trusted
|
|
15
|
+
* authors and pass human review (draft-gating, ADR-0033), so the platform
|
|
16
|
+
* trusts them by default. A deployment that does NOT trust its page authors
|
|
17
|
+
* turns it off server-side — the ObjectStack runtime injects the disable global
|
|
18
|
+
* when `OS_PAGE_REACT=off` (see framework cli/utils/console.ts).
|
|
19
|
+
*
|
|
20
|
+
* Globals a host/server can set in the page before the bundle runs:
|
|
21
|
+
* - `globalThis.__OBJECTUI_CAPABILITIES__` — string[] to force ON
|
|
22
|
+
* - `globalThis.__OBJECTUI_CAPABILITIES_DISABLED__` — string[] to force OFF
|
|
23
|
+
*/
|
|
24
|
+
/** Turn a capability on. Call from the host process only (not from metadata). */
|
|
25
|
+
export declare function enableCapability(name: string): void;
|
|
26
|
+
/** Turn a capability off. */
|
|
27
|
+
export declare function disableCapability(name: string): void;
|
|
28
|
+
/** Whether a capability is enabled. Host/global override wins over the default. */
|
|
29
|
+
export declare function isCapabilityEnabled(name: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* `kind:'react'` — execute trusted author JavaScript (full React: hooks, event
|
|
32
|
+
* handlers, arbitrary JS) directly in the main React tree. Default ON; a
|
|
33
|
+
* deployment disables it server-side with `OS_PAGE_REACT=off`.
|
|
34
|
+
*/
|
|
35
|
+
export declare const CAP_REACT_PAGES = "react-pages";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* Runtime capability gates — switches a *host* controls, never authored
|
|
9
|
+
* metadata. Each capability has a default; a host can flip it explicitly
|
|
10
|
+
* (`enableCapability`/`disableCapability`) or seed it from globals before any
|
|
11
|
+
* bundle code runs.
|
|
12
|
+
*
|
|
13
|
+
* {@link CAP_REACT_PAGES} (`kind:'react'` — execute author JavaScript in the
|
|
14
|
+
* main React tree) defaults **ON**: ObjectStack pages are authored by trusted
|
|
15
|
+
* authors and pass human review (draft-gating, ADR-0033), so the platform
|
|
16
|
+
* trusts them by default. A deployment that does NOT trust its page authors
|
|
17
|
+
* turns it off server-side — the ObjectStack runtime injects the disable global
|
|
18
|
+
* when `OS_PAGE_REACT=off` (see framework cli/utils/console.ts).
|
|
19
|
+
*
|
|
20
|
+
* Globals a host/server can set in the page before the bundle runs:
|
|
21
|
+
* - `globalThis.__OBJECTUI_CAPABILITIES__` — string[] to force ON
|
|
22
|
+
* - `globalThis.__OBJECTUI_CAPABILITIES_DISABLED__` — string[] to force OFF
|
|
23
|
+
*/
|
|
24
|
+
/** Default state per capability when neither the host nor a global overrides it. */
|
|
25
|
+
const DEFAULTS = {
|
|
26
|
+
'react-pages': true,
|
|
27
|
+
};
|
|
28
|
+
// Explicit host overrides (enable/disable) — win over defaults and globals.
|
|
29
|
+
const overrides = new Map();
|
|
30
|
+
let _seeded = false;
|
|
31
|
+
function seedFromGlobals() {
|
|
32
|
+
if (_seeded)
|
|
33
|
+
return;
|
|
34
|
+
_seeded = true;
|
|
35
|
+
const g = globalThis;
|
|
36
|
+
if (Array.isArray(g.__OBJECTUI_CAPABILITIES__)) {
|
|
37
|
+
for (const c of g.__OBJECTUI_CAPABILITIES__)
|
|
38
|
+
if (typeof c === 'string' && !overrides.has(c))
|
|
39
|
+
overrides.set(c, true);
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(g.__OBJECTUI_CAPABILITIES_DISABLED__)) {
|
|
42
|
+
// Disable wins: a server that turned something off must not be overridden
|
|
43
|
+
// by a stale enable-list left in the same page.
|
|
44
|
+
for (const c of g.__OBJECTUI_CAPABILITIES_DISABLED__)
|
|
45
|
+
if (typeof c === 'string')
|
|
46
|
+
overrides.set(c, false);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Turn a capability on. Call from the host process only (not from metadata). */
|
|
50
|
+
export function enableCapability(name) {
|
|
51
|
+
seedFromGlobals();
|
|
52
|
+
overrides.set(name, true);
|
|
53
|
+
}
|
|
54
|
+
/** Turn a capability off. */
|
|
55
|
+
export function disableCapability(name) {
|
|
56
|
+
seedFromGlobals();
|
|
57
|
+
overrides.set(name, false);
|
|
58
|
+
}
|
|
59
|
+
/** Whether a capability is enabled. Host/global override wins over the default. */
|
|
60
|
+
export function isCapabilityEnabled(name) {
|
|
61
|
+
seedFromGlobals();
|
|
62
|
+
const o = overrides.get(name);
|
|
63
|
+
if (o !== undefined)
|
|
64
|
+
return o;
|
|
65
|
+
return DEFAULTS[name] ?? false;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* `kind:'react'` — execute trusted author JavaScript (full React: hooks, event
|
|
69
|
+
* handlers, arbitrary JS) directly in the main React tree. Default ON; a
|
|
70
|
+
* deployment disables it server-side with `OS_PAGE_REACT=off`.
|
|
71
|
+
*/
|
|
72
|
+
export const CAP_REACT_PAGES = 'react-pages';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Render a record title from a `titleFormat` pattern.
|
|
10
|
+
*
|
|
11
|
+
* Accepts either a legacy string template or an Expression envelope
|
|
12
|
+
* (`{ dialect: 'template', source: string }`) emitted by `@objectstack/spec`'s
|
|
13
|
+
* normalized templates. Both single-brace (`{field}`) and double-brace
|
|
14
|
+
* (`{{field}}`, the handlebars-style some authoring paths emit) placeholders are
|
|
15
|
+
* supported. Dotted paths (`{account.name}`) walk `$expanded` lookup objects; a
|
|
16
|
+
* placeholder that resolves to a whole object is reduced to its display name.
|
|
17
|
+
*
|
|
18
|
+
* Empty placeholders (missing / null / empty fields) are stripped along with
|
|
19
|
+
* any orphan separator they leave behind, so `"{full_name} - {company}"`
|
|
20
|
+
* evaluated against `{ company: "Acme" }` yields `"Acme"`, not `" - Acme"`.
|
|
21
|
+
* Returns an empty string when no placeholder resolved.
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatTitleTemplate(titleFormat: string | {
|
|
24
|
+
source?: string;
|
|
25
|
+
} | undefined | null, record: any): string;
|
|
26
|
+
/**
|
|
27
|
+
* Decide whether a field definition can serve as a record title. Excludes the
|
|
28
|
+
* {@link NON_TITLE_TYPES} (dates, numbers, pickers, lookups, binary, …); a
|
|
29
|
+
* `formula` is eligible only when it returns text. A field with no declared
|
|
30
|
+
* type is treated as eligible (text-by-default), so loosely-typed metadata
|
|
31
|
+
* still produces a name rather than falling through to `Record #…`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isTitleEligibleField(def: any): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Type-aware derivation (precedence step 4): pick the best title-eligible field
|
|
36
|
+
* name from `objectDef.fields`, ranked:
|
|
37
|
+
*
|
|
38
|
+
* 1. name-ish exact — `name`,`title`,`subject`,`label`,`full_name`,
|
|
39
|
+
* `display_name` (case-insensitive)
|
|
40
|
+
* 2. name-ish affix — `*_name`, `*_title`, `name_*` (case-insensitive)
|
|
41
|
+
* 3. declaration order — first remaining title-eligible field
|
|
42
|
+
*
|
|
43
|
+
* Returns the field name, or undefined when `fields` is absent/empty or holds
|
|
44
|
+
* no title-eligible field.
|
|
45
|
+
*
|
|
46
|
+
* Memoized per `objectDef` identity (see {@link deriveTitleFieldCache}): the
|
|
47
|
+
* field scan runs once per object definition, not once per record. The result is
|
|
48
|
+
* byte-identical to the uncached computation — only the scan is cached, and only
|
|
49
|
+
* when `objectDef` is a non-null object (the WeakMap key requirement).
|
|
50
|
+
*/
|
|
51
|
+
export declare function deriveTitleField(objectDef: any): string | undefined;
|
|
52
|
+
export interface RecordDisplayNameOptions {
|
|
53
|
+
/**
|
|
54
|
+
* Optional explicit title field (e.g. a view's `titleField` / gallery
|
|
55
|
+
* `titleField` / kanban `cardTitle`). When set and it yields a non-empty
|
|
56
|
+
* value on the record, it wins over everything — preserving each view's
|
|
57
|
+
* author-chosen field. Pass nothing to use the object-level precedence only.
|
|
58
|
+
*/
|
|
59
|
+
titleField?: string;
|
|
60
|
+
/** Floor when the record has no id at all. Defaults to `'Untitled'`. */
|
|
61
|
+
fallback?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Whether to probe standard name-ish keys (`name`/`title`/…) directly on the
|
|
64
|
+
* record when `objectDef.fields` is absent (precedence step 3b). Defaults to
|
|
65
|
+
* `true`. Callers that have a better generic fallback to interleave (e.g. the
|
|
66
|
+
* detail header prefers `schema.title`, the object label, over a guessed
|
|
67
|
+
* record key) pass `false` so this step is skipped and the resolver returns
|
|
68
|
+
* its `Record #<id>` floor instead — letting the caller decide.
|
|
69
|
+
*/
|
|
70
|
+
deriveFromRecordKeys?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* THE unified record display-name resolver (ADR-0079).
|
|
74
|
+
*
|
|
75
|
+
* Precedence (ADR-0079 Phase 2 makes the object's declared field canonical and
|
|
76
|
+
* de-prioritizes the legacy `titleFormat` template):
|
|
77
|
+
* 0. `options.titleField`, then `objectDef.titleField` (when provided &
|
|
78
|
+
* non-empty on the record) — lets a view / object keep its author-chosen
|
|
79
|
+
* title field.
|
|
80
|
+
* 1. `objectDef.nameField` — the NEW canonical record-title pointer
|
|
81
|
+
* (ADR-0079). A field name the server can return and query.
|
|
82
|
+
* 2. `objectDef.displayNameField` / `objectDef.NAME_FIELD_KEY` — the
|
|
83
|
+
* deprecated alias of `nameField`, kept for back-compat.
|
|
84
|
+
* 3. `objectDef.titleFormat` (rendered template) — LEGACY, render-only, kept
|
|
85
|
+
* for back-compat only; an explicitly-declared field (1/2) now wins over
|
|
86
|
+
* it. See the deprecation note on the branch below.
|
|
87
|
+
* 4. type-aware derivation from `objectDef.fields` ({@link deriveTitleField}).
|
|
88
|
+
* 4b. standard name-ish keys probed directly on the record
|
|
89
|
+
* ({@link NAME_ISH_RECORD_KEYS}) — the safety net for when `fields` is
|
|
90
|
+
* absent so derivation can't run.
|
|
91
|
+
* 5. `Record #<id>` (using `record.id ?? record._id`), else `options.fallback`
|
|
92
|
+
* (default `'Untitled'`) for a truly id-less record.
|
|
93
|
+
*
|
|
94
|
+
* @param objectDef Object definition (may be `any`/partial — every field is
|
|
95
|
+
* read defensively).
|
|
96
|
+
* @param record The record data.
|
|
97
|
+
*/
|
|
98
|
+
export declare function getRecordDisplayName(objectDef: any, record: any, options?: RecordDisplayNameOptions): string;
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/core",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@objectstack/formula": "^11.
|
|
29
|
-
"@objectstack/spec": "^11.
|
|
28
|
+
"@objectstack/formula": "^11.5.0",
|
|
29
|
+
"@objectstack/spec": "^11.7.0",
|
|
30
30
|
"lodash": "^4.18.1",
|
|
31
31
|
"zod": "^4.4.3",
|
|
32
|
-
"@object-ui/types": "11.
|
|
32
|
+
"@object-ui/types": "11.4.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"typescript": "^6.0.3",
|