@object-ui/data-objectstack 3.1.5 → 3.3.1

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 ADDED
@@ -0,0 +1,118 @@
1
+ # @object-ui/data-objectstack
2
+
3
+ ## 3.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@3.3.1
8
+ - @object-ui/core@3.3.1
9
+
10
+ ## 3.3.0
11
+
12
+ ### Patch Changes
13
+
14
+ - @object-ui/types@3.3.0
15
+ - @object-ui/core@3.3.0
16
+
17
+ ## 3.2.0
18
+
19
+ ### Patch Changes
20
+
21
+ - @object-ui/types@3.2.0
22
+ - @object-ui/core@3.2.0
23
+
24
+ ## 3.1.5
25
+
26
+ ### Patch Changes
27
+
28
+ - @object-ui/types@3.1.5
29
+ - @object-ui/core@3.1.5
30
+
31
+ ## 3.1.4
32
+
33
+ ### Patch Changes
34
+
35
+ - @object-ui/types@3.1.4
36
+ - @object-ui/core@3.1.4
37
+
38
+ ## 3.1.3
39
+
40
+ ### Patch Changes
41
+
42
+ - @object-ui/types@3.1.3
43
+ - @object-ui/core@3.1.3
44
+
45
+ ## 3.1.2
46
+
47
+ ### Patch Changes
48
+
49
+ - @object-ui/types@3.1.2
50
+ - @object-ui/core@3.1.2
51
+
52
+ ## 3.1.1
53
+
54
+ ### Patch Changes
55
+
56
+ - Updated dependencies
57
+ - @object-ui/types@3.1.1
58
+ - @object-ui/core@3.1.1
59
+
60
+ ## 3.0.3
61
+
62
+ ### Patch Changes
63
+
64
+ - @object-ui/types@3.0.3
65
+ - @object-ui/core@3.0.3
66
+
67
+ ## 3.0.2
68
+
69
+ ### Patch Changes
70
+
71
+ - @object-ui/types@3.0.2
72
+ - @object-ui/core@3.0.2
73
+
74
+ ## 3.0.1
75
+
76
+ ### Patch Changes
77
+
78
+ - @object-ui/types@3.0.1
79
+ - @object-ui/core@3.0.1
80
+
81
+ ## 3.0.0
82
+
83
+ ### Minor Changes
84
+
85
+ - 87979c3: Upgrade to @objectstack v3.0.0 and console bundle optimization
86
+ - Upgraded all @objectstack/\* packages from ^2.0.7 to ^3.0.0
87
+ - Breaking change migrations: Hub → Cloud namespace, definePlugin removed, PaginatedResult.value → .records, PaginatedResult.count → .total, client.meta.getObject() → client.meta.getItem()
88
+ - Console bundle optimization: split monolithic 3.7 MB chunk into 17 granular cacheable chunks (95% main entry reduction)
89
+ - Added gzip + brotli pre-compression via vite-plugin-compression2
90
+ - Lazy MSW loading for build:server (~150 KB gzip saved)
91
+ - Added bundle analysis with rollup-plugin-visualizer
92
+
93
+ ### Patch Changes
94
+
95
+ - Updated dependencies [87979c3]
96
+ - @object-ui/types@3.0.0
97
+ - @object-ui/core@3.0.0
98
+
99
+ ## 2.0.0
100
+
101
+ ### Major Changes
102
+
103
+ - b859617: Release v1.0.0 — unify all package versions to 1.0.0
104
+
105
+ ### Patch Changes
106
+
107
+ - Updated dependencies [b859617]
108
+ - @object-ui/types@2.0.0
109
+ - @object-ui/core@2.0.0
110
+
111
+ ## 0.3.1
112
+
113
+ ### Patch Changes
114
+
115
+ - Maintenance release - Documentation and build improvements
116
+ - Updated dependencies
117
+ - @object-ui/types@0.3.1
118
+ - @object-ui/core@0.3.1
package/README.md CHANGED
@@ -356,6 +356,25 @@ dataSource.clearCache();
356
356
  dataSource.invalidateCache('users');
