@object-ui/data-objectstack 4.0.10 → 4.0.11

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,12 @@
1
1
  # @object-ui/data-objectstack
2
2
 
3
+ ## 4.0.11
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@4.0.11
8
+ - @object-ui/core@4.0.11
9
+
3
10
  ## 4.0.10
4
11
 
5
12
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -962,6 +962,11 @@ var ObjectStackAdapter = class {
962
962
  // multiple sibling components requesting the same dataset on first paint)
963
963
  // into a single network round trip.
964
964
  __publicField(this, "inflightFinds", /* @__PURE__ */ new Map());
965
+ // Resources that have responded 404 at least once (collection not installed
966
+ // on this backend). Subsequent find() calls short-circuit to an empty result
967
+ // so optional collections like sys_presence don't hammer the server with
968
+ // failing requests on every record open / panel render.
969
+ __publicField(this, "missingResources", /* @__PURE__ */ new Set());
965
970
  this.client = new import_client.ObjectStackClient({ ...config, logger: createQuietHttpLogger() });
966
971
  this.metadataCache = new MetadataCache(config.cache);
967
972
  this.autoReconnect = config.autoReconnect ?? true;
@@ -1099,18 +1104,29 @@ var ObjectStackAdapter = class {
1099
1104
  * Converts OData-style params to ObjectStack query options.
1100
1105
  */
1101
1106
  async find(resource, params) {
1107
+ if (this.missingResources.has(resource)) {
1108
+ return { data: [], total: 0 };
1109
+ }
1102
1110
  const key = `${resource}::${stableStringify(params)}`;
1103
1111
  const existing = this.inflightFinds.get(key);
1104
1112
  if (existing) return existing;
1105
1113
  const promise = (async () => {
1106
1114
  await this.connect();
1107
1115
  if (params?.$expand && params.$expand.length > 0) {
1108
- const result2 = await this.rawFindWithPopulate(resource, params);
1109
- return this.normalizeQueryResult(result2, params);
1116
+ const result = await this.rawFindWithPopulate(resource, params);
1117
+ return this.normalizeQueryResult(result, params);
1110
1118
  }
1111
1119
  const queryOptions = this.convertQueryParams(params);
1112
- const result = await this.client.data.find(resource, queryOptions);
1113
- return this.normalizeQueryResult(result, params);
1120
+ try {
1121
+ const result = await this.client.data.find(resource, queryOptions);
1122
+ return this.normalizeQueryResult(result, params);
1123
+ } catch (err) {
1124
+ if (is404Error(err)) {
1125
+ this.missingResources.add(resource);
1126
+ return { data: [], total: 0 };
1127
+ }
1128
+ throw err;
1129
+ }
1114
1130
  })();
1115
1131
  this.inflightFinds.set(key, promise);
1116
1132
  const cleanup = () => {
@@ -1640,7 +1656,10 @@ var ObjectStackAdapter = class {
1640
1656
  await this.connect();
1641
1657
  let name = String(spec?.name || "").trim();
1642
1658
  if (!name) {
1643
- const base = String(spec?.label || objectName || "view").toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40) || "view";
1659
+ let base = String(spec?.label || objectName || "view").toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40);
1660
+ if (!base || /^[0-9]/.test(base)) {
1661
+ base = base ? `view_${base}` : "view";
1662
+ }
1644
1663
  const suffix = Date.now().toString(36);
1645
1664
  name = `${base}_${suffix}`;
1646
1665
  }
package/dist/index.d.cts CHANGED
@@ -734,6 +734,7 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
734
734
  private token?;
735
735
  private fetchImpl;
736
736
  private inflightFinds;
737
+ private missingResources;
737
738
  constructor(config: {
738
739
  baseUrl: string;
739
740
  token?: string;
package/dist/index.d.ts CHANGED
@@ -734,6 +734,7 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
734
734
  private token?;
735
735
  private fetchImpl;
736
736
  private inflightFinds;
737
+ private missingResources;
737
738
  constructor(config: {
738
739
  baseUrl: string;
739
740
  token?: string;
package/dist/index.js CHANGED
@@ -919,6 +919,11 @@ var ObjectStackAdapter = class {
919
919
  // multiple sibling components requesting the same dataset on first paint)
920
920
  // into a single network round trip.
921
921
  __publicField(this, "inflightFinds", /* @__PURE__ */ new Map());
922
+ // Resources that have responded 404 at least once (collection not installed
923
+ // on this backend). Subsequent find() calls short-circuit to an empty result
924
+ // so optional collections like sys_presence don't hammer the server with
925
+ // failing requests on every record open / panel render.
926
+ __publicField(this, "missingResources", /* @__PURE__ */ new Set());
922
927
  this.client = new ObjectStackClient({ ...config, logger: createQuietHttpLogger() });
923
928
  this.metadataCache = new MetadataCache(config.cache);
924
929
  this.autoReconnect = config.autoReconnect ?? true;
@@ -1056,18 +1061,29 @@ var ObjectStackAdapter = class {
1056
1061
  * Converts OData-style params to ObjectStack query options.
1057
1062
  */
1058
1063
  async find(resource, params) {
1064
+ if (this.missingResources.has(resource)) {
1065
+ return { data: [], total: 0 };
1066
+ }
1059
1067
  const key = `${resource}::${stableStringify(params)}`;
1060
1068
  const existing = this.inflightFinds.get(key);
1061
1069
  if (existing) return existing;
1062
1070
  const promise = (async () => {
1063
1071
  await this.connect();
1064
1072
  if (params?.$expand && params.$expand.length > 0) {
1065
- const result2 = await this.rawFindWithPopulate(resource, params);
1066
- return this.normalizeQueryResult(result2, params);
1073
+ const result = await this.rawFindWithPopulate(resource, params);
1074
+ return this.normalizeQueryResult(result, params);
1067
1075
  }
1068
1076
  const queryOptions = this.convertQueryParams(params);
1069
- const result = await this.client.data.find(resource, queryOptions);
1070
- return this.normalizeQueryResult(result, params);
1077
+ try {
1078
+ const result = await this.client.data.find(resource, queryOptions);
1079
+ return this.normalizeQueryResult(result, params);
1080
+ } catch (err) {
1081
+ if (is404Error(err)) {
1082
+ this.missingResources.add(resource);
1083
+ return { data: [], total: 0 };
1084
+ }
1085
+ throw err;
1086
+ }
1071
1087
  })();
1072
1088
  this.inflightFinds.set(key, promise);
1073
1089
  const cleanup = () => {
@@ -1597,7 +1613,10 @@ var ObjectStackAdapter = class {
1597
1613
  await this.connect();
1598
1614
  let name = String(spec?.name || "").trim();
1599
1615
  if (!name) {
1600
- const base = String(spec?.label || objectName || "view").toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40) || "view";
1616
+ let base = String(spec?.label || objectName || "view").toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40);
1617
+ if (!base || /^[0-9]/.test(base)) {
1618
+ base = base ? `view_${base}` : "view";
1619
+ }
1601
1620
  const suffix = Date.now().toString(36);
1602
1621
  name = `${base}_${suffix}`;
1603
1622
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/data-objectstack",
3
- "version": "4.0.10",
3
+ "version": "4.0.11",
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.10",
27
- "@object-ui/types": "4.0.10"
26
+ "@object-ui/core": "4.0.11",
27
+ "@object-ui/types": "4.0.11"
28
28
  },
29
29
  "devDependencies": {
30
30
  "tsup": "^8.5.1",
package/src/index.ts CHANGED
@@ -275,6 +275,11 @@ export class ObjectStackAdapter<T = unknown> implements DataSource<T> {
275
275
  // multiple sibling components requesting the same dataset on first paint)
276
276
  // into a single network round trip.
277
277
  private inflightFinds = new Map<string, Promise<QueryResult<T>>>();
278
+ // Resources that have responded 404 at least once (collection not installed
279
+ // on this backend). Subsequent find() calls short-circuit to an empty result
280
+ // so optional collections like sys_presence don't hammer the server with
281
+ // failing requests on every record open / panel render.
282
+ private missingResources = new Set<string>();
278
283
 
279
284
  constructor(config: {
280
285
  baseUrl: string;
@@ -470,6 +475,12 @@ export class ObjectStackAdapter<T = unknown> implements DataSource<T> {
470
475
  * Converts OData-style params to ObjectStack query options.
471
476
  */
472
477
  async find(resource: string, params?: QueryParams): Promise<QueryResult<T>> {
478
+ // Short-circuit when this resource has previously responded 404 — the
479
+ // collection isn't installed on this backend. Callers (AppHeader,
480
+ // RecordDetailView, …) treat empty data as "feature unavailable".
481
+ if (this.missingResources.has(resource)) {
482
+ return { data: [], total: 0 } as QueryResult<T>;
483
+ }
473
484
  const key = `${resource}::${stableStringify(params)}`;
474
485
  const existing = this.inflightFinds.get(key);
475
486
  if (existing) return existing;
@@ -489,8 +500,17 @@ export class ObjectStackAdapter<T = unknown> implements DataSource<T> {
489
500
  }
490
501
 
491
502
  const queryOptions = this.convertQueryParams(params);
492
- const result: unknown = await this.client.data.find<T>(resource, queryOptions);
493
- return this.normalizeQueryResult(result, params);
503
+ try {
504
+ const result: unknown = await this.client.data.find<T>(resource, queryOptions);
505
+ return this.normalizeQueryResult(result, params);
506
+ } catch (err) {
507
+ if (is404Error(err)) {
508
+ // Mark the resource so subsequent calls don't repeat the 404.
509
+ this.missingResources.add(resource);
510
+ return { data: [], total: 0 } as QueryResult<T>;
511
+ }
512
+ throw err;
513
+ }
494
514
  })();
495
515
 
496
516
  this.inflightFinds.set(key, promise);
@@ -1188,11 +1208,17 @@ export class ObjectStackAdapter<T = unknown> implements DataSource<T> {
1188
1208
  await this.connect();
1189
1209
  let name = String(spec?.name || '').trim();
1190
1210
  if (!name) {
1191
- const base = String(spec?.label || objectName || 'view')
1211
+ let base = String(spec?.label || objectName || 'view')
1192
1212
  .toLowerCase()
1193
1213
  .replace(/[^a-z0-9_]+/g, '_')
1194
1214
  .replace(/^_+|_+$/g, '')
1195
- .slice(0, 40) || 'view';
1215
+ .slice(0, 40);
1216
+ // Spec requires snake_case starting with a letter or underscore.
1217
+ // Labels like "表格 1" collapse to "1" after non-ascii stripping, so we
1218
+ // need a fallback / prefix to keep the identifier valid.
1219
+ if (!base || /^[0-9]/.test(base)) {
1220
+ base = base ? `view_${base}` : 'view';
1221
+ }
1196
1222
  const suffix = Date.now().toString(36);
1197
1223
  name = `${base}_${suffix}`;
1198
1224
  }