@object-ui/data-objectstack 4.0.8 → 4.0.10

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @object-ui/data-objectstack
2
2
 
3
+ ## 4.0.10
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@4.0.10
8
+ - @object-ui/core@4.0.10
9
+
10
+ ## 4.0.9
11
+
12
+ ### Patch Changes
13
+
14
+ - @object-ui/types@4.0.9
15
+ - @object-ui/core@4.0.9
16
+
3
17
  ## 4.0.8
4
18
 
5
19
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -1586,20 +1586,126 @@ var ObjectStackAdapter = class {
1586
1586
  async updateViewConfig(objectName, viewId, config) {
1587
1587
  await this.connect();
1588
1588
  try {
1589
+ const merged = { ...config || {}, object: config?.object || objectName, name: viewId };
1589
1590
  const result = await this.client.meta.saveItem(
1590
- objectName,
1591
+ "view",
1591
1592
  viewId,
1592
- config
1593
+ merged
1593
1594
  );
1594
1595
  const cacheKey = `view:${objectName}:${viewId}`;
1595
1596
  this.metadataCache.invalidate?.(cacheKey);
1596
1597
  this.metadataCache.invalidate?.(`view-overrides:${objectName}`);
1598
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1597
1599
  if (result && result.item) return result.item;
1598
1600
  return result ?? void 0;
1599
1601
  } catch (err) {
1600
1602
  throw err;
1601
1603
  }
1602
1604
  }
1605
+ /**
1606
+ * List user-created views for a given object via the metadata overlay
1607
+ * API (ADR-0005). Replaces the legacy `find('sys_view', {...})` path
1608
+ * that wrote to a physical `sys_view` table whose columns no longer
1609
+ * match the view spec shape.
1610
+ *
1611
+ * Returns view spec objects with their canonical `name` as identifier.
1612
+ * Filters by `data.object === objectName` (or top-level `object`)
1613
+ * client-side because the metadata index is name-only, not field-typed.
1614
+ */
1615
+ async listViews(objectName) {
1616
+ await this.connect();
1617
+ try {
1618
+ const result = await this.client.meta.getItems("view");
1619
+ const items = Array.isArray(result?.items) ? result.items : Array.isArray(result) ? result : [];
1620
+ return items.filter((v) => {
1621
+ if (!v) return false;
1622
+ const spec = v.list ?? v;
1623
+ const obj = spec?.data?.object ?? spec?.object ?? spec?.objectName;
1624
+ return obj === objectName;
1625
+ }).map((v) => v.list ?? v);
1626
+ } catch (err) {
1627
+ console.warn("[OBJECTSTACKDataSource] listViews failed:", err);
1628
+ return [];
1629
+ }
1630
+ }
1631
+ /**
1632
+ * Create a new overlay view for an object. The view's `name` is the
1633
+ * stable identifier — must be unique within the project scope. Returns
1634
+ * the persisted view spec (or undefined when the server doesn't echo).
1635
+ *
1636
+ * Generates a snake_case name if `spec.name` is not provided by appending
1637
+ * a short timestamp suffix to the source-name hint.
1638
+ */
1639
+ async createView(objectName, spec) {
1640
+ await this.connect();
1641
+ let name = String(spec?.name || "").trim();
1642
+ if (!name) {
1643
+ const base = String(spec?.label || objectName || "view").toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40) || "view";
1644
+ const suffix = Date.now().toString(36);
1645
+ name = `${base}_${suffix}`;
1646
+ }
1647
+ const fullSpec = {
1648
+ ...spec,
1649
+ name,
1650
+ object: spec?.object || objectName,
1651
+ data: spec?.data || { provider: "object", object: objectName }
1652
+ };
1653
+ try {
1654
+ const result = await this.client.meta.saveItem("view", name, fullSpec);
1655
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1656
+ if (result && result.item) return result.item;
1657
+ return fullSpec;
1658
+ } catch (err) {
1659
+ throw err;
1660
+ }
1661
+ }
1662
+ /**
1663
+ * Apply a partial update to an existing overlay view. Reads the current
1664
+ * overlay (or seeds from artifact), merges, and writes back. ADR-0005
1665
+ * overlay rows store the *full* view document, so partial updates require
1666
+ * a read-merge-write cycle.
1667
+ */
1668
+ async updateView(objectName, viewName, partial) {
1669
+ await this.connect();
1670
+ let current = {};
1671
+ try {
1672
+ const r = await this.client.meta.getItem("view", viewName);
1673
+ current = r && (r.item || r) || {};
1674
+ if (current?.list) current = current.list;
1675
+ } catch {
1676
+ }
1677
+ const merged = {
1678
+ ...current,
1679
+ ...partial,
1680
+ name: viewName,
1681
+ object: current?.object || current?.data?.object || objectName
1682
+ };
1683
+ try {
1684
+ const result = await this.client.meta.saveItem("view", viewName, merged);
1685
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1686
+ this.metadataCache.invalidate?.(`view:${objectName}:${viewName}`);
1687
+ if (result && result.item) return result.item;
1688
+ return merged;
1689
+ } catch (err) {
1690
+ throw err;
1691
+ }
1692
+ }
1693
+ /**
1694
+ * Delete an overlay view (reset to artifact default if one exists, or
1695
+ * remove entirely if it was a user-created view). Routes to
1696
+ * `DELETE /api/v1/meta/view/:name`.
1697
+ */
1698
+ async deleteView(objectName, viewName) {
1699
+ await this.connect();
1700
+ try {
1701
+ const result = await this.client.meta.deleteItem("view", viewName);
1702
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1703
+ this.metadataCache.invalidate?.(`view:${objectName}:${viewName}`);
1704
+ return { deleted: !!(result?.deleted ?? result?.reset ?? true) };
1705
+ } catch (err) {
1706
+ throw err;
1707
+ }
1708
+ }
1603
1709
  /**
1604
1710
  * Get an application definition by name or ID.
1605
1711
  * Attempts to fetch from the server metadata API.
package/dist/index.d.cts CHANGED
@@ -896,6 +896,41 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
896
896
  * @param config - Full view definition to persist
897
897
  */