357
357
  ```
358
358
 
359
+ <!-- release-metadata:v3.3.0 -->
360
+
361
+ ## Compatibility
362
+
363
+ - **Node.js:** ≥ 18
364
+ - **TypeScript:** ≥ 5.0 (strict mode)
365
+ - **`@objectstack/spec`:** ^3.3.0
366
+ - **`@objectstack/client`:** ^3.3.0
367
+ - **Tailwind CSS:** ≥ 3.4 (for packages with UI)
368
+
369
+ ## Links
370
+
371
+ - 📚 [Documentation](https://www.objectui.org/docs/guide/data-source)
372
+ - 📦 [npm package](https://www.npmjs.com/package/@object-ui/data-objectstack)
373
+ - 📝 [Changelog](./CHANGELOG.md)
374
+ - 🐛 [Report an issue](https://github.com/objectstack-ai/objectui/issues)
375
+ - 🤝 [Contributing Guide](https://github.com/objectstack-ai/objectui/blob/main/CONTRIBUTING.md)
376
+ - 🗺️ [Roadmap](https://github.com/objectstack-ai/objectui/blob/main/ROADMAP.md)
377
+
359
378
  ## License
360
379
 
361
- MIT
380
+ MIT — see [LICENSE](./LICENSE).
package/dist/index.cjs CHANGED
@@ -33,10 +33,12 @@ __export(index_exports, {
33
33
  SecurityManager: () => SecurityManager,
34
34
  ValidationError: () => ValidationError,
35
35
  calculateAutoLayout: () => calculateAutoLayout,
36
+ clearSharedDiscoveryCache: () => clearSharedDiscoveryCache,
36
37
  createDefaultCanvasConfig: () => createDefaultCanvasConfig,
37
38
  createErrorFromResponse: () => createErrorFromResponse,
38
39
  createObjectStackAdapter: () => createObjectStackAdapter,
39
40
  generateContractManifest: () => generateContractManifest,
41
+ getSharedDiscovery: () => getSharedDiscovery,
40
42
  isErrorType: () => isErrorType,
41
43
  isObjectStackError: () => isObjectStackError,
42
44
  snapToGrid: () => snapToGrid,
@@ -44,7 +46,72 @@ __export(index_exports, {
44
46
  });
45
47
  module.exports = __toCommonJS(index_exports);
46
48
  var import_client = require("@objectstack/client");
47
- var import_core = require("@object-ui/core");
49
+
50
+ // ../core/src/utils/filter-converter.ts
51
+ function convertOperatorToAST(operator) {
52
+ const operatorMap = {
53
+ "$eq": "=",
54
+ "$ne": "!=",
55
+ "$gt": ">",
56
+ "$gte": ">=",
57
+ "$lt": "<",
58
+ "$lte": "<=",
59
+ "$in": "in",
60
+ "$nin": "nin",
61
+ "$notin": "nin",
62
+ "$between": "between",
63
+ "$contains": "contains",
64
+ "$notContains": "notcontains",
65
+ "$notcontains": "notcontains",
66
+ "$startsWith": "startswith",
67
+ "$startswith": "startswith",
68
+ "$endsWith": "endswith",
69
+ "$endswith": "endswith"
70
+ };
71
+ return operatorMap[operator] || null;
72
+ }
73
+ function convertFiltersToAST(filter) {
74
+ const conditions = [];
75
+ for (const [field, value] of Object.entries(filter)) {
76
+ if (value === null || value === void 0) continue;
77
+ if (typeof value === "object" && !Array.isArray(value)) {
78
+ for (const [operator, operatorValue] of Object.entries(value)) {
79
+ if (operator === "$regex") {
80
+ console.warn(
81
+ `[ObjectUI] Warning: $regex operator is not fully supported. Converting to 'contains' which only supports substring matching, not regex patterns. Field: '${field}', Value: ${JSON.stringify(operatorValue)}. Consider using $contains or $startsWith instead.`
82
+ );
83
+ conditions.push([field, "contains", operatorValue]);
84
+ continue;
85
+ }
86
+ if (operator === "$null") {
87
+ conditions.push([field, operatorValue ? "is_null" : "is_not_null", true]);
88
+ continue;
89
+ }
90
+ if (operator === "$exists") {
91
+ conditions.push([field, operatorValue ? "is_not_null" : "is_null", true]);
92
+ continue;
93
+ }
94
+ const astOperator = convertOperatorToAST(operator);
95
+ if (astOperator) {
96
+ conditions.push([field, astOperator, operatorValue]);
97
+ } else {
98
+ throw new Error(
99
+ `[ObjectUI] Unknown filter operator '${operator}' for field '${field}'. Supported operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $between, $contains, $notContains, $startsWith, $endsWith, $null, $exists. If you need exact object matching, use the value directly without an operator.`
100
+ );
101
+ }
102
+ }
103
+ } else {
104
+ conditions.push([field, "=", value]);
105
+ }
106
+ }
107
+ if (conditions.length === 0) {
108
+ return filter;
109
+ }
110
+ if (conditions.length === 1) {
111
+ return conditions[0];
112
+ }
113
+ return ["and", ...conditions];
114
+ }
48
115
 
49
116
  // src/cache/MetadataCache.ts
50
117
  var MetadataCache = class {
@@ -57,16 +124,19 @@ var MetadataCache = class {
57
124
  */
58
125
  constructor(options = {}) {
59
126
  __publicField(this, "cache");
127
+ __publicField(this, "inflight");
60
128
  __publicField(this, "maxSize");
61
129
  __publicField(this, "ttl");
62
130
  __publicField(this, "stats");
63
131
  this.cache = /* @__PURE__ */ new Map();
132
+ this.inflight = /* @__PURE__ */ new Map();
64
133
  this.maxSize = options.maxSize || 100;
65
134
  this.ttl = options.ttl || 5 * 60 * 1e3;
66
135
  this.stats = {
67
136
  hits: 0,
68
137
  misses: 0,
69
- evictions: 0
138
+ evictions: 0,
139
+ coalesced: 0
70
140
  };
71
141
  }
72
142
  /**
@@ -92,10 +162,31 @@ var MetadataCache = class {
92
162
  this.cache.delete(key);
93
163
  }
94
164
  }
165
+ const existing = this.inflight.get(key);
166
+ if (existing) {
167
+ this.stats.coalesced++;
168
+ return existing;
169
+ }
95
170
  this.stats.misses++;
96
- const data = await fetcher();
171
+ const promise = (async () => {
172
+ try {
173
+ const data = await fetcher();
174
+ this.set(key, data);
175
+ return data;
176
+ } finally {
177
+ this.inflight.delete(key);
178
+ }
179
+ })();
180
+ this.inflight.set(key, promise);
181
+ return promise;
182
+ }
183
+ /**
184
+ * Prime the cache with a pre-fetched value. Useful when a bulk endpoint
185
+ * (e.g. list of all object schemas) returns data that would otherwise
186
+ * be fetched again per item.
187
+ */
188
+ prime(key, data) {
97
189
  this.set(key, data);
98
- return data;
99
190
  }
100
191
  /**
101
192
  * Set a value in the cache
@@ -142,10 +233,12 @@ var MetadataCache = class {
142
233
  */
143
234
  clear() {
144
235
  this.cache.clear();
236
+ this.inflight.clear();
145
237
  this.stats = {
146
238
  hits: 0,
147
239
  misses: 0,
148
- evictions: 0
240
+ evictions: 0,
241
+ coalesced: 0
149
242
  };
150
243
  }
151
244
  /**
@@ -162,6 +255,7 @@ var MetadataCache = class {
162
255
  hits: this.stats.hits,
163
256
  misses: this.stats.misses,
164
257
  evictions: this.stats.evictions,
258
+ coalesced: this.stats.coalesced,
165
259
  hitRate
166
260
  };
167
261
  }
@@ -213,9 +307,9 @@ var ObjectStackError = class extends Error {
213
307
  */
214
308
  constructor(message, code, statusCode, details) {
215
309
  super(message);
216
- this.code = code;
217
- this.statusCode = statusCode;
218
- this.details = details;
310
+ __publicField(this, "code", code);
311
+ __publicField(this, "statusCode", statusCode);
312
+ __publicField(this, "details", details);
219
313
  this.name = "ObjectStackError";
220
314
  if (Error.captureStackTrace) {
221
315
  Error.captureStackTrace(this, this.constructor);
@@ -269,9 +363,9 @@ var BulkOperationError = class extends ObjectStackError {
269
363
  ...details
270
364
  }
271
365
  );
272
- this.successCount = successCount;
273
- this.failureCount = failureCount;
274
- this.errors = errors;
366
+ __publicField(this, "successCount", successCount);
367
+ __publicField(this, "failureCount", failureCount);
368
+ __publicField(this, "errors", errors);
275
369
  this.name = "BulkOperationError";
276
370
  }
277
371
  /**
@@ -298,7 +392,7 @@ var ConnectionError = class extends ObjectStackError {
298
392
  statusCode || 503,
299
393
  { url, ...details }
300
394
  );
301
- this.url = url;
395
+ __publicField(this, "url", url);
302
396
  this.name = "ConnectionError";
303
397
  }
304
398
  };
@@ -333,8 +427,8 @@ var ValidationError = class extends ObjectStackError {
333
427
  ...details
334
428
  }
335
429
  );
336
- this.field = field;
337
- this.validationErrors = validationErrors;
430
+ __publicField(this, "field", field);
431
+ __publicField(this, "validationErrors", validationErrors);
338
432
  this.name = "ValidationError";
339
433
  }
340
434
  /**
@@ -391,7 +485,7 @@ function isErrorType(error, errorClass) {
391
485
  // src/cloud.ts
392
486
  var CloudOperations = class {
393
487
  constructor(getClient) {
394
- this.getClient = getClient;
488
+ __publicField(this, "getClient", getClient);
395
489
  }
396
490
  /**
397
491
  * Deploy an application to the cloud.
@@ -735,10 +829,26 @@ function calculateAutoLayout(items, canvasWidth, padding = 40, gap = 40) {
735
829
  }
736
830
 
737
831
  // src/index.ts
832
+ var discoveryCache = /* @__PURE__ */ new Map();
833
+ async function getSharedDiscovery(baseUrl, fetcher) {
834
+ const key = baseUrl || "<default>";
835
+ const cached = discoveryCache.get(key);
836
+ if (cached) return cached;
837
+ const p = fetcher().catch((err) => {
838
+ discoveryCache.delete(key);
839
+ throw err;
840
+ });
841
+ discoveryCache.set(key, p);
842
+ return p;
843
+ }
844
+ function clearSharedDiscoveryCache() {
845
+ discoveryCache.clear();
846
+ }
738
847
  var ObjectStackAdapter = class {
739
848
  constructor(config) {
740
849
  __publicField(this, "client");
741
850
  __publicField(this, "connected", false);
851
+ __publicField(this, "connectPromise", null);
742
852
  __publicField(this, "metadataCache");
743
853
  __publicField(this, "connectionState", "disconnected");
744
854
  __publicField(this, "connectionStateListeners", []);
@@ -764,10 +874,25 @@ var ObjectStackAdapter = class {
764
874
  * Call this before making requests or it will auto-connect on first request.
765
875
  */
766
876
  async connect() {
767
- if (!this.connected) {
768
- this.setConnectionState("connecting");
877
+ if (this.connected) return;
878
+ if (this.connectPromise) return this.connectPromise;
879
+ this.setConnectionState("connecting");
880
+ this.connectPromise = (async () => {
769
881
  try {
770
- await this.client.connect();
882
+ const baseUrl = this.baseUrl || "";
883
+ const discoveryUrl = baseUrl ? `${baseUrl.replace(/\/$/, "")}/api/v1/discovery` : "/api/v1/discovery";
884
+ const data = await getSharedDiscovery(baseUrl, async () => {
885
+ const res = await this.fetchImpl(discoveryUrl, {
886
+ method: "GET",
887
+ headers: this.token ? { Authorization: `Bearer ${this.token}` } : void 0
888
+ });
889
+ if (!res.ok) {
890
+ throw new Error(`discovery ${res.status} ${res.statusText}`);
891
+ }
892
+ const body = await res.json();
893
+ return body && typeof body.success === "boolean" && "data" in body ? body.data : body;
894
+ });
895
+ this.client.discoveryInfo = data;
771
896
  this.connected = true;
772
897
  this.reconnectAttempts = 0;
773
898
  this.setConnectionState("connected");
@@ -784,8 +909,11 @@ var ObjectStackAdapter = class {
784
909
  } else {
785
910
  throw connectionError;
786
911
  }
912
+ } finally {
913
+ this.connectPromise = null;
787
914
  }
788
- }
915
+ })();
916
+ return this.connectPromise;
789
917
  }
790
918
  /**
791
919
  * Attempt to reconnect to the server with exponential backoff
@@ -1126,8 +1254,11 @@ var ObjectStackAdapter = class {
1126
1254
  queryParams.set("sort", sortStr);
1127
1255
  }
1128
1256
  }
1129
- if (params.$filter) {
1130
- queryParams.set("filter", JSON.stringify(params.$filter));
1257
+ if (params.$filter !== void 0 && params.$filter !== null) {
1258
+ const isEmpty = Array.isArray(params.$filter) ? params.$filter.length === 0 : typeof params.$filter === "object" && Object.keys(params.$filter).length === 0;
1259
+ if (!isEmpty) {
1260
+ queryParams.set("filter", JSON.stringify(params.$filter));
1261
+ }
1131
1262
  }
1132
1263
  const baseUrl = this.baseUrl.replace(/\/$/, "");
1133
1264
  const qs = queryParams.toString();
@@ -1163,11 +1294,14 @@ var ObjectStackAdapter = class {
1163
1294
  if (params.$select) {
1164
1295
  options.select = params.$select;
1165
1296
  }
1166
- if (params.$filter) {
1167
- if (Array.isArray(params.$filter)) {
1168
- options.filters = params.$filter;
1169
- } else {
1170
- options.filters = (0, import_core.convertFiltersToAST)(params.$filter);
1297
+ if (params.$filter !== void 0 && params.$filter !== null) {
1298
+ const isEmpty = Array.isArray(params.$filter) ? params.$filter.length === 0 : typeof params.$filter === "object" && Object.keys(params.$filter).length === 0;
1299
+ if (!isEmpty) {
1300
+ if (Array.isArray(params.$filter)) {
1301
+ options.filters = params.$filter;
1302
+ } else {
1303
+ options.filters = convertFiltersToAST(params.$filter);
1304
+ }
1171
1305
  }
1172
1306
  }
1173
1307
  if (params.$orderby) {
@@ -1318,19 +1452,26 @@ var ObjectStackAdapter = class {
1318
1452
  async aggregate(resource, params) {
1319
1453
  await this.connect();
1320
1454
  try {
1455
+ const measureName = params.function === "count" ? "count" : `${params.field}_${params.function}`;
1321
1456
  const payload = {
1322
- object: resource,
1323
- measures: [{ field: params.field, function: params.function }],
1324
- dimensions: [params.groupBy]
1457
+ cube: resource,
1458
+ measures: [measureName],
1459
+ // When groupBy is '_all' no dimensions are needed (single-bucket).
1460
+ dimensions: params.groupBy && params.groupBy !== "_all" ? [params.groupBy] : []
1325
1461
  };
1326
1462
  if (params.filter) {
1327
1463
  payload.filters = params.filter;
1328
1464
  }
1329
1465
  const data = await this.client.analytics.query(payload);
1330
- if (Array.isArray(data)) return data;
1331
- if (data?.data && Array.isArray(data.data)) return data.data;
1332
- if (data?.results && Array.isArray(data.results)) return data.results;
1333
- return [];
1466
+ const rawRows = Array.isArray(data) ? data : data?.rows && Array.isArray(data.rows) ? data.rows : data?.data && Array.isArray(data.data) ? data.data : data?.data?.rows && Array.isArray(data.data.rows) ? data.data.rows : data?.results && Array.isArray(data.results) ? data.results : [];
1467
+ return rawRows.map((row) => {
1468
+ const mapped = { ...row };
1469
+ if (measureName !== params.field && measureName in mapped) {
1470
+ mapped[params.field] = mapped[measureName];
1471
+ delete mapped[measureName];
1472
+ }
1473
+ return mapped;
1474
+ });
1334
1475
  } catch {
1335
1476
  const result = await this.find(resource);
1336
1477
  const records = result.data || [];
@@ -1525,10 +1666,12 @@ function createObjectStackAdapter(config) {
1525
1666
  SecurityManager,
1526
1667
  ValidationError,
1527
1668
  calculateAutoLayout,
1669
+ clearSharedDiscoveryCache,
1528
1670
  createDefaultCanvasConfig,
1529
1671
  createErrorFromResponse,
1530
1672
  createObjectStackAdapter,
1531
1673
  generateContractManifest,
1674
+ getSharedDiscovery,
1532
1675
  isErrorType,
1533
1676
  isObjectStackError,
1534
1677
  snapToGrid,
package/dist/index.d.cts CHANGED
@@ -156,6 +156,8 @@ interface CacheStats {
156
156
  hits: number;
157
157
  misses: number;
158
158
  evictions: number;
159
+ /** Number of concurrent fetches that were coalesced onto an in-flight request. */
160
+ coalesced: number;
159
161
  hitRate: number;
160
162
  }
161
163
 
@@ -638,6 +640,14 @@ declare function calculateAutoLayout(items: Array<{
638
640
  y: number;
639
641
  }>;
640
642
 
643
+ /**
644
+ * Fetch the server `discovery` document once per (baseUrl) and reuse the
645
+ * resulting Promise. Used by `ObjectStackAdapter.connect()` (and any caller
646
+ * that wants the discovery payload without spinning up a new client).
647
+ */
648
+ declare function getSharedDiscovery(baseUrl: string, fetcher: () => Promise<unknown>): Promise<unknown>;
649
+ /** Test/dev helper to drop the cache (e.g. on logout or origin change). */
650
+ declare function clearSharedDiscoveryCache(): void;
641
651
  /**
642
652
  * Connection state for monitoring
643
653
  */
@@ -701,6 +711,7 @@ type BatchProgressListener = (event: BatchProgressEvent) => void;
701
711
  declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
702
712
  private client;
703
713
  private connected;
714
+ private connectPromise;
704
715
  private metadataCache;
705
716
  private connectionState;
706
717
  private connectionStateListeners;
@@ -954,4 +965,4 @@ declare function createObjectStackAdapter<T = unknown>(config: {
954
965
  reconnectDelay?: number;
955
966
  }): DataSource<T>;
956
967
 
957
- export { type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, 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 PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, ValidationError, type WebhookIntegrationConfig, calculateAutoLayout, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, generateContractManifest, isErrorType, isObjectStackError, snapToGrid, validatePluginContract };
968
+ export { type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, 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 PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, ValidationError, type WebhookIntegrationConfig, calculateAutoLayout, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, generateContractManifest, getSharedDiscovery, isErrorType, isObjectStackError, snapToGrid, validatePluginContract };
package/dist/index.d.ts CHANGED
@@ -156,6 +156,8 @@ interface CacheStats {
156
156
  hits: number;
157
157
  misses: number;
158
158
  evictions: number;
159
+ /** Number of concurrent fetches that were coalesced onto an in-flight request. */
160
+ coalesced: number;
159
161
  hitRate: number;
160
162
  }
161
163
 
@@ -638,6 +640,14 @@ declare function calculateAutoLayout(items: Array<{
638
640
  y: number;
639
641
  }>;
640
642
 
643
+ /**
644
+ * Fetch the server `discovery` document once per (baseUrl) and reuse the
645
+ * resulting Promise. Used by `ObjectStackAdapter.connect()` (and any caller
646
+ * that wants the discovery payload without spinning up a new client).
647
+ */
648
+ declare function getSharedDiscovery(baseUrl: string, fetcher: () => Promise<unknown>): Promise<unknown>;
649
+ /** Test/dev helper to drop the cache (e.g. on logout or origin change). */
650
+ declare function clearSharedDiscoveryCache(): void;
641
651
  /**
642
652
  * Connection state for monitoring
643
653
  */
@@ -701,6 +711,7 @@ type BatchProgressListener = (event: BatchProgressEvent) => void;
701
711
  declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
702
712
  private client;
703
713
  private connected;
714
+ private connectPromise;
704
715
  private metadataCache;
705
716
  private connectionState;
706
717
  private connectionStateListeners;
@@ -954,4 +965,4 @@ declare function createObjectStackAdapter<T = unknown>(config: {
954
965
  reconnectDelay?: number;
955
966
  }): DataSource<T>;
956
967
 
957
- export { type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, 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 PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, ValidationError, type WebhookIntegrationConfig, calculateAutoLayout, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, generateContractManifest, isErrorType, isObjectStackError, snapToGrid, validatePluginContract };
968
+ export { type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, 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 PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, ValidationError, type WebhookIntegrationConfig, calculateAutoLayout, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, generateContractManifest, getSharedDiscovery, isErrorType, isObjectStackError, snapToGrid, validatePluginContract };