@spacelr/sdk 0.2.0 → 0.2.2

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
@@ -378,7 +378,9 @@ var TokenManager = class {
378
378
  return tokens.accessToken;
379
379
  }
380
380
  async setTokens(tokens) {
381
- await this.storage.setTokens(tokens);
381
+ const needsDefault = tokens.expiresAt === void 0 && !!tokens.refreshToken;
382
+ const normalised = needsDefault ? { ...tokens, expiresAt: Math.floor(Date.now() / 1e3) } : tokens;
383
+ await this.storage.setTokens(normalised);
382
384
  this.authLostEmitted = false;
383
385
  }
384
386
  async clearTokens() {
@@ -1640,6 +1642,68 @@ var StorageModule = class {
1640
1642
  };
1641
1643
 
1642
1644
  // libs/sdk/src/modules/database.module.ts
1645
+ var Paginator = class {
1646
+ constructor(http, basePath, opts) {
1647
+ this.http = http;
1648
+ this.basePath = basePath;
1649
+ this._exhausted = false;
1650
+ /**
1651
+ * Tail of the serialized `next()` chain. Each call appends to this so
1652
+ * concurrent invocations from a UI scroll handler (e.g. user spam-tapping
1653
+ * "load more") don't issue parallel requests with the same cursor — which
1654
+ * would return duplicate pages and clobber the cursor based on whichever
1655
+ * response settles last. Calls execute strictly in invocation order.
1656
+ */
1657
+ this.chain = Promise.resolve({
1658
+ documents: [],
1659
+ hasMore: false
1660
+ });
1661
+ this.cursor = opts.cursor;
1662
+ this.direction = opts.sort?._id ?? -1;
1663
+ this.pageSize = opts.limit ?? 50;
1664
+ this.where = opts.where;
1665
+ }
1666
+ /**
1667
+ * True once a `next()` call has returned an empty page. Subsequent
1668
+ * `next()` calls return an empty page without hitting the server.
1669
+ *
1670
+ * Note: only the empty-page signal flips this flag; a server response
1671
+ * that returns documents but `hasMore: false` does NOT exhaust. This
1672
+ * lets ascending paginators (`sort: { _id: 1 }`) keep polling for
1673
+ * documents inserted after the caller caught up to the current tail —
1674
+ * the next `.after(lastSeen)` call will simply return zero documents
1675
+ * until something new lands.
1676
+ */
1677
+ get exhausted() {
1678
+ return this._exhausted;
1679
+ }
1680
+ next() {
1681
+ const run = this.chain.then(
1682
+ () => this.fetchNextPage(),
1683
+ () => this.fetchNextPage()
1684
+ );
1685
+ this.chain = run;
1686
+ return run;
1687
+ }
1688
+ async fetchNextPage() {
1689
+ if (this._exhausted) return { documents: [], hasMore: false };
1690
+ const builder = new QueryBuilder(this.http, this.basePath, this.where).sort({ _id: this.direction }).limit(this.pageSize);
1691
+ let result;
1692
+ if (this.cursor !== void 0) {
1693
+ const cursorBuilder = this.direction === -1 ? builder.before(this.cursor) : builder.after(this.cursor);
1694
+ result = await cursorBuilder.execute();
1695
+ } else {
1696
+ result = await builder.execute();
1697
+ }
1698
+ if (result.documents.length === 0) {
1699
+ this._exhausted = true;
1700
+ return { documents: [], hasMore: false };
1701
+ }
1702
+ this.cursor = result.documents[result.documents.length - 1]._id;
1703
+ const hasMore = result.mode === "cursor" ? result.hasMore : result.documents.length < result.total;
1704
+ return { documents: result.documents, hasMore };
1705
+ }
1706
+ };
1643
1707
  var QueryBuilder = class {
1644
1708
  constructor(http, basePath, filter) {
1645
1709
  this.http = http;
@@ -1756,6 +1820,20 @@ var CollectionRef = class {
1756
1820
  find(filter) {
1757
1821
  return new QueryBuilder(this.http, this.basePath, filter);
1758
1822
  }
1823
+ /**
1824
+ * Cursor-based scroll-back helper. Returns a `Paginator` whose `.next()`
1825
+ * yields successive pages and tracks the last-seen `_id` internally.
1826
+ * Defaults to descending sort and 50 docs per page (chat scroll-back is
1827
+ * the canonical use case). See `PaginateOptions` for tuning.
1828
+ *
1829
+ * **Cursor constraint:** uses `_id` keyset pagination, which requires
1830
+ * 24-hex ObjectId `_id`s. Collections with custom string `_id` schemes
1831
+ * fall back to comparing strings as ObjectIds — the server's handler
1832
+ * documents this limitation on `before` / `after` directly.
1833
+ */
1834
+ paginate(opts = {}) {
1835
+ return new Paginator(this.http, this.basePath, opts);
1836
+ }
1759
1837
  /**
1760
1838
  * Server-side substring search across the specified fields.
1761
1839
  *