@spacelr/sdk 0.4.0 → 0.5.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/README.md +33 -1
- package/dist/index.d.mts +236 -1
- package/dist/index.d.ts +236 -1
- package/dist/index.js +247 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +239 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -825,7 +825,7 @@ var RealtimeClient = class {
|
|
|
825
825
|
if (!where || Object.keys(where).length === 0) {
|
|
826
826
|
return base;
|
|
827
827
|
}
|
|
828
|
-
const filterStr = Object.keys(where).sort().map((k) => `${k}=${
|
|
828
|
+
const filterStr = Object.keys(where).sort().map((k) => `${k}=${JSON.stringify(where[k])}`).join("&");
|
|
829
829
|
return `${base}?${filterStr}`;
|
|
830
830
|
}
|
|
831
831
|
async ensureConnected() {
|
|
@@ -973,15 +973,15 @@ var RealtimeClient = class {
|
|
|
973
973
|
if (room === base) return true;
|
|
974
974
|
if (!room.startsWith(`${base}?`)) return false;
|
|
975
975
|
const where = this.roomWhereMap.get(room);
|
|
976
|
-
if (!where) return
|
|
976
|
+
if (!where) return false;
|
|
977
977
|
if (!event.document) return false;
|
|
978
978
|
for (const [key, value] of Object.entries(where)) {
|
|
979
979
|
const docValue = event.document[key];
|
|
980
980
|
if (Array.isArray(docValue)) {
|
|
981
|
-
if (!docValue.
|
|
981
|
+
if (!docValue.includes(value)) {
|
|
982
982
|
return false;
|
|
983
983
|
}
|
|
984
|
-
} else if (
|
|
984
|
+
} else if (docValue !== value) {
|
|
985
985
|
return false;
|
|
986
986
|
}
|
|
987
987
|
}
|
|
@@ -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);
|
|
@@ -2672,6 +2838,65 @@ var FunctionsModule = class {
|
|
|
2672
2838
|
}
|
|
2673
2839
|
};
|
|
2674
2840
|
|
|
2841
|
+
// libs/sdk/src/modules/schedule.module.ts
|
|
2842
|
+
var ScheduleModule = class {
|
|
2843
|
+
constructor(http, projectId) {
|
|
2844
|
+
this.http = http;
|
|
2845
|
+
this.projectId = projectId;
|
|
2846
|
+
}
|
|
2847
|
+
/**
|
|
2848
|
+
* Schedule a one-shot function invocation. Returns the existing handle
|
|
2849
|
+
* unchanged if `idempotencyKey` matches a prior invoke in this project
|
|
2850
|
+
* for this function.
|
|
2851
|
+
*/
|
|
2852
|
+
async invoke(options) {
|
|
2853
|
+
return this.http.request({
|
|
2854
|
+
method: "POST",
|
|
2855
|
+
path: `/schedules/${encodeURIComponent(this.projectId)}`,
|
|
2856
|
+
body: {
|
|
2857
|
+
functionId: options.functionId,
|
|
2858
|
+
executeAt: this.toIsoString(options.executeAt),
|
|
2859
|
+
...options.payload !== void 0 ? { payload: options.payload } : {},
|
|
2860
|
+
...options.idempotencyKey !== void 0 ? { idempotencyKey: options.idempotencyKey } : {},
|
|
2861
|
+
...options.maxAttempts !== void 0 ? { maxAttempts: options.maxAttempts } : {}
|
|
2862
|
+
},
|
|
2863
|
+
authenticated: true
|
|
2864
|
+
});
|
|
2865
|
+
}
|
|
2866
|
+
async get(scheduleId) {
|
|
2867
|
+
return this.http.request({
|
|
2868
|
+
method: "GET",
|
|
2869
|
+
path: `/schedules/${encodeURIComponent(this.projectId)}/${encodeURIComponent(scheduleId)}`,
|
|
2870
|
+
authenticated: true
|
|
2871
|
+
});
|
|
2872
|
+
}
|
|
2873
|
+
async list(options = {}) {
|
|
2874
|
+
return this.http.request({
|
|
2875
|
+
method: "GET",
|
|
2876
|
+
path: `/schedules/${encodeURIComponent(this.projectId)}`,
|
|
2877
|
+
query: {
|
|
2878
|
+
functionId: options.functionId,
|
|
2879
|
+
status: options.status,
|
|
2880
|
+
limit: options.limit,
|
|
2881
|
+
offset: options.offset
|
|
2882
|
+
},
|
|
2883
|
+
authenticated: true
|
|
2884
|
+
});
|
|
2885
|
+
}
|
|
2886
|
+
async cancel(scheduleId) {
|
|
2887
|
+
return this.http.request({
|
|
2888
|
+
method: "DELETE",
|
|
2889
|
+
path: `/schedules/${encodeURIComponent(this.projectId)}/${encodeURIComponent(scheduleId)}`,
|
|
2890
|
+
authenticated: true
|
|
2891
|
+
});
|
|
2892
|
+
}
|
|
2893
|
+
toIsoString(input) {
|
|
2894
|
+
if (input instanceof Date) return input.toISOString();
|
|
2895
|
+
if (typeof input === "number") return new Date(input).toISOString();
|
|
2896
|
+
return input;
|
|
2897
|
+
}
|
|
2898
|
+
};
|
|
2899
|
+
|
|
2675
2900
|
// libs/sdk/src/client.ts
|
|
2676
2901
|
function createClient(config) {
|
|
2677
2902
|
const tokenStorage = config.tokenStorage ?? (typeof window !== "undefined" && typeof window.localStorage !== "undefined" ? new BrowserTokenStorage() : new MemoryTokenStorage());
|
|
@@ -2690,12 +2915,14 @@ function createClient(config) {
|
|
|
2690
2915
|
const db = new DatabaseModule(httpClient, config.projectId, realtime);
|
|
2691
2916
|
const notifications = new NotificationsModule(httpClient);
|
|
2692
2917
|
const functions = new FunctionsModule(httpClient);
|
|
2918
|
+
const schedule = new ScheduleModule(httpClient, config.projectId);
|
|
2693
2919
|
return {
|
|
2694
2920
|
auth,
|
|
2695
2921
|
storage,
|
|
2696
2922
|
db,
|
|
2697
2923
|
notifications,
|
|
2698
2924
|
functions,
|
|
2925
|
+
schedule,
|
|
2699
2926
|
setTokens(tokens) {
|
|
2700
2927
|
return tokenManager.setTokens(tokens);
|
|
2701
2928
|
},
|
|
@@ -2722,9 +2949,13 @@ function createClient(config) {
|
|
|
2722
2949
|
export {
|
|
2723
2950
|
BrowserTokenStorage,
|
|
2724
2951
|
CodeChallengeMethod,
|
|
2952
|
+
CursorInvalidError,
|
|
2725
2953
|
FileVisibility,
|
|
2954
|
+
ForbiddenError,
|
|
2726
2955
|
GrantType,
|
|
2727
2956
|
MemoryTokenStorage,
|
|
2957
|
+
NotFoundError,
|
|
2958
|
+
ServerConfigError,
|
|
2728
2959
|
SharePermission,
|
|
2729
2960
|
SpacelrAuthError,
|
|
2730
2961
|
SpacelrEmailVerificationRequiredError,
|
|
@@ -2733,6 +2964,10 @@ export {
|
|
|
2733
2964
|
SpacelrSearchFilterRequiredError,
|
|
2734
2965
|
SpacelrTimeoutError,
|
|
2735
2966
|
SpacelrTwoFactorRequiredError,
|
|
2967
|
+
TimelineError,
|
|
2968
|
+
TimelineModule,
|
|
2969
|
+
TimeoutError,
|
|
2970
|
+
ValidationError,
|
|
2736
2971
|
createClient,
|
|
2737
2972
|
generatePKCEChallenge,
|
|
2738
2973
|
localStorageCursorStorage,
|