@calimero-network/mero-js 1.1.0 → 1.2.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/admin-api/admin-client.d.ts +29 -27
- package/dist/admin-api/admin-client.d.ts.map +1 -1
- package/dist/admin-api/admin-client.js +70 -58
- package/dist/admin-api/admin-client.js.map +1 -1
- package/dist/admin-api/admin-types.d.ts +57 -159
- package/dist/admin-api/admin-types.d.ts.map +1 -1
- package/dist/admin-api/admin-types.js +1 -1
- package/dist/admin-api/admin-types.js.map +1 -1
- package/dist/auth/index.d.ts +26 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +51 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/events/index.d.ts +5 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +3 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/sse.d.ts +41 -0
- package/dist/events/sse.d.ts.map +1 -0
- package/dist/events/sse.js +237 -0
- package/dist/events/sse.js.map +1 -0
- package/dist/events/ws.d.ts +42 -0
- package/dist/events/ws.d.ts.map +1 -0
- package/dist/events/ws.js +178 -0
- package/dist/events/ws.js.map +1 -0
- package/dist/http-client/web-client.d.ts.map +1 -1
- package/dist/http-client/web-client.js +2 -4
- package/dist/http-client/web-client.js.map +1 -1
- package/dist/index.browser.mjs +2 -1
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +705 -88
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +705 -88
- package/dist/index.mjs.map +3 -3
- package/dist/mero-js.d.ts +47 -1
- package/dist/mero-js.d.ts.map +1 -1
- package/dist/mero-js.js +132 -16
- package/dist/mero-js.js.map +1 -1
- package/dist/rpc/index.d.ts +21 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +39 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/token-store/index.d.ts +20 -0
- package/dist/token-store/index.d.ts.map +1 -0
- package/dist/token-store/index.js +62 -0
- package/dist/token-store/index.js.map +1 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -22,8 +22,15 @@ __export(index_exports, {
|
|
|
22
22
|
AdminApiClient: () => AdminApiClient,
|
|
23
23
|
AuthApiClient: () => AuthApiClient,
|
|
24
24
|
HTTPError: () => HTTPError,
|
|
25
|
+
LocalStorageTokenStore: () => LocalStorageTokenStore,
|
|
26
|
+
MemoryTokenStore: () => MemoryTokenStore,
|
|
25
27
|
MeroJs: () => MeroJs,
|
|
28
|
+
RpcClient: () => RpcClient,
|
|
29
|
+
RpcError: () => RpcError,
|
|
30
|
+
SseClient: () => SseClient,
|
|
26
31
|
WebHttpClient: () => WebHttpClient,
|
|
32
|
+
WsClient: () => WsClient,
|
|
33
|
+
buildAuthLoginUrl: () => buildAuthLoginUrl,
|
|
27
34
|
combineSignals: () => combineSignals,
|
|
28
35
|
createAdminApiClient: () => createAdminApiClient,
|
|
29
36
|
createAdminApiClientFromHttpClient: () => createAdminApiClientFromHttpClient,
|
|
@@ -40,6 +47,7 @@ __export(index_exports, {
|
|
|
40
47
|
createRetryableMethod: () => createRetryableMethod,
|
|
41
48
|
createTimeoutSignal: () => createTimeoutSignal,
|
|
42
49
|
createUniversalHttpClient: () => createUniversalHttpClient,
|
|
50
|
+
parseAuthCallback: () => parseAuthCallback,
|
|
43
51
|
withRetry: () => withRetry
|
|
44
52
|
});
|
|
45
53
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -243,8 +251,7 @@ var WebHttpClient = class {
|
|
|
243
251
|
bodyText
|
|
244
252
|
);
|
|
245
253
|
const userAborted = init?.signal?.aborted === true;
|
|
246
|
-
if (response.status === 401 && this.transport.refreshToken && response.headers.get("x-auth-error") === "token_expired" && retryCount < MAX_RETRY_ATTEMPTS && !isStreamBody &&
|
|
247
|
-
!userAborted) {
|
|
254
|
+
if (response.status === 401 && this.transport.refreshToken && response.headers.get("x-auth-error") === "token_expired" && retryCount < MAX_RETRY_ATTEMPTS && !isStreamBody && !userAborted) {
|
|
248
255
|
try {
|
|
249
256
|
let refreshPromise = this.refreshTokenPromise;
|
|
250
257
|
if (!refreshPromise) {
|
|
@@ -682,122 +689,117 @@ function createAuthApiClientFromHttpClient(httpClient, _config) {
|
|
|
682
689
|
}
|
|
683
690
|
|
|
684
691
|
// src/admin-api/admin-client.ts
|
|
692
|
+
function unwrap(response) {
|
|
693
|
+
return response.data;
|
|
694
|
+
}
|
|
685
695
|
var AdminApiClient = class {
|
|
686
696
|
constructor(httpClient) {
|
|
687
697
|
this.httpClient = httpClient;
|
|
688
698
|
}
|
|
689
|
-
// Health and Status
|
|
699
|
+
// ---- Health and Status (public, no auth) ----
|
|
690
700
|
async healthCheck() {
|
|
691
|
-
|
|
692
|
-
if (!response.data) {
|
|
693
|
-
throw new Error("Health response data is null");
|
|
694
|
-
}
|
|
695
|
-
return response.data;
|
|
701
|
+
return unwrap(await this.httpClient.get("/admin-api/health"));
|
|
696
702
|
}
|
|
697
703
|
async isAuthed() {
|
|
698
|
-
return this.httpClient.get("/is-authed");
|
|
704
|
+
return this.httpClient.get("/admin-api/is-authed");
|
|
699
705
|
}
|
|
700
|
-
// Application Management
|
|
706
|
+
// ---- Application Management ----
|
|
701
707
|
async installApplication(request) {
|
|
702
|
-
return this.httpClient.post(
|
|
703
|
-
"/install-application",
|
|
704
|
-
request
|
|
705
|
-
);
|
|
708
|
+
return unwrap(await this.httpClient.post("/admin-api/install-application", request));
|
|
706
709
|
}
|
|
707
710
|
async installDevApplication(request) {
|
|
708
|
-
return this.httpClient.post(
|
|
709
|
-
"/install-dev-application",
|
|
710
|
-
request
|
|
711
|
-
);
|
|
711
|
+
return unwrap(await this.httpClient.post("/admin-api/install-dev-application", request));
|
|
712
712
|
}
|
|
713
713
|
async uninstallApplication(appId) {
|
|
714
|
-
return this.httpClient.delete(
|
|
715
|
-
`/applications/${appId}`
|
|
716
|
-
);
|
|
714
|
+
return unwrap(await this.httpClient.delete(`/admin-api/applications/${appId}`));
|
|
717
715
|
}
|
|
718
716
|
async listApplications() {
|
|
719
|
-
return this.httpClient.get("/applications");
|
|
717
|
+
return unwrap(await this.httpClient.get("/admin-api/applications"));
|
|
720
718
|
}
|
|
721
719
|
async getApplication(appId) {
|
|
720
|
+
return unwrap(await this.httpClient.get(`/admin-api/applications/${appId}`));
|
|
721
|
+
}
|
|
722
|
+
// ---- Package Management ----
|
|
723
|
+
async getLatestPackageVersion(packageName) {
|
|
722
724
|
return this.httpClient.get(
|
|
723
|
-
`/
|
|
725
|
+
`/admin-api/packages/${encodeURIComponent(packageName)}/latest`
|
|
724
726
|
);
|
|
725
727
|
}
|
|
726
|
-
// Context Management
|
|
728
|
+
// ---- Context Management ----
|
|
727
729
|
async createContext(request) {
|
|
728
|
-
return this.httpClient.post("/contexts", request);
|
|
730
|
+
return unwrap(await this.httpClient.post("/admin-api/contexts", request));
|
|
729
731
|
}
|
|
730
732
|
async deleteContext(contextId) {
|
|
731
|
-
return this.httpClient.delete(
|
|
732
|
-
`/contexts/${contextId}`
|
|
733
|
-
);
|
|
733
|
+
return unwrap(await this.httpClient.delete(`/admin-api/contexts/${contextId}`));
|
|
734
734
|
}
|
|
735
735
|
async getContexts() {
|
|
736
|
-
return this.httpClient.get("/contexts");
|
|
736
|
+
return unwrap(await this.httpClient.get("/admin-api/contexts"));
|
|
737
737
|
}
|
|
738
738
|
async getContext(contextId) {
|
|
739
|
-
return this.httpClient.get(`/contexts/${contextId}`);
|
|
739
|
+
return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}`));
|
|
740
740
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
return this.httpClient.post("/blobs", request);
|
|
741
|
+
async getContextsForApplication(applicationId) {
|
|
742
|
+
return unwrap(await this.httpClient.get(`/admin-api/contexts/for-application/${applicationId}`));
|
|
744
743
|
}
|
|
745
|
-
|
|
746
|
-
|
|
744
|
+
// ---- Context Identity ----
|
|
745
|
+
async generateContextIdentity() {
|
|
746
|
+
return unwrap(await this.httpClient.post("/admin-api/identity/context", {}));
|
|
747
747
|
}
|
|
748
|
-
async
|
|
749
|
-
return this.httpClient.get(
|
|
748
|
+
async getContextIdentities(contextId) {
|
|
749
|
+
return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}/identities`));
|
|
750
750
|
}
|
|
751
|
-
async
|
|
752
|
-
return this.httpClient.get(`/
|
|
751
|
+
async getContextIdentitiesOwned(contextId) {
|
|
752
|
+
return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}/identities-owned`));
|
|
753
753
|
}
|
|
754
|
-
//
|
|
755
|
-
async
|
|
756
|
-
return this.httpClient.post("/
|
|
754
|
+
// ---- Context Invite / Join ----
|
|
755
|
+
async inviteToContext(request) {
|
|
756
|
+
return unwrap(await this.httpClient.post("/admin-api/contexts/invite", request));
|
|
757
757
|
}
|
|
758
|
-
async
|
|
759
|
-
return this.httpClient.
|
|
758
|
+
async joinContext(request) {
|
|
759
|
+
return unwrap(await this.httpClient.post("/admin-api/contexts/join", request));
|
|
760
760
|
}
|
|
761
|
-
|
|
762
|
-
|
|
761
|
+
// ---- Blob Management ----
|
|
762
|
+
async uploadBlob(data) {
|
|
763
|
+
return unwrap(await this.httpClient.put("/admin-api/blobs", data));
|
|
763
764
|
}
|
|
764
|
-
async
|
|
765
|
-
return this.httpClient.
|
|
765
|
+
async deleteBlob(blobId) {
|
|
766
|
+
return unwrap(await this.httpClient.delete(`/admin-api/blobs/${blobId}`));
|
|
766
767
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
return this.httpClient.get("/network/peers");
|
|
768
|
+
async listBlobs() {
|
|
769
|
+
return unwrap(await this.httpClient.get("/admin-api/blobs"));
|
|
770
770
|
}
|
|
771
|
-
async
|
|
772
|
-
return this.httpClient.get(
|
|
771
|
+
async getBlob(blobId) {
|
|
772
|
+
return unwrap(await this.httpClient.get(`/admin-api/blobs/${blobId}`));
|
|
773
773
|
}
|
|
774
|
-
|
|
775
|
-
|
|
774
|
+
// ---- Alias Management ----
|
|
775
|
+
// Server uses type-specific alias routes: /admin-api/alias/{create,lookup,delete,list}/{context,application}
|
|
776
|
+
async createContextAlias(request) {
|
|
777
|
+
return this.httpClient.post("/admin-api/alias/create/context", request);
|
|
776
778
|
}
|
|
777
|
-
async
|
|
778
|
-
return this.httpClient.
|
|
779
|
-
"/network/config",
|
|
780
|
-
request
|
|
781
|
-
);
|
|
779
|
+
async createApplicationAlias(request) {
|
|
780
|
+
return this.httpClient.post("/admin-api/alias/create/application", request);
|
|
782
781
|
}
|
|
783
|
-
async
|
|
784
|
-
return this.httpClient.
|
|
782
|
+
async lookupContextAlias(name) {
|
|
783
|
+
return this.httpClient.post(`/admin-api/alias/lookup/context/${encodeURIComponent(name)}`, {});
|
|
784
|
+
}
|
|
785
|
+
async lookupApplicationAlias(name) {
|
|
786
|
+
return this.httpClient.post(`/admin-api/alias/lookup/application/${encodeURIComponent(name)}`, {});
|
|
785
787
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
return this.httpClient.get("/system/info");
|
|
788
|
+
async deleteContextAlias(name) {
|
|
789
|
+
return this.httpClient.post(`/admin-api/alias/delete/context/${encodeURIComponent(name)}`, {});
|
|
789
790
|
}
|
|
790
|
-
async
|
|
791
|
-
return this.httpClient.
|
|
791
|
+
async deleteApplicationAlias(name) {
|
|
792
|
+
return this.httpClient.post(`/admin-api/alias/delete/application/${encodeURIComponent(name)}`, {});
|
|
792
793
|
}
|
|
793
|
-
async
|
|
794
|
-
return this.httpClient.get("/
|
|
794
|
+
async listContextAliases() {
|
|
795
|
+
return unwrap(await this.httpClient.get("/admin-api/alias/list/context"));
|
|
795
796
|
}
|
|
796
|
-
async
|
|
797
|
-
return this.httpClient.
|
|
797
|
+
async listApplicationAliases() {
|
|
798
|
+
return unwrap(await this.httpClient.get("/admin-api/alias/list/application"));
|
|
798
799
|
}
|
|
799
|
-
|
|
800
|
-
|
|
800
|
+
// ---- Network ----
|
|
801
|
+
async getPeersCount() {
|
|
802
|
+
return this.httpClient.get("/admin-api/peers");
|
|
801
803
|
}
|
|
802
804
|
};
|
|
803
805
|
|
|
@@ -855,15 +857,495 @@ function createAdminApiClientFromHttpClient(httpClient, _config) {
|
|
|
855
857
|
return new AdminApiClient(httpClient);
|
|
856
858
|
}
|
|
857
859
|
|
|
860
|
+
// src/auth/index.ts
|
|
861
|
+
function parseAuthCallback(url) {
|
|
862
|
+
try {
|
|
863
|
+
const hashIndex = url.indexOf("#");
|
|
864
|
+
if (hashIndex === -1) return null;
|
|
865
|
+
const hash = url.substring(hashIndex + 1);
|
|
866
|
+
const params = new URLSearchParams(hash);
|
|
867
|
+
const accessToken = params.get("access_token");
|
|
868
|
+
if (!accessToken) return null;
|
|
869
|
+
return {
|
|
870
|
+
accessToken,
|
|
871
|
+
refreshToken: params.get("refresh_token") ?? "",
|
|
872
|
+
applicationId: params.get("application_id") ?? "",
|
|
873
|
+
contextId: params.get("context_id") ?? "",
|
|
874
|
+
contextIdentity: params.get("context_identity") ?? "",
|
|
875
|
+
nodeUrl: params.get("node_url") ?? ""
|
|
876
|
+
};
|
|
877
|
+
} catch {
|
|
878
|
+
return null;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
function buildAuthLoginUrl(nodeUrl, opts) {
|
|
882
|
+
const params = new URLSearchParams();
|
|
883
|
+
params.set("callback-url", opts.callbackUrl);
|
|
884
|
+
if (opts.permissions && opts.permissions.length > 0) {
|
|
885
|
+
params.set("permissions", opts.permissions.join(","));
|
|
886
|
+
}
|
|
887
|
+
params.set("mode", opts.mode);
|
|
888
|
+
if (opts.packageName) {
|
|
889
|
+
params.set("package-name", opts.packageName);
|
|
890
|
+
if (opts.packageVersion) {
|
|
891
|
+
params.set("package-version", opts.packageVersion);
|
|
892
|
+
}
|
|
893
|
+
if (opts.registryUrl) {
|
|
894
|
+
params.set("registry-url", opts.registryUrl);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
const base = nodeUrl.replace(/\/+$/, "");
|
|
898
|
+
return `${base}/auth/login?${params.toString()}`;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// src/rpc/index.ts
|
|
902
|
+
var RpcError = class extends Error {
|
|
903
|
+
constructor(code, message, data, type) {
|
|
904
|
+
super(message);
|
|
905
|
+
this.name = "RpcError";
|
|
906
|
+
this.code = code;
|
|
907
|
+
this.data = data;
|
|
908
|
+
this.type = type;
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
var RpcClient = class {
|
|
912
|
+
constructor(opts) {
|
|
913
|
+
this.httpClient = opts.httpClient;
|
|
914
|
+
}
|
|
915
|
+
async execute(params) {
|
|
916
|
+
const body = {
|
|
917
|
+
jsonrpc: "2.0",
|
|
918
|
+
id: 1,
|
|
919
|
+
method: "execute",
|
|
920
|
+
params: {
|
|
921
|
+
contextId: params.contextId,
|
|
922
|
+
method: params.method,
|
|
923
|
+
argsJson: params.argsJson ?? {},
|
|
924
|
+
executorPublicKey: params.executorPublicKey
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
const response = await this.httpClient.post(
|
|
928
|
+
"/jsonrpc",
|
|
929
|
+
body
|
|
930
|
+
);
|
|
931
|
+
if (response.error) {
|
|
932
|
+
const err = response.error;
|
|
933
|
+
const code = err.code ?? -1;
|
|
934
|
+
const message = err.message ?? err.type ?? "RPC error";
|
|
935
|
+
throw new RpcError(code, message, err.data, err.type);
|
|
936
|
+
}
|
|
937
|
+
if (response.result && "output" in response.result) {
|
|
938
|
+
return response.result.output;
|
|
939
|
+
}
|
|
940
|
+
return response.result;
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
// src/events/sse.ts
|
|
945
|
+
var SseClient = class {
|
|
946
|
+
constructor(opts) {
|
|
947
|
+
this.sessionId = null;
|
|
948
|
+
this.abortController = null;
|
|
949
|
+
this.reconnectTimer = null;
|
|
950
|
+
this.subscribedContextIds = /* @__PURE__ */ new Set();
|
|
951
|
+
this.closed = false;
|
|
952
|
+
this.listeners = { connect: [], event: [], error: [] };
|
|
953
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
954
|
+
this.getAuthToken = opts.getAuthToken;
|
|
955
|
+
this.reconnectDelayMs = opts.reconnectDelayMs ?? 3e3;
|
|
956
|
+
}
|
|
957
|
+
on(event, handler) {
|
|
958
|
+
const key = event;
|
|
959
|
+
if (key in this.listeners) {
|
|
960
|
+
const arr = this.listeners[key];
|
|
961
|
+
if (!arr.includes(handler)) arr.push(handler);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
off(event, handler) {
|
|
965
|
+
const key = event;
|
|
966
|
+
if (key in this.listeners) {
|
|
967
|
+
const arr = this.listeners[key];
|
|
968
|
+
const idx = arr.indexOf(handler);
|
|
969
|
+
if (idx !== -1) arr.splice(idx, 1);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
emit(event, arg) {
|
|
973
|
+
const key = event;
|
|
974
|
+
if (key in this.listeners) {
|
|
975
|
+
for (const handler of this.listeners[key]) {
|
|
976
|
+
try {
|
|
977
|
+
handler(arg);
|
|
978
|
+
} catch {
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
async connect() {
|
|
984
|
+
if (this.abortController && !this.closed) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
this.closed = false;
|
|
988
|
+
this.abortController = new AbortController();
|
|
989
|
+
try {
|
|
990
|
+
const token = await this.getAuthToken();
|
|
991
|
+
const response = await fetch(`${this.baseUrl}/sse`, {
|
|
992
|
+
headers: {
|
|
993
|
+
"Authorization": `Bearer ${token}`,
|
|
994
|
+
"Accept": "text/event-stream"
|
|
995
|
+
},
|
|
996
|
+
signal: this.abortController.signal
|
|
997
|
+
});
|
|
998
|
+
if (!response.ok) {
|
|
999
|
+
throw new Error(`SSE connection failed: ${response.status}`);
|
|
1000
|
+
}
|
|
1001
|
+
if (!response.body) {
|
|
1002
|
+
throw new Error("SSE response has no body");
|
|
1003
|
+
}
|
|
1004
|
+
this.readStream(response.body).catch((err) => {
|
|
1005
|
+
if (this.closed) return;
|
|
1006
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1007
|
+
this.emit("error", error);
|
|
1008
|
+
this.scheduleReconnect();
|
|
1009
|
+
});
|
|
1010
|
+
} catch (err) {
|
|
1011
|
+
if (this.closed) return;
|
|
1012
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1013
|
+
this.emit("error", error);
|
|
1014
|
+
this.scheduleReconnect();
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
async readStream(body) {
|
|
1018
|
+
const reader = body.getReader();
|
|
1019
|
+
const decoder = new TextDecoder();
|
|
1020
|
+
let buffer = "";
|
|
1021
|
+
try {
|
|
1022
|
+
for (; ; ) {
|
|
1023
|
+
const { done, value } = await reader.read();
|
|
1024
|
+
if (done) break;
|
|
1025
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1026
|
+
const lines = buffer.split("\n");
|
|
1027
|
+
buffer = lines.pop() ?? "";
|
|
1028
|
+
for (const line of lines) {
|
|
1029
|
+
if (line.startsWith("data:")) {
|
|
1030
|
+
const jsonStr = line.slice(5).trim();
|
|
1031
|
+
if (jsonStr) {
|
|
1032
|
+
this.handleMessage(jsonStr);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
buffer += decoder.decode();
|
|
1038
|
+
if (buffer.startsWith("data:")) {
|
|
1039
|
+
const jsonStr = buffer.slice(5).trim();
|
|
1040
|
+
if (jsonStr) {
|
|
1041
|
+
this.handleMessage(jsonStr);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
if (this.closed) return;
|
|
1046
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1047
|
+
this.emit("error", error);
|
|
1048
|
+
}
|
|
1049
|
+
if (!this.closed) {
|
|
1050
|
+
this.scheduleReconnect();
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
handleMessage(jsonStr) {
|
|
1054
|
+
try {
|
|
1055
|
+
const msg = JSON.parse(jsonStr);
|
|
1056
|
+
if (msg.type === "connect" && msg.session_id) {
|
|
1057
|
+
this.sessionId = msg.session_id;
|
|
1058
|
+
this.emit("connect", msg.session_id);
|
|
1059
|
+
if (this.subscribedContextIds.size > 0) {
|
|
1060
|
+
this.sendSubscription("subscribe", [...this.subscribedContextIds]);
|
|
1061
|
+
}
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
if (msg.result && msg.result.contextId) {
|
|
1065
|
+
let eventData = msg.result.data;
|
|
1066
|
+
if (Array.isArray(eventData)) {
|
|
1067
|
+
try {
|
|
1068
|
+
const bytes = new Uint8Array(eventData);
|
|
1069
|
+
const text = new TextDecoder().decode(bytes);
|
|
1070
|
+
eventData = JSON.parse(text);
|
|
1071
|
+
} catch {
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
this.emit("event", {
|
|
1075
|
+
contextId: msg.result.contextId,
|
|
1076
|
+
data: eventData
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
} catch {
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
async subscribe(contextIds) {
|
|
1083
|
+
const newIds = contextIds.filter((id) => !this.subscribedContextIds.has(id));
|
|
1084
|
+
for (const id of contextIds) {
|
|
1085
|
+
this.subscribedContextIds.add(id);
|
|
1086
|
+
}
|
|
1087
|
+
if (newIds.length > 0 && this.sessionId) {
|
|
1088
|
+
await this.sendSubscription("subscribe", newIds);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
async unsubscribe(contextIds) {
|
|
1092
|
+
const hadIds = contextIds.filter((id) => this.subscribedContextIds.has(id));
|
|
1093
|
+
for (const id of contextIds) {
|
|
1094
|
+
this.subscribedContextIds.delete(id);
|
|
1095
|
+
}
|
|
1096
|
+
if (hadIds.length > 0 && this.sessionId) {
|
|
1097
|
+
await this.sendSubscription("unsubscribe", hadIds);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
async sendSubscription(method, contextIds) {
|
|
1101
|
+
try {
|
|
1102
|
+
const token = await this.getAuthToken();
|
|
1103
|
+
const response = await fetch(`${this.baseUrl}/sse/subscription`, {
|
|
1104
|
+
method: "POST",
|
|
1105
|
+
headers: {
|
|
1106
|
+
"Authorization": `Bearer ${token}`,
|
|
1107
|
+
"Content-Type": "application/json"
|
|
1108
|
+
},
|
|
1109
|
+
body: JSON.stringify({
|
|
1110
|
+
id: this.sessionId,
|
|
1111
|
+
method,
|
|
1112
|
+
params: { contextIds }
|
|
1113
|
+
})
|
|
1114
|
+
});
|
|
1115
|
+
if (!response.ok) {
|
|
1116
|
+
this.emit("error", new Error(`SSE ${method} failed: ${response.status}`));
|
|
1117
|
+
}
|
|
1118
|
+
} catch (err) {
|
|
1119
|
+
this.emit("error", err instanceof Error ? err : new Error(`SSE ${method} failed`));
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
forceReconnect() {
|
|
1123
|
+
if (this.abortController) {
|
|
1124
|
+
this.abortController.abort();
|
|
1125
|
+
this.abortController = null;
|
|
1126
|
+
}
|
|
1127
|
+
this.sessionId = null;
|
|
1128
|
+
this.connect();
|
|
1129
|
+
}
|
|
1130
|
+
scheduleReconnect() {
|
|
1131
|
+
if (this.closed) return;
|
|
1132
|
+
if (this.reconnectTimer) {
|
|
1133
|
+
clearTimeout(this.reconnectTimer);
|
|
1134
|
+
}
|
|
1135
|
+
this.reconnectTimer = setTimeout(() => {
|
|
1136
|
+
this.reconnectTimer = null;
|
|
1137
|
+
this.forceReconnect();
|
|
1138
|
+
}, this.reconnectDelayMs);
|
|
1139
|
+
}
|
|
1140
|
+
close() {
|
|
1141
|
+
this.closed = true;
|
|
1142
|
+
if (this.abortController) {
|
|
1143
|
+
this.abortController.abort();
|
|
1144
|
+
this.abortController = null;
|
|
1145
|
+
}
|
|
1146
|
+
if (this.reconnectTimer) {
|
|
1147
|
+
clearTimeout(this.reconnectTimer);
|
|
1148
|
+
this.reconnectTimer = null;
|
|
1149
|
+
}
|
|
1150
|
+
this.sessionId = null;
|
|
1151
|
+
this.subscribedContextIds.clear();
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
// src/events/ws.ts
|
|
1156
|
+
var _WsClient = class _WsClient {
|
|
1157
|
+
constructor(opts) {
|
|
1158
|
+
this.ws = null;
|
|
1159
|
+
this.closed = false;
|
|
1160
|
+
this.reconnectAttempt = 0;
|
|
1161
|
+
this.reconnectTimer = null;
|
|
1162
|
+
this.subscribedContextIds = /* @__PURE__ */ new Set();
|
|
1163
|
+
this.listeners = { connect: [], event: [], error: [] };
|
|
1164
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
1165
|
+
this.getAuthToken = opts.getAuthToken;
|
|
1166
|
+
}
|
|
1167
|
+
on(event, handler) {
|
|
1168
|
+
const key = event;
|
|
1169
|
+
if (key in this.listeners) {
|
|
1170
|
+
const arr = this.listeners[key];
|
|
1171
|
+
if (!arr.includes(handler)) arr.push(handler);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
off(event, handler) {
|
|
1175
|
+
const key = event;
|
|
1176
|
+
if (key in this.listeners) {
|
|
1177
|
+
const arr = this.listeners[key];
|
|
1178
|
+
const idx = arr.indexOf(handler);
|
|
1179
|
+
if (idx !== -1) arr.splice(idx, 1);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
emit(event, arg) {
|
|
1183
|
+
const key = event;
|
|
1184
|
+
if (key in this.listeners) {
|
|
1185
|
+
for (const handler of this.listeners[key]) {
|
|
1186
|
+
try {
|
|
1187
|
+
handler(arg);
|
|
1188
|
+
} catch {
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
async connect() {
|
|
1194
|
+
if (this.ws && (this.ws.readyState === WebSocket.CONNECTING || this.ws.readyState === WebSocket.OPEN)) {
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
this.closed = false;
|
|
1198
|
+
try {
|
|
1199
|
+
const token = await this.getAuthToken();
|
|
1200
|
+
if (!token) {
|
|
1201
|
+
throw new Error("No authentication token available for WebSocket connection");
|
|
1202
|
+
}
|
|
1203
|
+
const wsUrl = this.baseUrl.replace(/^http/, "ws");
|
|
1204
|
+
this.ws = new WebSocket(`${wsUrl}/ws?token=${encodeURIComponent(token)}`);
|
|
1205
|
+
this.ws.onopen = () => {
|
|
1206
|
+
this.reconnectAttempt = 0;
|
|
1207
|
+
this.emit("connect");
|
|
1208
|
+
if (this.subscribedContextIds.size > 0) {
|
|
1209
|
+
this.sendMessage({
|
|
1210
|
+
id: null,
|
|
1211
|
+
method: "subscribe",
|
|
1212
|
+
params: { contextIds: [...this.subscribedContextIds] }
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
this.ws.onmessage = (event) => {
|
|
1217
|
+
this.handleMessage(event.data);
|
|
1218
|
+
};
|
|
1219
|
+
this.ws.onerror = () => {
|
|
1220
|
+
this.emit("error", new Error("WebSocket error"));
|
|
1221
|
+
};
|
|
1222
|
+
this.ws.onclose = () => {
|
|
1223
|
+
if (!this.closed) {
|
|
1224
|
+
this.scheduleReconnect();
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
} catch (err) {
|
|
1228
|
+
if (this.closed) return;
|
|
1229
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1230
|
+
this.emit("error", error);
|
|
1231
|
+
this.scheduleReconnect();
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
handleMessage(raw) {
|
|
1235
|
+
if (typeof raw !== "string") return;
|
|
1236
|
+
try {
|
|
1237
|
+
const msg = JSON.parse(raw);
|
|
1238
|
+
if (msg.result && msg.result.contextId) {
|
|
1239
|
+
let eventData = msg.result.data;
|
|
1240
|
+
if (Array.isArray(eventData)) {
|
|
1241
|
+
try {
|
|
1242
|
+
const bytes = new Uint8Array(eventData);
|
|
1243
|
+
const text = new TextDecoder().decode(bytes);
|
|
1244
|
+
eventData = JSON.parse(text);
|
|
1245
|
+
} catch {
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
this.emit("event", {
|
|
1249
|
+
contextId: msg.result.contextId,
|
|
1250
|
+
data: eventData
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
} catch {
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
subscribe(contextIds) {
|
|
1257
|
+
for (const id of contextIds) {
|
|
1258
|
+
this.subscribedContextIds.add(id);
|
|
1259
|
+
}
|
|
1260
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
1261
|
+
this.sendMessage({
|
|
1262
|
+
id: null,
|
|
1263
|
+
method: "subscribe",
|
|
1264
|
+
params: { contextIds }
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
unsubscribe(contextIds) {
|
|
1269
|
+
for (const id of contextIds) {
|
|
1270
|
+
this.subscribedContextIds.delete(id);
|
|
1271
|
+
}
|
|
1272
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
1273
|
+
this.sendMessage({
|
|
1274
|
+
id: null,
|
|
1275
|
+
method: "unsubscribe",
|
|
1276
|
+
params: { contextIds }
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
sendMessage(msg) {
|
|
1281
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
1282
|
+
this.ws.send(JSON.stringify(msg));
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
scheduleReconnect() {
|
|
1286
|
+
if (this.closed) return;
|
|
1287
|
+
if (this.reconnectTimer) {
|
|
1288
|
+
clearTimeout(this.reconnectTimer);
|
|
1289
|
+
}
|
|
1290
|
+
const delay = Math.min(
|
|
1291
|
+
1e3 * Math.pow(2, this.reconnectAttempt),
|
|
1292
|
+
_WsClient.MAX_BACKOFF_MS
|
|
1293
|
+
);
|
|
1294
|
+
this.reconnectAttempt++;
|
|
1295
|
+
this.reconnectTimer = setTimeout(() => {
|
|
1296
|
+
this.reconnectTimer = null;
|
|
1297
|
+
this.connect();
|
|
1298
|
+
}, delay);
|
|
1299
|
+
}
|
|
1300
|
+
close() {
|
|
1301
|
+
this.closed = true;
|
|
1302
|
+
if (this.reconnectTimer) {
|
|
1303
|
+
clearTimeout(this.reconnectTimer);
|
|
1304
|
+
this.reconnectTimer = null;
|
|
1305
|
+
}
|
|
1306
|
+
if (this.ws) {
|
|
1307
|
+
this.ws.onclose = null;
|
|
1308
|
+
this.ws.close();
|
|
1309
|
+
this.ws = null;
|
|
1310
|
+
}
|
|
1311
|
+
this.subscribedContextIds.clear();
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
_WsClient.MAX_BACKOFF_MS = 3e4;
|
|
1315
|
+
var WsClient = _WsClient;
|
|
1316
|
+
|
|
858
1317
|
// src/mero-js.ts
|
|
1318
|
+
function expiresAtFromJwt(token, fallbackMs) {
|
|
1319
|
+
try {
|
|
1320
|
+
const parts = token.split(".");
|
|
1321
|
+
if (parts.length === 3) {
|
|
1322
|
+
let b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
1323
|
+
while (b64.length % 4) b64 += "=";
|
|
1324
|
+
const payload = JSON.parse(atob(b64));
|
|
1325
|
+
if (typeof payload.exp === "number") {
|
|
1326
|
+
return payload.exp * 1e3;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
} catch {
|
|
1330
|
+
}
|
|
1331
|
+
return fallbackMs;
|
|
1332
|
+
}
|
|
859
1333
|
var MeroJs = class {
|
|
860
1334
|
constructor(config) {
|
|
861
1335
|
this.tokenData = null;
|
|
862
1336
|
this.refreshPromise = null;
|
|
1337
|
+
this.rpcClient = null;
|
|
1338
|
+
this.sseClient = null;
|
|
1339
|
+
this.wsClient = null;
|
|
1340
|
+
this.wsWarned = false;
|
|
863
1341
|
this.config = {
|
|
864
1342
|
timeoutMs: 1e4,
|
|
865
1343
|
...config
|
|
866
1344
|
};
|
|
1345
|
+
this.tokenStore = config.tokenStore ?? null;
|
|
1346
|
+
if (this.tokenStore) {
|
|
1347
|
+
this.tokenData = this.tokenStore.getTokens();
|
|
1348
|
+
}
|
|
867
1349
|
const isTauri = typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
|
868
1350
|
this.httpClient = createBrowserHttpClient({
|
|
869
1351
|
baseUrl: this.config.baseUrl,
|
|
@@ -871,6 +1353,16 @@ var MeroJs = class {
|
|
|
871
1353
|
const token = await this.getValidToken();
|
|
872
1354
|
return token?.access_token || "";
|
|
873
1355
|
},
|
|
1356
|
+
refreshToken: async () => {
|
|
1357
|
+
const refreshed = await this.performTokenRefresh();
|
|
1358
|
+
return refreshed.access_token;
|
|
1359
|
+
},
|
|
1360
|
+
onTokenRefresh: async (newToken) => {
|
|
1361
|
+
if (this.tokenData) {
|
|
1362
|
+
this.tokenData.access_token = newToken;
|
|
1363
|
+
this.tokenStore?.setTokens(this.tokenData);
|
|
1364
|
+
}
|
|
1365
|
+
},
|
|
874
1366
|
timeoutMs: this.config.timeoutMs,
|
|
875
1367
|
credentials: this.config.requestCredentials ?? (isTauri ? "omit" : void 0)
|
|
876
1368
|
});
|
|
@@ -903,6 +1395,50 @@ var MeroJs = class {
|
|
|
903
1395
|
get admin() {
|
|
904
1396
|
return this.adminClient;
|
|
905
1397
|
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Get the RPC client (lazy initialized)
|
|
1400
|
+
*/
|
|
1401
|
+
get rpc() {
|
|
1402
|
+
if (!this.rpcClient) {
|
|
1403
|
+
this.rpcClient = new RpcClient({ httpClient: this.httpClient });
|
|
1404
|
+
}
|
|
1405
|
+
return this.rpcClient;
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Get the SSE event client (lazy initialized)
|
|
1409
|
+
*/
|
|
1410
|
+
get events() {
|
|
1411
|
+
if (!this.sseClient) {
|
|
1412
|
+
this.sseClient = new SseClient({
|
|
1413
|
+
baseUrl: this.config.baseUrl,
|
|
1414
|
+
getAuthToken: async () => {
|
|
1415
|
+
const token = await this.getValidToken();
|
|
1416
|
+
return token?.access_token || "";
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1420
|
+
return this.sseClient;
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Get the WebSocket event client (lazy initialized).
|
|
1424
|
+
* @experimental Use `events` (SSE) for production. WsClient is experimental.
|
|
1425
|
+
*/
|
|
1426
|
+
get ws() {
|
|
1427
|
+
if (!this.wsWarned) {
|
|
1428
|
+
this.wsWarned = true;
|
|
1429
|
+
console.warn("[mero-js] WsClient is experimental. Use mero.events (SSE) for production.");
|
|
1430
|
+
}
|
|
1431
|
+
if (!this.wsClient) {
|
|
1432
|
+
this.wsClient = new WsClient({
|
|
1433
|
+
baseUrl: this.config.baseUrl,
|
|
1434
|
+
getAuthToken: async () => {
|
|
1435
|
+
const token = await this.getValidToken();
|
|
1436
|
+
return token?.access_token || "";
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
return this.wsClient;
|
|
1441
|
+
}
|
|
906
1442
|
/**
|
|
907
1443
|
* Authenticate with the provided credentials
|
|
908
1444
|
* This will create the root key on first use
|
|
@@ -925,12 +1461,13 @@ var MeroJs = class {
|
|
|
925
1461
|
}
|
|
926
1462
|
};
|
|
927
1463
|
const response = await this.authClient.generateTokens(requestBody);
|
|
1464
|
+
const accessToken = response.data.access_token;
|
|
928
1465
|
this.tokenData = {
|
|
929
|
-
access_token:
|
|
1466
|
+
access_token: accessToken,
|
|
930
1467
|
refresh_token: response.data.refresh_token,
|
|
931
|
-
expires_at: Date.now() +
|
|
932
|
-
// Default to 24 hours
|
|
1468
|
+
expires_at: expiresAtFromJwt(accessToken, Date.now() + 36e5)
|
|
933
1469
|
};
|
|
1470
|
+
this.tokenStore?.setTokens(this.tokenData);
|
|
934
1471
|
return this.tokenData;
|
|
935
1472
|
} catch (error) {
|
|
936
1473
|
throw new Error(
|
|
@@ -939,16 +1476,12 @@ var MeroJs = class {
|
|
|
939
1476
|
}
|
|
940
1477
|
}
|
|
941
1478
|
/**
|
|
942
|
-
* Get a valid token
|
|
1479
|
+
* Get a valid token. Returns the current token as-is.
|
|
1480
|
+
* The server rejects refresh attempts while the access token is still valid,
|
|
1481
|
+
* so we never proactively refresh. Instead, the WebHttpClient handles 401
|
|
1482
|
+
* responses reactively via the refreshToken transport hook.
|
|
943
1483
|
*/
|
|
944
1484
|
async getValidToken() {
|
|
945
|
-
if (!this.tokenData) {
|
|
946
|
-
return null;
|
|
947
|
-
}
|
|
948
|
-
const bufferTime = 5 * 60 * 1e3;
|
|
949
|
-
if (Date.now() >= this.tokenData.expires_at - bufferTime) {
|
|
950
|
-
return await this.refreshToken();
|
|
951
|
-
}
|
|
952
1485
|
return this.tokenData;
|
|
953
1486
|
}
|
|
954
1487
|
/**
|
|
@@ -981,15 +1514,15 @@ var MeroJs = class {
|
|
|
981
1514
|
access_token: this.tokenData.access_token,
|
|
982
1515
|
refresh_token: this.tokenData.refresh_token
|
|
983
1516
|
});
|
|
1517
|
+
const accessToken = response.data.access_token;
|
|
984
1518
|
this.tokenData = {
|
|
985
|
-
access_token:
|
|
1519
|
+
access_token: accessToken,
|
|
986
1520
|
refresh_token: response.data.refresh_token,
|
|
987
|
-
expires_at: Date.now() +
|
|
988
|
-
// Default to 24 hours
|
|
1521
|
+
expires_at: expiresAtFromJwt(accessToken, Date.now() + 36e5)
|
|
989
1522
|
};
|
|
1523
|
+
this.tokenStore?.setTokens(this.tokenData);
|
|
990
1524
|
return this.tokenData;
|
|
991
1525
|
} catch (error) {
|
|
992
|
-
this.clearToken();
|
|
993
1526
|
throw new Error(
|
|
994
1527
|
`Token refresh failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
995
1528
|
);
|
|
@@ -1000,6 +1533,7 @@ var MeroJs = class {
|
|
|
1000
1533
|
*/
|
|
1001
1534
|
clearToken() {
|
|
1002
1535
|
this.tokenData = null;
|
|
1536
|
+
this.tokenStore?.clear();
|
|
1003
1537
|
}
|
|
1004
1538
|
/**
|
|
1005
1539
|
* Check if the SDK is authenticated
|
|
@@ -1007,14 +1541,97 @@ var MeroJs = class {
|
|
|
1007
1541
|
isAuthenticated() {
|
|
1008
1542
|
return this.tokenData !== null;
|
|
1009
1543
|
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Set token data directly (e.g., from auth callback).
|
|
1546
|
+
* If `expires_at` is missing or 0, attempts to parse the JWT exp claim,
|
|
1547
|
+
* falling back to 1 hour from now.
|
|
1548
|
+
*/
|
|
1549
|
+
setTokenData(data) {
|
|
1550
|
+
const expiresAt = data.expires_at || expiresAtFromJwt(data.access_token, Date.now() + 36e5);
|
|
1551
|
+
this.tokenData = { ...data, expires_at: expiresAt };
|
|
1552
|
+
this.tokenStore?.setTokens(this.tokenData);
|
|
1553
|
+
}
|
|
1010
1554
|
/**
|
|
1011
1555
|
* Get the current token data (for debugging)
|
|
1012
1556
|
*/
|
|
1013
1557
|
getTokenData() {
|
|
1014
1558
|
return this.tokenData;
|
|
1015
1559
|
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Close all event connections and clean up resources
|
|
1562
|
+
*/
|
|
1563
|
+
close() {
|
|
1564
|
+
this.sseClient?.close();
|
|
1565
|
+
this.wsClient?.close();
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Parse an auth callback URL hash fragment (static utility)
|
|
1569
|
+
*/
|
|
1570
|
+
static parseAuthCallback(url) {
|
|
1571
|
+
return parseAuthCallback(url);
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Build an auth login URL (static utility)
|
|
1575
|
+
*/
|
|
1576
|
+
static buildAuthLoginUrl(nodeUrl, opts) {
|
|
1577
|
+
return buildAuthLoginUrl(nodeUrl, opts);
|
|
1578
|
+
}
|
|
1016
1579
|
};
|
|
1017
1580
|
function createMeroJs(config) {
|
|
1018
1581
|
return new MeroJs(config);
|
|
1019
1582
|
}
|
|
1583
|
+
|
|
1584
|
+
// src/token-store/index.ts
|
|
1585
|
+
var MemoryTokenStore = class {
|
|
1586
|
+
constructor() {
|
|
1587
|
+
this.tokens = null;
|
|
1588
|
+
}
|
|
1589
|
+
getTokens() {
|
|
1590
|
+
return this.tokens;
|
|
1591
|
+
}
|
|
1592
|
+
setTokens(data) {
|
|
1593
|
+
this.tokens = data;
|
|
1594
|
+
}
|
|
1595
|
+
clear() {
|
|
1596
|
+
this.tokens = null;
|
|
1597
|
+
}
|
|
1598
|
+
};
|
|
1599
|
+
var STORAGE_KEY = "mero-tokens";
|
|
1600
|
+
var LocalStorageTokenStore = class {
|
|
1601
|
+
constructor(key = STORAGE_KEY) {
|
|
1602
|
+
this.key = key;
|
|
1603
|
+
}
|
|
1604
|
+
getTokens() {
|
|
1605
|
+
try {
|
|
1606
|
+
if (typeof localStorage === "undefined") return null;
|
|
1607
|
+
const raw = localStorage.getItem(this.key);
|
|
1608
|
+
if (!raw) return null;
|
|
1609
|
+
const parsed = JSON.parse(raw);
|
|
1610
|
+
if (parsed && parsed.access_token && parsed.refresh_token) {
|
|
1611
|
+
return {
|
|
1612
|
+
access_token: parsed.access_token,
|
|
1613
|
+
refresh_token: parsed.refresh_token,
|
|
1614
|
+
expires_at: typeof parsed.expires_at === "number" ? parsed.expires_at : Date.now() + 36e5
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1617
|
+
return null;
|
|
1618
|
+
} catch {
|
|
1619
|
+
return null;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
setTokens(data) {
|
|
1623
|
+
try {
|
|
1624
|
+
if (typeof localStorage === "undefined") return;
|
|
1625
|
+
localStorage.setItem(this.key, JSON.stringify(data));
|
|
1626
|
+
} catch {
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
clear() {
|
|
1630
|
+
try {
|
|
1631
|
+
if (typeof localStorage === "undefined") return;
|
|
1632
|
+
localStorage.removeItem(this.key);
|
|
1633
|
+
} catch {
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
};
|
|
1020
1637
|
//# sourceMappingURL=index.cjs.map
|