@livedesk/client 0.1.207 → 0.1.208
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/bin/livedesk-client.js +118 -48
- package/package.json +1 -1
package/bin/livedesk-client.js
CHANGED
|
@@ -47,8 +47,7 @@ const FRESH_REGISTRY_TIMEOUT_MAX_MS = 10000;
|
|
|
47
47
|
// polling must stay interactive instead of backing off to multi-minute waits.
|
|
48
48
|
const DISCOVERY_RETRY_SCHEDULE_MS = [750, 750, 750, 750, 750, 750, 750, 750, 5000];
|
|
49
49
|
const DISCOVERY_RETRY_JITTER_RATIO = 0.2;
|
|
50
|
-
const
|
|
51
|
-
const EXIT_INVALID_PAIR_TOKEN = 23;
|
|
50
|
+
const EXIT_INVALID_PAIR_TOKEN = 23;
|
|
52
51
|
const EXIT_CLIENT_UPDATE = 42;
|
|
53
52
|
const SESSION_REFRESH_SKEW_SECONDS = 60;
|
|
54
53
|
const HUB_TARGET_CACHE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
@@ -2706,9 +2705,10 @@ export async function resolveManagerFromPin(supabase, pin, options = {}) {
|
|
|
2706
2705
|
allowRelayFallback: options.allowRelayFallback === true,
|
|
2707
2706
|
relayEndpoint: options.relayEndpoint,
|
|
2708
2707
|
probeEndpoint: options.probeEndpoint,
|
|
2709
|
-
resolveFreshTarget: async
|
|
2708
|
+
resolveFreshTarget: async signal => {
|
|
2710
2709
|
const { data, error } = await supabase.functions.invoke('livedesk-resolve-remote-host', {
|
|
2711
|
-
body: { pin: normalizedPin }
|
|
2710
|
+
body: { pin: normalizedPin },
|
|
2711
|
+
signal
|
|
2712
2712
|
});
|
|
2713
2713
|
if (error) {
|
|
2714
2714
|
throw await normalizePinResolverInvocationError(error);
|
|
@@ -3667,28 +3667,73 @@ export function resolveManagerFromCachedRelayFallback(ownerKey, options = {}) {
|
|
|
3667
3667
|
};
|
|
3668
3668
|
}
|
|
3669
3669
|
|
|
3670
|
+
function normalizeFreshRegistryTimeoutMs(value) {
|
|
3671
|
+
const configured = Number(value);
|
|
3672
|
+
return Number.isFinite(configured)
|
|
3673
|
+
? Math.max(FRESH_REGISTRY_TIMEOUT_MIN_MS, Math.min(FRESH_REGISTRY_TIMEOUT_MAX_MS, configured))
|
|
3674
|
+
: FRESH_REGISTRY_TIMEOUT_MS;
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3677
|
+
export async function runFreshHubRegistryLookup(resolveFreshTarget, options = {}) {
|
|
3678
|
+
if (typeof resolveFreshTarget !== 'function') {
|
|
3679
|
+
throw createHubDiscoveryError(
|
|
3680
|
+
'fresh-registry-resolver-required',
|
|
3681
|
+
'Fresh Hub registry resolver is required.'
|
|
3682
|
+
);
|
|
3683
|
+
}
|
|
3684
|
+
const timeoutMs = normalizeFreshRegistryTimeoutMs(options.timeoutMs);
|
|
3685
|
+
const controller = new AbortController();
|
|
3686
|
+
let timeoutHandle = null;
|
|
3687
|
+
const lookupOutcome = Promise.resolve()
|
|
3688
|
+
.then(() => resolveFreshTarget(controller.signal))
|
|
3689
|
+
.then(
|
|
3690
|
+
target => ({ type: 'target', target }),
|
|
3691
|
+
error => ({ type: 'error', error })
|
|
3692
|
+
);
|
|
3693
|
+
const timeoutOutcome = new Promise(resolveTimeout => {
|
|
3694
|
+
timeoutHandle = setTimeout(
|
|
3695
|
+
() => resolveTimeout({ type: 'timeout' }),
|
|
3696
|
+
timeoutMs
|
|
3697
|
+
);
|
|
3698
|
+
});
|
|
3699
|
+
const outcomes = [lookupOutcome, timeoutOutcome];
|
|
3700
|
+
if (options.wakePromise && typeof options.wakePromise.then === 'function') {
|
|
3701
|
+
outcomes.push(Promise.resolve(options.wakePromise).then(
|
|
3702
|
+
event => ({ type: 'hub-online', event }),
|
|
3703
|
+
() => new Promise(() => {})
|
|
3704
|
+
));
|
|
3705
|
+
}
|
|
3706
|
+
const outcome = await Promise.race(outcomes).finally(() => {
|
|
3707
|
+
clearTimeout(timeoutHandle);
|
|
3708
|
+
});
|
|
3709
|
+
if (outcome.type === 'hub-online') {
|
|
3710
|
+
controller.abort('hub-online');
|
|
3711
|
+
return outcome;
|
|
3712
|
+
}
|
|
3713
|
+
if (outcome.type === 'timeout') {
|
|
3714
|
+
controller.abort('hub-registry-timeout');
|
|
3715
|
+
throw createHubDiscoveryError(
|
|
3716
|
+
'hub-registry-timeout',
|
|
3717
|
+
`Fresh LiveDesk Hub registry lookup exceeded ${timeoutMs}ms.`
|
|
3718
|
+
);
|
|
3719
|
+
}
|
|
3720
|
+
if (outcome.type === 'error') {
|
|
3721
|
+
controller.abort('hub-registry-error');
|
|
3722
|
+
throw outcome.error;
|
|
3723
|
+
}
|
|
3724
|
+
return outcome;
|
|
3725
|
+
}
|
|
3726
|
+
|
|
3670
3727
|
export async function resolveManagerWithCachedRecovery(ownerKey, options = {}) {
|
|
3671
3728
|
const cached = Object.prototype.hasOwnProperty.call(options, 'cachedTarget')
|
|
3672
3729
|
? normalizeCachedHubTarget(options.cachedTarget, ownerKey, options.now)
|
|
3673
3730
|
: readCachedHubTarget(ownerKey);
|
|
3674
3731
|
try {
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
const
|
|
3680
|
-
? Math.max(FRESH_REGISTRY_TIMEOUT_MIN_MS, Math.min(FRESH_REGISTRY_TIMEOUT_MAX_MS, configuredFreshTimeoutMs))
|
|
3681
|
-
: FRESH_REGISTRY_TIMEOUT_MS;
|
|
3682
|
-
let timeoutHandle = null;
|
|
3683
|
-
const fresh = await Promise.race([
|
|
3684
|
-
Promise.resolve().then(() => options.resolveFreshTarget()),
|
|
3685
|
-
new Promise((_, reject) => {
|
|
3686
|
-
timeoutHandle = setTimeout(() => reject(createHubDiscoveryError(
|
|
3687
|
-
'hub-registry-timeout',
|
|
3688
|
-
`Fresh LiveDesk Hub registry lookup exceeded ${freshTimeoutMs}ms.`
|
|
3689
|
-
)), freshTimeoutMs);
|
|
3690
|
-
})
|
|
3691
|
-
]).finally(() => clearTimeout(timeoutHandle));
|
|
3732
|
+
const freshOutcome = await runFreshHubRegistryLookup(
|
|
3733
|
+
options.resolveFreshTarget,
|
|
3734
|
+
{ timeoutMs: options.freshTimeoutMs }
|
|
3735
|
+
);
|
|
3736
|
+
const fresh = freshOutcome.target;
|
|
3692
3737
|
if (!fresh?.manager || !fresh?.pair) {
|
|
3693
3738
|
throw createHubDiscoveryError('fresh-registry-target-invalid', 'Fresh Hub registry target is incomplete.');
|
|
3694
3739
|
}
|
|
@@ -3770,12 +3815,21 @@ function normalizeEndpointCandidates(target) {
|
|
|
3770
3815
|
}
|
|
3771
3816
|
|
|
3772
3817
|
export async function resolveManagerFromSupabase(supabase, options = {}) {
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
.
|
|
3818
|
+
if (options.signal?.aborted) {
|
|
3819
|
+
throw createHubDiscoveryError('hub-registry-aborted', 'LiveDesk Hub registry lookup was cancelled.');
|
|
3820
|
+
}
|
|
3821
|
+
await refreshSessionIfNeeded(supabase);
|
|
3822
|
+
if (options.signal?.aborted) {
|
|
3823
|
+
throw createHubDiscoveryError('hub-registry-aborted', 'LiveDesk Hub registry lookup was cancelled.');
|
|
3824
|
+
}
|
|
3825
|
+
let query = supabase
|
|
3826
|
+
.from('livedesk_remote_host_targets')
|
|
3827
|
+
.select('node_id, endpoint, endpoint_candidates, pair_token, active, expires_at, updated_at, manager_version')
|
|
3828
|
+
.eq('product_key', 'livedesk');
|
|
3829
|
+
if (options.signal && typeof query.abortSignal === 'function') {
|
|
3830
|
+
query = query.abortSignal(options.signal);
|
|
3831
|
+
}
|
|
3832
|
+
const { data, error } = await query.maybeSingle();
|
|
3779
3833
|
if (error) {
|
|
3780
3834
|
throw error;
|
|
3781
3835
|
}
|
|
@@ -3849,9 +3903,12 @@ async function registerClientDeviceWithSupabase(supabase, options = {}) {
|
|
|
3849
3903
|
}
|
|
3850
3904
|
}
|
|
3851
3905
|
|
|
3852
|
-
async function waitForManagerFromSupabase(supabase, options = {}) {
|
|
3906
|
+
export async function waitForManagerFromSupabase(supabase, options = {}) {
|
|
3853
3907
|
const configuredIntervalMs = Number(options.intervalMs || 0);
|
|
3854
3908
|
const shouldStop = typeof options.shouldStop === 'function' ? options.shouldStop : () => false;
|
|
3909
|
+
const createWakeListener = typeof options.createWakeListener === 'function'
|
|
3910
|
+
? options.createWakeListener
|
|
3911
|
+
: createHubWakeListener;
|
|
3855
3912
|
let attempts = 0;
|
|
3856
3913
|
let lastMessage = '';
|
|
3857
3914
|
let wakeListener = null;
|
|
@@ -3862,6 +3919,17 @@ async function waitForManagerFromSupabase(supabase, options = {}) {
|
|
|
3862
3919
|
if (shouldStop()) {
|
|
3863
3920
|
return null;
|
|
3864
3921
|
}
|
|
3922
|
+
if (!wakeListener) {
|
|
3923
|
+
try {
|
|
3924
|
+
wakeListener = await createWakeListener({
|
|
3925
|
+
getAccessToken: async () => (await refreshSessionIfNeeded(supabase))?.access_token || ''
|
|
3926
|
+
});
|
|
3927
|
+
} catch (error) {
|
|
3928
|
+
if (attempts === 0) {
|
|
3929
|
+
console.warn(`[LiveDesk Client] Hub-online event channel unavailable; adaptive registry retries remain active: ${error?.message || error}`);
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3865
3933
|
attempts += 1;
|
|
3866
3934
|
try {
|
|
3867
3935
|
if (initialError) {
|
|
@@ -3869,9 +3937,24 @@ async function waitForManagerFromSupabase(supabase, options = {}) {
|
|
|
3869
3937
|
initialError = null;
|
|
3870
3938
|
throw error;
|
|
3871
3939
|
}
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3940
|
+
const outcome = await runFreshHubRegistryLookup(
|
|
3941
|
+
signal => resolveManagerFromSupabase(supabase, {
|
|
3942
|
+
allowRelayFallback: options.allowRelayFallback === true,
|
|
3943
|
+
probeEndpoint: options.probeEndpoint,
|
|
3944
|
+
signal
|
|
3945
|
+
}),
|
|
3946
|
+
{
|
|
3947
|
+
timeoutMs: options.freshTimeoutMs,
|
|
3948
|
+
wakePromise: wakeListener?.promise
|
|
3949
|
+
}
|
|
3950
|
+
);
|
|
3951
|
+
if (outcome.type === 'hub-online') {
|
|
3952
|
+
wakeListener?.close();
|
|
3953
|
+
wakeListener = null;
|
|
3954
|
+
console.log('[LiveDesk Client] Hub-online event received. Rechecking the registry now.');
|
|
3955
|
+
continue;
|
|
3956
|
+
}
|
|
3957
|
+
return outcome.target;
|
|
3875
3958
|
} catch (err) {
|
|
3876
3959
|
const message = formatDiscoveryError(err);
|
|
3877
3960
|
if (message !== lastMessage || attempts === 1 || attempts % 6 === 0) {
|
|
@@ -3881,18 +3964,6 @@ async function waitForManagerFromSupabase(supabase, options = {}) {
|
|
|
3881
3964
|
}
|
|
3882
3965
|
}
|
|
3883
3966
|
|
|
3884
|
-
if (!wakeListener) {
|
|
3885
|
-
try {
|
|
3886
|
-
wakeListener = await createHubWakeListener({
|
|
3887
|
-
getAccessToken: async () => (await refreshSessionIfNeeded(supabase))?.access_token || ''
|
|
3888
|
-
});
|
|
3889
|
-
} catch (error) {
|
|
3890
|
-
if (attempts === 1) {
|
|
3891
|
-
console.warn(`[LiveDesk Client] Hub-online event channel unavailable; adaptive registry retries remain active: ${error?.message || error}`);
|
|
3892
|
-
}
|
|
3893
|
-
}
|
|
3894
|
-
}
|
|
3895
|
-
|
|
3896
3967
|
const trigger = await waitForDiscoveryTrigger(
|
|
3897
3968
|
getDiscoveryRetryDelay(attempts, configuredIntervalMs),
|
|
3898
3969
|
wakeListener?.promise,
|
|
@@ -3901,9 +3972,7 @@ async function waitForManagerFromSupabase(supabase, options = {}) {
|
|
|
3901
3972
|
if (trigger.type === 'hub-online') {
|
|
3902
3973
|
wakeListener?.close();
|
|
3903
3974
|
wakeListener = null;
|
|
3904
|
-
|
|
3905
|
-
console.log(`[LiveDesk Client] Hub-online event received. Rechecking the registry in ${jitterMs}ms.`);
|
|
3906
|
-
await waitForDiscoveryTrigger(jitterMs, null, shouldStop);
|
|
3975
|
+
console.log('[LiveDesk Client] Hub-online event received. Rechecking the registry now.');
|
|
3907
3976
|
}
|
|
3908
3977
|
}
|
|
3909
3978
|
} finally {
|
|
@@ -3993,7 +4062,7 @@ async function prepareLoginConnection(parsed, existingConnectionPage = null) {
|
|
|
3993
4062
|
resolved = await resolveManagerWithCachedRecovery(cacheOwnerKey, {
|
|
3994
4063
|
allowRelayFallback,
|
|
3995
4064
|
relayEndpoint: parsed.relay,
|
|
3996
|
-
resolveFreshTarget: async
|
|
4065
|
+
resolveFreshTarget: async signal => {
|
|
3997
4066
|
// The signed registry is authoritative for Hub replacement
|
|
3998
4067
|
// and pair-token rotation. Cache direct/relay recovery is
|
|
3999
4068
|
// considered only after this one current lookup reports
|
|
@@ -4006,7 +4075,8 @@ async function prepareLoginConnection(parsed, existingConnectionPage = null) {
|
|
|
4006
4075
|
console.warn('[LiveDesk Client] Another auth owner rotated the refresh token. Keeping the runtime alive while the saved session catches up.');
|
|
4007
4076
|
}
|
|
4008
4077
|
return await resolveManagerFromSupabase(supabase, {
|
|
4009
|
-
allowRelayFallback
|
|
4078
|
+
allowRelayFallback,
|
|
4079
|
+
signal
|
|
4010
4080
|
});
|
|
4011
4081
|
}
|
|
4012
4082
|
});
|