@bounded-sh/core 0.0.21 → 0.0.22
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/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
|
@@ -60,7 +60,7 @@ export declare function hasActiveConnection(): boolean;
|
|
|
60
60
|
* room authority — the connection is already routed to the room DO, so the
|
|
61
61
|
* client never names a destination.
|
|
62
62
|
*/
|
|
63
|
-
export declare function wsIntent(appId: string, roomRoutePath: string, intent: unknown): boolean
|
|
63
|
+
export declare function wsIntent(appId: string, roomRoutePath: string, intent: unknown, isServer: boolean): Promise<boolean>;
|
|
64
64
|
/**
|
|
65
65
|
* Send a live-room intent over the EXISTING per-room socket and AWAIT the server
|
|
66
66
|
* ack — so a policy/auth denial (401/403/404/503) REJECTS instead of being
|
|
@@ -69,6 +69,6 @@ export declare function wsIntent(appId: string, roomRoutePath: string, intent: u
|
|
|
69
69
|
* Promise that resolves on ack / rejects on error, or `undefined` if no live
|
|
70
70
|
* socket exists yet (caller falls back to HTTP, which also surfaces errors).
|
|
71
71
|
*/
|
|
72
|
-
export declare function wsIntentReliable(appId: string, roomRoutePath: string, intent: unknown): Promise<{
|
|
72
|
+
export declare function wsIntentReliable(appId: string, roomRoutePath: string, intent: unknown, isServer: boolean): Promise<{
|
|
73
73
|
ok: true;
|
|
74
|
-
}
|
|
74
|
+
} | undefined>;
|
package/dist/index.js
CHANGED
|
@@ -5435,6 +5435,48 @@ function getCacheKey(path, prompt, shape, limit, cursor, filter, identity) {
|
|
|
5435
5435
|
function principalFromIdToken(idToken) {
|
|
5436
5436
|
return idToken ? `t${hashForKey(idToken)}` : null;
|
|
5437
5437
|
}
|
|
5438
|
+
function livePrincipalFromIdToken(idToken) {
|
|
5439
|
+
if (!idToken)
|
|
5440
|
+
return null;
|
|
5441
|
+
try {
|
|
5442
|
+
const payload = JSON.parse(decodeBase64Url(idToken.split('.')[1]));
|
|
5443
|
+
const userId = payload['custom:userId'];
|
|
5444
|
+
if (typeof userId === 'string' && userId.length > 0)
|
|
5445
|
+
return userId;
|
|
5446
|
+
const walletAddress = payload['custom:walletAddress'];
|
|
5447
|
+
if (typeof walletAddress === 'string' && walletAddress.length > 0)
|
|
5448
|
+
return walletAddress;
|
|
5449
|
+
const subject = payload.sub;
|
|
5450
|
+
return typeof subject === 'string' && subject.length > 0 ? subject : null;
|
|
5451
|
+
}
|
|
5452
|
+
catch (_a) {
|
|
5453
|
+
return null;
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
function authSnapshotFromToken(idToken) {
|
|
5457
|
+
return {
|
|
5458
|
+
tokenFingerprint: principalFromIdToken(idToken),
|
|
5459
|
+
principal: livePrincipalFromIdToken(idToken),
|
|
5460
|
+
};
|
|
5461
|
+
}
|
|
5462
|
+
function connectionMatchesAuthToken(connection, idToken) {
|
|
5463
|
+
const current = authSnapshotFromToken(idToken);
|
|
5464
|
+
if (!current.tokenFingerprint) {
|
|
5465
|
+
return connection.authTokenFingerprint === null && connection.authPrincipal === null;
|
|
5466
|
+
}
|
|
5467
|
+
if (connection.authTokenFingerprint && connection.authTokenFingerprint === current.tokenFingerprint) {
|
|
5468
|
+
return true;
|
|
5469
|
+
}
|
|
5470
|
+
return !!connection.authPrincipal && !!current.principal && connection.authPrincipal === current.principal;
|
|
5471
|
+
}
|
|
5472
|
+
async function canSendAuthenticatedLiveIntent(connection, isServer) {
|
|
5473
|
+
const currentToken = await getIdToken(isServer);
|
|
5474
|
+
if (!currentToken)
|
|
5475
|
+
return false;
|
|
5476
|
+
if (!connection.authTokenFingerprint && !connection.authPrincipal)
|
|
5477
|
+
return false;
|
|
5478
|
+
return connectionMatchesAuthToken(connection, currentToken);
|
|
5479
|
+
}
|
|
5438
5480
|
async function getSubscriptionIdentity(effectiveAppId, isServer, overrides) {
|
|
5439
5481
|
// Per-subscription wallet override (server WalletClient.subscribe): key by
|
|
5440
5482
|
// the wallet's own opaque token material, mirroring getReadPrincipalKey. Do
|
|
@@ -5510,6 +5552,9 @@ function rememberAmbientAuthFailure(error) {
|
|
|
5510
5552
|
function failConnectionAuth(connection, error) {
|
|
5511
5553
|
connection.authFailure = error;
|
|
5512
5554
|
connection.pendingAuthToken = null;
|
|
5555
|
+
connection.pendingAuthSnapshot = null;
|
|
5556
|
+
connection.authTokenFingerprint = null;
|
|
5557
|
+
connection.authPrincipal = null;
|
|
5513
5558
|
connection.isConnecting = false;
|
|
5514
5559
|
connection.isConnected = false;
|
|
5515
5560
|
connection.isAuthenticating = false;
|
|
@@ -5728,16 +5773,37 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5728
5773
|
if (connection.authFailure) {
|
|
5729
5774
|
throw connection.authFailure;
|
|
5730
5775
|
}
|
|
5776
|
+
let currentAuthToken;
|
|
5731
5777
|
try {
|
|
5732
|
-
await getConnectionAuthToken(isServer, authTokenProvider);
|
|
5778
|
+
currentAuthToken = await getConnectionAuthToken(isServer, authTokenProvider);
|
|
5733
5779
|
}
|
|
5734
5780
|
catch (error) {
|
|
5735
5781
|
const authError = normalizeAuthExpiredError(error, 'Authentication expired and refresh failed');
|
|
5736
5782
|
failConnectionAuth(connection, authError);
|
|
5737
5783
|
throw authError;
|
|
5738
5784
|
}
|
|
5785
|
+
if (connection.isConnected &&
|
|
5786
|
+
!connection.isAuthenticating &&
|
|
5787
|
+
!connectionMatchesAuthToken(connection, currentAuthToken)) {
|
|
5788
|
+
if (connection.tokenRefreshTimer) {
|
|
5789
|
+
clearInterval(connection.tokenRefreshTimer);
|
|
5790
|
+
connection.tokenRefreshTimer = null;
|
|
5791
|
+
}
|
|
5792
|
+
try {
|
|
5793
|
+
connection.ws.close();
|
|
5794
|
+
}
|
|
5795
|
+
catch (_a) {
|
|
5796
|
+
// Already closing.
|
|
5797
|
+
}
|
|
5798
|
+
connection.ws = null;
|
|
5799
|
+
connection.isConnected = false;
|
|
5800
|
+
connections.delete(connection.key);
|
|
5801
|
+
}
|
|
5802
|
+
else {
|
|
5803
|
+
connection.authFailure = null;
|
|
5804
|
+
return connection;
|
|
5805
|
+
}
|
|
5739
5806
|
connection.authFailure = null;
|
|
5740
|
-
return connection;
|
|
5741
5807
|
}
|
|
5742
5808
|
let initialAuthToken = await getConnectionAuthToken(isServer, authTokenProvider);
|
|
5743
5809
|
// Create new connection
|
|
@@ -5755,6 +5821,9 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5755
5821
|
routePath: roomKey ? routePath : undefined,
|
|
5756
5822
|
authTokenProvider,
|
|
5757
5823
|
pendingAuthToken: null,
|
|
5824
|
+
pendingAuthSnapshot: null,
|
|
5825
|
+
authTokenFingerprint: null,
|
|
5826
|
+
authPrincipal: null,
|
|
5758
5827
|
tokenRefreshTimer: null,
|
|
5759
5828
|
consecutiveAuthFailures: 0,
|
|
5760
5829
|
authFailure: null,
|
|
@@ -5792,6 +5861,7 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5792
5861
|
throw authError;
|
|
5793
5862
|
}
|
|
5794
5863
|
connection.pendingAuthToken = authToken || null;
|
|
5864
|
+
connection.pendingAuthSnapshot = authSnapshotFromToken(authToken);
|
|
5795
5865
|
if (authToken) {
|
|
5796
5866
|
// Successful token acquisition — reset failure counter
|
|
5797
5867
|
connection.consecutiveAuthFailures = 0;
|
|
@@ -5831,6 +5901,8 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5831
5901
|
}
|
|
5832
5902
|
else {
|
|
5833
5903
|
connection.isAuthenticating = false;
|
|
5904
|
+
connection.authTokenFingerprint = null;
|
|
5905
|
+
connection.authPrincipal = null;
|
|
5834
5906
|
replaySubscriptions(connection);
|
|
5835
5907
|
}
|
|
5836
5908
|
});
|
|
@@ -5870,10 +5942,12 @@ async function getOrCreateConnection(appId, isServer, routePath, authTokenProvid
|
|
|
5870
5942
|
return connection;
|
|
5871
5943
|
}
|
|
5872
5944
|
function handleServerMessage(connection, message) {
|
|
5873
|
-
var _a;
|
|
5945
|
+
var _a, _b, _c, _d, _e;
|
|
5874
5946
|
switch (message.type) {
|
|
5875
5947
|
case 'authenticated': {
|
|
5876
5948
|
connection.isAuthenticating = false;
|
|
5949
|
+
connection.authTokenFingerprint = (_b = (_a = connection.pendingAuthSnapshot) === null || _a === void 0 ? void 0 : _a.tokenFingerprint) !== null && _b !== void 0 ? _b : null;
|
|
5950
|
+
connection.authPrincipal = (_d = (_c = connection.pendingAuthSnapshot) === null || _c === void 0 ? void 0 : _c.principal) !== null && _d !== void 0 ? _d : null;
|
|
5877
5951
|
replaySubscriptions(connection);
|
|
5878
5952
|
break;
|
|
5879
5953
|
}
|
|
@@ -5944,7 +6018,7 @@ function handleServerMessage(connection, message) {
|
|
|
5944
6018
|
connection.pendingRequests.delete(message.requestId);
|
|
5945
6019
|
clearTimeout(pendingSet.timer);
|
|
5946
6020
|
if (message.statusCode >= 400) {
|
|
5947
|
-
pendingSet.reject(new Error(((
|
|
6021
|
+
pendingSet.reject(new Error(((_e = message.body) === null || _e === void 0 ? void 0 : _e.message) || `Set failed with status ${message.statusCode}`));
|
|
5948
6022
|
}
|
|
5949
6023
|
else {
|
|
5950
6024
|
pendingSet.resolve(message.body);
|
|
@@ -6472,13 +6546,16 @@ function hasActiveConnection() {
|
|
|
6472
6546
|
* room authority — the connection is already routed to the room DO, so the
|
|
6473
6547
|
* client never names a destination.
|
|
6474
6548
|
*/
|
|
6475
|
-
function wsIntent(appId, roomRoutePath, intent) {
|
|
6549
|
+
async function wsIntent(appId, roomRoutePath, intent, isServer) {
|
|
6476
6550
|
const roomKey = roomKeyFromRoutePath(roomRoutePath);
|
|
6477
6551
|
const connKey = roomKey ? `${appId}#room#${roomKey}` : appId;
|
|
6478
6552
|
const connection = connections.get(connKey);
|
|
6479
6553
|
if (!connection || !connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN || connection.isAuthenticating) {
|
|
6480
6554
|
return false;
|
|
6481
6555
|
}
|
|
6556
|
+
if (!(await canSendAuthenticatedLiveIntent(connection, isServer))) {
|
|
6557
|
+
return false;
|
|
6558
|
+
}
|
|
6482
6559
|
try {
|
|
6483
6560
|
connection.ws.send(JSON.stringify({ type: 'intent', intent }));
|
|
6484
6561
|
return true;
|
|
@@ -6495,13 +6572,16 @@ function wsIntent(appId, roomRoutePath, intent) {
|
|
|
6495
6572
|
* Promise that resolves on ack / rejects on error, or `undefined` if no live
|
|
6496
6573
|
* socket exists yet (caller falls back to HTTP, which also surfaces errors).
|
|
6497
6574
|
*/
|
|
6498
|
-
function wsIntentReliable(appId, roomRoutePath, intent) {
|
|
6575
|
+
async function wsIntentReliable(appId, roomRoutePath, intent, isServer) {
|
|
6499
6576
|
const roomKey = roomKeyFromRoutePath(roomRoutePath);
|
|
6500
6577
|
const connKey = roomKey ? `${appId}#room#${roomKey}` : appId;
|
|
6501
6578
|
const connection = connections.get(connKey);
|
|
6502
6579
|
if (!connection || !connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN || connection.isAuthenticating) {
|
|
6503
6580
|
return undefined;
|
|
6504
6581
|
}
|
|
6582
|
+
if (!(await canSendAuthenticatedLiveIntent(connection, isServer))) {
|
|
6583
|
+
return undefined;
|
|
6584
|
+
}
|
|
6505
6585
|
const requestId = generateRequestId();
|
|
6506
6586
|
return new Promise((resolve, reject) => {
|
|
6507
6587
|
const timer = setTimeout(() => {
|
|
@@ -6913,13 +6993,13 @@ async function intent(roomPath, intent, opts = {}) {
|
|
|
6913
6993
|
const hasAuthOverride = !!((_a = opts._overrides) === null || _a === void 0 ? void 0 : _a._getAuthHeaders);
|
|
6914
6994
|
if (!hasAuthOverride) {
|
|
6915
6995
|
if (opts.fireAndForget) {
|
|
6916
|
-
if (wsIntent(config.appId, normalizedRoomPath, intent))
|
|
6996
|
+
if (await wsIntent(config.appId, normalizedRoomPath, intent, config.isServer))
|
|
6917
6997
|
return { ok: true };
|
|
6918
6998
|
}
|
|
6919
6999
|
else {
|
|
6920
|
-
const ack = wsIntentReliable(config.appId, normalizedRoomPath, intent);
|
|
7000
|
+
const ack = await wsIntentReliable(config.appId, normalizedRoomPath, intent, config.isServer);
|
|
6921
7001
|
if (ack)
|
|
6922
|
-
return
|
|
7002
|
+
return ack;
|
|
6923
7003
|
}
|
|
6924
7004
|
}
|
|
6925
7005
|
const base = realtimeHttpBase(config.wsApiUrl);
|