@bounded-sh/core 0.0.21 → 0.0.23
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 +3 -3
- package/dist/client/subscription-v2.d.ts +3 -3
- package/dist/index.js +89 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +89 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -5415,6 +5415,48 @@ function getCacheKey(path, prompt, shape, limit, cursor, filter, identity) {
|
|
|
5415
5415
|
function principalFromIdToken(idToken) {
|
|
5416
5416
|
return idToken ? `t${hashForKey(idToken)}` : null;
|
|
5417
5417
|
}
|
|
5418
|
+
function livePrincipalFromIdToken(idToken) {
|
|
5419
|
+
if (!idToken)
|
|
5420
|
+
return null;
|
|
5421
|
+
try {
|
|
5422
|
+
const payload = JSON.parse(decodeBase64Url(idToken.split('.')[1]));
|
|
5423
|
+
const userId = payload['custom:userId'];
|
|
5424
|
+
if (typeof userId === 'string' && userId.length > 0)
|
|
5425
|
+
return userId;
|
|
5426
|
+
const walletAddress = payload['custom:walletAddress'];
|
|
5427
|
+
if (typeof walletAddress === 'string' && walletAddress.length > 0)
|
|
5428
|
+
return walletAddress;
|
|
5429
|
+
const subject = payload.sub;
|
|
5430
|
+
return typeof subject === 'string' && subject.length > 0 ? subject : null;
|
|
5431
|
+
}
|
|
5432
|
+
catch (_a) {
|
|
5433
|
+
return null;
|
|
5434
|
+
}
|
|
5435
|
+
}
|
|
5436
|
+
function authSnapshotFromToken(idToken) {
|
|
5437
|
+
return {
|
|
5438
|
+
tokenFingerprint: principalFromIdToken(idToken),
|
|
5439
|
+
principal: livePrincipalFromIdToken(idToken),
|
|
5440
|
+
};
|
|
5441
|
+
}
|
|
5442
|
+
function connectionMatchesAuthToken(connection, idToken) {
|
|
5443
|
+
const current = authSnapshotFromToken(idToken);
|
|
5444
|
+
if (!current.tokenFingerprint) {
|
|
5445
|
+
return connection.authTokenFingerprint === null && connection.authPrincipal === null;
|
|
5446
|
+
}
|
|
5447
|
+
if (connection.authTokenFingerprint && connection.authTokenFingerprint === current.tokenFingerprint) {
|
|
5448
|
+
return true;
|
|
5449
|
+
}
|
|
5450
|
+
return !!connection.authPrincipal && !!current.principal && connection.authPrincipal === current.principal;
|
|
5451
|
+
}
|
|
5452
|
+
async function canSendAuthenticatedLiveIntent(connection, isServer) {
|
|
5453
|
+
const currentToken = await getIdToken(isServer);
|
|
5454
|
+
if (!currentToken)
|
|
5455
|
+
return false;
|
|
5456
|
+
if (!connection.authTokenFingerprint && !connection.authPrincipal)
|
|
5457
|
+
return false;
|
|
5458
|
+
return connectionMatchesAuthToken(connection, currentToken);
|
|
5459
|
+
}
|
|
5418
5460
|
async function getSubscriptionIdentity(effectiveAppId, isServer, overrides) {
|
|
5419
5461
|
// Per-subscription wallet override (server WalletClient.subscribe): key by
|
|
5420
5462
|
// the wallet's own opaque token material, mirroring getReadPrincipalKey. Do
|
|
@@ -5490,6 +5532,9 @@ function rememberAmbientAuthFailure(error) {
|
|
|
5490
5532
|
function failConnectionAuth(connection, error) {
|
|
5491
5533
|
connection.authFailure = error;
|
|
5492
5534
|
connection.pendingAuthToken = null;
|
|
5535
|
+
connection.pendingAuthSnapshot = null;
|
|
5536
|
+
connection.authTokenFingerprint = null;
|
|
5537
|
+
connection.authPrincipal = null;
|
|
5493
5538
|
connection.isConnecting = false;
|
|
5494
5539
|
connection.isConnected = false;
|
|
5495
5540
|
connection.isAuthenticating = false;
|
|
@@ -5708,16 +5753,37 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5708
5753
|
if (connection.authFailure) {
|
|
5709
5754
|
throw connection.authFailure;
|
|
5710
5755
|
}
|
|
5756
|
+
let currentAuthToken;
|
|
5711
5757
|
try {
|
|
5712
|
-
await getConnectionAuthToken(isServer, authTokenProvider);
|
|
5758
|
+
currentAuthToken = await getConnectionAuthToken(isServer, authTokenProvider);
|
|
5713
5759
|
}
|
|
5714
5760
|
catch (error) {
|
|
5715
5761
|
const authError = normalizeAuthExpiredError(error, 'Authentication expired and refresh failed');
|
|
5716
5762
|
failConnectionAuth(connection, authError);
|
|
5717
5763
|
throw authError;
|
|
5718
5764
|
}
|
|
5765
|
+
if (connection.isConnected &&
|
|
5766
|
+
!connection.isAuthenticating &&
|
|
5767
|
+
!connectionMatchesAuthToken(connection, currentAuthToken)) {
|
|
5768
|
+
if (connection.tokenRefreshTimer) {
|
|
5769
|
+
clearInterval(connection.tokenRefreshTimer);
|
|
5770
|
+
connection.tokenRefreshTimer = null;
|
|
5771
|
+
}
|
|
5772
|
+
try {
|
|
5773
|
+
connection.ws.close();
|
|
5774
|
+
}
|
|
5775
|
+
catch (_a) {
|
|
5776
|
+
// Already closing.
|
|
5777
|
+
}
|
|
5778
|
+
connection.ws = null;
|
|
5779
|
+
connection.isConnected = false;
|
|
5780
|
+
connections.delete(connection.key);
|
|
5781
|
+
}
|
|
5782
|
+
else {
|
|
5783
|
+
connection.authFailure = null;
|
|
5784
|
+
return connection;
|
|
5785
|
+
}
|
|
5719
5786
|
connection.authFailure = null;
|
|
5720
|
-
return connection;
|
|
5721
5787
|
}
|
|
5722
5788
|
let initialAuthToken = await getConnectionAuthToken(isServer, authTokenProvider);
|
|
5723
5789
|
// Create new connection
|
|
@@ -5735,6 +5801,9 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5735
5801
|
routePath: roomKey ? routePath : undefined,
|
|
5736
5802
|
authTokenProvider,
|
|
5737
5803
|
pendingAuthToken: null,
|
|
5804
|
+
pendingAuthSnapshot: null,
|
|
5805
|
+
authTokenFingerprint: null,
|
|
5806
|
+
authPrincipal: null,
|
|
5738
5807
|
tokenRefreshTimer: null,
|
|
5739
5808
|
consecutiveAuthFailures: 0,
|
|
5740
5809
|
authFailure: null,
|
|
@@ -5772,6 +5841,7 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5772
5841
|
throw authError;
|
|
5773
5842
|
}
|
|
5774
5843
|
connection.pendingAuthToken = authToken || null;
|
|
5844
|
+
connection.pendingAuthSnapshot = authSnapshotFromToken(authToken);
|
|
5775
5845
|
if (authToken) {
|
|
5776
5846
|
// Successful token acquisition — reset failure counter
|
|
5777
5847
|
connection.consecutiveAuthFailures = 0;
|
|
@@ -5811,6 +5881,8 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5811
5881
|
}
|
|
5812
5882
|
else {
|
|
5813
5883
|
connection.isAuthenticating = false;
|
|
5884
|
+
connection.authTokenFingerprint = null;
|
|
5885
|
+
connection.authPrincipal = null;
|
|
5814
5886
|
replaySubscriptions(connection);
|
|
5815
5887
|
}
|
|
5816
5888
|
});
|
|
@@ -5850,10 +5922,12 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5850
5922
|
return connection;
|
|
5851
5923
|
}
|
|
5852
5924
|
function handleServerMessage(connection, message) {
|
|
5853
|
-
var _a;
|
|
5925
|
+
var _a, _b, _c, _d, _e;
|
|
5854
5926
|
switch (message.type) {
|
|
5855
5927
|
case 'authenticated': {
|
|
5856
5928
|
connection.isAuthenticating = false;
|
|
5929
|
+
connection.authTokenFingerprint = (_b = (_a = connection.pendingAuthSnapshot) === null || _a === void 0 ? void 0 : _a.tokenFingerprint) !== null && _b !== void 0 ? _b : null;
|
|
5930
|
+
connection.authPrincipal = (_d = (_c = connection.pendingAuthSnapshot) === null || _c === void 0 ? void 0 : _c.principal) !== null && _d !== void 0 ? _d : null;
|
|
5857
5931
|
replaySubscriptions(connection);
|
|
5858
5932
|
break;
|
|
5859
5933
|
}
|
|
@@ -5924,7 +5998,7 @@ function handleServerMessage(connection, message) {
|
|
|
5924
5998
|
connection.pendingRequests.delete(message.requestId);
|
|
5925
5999
|
clearTimeout(pendingSet.timer);
|
|
5926
6000
|
if (message.statusCode >= 400) {
|
|
5927
|
-
pendingSet.reject(new Error(((
|
|
6001
|
+
pendingSet.reject(new Error(((_e = message.body) === null || _e === void 0 ? void 0 : _e.message) || `Set failed with status ${message.statusCode}`));
|
|
5928
6002
|
}
|
|
5929
6003
|
else {
|
|
5930
6004
|
pendingSet.resolve(message.body);
|
|
@@ -6452,13 +6526,16 @@ function hasActiveConnection() {
|
|
|
6452
6526
|
* room authority — the connection is already routed to the room DO, so the
|
|
6453
6527
|
* client never names a destination.
|
|
6454
6528
|
*/
|
|
6455
|
-
function wsIntent(appId, roomRoutePath, intent) {
|
|
6529
|
+
async function wsIntent(appId, roomRoutePath, intent, isServer) {
|
|
6456
6530
|
const roomKey = roomKeyFromRoutePath(roomRoutePath);
|
|
6457
6531
|
const connKey = roomKey ? `${appId}#room#${roomKey}` : appId;
|
|
6458
6532
|
const connection = connections.get(connKey);
|
|
6459
6533
|
if (!connection || !connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN || connection.isAuthenticating) {
|
|
6460
6534
|
return false;
|
|
6461
6535
|
}
|
|
6536
|
+
if (!(await canSendAuthenticatedLiveIntent(connection, isServer))) {
|
|
6537
|
+
return false;
|
|
6538
|
+
}
|
|
6462
6539
|
try {
|
|
6463
6540
|
connection.ws.send(JSON.stringify({ type: 'intent', intent }));
|
|
6464
6541
|
return true;
|
|
@@ -6475,13 +6552,16 @@ function wsIntent(appId, roomRoutePath, intent) {
|
|
|
6475
6552
|
* Promise that resolves on ack / rejects on error, or `undefined` if no live
|
|
6476
6553
|
* socket exists yet (caller falls back to HTTP, which also surfaces errors).
|
|
6477
6554
|
*/
|
|
6478
|
-
function wsIntentReliable(appId, roomRoutePath, intent) {
|
|
6555
|
+
async function wsIntentReliable(appId, roomRoutePath, intent, isServer) {
|
|
6479
6556
|
const roomKey = roomKeyFromRoutePath(roomRoutePath);
|
|
6480
6557
|
const connKey = roomKey ? `${appId}#room#${roomKey}` : appId;
|
|
6481
6558
|
const connection = connections.get(connKey);
|
|
6482
6559
|
if (!connection || !connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN || connection.isAuthenticating) {
|
|
6483
6560
|
return undefined;
|
|
6484
6561
|
}
|
|
6562
|
+
if (!(await canSendAuthenticatedLiveIntent(connection, isServer))) {
|
|
6563
|
+
return undefined;
|
|
6564
|
+
}
|
|
6485
6565
|
const requestId = generateRequestId();
|
|
6486
6566
|
return new Promise((resolve, reject) => {
|
|
6487
6567
|
const timer = setTimeout(() => {
|
|
@@ -6893,13 +6973,13 @@ async function intent(roomPath, intent, opts = {}) {
|
|
|
6893
6973
|
const hasAuthOverride = !!((_a = opts._overrides) === null || _a === void 0 ? void 0 : _a._getAuthHeaders);
|
|
6894
6974
|
if (!hasAuthOverride) {
|
|
6895
6975
|
if (opts.fireAndForget) {
|
|
6896
|
-
if (wsIntent(config.appId, normalizedRoomPath, intent))
|
|
6976
|
+
if (await wsIntent(config.appId, normalizedRoomPath, intent, config.isServer))
|
|
6897
6977
|
return { ok: true };
|
|
6898
6978
|
}
|
|
6899
6979
|
else {
|
|
6900
|
-
const ack = wsIntentReliable(config.appId, normalizedRoomPath, intent);
|
|
6980
|
+
const ack = await wsIntentReliable(config.appId, normalizedRoomPath, intent, config.isServer);
|
|
6901
6981
|
if (ack)
|
|
6902
|
-
return
|
|
6982
|
+
return ack;
|
|
6903
6983
|
}
|
|
6904
6984
|
}
|
|
6905
6985
|
const base = realtimeHttpBase(config.wsApiUrl);
|