@objectstack/client 3.3.1 → 4.0.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/dist/index.mjs CHANGED
@@ -193,12 +193,20 @@ var QueryBuilder = class {
193
193
  return this;
194
194
  }
195
195
  /**
196
- * Skip records (for pagination)
196
+ * Skip records (for pagination).
197
+ * @deprecated Prefer `.offset()` for alignment with Spec canonical field names.
197
198
  */
198
199
  skip(count) {
199
200
  this.query.offset = count;
200
201
  return this;
201
202
  }
203
+ /**
204
+ * Offset records (for pagination) — canonical alias for `.skip()`
205
+ */
206
+ offset(count) {
207
+ this.query.offset = count;
208
+ return this;
209
+ }
202
210
  /**
203
211
  * Paginate results
204
212
  */
@@ -1144,7 +1152,7 @@ var ObjectStackClient = class {
1144
1152
  * List feed items for a record
1145
1153
  */
1146
1154
  list: async (object, recordId, options) => {
1147
- const route = this.getRoute("feed");
1155
+ const route = this.getRoute("data");
1148
1156
  const params = new URLSearchParams();
1149
1157
  if (options?.type) params.set("type", options.type);
1150
1158
  if (options?.limit) params.set("limit", String(options.limit));
@@ -1157,7 +1165,7 @@ var ObjectStackClient = class {
1157
1165
  * Create a new feed item (comment, note, task, etc.)
1158
1166
  */
1159
1167
  create: async (object, recordId, data) => {
1160
- const route = this.getRoute("feed");
1168
+ const route = this.getRoute("data");
1161
1169
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed`, {
1162
1170
  method: "POST",
1163
1171
  body: JSON.stringify(data)
@@ -1168,7 +1176,7 @@ var ObjectStackClient = class {
1168
1176
  * Update an existing feed item
1169
1177
  */
1170
1178
  update: async (object, recordId, feedId, data) => {
1171
- const route = this.getRoute("feed");
1179
+ const route = this.getRoute("data");
1172
1180
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}`, {
1173
1181
  method: "PUT",
1174
1182
  body: JSON.stringify(data)
@@ -1179,7 +1187,7 @@ var ObjectStackClient = class {
1179
1187
  * Delete a feed item
1180
1188
  */
1181
1189
  delete: async (object, recordId, feedId) => {
1182
- const route = this.getRoute("feed");
1190
+ const route = this.getRoute("data");
1183
1191
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}`, {
1184
1192
  method: "DELETE"
1185
1193
  });
@@ -1189,7 +1197,7 @@ var ObjectStackClient = class {
1189
1197
  * Add an emoji reaction to a feed item
1190
1198
  */
1191
1199
  addReaction: async (object, recordId, feedId, emoji) => {
1192
- const route = this.getRoute("feed");
1200
+ const route = this.getRoute("data");
1193
1201
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/reactions`, {
1194
1202
  method: "POST",
1195
1203
  body: JSON.stringify({ emoji })
@@ -1200,7 +1208,7 @@ var ObjectStackClient = class {
1200
1208
  * Remove an emoji reaction from a feed item
1201
1209
  */
1202
1210
  removeReaction: async (object, recordId, feedId, emoji) => {
1203
- const route = this.getRoute("feed");
1211
+ const route = this.getRoute("data");
1204
1212
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/reactions/${encodeURIComponent(emoji)}`, {
1205
1213
  method: "DELETE"
1206
1214
  });
@@ -1210,7 +1218,7 @@ var ObjectStackClient = class {
1210
1218
  * Pin a feed item to the top of the timeline
1211
1219
  */
1212
1220
  pin: async (object, recordId, feedId) => {
1213
- const route = this.getRoute("feed");
1221
+ const route = this.getRoute("data");
1214
1222
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/pin`, {
1215
1223
  method: "POST"
1216
1224
  });
@@ -1220,7 +1228,7 @@ var ObjectStackClient = class {
1220
1228
  * Unpin a feed item
1221
1229
  */
1222
1230
  unpin: async (object, recordId, feedId) => {
1223
- const route = this.getRoute("feed");
1231
+ const route = this.getRoute("data");
1224
1232
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/pin`, {
1225
1233
  method: "DELETE"
1226
1234
  });
@@ -1230,7 +1238,7 @@ var ObjectStackClient = class {
1230
1238
  * Star (bookmark) a feed item
1231
1239
  */
1232
1240
  star: async (object, recordId, feedId) => {
1233
- const route = this.getRoute("feed");
1241
+ const route = this.getRoute("data");
1234
1242
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/star`, {
1235
1243
  method: "POST"
1236
1244
  });
@@ -1240,7 +1248,7 @@ var ObjectStackClient = class {
1240
1248
  * Unstar a feed item
1241
1249
  */
1242
1250
  unstar: async (object, recordId, feedId) => {
1243
- const route = this.getRoute("feed");
1251
+ const route = this.getRoute("data");
1244
1252
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/star`, {
1245
1253
  method: "DELETE"
1246
1254
  });
@@ -1250,7 +1258,7 @@ var ObjectStackClient = class {
1250
1258
  * Search feed items
1251
1259
  */
1252
1260
  search: async (object, recordId, query, options) => {
1253
- const route = this.getRoute("feed");
1261
+ const route = this.getRoute("data");
1254
1262
  const params = new URLSearchParams();
1255
1263
  params.set("query", query);
1256
1264
  if (options?.type) params.set("type", options.type);
@@ -1266,7 +1274,7 @@ var ObjectStackClient = class {
1266
1274
  * Get field-level changelog for a record
1267
1275
  */
1268
1276
  getChangelog: async (object, recordId, options) => {
1269
- const route = this.getRoute("feed");
1277
+ const route = this.getRoute("data");
1270
1278
  const params = new URLSearchParams();
1271
1279
  if (options?.field) params.set("field", options.field);
1272
1280
  if (options?.actorId) params.set("actorId", options.actorId);
@@ -1282,7 +1290,7 @@ var ObjectStackClient = class {
1282
1290
  * Subscribe to record notifications
1283
1291
  */
1284
1292
  subscribe: async (object, recordId, options) => {
1285
- const route = this.getRoute("feed");
1293
+ const route = this.getRoute("data");
1286
1294
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/subscribe`, {
1287
1295
  method: "POST",
1288
1296
  body: JSON.stringify(options || {})
@@ -1293,7 +1301,7 @@ var ObjectStackClient = class {
1293
1301
  * Unsubscribe from record notifications
1294
1302
  */
1295
1303
  unsubscribe: async (object, recordId) => {
1296
- const route = this.getRoute("feed");
1304
+ const route = this.getRoute("data");
1297
1305
  const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/subscribe`, {
1298
1306
  method: "DELETE"
1299
1307
  });
@@ -1316,23 +1324,40 @@ var ObjectStackClient = class {
1316
1324
  });
1317
1325
  return this.unwrapResponse(res);
1318
1326
  },
1327
+ /**
1328
+ * @deprecated Use `data.query()` with standard QueryAST parameters instead.
1329
+ * This method uses legacy parameter names. Internally adapts to HTTP GET params.
1330
+ */
1319
1331
  find: async (object, options = {}) => {
1320
1332
  const route = this.getRoute("data");
1321
1333
  const queryParams = new URLSearchParams();
1322
- if (options.top) queryParams.set("top", options.top.toString());
1323
- if (options.skip) queryParams.set("skip", options.skip.toString());
1324
- if (options.sort) {
1325
- if (Array.isArray(options.sort) && typeof options.sort[0] === "object") {
1326
- queryParams.set("sort", JSON.stringify(options.sort));
1334
+ const v2 = options;
1335
+ const normalizedOptions = {};
1336
+ if ("where" in options || "fields" in options || "orderBy" in options || "offset" in options) {
1337
+ if (v2.where) normalizedOptions.filter = v2.where;
1338
+ if (v2.fields) normalizedOptions.select = v2.fields;
1339
+ if (v2.orderBy) normalizedOptions.sort = v2.orderBy;
1340
+ if (v2.limit != null) normalizedOptions.top = v2.limit;
1341
+ if (v2.offset != null) normalizedOptions.skip = v2.offset;
1342
+ if (v2.aggregations) normalizedOptions.aggregations = v2.aggregations;
1343
+ if (v2.groupBy) normalizedOptions.groupBy = v2.groupBy;
1344
+ } else {
1345
+ Object.assign(normalizedOptions, options);
1346
+ }
1347
+ if (normalizedOptions.top) queryParams.set("top", normalizedOptions.top.toString());
1348
+ if (normalizedOptions.skip) queryParams.set("skip", normalizedOptions.skip.toString());
1349
+ if (normalizedOptions.sort) {
1350
+ if (Array.isArray(normalizedOptions.sort) && typeof normalizedOptions.sort[0] === "object") {
1351
+ queryParams.set("sort", JSON.stringify(normalizedOptions.sort));
1327
1352
  } else {
1328
- const sortVal = Array.isArray(options.sort) ? options.sort.join(",") : options.sort;
1353
+ const sortVal = Array.isArray(normalizedOptions.sort) ? normalizedOptions.sort.join(",") : normalizedOptions.sort;
1329
1354
  queryParams.set("sort", sortVal);
1330
1355
  }
1331
1356
  }
1332
- if (options.select) {
1333
- queryParams.set("select", options.select.join(","));
1357
+ if (normalizedOptions.select) {
1358
+ queryParams.set("select", normalizedOptions.select.join(","));
1334
1359
  }
1335
- const filterValue = options.filter ?? options.filters;
1360
+ const filterValue = normalizedOptions.filter ?? normalizedOptions.filters;
1336
1361
  if (filterValue) {
1337
1362
  if (this.isFilterAST(filterValue) || Array.isArray(filterValue)) {
1338
1363
  queryParams.set("filter", JSON.stringify(filterValue));
@@ -1344,11 +1369,11 @@ var ObjectStackClient = class {
1344
1369
  });
1345
1370
  }
1346
1371
  }
1347
- if (options.aggregations) {
1348
- queryParams.set("aggregations", JSON.stringify(options.aggregations));
1372
+ if (normalizedOptions.aggregations) {
1373
+ queryParams.set("aggregations", JSON.stringify(normalizedOptions.aggregations));
1349
1374
  }
1350
- if (options.groupBy) {
1351
- queryParams.set("groupBy", options.groupBy.join(","));
1375
+ if (normalizedOptions.groupBy) {
1376
+ queryParams.set("groupBy", normalizedOptions.groupBy.join(","));
1352
1377
  }
1353
1378
  const res = await this.fetch(`${this.baseUrl}${route}/${object}?${queryParams.toString()}`);
1354
1379
  return this.unwrapResponse(res);
@@ -1468,8 +1493,8 @@ var ObjectStackClient = class {
1468
1493
  this.logger.debug("Standard discovery probe failed", { error: e.message });
1469
1494
  }
1470
1495
  if (!data) {
1471
- const fallbackUrl = `${this.baseUrl}/api/v1`;
1472
- this.logger.debug("Falling back to legacy discovery", { url: fallbackUrl });
1496
+ const fallbackUrl = `${this.baseUrl}/api/v1/discovery`;
1497
+ this.logger.debug("Falling back to standard discovery endpoint", { url: fallbackUrl });
1473
1498
  const res = await this.fetchImpl(fallbackUrl);
1474
1499
  if (!res.ok) {
1475
1500
  throw new Error(`Failed to connect to ${fallbackUrl}: ${res.statusText}`);
@@ -1496,9 +1521,19 @@ var ObjectStackClient = class {
1496
1521
  * Well-known capability flags discovered from the server.
1497
1522
  * Returns undefined if the client has not yet connected or the server
1498
1523
  * did not include capabilities in its discovery response.
1524
+ *
1525
+ * The server may return capabilities in hierarchical format
1526
+ * `{ key: { enabled: boolean } }` or flat boolean format `{ key: boolean }`.
1527
+ * This getter normalizes both to flat `WellKnownCapabilities`.
1499
1528
  */
1500
1529
  get capabilities() {
1501
- return this.discoveryInfo?.capabilities;
1530
+ const raw = this.discoveryInfo?.capabilities;
1531
+ if (!raw) return void 0;
1532
+ const result = {};
1533
+ for (const [key, value] of Object.entries(raw)) {
1534
+ result[key] = typeof value === "object" && value !== null ? !!value.enabled : !!value;
1535
+ }
1536
+ return result;
1502
1537
  }
1503
1538
  /**
1504
1539
  * Private Helpers
@@ -1570,12 +1605,16 @@ var ObjectStackClient = class {
1570
1605
  * ObjectStack uses standard conventions: /api/v1/data, /api/v1/meta, /api/v1/ui
1571
1606
  */
1572
1607
  getRoute(type) {
1573
- if (this.discoveryInfo?.routes && this.discoveryInfo.routes[type]) {
1574
- return this.discoveryInfo.routes[type];
1608
+ const routes = this.discoveryInfo?.routes;
1609
+ if (routes) {
1610
+ const key = type;
1611
+ const discovered = routes[key];
1612
+ if (discovered) return discovered;
1575
1613
  }
1576
1614
  const routeMap = {
1577
1615
  data: "/api/v1/data",
1578
1616
  metadata: "/api/v1/meta",
1617
+ discovery: "/api/v1/discovery",
1579
1618
  ui: "/api/v1/ui",
1580
1619
  auth: "/api/v1/auth",
1581
1620
  analytics: "/api/v1/analytics",
@@ -1589,7 +1628,8 @@ var ObjectStackClient = class {
1589
1628
  notifications: "/api/v1/notifications",
1590
1629
  ai: "/api/v1/ai",
1591
1630
  i18n: "/api/v1/i18n",
1592
- feed: "/api/v1/data"
1631
+ feed: "/api/v1/feed",
1632
+ graphql: "/graphql"
1593
1633
  };
1594
1634
  return routeMap[type] || `/api/v1/${type}`;
1595
1635
  }