898
898
  updateViewConfig(objectName: string, viewId: string, config: Record<string, any>): Promise<Record<string, any> | void>;
899
+ /**
900
+ * List user-created views for a given object via the metadata overlay
901
+ * API (ADR-0005). Replaces the legacy `find('sys_view', {...})` path
902
+ * that wrote to a physical `sys_view` table whose columns no longer
903
+ * match the view spec shape.
904
+ *
905
+ * Returns view spec objects with their canonical `name` as identifier.
906
+ * Filters by `data.object === objectName` (or top-level `object`)
907
+ * client-side because the metadata index is name-only, not field-typed.
908
+ */
909
+ listViews(objectName: string): Promise<any[]>;
910
+ /**
911
+ * Create a new overlay view for an object. The view's `name` is the
912
+ * stable identifier — must be unique within the project scope. Returns
913
+ * the persisted view spec (or undefined when the server doesn't echo).
914
+ *
915
+ * Generates a snake_case name if `spec.name` is not provided by appending
916
+ * a short timestamp suffix to the source-name hint.
917
+ */
918
+ createView(objectName: string, spec: Record<string, any>): Promise<Record<string, any> | void>;
919
+ /**
920
+ * Apply a partial update to an existing overlay view. Reads the current
921
+ * overlay (or seeds from artifact), merges, and writes back. ADR-0005
922
+ * overlay rows store the *full* view document, so partial updates require
923
+ * a read-merge-write cycle.
924
+ */
925
+ updateView(objectName: string, viewName: string, partial: Record<string, any>): Promise<Record<string, any> | void>;
926
+ /**
927
+ * Delete an overlay view (reset to artifact default if one exists, or
928
+ * remove entirely if it was a user-created view). Routes to
929
+ * `DELETE /api/v1/meta/view/:name`.
930
+ */
931
+ deleteView(objectName: string, viewName: string): Promise<{
932
+ deleted: boolean;
933
+ }>;
899
934
  /**
900
935
  * Get an application definition by name or ID.
901
936
  * Attempts to fetch from the server metadata API.
package/dist/index.d.ts CHANGED
@@ -896,6 +896,41 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
896
896
  * @param config - Full view definition to persist
897
897
  */
