@object-ui/data-objectstack 6.0.4 → 6.2.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 +95 -0
- package/dist/index.cjs +186 -3
- package/dist/index.d.cts +157 -1
- package/dist/index.d.ts +157 -1
- package/dist/index.js +185 -3
- package/package.json +5 -5
- package/src/index.ts +15 -0
- package/src/metadata-client.test.ts +124 -0
- package/src/metadata-client.ts +338 -0
- package/src/userState.test.ts +2 -2
- package/src/userState.ts +18 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,100 @@
|
|
|
1
1
|
# @object-ui/data-objectstack
|
|
2
2
|
|
|
3
|
+
## 6.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ec8dcde: Add visual editing for object & field metadata in the Setup app.
|
|
8
|
+
|
|
9
|
+
**`@object-ui/data-objectstack`** — new `MetadataClient` class. A thin,
|
|
10
|
+
auth-friendly wrapper over the framework's `/api/v1/meta/*` REST
|
|
11
|
+
endpoints (list / get / save / reset / history), with first-class
|
|
12
|
+
support for `If-Match` (optimistic concurrency), `X-Actor` (audit
|
|
13
|
+
attribution), environment-scoped paths
|
|
14
|
+
(`/environments/:id/meta/*`), and 404-as-null semantics. Use
|
|
15
|
+
`new MetadataClient({ baseUrl })` or `client.withEnvironment(id)` to
|
|
16
|
+
target a specific environment.
|
|
17
|
+
|
|
18
|
+
**`@object-ui/plugin-designer`** — two new route-ready pages that
|
|
19
|
+
together close the "Data Model" management loop in the Setup app:
|
|
20
|
+
- `MetadataObjectsPage` — lists every object schema (via
|
|
21
|
+
`MetadataClient.list('object')`), renders the existing
|
|
22
|
+
`ObjectManager`, and persists edits/deletes through PUT/DELETE on
|
|
23
|
+
the metadata REST surface. Honours `allowRuntimeCreate` and
|
|
24
|
+
surfaces server errors verbatim.
|
|
25
|
+
- `MetadataFieldsPage` — for a single object, loads the parent
|
|
26
|
+
schema, projects `fields` into the existing `FieldDesigner`, and
|
|
27
|
+
on save merges the edited field map back into the object before
|
|
28
|
+
issuing a single PUT. Preserves unknown per-field attributes so
|
|
29
|
+
nothing the designer doesn't render is dropped.
|
|
30
|
+
|
|
31
|
+
Both pages take either a pre-built `MetadataClient` or a
|
|
32
|
+
`MetadataClientConfig`; neither imposes a routing convention on the
|
|
33
|
+
host app — they can be mounted anywhere (e.g.
|
|
34
|
+
`/apps/setup/_meta/object` and `/apps/setup/_meta/object/:name/fields`).
|
|
35
|
+
|
|
36
|
+
These additions do not modify the underlying `ObjectManager` /
|
|
37
|
+
`FieldDesigner` components, which remain pure controlled-input
|
|
38
|
+
components usable in non-REST contexts.
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
- fe3c1d3: Metadata Admin engine — unified UI for all 27 metadata types.
|
|
43
|
+
|
|
44
|
+
A generic, schema-driven admin shell that replaces the old per-type
|
|
45
|
+
bespoke pages with a single registry-driven engine. Admins can now browse,
|
|
46
|
+
create, override, diff, and roll back every registered metadata type from
|
|
47
|
+
the Setup app → _All Metadata Types_.
|
|
48
|
+
|
|
49
|
+
### New: `@object-ui/app-shell` views/metadata-admin
|
|
50
|
+
- **`MetadataDirectoryPage`** — auto-grouped tile directory by domain, with
|
|
51
|
+
free-text search, domain chips, and a _Writable only_ filter.
|
|
52
|
+
- **`MetadataResourceListPage` / `MetadataResourceEditPage` / `…CreatePage` / `…HistoryPage`** —
|
|
53
|
+
generic CRUD shell. Uses the new `/meta/types` schema field to render
|
|
54
|
+
SchemaForm; uses `?layers=code,overlay,effective` to power a 3-state diff
|
|
55
|
+
tab; uses `/references` to warn before destructive deletes.
|
|
56
|
+
- **`MetadataQuickFind`** — Cmd+Shift+M palette searching across types and
|
|
57
|
+
items.
|
|
58
|
+
- **`PermissionMatrixEditor`** — Salesforce-style matrix custom editor for
|
|
59
|
+
`type=permission`. Objects × CRUD/VAMA/lifecycle columns with cascade
|
|
60
|
+
rules (viewAllRecords ⟹ allowRead, etc.), expandable per-object field
|
|
61
|
+
R/W subtable, bulk-set (R / CRUD / All / None), filter, _only granted_
|
|
62
|
+
toggle, destructive-change confirmation, profile switch.
|
|
63
|
+
- **`DesignerEditorWrapper`** — generic load–edit–save shell that hosts any
|
|
64
|
+
bespoke designer (`ObjectViewConfigurator`, `DashboardEditor`,
|
|
65
|
+
`PageCanvasEditor`, …). Handles dirty tracking, Save / Reset / Refresh /
|
|
66
|
+
History buttons, and the read-only fallback when `allowOrgOverride` is
|
|
67
|
+
false.
|
|
68
|
+
- **`i18n.ts`** — bilingual (`en-US`, `zh-CN`) bundle for built-in type
|
|
69
|
+
labels, domain labels, and engine UI strings, with `detectLocale()` and a
|
|
70
|
+
`t(key)` helper.
|
|
71
|
+
|
|
72
|
+
### New routing variant
|
|
73
|
+
- App nav now supports `{ type: 'component', componentRef, params? }` items.
|
|
74
|
+
`AppContent` resolves them through the existing `ComponentRegistry`.
|
|
75
|
+
- Built-in components registered: `metadata:directory`, `metadata:resource`,
|
|
76
|
+
`metadata:object/edit` (FieldsPage), `metadata:permission/edit`
|
|
77
|
+
(PermissionMatrixEditor), and lazy designer wrappers for view / dashboard
|
|
78
|
+
/ page.
|
|
79
|
+
|
|
80
|
+
### Plugin-designer
|
|
81
|
+
- Lazy-exported `ObjectManager`, `FieldDesigner`, `ObjectViewConfigurator`,
|
|
82
|
+
`DashboardEditor`, `PageCanvasEditor`, `MetadataObjectsPage`, and
|
|
83
|
+
`MetadataFieldsPage` so the engine can mount them on demand.
|
|
84
|
+
|
|
85
|
+
The temporary `/dev/meta` route is removed. Setup app navigation flows
|
|
86
|
+
through the new component routes.
|
|
87
|
+
- @object-ui/types@6.2.0
|
|
88
|
+
- @object-ui/core@6.2.0
|
|
89
|
+
|
|
90
|
+
## 6.1.0
|
|
91
|
+
|
|
92
|
+
### Patch Changes
|
|
93
|
+
|
|
94
|
+
- Updated dependencies [991b62d]
|
|
95
|
+
- @object-ui/core@6.1.0
|
|
96
|
+
- @object-ui/types@6.1.0
|
|
97
|
+
|
|
3
98
|
## 6.0.4
|
|
4
99
|
|
|
5
100
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,7 @@ __export(index_exports, {
|
|
|
28
28
|
ConcurrentUpdateError: () => ConcurrentUpdateError,
|
|
29
29
|
ConnectionError: () => ConnectionError,
|
|
30
30
|
IntegrationManager: () => IntegrationManager,
|
|
31
|
+
MetadataClient: () => MetadataClient,
|
|
31
32
|
MetadataNotFoundError: () => MetadataNotFoundError,
|
|
32
33
|
ObjectStackAdapter: () => ObjectStackAdapter,
|
|
33
34
|
ObjectStackError: () => ObjectStackError,
|
|
@@ -586,15 +587,21 @@ function createObjectStackUserStateAdapter(options) {
|
|
|
586
587
|
let cachedRowId = null;
|
|
587
588
|
const findExisting = async () => {
|
|
588
589
|
const params = {
|
|
589
|
-
filter: {
|
|
590
|
+
$filter: {
|
|
590
591
|
user_id: userId,
|
|
591
592
|
key
|
|
592
593
|
},
|
|
593
|
-
|
|
594
|
+
$top: 1
|
|
594
595
|
};
|
|
595
596
|
const result = await dataSource.find(resource, params);
|
|
596
597
|
const rows = result?.data ?? [];
|
|
597
|
-
|
|
598
|
+
const match = rows.find((r) => {
|
|
599
|
+
if (!r) return false;
|
|
600
|
+
const userMismatch = r.user_id !== void 0 && r.user_id !== userId;
|
|
601
|
+
const keyMismatch = r.key !== void 0 && r.key !== key;
|
|
602
|
+
return !userMismatch && !keyMismatch;
|
|
603
|
+
});
|
|
604
|
+
return match ?? null;
|
|
598
605
|
};
|
|
599
606
|
const decodeValue = (value) => {
|
|
600
607
|
if (Array.isArray(value)) return value;
|
|
@@ -773,6 +780,181 @@ var IntegrationManager = class {
|
|
|
773
780
|
}
|
|
774
781
|
};
|
|
775
782
|
|
|
783
|
+
// src/metadata-client.ts
|
|
784
|
+
var META_PREFIX = "/meta";
|
|
785
|
+
var API_PREFIX = "/api/v1";
|
|
786
|
+
function buildBase(config) {
|
|
787
|
+
const trimmed = config.baseUrl.replace(/\/+$/, "");
|
|
788
|
+
const scoped = config.environmentId ? `${API_PREFIX}/environments/${encodeURIComponent(config.environmentId)}${META_PREFIX}` : `${API_PREFIX}${META_PREFIX}`;
|
|
789
|
+
if (/\/api\/v\d+$/i.test(trimmed)) {
|
|
790
|
+
const stripped = trimmed.replace(/\/api\/v\d+$/i, "");
|
|
791
|
+
const scopedNoApi = config.environmentId ? `${API_PREFIX}/environments/${encodeURIComponent(config.environmentId)}${META_PREFIX}` : `${API_PREFIX}${META_PREFIX}`;
|
|
792
|
+
return `${stripped}${scopedNoApi}`;
|
|
793
|
+
}
|
|
794
|
+
return `${trimmed}${scoped}`;
|
|
795
|
+
}
|
|
796
|
+
async function parseError(res) {
|
|
797
|
+
let body;
|
|
798
|
+
try {
|
|
799
|
+
body = await res.json();
|
|
800
|
+
} catch {
|
|
801
|
+
body = await res.text().catch(() => void 0);
|
|
802
|
+
}
|
|
803
|
+
const message = (body && typeof body === "object" && "error" in body ? String(body.error) : void 0) ?? `Metadata request failed: ${res.status} ${res.statusText}`;
|
|
804
|
+
const err = new Error(message);
|
|
805
|
+
err.status = res.status;
|
|
806
|
+
err.body = body;
|
|
807
|
+
if (body && typeof body === "object" && "code" in body) {
|
|
808
|
+
err.code = String(body.code);
|
|
809
|
+
}
|
|
810
|
+
return err;
|
|
811
|
+
}
|
|
812
|
+
var MetadataClient = class _MetadataClient {
|
|
813
|
+
constructor(config) {
|
|
814
|
+
__publicField(this, "base");
|
|
815
|
+
__publicField(this, "fetchImpl");
|
|
816
|
+
__publicField(this, "headers");
|
|
817
|
+
this.base = buildBase(config);
|
|
818
|
+
this.fetchImpl = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
819
|
+
this.headers = { Accept: "application/json", ...config.headers ?? {} };
|
|
820
|
+
}
|
|
821
|
+
/** Update the client's environment scope at runtime. */
|
|
822
|
+
withEnvironment(environmentId) {
|
|
823
|
+
return new _MetadataClient({
|
|
824
|
+
baseUrl: this.base.replace(/\/api\/v\d+(?:\/environments\/[^/]+)?\/meta$/, "").replace(/\/+$/, ""),
|
|
825
|
+
environmentId,
|
|
826
|
+
fetch: this.fetchImpl,
|
|
827
|
+
headers: this.headers
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
/** List all registered metadata types (returns the registry rows). */
|
|
831
|
+
async listTypes() {
|
|
832
|
+
const res = await this.fetchImpl(this.base, { method: "GET", headers: this.headers, cache: "no-store" });
|
|
833
|
+
if (!res.ok) throw await parseError(res);
|
|
834
|
+
const data = await res.json();
|
|
835
|
+
if (Array.isArray(data)) return data;
|
|
836
|
+
if (data && Array.isArray(data.entries)) return data.entries;
|
|
837
|
+
if (data && Array.isArray(data.items)) return data.items;
|
|
838
|
+
if (data && Array.isArray(data.types)) {
|
|
839
|
+
return data.types.map((t) => ({ type: t }));
|
|
840
|
+
}
|
|
841
|
+
return [];
|
|
842
|
+
}
|
|
843
|
+
/** List items of a metadata type (e.g. `object`, `field`, `view`). */
|
|
844
|
+
async list(type, options = {}) {
|
|
845
|
+
const qs = options.packageId ? `?package=${encodeURIComponent(options.packageId)}` : "";
|
|
846
|
+
const url = `${this.base}/${encodeURIComponent(type)}${qs}`;
|
|
847
|
+
const res = await this.fetchImpl(url, { method: "GET", headers: this.headers, cache: "no-store" });
|
|
848
|
+
if (!res.ok) throw await parseError(res);
|
|
849
|
+
const data = await res.json();
|
|
850
|
+
if (Array.isArray(data)) return data;
|
|
851
|
+
if (data && Array.isArray(data.items)) {
|
|
852
|
+
return data.items;
|
|
853
|
+
}
|
|
854
|
+
return [];
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Get a single metadata item. Returns the unwrapped item content
|
|
858
|
+
* (matching the framework REST handler which calls `res.json(item)`).
|
|
859
|
+
* Returns `null` on 404 to keep the call-site ergonomic.
|
|
860
|
+
*/
|
|
861
|
+
async get(type, name) {
|
|
862
|
+
const url = `${this.base}/${encodeURIComponent(type)}/${encodeURIComponent(name)}`;
|
|
863
|
+
const res = await this.fetchImpl(url, { method: "GET", headers: this.headers, cache: "no-store" });
|
|
864
|
+
if (res.status === 404) return null;
|
|
865
|
+
if (!res.ok) throw await parseError(res);
|
|
866
|
+
return await res.json();
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Save (PUT) a metadata item. The framework accepts both the bare
|
|
870
|
+
* item payload and the `{ item: ... }` / `{ metadata: ... }`
|
|
871
|
+
* envelopes; we send bare for consistency.
|
|
872
|
+
*/
|
|
873
|
+
async save(type, name, item, options = {}) {
|
|
874
|
+
const qs = options.force ? "?force=true" : "";
|
|
875
|
+
const url = `${this.base}/${encodeURIComponent(type)}/${encodeURIComponent(name)}${qs}`;
|
|
876
|
+
const headers = {
|
|
877
|
+
...this.headers,
|
|
878
|
+
"Content-Type": "application/json"
|
|
879
|
+
};
|
|
880
|
+
if (options.ifMatch) headers["If-Match"] = options.ifMatch;
|
|
881
|
+
if (options.actor) headers["X-Actor"] = options.actor;
|
|
882
|
+
const res = await this.fetchImpl(url, {
|
|
883
|
+
method: "PUT",
|
|
884
|
+
headers,
|
|
885
|
+
body: JSON.stringify(item)
|
|
886
|
+
});
|
|
887
|
+
if (!res.ok) throw await parseError(res);
|
|
888
|
+
return await res.json();
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Get the 3-state layered view of a metadata item (Phase 3a). Returns
|
|
892
|
+
* `code` (the artifact / fallback default), `overlay` (the saved
|
|
893
|
+
* customisation, if any), and `effective` (what the runtime sees).
|
|
894
|
+
*/
|
|
895
|
+
async layered(type, name) {
|
|
896
|
+
const url = `${this.base}/${encodeURIComponent(type)}/${encodeURIComponent(name)}?layers=true`;
|
|
897
|
+
const res = await this.fetchImpl(url, { method: "GET", headers: this.headers, cache: "no-store" });
|
|
898
|
+
if (res.status === 404) {
|
|
899
|
+
return { code: null, overlay: null, overlayScope: null, effective: null };
|
|
900
|
+
}
|
|
901
|
+
if (!res.ok) throw await parseError(res);
|
|
902
|
+
const body = await res.json();
|
|
903
|
+
const hasEnvelope = body && ("code" in body || "overlay" in body || "effective" in body);
|
|
904
|
+
if (!hasEnvelope) {
|
|
905
|
+
return {
|
|
906
|
+
code: null,
|
|
907
|
+
overlay: null,
|
|
908
|
+
overlayScope: null,
|
|
909
|
+
effective: body
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
return {
|
|
913
|
+
code: body.code ?? null,
|
|
914
|
+
overlay: body.overlay ?? null,
|
|
915
|
+
overlayScope: body.overlayScope ?? null,
|
|
916
|
+
effective: body.effective ?? null
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Find every metadata item that references this one (Phase 3a). Useful
|
|
921
|
+
* for pre-delete impact analysis: "Are any views pointing at this
|
|
922
|
+
* object before I drop it?".
|
|
923
|
+
*/
|
|
924
|
+
async references(type, name) {
|
|
925
|
+
const url = `${this.base}/${encodeURIComponent(type)}/${encodeURIComponent(name)}/references`;
|
|
926
|
+
const res = await this.fetchImpl(url, { method: "GET", headers: this.headers, cache: "no-store" });
|
|
927
|
+
if (res.status === 404) return [];
|
|
928
|
+
if (!res.ok) throw await parseError(res);
|
|
929
|
+
const data = await res.json();
|
|
930
|
+
return Array.isArray(data) ? data : data?.items ?? [];
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Reset a metadata customization overlay back to the artifact default.
|
|
934
|
+
* Idempotent: returns the result even when no overlay row existed.
|
|
935
|
+
*/
|
|
936
|
+
async reset(type, name, options = {}) {
|
|
937
|
+
const url = `${this.base}/${encodeURIComponent(type)}/${encodeURIComponent(name)}`;
|
|
938
|
+
const headers = { ...this.headers };
|
|
939
|
+
if (options.ifMatch) headers["If-Match"] = options.ifMatch;
|
|
940
|
+
if (options.actor) headers["X-Actor"] = options.actor;
|
|
941
|
+
const res = await this.fetchImpl(url, { method: "DELETE", headers });
|
|
942
|
+
if (!res.ok) throw await parseError(res);
|
|
943
|
+
return await res.json();
|
|
944
|
+
}
|
|
945
|
+
/** Fetch the durable history (change log) for one metadata item. */
|
|
946
|
+
async history(type, name, options = {}) {
|
|
947
|
+
const params = new URLSearchParams();
|
|
948
|
+
if (options.sinceSeq !== void 0) params.set("sinceSeq", String(options.sinceSeq));
|
|
949
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
950
|
+
const qs = params.toString();
|
|
951
|
+
const url = `${this.base}/${encodeURIComponent(type)}/${encodeURIComponent(name)}/history${qs ? `?${qs}` : ""}`;
|
|
952
|
+
const res = await this.fetchImpl(url, { method: "GET", headers: this.headers, cache: "no-store" });
|
|
953
|
+
if (!res.ok) throw await parseError(res);
|
|
954
|
+
return await res.json();
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
|
|
776
958
|
// src/security.ts
|
|
777
959
|
var SecurityManager = class {
|
|
778
960
|
constructor(policy = {}) {
|
|
@@ -2342,6 +2524,7 @@ function createObjectStackAdapter(config) {
|
|
|
2342
2524
|
ConcurrentUpdateError,
|
|
2343
2525
|
ConnectionError,
|
|
2344
2526
|
IntegrationManager,
|
|
2527
|
+
MetadataClient,
|
|
2345
2528
|
MetadataNotFoundError,
|
|
2346
2529
|
ObjectStackAdapter,
|
|
2347
2530
|
ObjectStackError,
|
package/dist/index.d.cts
CHANGED
|
@@ -491,6 +491,162 @@ declare class IntegrationManager {
|
|
|
491
491
|
private send;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
+
/**
|
|
495
|
+
* ObjectUI
|
|
496
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
497
|
+
*
|
|
498
|
+
* This source code is licensed under the MIT license found in the
|
|
499
|
+
* LICENSE file in the root directory of this source tree.
|
|
500
|
+
*/
|
|
501
|
+
/**
|
|
502
|
+
* MetadataClient
|
|
503
|
+
*
|
|
504
|
+
* Thin, framework-agnostic HTTP client for the ObjectStack metadata
|
|
505
|
+
* API (`/api/v1/meta/*`). Used by the platform Setup app surfaces in
|
|
506
|
+
* `@object-ui/plugin-designer` (Object Manager, Field Designer, etc.)
|
|
507
|
+
* so they can read and write protocol metadata without depending on
|
|
508
|
+
* `ObjectStackAdapter` (which is a generic data-source binding and
|
|
509
|
+
* carries a lot of view/dashboard-specific behaviour we don't need
|
|
510
|
+
* here).
|
|
511
|
+
*
|
|
512
|
+
* Endpoints (see `packages/rest/src/rest-server.ts`):
|
|
513
|
+
* GET /api/v1/meta — list all metadata types
|
|
514
|
+
* GET /api/v1/meta/:type — list items of a type
|
|
515
|
+
* GET /api/v1/meta/:type/:name — get one item (returns the
|
|
516
|
+
* unwrapped item content)
|
|
517
|
+
* PUT /api/v1/meta/:type/:name — save (overlay) one item
|
|
518
|
+
* honours `If-Match` for OCC
|
|
519
|
+
* DELETE /api/v1/meta/:type/:name — reset overlay to artifact
|
|
520
|
+
* GET /api/v1/meta/:type/:name/history — durable change log
|
|
521
|
+
*
|
|
522
|
+
* The client deliberately keeps the response shape opaque (typed as
|
|
523
|
+
* `unknown`/generic `T`) so callers explicitly narrow per-metadata-
|
|
524
|
+
* type, mirroring the framework's "single Zod source per type" rule.
|
|
525
|
+
*/
|
|
526
|
+
interface MetadataClientConfig {
|
|
527
|
+
/** Base URL of the ObjectStack server (no trailing slash needed). */
|
|
528
|
+
baseUrl: string;
|
|
529
|
+
/**
|
|
530
|
+
* Optional environment ID to scope reads/writes to a tenant. When
|
|
531
|
+
* provided, requests use the scoped path
|
|
532
|
+
* `/api/v1/environments/:environmentId/meta/...` and overlays are
|
|
533
|
+
* persisted in the environment's own metadata store.
|
|
534
|
+
*/
|
|
535
|
+
environmentId?: string;
|
|
536
|
+
/** Optional custom fetch implementation (defaults to `globalThis.fetch`). */
|
|
537
|
+
fetch?: typeof fetch;
|
|
538
|
+
/** Additional headers (e.g. auth) included on every request. */
|
|
539
|
+
headers?: Record<string, string>;
|
|
540
|
+
}
|
|
541
|
+
interface MetadataListOptions {
|
|
542
|
+
/** Filter by source package id (matches the `package` query param). */
|
|
543
|
+
packageId?: string;
|
|
544
|
+
}
|
|
545
|
+
interface MetadataSaveOptions {
|
|
546
|
+
/**
|
|
547
|
+
* Optimistic concurrency token (the `checksum` returned by the last
|
|
548
|
+
* read). When present, sent as the `If-Match` header so concurrent
|
|
549
|
+
* edits get a 409 instead of overwriting each other.
|
|
550
|
+
*/
|
|
551
|
+
ifMatch?: string;
|
|
552
|
+
/** Optional actor id, sent as `X-Actor` for history attribution. */
|
|
553
|
+
actor?: string;
|
|
554
|
+
/**
|
|
555
|
+
* Bypass destructive-change protection (Phase 3a). The server returns
|
|
556
|
+
* `409 destructive_change` with `issues[]` if a write would drop or
|
|
557
|
+
* narrow data; setting `force: true` adds `?force=true` to the request
|
|
558
|
+
* so the operator can confirm and proceed.
|
|
559
|
+
*/
|
|
560
|
+
force?: boolean;
|
|
561
|
+
}
|
|
562
|
+
/** Layered view of a metadata item — Phase 3a `?layers=true`. */
|
|
563
|
+
interface MetadataLayered<T = unknown> {
|
|
564
|
+
/** Code-level (artifact) item; null if the item only exists as an overlay. */
|
|
565
|
+
code: T | null;
|
|
566
|
+
/** Org/environment overlay (just the saved delta or full overlay row). */
|
|
567
|
+
overlay: T | null;
|
|
568
|
+
/** Overlay scope (`organization` | `environment` | `package` | null). */
|
|
569
|
+
overlayScope: string | null;
|
|
570
|
+
/** Merged effective view — what the runtime actually sees. */
|
|
571
|
+
effective: T | null;
|
|
572
|
+
}
|
|
573
|
+
/** Reference back-pointer — Phase 3a `/references`. */
|
|
574
|
+
interface MetadataReference {
|
|
575
|
+
/** Referencing item's metadata type. */
|
|
576
|
+
fromType: string;
|
|
577
|
+
/** Referencing item's name. */
|
|
578
|
+
fromName: string;
|
|
579
|
+
/** JSON path within the referencing item that holds the reference. */
|
|
580
|
+
path: string;
|
|
581
|
+
/** The actual value seen at `path` (the referenced name). */
|
|
582
|
+
value: string;
|
|
583
|
+
}
|
|
584
|
+
interface MetadataHistoryOptions {
|
|
585
|
+
/** Only return events after this sequence number. */
|
|
586
|
+
sinceSeq?: number;
|
|
587
|
+
/** Limit the number of events returned. */
|
|
588
|
+
limit?: number;
|
|
589
|
+
}
|
|
590
|
+
interface MetadataError extends Error {
|
|
591
|
+
status: number;
|
|
592
|
+
code?: string;
|
|
593
|
+
body?: unknown;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* MetadataClient — read/write protocol metadata via the framework REST API.
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```ts
|
|
600
|
+
* const client = new MetadataClient({ baseUrl: 'http://localhost:3000' });
|
|
601
|
+
* const objects = await client.list<{ name: string; label?: string }>('object');
|
|
602
|
+
* const account = await client.get<{ fields: Record<string, unknown> }>('object', 'account');
|
|
603
|
+
* await client.save('object', 'account', { ...account, label: 'Customer' });
|
|
604
|
+
* ```
|
|
605
|
+
*/
|
|
606
|
+
declare class MetadataClient {
|
|
607
|
+
private readonly base;
|
|
608
|
+
private readonly fetchImpl;
|
|
609
|
+
private readonly headers;
|
|
610
|
+
constructor(config: MetadataClientConfig);
|
|
611
|
+
/** Update the client's environment scope at runtime. */
|
|
612
|
+
withEnvironment(environmentId: string | undefined): MetadataClient;
|
|
613
|
+
/** List all registered metadata types (returns the registry rows). */
|
|
614
|
+
listTypes(): Promise<unknown[]>;
|
|
615
|
+
/** List items of a metadata type (e.g. `object`, `field`, `view`). */
|
|
616
|
+
list<T = unknown>(type: string, options?: MetadataListOptions): Promise<T[]>;
|
|
617
|
+
/**
|
|
618
|
+
* Get a single metadata item. Returns the unwrapped item content
|
|
619
|
+
* (matching the framework REST handler which calls `res.json(item)`).
|
|
620
|
+
* Returns `null` on 404 to keep the call-site ergonomic.
|
|
621
|
+
*/
|
|
622
|
+
get<T = unknown>(type: string, name: string): Promise<T | null>;
|
|
623
|
+
/**
|
|
624
|
+
* Save (PUT) a metadata item. The framework accepts both the bare
|
|
625
|
+
* item payload and the `{ item: ... }` / `{ metadata: ... }`
|
|
626
|
+
* envelopes; we send bare for consistency.
|
|
627
|
+
*/
|
|
628
|
+
save<T = unknown>(type: string, name: string, item: unknown, options?: MetadataSaveOptions): Promise<T>;
|
|
629
|
+
/**
|
|
630
|
+
* Get the 3-state layered view of a metadata item (Phase 3a). Returns
|
|
631
|
+
* `code` (the artifact / fallback default), `overlay` (the saved
|
|
632
|
+
* customisation, if any), and `effective` (what the runtime sees).
|
|
633
|
+
*/
|
|
634
|
+
layered<T = unknown>(type: string, name: string): Promise<MetadataLayered<T>>;
|
|
635
|
+
/**
|
|
636
|
+
* Find every metadata item that references this one (Phase 3a). Useful
|
|
637
|
+
* for pre-delete impact analysis: "Are any views pointing at this
|
|
638
|
+
* object before I drop it?".
|
|
639
|
+
*/
|
|
640
|
+
references(type: string, name: string): Promise<MetadataReference[]>;
|
|
641
|
+
/**
|
|
642
|
+
* Reset a metadata customization overlay back to the artifact default.
|
|
643
|
+
* Idempotent: returns the result even when no overlay row existed.
|
|
644
|
+
*/
|
|
645
|
+
reset<T = unknown>(type: string, name: string, options?: MetadataSaveOptions): Promise<T>;
|
|
646
|
+
/** Fetch the durable history (change log) for one metadata item. */
|
|
647
|
+
history<T = unknown>(type: string, name: string, options?: MetadataHistoryOptions): Promise<T>;
|
|
648
|
+
}
|
|
649
|
+
|
|
494
650
|
/**
|
|
495
651
|
* ObjectUI
|
|
496
652
|
* Copyright (c) 2024-present ObjectStack Inc.
|
|
@@ -1233,4 +1389,4 @@ declare function createObjectStackAdapter<T = unknown>(config: {
|
|
|
1233
1389
|
reconnectDelay?: number;
|
|
1234
1390
|
}): DataSource<T>;
|
|
1235
1391
|
|
|
1236
|
-
export { type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, ConcurrentUpdateError, ConnectionError, type ConnectionState, type ConnectionStateEvent, type ConnectionStateListener, type ContractValidationError, type ContractValidationResult, type DataMaskingConfig, type DataMaskingRule, type EmailIntegrationConfig, type IntegrationConfig, IntegrationManager, type IntegrationProvider, type IntegrationTrigger, MetadataNotFoundError, ObjectStackAdapter, ObjectStackError, type ObjectStackUserStateAdapterOptions, type PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, type UserDataAdapter, ValidationError, type WebhookIntegrationConfig, calculateAutoLayout, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, createObjectStackUserStateAdapter, generateContractManifest, getSharedDiscovery, is404Error, isConcurrentUpdateError, isErrorType, isObjectStackError, normaliseClientError, snapToGrid, validatePluginContract };
|
|
1392
|
+
export { type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, ConcurrentUpdateError, ConnectionError, type ConnectionState, type ConnectionStateEvent, type ConnectionStateListener, type ContractValidationError, type ContractValidationResult, type DataMaskingConfig, type DataMaskingRule, type EmailIntegrationConfig, type IntegrationConfig, IntegrationManager, type IntegrationProvider, type IntegrationTrigger, MetadataClient, type MetadataClientConfig, type MetadataError, type MetadataHistoryOptions, type MetadataLayered, type MetadataListOptions, MetadataNotFoundError, type MetadataReference, type MetadataSaveOptions, ObjectStackAdapter, ObjectStackError, type ObjectStackUserStateAdapterOptions, type PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, type UserDataAdapter, ValidationError, type WebhookIntegrationConfig, calculateAutoLayout, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, createObjectStackUserStateAdapter, generateContractManifest, getSharedDiscovery, is404Error, isConcurrentUpdateError, isErrorType, isObjectStackError, normaliseClientError, snapToGrid, validatePluginContract };
|
package/dist/index.d.ts
CHANGED
|
@@ -491,6 +491,162 @@ declare class IntegrationManager {
|
|
|
491
491
|
private send;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
+
/**
|
|
495
|
+
* ObjectUI
|
|
496
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
497
|
+
*
|
|
498
|
+
* This source code is licensed under the MIT license found in the
|
|
499
|
+
* LICENSE file in the root directory of this source tree.
|
|
500
|
+
*/
|
|
501
|
+
/**
|
|
502
|
+
* MetadataClient
|
|
503
|
+
*
|
|
504
|
+
* Thin, framework-agnostic HTTP client for the ObjectStack metadata
|
|
505
|
+
* API (`/api/v1/meta/*`). Used by the platform Setup app surfaces in
|
|
506
|
+
* `@object-ui/plugin-designer` (Object Manager, Field Designer, etc.)
|
|
507
|
+
* so they can read and write protocol metadata without depending on
|
|
508
|
+
* `ObjectStackAdapter` (which is a generic data-source binding and
|
|
509
|
+
* carries a lot of view/dashboard-specific behaviour we don't need
|
|
510
|
+
* here).
|
|
511
|
+
*
|
|
512
|
+
* Endpoints (see `packages/rest/src/rest-server.ts`):
|
|
513
|
+
* GET /api/v1/meta — list all metadata types
|
|
514
|
+
* GET /api/v1/meta/:type — list items of a type
|
|
515
|
+
* GET /api/v1/meta/:type/:name — get one item (returns the
|
|
516
|
+
* unwrapped item content)
|
|
517
|
+
* PUT /api/v1/meta/:type/:name — save (overlay) one item
|
|
518
|
+
* honours `If-Match` for OCC
|
|
519
|
+
* DELETE /api/v1/meta/:type/:name — reset overlay to artifact
|
|
520
|
+
* GET /api/v1/meta/:type/:name/history — durable change log
|
|
521
|
+
*
|
|
522
|
+
* The client deliberately keeps the response shape opaque (typed as
|
|
523
|
+
* `unknown`/generic `T`) so callers explicitly narrow per-metadata-
|
|
524
|
+
* type, mirroring the framework's "single Zod source per type" rule.
|
|
525
|
+
*/
|
|
526
|
+
interface MetadataClientConfig {
|
|
527
|
+
/** Base URL of the ObjectStack server (no trailing slash needed). */
|
|
528
|
+
baseUrl: string;
|
|
529
|
+
/**
|
|
530
|
+
* Optional environment ID to scope reads/writes to a tenant. When
|
|
531
|
+
* provided, requests use the scoped path
|
|
532
|
+
* `/api/v1/environments/:environmentId/meta/...` and overlays are
|
|
533
|
+
* persisted in the environment's own metadata store.
|
|
534
|
+
*/
|
|
535
|
+
environmentId?: string;
|
|
536
|
+
/** Optional custom fetch implementation (defaults to `globalThis.fetch`). */
|
|
537
|
+
fetch?: typeof fetch;
|
|
538
|
+
/** Additional headers (e.g. auth) included on every request. */
|
|
539
|
+
headers?: Record<string, string>;
|
|
540
|
+
}
|
|
541
|
+
interface MetadataListOptions {
|
|
542
|
+
/** Filter by source package id (matches the `package` query param). */
|
|
543
|
+
packageId?: string;
|
|
544
|
+
}
|
|
545
|
+
interface MetadataSaveOptions {
|
|
546
|
+
/**
|
|
547
|
+
* Optimistic concurrency token (the `checksum` returned by the last
|
|
548
|
+
* read). When present, sent as the `If-Match` header so concurrent
|
|
549
|
+
* edits get a 409 instead of overwriting each other.
|
|
550
|
+
*/
|
|
551
|
+
ifMatch?: string;
|
|
552
|
+
/** Optional actor id, sent as `X-Actor` for history attribution. */
|
|
553
|
+
actor?: string;
|
|
554
|
+
/**
|
|
555
|
+
* Bypass destructive-change protection (Phase 3a). The server returns
|
|
556
|
+
* `409 destructive_change` with `issues[]` if a write would drop or
|
|
557
|
+
* narrow data; setting `force: true` adds `?force=true` to the request
|
|
558
|
+
* so the operator can confirm and proceed.
|
|
559
|
+
*/
|
|
560
|
+
force?: boolean;
|
|
561
|
+
}
|
|
562
|
+
/** Layered view of a metadata item — Phase 3a `?layers=true`. */
|
|
563
|
+
interface MetadataLayered<T = unknown> {
|
|
564
|
+
/** Code-level (artifact) item; null if the item only exists as an overlay. */
|
|
565
|
+
code: T | null;
|
|
566
|
+
/** Org/environment overlay (just the saved delta or full overlay row). */
|
|
567
|
+
overlay: T | null;
|
|
568
|
+
/** Overlay scope (`organization` | `environment` | `package` | null). */
|
|
569
|
+
overlayScope: string | null;
|
|
570
|
+
/** Merged effective view — what the runtime actually sees. */
|
|
571
|
+
effective: T | null;
|
|
572
|
+
}
|
|
573
|
+
/** Reference back-pointer — Phase 3a `/references`. */
|
|
574
|
+
interface MetadataReference {
|
|
575
|
+
/** Referencing item's metadata type. */
|
|
576
|
+
fromType: string;
|
|
577
|
+
/** Referencing item's name. */
|
|
578
|
+
fromName: string;
|
|
579
|
+
/** JSON path within the referencing item that holds the reference. */
|
|
580
|
+
path: string;
|
|
581
|
+
/** The actual value seen at `path` (the referenced name). */
|
|
582
|
+
value: string;
|
|
583
|
+
}
|
|
584
|
+
interface MetadataHistoryOptions {
|
|
585
|
+
/** Only return events after this sequence number. */
|
|
586
|
+
sinceSeq?: number;
|
|
587
|
+
/** Limit the number of events returned. */
|
|
588
|
+
limit?: number;
|
|
589
|
+
}
|
|
590
|
+
interface MetadataError extends Error {
|
|
591
|
+
status: number;
|
|
592
|
+
code?: string;
|
|
593
|
+
body?: unknown;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* MetadataClient — read/write protocol metadata via the framework REST API.
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```ts
|
|
600
|
+
* const client = new MetadataClient({ baseUrl: 'http://localhost:3000' });
|
|
601
|
+
* const objects = await client.list<{ name: string; label?: string }>('object');
|
|
602
|
+
* const account = await client.get<{ fields: Record<string, unknown> }>('object', 'account');
|
|
603
|
+
* await client.save('object', 'account', { ...account, label: 'Customer' });
|
|
604
|
+
* ```
|
|
605
|
+
*/
|
|
606
|
+
declare class MetadataClient {
|
|
607
|
+
private readonly base;
|
|
608
|
+
private readonly fetchImpl;
|
|
609
|
+
private readonly headers;
|
|
610
|
+
constructor(config: MetadataClientConfig);
|
|
611
|
+
/** Update the client's environment scope at runtime. */
|
|
612
|
+
withEnvironment(environmentId: string | undefined): MetadataClient;
|
|
613
|
+
/** List all registered metadata types (returns the registry rows). */
|
|
614
|
+
listTypes(): Promise<unknown[]>;
|
|
615
|
+
/** List items of a metadata type (e.g. `object`, `field`, `view`). */
|
|
616
|
+
list<T = unknown>(type: string, options?: MetadataListOptions): Promise<T[]>;
|
|
617
|
+
/**
|
|
618
|
+
* Get a single metadata item. Returns the unwrapped item content
|
|
619
|
+
* (matching the framework REST handler which calls `res.json(item)`).
|
|
620
|
+
* Returns `null` on 404 to keep the call-site ergonomic.
|
|
621
|
+
*/
|
|
622
|
+
get<T = unknown>(type: string, name: string): Promise<T | null>;
|
|
623
|
+
/**
|
|
624
|
+
* Save (PUT) a metadata item. The framework accepts both the bare
|
|
625
|
+
* item payload and the `{ item: ... }` / `{ metadata: ... }`
|
|
626
|
+
* envelopes; we send bare for consistency.
|
|
627
|
+
*/
|
|
628
|
+
save<T = unknown>(type: string, name: string, item: unknown, options?: MetadataSaveOptions): Promise<T>;
|
|
629
|
+
/**
|
|
630
|
+
* Get the 3-state layered view of a metadata item (Phase 3a). Returns
|
|
631
|
+
* `code` (the artifact / fallback default), `overlay` (the saved
|
|
632
|
+
* customisation, if any), and `effective` (what the runtime sees).
|
|
633
|
+
*/
|
|
634
|
+
layered<T = unknown>(type: string, name: string): Promise<MetadataLayered<T>>;
|
|
635
|
+
/**
|
|
636
|
+
* Find every metadata item that references this one (Phase 3a). Useful
|
|
637
|
+
* for pre-delete impact analysis: "Are any views pointing at this
|
|
638
|
+
* object before I drop it?".
|
|
639
|
+
*/
|
|
640
|
+
references(type: string, name: string): Promise<MetadataReference[]>;
|
|
641
|
+
/**
|
|
642
|
+
* Reset a metadata customization overlay back to the artifact default.
|
|
643
|
+
* Idempotent: returns the result even when no overlay row existed.
|
|
644
|
+
*/
|
|
645
|
+
reset<T = unknown>(type: string, name: string, options?: MetadataSaveOptions): Promise<T>;
|
|
646
|
+
/** Fetch the durable history (change log) for one metadata item. */
|
|
647
|
+
history<T = unknown>(type: string, name: string, options?: MetadataHistoryOptions): Promise<T>;
|
|
648
|
+
}
|
|
649
|
+
|
|
494
650
|
/**
|
|
495
651
|
* ObjectUI
|
|
496
652
|
* Copyright (c) 2024-present ObjectStack Inc.
|
|
@@ -1233,4 +1389,4 @@ declare function createObjectStackAdapter<T = unknown>(config: {
|
|
|
1233
1389
|
reconnectDelay?: number;
|
|
1234
1390
|
}): DataSource<T>;
|
|
1235
1391
|
|
|
1236
|
-
export { type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, ConcurrentUpdateError, ConnectionError, type ConnectionState, type ConnectionStateEvent, type ConnectionStateListener, type ContractValidationError, type ContractValidationResult, type DataMaskingConfig, type DataMaskingRule, type EmailIntegrationConfig, type IntegrationConfig, IntegrationManager, type IntegrationProvider, type IntegrationTrigger, MetadataNotFoundError, ObjectStackAdapter, ObjectStackError, type ObjectStackUserStateAdapterOptions, type PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, type UserDataAdapter, ValidationError, type WebhookIntegrationConfig, calculateAutoLayout, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, createObjectStackUserStateAdapter, generateContractManifest, getSharedDiscovery, is404Error, isConcurrentUpdateError, isErrorType, isObjectStackError, normaliseClientError, snapToGrid, validatePluginContract };
|
|
1392
|
+
export { type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, ConcurrentUpdateError, ConnectionError, type ConnectionState, type ConnectionStateEvent, type ConnectionStateListener, type ContractValidationError, type ContractValidationResult, type DataMaskingConfig, type DataMaskingRule, type EmailIntegrationConfig, type IntegrationConfig, IntegrationManager, type IntegrationProvider, type IntegrationTrigger, MetadataClient, type MetadataClientConfig, type MetadataError, type MetadataHistoryOptions, type MetadataLayered, type MetadataListOptions, MetadataNotFoundError, type MetadataReference, type MetadataSaveOptions, ObjectStackAdapter, ObjectStackError, type ObjectStackUserStateAdapterOptions, type PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, type UserDataAdapter, ValidationError, type WebhookIntegrationConfig, calculateAutoLayout, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, createObjectStackUserStateAdapter, generateContractManifest, getSharedDiscovery, is404Error, isConcurrentUpdateError, isErrorType, isObjectStackError, normaliseClientError, snapToGrid, validatePluginContract };
|