@objectstack/client 3.3.1 → 4.0.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/dist/index.js CHANGED
@@ -221,12 +221,20 @@ var QueryBuilder = class {
221
221
  return this;
222
222
  }
223
223
  /**
224
- * Skip records (for pagination)
224
+ * Skip records (for pagination).
225
+ * @deprecated Prefer `.offset()` for alignment with Spec canonical field names.
225
226
  */
226
227
  skip(count) {
227
228
  this.query.offset = count;
228
229
  return this;
229
230
  }
231
+ /**
232
+ * Offset records (for pagination) — canonical alias for `.skip()`
233
+ */
234
+ offset(count) {
235
+ this.query.offset = count;
236
+ return this;
237
+ }
230
238
  /**
231
239
  * Paginate results
232
240
  */
@@ -1172,7 +1180,7 @@ var ObjectStackClient = class {
1172
1180
  * List feed items for a record
1173
1181
  */
1174
1182
  list: async (object, recordId, options) => {
1175
- const route = this.getRoute("feed");
1183
+ const route = this.getRoute("data");
1176
1184
  const params = new URLSearchParams();
1177
1185
  if (options?.type) params.set("type", options.type);
1178
1186
  if (options?.limit) params.set("limit", String(options.limit));
@@ -1185,7 +1193,7 @@ var ObjectStackClient = class {
1185
1193
  * Create a new feed item (comment, note, task, etc.)
1186
1194
  */
1187
1195
  create: async (object, recordId, data) => {
1188
- const route = this.getRoute("feed");
1196
+ const route = this.getRoute("data");
1189
1197
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed`, {
1190
1198
  method: "POST",
1191
1199
  body: JSON.stringify(data)
@@ -1196,7 +1204,7 @@ var ObjectStackClient = class {
1196
1204
  * Update an existing feed item
1197
1205
  */
1198
1206
  update: async (object, recordId, feedId, data) => {
1199
- const route = this.getRoute("feed");
1207
+ const route = this.getRoute("data");
1200
1208
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}`, {
1201
1209
  method: "PUT",
1202
1210
  body: JSON.stringify(data)
@@ -1207,7 +1215,7 @@ var ObjectStackClient = class {
1207
1215
  * Delete a feed item
1208
1216
  */
1209
1217
  delete: async (object, recordId, feedId) => {
1210
- const route = this.getRoute("feed");
1218
+ const route = this.getRoute("data");
1211
1219
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}`, {
1212
1220
  method: "DELETE"
1213
1221
  });
@@ -1217,7 +1225,7 @@ var ObjectStackClient = class {
1217
1225
  * Add an emoji reaction to a feed item
1218
1226
  */
1219
1227
  addReaction: async (object, recordId, feedId, emoji) => {
1220
- const route = this.getRoute("feed");
1228
+ const route = this.getRoute("data");
1221
1229
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/reactions`, {
1222
1230
  method: "POST",
1223
1231
  body: JSON.stringify({ emoji })
@@ -1228,7 +1236,7 @@ var ObjectStackClient = class {
1228
1236
  * Remove an emoji reaction from a feed item
1229
1237
  */
1230
1238
  removeReaction: async (object, recordId, feedId, emoji) => {
1231
- const route = this.getRoute("feed");
1239
+ const route = this.getRoute("data");
1232
1240
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/reactions/${encodeURIComponent(emoji)}`, {
1233
1241
  method: "DELETE"
1234
1242
  });
@@ -1238,7 +1246,7 @@ var ObjectStackClient = class {
1238
1246
  * Pin a feed item to the top of the timeline
1239
1247
  */
1240
1248
  pin: async (object, recordId, feedId) => {
1241
- const route = this.getRoute("feed");
1249
+ const route = this.getRoute("data");
1242
1250
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/pin`, {
1243
1251
  method: "POST"
1244
1252
  });
@@ -1248,7 +1256,7 @@ var ObjectStackClient = class {
1248
1256
  * Unpin a feed item
1249
1257
  */
1250
1258
  unpin: async (object, recordId, feedId) => {
1251
- const route = this.getRoute("feed");
1259
+ const route = this.getRoute("data");
1252
1260
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/pin`, {
1253
1261
  method: "DELETE"
1254
1262
  });
@@ -1258,7 +1266,7 @@ var ObjectStackClient = class {
1258
1266
  * Star (bookmark) a feed item
1259
1267
  */
1260
1268
  star: async (object, recordId, feedId) => {
1261
- const route = this.getRoute("feed");
1269
+ const route = this.getRoute("data");
1262
1270
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/star`, {
1263
1271
  method: "POST"
1264
1272
  });
@@ -1268,7 +1276,7 @@ var ObjectStackClient = class {
1268
1276
  * Unstar a feed item
1269
1277
  */
1270
1278
  unstar: async (object, recordId, feedId) => {
1271
- const route = this.getRoute("feed");
1279
+ const route = this.getRoute("data");
1272
1280
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/star`, {
1273
1281
  method: "DELETE"
1274
1282
  });
@@ -1278,7 +1286,7 @@ var ObjectStackClient = class {
1278
1286
  * Search feed items
1279
1287
  */
1280
1288
  search: async (object, recordId, query, options) => {
1281
- const route = this.getRoute("feed");
1289
+ const route = this.getRoute("data");
1282
1290
  const params = new URLSearchParams();
1283
1291
  params.set("query", query);
1284
1292
  if (options?.type) params.set("type", options.type);
@@ -1294,7 +1302,7 @@ var ObjectStackClient = class {
1294
1302
  * Get field-level changelog for a record
1295
1303
  */
1296
1304
  getChangelog: async (object, recordId, options) => {
1297
- const route = this.getRoute("feed");
1305
+ const route = this.getRoute("data");
1298
1306
  const params = new URLSearchParams();
1299
1307
  if (options?.field) params.set("field", options.field);
1300
1308
  if (options?.actorId) params.set("actorId", options.actorId);
@@ -1310,7 +1318,7 @@ var ObjectStackClient = class {
1310
1318
  * Subscribe to record notifications
1311
1319
  */
1312
1320
  subscribe: async (object, recordId, options) => {
1313
- const route = this.getRoute("feed");
1321
+ const route = this.getRoute("data");
1314
1322
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/subscribe`, {
1315
1323
  method: "POST",
1316
1324
  body: JSON.stringify(options || {})
@@ -1321,7 +1329,7 @@ var ObjectStackClient = class {
1321
1329
  * Unsubscribe from record notifications
1322
1330
  */
1323
1331
  unsubscribe: async (object, recordId) => {
1324
- const route = this.getRoute("feed");
1332
+ const route = this.getRoute("data");
1325
1333
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/subscribe`, {
1326
1334
  method: "DELETE"
1327
1335
  });
@@ -1344,23 +1352,40 @@ var ObjectStackClient = class {
1344
1352
  });
1345
1353
  return this.unwrapResponse(res);
1346
1354
  },
1355
+ /**
1356
+ * @deprecated Use `data.query()` with standard QueryAST parameters instead.
1357
+ * This method uses legacy parameter names. Internally adapts to HTTP GET params.
1358
+ */
1347
1359
  find: async (object, options = {}) => {
1348
1360
  const route = this.getRoute("data");
1349
1361
  const queryParams = new URLSearchParams();
1350
- if (options.top) queryParams.set("top", options.top.toString());
1351
- if (options.skip) queryParams.set("skip", options.skip.toString());
1352
- if (options.sort) {
1353
- if (Array.isArray(options.sort) && typeof options.sort[0] === "object") {
1354
- queryParams.set("sort", JSON.stringify(options.sort));
1362
+ const v2 = options;
1363
+ const normalizedOptions = {};
1364
+ if ("where" in options || "fields" in options || "orderBy" in options || "offset" in options) {
1365
+ if (v2.where) normalizedOptions.filter = v2.where;
1366
+ if (v2.fields) normalizedOptions.select = v2.fields;
1367
+ if (v2.orderBy) normalizedOptions.sort = v2.orderBy;
1368
+ if (v2.limit != null) normalizedOptions.top = v2.limit;
1369
+ if (v2.offset != null) normalizedOptions.skip = v2.offset;
1370
+ if (v2.aggregations) normalizedOptions.aggregations = v2.aggregations;
1371
+ if (v2.groupBy) normalizedOptions.groupBy = v2.groupBy;
1372
+ } else {
1373
+ Object.assign(normalizedOptions, options);
1374
+ }
1375
+ if (normalizedOptions.top) queryParams.set("top", normalizedOptions.top.toString());
1376
+ if (normalizedOptions.skip) queryParams.set("skip", normalizedOptions.skip.toString());
1377
+ if (normalizedOptions.sort) {
1378
+ if (Array.isArray(normalizedOptions.sort) && typeof normalizedOptions.sort[0] === "object") {
1379
+ queryParams.set("sort", JSON.stringify(normalizedOptions.sort));
1355
1380
  } else {
1356
- const sortVal = Array.isArray(options.sort) ? options.sort.join(",") : options.sort;
1381
+ const sortVal = Array.isArray(normalizedOptions.sort) ? normalizedOptions.sort.join(",") : normalizedOptions.sort;
1357
1382
  queryParams.set("sort", sortVal);
1358
1383
  }
1359
1384
  }
1360
- if (options.select) {
1361
- queryParams.set("select", options.select.join(","));
1385
+ if (normalizedOptions.select) {
1386
+ queryParams.set("select", normalizedOptions.select.join(","));
1362
1387
  }
1363
- const filterValue = options.filter ?? options.filters;
1388
+ const filterValue = normalizedOptions.filter ?? normalizedOptions.filters;
1364
1389
  if (filterValue) {
1365
1390
  if (this.isFilterAST(filterValue) || Array.isArray(filterValue)) {
1366
1391
  queryParams.set("filter", JSON.stringify(filterValue));
@@ -1372,11 +1397,11 @@ var ObjectStackClient = class {
1372
1397
  });
1373
1398
  }
1374
1399
  }
1375
- if (options.aggregations) {
1376
- queryParams.set("aggregations", JSON.stringify(options.aggregations));
1400
+ if (normalizedOptions.aggregations) {
1401
+ queryParams.set("aggregations", JSON.stringify(normalizedOptions.aggregations));
1377
1402
  }
1378
- if (options.groupBy) {
1379
- queryParams.set("groupBy", options.groupBy.join(","));
1403
+ if (normalizedOptions.groupBy) {
1404
+ queryParams.set("groupBy", normalizedOptions.groupBy.join(","));
1380
1405
  }
1381
1406
  const res = await this.fetch(`${this.baseUrl}${route}/${object}?${queryParams.toString()}`);
1382
1407
  return this.unwrapResponse(res);
@@ -1496,8 +1521,8 @@ var ObjectStackClient = class {
1496
1521
  this.logger.debug("Standard discovery probe failed", { error: e.message });
1497
1522
  }
1498
1523
  if (!data) {
1499
- const fallbackUrl = `${this.baseUrl}/api/v1`;
1500
- this.logger.debug("Falling back to legacy discovery", { url: fallbackUrl });
1524
+ const fallbackUrl = `${this.baseUrl}/api/v1/discovery`;
1525
+ this.logger.debug("Falling back to standard discovery endpoint", { url: fallbackUrl });
1501
1526
  const res = await this.fetchImpl(fallbackUrl);
1502
1527
  if (!res.ok) {
1503
1528
  throw new Error(`Failed to connect to ${fallbackUrl}: ${res.statusText}`);
@@ -1524,9 +1549,19 @@ var ObjectStackClient = class {
1524
1549
  * Well-known capability flags discovered from the server.
1525
1550
  * Returns undefined if the client has not yet connected or the server
1526
1551
  * did not include capabilities in its discovery response.
1552
+ *
1553
+ * The server may return capabilities in hierarchical format
1554
+ * `{ key: { enabled: boolean } }` or flat boolean format `{ key: boolean }`.
1555
+ * This getter normalizes both to flat `WellKnownCapabilities`.
1527
1556
  */
1528
1557
  get capabilities() {
1529
- return this.discoveryInfo?.capabilities;
1558
+ const raw = this.discoveryInfo?.capabilities;
1559
+ if (!raw) return void 0;
1560
+ const result = {};
1561
+ for (const [key, value] of Object.entries(raw)) {
1562
+ result[key] = typeof value === "object" && value !== null ? !!value.enabled : !!value;
1563
+ }
1564
+ return result;
1530
1565
  }
1531
1566
  /**
1532
1567
  * Private Helpers
@@ -1598,12 +1633,16 @@ var ObjectStackClient = class {
1598
1633
  * ObjectStack uses standard conventions: /api/v1/data, /api/v1/meta, /api/v1/ui
1599
1634
  */
1600
1635
  getRoute(type) {
1601
- if (this.discoveryInfo?.routes && this.discoveryInfo.routes[type]) {
1602
- return this.discoveryInfo.routes[type];
1636
+ const routes = this.discoveryInfo?.routes;
1637
+ if (routes) {
1638
+ const key = type;
1639
+ const discovered = routes[key];
1640
+ if (discovered) return discovered;
1603
1641
  }
1604
1642
  const routeMap = {
1605
1643
  data: "/api/v1/data",
1606
1644
  metadata: "/api/v1/meta",
1645
+ discovery: "/api/v1/discovery",
1607
1646
  ui: "/api/v1/ui",
1608
1647
  auth: "/api/v1/auth",
1609
1648
  analytics: "/api/v1/analytics",
@@ -1617,7 +1656,8 @@ var ObjectStackClient = class {
1617
1656
  notifications: "/api/v1/notifications",
1618
1657
  ai: "/api/v1/ai",
1619
1658
  i18n: "/api/v1/i18n",
1620
- feed: "/api/v1/data"
1659
+ feed: "/api/v1/feed",
1660
+ graphql: "/graphql"
1621
1661
  };
1622
1662
  return routeMap[type] || `/api/v1/${type}`;
1623
1663
  }