@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.d.mts +77 -22
- package/dist/index.d.ts +77 -22
- package/dist/index.js +79 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -381,28 +381,6 @@ interface DatabaseChangeEvent {
|
|
|
381
381
|
* for pubsub-mode events. Used by function triggers as an idempotency key.
|
|
382
382
|
*/
|
|
383
383
|
eventId?: string;
|
|
384
|
-
/**
|
|
385
|
-
* Identifies the origin of the write. Stamped on the envelope (never in the
|
|
386
|
-
* document body) so function-service can run a tamper-resistant recursion guard
|
|
387
|
-
* (internal TCP caller can spoof — see PR notes). Absent on legacy events
|
|
388
|
-
* published before this field existed.
|
|
389
|
-
*/
|
|
390
|
-
_source?: 'user' | 'function';
|
|
391
|
-
/**
|
|
392
|
-
* When `_source === 'function'`, the id of the function whose runtime wrote
|
|
393
|
-
* the document. Used to skip self-chain events without blocking legitimate
|
|
394
|
-
* cross-function chains.
|
|
395
|
-
*/
|
|
396
|
-
_sourceFunctionId?: string;
|
|
397
|
-
/**
|
|
398
|
-
* Hop-counter on function-originated events. User writes have no value.
|
|
399
|
-
* Each function-write increments the incoming envelope's depth by one,
|
|
400
|
-
* so an A→B→A loop bumps the counter on every hop. The reader rejects
|
|
401
|
-
* dispatch when depth >= MAX_CHAIN_DEPTH so mutual chains terminate
|
|
402
|
-
* deterministically rather than relying on the bounded queue to drop
|
|
403
|
-
* events.
|
|
404
|
-
*/
|
|
405
|
-
_chainDepth?: number;
|
|
406
384
|
}
|
|
407
385
|
interface RealtimeConfig {
|
|
408
386
|
baseUrl: string;
|
|
@@ -825,6 +803,71 @@ interface SubscribeHandlers<T = Record<string, unknown>> {
|
|
|
825
803
|
onDelete?: (documentId: string) => void;
|
|
826
804
|
onError?: (error: Error) => void;
|
|
827
805
|
}
|
|
806
|
+
interface PaginateOptions {
|
|
807
|
+
where?: Record<string, unknown>;
|
|
808
|
+
/** Sort direction by `_id`. Defaults to -1 (newest first — chat scroll-back). */
|
|
809
|
+
sort?: {
|
|
810
|
+
_id: 1 | -1;
|
|
811
|
+
};
|
|
812
|
+
/** Page size. Default 50. Server typically caps at 100. */
|
|
813
|
+
limit?: number;
|
|
814
|
+
/**
|
|
815
|
+
* Optional initial cursor — paginate from this `_id` exclusively. Useful
|
|
816
|
+
* when the caller already holds a boundary document (e.g. the oldest
|
|
817
|
+
* message currently rendered in a chat view paired with `subscribeEvents`).
|
|
818
|
+
*/
|
|
819
|
+
cursor?: string;
|
|
820
|
+
}
|
|
821
|
+
interface PaginatorPage<T = Record<string, unknown>> {
|
|
822
|
+
documents: (T & {
|
|
823
|
+
_id: string;
|
|
824
|
+
})[];
|
|
825
|
+
/**
|
|
826
|
+
* True when more documents exist past this page. The paginator also flips
|
|
827
|
+
* `exhausted` to true when this returns false, so callers can poll either
|
|
828
|
+
* `page.hasMore` after each call or `paginator.exhausted` between calls.
|
|
829
|
+
*/
|
|
830
|
+
hasMore: boolean;
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Cursor-based scroll helper around `find()`. Tracks the last-seen `_id`
|
|
834
|
+
* across calls and applies it as `.before()` (descending sort) or
|
|
835
|
+
* `.after()` (ascending sort) on the next page so the keyset stays stable
|
|
836
|
+
* under concurrent inserts. Use `subscribeEvents` for new docs and
|
|
837
|
+
* `paginate` for older — the two compose into a chat-style timeline.
|
|
838
|
+
*/
|
|
839
|
+
declare class Paginator<T = Record<string, unknown>> {
|
|
840
|
+
private readonly http;
|
|
841
|
+
private readonly basePath;
|
|
842
|
+
private cursor?;
|
|
843
|
+
private _exhausted;
|
|
844
|
+
private readonly direction;
|
|
845
|
+
private readonly pageSize;
|
|
846
|
+
private readonly where?;
|
|
847
|
+
/**
|
|
848
|
+
* Tail of the serialized `next()` chain. Each call appends to this so
|
|
849
|
+
* concurrent invocations from a UI scroll handler (e.g. user spam-tapping
|
|
850
|
+
* "load more") don't issue parallel requests with the same cursor — which
|
|
851
|
+
* would return duplicate pages and clobber the cursor based on whichever
|
|
852
|
+
* response settles last. Calls execute strictly in invocation order.
|
|
853
|
+
*/
|
|
854
|
+
private chain;
|
|
855
|
+
constructor(http: HttpClient, basePath: string, opts: PaginateOptions);
|
|
856
|
+
/**
|
|
857
|
+
* True once a `next()` call has returned an empty page. Subsequent
|
|
858
|
+
* `next()` calls return an empty page without hitting the server.
|
|
859
|
+
*
|
|
860
|
+
* Note: only the empty-page signal flips this flag; a server response
|
|
861
|
+
* that returns documents but `hasMore: false` does NOT exhaust. This
|
|
862
|
+
* lets ascending paginators (`sort: { _id: 1 }`) keep polling for
|
|
863
|
+
* documents inserted after the caller caught up to the current tail —
|
|
864
|
+
* the next `.after(lastSeen)` call will simply return zero documents
|
|
865
|
+
* until something new lands.
|
|
866
|
+
*/
|
|
867
|
+
get exhausted(): boolean;
|
|
868
|
+
next(): Promise<PaginatorPage<T>>;
|
|
869
|
+
private fetchNextPage;
|
|
870
|
+
}
|
|
828
871
|
declare class QueryBuilder<T = Record<string, unknown>, M extends 'offset' | 'cursor' = 'offset'> {
|
|
829
872
|
private http;
|
|
830
873
|
private basePath;
|
|
@@ -892,6 +935,18 @@ declare class CollectionRef<T = Record<string, unknown>> {
|
|
|
892
935
|
_id?: string;
|
|
893
936
|
})[]): Promise<InsertResult>;
|
|
894
937
|
find(filter?: Record<string, unknown>): QueryBuilder<T>;
|
|
938
|
+
/**
|
|
939
|
+
* Cursor-based scroll-back helper. Returns a `Paginator` whose `.next()`
|
|
940
|
+
* yields successive pages and tracks the last-seen `_id` internally.
|
|
941
|
+
* Defaults to descending sort and 50 docs per page (chat scroll-back is
|
|
942
|
+
* the canonical use case). See `PaginateOptions` for tuning.
|
|
943
|
+
*
|
|
944
|
+
* **Cursor constraint:** uses `_id` keyset pagination, which requires
|
|
945
|
+
* 24-hex ObjectId `_id`s. Collections with custom string `_id` schemes
|
|
946
|
+
* fall back to comparing strings as ObjectIds — the server's handler
|
|
947
|
+
* documents this limitation on `before` / `after` directly.
|
|
948
|
+
*/
|
|
949
|
+
paginate(opts?: PaginateOptions): Paginator<T>;
|
|
895
950
|
/**
|
|
896
951
|
* Server-side substring search across the specified fields.
|
|
897
952
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -381,28 +381,6 @@ interface DatabaseChangeEvent {
|
|
|
381
381
|
* for pubsub-mode events. Used by function triggers as an idempotency key.
|
|
382
382
|
*/
|
|
383
383
|
eventId?: string;
|
|
384
|
-
/**
|
|
385
|
-
* Identifies the origin of the write. Stamped on the envelope (never in the
|
|
386
|
-
* document body) so function-service can run a tamper-resistant recursion guard
|
|
387
|
-
* (internal TCP caller can spoof — see PR notes). Absent on legacy events
|
|
388
|
-
* published before this field existed.
|
|
389
|
-
*/
|
|
390
|
-
_source?: 'user' | 'function';
|
|
391
|
-
/**
|
|
392
|
-
* When `_source === 'function'`, the id of the function whose runtime wrote
|
|
393
|
-
* the document. Used to skip self-chain events without blocking legitimate
|
|
394
|
-
* cross-function chains.
|
|
395
|
-
*/
|
|
396
|
-
_sourceFunctionId?: string;
|
|
397
|
-
/**
|
|
398
|
-
* Hop-counter on function-originated events. User writes have no value.
|
|
399
|
-
* Each function-write increments the incoming envelope's depth by one,
|
|
400
|
-
* so an A→B→A loop bumps the counter on every hop. The reader rejects
|
|
401
|
-
* dispatch when depth >= MAX_CHAIN_DEPTH so mutual chains terminate
|
|
402
|
-
* deterministically rather than relying on the bounded queue to drop
|
|
403
|
-
* events.
|
|
404
|
-
*/
|
|
405
|
-
_chainDepth?: number;
|
|
406
384
|
}
|
|
407
385
|
interface RealtimeConfig {
|
|
408
386
|
baseUrl: string;
|
|
@@ -825,6 +803,71 @@ interface SubscribeHandlers<T = Record<string, unknown>> {
|
|
|
825
803
|
onDelete?: (documentId: string) => void;
|
|
826
804
|
onError?: (error: Error) => void;
|
|
827
805
|
}
|
|
806
|
+
interface PaginateOptions {
|
|
807
|
+
where?: Record<string, unknown>;
|
|
808
|
+
/** Sort direction by `_id`. Defaults to -1 (newest first — chat scroll-back). */
|
|
809
|
+
sort?: {
|
|
810
|
+
_id: 1 | -1;
|
|
811
|
+
};
|
|
812
|
+
/** Page size. Default 50. Server typically caps at 100. */
|
|
813
|
+
limit?: number;
|
|
814
|
+
/**
|
|
815
|
+
* Optional initial cursor — paginate from this `_id` exclusively. Useful
|
|
816
|
+
* when the caller already holds a boundary document (e.g. the oldest
|
|
817
|
+
* message currently rendered in a chat view paired with `subscribeEvents`).
|
|
818
|
+
*/
|
|
819
|
+
cursor?: string;
|
|
820
|
+
}
|
|
821
|
+
interface PaginatorPage<T = Record<string, unknown>> {
|
|
822
|
+
documents: (T & {
|
|
823
|
+
_id: string;
|
|
824
|
+
})[];
|
|
825
|
+
/**
|
|
826
|
+
* True when more documents exist past this page. The paginator also flips
|
|
827
|
+
* `exhausted` to true when this returns false, so callers can poll either
|
|
828
|
+
* `page.hasMore` after each call or `paginator.exhausted` between calls.
|
|
829
|
+
*/
|
|
830
|
+
hasMore: boolean;
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Cursor-based scroll helper around `find()`. Tracks the last-seen `_id`
|
|
834
|
+
* across calls and applies it as `.before()` (descending sort) or
|
|
835
|
+
* `.after()` (ascending sort) on the next page so the keyset stays stable
|
|
836
|
+
* under concurrent inserts. Use `subscribeEvents` for new docs and
|
|
837
|
+
* `paginate` for older — the two compose into a chat-style timeline.
|
|
838
|
+
*/
|
|
839
|
+
declare class Paginator<T = Record<string, unknown>> {
|
|
840
|
+
private readonly http;
|
|
841
|
+
private readonly basePath;
|
|
842
|
+
private cursor?;
|
|
843
|
+
private _exhausted;
|
|
844
|
+
private readonly direction;
|
|
845
|
+
private readonly pageSize;
|
|
846
|
+
private readonly where?;
|
|
847
|
+
/**
|
|
848
|
+
* Tail of the serialized `next()` chain. Each call appends to this so
|
|
849
|
+
* concurrent invocations from a UI scroll handler (e.g. user spam-tapping
|
|
850
|
+
* "load more") don't issue parallel requests with the same cursor — which
|
|
851
|
+
* would return duplicate pages and clobber the cursor based on whichever
|
|
852
|
+
* response settles last. Calls execute strictly in invocation order.
|
|
853
|
+
*/
|
|
854
|
+
private chain;
|
|
855
|
+
constructor(http: HttpClient, basePath: string, opts: PaginateOptions);
|
|
856
|
+
/**
|
|
857
|
+
* True once a `next()` call has returned an empty page. Subsequent
|
|
858
|
+
* `next()` calls return an empty page without hitting the server.
|
|
859
|
+
*
|
|
860
|
+
* Note: only the empty-page signal flips this flag; a server response
|
|
861
|
+
* that returns documents but `hasMore: false` does NOT exhaust. This
|
|
862
|
+
* lets ascending paginators (`sort: { _id: 1 }`) keep polling for
|
|
863
|
+
* documents inserted after the caller caught up to the current tail —
|
|
864
|
+
* the next `.after(lastSeen)` call will simply return zero documents
|
|
865
|
+
* until something new lands.
|
|
866
|
+
*/
|
|
867
|
+
get exhausted(): boolean;
|
|
868
|
+
next(): Promise<PaginatorPage<T>>;
|
|
869
|
+
private fetchNextPage;
|
|
870
|
+
}
|
|
828
871
|
declare class QueryBuilder<T = Record<string, unknown>, M extends 'offset' | 'cursor' = 'offset'> {
|
|
829
872
|
private http;
|
|
830
873
|
private basePath;
|
|
@@ -892,6 +935,18 @@ declare class CollectionRef<T = Record<string, unknown>> {
|
|
|
892
935
|
_id?: string;
|
|
893
936
|
})[]): Promise<InsertResult>;
|
|
894
937
|
find(filter?: Record<string, unknown>): QueryBuilder<T>;
|
|
938
|
+
/**
|
|
939
|
+
* Cursor-based scroll-back helper. Returns a `Paginator` whose `.next()`
|
|
940
|
+
* yields successive pages and tracks the last-seen `_id` internally.
|
|
941
|
+
* Defaults to descending sort and 50 docs per page (chat scroll-back is
|
|
942
|
+
* the canonical use case). See `PaginateOptions` for tuning.
|
|
943
|
+
*
|
|
944
|
+
* **Cursor constraint:** uses `_id` keyset pagination, which requires
|
|
945
|
+
* 24-hex ObjectId `_id`s. Collections with custom string `_id` schemes
|
|
946
|
+
* fall back to comparing strings as ObjectIds — the server's handler
|
|
947
|
+
* documents this limitation on `before` / `after` directly.
|
|
948
|
+
*/
|
|
949
|
+
paginate(opts?: PaginateOptions): Paginator<T>;
|
|
895
950
|
/**
|
|
896
951
|
* Server-side substring search across the specified fields.
|
|
897
952
|
*
|
package/dist/index.js
CHANGED
|
@@ -412,7 +412,9 @@ var TokenManager = class {
|
|
|
412
412
|
return tokens.accessToken;
|
|
413
413
|
}
|
|
414
414
|
async setTokens(tokens) {
|
|
415
|
-
|
|
415
|
+
const needsDefault = tokens.expiresAt === void 0 && !!tokens.refreshToken;
|
|
416
|
+
const normalised = needsDefault ? { ...tokens, expiresAt: Math.floor(Date.now() / 1e3) } : tokens;
|
|
417
|
+
await this.storage.setTokens(normalised);
|
|
416
418
|
this.authLostEmitted = false;
|
|
417
419
|
}
|
|
418
420
|
async clearTokens() {
|
|
@@ -1674,6 +1676,68 @@ var StorageModule = class {
|
|
|
1674
1676
|
};
|
|
1675
1677
|
|
|
1676
1678
|
// libs/sdk/src/modules/database.module.ts
|
|
1679
|
+
var Paginator = class {
|
|
1680
|
+
constructor(http, basePath, opts) {
|
|
1681
|
+
this.http = http;
|
|
1682
|
+
this.basePath = basePath;
|
|
1683
|
+
this._exhausted = false;
|
|
1684
|
+
/**
|
|
1685
|
+
* Tail of the serialized `next()` chain. Each call appends to this so
|
|
1686
|
+
* concurrent invocations from a UI scroll handler (e.g. user spam-tapping
|
|
1687
|
+
* "load more") don't issue parallel requests with the same cursor — which
|
|
1688
|
+
* would return duplicate pages and clobber the cursor based on whichever
|
|
1689
|
+
* response settles last. Calls execute strictly in invocation order.
|
|
1690
|
+
*/
|
|
1691
|
+
this.chain = Promise.resolve({
|
|
1692
|
+
documents: [],
|
|
1693
|
+
hasMore: false
|
|
1694
|
+
});
|
|
1695
|
+
this.cursor = opts.cursor;
|
|
1696
|
+
this.direction = opts.sort?._id ?? -1;
|
|
1697
|
+
this.pageSize = opts.limit ?? 50;
|
|
1698
|
+
this.where = opts.where;
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* True once a `next()` call has returned an empty page. Subsequent
|
|
1702
|
+
* `next()` calls return an empty page without hitting the server.
|
|
1703
|
+
*
|
|
1704
|
+
* Note: only the empty-page signal flips this flag; a server response
|
|
1705
|
+
* that returns documents but `hasMore: false` does NOT exhaust. This
|
|
1706
|
+
* lets ascending paginators (`sort: { _id: 1 }`) keep polling for
|
|
1707
|
+
* documents inserted after the caller caught up to the current tail —
|
|
1708
|
+
* the next `.after(lastSeen)` call will simply return zero documents
|
|
1709
|
+
* until something new lands.
|
|
1710
|
+
*/
|
|
1711
|
+
get exhausted() {
|
|
1712
|
+
return this._exhausted;
|
|
1713
|
+
}
|
|
1714
|
+
next() {
|
|
1715
|
+
const run = this.chain.then(
|
|
1716
|
+
() => this.fetchNextPage(),
|
|
1717
|
+
() => this.fetchNextPage()
|
|
1718
|
+
);
|
|
1719
|
+
this.chain = run;
|
|
1720
|
+
return run;
|
|
1721
|
+
}
|
|
1722
|
+
async fetchNextPage() {
|
|
1723
|
+
if (this._exhausted) return { documents: [], hasMore: false };
|
|
1724
|
+
const builder = new QueryBuilder(this.http, this.basePath, this.where).sort({ _id: this.direction }).limit(this.pageSize);
|
|
1725
|
+
let result;
|
|
1726
|
+
if (this.cursor !== void 0) {
|
|
1727
|
+
const cursorBuilder = this.direction === -1 ? builder.before(this.cursor) : builder.after(this.cursor);
|
|
1728
|
+
result = await cursorBuilder.execute();
|
|
1729
|
+
} else {
|
|
1730
|
+
result = await builder.execute();
|
|
1731
|
+
}
|
|
1732
|
+
if (result.documents.length === 0) {
|
|
1733
|
+
this._exhausted = true;
|
|
1734
|
+
return { documents: [], hasMore: false };
|
|
1735
|
+
}
|
|
1736
|
+
this.cursor = result.documents[result.documents.length - 1]._id;
|
|
1737
|
+
const hasMore = result.mode === "cursor" ? result.hasMore : result.documents.length < result.total;
|
|
1738
|
+
return { documents: result.documents, hasMore };
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1677
1741
|
var QueryBuilder = class {
|
|
1678
1742
|
constructor(http, basePath, filter) {
|
|
1679
1743
|
this.http = http;
|
|
@@ -1790,6 +1854,20 @@ var CollectionRef = class {
|
|
|
1790
1854
|
find(filter) {
|
|
1791
1855
|
return new QueryBuilder(this.http, this.basePath, filter);
|
|
1792
1856
|
}
|
|
1857
|
+
/**
|
|
1858
|
+
* Cursor-based scroll-back helper. Returns a `Paginator` whose `.next()`
|
|
1859
|
+
* yields successive pages and tracks the last-seen `_id` internally.
|
|
1860
|
+
* Defaults to descending sort and 50 docs per page (chat scroll-back is
|
|
1861
|
+
* the canonical use case). See `PaginateOptions` for tuning.
|
|
1862
|
+
*
|
|
1863
|
+
* **Cursor constraint:** uses `_id` keyset pagination, which requires
|
|
1864
|
+
* 24-hex ObjectId `_id`s. Collections with custom string `_id` schemes
|
|
1865
|
+
* fall back to comparing strings as ObjectIds — the server's handler
|
|
1866
|
+
* documents this limitation on `before` / `after` directly.
|
|
1867
|
+
*/
|
|
1868
|
+
paginate(opts = {}) {
|
|
1869
|
+
return new Paginator(this.http, this.basePath, opts);
|
|
1870
|
+
}
|
|
1793
1871
|
/**
|
|
1794
1872
|
* Server-side substring search across the specified fields.
|
|
1795
1873
|
*
|