@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/dist/index.js CHANGED
@@ -22,9 +22,13 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  BrowserTokenStorage: () => BrowserTokenStorage,
24
24
  CodeChallengeMethod: () => CodeChallengeMethod,
25
+ CursorInvalidError: () => CursorInvalidError,
25
26
  FileVisibility: () => FileVisibility,
27
+ ForbiddenError: () => ForbiddenError,
26
28
  GrantType: () => GrantType,
27
29
  MemoryTokenStorage: () => MemoryTokenStorage,
30
+ NotFoundError: () => NotFoundError,
31
+ ServerConfigError: () => ServerConfigError,
28
32
  SharePermission: () => SharePermission,
29
33
  SpacelrAuthError: () => SpacelrAuthError,
30
34
  SpacelrEmailVerificationRequiredError: () => SpacelrEmailVerificationRequiredError,
@@ -33,6 +37,10 @@ __export(index_exports, {
33
37
  SpacelrSearchFilterRequiredError: () => SpacelrSearchFilterRequiredError,
34
38
  SpacelrTimeoutError: () => SpacelrTimeoutError,
35
39
  SpacelrTwoFactorRequiredError: () => SpacelrTwoFactorRequiredError,
40
+ TimelineError: () => TimelineError,
41
+ TimelineModule: () => TimelineModule,
42
+ TimeoutError: () => TimeoutError,
43
+ ValidationError: () => ValidationError,
36
44
  createClient: () => createClient,
37
45
  generatePKCEChallenge: () => generatePKCEChallenge,
38
46
  localStorageCursorStorage: () => localStorageCursorStorage,
@@ -860,7 +868,7 @@ var RealtimeClient = class {
860
868
  if (!where || Object.keys(where).length === 0) {
861
869
  return base;
862
870
  }
863
- const filterStr = Object.keys(where).sort().map((k) => `${k}=${String(where[k])}`).join("&");
871
+ const filterStr = Object.keys(where).sort().map((k) => `${k}=${JSON.stringify(where[k])}`).join("&");
864
872
  return `${base}?${filterStr}`;
865
873
  }
866
874
  async ensureConnected() {
@@ -1008,15 +1016,15 @@ var RealtimeClient = class {
1008
1016
  if (room === base) return true;
1009
1017
  if (!room.startsWith(`${base}?`)) return false;
1010
1018
  const where = this.roomWhereMap.get(room);
1011
- if (!where) return true;
1019
+ if (!where) return false;
1012
1020
  if (!event.document) return false;
1013
1021
  for (const [key, value] of Object.entries(where)) {
1014
1022
  const docValue = event.document[key];
1015
1023
  if (Array.isArray(docValue)) {
1016
- if (!docValue.some((item) => String(item) === String(value))) {
1024
+ if (!docValue.includes(value)) {
1017
1025
  return false;
1018
1026
  }
1019
- } else if (String(docValue) !== String(value)) {
1027
+ } else if (docValue !== value) {
1020
1028
  return false;
1021
1029
  }
1022
1030
  }
@@ -1819,6 +1827,144 @@ var StorageModule = class {
1819
1827
  }
1820
1828
  };
1821
1829
 
1830
+ // libs/sdk/src/modules/timeline.errors.ts
1831
+ var TimelineError = class extends SpacelrError {
1832
+ constructor(message, opts = {}) {
1833
+ super(message, opts.code ?? "TIMELINE_ERROR", opts.statusCode);
1834
+ this.name = "TimelineError";
1835
+ }
1836
+ };
1837
+ var CursorInvalidError = class extends TimelineError {
1838
+ constructor(message, opts = {}) {
1839
+ super(message, { statusCode: opts.statusCode ?? 400, code: opts.code ?? "CURSOR_INVALID" });
1840
+ this.name = "CursorInvalidError";
1841
+ }
1842
+ };
1843
+ var ValidationError = class extends TimelineError {
1844
+ constructor(message, opts = {}) {
1845
+ super(message, { statusCode: opts.statusCode ?? 400, code: opts.code ?? "BAD_REQUEST" });
1846
+ this.name = "ValidationError";
1847
+ }
1848
+ };
1849
+ var ForbiddenError = class extends TimelineError {
1850
+ constructor(message, opts = {}) {
1851
+ super(message, { statusCode: opts.statusCode ?? 403, code: opts.code ?? "FORBIDDEN" });
1852
+ this.name = "ForbiddenError";
1853
+ }
1854
+ };
1855
+ var NotFoundError = class extends TimelineError {
1856
+ constructor(message, opts = {}) {
1857
+ super(message, { statusCode: opts.statusCode ?? 404, code: opts.code ?? "NOT_FOUND" });
1858
+ this.name = "NotFoundError";
1859
+ }
1860
+ };
1861
+ var ServerConfigError = class extends TimelineError {
1862
+ constructor(message, opts = {}) {
1863
+ super(message, { statusCode: opts.statusCode ?? 500, code: opts.code ?? "CONFIG_INVALID" });
1864
+ this.name = "ServerConfigError";
1865
+ }
1866
+ };
1867
+ var TimeoutError = class extends TimelineError {
1868
+ constructor(message, opts = {}) {
1869
+ super(message, { statusCode: opts.statusCode ?? 504, code: opts.code ?? "TIMEOUT" });
1870
+ this.name = "TimeoutError";
1871
+ }
1872
+ };
1873
+ function mapTimelineError(statusCode, body) {
1874
+ const code = body?.code;
1875
+ const message = body?.message ?? `Timeline request failed with HTTP ${statusCode}`;
1876
+ if (statusCode === 400) {
1877
+ if (code === "CURSOR_INVALID") {
1878
+ return new CursorInvalidError(message, { statusCode, code });
1879
+ }
1880
+ return new ValidationError(message, { statusCode, code });
1881
+ }
1882
+ if (statusCode === 403) {
1883
+ return new ForbiddenError(message, { statusCode, code });
1884
+ }
1885
+ if (statusCode === 404) {
1886
+ return new NotFoundError(message, { statusCode, code });
1887
+ }
1888
+ if (statusCode === 500) {
1889
+ return new ServerConfigError(message, { statusCode, code });
1890
+ }
1891
+ if (statusCode === 504) {
1892
+ return new TimeoutError(message, { statusCode, code });
1893
+ }
1894
+ return new TimelineError(message, { statusCode, code });
1895
+ }
1896
+
1897
+ // libs/sdk/src/modules/timeline.module.ts
1898
+ var TimelineModule = class {
1899
+ constructor(http) {
1900
+ this.http = http;
1901
+ }
1902
+ async query(opts) {
1903
+ const body = {
1904
+ collection: opts.collection,
1905
+ partitionValue: opts.partitionValue
1906
+ };
1907
+ if (opts.where !== void 0) body["where"] = opts.where;
1908
+ if (opts.orderBy !== void 0) body["orderBy"] = opts.orderBy;
1909
+ if (opts.limit !== void 0) body["limit"] = opts.limit;
1910
+ if (opts.cursor !== void 0) body["cursor"] = opts.cursor;
1911
+ let raw;
1912
+ try {
1913
+ raw = await this.http.request({
1914
+ method: "POST",
1915
+ path: "/db/timeline",
1916
+ body,
1917
+ authenticated: true
1918
+ });
1919
+ } catch (err) {
1920
+ throw this.translateError(err);
1921
+ }
1922
+ if (!isTimelineQueryResponse(raw)) {
1923
+ throw new TimelineError(
1924
+ "Timeline gateway returned a response shape the SDK does not recognise",
1925
+ { statusCode: 500, code: "INVALID_RESPONSE_SHAPE" }
1926
+ );
1927
+ }
1928
+ return raw;
1929
+ }
1930
+ translateError(err) {
1931
+ if (err instanceof SpacelrTimeoutError) {
1932
+ return new TimeoutError(err.message, { statusCode: 504, code: "TIMEOUT" });
1933
+ }
1934
+ if (err instanceof SpacelrAuthError) {
1935
+ if (err.statusCode === 403) {
1936
+ return new ForbiddenError(err.message, { statusCode: 403, code: err.code ?? "FORBIDDEN" });
1937
+ }
1938
+ return err;
1939
+ }
1940
+ if (err instanceof SpacelrNetworkError) {
1941
+ return err;
1942
+ }
1943
+ if (err instanceof SpacelrError) {
1944
+ return mapTimelineError(err.statusCode ?? 0, { code: err.code, message: err.message });
1945
+ }
1946
+ return err;
1947
+ }
1948
+ };
1949
+ function isTimelineQueryResponse(value) {
1950
+ if (typeof value !== "object" || value === null) return false;
1951
+ const v = value;
1952
+ if (!Array.isArray(v["items"])) return false;
1953
+ if (v["nextCursor"] !== null && typeof v["nextCursor"] !== "string") return false;
1954
+ if (!isTimelineSourceStats(v["sourceStats"])) return false;
1955
+ return true;
1956
+ }
1957
+ function isTimelineSourceStats(value) {
1958
+ if (typeof value !== "object" || value === null) return false;
1959
+ const v = value;
1960
+ if (typeof v["hot"] !== "number") return false;
1961
+ if (typeof v["cold"] !== "number") return false;
1962
+ if (v["segmentsScanned"] !== void 0 && typeof v["segmentsScanned"] !== "number") {
1963
+ return false;
1964
+ }
1965
+ return true;
1966
+ }
1967
+
1822
1968
  // libs/sdk/src/modules/database.module.ts
1823
1969
  var Paginator = class {
1824
1970
  constructor(http, basePath, opts) {
@@ -2002,6 +2148,16 @@ var CollectionRef = class {
2002
2148
  authenticated: true
2003
2149
  });
2004
2150
  }
2151
+ /**
2152
+ * Query the collection's **hot tier** (live MongoDB).
2153
+ *
2154
+ * **Cold-tier note:** if the collection has cold-tier archival enabled, aged
2155
+ * documents are moved to object storage and purged from the hot tier — they
2156
+ * will NOT appear in `find()` results (nor `findById`, `count`, `search`,
2157
+ * `paginate`, which are all hot-tier only). To read archived history, use
2158
+ * {@link TimelineModule.query} via `db.timeline.query(...)`, which transparently
2159
+ * merges hot and cold results for a partition.
2160
+ */
2005
2161
  find(filter) {
2006
2162
  return new QueryBuilder(this.http, this.basePath, filter);
2007
2163
  }
@@ -2036,6 +2192,9 @@ var CollectionRef = class {
2036
2192
  *
2037
2193
  * Limits: `query` 1–200 chars, `fields` 1–10 entries (each matching
2038
2194
  * `/^[a-zA-Z0-9_.]+$/`, max 64 chars), `limit` max 100.
2195
+ *
2196
+ * **Cold-tier note:** searches the hot tier only; archived documents are not
2197
+ * included. See {@link CollectionRef.find} and `db.timeline.query(...)`.
2039
2198
  */
2040
2199
  async search(opts) {
2041
2200
  return this.http.request({
@@ -2045,6 +2204,13 @@ var CollectionRef = class {
2045
2204
  authenticated: true
2046
2205
  });
2047
2206
  }
2207
+ /**
2208
+ * Fetch a single document by `_id` from the **hot tier**.
2209
+ *
2210
+ * **Cold-tier note:** returns null/throws for documents that have been
2211
+ * archived and purged from the hot tier. Archived history is reachable only
2212
+ * via `db.timeline.query(...)`. See {@link CollectionRef.find}.
2213
+ */
2048
2214
  async findById(id, options) {
2049
2215
  const query = {};
2050
2216
  if (options?.populate?.length) {
@@ -2074,6 +2240,13 @@ var CollectionRef = class {
2074
2240
  authenticated: true
2075
2241
  });
2076
2242
  }
2243
+ /**
2244
+ * Count documents in the **hot tier** matching `filter`.
2245
+ *
2246
+ * **Cold-tier note:** counts hot-tier documents only — archived/purged
2247
+ * documents are not included, so this is not a total-history count. See
2248
+ * {@link CollectionRef.find} and `db.timeline.query(...)`.
2249
+ */
2077
2250
  async count(filter) {
2078
2251
  const result = await this.http.request({
2079
2252
  method: "POST",
@@ -2509,6 +2682,7 @@ var DatabaseModule = class {
2509
2682
  this.http = http;
2510
2683
  this.projectId = projectId;
2511
2684
  this.realtime = realtime ?? null;
2685
+ this.timeline = new TimelineModule(http);
2512
2686
  }
2513
2687
  collection(name) {
2514
2688
  return new CollectionRef(this.http, this.realtime, this.projectId, name);
@@ -2707,6 +2881,65 @@ var FunctionsModule = class {
2707
2881
  }
2708
2882
  };
2709
2883
 
2884
+ // libs/sdk/src/modules/schedule.module.ts
2885
+ var ScheduleModule = class {
2886
+ constructor(http, projectId) {
2887
+ this.http = http;
2888
+ this.projectId = projectId;
2889
+ }
2890
+ /**
2891
+ * Schedule a one-shot function invocation. Returns the existing handle
2892
+ * unchanged if `idempotencyKey` matches a prior invoke in this project
2893
+ * for this function.
2894
+ */
2895
+ async invoke(options) {
2896
+ return this.http.request({
2897
+ method: "POST",
2898
+ path: `/schedules/${encodeURIComponent(this.projectId)}`,
2899
+ body: {
2900
+ functionId: options.functionId,
2901
+ executeAt: this.toIsoString(options.executeAt),
2902
+ ...options.payload !== void 0 ? { payload: options.payload } : {},
2903
+ ...options.idempotencyKey !== void 0 ? { idempotencyKey: options.idempotencyKey } : {},
2904
+ ...options.maxAttempts !== void 0 ? { maxAttempts: options.maxAttempts } : {}
2905
+ },
2906
+ authenticated: true
2907
+ });
2908
+ }
2909
+ async get(scheduleId) {
2910
+ return this.http.request({
2911
+ method: "GET",
2912
+ path: `/schedules/${encodeURIComponent(this.projectId)}/${encodeURIComponent(scheduleId)}`,
2913
+ authenticated: true
2914
+ });
2915
+ }
2916
+ async list(options = {}) {
2917
+ return this.http.request({
2918
+ method: "GET",
2919
+ path: `/schedules/${encodeURIComponent(this.projectId)}`,
2920
+ query: {
2921
+ functionId: options.functionId,
2922
+ status: options.status,
2923
+ limit: options.limit,
2924
+ offset: options.offset
2925
+ },
2926
+ authenticated: true
2927
+ });
2928
+ }
2929
+ async cancel(scheduleId) {
2930
+ return this.http.request({
2931
+ method: "DELETE",
2932
+ path: `/schedules/${encodeURIComponent(this.projectId)}/${encodeURIComponent(scheduleId)}`,
2933
+ authenticated: true
2934
+ });
2935
+ }
2936
+ toIsoString(input) {
2937
+ if (input instanceof Date) return input.toISOString();
2938
+ if (typeof input === "number") return new Date(input).toISOString();
2939
+ return input;
2940
+ }
2941
+ };
2942
+
2710
2943
  // libs/sdk/src/client.ts
2711
2944
  function createClient(config) {
2712
2945
  const tokenStorage = config.tokenStorage ?? (typeof window !== "undefined" && typeof window.localStorage !== "undefined" ? new BrowserTokenStorage() : new MemoryTokenStorage());
@@ -2725,12 +2958,14 @@ function createClient(config) {
2725
2958
  const db = new DatabaseModule(httpClient, config.projectId, realtime);
2726
2959
  const notifications = new NotificationsModule(httpClient);
2727
2960
  const functions = new FunctionsModule(httpClient);
2961
+ const schedule = new ScheduleModule(httpClient, config.projectId);
2728
2962
  return {
2729
2963
  auth,
2730
2964
  storage,
2731
2965
  db,
2732
2966
  notifications,
2733
2967
  functions,
2968
+ schedule,
2734
2969
  setTokens(tokens) {
2735
2970
  return tokenManager.setTokens(tokens);
2736
2971
  },
@@ -2758,9 +2993,13 @@ function createClient(config) {
2758
2993
  0 && (module.exports = {
2759
2994
  BrowserTokenStorage,
2760
2995
  CodeChallengeMethod,
2996
+ CursorInvalidError,
2761
2997
  FileVisibility,
2998
+ ForbiddenError,
2762
2999
  GrantType,
2763
3000
  MemoryTokenStorage,
3001
+ NotFoundError,
3002
+ ServerConfigError,
2764
3003
  SharePermission,
2765
3004
  SpacelrAuthError,
2766
3005
  SpacelrEmailVerificationRequiredError,
@@ -2769,6 +3008,10 @@ function createClient(config) {
2769
3008
  SpacelrSearchFilterRequiredError,
2770
3009
  SpacelrTimeoutError,
2771
3010
  SpacelrTwoFactorRequiredError,
3011
+ TimelineError,
3012
+ TimelineModule,
3013
+ TimeoutError,
3014
+ ValidationError,
2772
3015
  createClient,
2773
3016
  generatePKCEChallenge,
2774
3017
  localStorageCursorStorage,