@objectstack/client 3.0.7 → 3.0.9

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
@@ -586,12 +586,80 @@ var ObjectStackClient = class {
586
586
  const res = await this.fetch(`${this.baseUrl}${route}/files/${fileId}/url`);
587
587
  const data = await res.json();
588
588
  return data.url;
589
+ },
590
+ /**
591
+ * Get a presigned URL for direct-to-cloud upload
592
+ */
593
+ getPresignedUrl: async (req) => {
594
+ const route = this.getRoute("storage");
595
+ const res = await this.fetch(`${this.baseUrl}${route}/upload/presigned`, {
596
+ method: "POST",
597
+ body: JSON.stringify(req)
598
+ });
599
+ return res.json();
600
+ },
601
+ /**
602
+ * Initiate a chunked (multipart) upload session
603
+ */
604
+ initChunkedUpload: async (req) => {
605
+ const route = this.getRoute("storage");
606
+ const res = await this.fetch(`${this.baseUrl}${route}/upload/chunked`, {
607
+ method: "POST",
608
+ body: JSON.stringify(req)
609
+ });
610
+ return res.json();
611
+ },
612
+ /**
613
+ * Upload a single chunk/part of a multipart upload
614
+ */
615
+ uploadPart: async (uploadId, chunkIndex, resumeToken, data) => {
616
+ const route = this.getRoute("storage");
617
+ const res = await this.fetch(`${this.baseUrl}${route}/upload/chunked/${uploadId}/chunk/${chunkIndex}`, {
618
+ method: "PUT",
619
+ headers: { "x-resume-token": resumeToken },
620
+ body: data
621
+ });
622
+ return res.json();
623
+ },
624
+ /**
625
+ * Complete a chunked upload by assembling all parts
626
+ */
627
+ completeChunkedUpload: async (req) => {
628
+ const route = this.getRoute("storage");
629
+ const res = await this.fetch(`${this.baseUrl}${route}/upload/chunked/${req.uploadId}/complete`, {
630
+ method: "POST",
631
+ body: JSON.stringify(req)
632
+ });
633
+ return res.json();
634
+ },
635
+ /**
636
+ * Resume an interrupted chunked upload.
637
+ * Fetches current progress, then uploads remaining chunks and completes.
638
+ */
639
+ resumeUpload: async (uploadId, file, chunkSize, resumeToken) => {
640
+ const route = this.getRoute("storage");
641
+ const progressRes = await this.fetch(`${this.baseUrl}${route}/upload/chunked/${uploadId}/progress`);
642
+ const progress = await progressRes.json();
643
+ const { totalChunks, uploadedChunks } = progress.data;
644
+ const parts = [];
645
+ const fileBuffer = file instanceof ArrayBuffer ? file : await file.arrayBuffer();
646
+ for (let i = uploadedChunks; i < totalChunks; i++) {
647
+ const start = i * chunkSize;
648
+ const end = Math.min(start + chunkSize, fileBuffer.byteLength);
649
+ const chunk = new Blob([fileBuffer.slice(start, end)]);
650
+ const chunkRes = await this.storage.uploadPart(uploadId, i, resumeToken, chunk);
651
+ parts.push({ chunkIndex: i, eTag: chunkRes.data.eTag });
652
+ }
653
+ return this.storage.completeChunkedUpload({ uploadId, parts });
589
654
  }
590
655
  };
591
656
  /**
592
657
  * Automation Services
593
658
  */
