nodestack-client 1.3.0 → 2.0.0

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
@@ -431,7 +431,8 @@ var FileService = class extends BaseService {
431
431
  const cleanCol = encodeURIComponent(collectionName);
432
432
  const cleanId = encodeURIComponent(recordId);
433
433
  const cleanFile = encodeURIComponent(filename);
434
- let url = `${cleanBase}/api/files/${cleanCol}/${cleanId}/${cleanFile}`;
434
+ const appSlug = options.app || this.client.appSlug;
435
+ let url = appSlug && appSlug !== "default" ? `${cleanBase}/api/apps/${encodeURIComponent(appSlug)}/files/${cleanCol}/${cleanId}/${cleanFile}` : `${cleanBase}/api/files/${cleanCol}/${cleanId}/${cleanFile}`;
435
436
  const queryParts = [];
436
437
  if (options.download) {
437
438
  queryParts.push("download=1");
@@ -504,8 +505,16 @@ var RealtimeService = class extends BaseService {
504
505
  const EventSourceClass = this.getEventSourceConstructor();
505
506
  const base = (this.client.baseUrl || "").replace(/\/+$/, "");
506
507
  let url = `${base}/api/realtime`;
508
+ const queryParams = new URLSearchParams();
507
509
  if (this.client.authStore.token) {
508
- url += `?token=${encodeURIComponent(this.client.authStore.token)}`;
510
+ queryParams.append("token", this.client.authStore.token);
511
+ }
512
+ if (this.client.appSlug) {
513
+ queryParams.append("app", this.client.appSlug);
514
+ }
515
+ const qs = queryParams.toString();
516
+ if (qs) {
517
+ url += `?${qs}`;
509
518
  }
510
519
  this.eventSource = new EventSourceClass(url);
511
520
  const handleConnect = async (event) => {
@@ -737,6 +746,8 @@ var AdminService = class extends BaseService {
737
746
 
738
747
  // src/services/CollectionService.ts
739
748
  var CollectionService = class extends BaseService {
749
+ list = this.getList.bind(this);
750
+ get = this.getOne.bind(this);
740
751
  /**
741
752
  * Retrieves all collection schema models.
742
753
  */
@@ -843,11 +854,72 @@ var DemoService = class extends BaseService {
843
854
  }
844
855
  };
845
856
 
857
+ // src/services/SnapshotService.ts
858
+ var SnapshotService = class extends BaseService {
859
+ /**
860
+ * Retrieves all snapshots, active baseline, and live drift information.
861
+ */
862
+ async list() {
863
+ return this.send("/api/snapshots", {
864
+ method: "GET"
865
+ });
866
+ }
867
+ /**
868
+ * Alias for list() to retrieve status.
869
+ */
870
+ async getStatus() {
871
+ return this.list();
872
+ }
873
+ /**
874
+ * Creates a new application state snapshot.
875
+ * If snapshot limit (10) is reached, evictOldest: true can be passed to confirm eviction of the oldest.
876
+ */
877
+ async create(options) {
878
+ return this.send("/api/snapshots", {
879
+ method: "POST",
880
+ body: options || {}
881
+ });
882
+ }
883
+ /**
884
+ * Retrieves a specific snapshot by ID.
885
+ */
886
+ async get(id) {
887
+ return this.send(`/api/snapshots/${encodeURIComponent(id)}`, {
888
+ method: "GET"
889
+ });
890
+ }
891
+ /**
892
+ * Restores application state to a specific snapshot.
893
+ * Note: Future snapshots are NOT deleted; history remains intact.
894
+ */
895
+ async restore(id) {
896
+ return this.send(`/api/snapshots/${encodeURIComponent(id)}/restore`, {
897
+ method: "POST"
898
+ });
899
+ }
900
+ /**
901
+ * Deletes a specific snapshot by ID.
902
+ */
903
+ async delete(id) {
904
+ return this.send(`/api/snapshots/${encodeURIComponent(id)}`, {
905
+ method: "DELETE"
906
+ });
907
+ }
908
+ /**
909
+ * Clears all saved snapshots.
910
+ */
911
+ async clear() {
912
+ return this.send("/api/snapshots", {
913
+ method: "DELETE"
914
+ });
915
+ }
916
+ };
917
+
846
918
  // src/services/WebhookService.ts
847
919
  function computeWebhookSignature(payload, secret) {
848
920
  const str = typeof payload === "string" ? payload : JSON.stringify(payload);
849
921
  try {
850
- const nodeCrypto = typeof __require !== "undefined" ? __require("crypto") : globalThis?.crypto;
922
+ const nodeCrypto = typeof __require !== "undefined" ? __require("crypto") : typeof globalThis !== "undefined" ? globalThis.require?.("crypto") || globalThis.crypto : null;
851
923
  if (nodeCrypto && typeof nodeCrypto.createHmac === "function") {
852
924
  return nodeCrypto.createHmac("sha256", secret).update(str, "utf8").digest("hex");
853
925
  }
@@ -871,9 +943,10 @@ function verifyWebhookSignature(payload, signatureHeader, secret) {
871
943
  }
872
944
  if (cleanHeader.length !== expected.length) return false;
873
945
  try {
874
- const nodeCrypto = typeof __require !== "undefined" ? __require("crypto") : null;
875
- if (nodeCrypto && typeof nodeCrypto.timingSafeEqual === "function" && typeof Buffer !== "undefined") {
876
- return nodeCrypto.timingSafeEqual(Buffer.from(cleanHeader, "hex"), Buffer.from(expected, "hex"));
946
+ const nodeCrypto = typeof __require !== "undefined" ? __require("crypto") : typeof globalThis !== "undefined" ? globalThis.require?.("crypto") : null;
947
+ const buf = typeof Buffer !== "undefined" ? Buffer : typeof globalThis !== "undefined" ? globalThis.Buffer : null;
948
+ if (nodeCrypto && typeof nodeCrypto.timingSafeEqual === "function" && buf) {
949
+ return nodeCrypto.timingSafeEqual(buf.from(cleanHeader, "hex"), buf.from(expected, "hex"));
877
950
  }
878
951
  } catch {
879
952
  }
@@ -1000,16 +1073,69 @@ var WebhookService = class extends BaseService {
1000
1073
  static computeSignature = computeWebhookSignature;
1001
1074
  };
1002
1075
 
1076
+ // src/services/AppService.ts
1077
+ var AppService = class extends BaseService {
1078
+ list = this.getList.bind(this);
1079
+ get = this.getOne.bind(this);
1080
+ /**
1081
+ * Retrieves all configured applications.
1082
+ */
1083
+ async getList() {
1084
+ const res = await this.send("/api/apps", {
1085
+ method: "GET"
1086
+ });
1087
+ return Array.isArray(res) ? res : res?.items || [];
1088
+ }
1089
+ /**
1090
+ * Retrieves a single application by ID or slug.
1091
+ */
1092
+ async getOne(appId) {
1093
+ return this.send(`/api/apps/${encodeURIComponent(appId)}`, {
1094
+ method: "GET"
1095
+ });
1096
+ }
1097
+ /**
1098
+ * Creates a new application.
1099
+ */
1100
+ async create(data) {
1101
+ return this.send("/api/apps", {
1102
+ method: "POST",
1103
+ body: data
1104
+ });
1105
+ }
1106
+ /**
1107
+ * Updates an existing application.
1108
+ */
1109
+ async update(appId, data) {
1110
+ return this.send(`/api/apps/${encodeURIComponent(appId)}`, {
1111
+ method: "PATCH",
1112
+ body: data
1113
+ });
1114
+ }
1115
+ /**
1116
+ * Deletes an application by ID or slug.
1117
+ */
1118
+ async delete(appId) {
1119
+ await this.send(`/api/apps/${encodeURIComponent(appId)}`, {
1120
+ method: "DELETE"
1121
+ });
1122
+ return true;
1123
+ }
1124
+ };
1125
+
1003
1126
  // src/Client.ts
1004
- var NodeStackClient = class {
1127
+ var NodeStackClient = class _NodeStackClient {
1005
1128
  baseUrl;
1006
1129
  authStore;
1007
1130
  files;
1008
1131
  realtime;
1009
1132
  admins;
1010
1133
  collections;
1134
+ snapshots;
1011
1135
  demo;
1012
1136
  webhooks;
1137
+ apps;
1138
+ appSlug;
1013
1139
  customFetch;
1014
1140
  defaultHeaders;
1015
1141
  defaultTimeout;
@@ -1022,12 +1148,15 @@ var NodeStackClient = class {
1022
1148
  this.defaultHeaders = options.headers || {};
1023
1149
  this.defaultTimeout = options.timeout || 12e4;
1024
1150
  this.chaosOptions = options.chaos ? { ...options.chaos } : null;
1151
+ this.appSlug = options.app;
1025
1152
  this.files = new FileService(this);
1026
1153
  this.realtime = new RealtimeService(this, options.EventSource);
1027
1154
  this.admins = new AdminService(this);
1028
1155
  this.collections = new CollectionService(this);
1156
+ this.snapshots = new SnapshotService(this);
1029
1157
  this.demo = new DemoService(this);
1030
1158
  this.webhooks = new WebhookService(this);
1159
+ this.apps = new AppService(this);
1031
1160
  }
1032
1161
  /**
1033
1162
  * Dynamically configure latency & chaos simulation options for all future requests.
@@ -1081,6 +1210,9 @@ var NodeStackClient = class {
1081
1210
  if (this.authStore.token && !headers["Authorization"] && !headers["authorization"]) {
1082
1211
  headers["Authorization"] = `Bearer ${this.authStore.token}`;
1083
1212
  }
1213
+ if (this.appSlug && !headers["x-nodestack-app"] && !headers["X-NodeStack-App"]) {
1214
+ headers["x-nodestack-app"] = this.appSlug;
1215
+ }
1084
1216
  const effectiveChaos = {
1085
1217
  ...this.chaosOptions || {},
1086
1218
  ...options.chaos || {},
@@ -1197,6 +1329,21 @@ var NodeStackClient = class {
1197
1329
  async metrics() {
1198
1330
  return this.send("/api/metrics", { method: "GET" });
1199
1331
  }
1332
+ /**
1333
+ * Returns a new NodeStackClient instance scoped to a specific application/MVP.
1334
+ * Inherits baseUrl, authStore, customFetch, defaultHeaders, and defaultTimeout.
1335
+ */
1336
+ app(slug, options = {}) {
1337
+ return new _NodeStackClient(this.baseUrl, {
1338
+ authStore: options.authStore || this.authStore,
1339
+ fetch: options.fetch || this.customFetch,
1340
+ headers: { ...this.defaultHeaders, ...options.headers || {} },
1341
+ timeout: options.timeout !== void 0 ? options.timeout : this.defaultTimeout,
1342
+ chaos: options.chaos !== void 0 ? options.chaos ? { ...options.chaos } : void 0 : this.chaosOptions ? { ...this.chaosOptions } : void 0,
1343
+ app: slug,
1344
+ EventSource: options.EventSource || this.realtime.customEventSource
1345
+ });
1346
+ }
1200
1347
  };
1201
1348
 
1202
1349
  // src/auth/MemoryAuthStore.ts
@@ -1205,6 +1352,7 @@ var MemoryAuthStore = class extends BaseAuthStore {
1205
1352
  };
1206
1353
  export {
1207
1354
  AdminService,
1355
+ AppService,
1208
1356
  BaseAuthStore,
1209
1357
  BaseService,
1210
1358
  ClientResponseError,
@@ -1216,6 +1364,7 @@ export {
1216
1364
  NodeStackClient,
1217
1365
  RealtimeService,
1218
1366
  RecordService,
1367
+ SnapshotService,
1219
1368
  WebhookService,
1220
1369
  computeWebhookSignature,
1221
1370
  decodeJwtPayload,