nodestack-client 1.2.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/README.md +120 -7
- package/dist/Client.d.ts +12 -0
- package/dist/Client.d.ts.map +1 -1
- package/dist/auth/BaseAuthStore.d.ts.map +1 -1
- package/dist/auth/LocalAuthStore.d.ts.map +1 -1
- package/dist/errors/ClientResponseError.d.ts.map +1 -1
- package/dist/index.cjs +315 -4
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +322 -4
- package/dist/index.mjs.map +3 -3
- package/dist/services/AdminService.d.ts.map +1 -1
- package/dist/services/AppService.d.ts +30 -0
- package/dist/services/AppService.d.ts.map +1 -0
- package/dist/services/BaseService.d.ts +1 -0
- package/dist/services/BaseService.d.ts.map +1 -1
- package/dist/services/CollectionService.d.ts +2 -0
- package/dist/services/CollectionService.d.ts.map +1 -1
- package/dist/services/DemoService.d.ts.map +1 -1
- package/dist/services/FileService.d.ts +1 -0
- package/dist/services/FileService.d.ts.map +1 -1
- package/dist/services/RealtimeService.d.ts.map +1 -1
- package/dist/services/RecordService.d.ts.map +1 -1
- package/dist/services/SnapshotService.d.ts +38 -0
- package/dist/services/SnapshotService.d.ts.map +1 -0
- package/dist/services/WebhookService.d.ts +72 -0
- package/dist/services/WebhookService.d.ts.map +1 -0
- package/dist/types.d.ts +151 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -5
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
1
8
|
// src/auth/BaseAuthStore.ts
|
|
2
9
|
function decodeJwtPayload(token) {
|
|
3
10
|
if (!token || typeof token !== "string") return null;
|
|
@@ -424,7 +431,8 @@ var FileService = class extends BaseService {
|
|
|
424
431
|
const cleanCol = encodeURIComponent(collectionName);
|
|
425
432
|
const cleanId = encodeURIComponent(recordId);
|
|
426
433
|
const cleanFile = encodeURIComponent(filename);
|
|
427
|
-
|
|
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}`;
|
|
428
436
|
const queryParts = [];
|
|
429
437
|
if (options.download) {
|
|
430
438
|
queryParts.push("download=1");
|
|
@@ -497,8 +505,16 @@ var RealtimeService = class extends BaseService {
|
|
|
497
505
|
const EventSourceClass = this.getEventSourceConstructor();
|
|
498
506
|
const base = (this.client.baseUrl || "").replace(/\/+$/, "");
|
|
499
507
|
let url = `${base}/api/realtime`;
|
|
508
|
+
const queryParams = new URLSearchParams();
|
|
500
509
|
if (this.client.authStore.token) {
|
|
501
|
-
|
|
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}`;
|
|
502
518
|
}
|
|
503
519
|
this.eventSource = new EventSourceClass(url);
|
|
504
520
|
const handleConnect = async (event) => {
|
|
@@ -730,6 +746,8 @@ var AdminService = class extends BaseService {
|
|
|
730
746
|
|
|
731
747
|
// src/services/CollectionService.ts
|
|
732
748
|
var CollectionService = class extends BaseService {
|
|
749
|
+
list = this.getList.bind(this);
|
|
750
|
+
get = this.getOne.bind(this);
|
|
733
751
|
/**
|
|
734
752
|
* Retrieves all collection schema models.
|
|
735
753
|
*/
|
|
@@ -836,15 +854,288 @@ var DemoService = class extends BaseService {
|
|
|
836
854
|
}
|
|
837
855
|
};
|
|
838
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
|
+
|
|
918
|
+
// src/services/WebhookService.ts
|
|
919
|
+
function computeWebhookSignature(payload, secret) {
|
|
920
|
+
const str = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
921
|
+
try {
|
|
922
|
+
const nodeCrypto = typeof __require !== "undefined" ? __require("crypto") : typeof globalThis !== "undefined" ? globalThis.require?.("crypto") || globalThis.crypto : null;
|
|
923
|
+
if (nodeCrypto && typeof nodeCrypto.createHmac === "function") {
|
|
924
|
+
return nodeCrypto.createHmac("sha256", secret).update(str, "utf8").digest("hex");
|
|
925
|
+
}
|
|
926
|
+
} catch {
|
|
927
|
+
}
|
|
928
|
+
throw new Error("[NodeStackClient] HMAC-SHA256 computation requires crypto module.");
|
|
929
|
+
}
|
|
930
|
+
function verifyWebhookSignature(payload, signatureHeader, secret) {
|
|
931
|
+
if (!signatureHeader || !secret) return false;
|
|
932
|
+
let expected = "";
|
|
933
|
+
try {
|
|
934
|
+
expected = computeWebhookSignature(payload, secret);
|
|
935
|
+
} catch {
|
|
936
|
+
return false;
|
|
937
|
+
}
|
|
938
|
+
let cleanHeader = signatureHeader.trim();
|
|
939
|
+
if (cleanHeader.startsWith("sha256=")) {
|
|
940
|
+
cleanHeader = cleanHeader.substring(7);
|
|
941
|
+
} else if (cleanHeader.startsWith("sha256:")) {
|
|
942
|
+
cleanHeader = cleanHeader.substring(7);
|
|
943
|
+
}
|
|
944
|
+
if (cleanHeader.length !== expected.length) return false;
|
|
945
|
+
try {
|
|
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"));
|
|
950
|
+
}
|
|
951
|
+
} catch {
|
|
952
|
+
}
|
|
953
|
+
let diff = 0;
|
|
954
|
+
for (let i = 0; i < cleanHeader.length; i++) {
|
|
955
|
+
diff |= cleanHeader.charCodeAt(i) ^ expected.charCodeAt(i);
|
|
956
|
+
}
|
|
957
|
+
return diff === 0;
|
|
958
|
+
}
|
|
959
|
+
var WebhookService = class extends BaseService {
|
|
960
|
+
/**
|
|
961
|
+
* Retrieves all configured outbound webhooks.
|
|
962
|
+
*/
|
|
963
|
+
async getList(options = {}) {
|
|
964
|
+
const res = await this.send("/api/webhooks", {
|
|
965
|
+
method: "GET",
|
|
966
|
+
query: options
|
|
967
|
+
});
|
|
968
|
+
return Array.isArray(res) ? res : [];
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Retrieves a single webhook by ID.
|
|
972
|
+
*/
|
|
973
|
+
async getOne(id) {
|
|
974
|
+
return this.send(`/api/webhooks/${encodeURIComponent(id)}`, {
|
|
975
|
+
method: "GET"
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Creates a new outbound webhook configuration.
|
|
980
|
+
*/
|
|
981
|
+
async create(data) {
|
|
982
|
+
return this.send("/api/webhooks", {
|
|
983
|
+
method: "POST",
|
|
984
|
+
body: data
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Updates an existing webhook configuration.
|
|
989
|
+
*/
|
|
990
|
+
async update(id, data) {
|
|
991
|
+
return this.send(`/api/webhooks/${encodeURIComponent(id)}`, {
|
|
992
|
+
method: "PATCH",
|
|
993
|
+
body: data
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Deletes a configured webhook by ID.
|
|
998
|
+
*/
|
|
999
|
+
async delete(id) {
|
|
1000
|
+
await this.send(`/api/webhooks/${encodeURIComponent(id)}`, {
|
|
1001
|
+
method: "DELETE"
|
|
1002
|
+
});
|
|
1003
|
+
return true;
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Dispatches a live test event to the target webhook endpoint with an optional payload.
|
|
1007
|
+
*/
|
|
1008
|
+
async test(id, payload) {
|
|
1009
|
+
return this.send(`/api/webhooks/${encodeURIComponent(id)}/test`, {
|
|
1010
|
+
method: "POST",
|
|
1011
|
+
body: payload !== void 0 ? { payload } : {}
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Retrieves overall webhook health and delivery statistics.
|
|
1016
|
+
*/
|
|
1017
|
+
async getStats() {
|
|
1018
|
+
return this.send("/api/webhooks/stats", {
|
|
1019
|
+
method: "GET"
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Queries paginated webhook delivery logs with optional filtering by webhook ID, collection, status, or search.
|
|
1024
|
+
*/
|
|
1025
|
+
async getDeliveries(options = {}) {
|
|
1026
|
+
return this.send("/api/webhooks/deliveries", {
|
|
1027
|
+
method: "GET",
|
|
1028
|
+
query: options
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Retrieves complete delivery log details including headers and request/response payloads.
|
|
1033
|
+
*/
|
|
1034
|
+
async getDelivery(id) {
|
|
1035
|
+
return this.send(`/api/webhooks/deliveries/${encodeURIComponent(id)}`, {
|
|
1036
|
+
method: "GET"
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Manually retries a failed delivery attempt to its target endpoint.
|
|
1041
|
+
*/
|
|
1042
|
+
async retryDelivery(id) {
|
|
1043
|
+
return this.send(`/api/webhooks/deliveries/${encodeURIComponent(id)}/retry`, {
|
|
1044
|
+
method: "POST"
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Clears delivery history logs. If olderThanDays is specified, only deletes logs older than that many days.
|
|
1049
|
+
*/
|
|
1050
|
+
async clearDeliveries(olderThanDays) {
|
|
1051
|
+
const query = {};
|
|
1052
|
+
if (olderThanDays !== void 0 && olderThanDays !== null) {
|
|
1053
|
+
query.olderThanDays = olderThanDays;
|
|
1054
|
+
}
|
|
1055
|
+
return this.send("/api/webhooks/deliveries", {
|
|
1056
|
+
method: "DELETE",
|
|
1057
|
+
query
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Verifies an incoming X-NodeStack-Signature header against the expected secret.
|
|
1062
|
+
*/
|
|
1063
|
+
verifySignature(payload, signatureHeader, secret) {
|
|
1064
|
+
return verifyWebhookSignature(payload, signatureHeader, secret);
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Computes an HMAC-SHA256 signature for a payload and secret string.
|
|
1068
|
+
*/
|
|
1069
|
+
computeSignature(payload, secret) {
|
|
1070
|
+
return computeWebhookSignature(payload, secret);
|
|
1071
|
+
}
|
|
1072
|
+
static verifySignature = verifyWebhookSignature;
|
|
1073
|
+
static computeSignature = computeWebhookSignature;
|
|
1074
|
+
};
|
|
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
|
+
|
|
839
1126
|
// src/Client.ts
|
|
840
|
-
var NodeStackClient = class {
|
|
1127
|
+
var NodeStackClient = class _NodeStackClient {
|
|
841
1128
|
baseUrl;
|
|
842
1129
|
authStore;
|
|
843
1130
|
files;
|
|
844
1131
|
realtime;
|
|
845
1132
|
admins;
|
|
846
1133
|
collections;
|
|
1134
|
+
snapshots;
|
|
847
1135
|
demo;
|
|
1136
|
+
webhooks;
|
|
1137
|
+
apps;
|
|
1138
|
+
appSlug;
|
|
848
1139
|
customFetch;
|
|
849
1140
|
defaultHeaders;
|
|
850
1141
|
defaultTimeout;
|
|
@@ -857,11 +1148,15 @@ var NodeStackClient = class {
|
|
|
857
1148
|
this.defaultHeaders = options.headers || {};
|
|
858
1149
|
this.defaultTimeout = options.timeout || 12e4;
|
|
859
1150
|
this.chaosOptions = options.chaos ? { ...options.chaos } : null;
|
|
1151
|
+
this.appSlug = options.app;
|
|
860
1152
|
this.files = new FileService(this);
|
|
861
1153
|
this.realtime = new RealtimeService(this, options.EventSource);
|
|
862
1154
|
this.admins = new AdminService(this);
|
|
863
1155
|
this.collections = new CollectionService(this);
|
|
1156
|
+
this.snapshots = new SnapshotService(this);
|
|
864
1157
|
this.demo = new DemoService(this);
|
|
1158
|
+
this.webhooks = new WebhookService(this);
|
|
1159
|
+
this.apps = new AppService(this);
|
|
865
1160
|
}
|
|
866
1161
|
/**
|
|
867
1162
|
* Dynamically configure latency & chaos simulation options for all future requests.
|
|
@@ -915,6 +1210,9 @@ var NodeStackClient = class {
|
|
|
915
1210
|
if (this.authStore.token && !headers["Authorization"] && !headers["authorization"]) {
|
|
916
1211
|
headers["Authorization"] = `Bearer ${this.authStore.token}`;
|
|
917
1212
|
}
|
|
1213
|
+
if (this.appSlug && !headers["x-nodestack-app"] && !headers["X-NodeStack-App"]) {
|
|
1214
|
+
headers["x-nodestack-app"] = this.appSlug;
|
|
1215
|
+
}
|
|
918
1216
|
const effectiveChaos = {
|
|
919
1217
|
...this.chaosOptions || {},
|
|
920
1218
|
...options.chaos || {},
|
|
@@ -1031,6 +1329,21 @@ var NodeStackClient = class {
|
|
|
1031
1329
|
async metrics() {
|
|
1032
1330
|
return this.send("/api/metrics", { method: "GET" });
|
|
1033
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
|
+
}
|
|
1034
1347
|
};
|
|
1035
1348
|
|
|
1036
1349
|
// src/auth/MemoryAuthStore.ts
|
|
@@ -1039,6 +1352,7 @@ var MemoryAuthStore = class extends BaseAuthStore {
|
|
|
1039
1352
|
};
|
|
1040
1353
|
export {
|
|
1041
1354
|
AdminService,
|
|
1355
|
+
AppService,
|
|
1042
1356
|
BaseAuthStore,
|
|
1043
1357
|
BaseService,
|
|
1044
1358
|
ClientResponseError,
|
|
@@ -1050,7 +1364,11 @@ export {
|
|
|
1050
1364
|
NodeStackClient,
|
|
1051
1365
|
RealtimeService,
|
|
1052
1366
|
RecordService,
|
|
1367
|
+
SnapshotService,
|
|
1368
|
+
WebhookService,
|
|
1369
|
+
computeWebhookSignature,
|
|
1053
1370
|
decodeJwtPayload,
|
|
1054
|
-
NodeStackClient as default
|
|
1371
|
+
NodeStackClient as default,
|
|
1372
|
+
verifyWebhookSignature
|
|
1055
1373
|
};
|
|
1056
1374
|
//# sourceMappingURL=index.mjs.map
|