594
659
  this.automation = {
660
+ /**
661
+ * Trigger a named automation flow (legacy endpoint)
662
+ */
595
663
  trigger: async (triggerName, payload) => {
596
664
  const route = this.getRoute("automation");
597
665
  const res = await this.fetch(`${this.baseUrl}${route}/trigger/${triggerName}`, {
@@ -599,6 +667,90 @@ var ObjectStackClient = class {
599
667
  body: JSON.stringify(payload)
600
668
  });
601
669
  return res.json();
670
+ },
671
+ /**
672
+ * List all registered automation flows
673
+ */
674
+ list: async () => {
675
+ const route = this.getRoute("automation");
676
+ const res = await this.fetch(`${this.baseUrl}${route}`);
677
+ return this.unwrapResponse(res);
678
+ },
679
+ /**
680
+ * Get a flow definition by name
681
+ */
682
+ get: async (name) => {
683
+ const route = this.getRoute("automation");
684
+ const res = await this.fetch(`${this.baseUrl}${route}/${name}`);
685
+ return this.unwrapResponse(res);
686
+ },
687
+ /**
688
+ * Create (register) a new flow
689
+ */
690
+ create: async (name, definition) => {
691
+ const route = this.getRoute("automation");
692
+ const res = await this.fetch(`${this.baseUrl}${route}`, {
693
+ method: "POST",
694
+ body: JSON.stringify({ name, ...definition })
695
+ });
696
+ return this.unwrapResponse(res);
697
+ },
698
+ /**
699
+ * Update an existing flow
700
+ */
701
+ update: async (name, definition) => {
702
+ const route = this.getRoute("automation");
703
+ const res = await this.fetch(`${this.baseUrl}${route}/${name}`, {
704
+ method: "PUT",
705
+ body: JSON.stringify({ definition })
706
+ });
707
+ return this.unwrapResponse(res);
708
+ },
709
+ /**
710
+ * Delete (unregister) a flow
711
+ */
712
+ delete: async (name) => {
713
+ const route = this.getRoute("automation");
714
+ const res = await this.fetch(`${this.baseUrl}${route}/${name}`, {
715
+ method: "DELETE"
716
+ });
717
+ return this.unwrapResponse(res);
718
+ },
719
+ /**
720
+ * Enable or disable a flow
721
+ */
722
+ toggle: async (name, enabled) => {
723
+ const route = this.getRoute("automation");
724
+ const res = await this.fetch(`${this.baseUrl}${route}/${name}/toggle`, {
725
+ method: "POST",
726
+ body: JSON.stringify({ enabled })
727
+ });
728
+ return this.unwrapResponse(res);
729
+ },
730
+ /**
731
+ * Execution run history
732
+ */
733
+ runs: {
734
+ /**
735
+ * List execution runs for a flow
736
+ */
737
+ list: async (flowName, options) => {
738
+ const route = this.getRoute("automation");
739
+ const params = new URLSearchParams();
740
+ if (options?.limit) params.set("limit", String(options.limit));
741
+ if (options?.cursor) params.set("cursor", options.cursor);
742
+ const qs = params.toString();
743
+ const res = await this.fetch(`${this.baseUrl}${route}/${flowName}/runs${qs ? `?${qs}` : ""}`);
744
+ return this.unwrapResponse(res);
745
+ },
746
+ /**
747
+ * Get a single execution run
748
+ */
749
+ get: async (flowName, runId) => {
750
+ const route = this.getRoute("automation");
751
+ const res = await this.fetch(`${this.baseUrl}${route}/${flowName}/runs/${runId}`);
752
+ return this.unwrapResponse(res);
753
+ }
602
754
  }
603
755
  };
604
756
  /**
@@ -979,6 +1131,174 @@ var ObjectStackClient = class {
979
1131
  return this.unwrapResponse(res);
980
1132
  }
981
1133
  };
1134
+ /**
1135
+ * Feed / Chatter Services
1136
+ *
1137
+ * Provides access to the activity timeline (comments, field changes, tasks),
1138
+ * emoji reactions, pin/star, search, changelog, and record subscriptions.
1139
+ * Base path: /api/data/{object}/{recordId}/feed
1140
+ */
1141
+ this.feed = {
1142
+ /**
1143
+ * List feed items for a record
1144
+ */
1145
+ list: async (object, recordId, options) => {
1146
+ const route = this.getRoute("feed");
1147
+ const params = new URLSearchParams();
1148
+ if (options?.type) params.set("type", options.type);
1149
+ if (options?.limit) params.set("limit", String(options.limit));
1150
+ if (options?.cursor) params.set("cursor", options.cursor);
1151
+ const qs = params.toString();
1152
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed${qs ? `?${qs}` : ""}`);
1153
+ return this.unwrapResponse(res);
1154
+ },
1155
+ /**
1156
+ * Create a new feed item (comment, note, task, etc.)
1157
+ */
1158
+ create: async (object, recordId, data) => {
1159
+ const route = this.getRoute("feed");
1160
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed`, {
1161
+ method: "POST",
1162
+ body: JSON.stringify(data)
1163
+ });
1164
+ return this.unwrapResponse(res);
1165
+ },
1166
+ /**
1167
+ * Update an existing feed item
1168
+ */
1169
+ update: async (object, recordId, feedId, data) => {
1170
+ const route = this.getRoute("feed");
1171
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}`, {
1172
+ method: "PUT",
1173
+ body: JSON.stringify(data)
1174
+ });
1175
+ return this.unwrapResponse(res);
1176
+ },
1177
+ /**
1178
+ * Delete a feed item
1179
+ */
1180
+ delete: async (object, recordId, feedId) => {
1181
+ const route = this.getRoute("feed");
1182
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}`, {
1183
+ method: "DELETE"
1184
+ });
1185
+ return this.unwrapResponse(res);
1186
+ },
1187
+ /**
1188
+ * Add an emoji reaction to a feed item
1189
+ */
1190
+ addReaction: async (object, recordId, feedId, emoji) => {
1191
+ const route = this.getRoute("feed");
1192
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/reactions`, {
1193
+ method: "POST",
1194
+ body: JSON.stringify({ emoji })
1195
+ });
1196
+ return this.unwrapResponse(res);
1197
+ },
1198
+ /**
1199
+ * Remove an emoji reaction from a feed item
1200
+ */
1201
+ removeReaction: async (object, recordId, feedId, emoji) => {
1202
+ const route = this.getRoute("feed");
1203
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/reactions/${encodeURIComponent(emoji)}`, {
1204
+ method: "DELETE"
1205
+ });
1206
+ return this.unwrapResponse(res);
1207
+ },
1208
+ /**
1209
+ * Pin a feed item to the top of the timeline
1210
+ */
1211
+ pin: async (object, recordId, feedId) => {
1212
+ const route = this.getRoute("feed");
1213
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/pin`, {
1214
+ method: "POST"
1215
+ });
1216
+ return this.unwrapResponse(res);
1217
+ },
1218
+ /**
1219
+ * Unpin a feed item
1220
+ */
1221
+ unpin: async (object, recordId, feedId) => {
1222
+ const route = this.getRoute("feed");
1223
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/pin`, {
1224
+ method: "DELETE"
1225
+ });
1226
+ return this.unwrapResponse(res);
1227
+ },
1228
+ /**
1229
+ * Star (bookmark) a feed item
1230
+ */
1231
+ star: async (object, recordId, feedId) => {
1232
+ const route = this.getRoute("feed");
1233
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/star`, {
1234
+ method: "POST"
1235
+ });
1236
+ return this.unwrapResponse(res);
1237
+ },
1238
+ /**
1239
+ * Unstar a feed item
1240
+ */
1241
+ unstar: async (object, recordId, feedId) => {
1242
+ const route = this.getRoute("feed");
1243
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/${encodeURIComponent(feedId)}/star`, {
1244
+ method: "DELETE"
1245
+ });
1246
+ return this.unwrapResponse(res);
1247
+ },
1248
+ /**
1249
+ * Search feed items
1250
+ */
1251
+ search: async (object, recordId, query, options) => {
1252
+ const route = this.getRoute("feed");
1253
+ const params = new URLSearchParams();
1254
+ params.set("query", query);
1255
+ if (options?.type) params.set("type", options.type);
1256
+ if (options?.actorId) params.set("actorId", options.actorId);
1257
+ if (options?.dateFrom) params.set("dateFrom", options.dateFrom);
1258
+ if (options?.dateTo) params.set("dateTo", options.dateTo);
1259
+ if (options?.limit) params.set("limit", String(options.limit));
1260
+ if (options?.cursor) params.set("cursor", options.cursor);
1261
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/feed/search?${params.toString()}`);
1262
+ return this.unwrapResponse(res);
1263
+ },
1264
+ /**
1265
+ * Get field-level changelog for a record
1266
+ */
1267
+ getChangelog: async (object, recordId, options) => {
1268
+ const route = this.getRoute("feed");
1269
+ const params = new URLSearchParams();
1270
+ if (options?.field) params.set("field", options.field);
1271
+ if (options?.actorId) params.set("actorId", options.actorId);
1272
+ if (options?.dateFrom) params.set("dateFrom", options.dateFrom);
1273
+ if (options?.dateTo) params.set("dateTo", options.dateTo);
1274
+ if (options?.limit) params.set("limit", String(options.limit));
1275
+ if (options?.cursor) params.set("cursor", options.cursor);
1276
+ const qs = params.toString();
1277
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/changelog${qs ? `?${qs}` : ""}`);
1278
+ return this.unwrapResponse(res);
1279
+ },
1280
+ /**
1281
+ * Subscribe to record notifications
1282
+ */
1283
+ subscribe: async (object, recordId, options) => {
1284
+ const route = this.getRoute("feed");
1285
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/subscribe`, {
1286
+ method: "POST",
1287
+ body: JSON.stringify(options || {})
1288
+ });
1289
+ return this.unwrapResponse(res);
1290
+ },
1291
+ /**
1292
+ * Unsubscribe from record notifications
1293
+ */
1294
+ unsubscribe: async (object, recordId) => {
1295
+ const route = this.getRoute("feed");
1296
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/subscribe`, {
1297
+ method: "DELETE"
1298
+ });
1299
+ return this.unwrapResponse(res);
1300
+ }
1301
+ };
982
1302
  /**
983
1303
  * Data Operations
984
1304
  */
@@ -1170,6 +1490,14 @@ var ObjectStackClient = class {
1170
1490
  throw e;
1171
1491
  }
1172
1492
  }
1493
+ /**
1494
+ * Well-known capability flags discovered from the server.
1495
+ * Returns undefined if the client has not yet connected or the server
1496
+ * did not include capabilities in its discovery response.
1497
+ */
1498
+ get capabilities() {
1499
+ return this.discoveryInfo?.capabilities;
1500
+ }
1173
1501
  /**
1174
1502
  * Private Helpers
1175
1503
  */
@@ -1259,7 +1587,8 @@ var ObjectStackClient = class {
1259
1587
  views: "/api/v1/ui/views",
1260
1588
  notifications: "/api/v1/notifications",
1261
1589
  ai: "/api/v1/ai",
1262
- i18n: "/api/v1/i18n"
1590
+ i18n: "/api/v1/i18n",
1591
+ feed: "/api/v1/data"
1263
1592
  };
1264
1593
  return routeMap[type] || `/api/v1/${type}`;
1265
1594
  }