skikrumb-api 2.1.4 → 2.1.7
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.ts +26 -0
- package/dist/index.js +156 -12
- package/dist/models.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,12 +10,14 @@ declare class SkiKrumbRealtimeClient {
|
|
|
10
10
|
private reconnectAttempts;
|
|
11
11
|
private maxReconnectAttempts;
|
|
12
12
|
private reconnectDelay;
|
|
13
|
+
private maxReconnectDelay;
|
|
13
14
|
constructor(sessionToken: string, userId: string, url: string, supabaseToken?: string);
|
|
14
15
|
connect(): Promise<void>;
|
|
15
16
|
private connectToWebSocket;
|
|
16
17
|
private scheduleReconnect;
|
|
17
18
|
disconnect(): void;
|
|
18
19
|
ping(): void;
|
|
20
|
+
sendPong(): void;
|
|
19
21
|
requestRefresh(): void;
|
|
20
22
|
on(event: string, callback: Function): void;
|
|
21
23
|
off(event: string, callback?: Function): void;
|
|
@@ -45,6 +47,30 @@ export declare const skiKrumb: (options?: {
|
|
|
45
47
|
createSharingLink: (shareRequest: ShareLinkRequest) => Promise<ShareLinkResponse>;
|
|
46
48
|
previewSharingLink: (token: string) => Promise<SharePreviewResponse>;
|
|
47
49
|
acceptSharingLink: (token: string, acceptRequest: ShareAcceptRequest) => Promise<ShareAcceptResponse>;
|
|
50
|
+
shareBack: (targetAccountId: string, durationDays?: number, originalFamilyId?: string) => Promise<any>;
|
|
51
|
+
deleteFamilyShare: (familyId: string) => Promise<{
|
|
52
|
+
success: boolean;
|
|
53
|
+
message?: string;
|
|
54
|
+
error?: any;
|
|
55
|
+
}>;
|
|
56
|
+
updateFamilyShare: (familyId: string, profiles: string[]) => Promise<{
|
|
57
|
+
success: boolean;
|
|
58
|
+
data?: any;
|
|
59
|
+
error?: any;
|
|
60
|
+
}>;
|
|
61
|
+
getReplayData: (serialNumber: string, date: string, size?: number) => Promise<any>;
|
|
62
|
+
getDailyStats: (serialNumber: string, date: string) => Promise<any>;
|
|
63
|
+
getAccessibleProfiles: () => Promise<{
|
|
64
|
+
success: boolean;
|
|
65
|
+
accessibleProfiles: any[];
|
|
66
|
+
profilesCount: number;
|
|
67
|
+
accessibleRegistrations: any[];
|
|
68
|
+
}>;
|
|
69
|
+
getLatestDeviceData: (serialNumber: string) => Promise<{
|
|
70
|
+
success: boolean;
|
|
71
|
+
data?: any;
|
|
72
|
+
error?: any;
|
|
73
|
+
}>;
|
|
48
74
|
createRealtimeClient: (userId: string, sessionToken?: string, supabaseToken?: string) => SkiKrumbRealtimeClient;
|
|
49
75
|
};
|
|
50
76
|
export type { Device, Gateways, QueryDevice, RateRequest, Rates, apiKeys, ExternalUserRequest, ExternalUserResponse, ShareLinkRequest, ShareLinkResponse, SharePreviewResponse, ShareAcceptRequest, ShareAcceptResponse, };
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,9 @@ class SkiKrumbRealtimeClient {
|
|
|
5
5
|
this.listeners = {};
|
|
6
6
|
this.isConnecting = false;
|
|
7
7
|
this.reconnectAttempts = 0;
|
|
8
|
-
this.maxReconnectAttempts =
|
|
9
|
-
this.reconnectDelay = 1000;
|
|
8
|
+
this.maxReconnectAttempts = Infinity; // Never stop trying
|
|
9
|
+
this.reconnectDelay = 1000; // 1 second base
|
|
10
|
+
this.maxReconnectDelay = 300000; // 5 minutes max
|
|
10
11
|
this.sessionToken = sessionToken;
|
|
11
12
|
this.supabaseToken = supabaseToken;
|
|
12
13
|
this.userId = userId;
|
|
@@ -67,6 +68,10 @@ class SkiKrumbRealtimeClient {
|
|
|
67
68
|
(_a = this.websocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
68
69
|
reject(new Error(`Connection failed: ${message.message || message.error}`));
|
|
69
70
|
}
|
|
71
|
+
else if (message.type === 'ping') {
|
|
72
|
+
// Server-initiated ping - respond with pong
|
|
73
|
+
this.sendPong();
|
|
74
|
+
}
|
|
70
75
|
else if (message.type === 'session_replaced') {
|
|
71
76
|
this.emit('session_replaced', message);
|
|
72
77
|
}
|
|
@@ -130,12 +135,8 @@ class SkiKrumbRealtimeClient {
|
|
|
130
135
|
this.emit('disconnected', {
|
|
131
136
|
reason: event.reason || 'Connection closed',
|
|
132
137
|
});
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
this.emit('max_reconnect_attempts_reached');
|
|
138
|
-
}
|
|
138
|
+
// Always try to reconnect with smart backoff
|
|
139
|
+
this.scheduleReconnect();
|
|
139
140
|
}
|
|
140
141
|
};
|
|
141
142
|
}
|
|
@@ -147,12 +148,12 @@ class SkiKrumbRealtimeClient {
|
|
|
147
148
|
}
|
|
148
149
|
scheduleReconnect() {
|
|
149
150
|
this.reconnectAttempts++;
|
|
150
|
-
|
|
151
|
+
// Exponential backoff with 5-minute cap
|
|
152
|
+
const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
|
|
151
153
|
setTimeout(() => {
|
|
152
154
|
this.connect().catch((error) => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
155
|
+
// Errors are expected during reconnection, will keep trying
|
|
156
|
+
// No max attempts check - keeps trying indefinitely with smart backoff
|
|
156
157
|
});
|
|
157
158
|
}, delay);
|
|
158
159
|
}
|
|
@@ -178,6 +179,11 @@ class SkiKrumbRealtimeClient {
|
|
|
178
179
|
this.websocket.send(JSON.stringify({ type: 'ping', timestamp: new Date().toISOString() }));
|
|
179
180
|
}
|
|
180
181
|
}
|
|
182
|
+
sendPong() {
|
|
183
|
+
if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
|
|
184
|
+
this.websocket.send(JSON.stringify({ type: 'pong', timestamp: new Date().toISOString() }));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
181
187
|
requestRefresh() {
|
|
182
188
|
if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
|
|
183
189
|
this.websocket.send(JSON.stringify({
|
|
@@ -395,6 +401,137 @@ export const skiKrumb = (options = {
|
|
|
395
401
|
.json();
|
|
396
402
|
return response;
|
|
397
403
|
};
|
|
404
|
+
const patchSharingLink = async (token, body) => {
|
|
405
|
+
const requestWithAuth = ky.create({
|
|
406
|
+
prefixUrl: options.url,
|
|
407
|
+
headers: {
|
|
408
|
+
'Content-Type': 'application/json',
|
|
409
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
410
|
+
'supabase-auth-token': options.supabaseToken || '',
|
|
411
|
+
'x-client': options.requestedWith,
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
const response = await requestWithAuth
|
|
415
|
+
.patch(`sharing/${token}`, {
|
|
416
|
+
json: body,
|
|
417
|
+
})
|
|
418
|
+
.json();
|
|
419
|
+
return response;
|
|
420
|
+
};
|
|
421
|
+
const shareBack = async (targetAccountId, durationDays, originalFamilyId) => {
|
|
422
|
+
const requestWithAuth = ky.create({
|
|
423
|
+
prefixUrl: options.url,
|
|
424
|
+
headers: {
|
|
425
|
+
'Content-Type': 'application/json',
|
|
426
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
427
|
+
'supabase-auth-token': options.supabaseToken || '',
|
|
428
|
+
'x-client': options.requestedWith,
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
const response = await requestWithAuth
|
|
432
|
+
.post('sharing/share-back', {
|
|
433
|
+
json: {
|
|
434
|
+
target_account_id: targetAccountId,
|
|
435
|
+
duration_days: durationDays,
|
|
436
|
+
original_family_id: originalFamilyId,
|
|
437
|
+
},
|
|
438
|
+
})
|
|
439
|
+
.json();
|
|
440
|
+
return response;
|
|
441
|
+
};
|
|
442
|
+
const getReplayData = async (serialNumber, date, size = 10000) => {
|
|
443
|
+
const requestWithAuth = ky.create({
|
|
444
|
+
prefixUrl: options.url,
|
|
445
|
+
headers: {
|
|
446
|
+
'Content-Type': 'application/json',
|
|
447
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
448
|
+
'supabase-auth-token': options.supabaseToken || '',
|
|
449
|
+
'x-client': options.requestedWith,
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
const response = await requestWithAuth
|
|
453
|
+
.get(`data/replay/${serialNumber}`, {
|
|
454
|
+
searchParams: { date, size },
|
|
455
|
+
})
|
|
456
|
+
.json();
|
|
457
|
+
return response;
|
|
458
|
+
};
|
|
459
|
+
const getDailyStats = async (serialNumber, date) => {
|
|
460
|
+
const requestWithAuth = ky.create({
|
|
461
|
+
prefixUrl: options.url,
|
|
462
|
+
headers: {
|
|
463
|
+
'Content-Type': 'application/json',
|
|
464
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
465
|
+
'supabase-auth-token': options.supabaseToken || '',
|
|
466
|
+
'x-client': options.requestedWith,
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
const response = await requestWithAuth
|
|
470
|
+
.get(`data/stats/${serialNumber}`, {
|
|
471
|
+
searchParams: { date },
|
|
472
|
+
})
|
|
473
|
+
.json();
|
|
474
|
+
return response;
|
|
475
|
+
};
|
|
476
|
+
const getAccessibleProfiles = async () => {
|
|
477
|
+
const requestWithAuth = ky.create({
|
|
478
|
+
prefixUrl: options.url,
|
|
479
|
+
headers: {
|
|
480
|
+
'Content-Type': 'application/json',
|
|
481
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
482
|
+
'supabase-auth-token': options.supabaseToken || '',
|
|
483
|
+
'x-client': options.requestedWith,
|
|
484
|
+
},
|
|
485
|
+
});
|
|
486
|
+
const response = await requestWithAuth.get('auth/profiles').json();
|
|
487
|
+
return response;
|
|
488
|
+
};
|
|
489
|
+
const getLatestDeviceData = async (serialNumber) => {
|
|
490
|
+
const requestWithAuth = ky.create({
|
|
491
|
+
prefixUrl: options.url,
|
|
492
|
+
headers: {
|
|
493
|
+
'Content-Type': 'application/json',
|
|
494
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
495
|
+
'supabase-auth-token': options.supabaseToken || '',
|
|
496
|
+
'x-client': options.requestedWith,
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
const response = await requestWithAuth
|
|
500
|
+
.get(`data/latest/${serialNumber}`)
|
|
501
|
+
.json();
|
|
502
|
+
return response;
|
|
503
|
+
};
|
|
504
|
+
const deleteFamilyShare = async (familyId) => {
|
|
505
|
+
const requestWithAuth = ky.create({
|
|
506
|
+
prefixUrl: options.url,
|
|
507
|
+
headers: {
|
|
508
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
509
|
+
'supabase-auth-token': options.supabaseToken || '',
|
|
510
|
+
'x-client': options.requestedWith,
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
const response = await requestWithAuth
|
|
514
|
+
.delete(`sharing/family/${familyId}`)
|
|
515
|
+
.json();
|
|
516
|
+
return response;
|
|
517
|
+
};
|
|
518
|
+
const updateFamilyShare = async (familyId, profiles) => {
|
|
519
|
+
const requestWithAuth = ky.create({
|
|
520
|
+
prefixUrl: options.url,
|
|
521
|
+
headers: {
|
|
522
|
+
'Content-Type': 'application/json',
|
|
523
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
524
|
+
'supabase-auth-token': options.supabaseToken || '',
|
|
525
|
+
'x-client': options.requestedWith,
|
|
526
|
+
},
|
|
527
|
+
});
|
|
528
|
+
const response = await requestWithAuth
|
|
529
|
+
.patch(`sharing/family/${familyId}`, {
|
|
530
|
+
json: { profiles },
|
|
531
|
+
})
|
|
532
|
+
.json();
|
|
533
|
+
return response;
|
|
534
|
+
};
|
|
398
535
|
return {
|
|
399
536
|
createDevice,
|
|
400
537
|
readDevices,
|
|
@@ -410,6 +547,13 @@ export const skiKrumb = (options = {
|
|
|
410
547
|
createSharingLink,
|
|
411
548
|
previewSharingLink,
|
|
412
549
|
acceptSharingLink,
|
|
550
|
+
shareBack,
|
|
551
|
+
deleteFamilyShare,
|
|
552
|
+
updateFamilyShare,
|
|
553
|
+
getReplayData,
|
|
554
|
+
getDailyStats,
|
|
555
|
+
getAccessibleProfiles,
|
|
556
|
+
getLatestDeviceData,
|
|
413
557
|
createRealtimeClient: (userId, sessionToken, supabaseToken) => {
|
|
414
558
|
if (!sessionToken && !options.apiKey) {
|
|
415
559
|
throw new Error('Session token or API key required for realtime client');
|
package/dist/models.d.ts
CHANGED