@spacelr/sdk 0.1.8 → 0.1.9
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.d.mts +67 -7
- package/dist/index.d.ts +67 -7
- package/dist/index.js +97 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +97 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -869,6 +869,8 @@ var RealtimeClient = class {
|
|
|
869
869
|
// libs/sdk/src/modules/auth.module.ts
|
|
870
870
|
var AuthModule = class {
|
|
871
871
|
constructor(http, tokenManager, config) {
|
|
872
|
+
this.stateListeners = /* @__PURE__ */ new Set();
|
|
873
|
+
this.lastEmittedState = null;
|
|
872
874
|
this.http = http;
|
|
873
875
|
this.tokenManager = tokenManager;
|
|
874
876
|
this.config = config;
|
|
@@ -881,6 +883,84 @@ var AuthModule = class {
|
|
|
881
883
|
expiresAt
|
|
882
884
|
};
|
|
883
885
|
});
|
|
886
|
+
this.unsubscribeAuthLost = this.tokenManager.onAuthLost(
|
|
887
|
+
() => this.emitState("unauthenticated")
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Returns true if a non-expired access token is currently in storage.
|
|
892
|
+
* Does NOT make a network request — safe for route guards and other
|
|
893
|
+
* hot paths that run on every navigation.
|
|
894
|
+
*
|
|
895
|
+
* A token within the refresh buffer (about to expire) still counts as
|
|
896
|
+
* authenticated because the next protected request will auto-refresh it.
|
|
897
|
+
*
|
|
898
|
+
* Any error from the underlying TokenStorage (corrupt JSON, quota, etc.)
|
|
899
|
+
* is treated as "not authenticated" rather than propagated, so route
|
|
900
|
+
* guards can't be crashed by a misbehaving storage backend.
|
|
901
|
+
*/
|
|
902
|
+
async isAuthenticated() {
|
|
903
|
+
try {
|
|
904
|
+
const tokens = await this.tokenManager.getStoredTokens();
|
|
905
|
+
if (!tokens?.accessToken) return false;
|
|
906
|
+
if (tokens.expiresAt && tokens.expiresAt * 1e3 <= Date.now()) return false;
|
|
907
|
+
return true;
|
|
908
|
+
} catch {
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Subscribe to auth-state transitions. The callback fires:
|
|
914
|
+
* - 'authenticated' after a successful login/register/exchange/2FA-verify
|
|
915
|
+
* - 'unauthenticated' after logout or when a token refresh fails
|
|
916
|
+
*
|
|
917
|
+
* Only fires for transitions that happen after the subscription. If the
|
|
918
|
+
* user is already logged in at subscribe time (e.g. tokens restored from
|
|
919
|
+
* storage on app boot), no 'authenticated' event is emitted — call
|
|
920
|
+
* `isAuthenticated()` once up-front for the initial state.
|
|
921
|
+
*
|
|
922
|
+
* Silent token refreshes do NOT produce an event (auth state is
|
|
923
|
+
* unchanged). Subscribe to `spacelrClient.onTokenRefreshed(...)` if you
|
|
924
|
+
* need to observe successful refreshes.
|
|
925
|
+
*
|
|
926
|
+
* Listener may return `void` or `Promise<void>`. Rejections are swallowed
|
|
927
|
+
* so one broken subscriber can't poison others or the auth flow. The
|
|
928
|
+
* dispatch is fire-and-forget: `logout()` / `login()` resolve as soon as
|
|
929
|
+
* the dispatch loop returns, without awaiting async listeners.
|
|
930
|
+
*
|
|
931
|
+
* Returns an unsubscribe function.
|
|
932
|
+
*/
|
|
933
|
+
onAuthStateChange(listener) {
|
|
934
|
+
this.stateListeners.add(listener);
|
|
935
|
+
return () => {
|
|
936
|
+
this.stateListeners.delete(listener);
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Detach this AuthModule from the TokenManager. Call when discarding the
|
|
941
|
+
* client (tests, HMR, multi-client setups) to avoid leaking the internal
|
|
942
|
+
* onAuthLost subscription. Idempotent — safe to call more than once.
|
|
943
|
+
*/
|
|
944
|
+
dispose() {
|
|
945
|
+
this.unsubscribeAuthLost();
|
|
946
|
+
this.unsubscribeAuthLost = () => {
|
|
947
|
+
};
|
|
948
|
+
this.stateListeners.clear();
|
|
949
|
+
this.lastEmittedState = null;
|
|
950
|
+
}
|
|
951
|
+
emitState(state) {
|
|
952
|
+
if (state === this.lastEmittedState) return;
|
|
953
|
+
this.lastEmittedState = state;
|
|
954
|
+
for (const listener of this.stateListeners) {
|
|
955
|
+
try {
|
|
956
|
+
const result = listener(state);
|
|
957
|
+
if (result && typeof result.then === "function") {
|
|
958
|
+
result.then(void 0, () => {
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
} catch {
|
|
962
|
+
}
|
|
963
|
+
}
|
|
884
964
|
}
|
|
885
965
|
async login(params) {
|
|
886
966
|
const response = await this.http.request({
|
|
@@ -926,6 +1006,7 @@ var AuthModule = class {
|
|
|
926
1006
|
} catch {
|
|
927
1007
|
}
|
|
928
1008
|
await this.tokenManager.clearTokens();
|
|
1009
|
+
this.emitState("unauthenticated");
|
|
929
1010
|
}
|
|
930
1011
|
async verifyEmail(token) {
|
|
931
1012
|
return this.http.request({
|
|
@@ -996,6 +1077,7 @@ var AuthModule = class {
|
|
|
996
1077
|
refreshToken: response.refresh_token,
|
|
997
1078
|
expiresAt
|
|
998
1079
|
});
|
|
1080
|
+
this.emitState("authenticated");
|
|
999
1081
|
return response;
|
|
1000
1082
|
}
|
|
1001
1083
|
async generatePKCE() {
|
|
@@ -1078,6 +1160,7 @@ var AuthModule = class {
|
|
|
1078
1160
|
refreshToken: response.refresh_token,
|
|
1079
1161
|
expiresAt
|
|
1080
1162
|
});
|
|
1163
|
+
this.emitState("authenticated");
|
|
1081
1164
|
}
|
|
1082
1165
|
async storeTokensFromRegister(response) {
|
|
1083
1166
|
if (!response.access_token) return;
|
|
@@ -1085,6 +1168,7 @@ var AuthModule = class {
|
|
|
1085
1168
|
accessToken: response.access_token,
|
|
1086
1169
|
refreshToken: response.refresh_token
|
|
1087
1170
|
});
|
|
1171
|
+
this.emitState("authenticated");
|
|
1088
1172
|
}
|
|
1089
1173
|
};
|
|
1090
1174
|
|
|
@@ -1656,19 +1740,25 @@ var FunctionsModule = class {
|
|
|
1656
1740
|
this.http = http;
|
|
1657
1741
|
}
|
|
1658
1742
|
/**
|
|
1659
|
-
* Invoke a function
|
|
1743
|
+
* Invoke a function.
|
|
1660
1744
|
* Calls POST /api/v1/functions/:projectId/:functionId/invoke
|
|
1661
|
-
*
|
|
1745
|
+
*
|
|
1746
|
+
* Provide `secret` for webhook/hybrid functions, `authenticated: true` for
|
|
1747
|
+
* JWT-based invocation, or both for hybrid (JWT wins). Public mode needs
|
|
1748
|
+
* neither, though `authenticated: true` still populates `event.auth` inside
|
|
1749
|
+
* the function.
|
|
1662
1750
|
*/
|
|
1663
|
-
async invoke(projectId, functionId, options) {
|
|
1751
|
+
async invoke(projectId, functionId, options = {}) {
|
|
1752
|
+
const headers = {};
|
|
1753
|
+
if (options.secret) {
|
|
1754
|
+
headers["X-Webhook-Secret"] = options.secret;
|
|
1755
|
+
}
|
|
1664
1756
|
return this.http.request({
|
|
1665
1757
|
method: "POST",
|
|
1666
1758
|
path: `/api/v1/functions/${encodeURIComponent(projectId)}/${encodeURIComponent(functionId)}/invoke`,
|
|
1667
|
-
headers
|
|
1668
|
-
"X-Webhook-Secret": options.secret
|
|
1669
|
-
},
|
|
1759
|
+
headers,
|
|
1670
1760
|
body: options.payload ?? {},
|
|
1671
|
-
authenticated: false
|
|
1761
|
+
authenticated: options.authenticated ?? false
|
|
1672
1762
|
});
|
|
1673
1763
|
}
|
|
1674
1764
|
};
|