@spacelr/sdk 0.5.0 → 0.5.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/README.md +33 -1
- package/dist/index.d.mts +186 -5
- package/dist/index.d.ts +186 -5
- package/dist/index.js +197 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +189 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1784,6 +1784,144 @@ var StorageModule = class {
|
|
|
1784
1784
|
}
|
|
1785
1785
|
};
|
|
1786
1786
|
|
|
1787
|
+
// libs/sdk/src/modules/timeline.errors.ts
|
|
1788
|
+
var TimelineError = class extends SpacelrError {
|
|
1789
|
+
constructor(message, opts = {}) {
|
|
1790
|
+
super(message, opts.code ?? "TIMELINE_ERROR", opts.statusCode);
|
|
1791
|
+
this.name = "TimelineError";
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
var CursorInvalidError = class extends TimelineError {
|
|
1795
|
+
constructor(message, opts = {}) {
|
|
1796
|
+
super(message, { statusCode: opts.statusCode ?? 400, code: opts.code ?? "CURSOR_INVALID" });
|
|
1797
|
+
this.name = "CursorInvalidError";
|
|
1798
|
+
}
|
|
1799
|
+
};
|
|
1800
|
+
var ValidationError = class extends TimelineError {
|
|
1801
|
+
constructor(message, opts = {}) {
|
|
1802
|
+
super(message, { statusCode: opts.statusCode ?? 400, code: opts.code ?? "BAD_REQUEST" });
|
|
1803
|
+
this.name = "ValidationError";
|
|
1804
|
+
}
|
|
1805
|
+
};
|
|
1806
|
+
var ForbiddenError = class extends TimelineError {
|
|
1807
|
+
constructor(message, opts = {}) {
|
|
1808
|
+
super(message, { statusCode: opts.statusCode ?? 403, code: opts.code ?? "FORBIDDEN" });
|
|
1809
|
+
this.name = "ForbiddenError";
|
|
1810
|
+
}
|
|
1811
|
+
};
|
|
1812
|
+
var NotFoundError = class extends TimelineError {
|
|
1813
|
+
constructor(message, opts = {}) {
|
|
1814
|
+
super(message, { statusCode: opts.statusCode ?? 404, code: opts.code ?? "NOT_FOUND" });
|
|
1815
|
+
this.name = "NotFoundError";
|
|
1816
|
+
}
|
|
1817
|
+
};
|
|
1818
|
+
var ServerConfigError = class extends TimelineError {
|
|
1819
|
+
constructor(message, opts = {}) {
|
|
1820
|
+
super(message, { statusCode: opts.statusCode ?? 500, code: opts.code ?? "CONFIG_INVALID" });
|
|
1821
|
+
this.name = "ServerConfigError";
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
var TimeoutError = class extends TimelineError {
|
|
1825
|
+
constructor(message, opts = {}) {
|
|
1826
|
+
super(message, { statusCode: opts.statusCode ?? 504, code: opts.code ?? "TIMEOUT" });
|
|
1827
|
+
this.name = "TimeoutError";
|
|
1828
|
+
}
|
|
1829
|
+
};
|
|
1830
|
+
function mapTimelineError(statusCode, body) {
|
|
1831
|
+
const code = body?.code;
|
|
1832
|
+
const message = body?.message ?? `Timeline request failed with HTTP ${statusCode}`;
|
|
1833
|
+
if (statusCode === 400) {
|
|
1834
|
+
if (code === "CURSOR_INVALID") {
|
|
1835
|
+
return new CursorInvalidError(message, { statusCode, code });
|
|
1836
|
+
}
|
|
1837
|
+
return new ValidationError(message, { statusCode, code });
|
|
1838
|
+
}
|
|
1839
|
+
if (statusCode === 403) {
|
|
1840
|
+
return new ForbiddenError(message, { statusCode, code });
|
|
1841
|
+
}
|
|
1842
|
+
if (statusCode === 404) {
|
|
1843
|
+
return new NotFoundError(message, { statusCode, code });
|
|
1844
|
+
}
|
|
1845
|
+
if (statusCode === 500) {
|
|
1846
|
+
return new ServerConfigError(message, { statusCode, code });
|
|
1847
|
+
}
|
|
1848
|
+
if (statusCode === 504) {
|
|
1849
|
+
return new TimeoutError(message, { statusCode, code });
|
|
1850
|
+
}
|
|
1851
|
+
return new TimelineError(message, { statusCode, code });
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
// libs/sdk/src/modules/timeline.module.ts
|
|
1855
|
+
var TimelineModule = class {
|
|
1856
|
+
constructor(http) {
|
|
1857
|
+
this.http = http;
|
|
1858
|
+
}
|
|
1859
|
+
async query(opts) {
|
|
1860
|
+
const body = {
|
|
1861
|
+
collection: opts.collection,
|
|
1862
|
+
partitionValue: opts.partitionValue
|
|
1863
|
+
};
|
|
1864
|
+
if (opts.where !== void 0) body["where"] = opts.where;
|
|
1865
|
+
if (opts.orderBy !== void 0) body["orderBy"] = opts.orderBy;
|
|
1866
|
+
if (opts.limit !== void 0) body["limit"] = opts.limit;
|
|
1867
|
+
if (opts.cursor !== void 0) body["cursor"] = opts.cursor;
|
|
1868
|
+
let raw;
|
|
1869
|
+
try {
|
|
1870
|
+
raw = await this.http.request({
|
|
1871
|
+
method: "POST",
|
|
1872
|
+
path: "/db/timeline",
|
|
1873
|
+
body,
|
|
1874
|
+
authenticated: true
|
|
1875
|
+
});
|
|
1876
|
+
} catch (err) {
|
|
1877
|
+
throw this.translateError(err);
|
|
1878
|
+
}
|
|
1879
|
+
if (!isTimelineQueryResponse(raw)) {
|
|
1880
|
+
throw new TimelineError(
|
|
1881
|
+
"Timeline gateway returned a response shape the SDK does not recognise",
|
|
1882
|
+
{ statusCode: 500, code: "INVALID_RESPONSE_SHAPE" }
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
return raw;
|
|
1886
|
+
}
|
|
1887
|
+
translateError(err) {
|
|
1888
|
+
if (err instanceof SpacelrTimeoutError) {
|
|
1889
|
+
return new TimeoutError(err.message, { statusCode: 504, code: "TIMEOUT" });
|
|
1890
|
+
}
|
|
1891
|
+
if (err instanceof SpacelrAuthError) {
|
|
1892
|
+
if (err.statusCode === 403) {
|
|
1893
|
+
return new ForbiddenError(err.message, { statusCode: 403, code: err.code ?? "FORBIDDEN" });
|
|
1894
|
+
}
|
|
1895
|
+
return err;
|
|
1896
|
+
}
|
|
1897
|
+
if (err instanceof SpacelrNetworkError) {
|
|
1898
|
+
return err;
|
|
1899
|
+
}
|
|
1900
|
+
if (err instanceof SpacelrError) {
|
|
1901
|
+
return mapTimelineError(err.statusCode ?? 0, { code: err.code, message: err.message });
|
|
1902
|
+
}
|
|
1903
|
+
return err;
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
1906
|
+
function isTimelineQueryResponse(value) {
|
|
1907
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1908
|
+
const v = value;
|
|
1909
|
+
if (!Array.isArray(v["items"])) return false;
|
|
1910
|
+
if (v["nextCursor"] !== null && typeof v["nextCursor"] !== "string") return false;
|
|
1911
|
+
if (!isTimelineSourceStats(v["sourceStats"])) return false;
|
|
1912
|
+
return true;
|
|
1913
|
+
}
|
|
1914
|
+
function isTimelineSourceStats(value) {
|
|
1915
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1916
|
+
const v = value;
|
|
1917
|
+
if (typeof v["hot"] !== "number") return false;
|
|
1918
|
+
if (typeof v["cold"] !== "number") return false;
|
|
1919
|
+
if (v["segmentsScanned"] !== void 0 && typeof v["segmentsScanned"] !== "number") {
|
|
1920
|
+
return false;
|
|
1921
|
+
}
|
|
1922
|
+
return true;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1787
1925
|
// libs/sdk/src/modules/database.module.ts
|
|
1788
1926
|
var Paginator = class {
|
|
1789
1927
|
constructor(http, basePath, opts) {
|
|
@@ -1967,6 +2105,16 @@ var CollectionRef = class {
|
|
|
1967
2105
|
authenticated: true
|
|
1968
2106
|
});
|
|
1969
2107
|
}
|
|
2108
|
+
/**
|
|
2109
|
+
* Query the collection's **hot tier** (live MongoDB).
|
|
2110
|
+
*
|
|
2111
|
+
* **Cold-tier note:** if the collection has cold-tier archival enabled, aged
|
|
2112
|
+
* documents are moved to object storage and purged from the hot tier — they
|
|
2113
|
+
* will NOT appear in `find()` results (nor `findById`, `count`, `search`,
|
|
2114
|
+
* `paginate`, which are all hot-tier only). To read archived history, use
|
|
2115
|
+
* {@link TimelineModule.query} via `db.timeline.query(...)`, which transparently
|
|
2116
|
+
* merges hot and cold results for a partition.
|
|
2117
|
+
*/
|
|
1970
2118
|
find(filter) {
|
|
1971
2119
|
return new QueryBuilder(this.http, this.basePath, filter);
|
|
1972
2120
|
}
|
|
@@ -2001,6 +2149,9 @@ var CollectionRef = class {
|
|
|
2001
2149
|
*
|
|
2002
2150
|
* Limits: `query` 1–200 chars, `fields` 1–10 entries (each matching
|
|
2003
2151
|
* `/^[a-zA-Z0-9_.]+$/`, max 64 chars), `limit` max 100.
|
|
2152
|
+
*
|
|
2153
|
+
* **Cold-tier note:** searches the hot tier only; archived documents are not
|
|
2154
|
+
* included. See {@link CollectionRef.find} and `db.timeline.query(...)`.
|
|
2004
2155
|
*/
|
|
2005
2156
|
async search(opts) {
|
|
2006
2157
|
return this.http.request({
|
|
@@ -2010,6 +2161,13 @@ var CollectionRef = class {
|
|
|
2010
2161
|
authenticated: true
|
|
2011
2162
|
});
|
|
2012
2163
|
}
|
|
2164
|
+
/**
|
|
2165
|
+
* Fetch a single document by `_id` from the **hot tier**.
|
|
2166
|
+
*
|
|
2167
|
+
* **Cold-tier note:** returns null/throws for documents that have been
|
|
2168
|
+
* archived and purged from the hot tier. Archived history is reachable only
|
|
2169
|
+
* via `db.timeline.query(...)`. See {@link CollectionRef.find}.
|
|
2170
|
+
*/
|
|
2013
2171
|
async findById(id, options) {
|
|
2014
2172
|
const query = {};
|
|
2015
2173
|
if (options?.populate?.length) {
|
|
@@ -2039,6 +2197,13 @@ var CollectionRef = class {
|
|
|
2039
2197
|
authenticated: true
|
|
2040
2198
|
});
|
|
2041
2199
|
}
|
|
2200
|
+
/**
|
|
2201
|
+
* Count documents in the **hot tier** matching `filter`.
|
|
2202
|
+
*
|
|
2203
|
+
* **Cold-tier note:** counts hot-tier documents only — archived/purged
|
|
2204
|
+
* documents are not included, so this is not a total-history count. See
|
|
2205
|
+
* {@link CollectionRef.find} and `db.timeline.query(...)`.
|
|
2206
|
+
*/
|
|
2042
2207
|
async count(filter) {
|
|
2043
2208
|
const result = await this.http.request({
|
|
2044
2209
|
method: "POST",
|
|
@@ -2474,6 +2639,7 @@ var DatabaseModule = class {
|
|
|
2474
2639
|
this.http = http;
|
|
2475
2640
|
this.projectId = projectId;
|
|
2476
2641
|
this.realtime = realtime ?? null;
|
|
2642
|
+
this.timeline = new TimelineModule(http);
|
|
2477
2643
|
}
|
|
2478
2644
|
collection(name) {
|
|
2479
2645
|
return new CollectionRef(this.http, this.realtime, this.projectId, name);
|
|
@@ -2538,7 +2704,7 @@ var NotificationsModule = class {
|
|
|
2538
2704
|
authenticated: true
|
|
2539
2705
|
});
|
|
2540
2706
|
}
|
|
2541
|
-
/** Register a push subscription (web, android, or
|
|
2707
|
+
/** Register a push subscription (web, android, ios, or web-fcm) */
|
|
2542
2708
|
async subscribe(subscription, deviceName) {
|
|
2543
2709
|
return this.http.request({
|
|
2544
2710
|
method: "POST",
|
|
@@ -2624,6 +2790,20 @@ var NotificationsModule = class {
|
|
|
2624
2790
|
deviceName
|
|
2625
2791
|
);
|
|
2626
2792
|
}
|
|
2793
|
+
/**
|
|
2794
|
+
* Registers a web Firebase Cloud Messaging registration token (obtained via
|
|
2795
|
+
* the Firebase JS SDK `getToken()`), so `notifications.send` delivers to this
|
|
2796
|
+
* browser through the project's FCM provider instead of VAPID WebPush.
|
|
2797
|
+
*/
|
|
2798
|
+
async registerWebFcm(fcmToken, deviceName) {
|
|
2799
|
+
return this.subscribe(
|
|
2800
|
+
{
|
|
2801
|
+
platform: "web-fcm",
|
|
2802
|
+
deviceToken: fcmToken
|
|
2803
|
+
},
|
|
2804
|
+
deviceName
|
|
2805
|
+
);
|
|
2806
|
+
}
|
|
2627
2807
|
urlBase64ToUint8Array(base64String) {
|
|
2628
2808
|
const padding = "=".repeat((4 - base64String.length % 4) % 4);
|
|
2629
2809
|
const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -2783,9 +2963,13 @@ function createClient(config) {
|
|
|
2783
2963
|
export {
|
|
2784
2964
|
BrowserTokenStorage,
|
|
2785
2965
|
CodeChallengeMethod,
|
|
2966
|
+
CursorInvalidError,
|
|
2786
2967
|
FileVisibility,
|
|
2968
|
+
ForbiddenError,
|
|
2787
2969
|
GrantType,
|
|
2788
2970
|
MemoryTokenStorage,
|
|
2971
|
+
NotFoundError,
|
|
2972
|
+
ServerConfigError,
|
|
2789
2973
|
SharePermission,
|
|
2790
2974
|
SpacelrAuthError,
|
|
2791
2975
|
SpacelrEmailVerificationRequiredError,
|
|
@@ -2794,6 +2978,10 @@ export {
|
|
|
2794
2978
|
SpacelrSearchFilterRequiredError,
|
|
2795
2979
|
SpacelrTimeoutError,
|
|
2796
2980
|
SpacelrTwoFactorRequiredError,
|
|
2981
|
+
TimelineError,
|
|
2982
|
+
TimelineModule,
|
|
2983
|
+
TimeoutError,
|
|
2984
|
+
ValidationError,
|
|
2797
2985
|
createClient,
|
|
2798
2986
|
generatePKCEChallenge,
|
|
2799
2987
|
localStorageCursorStorage,
|