@object-ui/data-objectstack 16.0.0 → 17.1.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 +711 -0
- package/README.md +63 -0
- package/dist/index.cjs +1425 -949
- package/dist/index.d.cts +319 -19
- package/dist/index.d.ts +319 -19
- package/dist/index.js +1420 -949
- package/package.json +5 -4
- package/src/aggregate-capability.test.ts +177 -0
- package/src/exportDownload.test.ts +51 -3
- package/src/filter-entry-translation.test.ts +360 -0
- package/src/filter-operator-ast-parity.test.ts +71 -0
- package/src/index.ts +984 -220
- package/src/integration.ts +8 -0
- package/src/listViews.test.ts +97 -0
- package/src/metadata-client.test.ts +8 -0
- package/src/metadata-client.ts +9 -0
- package/src/onMutation.test.ts +296 -31
- package/src/onWriteWarning.test.ts +172 -0
- package/src/orderby-serialization.test.ts +115 -0
- package/src/queryDataset.test.ts +50 -1
- package/src/searchAll.test.ts +120 -0
- package/src/userState.test.ts +25 -4
- package/src/userState.ts +10 -6
- package/src/validation-error.test.ts +94 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ObjectStackClient } from '@objectstack/client';
|
|
2
|
-
import { DataSource, QueryParams, QueryResult,
|
|
2
|
+
import { DataSource, QueryParams, QueryResult, GlobalSearchResult, DataSourceMutationEvent, BatchTransactionOperation, ImportRequestOptions, ImportRecordsResult, CreateImportJobResult, ImportJobProgressInfo, ImportJobResultsInfo, ListImportJobsOptions, ImportJobSummaryInfo, ImportJobUndoResult, ExportDownloadRequest, FileUploadResult } from '@object-ui/types';
|
|
3
3
|
export { FileUploadResult } from '@object-ui/types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1174,6 +1174,64 @@ declare function calculateAutoLayout(items: Array<{
|
|
|
1174
1174
|
y: number;
|
|
1175
1175
|
}>;
|
|
1176
1176
|
|
|
1177
|
+
/**
|
|
1178
|
+
* Map human-readable filter operator names produced by SDUI view configs
|
|
1179
|
+
* (e.g. `lead.view.ts`) to the canonical operator symbols expected by the
|
|
1180
|
+
* ObjectStack server's filter AST. Unknown operators fall through unchanged
|
|
1181
|
+
* so existing AST-style entries keep working.
|
|
1182
|
+
*
|
|
1183
|
+
* Every VALUE here must be a member of the spec's `VALID_AST_OPERATORS`
|
|
1184
|
+
* (`@objectstack/spec/data`) — that set gates `isFilterAST()`, and a filter it
|
|
1185
|
+
* rejects is not converted, not validated, and then silently DROPPED by
|
|
1186
|
+
* driver-sql (objectstack#3948). Pinned by `filter-operator-ast-parity.test.ts`.
|
|
1187
|
+
*
|
|
1188
|
+
* Exported for that test. @internal
|
|
1189
|
+
*/
|
|
1190
|
+
declare const FILTER_OPERATOR_ALIASES: Record<string, string>;
|
|
1191
|
+
/**
|
|
1192
|
+
* A filter entry this adapter cannot translate into an AST tuple.
|
|
1193
|
+
*
|
|
1194
|
+
* Thrown rather than skipped. Dropping one entry out of an `and` WIDENS the
|
|
1195
|
+
* result set, and dropping the last one emits no `filter=` at all — every row,
|
|
1196
|
+
* no error, from a query that asked for a subset. That is the same silent
|
|
1197
|
+
* over-fetch the server-side drivers stopped doing in objectstack#3948, and
|
|
1198
|
+
* skipping it here just moves it one layer up.
|
|
1199
|
+
*
|
|
1200
|
+
* Carries the code and status the data API uses for its own version of this
|
|
1201
|
+
* refusal (objectstack#4121) so a failed list renders "this view's filter is
|
|
1202
|
+
* malformed" rather than "check your connection" (#3066).
|
|
1203
|
+
*/
|
|
1204
|
+
declare class MalformedFilterError extends Error {
|
|
1205
|
+
readonly code = "INVALID_FILTER";
|
|
1206
|
+
readonly httpStatus = 400;
|
|
1207
|
+
readonly entry: unknown;
|
|
1208
|
+
readonly index: number;
|
|
1209
|
+
constructor(entry: unknown, index: number);
|
|
1210
|
+
}
|
|
1211
|
+
/** Detect the malformed-filter refusal, whether raised here or by the server. */
|
|
1212
|
+
declare function isMalformedFilterError(error: unknown): boolean;
|
|
1213
|
+
/**
|
|
1214
|
+
* Serialize a `$orderby` to the server's `sort` shorthand
|
|
1215
|
+
* (`field,-other_field`), for every shape `QueryParams['$orderby']` declares.
|
|
1216
|
+
*
|
|
1217
|
+
* The type declares four — `string`, `string[]`, `SortNode[]`,
|
|
1218
|
+
* `Record<field, direction>` — and the two `find()` routes each open-coded a
|
|
1219
|
+
* fold that handled three of them. The missing one was the bare string, and it
|
|
1220
|
+
* did not degrade quietly: `Object.entries('name asc')` enumerates a string's
|
|
1221
|
+
* character indices, so the request went out as `sort=0,1,2,3,4,5,6,7`. Against
|
|
1222
|
+
* a server that rejects an unreadable sort rather than ignoring it
|
|
1223
|
+
* (objectstack#4226), that is a `400 INVALID_SORT` and an empty list — so a
|
|
1224
|
+
* standalone `ObjectGrid` with a `sort` in its metadata, which is exactly the
|
|
1225
|
+
* shape it builds (`ObjectGrid.tsx`: `` `${field} ${order}` ``), failed to load
|
|
1226
|
+
* at all.
|
|
1227
|
+
*
|
|
1228
|
+
* One serializer for both routes, for the reason the filter path already has
|
|
1229
|
+
* one: two copies of a fold can only agree by inspection, and these two did not.
|
|
1230
|
+
*
|
|
1231
|
+
* Returns `undefined` when nothing is sortable, so callers skip the parameter
|
|
1232
|
+
* entirely rather than sending an empty one.
|
|
1233
|
+
*/
|
|
1234
|
+
declare function serializeOrderBy(orderby: QueryParams['$orderby']): string | undefined;
|
|
1177
1235
|
/**
|
|
1178
1236
|
* Fetch the server `discovery` document once per (baseUrl) and reuse the
|
|
1179
1237
|
* resulting Promise. Used by `ObjectStackAdapter.connect()` (and any caller
|
|
@@ -1182,6 +1240,26 @@ declare function calculateAutoLayout(items: Array<{
|
|
|
1182
1240
|
declare function getSharedDiscovery(baseUrl: string, fetcher: () => Promise<unknown>): Promise<unknown>;
|
|
1183
1241
|
/** Test/dev helper to drop the cache (e.g. on logout or origin change). */
|
|
1184
1242
|
declare function clearSharedDiscoveryCache(): void;
|
|
1243
|
+
/**
|
|
1244
|
+
* Read the cross-object atomic-batch capability from a `discovery` document
|
|
1245
|
+
* (framework #3298 / objectui #2693). The server advertises it hierarchically
|
|
1246
|
+
* under `capabilities.transactionalBatch.enabled`; the published
|
|
1247
|
+
* `@objectstack/client` also accepts the flat `capabilities.transactionalBatch:
|
|
1248
|
+
* boolean` form and normalizes the two — mirror that here so the adapter reads
|
|
1249
|
+
* the same bit regardless of which shape reaches it.
|
|
1250
|
+
*
|
|
1251
|
+
* Returns:
|
|
1252
|
+
* - `true` — the backend GUARANTEES an atomic `/batch` (declared === enforced,
|
|
1253
|
+
* i.e. the route is mounted AND the runtime can honour a transaction): the
|
|
1254
|
+
* client may drop its non-atomic fallback and treat any batch failure as a
|
|
1255
|
+
* real error.
|
|
1256
|
+
* - `false` — the backend explicitly does NOT (route absent, or a runtime that
|
|
1257
|
+
* can't open a transaction).
|
|
1258
|
+
* - `undefined` — the capability is absent, i.e. the backend predates #3298;
|
|
1259
|
+
* the caller must keep the legacy runtime-probe fallback (we can't tell
|
|
1260
|
+
* whether `/batch` exists without trying it).
|
|
1261
|
+
*/
|
|
1262
|
+
declare function readTransactionalBatchCapability(discovery: unknown): boolean | undefined;
|
|
1185
1263
|
/**
|
|
1186
1264
|
* Detect "missing resource" errors regardless of where they originate.
|
|
1187
1265
|
*
|
|
@@ -1192,6 +1270,73 @@ declare function clearSharedDiscoveryCache(): void;
|
|
|
1192
1270
|
* tripping on the property-name mismatch.
|
|
1193
1271
|
*/
|
|
1194
1272
|
declare function is404Error(error: unknown): boolean;
|
|
1273
|
+
/**
|
|
1274
|
+
* Thrown when the deployment has no analytics capability installed
|
|
1275
|
+
* (framework#3891 / #4019).
|
|
1276
|
+
*
|
|
1277
|
+
* The framework retired its degraded in-kernel analytics fallback — it dropped
|
|
1278
|
+
* the caller's RLS/tenant scope and ignored the contract filter, so it answered
|
|
1279
|
+
* 200 with over-broad numbers. `@objectstack/service-analytics` is now the
|
|
1280
|
+
* domain's only implementation, and a deployment without it answers:
|
|
1281
|
+
*
|
|
1282
|
+
* - `POST /api/v1/analytics/query` → **404** (the routes aren't even mounted);
|
|
1283
|
+
* - `POST /api/v1/analytics/dataset/query` → **501 NOT_IMPLEMENTED**.
|
|
1284
|
+
*
|
|
1285
|
+
* Neither is a bug to report as a stack trace: it is a deployment that hasn't
|
|
1286
|
+
* installed the capability. This error carries a message a UI can show as-is.
|
|
1287
|
+
*/
|
|
1288
|
+
declare class AnalyticsNotInstalledError extends Error {
|
|
1289
|
+
readonly code = "ANALYTICS_NOT_INSTALLED";
|
|
1290
|
+
/** The surface that was unavailable, for the message a host renders. */
|
|
1291
|
+
readonly surface: string;
|
|
1292
|
+
constructor(surface: string, detail?: string);
|
|
1293
|
+
}
|
|
1294
|
+
/** True when `error` is an {@link AnalyticsNotInstalledError} (or its wire twin). */
|
|
1295
|
+
declare function isAnalyticsNotInstalledError(error: unknown): boolean;
|
|
1296
|
+
/**
|
|
1297
|
+
* Thrown when the server REJECTED the analytics query body (HTTP 400 —
|
|
1298
|
+
* `VALIDATION_FAILED` since framework#4010 validates `/analytics/query` at the
|
|
1299
|
+
* entry against the canonical bare `AnalyticsQuery` shape).
|
|
1300
|
+
*
|
|
1301
|
+
* Distinct from {@link AnalyticsNotInstalledError} on purpose: this one is a
|
|
1302
|
+
* defect in what WE sent, so it must never be answered with the client-side
|
|
1303
|
+
* fallback. Numbers produced by a different code path would look plausible and
|
|
1304
|
+
* bury the contract violation — the misdirection framework#3878 documented.
|
|
1305
|
+
*/
|
|
1306
|
+
declare class AnalyticsQueryRejectedError extends Error {
|
|
1307
|
+
readonly code = "ANALYTICS_QUERY_REJECTED";
|
|
1308
|
+
/** The server's own error code (e.g. `VALIDATION_FAILED`), when it sent one. */
|
|
1309
|
+
readonly serverCode?: string;
|
|
1310
|
+
constructor(detail?: string, serverCode?: string);
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Classify a FAILED analytics call so the caller knows whether to degrade or
|
|
1314
|
+
* to surface the failure.
|
|
1315
|
+
*
|
|
1316
|
+
* `@objectstack/client`'s fetch wrapper throws on a non-2xx, decorating the
|
|
1317
|
+
* error with the semantic `code` string and the numeric `httpStatus` (the
|
|
1318
|
+
* ADR-0112 / framework#3842 shape this repo already reads elsewhere). Two
|
|
1319
|
+
* outcomes must NOT be conflated:
|
|
1320
|
+
*
|
|
1321
|
+
* - **`not-installed`** — the deployment has no analytics service. Since
|
|
1322
|
+
* framework#3891 retired the degraded in-kernel shim, that is a 404 (the
|
|
1323
|
+
* routes aren't mounted at all, framework#4019) or a 501 `NOT_IMPLEMENTED`
|
|
1324
|
+
* (REST's dataset route with no service behind it). Degrading to a
|
|
1325
|
+
* client-side aggregate over a scoped `find()` is CORRECT here.
|
|
1326
|
+
* - **`rejected`** — the server refused OUR body (400 `VALIDATION_FAILED`;
|
|
1327
|
+
* framework#4010 validates `/analytics/query` at the entry). Degrading
|
|
1328
|
+
* would answer our own contract violation with plausible numbers from a
|
|
1329
|
+
* different code path and bury it — the misdirection framework#3878
|
|
1330
|
+
* documented. It must be surfaced.
|
|
1331
|
+
*
|
|
1332
|
+
* Anything else (5xx, network) is `unknown`: degrade, but silently — it is a
|
|
1333
|
+
* transient failure, not a deployment that is missing a capability.
|
|
1334
|
+
*/
|
|
1335
|
+
declare function classifyAnalyticsFailure(error: unknown): {
|
|
1336
|
+
kind: 'not-installed' | 'rejected' | 'unknown';
|
|
1337
|
+
code?: string;
|
|
1338
|
+
message?: string;
|
|
1339
|
+
};
|
|
1195
1340
|
/**
|
|
1196
1341
|
* Thrown by `update()` / `delete()` when the server returns
|
|
1197
1342
|
* `409 CONCURRENT_UPDATE` — i.e. the record was modified by someone else
|
|
@@ -1228,10 +1373,15 @@ declare class ConcurrentUpdateError extends Error {
|
|
|
1228
1373
|
*/
|
|
1229
1374
|
declare function isConcurrentUpdateError(error: unknown): error is ConcurrentUpdateError;
|
|
1230
1375
|
/**
|
|
1231
|
-
* Convert any error thrown by the upstream client into a typed
|
|
1232
|
-
*
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1376
|
+
* Convert any error thrown by the upstream client into a typed error when we
|
|
1377
|
+
* recognise its shape. Returns the original error untouched otherwise, so
|
|
1378
|
+
* callers can simply `throw normaliseClientError(err)` from their catch blocks.
|
|
1379
|
+
*
|
|
1380
|
+
* Two shapes are recognised:
|
|
1381
|
+
* - `409` + `CONCURRENT_UPDATE` → {@link ConcurrentUpdateError};
|
|
1382
|
+
* - `400` + `VALIDATION_FAILED` → {@link ValidationError}, carrying the
|
|
1383
|
+
* server's per-field entries so a form can mark the offending inputs
|
|
1384
|
+
* instead of showing one undirected toast.
|
|
1235
1385
|
*/
|
|
1236
1386
|
declare function normaliseClientError(error: unknown): unknown;
|
|
1237
1387
|
/**
|
|
@@ -1264,6 +1414,33 @@ type ConnectionStateListener = (event: ConnectionStateEvent) => void;
|
|
|
1264
1414
|
* Event listener type for batch operation progress
|
|
1265
1415
|
*/
|
|
1266
1416
|
type BatchProgressListener = (event: BatchProgressEvent) => void;
|
|
1417
|
+
/**
|
|
1418
|
+
* One server-reported write-strip: caller-supplied fields the backend LEGALLY
|
|
1419
|
+
* removed from a write before persisting (a non-system caller cannot seed a
|
|
1420
|
+
* `readonly` field, a `readonlyWhen` predicate locked it, etc.). Mirrors the
|
|
1421
|
+
* framework `DroppedFieldsEvent` (spec `DroppedFieldsEventSchema`) structurally
|
|
1422
|
+
* so we don't pin a client type version — `reason` is kept as a widened string
|
|
1423
|
+
* for forward-compatibility with reasons added server-side.
|
|
1424
|
+
*/
|
|
1425
|
+
interface DroppedFieldsEvent {
|
|
1426
|
+
object: string;
|
|
1427
|
+
fields: string[];
|
|
1428
|
+
reason: string;
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Emitted after a create/update whose response carried `droppedFields`
|
|
1432
|
+
* (framework #3431/#3455). The write SUCCEEDED — this is a warning that some
|
|
1433
|
+
* supplied fields never landed, so the UI can tell the user rather than let it
|
|
1434
|
+
* pass silently. Subscribe via {@link ObjectStackAdapter.onWriteWarning}.
|
|
1435
|
+
*/
|
|
1436
|
+
interface WriteWarningEvent {
|
|
1437
|
+
operation: 'create' | 'update';
|
|
1438
|
+
resource: string;
|
|
1439
|
+
id?: string | number;
|
|
1440
|
+
droppedFields: DroppedFieldsEvent[];
|
|
1441
|
+
}
|
|
1442
|
+
/** Event listener type for write-warning (dropped-fields) events. */
|
|
1443
|
+
type WriteWarningListener = (event: WriteWarningEvent) => void;
|
|
1267
1444
|
|
|
1268
1445
|
/**
|
|
1269
1446
|
* ObjectStack Data Source Adapter
|
|
@@ -1308,10 +1485,15 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
1308
1485
|
private reconnectAttempts;
|
|
1309
1486
|
private baseUrl;
|
|
1310
1487
|
private token?;
|
|
1488
|
+
/** One "analytics capability is missing" console line per adapter, not per widget. */
|
|
1489
|
+
private analyticsCapabilityWarned;
|
|
1311
1490
|
private fetchImpl;
|
|
1312
1491
|
private inflightFinds;
|
|
1313
1492
|
private missingResources;
|
|
1493
|
+
private batchUnsupported;
|
|
1494
|
+
private atomicBatchCapability;
|
|
1314
1495
|
private mutationListeners;
|
|
1496
|
+
private writeWarningListeners;
|
|
1315
1497
|
constructor(config: {
|
|
1316
1498
|
baseUrl: string;
|
|
1317
1499
|
token?: string;
|
|
@@ -1362,6 +1544,26 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
1362
1544
|
* Converts OData-style params to ObjectStack query options.
|
|
1363
1545
|
*/
|
|
1364
1546
|
find(resource: string, params?: QueryParams): Promise<QueryResult<T>>;
|
|
1547
|
+
/**
|
|
1548
|
+
* Full-text search across every searchable object in a single round-trip.
|
|
1549
|
+
*
|
|
1550
|
+
* Hits `GET /api/v1/search?q=`, the platform's global search endpoint served
|
|
1551
|
+
* by the registered search service (the pinyin full-text plugin) and backed
|
|
1552
|
+
* by `metadata-protocol`'s `searchAll`. Unlike `find(resource, { $search })`
|
|
1553
|
+
* — a per-object metadata-driven search (ADR-0061) — this consults the search
|
|
1554
|
+
* index and ranks hits across objects, so it surfaces records the per-object
|
|
1555
|
+
* fanout misses. Global affordances (⌘K command palette, search page) prefer
|
|
1556
|
+
* this path (framework #3371).
|
|
1557
|
+
*
|
|
1558
|
+
* Returns `{ query, hits }`. A backend without the search plugin installed
|
|
1559
|
+
* answers `404`; we treat that as "no global search here" and return an empty
|
|
1560
|
+
* hit set so callers can fall back to a per-object fanout rather than surface
|
|
1561
|
+
* an error.
|
|
1562
|
+
*/
|
|
1563
|
+
searchAll(query: string, options?: {
|
|
1564
|
+
limit?: number;
|
|
1565
|
+
objects?: string[];
|
|
1566
|
+
}): Promise<GlobalSearchResult>;
|
|
1365
1567
|
/**
|
|
1366
1568
|
* Find a single record by ID.
|
|
1367
1569
|
*/
|
|
@@ -1380,7 +1582,38 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
1380
1582
|
* mutation (e.g. inline-edit "Save All", which writes through `update` and
|
|
1381
1583
|
* must repaint the list without a manual reload).
|
|
1382
1584
|
*/
|
|
1383
|
-
onMutation(callback: (event:
|
|
1585
|
+
onMutation(callback: (event: DataSourceMutationEvent<T>) => void): () => void;
|
|
1586
|
+
/**
|
|
1587
|
+
* Notify all write-warning subscribers. Isolated like {@link emitMutation}: a
|
|
1588
|
+
* throwing listener must not break the write or starve the others.
|
|
1589
|
+
*/
|
|
1590
|
+
private emitWriteWarning;
|
|
1591
|
+
/**
|
|
1592
|
+
* Read `droppedFields` off a create/update response (framework #3431/#3455)
|
|
1593
|
+
* and, when present, notify write-warning subscribers. Tolerant of a client
|
|
1594
|
+
* whose response type predates `droppedFields`: the field is read structurally
|
|
1595
|
+
* and validated, so an older client (or a backend that never drops) is a no-op.
|
|
1596
|
+
*/
|
|
1597
|
+
private notifyDroppedFields;
|
|
1598
|
+
/**
|
|
1599
|
+
* Same, for the cross-object transactional batch (framework #3794). Its
|
|
1600
|
+
* response hangs the events off a top-level `droppedFields` list, each tagged
|
|
1601
|
+
* with the `index` of the operation it came from — `results` entries are bare
|
|
1602
|
+
* record echoes with nowhere to hang a per-row list.
|
|
1603
|
+
*
|
|
1604
|
+
* This is the path that matters most for the warning: `batchTransaction` is
|
|
1605
|
+
* how the console's record form saves a master-detail record, so a
|
|
1606
|
+
* `readonlyWhen`-locked field edited in that form was stripped server-side
|
|
1607
|
+
* while the UI reported a plain success. The operation kind is taken from the
|
|
1608
|
+
* originating op so the toast doesn't call an update a create.
|
|
1609
|
+
*/
|
|
1610
|
+
private notifyBatchDroppedFields;
|
|
1611
|
+
/**
|
|
1612
|
+
* Subscribe to write-warning events (a create/update dropped caller-supplied
|
|
1613
|
+
* fields — #3431/#3455). Returns an unsubscribe function. The app shell uses
|
|
1614
|
+
* this to toast the user; the write itself already succeeded.
|
|
1615
|
+
*/
|
|
1616
|
+
onWriteWarning(callback: WriteWarningListener): () => void;
|
|
1384
1617
|
create(resource: string, data: Partial<T>): Promise<T>;
|
|
1385
1618
|
/**
|
|
1386
1619
|
* Update an existing record.
|
|
@@ -1440,19 +1673,53 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
1440
1673
|
* @returns Promise resolving to array of results
|
|
1441
1674
|
*/
|
|
1442
1675
|
/**
|
|
1443
|
-
* Cross-object transactional batch (ObjectStack #1604
|
|
1444
|
-
* in ONE server transaction — commit all or roll back
|
|
1445
|
-
* `{ $ref: <earlier op index> }` resolves to that op's
|
|
1446
|
-
* can reference its parent created earlier in the same
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1676
|
+
* Cross-object transactional batch (ObjectStack #1604 / ADR-0034 item 4).
|
|
1677
|
+
* Runs the operations in ONE server transaction — commit all or roll back
|
|
1678
|
+
* all. A field value of `{ $ref: <earlier op index> }` resolves to that op's
|
|
1679
|
+
* created id, so a child can reference its parent created earlier in the same
|
|
1680
|
+
* batch (master-detail).
|
|
1681
|
+
*
|
|
1682
|
+
* Transport: the published `@objectstack/client` SDK method
|
|
1683
|
+
* `data.batchTransaction` (framework #3271; shipped since client v16, our
|
|
1684
|
+
* dependency floor). Per AGENTS.md §7 data always flows through the client —
|
|
1685
|
+
* never a hand-rolled `fetch('/api/v1/batch')`.
|
|
1686
|
+
*
|
|
1687
|
+
* Fallback decision — declarative capability negotiation (framework #3298 /
|
|
1688
|
+
* objectui #2693). At connect() we read `capabilities.transactionalBatch`
|
|
1689
|
+
* from discovery:
|
|
1690
|
+
* - Declared `true` → the backend GUARANTEES atomicity (declared ===
|
|
1691
|
+
* enforced). We TRUST it: any batch failure — including 404/405/501 —
|
|
1692
|
+
* surfaces as a real error. No non-atomic client-side compensation. This
|
|
1693
|
+
* is the path modern backends take.
|
|
1694
|
+
* - Declared `false`, or ABSENT (backend predates #3298) → we can't rely on
|
|
1695
|
+
* server atomicity, so we keep the legacy behaviour: on 404/405 (no
|
|
1696
|
+
* endpoint) or 501 (runtime without transactions) degrade to the
|
|
1697
|
+
* client-side, NON-atomic {@link emulateBatchTransaction} so a save is
|
|
1698
|
+
* still possible. Removing that here would regress older backends from
|
|
1699
|
+
* "saves, less safe" to "no save path" (#2679 compatibility constraint).
|
|
1700
|
+
* The non-atomic fallback stays isolated to THIS adapter.
|
|
1701
|
+
*/
|
|
1702
|
+
batchTransaction(operations: BatchTransactionOperation[]): Promise<{
|
|
1454
1703
|
results: any[];
|
|
1455
1704
|
}>;
|
|
1705
|
+
/** True for statuses that mean "this backend can't do a transactional batch". */
|
|
1706
|
+
private batchStatusUnsupported;
|
|
1707
|
+
/** Best-effort HTTP status extraction from a thrown SDK/client error. */
|
|
1708
|
+
private errorStatusOf;
|
|
1709
|
+
/** Mark the endpoint unsupported (warn once) and serve via emulation. */
|
|
1710
|
+
private fallbackToEmulation;
|
|
1711
|
+
/**
|
|
1712
|
+
* Emit one DataSourceMutationEvent per committed operation so the invalidation bus
|
|
1713
|
+
* (#2269) sees writes that went through /batch exactly like single
|
|
1714
|
+
* create/update/delete calls — master-detail ModalForm saves otherwise leave
|
|
1715
|
+
* related lists and count badges stale (#2582). `results` is index-aligned
|
|
1716
|
+
* with `operations`; creates take id/record from the server echo.
|
|
1717
|
+
*
|
|
1718
|
+
* Only called on the server-committed paths. The emulation branch drives the
|
|
1719
|
+
* adapter's own create/update/delete primitives, which already emit — so it
|
|
1720
|
+
* must NOT be routed through here, or events would double-fire.
|
|
1721
|
+
*/
|
|
1722
|
+
private emitBatchMutations;
|
|
1456
1723
|
bulk(resource: string, operation: 'create' | 'update' | 'delete', data: Partial<T>[]): Promise<T[]>;
|
|
1457
1724
|
/**
|
|
1458
1725
|
* Bulk-import raw spreadsheet rows in a single server round-trip via
|
|
@@ -1640,7 +1907,16 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
1640
1907
|
* Filters by `data.object === objectName` (or top-level `object`)
|
|
1641
1908
|
* client-side because the metadata index is name-only, not field-typed.
|
|
1642
1909
|
*/
|
|
1643
|
-
listViews(objectName: string
|
|
1910
|
+
listViews(objectName: string, options?: {
|
|
1911
|
+
previewDrafts?: boolean;
|
|
1912
|
+
}): Promise<any[]>;
|
|
1913
|
+
/**
|
|
1914
|
+
* Build a {@link MetadataClient} bound to this adapter's server + auth. Used
|
|
1915
|
+
* by draft-aware reads (`listViews({ previewDrafts })`) so the `/meta` route,
|
|
1916
|
+
* `?preview=draft` flag, and environment scoping live in the SDK rather than
|
|
1917
|
+
* being hand-assembled at each call site (#2767 P3).
|
|
1918
|
+
*/
|
|
1919
|
+
private metadataClient;
|
|
1644
1920
|
/**
|
|
1645
1921
|
* List registered import `mapping` artifacts targeting a given object
|
|
1646
1922
|
* (framework #2611). Reads the `mapping` metadata kind via the overlay API
|
|
@@ -1711,6 +1987,23 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
1711
1987
|
* is not available.
|
|
1712
1988
|
*/
|
|
1713
1989
|
aggregate(resource: string, params: any): Promise<any[]>;
|
|
1990
|
+
/**
|
|
1991
|
+
* Client-side aggregation over a server-scoped `find()` — the fallback used
|
|
1992
|
+
* whenever the analytics endpoint cannot answer (capability absent, network
|
|
1993
|
+
* failure, or a result whose measure came back missing).
|
|
1994
|
+
*
|
|
1995
|
+
* Forwarding `params.filter` is load-bearing: without it the fallback
|
|
1996
|
+
* aggregates the whole table while the caller believes it applied a filter,
|
|
1997
|
+
* which is the "KPI silently sums everything" failure this adapter has
|
|
1998
|
+
* guarded against since the widget filter was threaded through.
|
|
1999
|
+
*/
|
|
2000
|
+
private aggregateViaFind;
|
|
2001
|
+
/**
|
|
2002
|
+
* Say "the analytics capability isn't installed" ONCE per adapter, not once
|
|
2003
|
+
* per widget: a dashboard fans out one aggregate() per KPI, and N identical
|
|
2004
|
+
* console lines read like N different failures.
|
|
2005
|
+
*/
|
|
2006
|
+
private warnAnalyticsCapabilityOnce;
|
|
1714
2007
|
/**
|
|
1715
2008
|
* Run a semantic-layer `dataset` (ADR-0021) and return chart-ready rows.
|
|
1716
2009
|
*
|
|
@@ -1771,6 +2064,13 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
1771
2064
|
}>;
|
|
1772
2065
|
}>;
|
|
1773
2066
|
/** Client-side aggregation fallback */
|
|
2067
|
+
/**
|
|
2068
|
+
* The result column an object-bound `aggregate` projects its value under
|
|
2069
|
+
* (framework#3701, `chartAggregateValueKey` in `@objectstack/spec/ui`): the
|
|
2070
|
+
* raw `field` name — no `sum_`-style decoration, unlike a dataset measure —
|
|
2071
|
+
* or the literal `count` when a count names no field.
|
|
2072
|
+
*/
|
|
2073
|
+
private aggregateValueKey;
|
|
1774
2074
|
private aggregateClientSide;
|
|
1775
2075
|
/**
|
|
1776
2076
|
* Get multiple metadata items from ObjectStack.
|
|
@@ -1873,4 +2173,4 @@ declare function createObjectStackAdapter<T = unknown>(config: {
|
|
|
1873
2173
|
reconnectDelay?: number;
|
|
1874
2174
|
}): DataSource<T>;
|
|
1875
2175
|
|
|
1876
|
-
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, type MetadataAuditEntry, type MetadataAuditResponse, MetadataClient, type MetadataClientConfig, type MetadataDeleteOptions, type MetadataDiagnostics, type MetadataDiagnosticsEntry, type MetadataDiagnosticsOptions, type MetadataDiagnosticsSummary, type MetadataDraftHeader, type MetadataError, type MetadataGetOptions, type MetadataHistoryOptions, type MetadataLayered, type MetadataListOptions, MetadataNotFoundError, type MetadataReference, type MetadataSaveOptions, type MetadataValidationIssue, 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 };
|
|
2176
|
+
export { AnalyticsNotInstalledError, AnalyticsQueryRejectedError, 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 DroppedFieldsEvent, type EmailIntegrationConfig, FILTER_OPERATOR_ALIASES, type IntegrationConfig, IntegrationManager, type IntegrationProvider, type IntegrationTrigger, MalformedFilterError, type MetadataAuditEntry, type MetadataAuditResponse, MetadataClient, type MetadataClientConfig, type MetadataDeleteOptions, type MetadataDiagnostics, type MetadataDiagnosticsEntry, type MetadataDiagnosticsOptions, type MetadataDiagnosticsSummary, type MetadataDraftHeader, type MetadataError, type MetadataGetOptions, type MetadataHistoryOptions, type MetadataLayered, type MetadataListOptions, MetadataNotFoundError, type MetadataReference, type MetadataSaveOptions, type MetadataValidationIssue, 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, type WriteWarningEvent, type WriteWarningListener, calculateAutoLayout, classifyAnalyticsFailure, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, createObjectStackUserStateAdapter, generateContractManifest, getSharedDiscovery, is404Error, isAnalyticsNotInstalledError, isConcurrentUpdateError, isErrorType, isMalformedFilterError, isObjectStackError, normaliseClientError, readTransactionalBatchCapability, serializeOrderBy, snapToGrid, validatePluginContract };
|