898
898
  updateViewConfig(objectName: string, viewId: string, config: Record<string, any>): Promise<Record<string, any> | void>;
899
+ /**
900
+ * List user-created views for a given object via the metadata overlay
901
+ * API (ADR-0005). Replaces the legacy `find('sys_view', {...})` path
902
+ * that wrote to a physical `sys_view` table whose columns no longer
903
+ * match the view spec shape.
904
+ *
905
+ * Returns view spec objects with their canonical `name` as identifier.
906
+ * Filters by `data.object === objectName` (or top-level `object`)
907
+ * client-side because the metadata index is name-only, not field-typed.
908
+ */
909
+ listViews(objectName: string): Promise<any[]>;
910
+ /**
911
+ * Create a new overlay view for an object. The view's `name` is the
912
+ * stable identifier — must be unique within the project scope. Returns
913
+ * the persisted view spec (or undefined when the server doesn't echo).
914
+ *
915
+ * Generates a snake_case name if `spec.name` is not provided by appending
916
+ * a short timestamp suffix to the source-name hint.
917
+ */
918
+ createView(objectName: string, spec: Record<string, any>): Promise<Record<string, any> | void>;
919
+ /**
920
+ * Apply a partial update to an existing overlay view. Reads the current
921
+ * overlay (or seeds from artifact), merges, and writes back. ADR-0005
922
+ * overlay rows store the *full* view document, so partial updates require
923
+ * a read-merge-write cycle.
924
+ */
925
+ updateView(objectName: string, viewName: string, partial: Record<string, any>): Promise<Record<string, any> | void>;
926
+ /**
927
+ * Delete an overlay view (reset to artifact default if one exists, or
928
+ * remove entirely if it was a user-created view). Routes to
929
+ * `DELETE /api/v1/meta/view/:name`.
930
+ */
931
+ deleteView(objectName: string, viewName: string): Promise<{
932
+ deleted: boolean;
933
+ }>;
899
934
  /**
900
935
  * Get an application definition by name or ID.
901
936
  * Attempts to fetch from the server metadata API.
package/dist/index.js CHANGED
@@ -1543,20 +1543,126 @@ var ObjectStackAdapter = class {
1543
1543
  async updateViewConfig(objectName, viewId, config) {
1544
1544
  await this.connect();
1545
1545
  try {
1546
+ const merged = { ...config || {}, object: config?.object || objectName, name: viewId };
1546
1547
  const result = await this.client.meta.saveItem(
1547
- objectName,
1548
+ "view",
1548
1549
  viewId,
1549
- config
1550
+ merged
1550
1551
  );
1551
1552
  const cacheKey = `view:${objectName}:${viewId}`;
1552
1553
  this.metadataCache.invalidate?.(cacheKey);
1553
1554
  this.metadataCache.invalidate?.(`view-overrides:${objectName}`);
1555
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1554
1556
  if (result && result.item) return result.item;
1555
1557
  return result ?? void 0;
1556
1558
  } catch (err) {
1557
1559
  throw err;
1558
1560
  }
1559
1561
  }
1562
+ /**
1563
+ * List user-created views for a given object via the metadata overlay
1564
+ * API (ADR-0005). Replaces the legacy `find('sys_view', {...})` path
1565
+ * that wrote to a physical `sys_view` table whose columns no longer
1566
+ * match the view spec shape.
1567
+ *
1568
+ * Returns view spec objects with their canonical `name` as identifier.
1569
+ * Filters by `data.object === objectName` (or top-level `object`)
1570
+ * client-side because the metadata index is name-only, not field-typed.
1571
+ */
1572
+ async listViews(objectName) {
1573
+ await this.connect();
1574
+ try {
1575
+ const result = await this.client.meta.getItems("view");
1576
+ const items = Array.isArray(result?.items) ? result.items : Array.isArray(result) ? result : [];
1577
+ return items.filter((v) => {
1578
+ if (!v) return false;
1579
+ const spec = v.list ?? v;
1580
+ const obj = spec?.data?.object ?? spec?.object ?? spec?.objectName;
1581
+ return obj === objectName;
1582
+ }).map((v) => v.list ?? v);
1583
+ } catch (err) {
1584
+ console.warn("[OBJECTSTACKDataSource] listViews failed:", err);
1585
+ return [];
1586
+ }
1587
+ }
1588
+ /**
1589
+ * Create a new overlay view for an object. The view's `name` is the
1590
+ * stable identifier — must be unique within the project scope. Returns
1591
+ * the persisted view spec (or undefined when the server doesn't echo).
1592
+ *
1593
+ * Generates a snake_case name if `spec.name` is not provided by appending
1594
+ * a short timestamp suffix to the source-name hint.
1595
+ */
1596
+ async createView(objectName, spec) {
1597
+ await this.connect();
1598
+ let name = String(spec?.name || "").trim();
1599
+ if (!name) {
1600
+ const base = String(spec?.label || objectName || "view").toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40) || "view";
1601
+ const suffix = Date.now().toString(36);
1602
+ name = `${base}_${suffix}`;
1603
+ }
1604
+ const fullSpec = {
1605
+ ...spec,
1606
+ name,
1607
+ object: spec?.object || objectName,
1608
+ data: spec?.data || { provider: "object", object: objectName }
1609
+ };
1610
+ try {
1611
+ const result = await this.client.meta.saveItem("view", name, fullSpec);
1612
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1613
+ if (result && result.item) return result.item;
1614
+ return fullSpec;
1615
+ } catch (err) {
1616
+ throw err;
1617
+ }
1618
+ }
1619
+ /**
1620
+ * Apply a partial update to an existing overlay view. Reads the current
1621
+ * overlay (or seeds from artifact), merges, and writes back. ADR-0005
1622
+ * overlay rows store the *full* view document, so partial updates require
1623
+ * a read-merge-write cycle.
1624
+ */
1625
+ async updateView(objectName, viewName, partial) {
1626
+ await this.connect();
1627
+ let current = {};
1628
+ try {
1629
+ const r = await this.client.meta.getItem("view", viewName);
1630
+ current = r && (r.item || r) || {};
1631
+ if (current?.list) current = current.list;
1632
+ } catch {
1633
+ }
1634
+ const merged = {
1635
+ ...current,
1636
+ ...partial,
1637
+ name: viewName,
1638
+ object: current?.object || current?.data?.object || objectName
1639
+ };
1640
+ try {
1641
+ const result = await this.client.meta.saveItem("view", viewName, merged);
1642
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1643
+ this.metadataCache.invalidate?.(`view:${objectName}:${viewName}`);
1644
+ if (result && result.item) return result.item;
1645
+ return merged;
1646
+ } catch (err) {
1647
+ throw err;
1648
+ }
1649
+ }
1650
+ /**
1651
+ * Delete an overlay view (reset to artifact default if one exists, or
1652
+ * remove entirely if it was a user-created view). Routes to
1653
+ * `DELETE /api/v1/meta/view/:name`.
1654
+ */
1655
+ async deleteView(objectName, viewName) {
1656
+ await this.connect();
1657
+ try {
1658
+ const result = await this.client.meta.deleteItem("view", viewName);
1659
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1660
+ this.metadataCache.invalidate?.(`view:${objectName}:${viewName}`);
1661
+ return { deleted: !!(result?.deleted ?? result?.reset ?? true) };
1662
+ } catch (err) {
1663
+ throw err;
1664
+ }
1665
+ }
1560
1666
  /**
1561
1667
  * Get an application definition by name or ID.
1562
1668
  * Attempts to fetch from the server metadata API.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/data-objectstack",
3
- "version": "4.0.8",
3
+ "version": "4.0.10",
4
4
  "description": "ObjectStack Data Adapter for Object UI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,8 +23,8 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@objectstack/client": "^4.0.5",
26
- "@object-ui/core": "4.0.8",
27
- "@object-ui/types": "4.0.8"
26
+ "@object-ui/core": "4.0.10",
27
+ "@object-ui/types": "4.0.10"
28
28
  },
29
29
  "devDependencies": {
30
30
  "tsup": "^8.5.1",
package/src/index.ts CHANGED
@@ -1116,16 +1116,23 @@ export class ObjectStackAdapter<T = unknown> implements DataSource<T> {
1116
1116
  ): Promise<Record<string, any> | void> {
1117
1117
  await this.connect();
1118
1118
  try {
1119
+ // ADR-0005 metadata customization overlay: persist views under
1120
+ // `type='view'` (NOT `type=<objectName>` — that was a pre-overlay
1121
+ // misuse that hit `/api/v1/meta/<objectName>/<viewId>`, which the
1122
+ // server never wired). The view's `data.object` field is what
1123
+ // associates it back to the object on read.
1124
+ const merged = { ...(config || {}), object: (config as any)?.object || objectName, name: viewId };
1119
1125
  const result: any = await this.client.meta.saveItem(
1120
- objectName,
1126
+ 'view',
1121
1127
  viewId,
1122
- config
1128
+ merged
1123
1129
  );
1124
1130
  // Invalidate cached read so next getView reflects the change
1125
1131
  const cacheKey = `view:${objectName}:${viewId}`;
1126
1132
  this.metadataCache.invalidate?.(cacheKey);
1127
1133
  // Also invalidate the batch override map so listViewOverrides re-fetches
1128
1134
  this.metadataCache.invalidate?.(`view-overrides:${objectName}`);
1135
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1129
1136
  if (result && result.item) return result.item;
1130
1137
  return result ?? undefined;
1131
1138
  } catch (err) {
@@ -1136,6 +1143,134 @@ export class ObjectStackAdapter<T = unknown> implements DataSource<T> {
1136
1143
  }
1137
1144
  }
1138
1145
 
1146
+ /**
1147
+ * List user-created views for a given object via the metadata overlay
1148
+ * API (ADR-0005). Replaces the legacy `find('sys_view', {...})` path
1149
+ * that wrote to a physical `sys_view` table whose columns no longer
1150
+ * match the view spec shape.
1151
+ *
1152
+ * Returns view spec objects with their canonical `name` as identifier.
1153
+ * Filters by `data.object === objectName` (or top-level `object`)
1154
+ * client-side because the metadata index is name-only, not field-typed.
1155
+ */
1156
+ async listViews(objectName: string): Promise<any[]> {
1157
+ await this.connect();
1158
+ try {
1159
+ const result: any = await this.client.meta.getItems('view');
1160
+ const items: any[] = Array.isArray(result?.items)
1161
+ ? result.items
1162
+ : Array.isArray(result) ? result : [];
1163
+ return items.filter((v: any) => {
1164
+ if (!v) return false;
1165
+ // Handle both bare view spec and `{list: {...}}` artifact wrapper
1166
+ const spec = v.list ?? v;
1167
+ const obj = spec?.data?.object ?? spec?.object ?? spec?.objectName;
1168
+ return obj === objectName;
1169
+ }).map((v: any) => v.list ?? v);
1170
+ } catch (err) {
1171
+ console.warn('[OBJECTSTACKDataSource] listViews failed:', err);
1172
+ return [];
1173
+ }
1174
+ }
1175
+
1176
+ /**
1177
+ * Create a new overlay view for an object. The view's `name` is the
1178
+ * stable identifier — must be unique within the project scope. Returns
1179
+ * the persisted view spec (or undefined when the server doesn't echo).
1180
+ *
1181
+ * Generates a snake_case name if `spec.name` is not provided by appending
1182
+ * a short timestamp suffix to the source-name hint.
1183
+ */
1184
+ async createView(
1185
+ objectName: string,
1186
+ spec: Record<string, any>,
1187
+ ): Promise<Record<string, any> | void> {
1188
+ await this.connect();
1189
+ let name = String(spec?.name || '').trim();
1190
+ if (!name) {
1191
+ const base = String(spec?.label || objectName || 'view')
1192
+ .toLowerCase()
1193
+ .replace(/[^a-z0-9_]+/g, '_')
1194
+ .replace(/^_+|_+$/g, '')
1195
+ .slice(0, 40) || 'view';
1196
+ const suffix = Date.now().toString(36);
1197
+ name = `${base}_${suffix}`;
1198
+ }
1199
+ const fullSpec = {
1200
+ ...spec,
1201
+ name,
1202
+ object: spec?.object || objectName,
1203
+ data: spec?.data || { provider: 'object', object: objectName },
1204
+ };
1205
+ try {
1206
+ const result: any = await this.client.meta.saveItem('view', name, fullSpec);
1207
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1208
+ if (result && result.item) return result.item;
1209
+ return fullSpec;
1210
+ } catch (err) {
1211
+ throw err;
1212
+ }
1213
+ }
1214
+
1215
+ /**
1216
+ * Apply a partial update to an existing overlay view. Reads the current
1217
+ * overlay (or seeds from artifact), merges, and writes back. ADR-0005
1218
+ * overlay rows store the *full* view document, so partial updates require
1219
+ * a read-merge-write cycle.
1220
+ */
1221
+ async updateView(
1222
+ objectName: string,
1223
+ viewName: string,
1224
+ partial: Record<string, any>,
1225
+ ): Promise<Record<string, any> | void> {
1226
+ await this.connect();
1227
+ let current: any = {};
1228
+ try {
1229
+ const r: any = await this.client.meta.getItem('view', viewName);
1230
+ current = (r && (r.item || r)) || {};
1231
+ // Some endpoints return the bare item; others wrap as {type,name,item}
1232
+ if (current?.list) current = current.list;
1233
+ } catch {
1234
+ // Treat missing as create-equivalent
1235
+ }
1236
+ const merged = {
1237
+ ...current,
1238
+ ...partial,
1239
+ name: viewName,
1240
+ object: current?.object || (current as any)?.data?.object || objectName,
1241
+ };
1242
+ try {
1243
+ const result: any = await this.client.meta.saveItem('view', viewName, merged);
1244
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1245
+ this.metadataCache.invalidate?.(`view:${objectName}:${viewName}`);
1246
+ if (result && result.item) return result.item;
1247
+ return merged;
1248
+ } catch (err) {
1249
+ throw err;
1250
+ }
1251
+ }
1252
+
1253
+ /**
1254
+ * Delete an overlay view (reset to artifact default if one exists, or
1255
+ * remove entirely if it was a user-created view). Routes to
1256
+ * `DELETE /api/v1/meta/view/:name`.
1257
+ */
1258
+ async deleteView(
1259
+ objectName: string,
1260
+ viewName: string,
1261
+ ): Promise<{ deleted: boolean }> {
1262
+ await this.connect();
1263
+ try {
1264
+ const result: any = await this.client.meta.deleteItem('view', viewName);
1265
+ this.metadataCache.invalidate?.(`views:${objectName}`);
1266
+ this.metadataCache.invalidate?.(`view:${objectName}:${viewName}`);
1267
+ return { deleted: !!(result?.deleted ?? result?.reset ?? true) };
1268
+ } catch (err) {
1269
+ throw err;
1270
+ }
1271
+ }
1272
+
1273
+
1139
1274
  /**
1140
1275
  * Get an application definition by name or ID.
1141
1276
  * Attempts to fetch from the server metadata API.