skikrumb-api 2.1.9 → 2.1.11

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 CHANGED
@@ -1,17 +1,19 @@
1
- import { apiKeys, Device, Gateways, QueryDevice, RateRequest, Rates, ExternalUserRequest, ExternalUserResponse, ShareLinkRequest, ShareLinkResponse, SharePreviewResponse, ShareAcceptRequest, ShareAcceptResponse } from './models';
1
+ import { apiKeys, Device, Gateways, QueryDevice, RateRequest, Rates, ExternalUserRequest, ExternalUserResponse, ShareLinkRequest, ShareLinkResponse, SharePreviewResponse, ShareAcceptRequest, ShareAcceptResponse, Data } from './models';
2
+ type RealtimeEndpointType = 'user' | 'organization';
2
3
  declare class SkiKrumbRealtimeClient {
3
4
  private websocket;
4
- private sessionToken;
5
+ private sessionToken?;
5
6
  private supabaseToken?;
6
7
  private url;
7
8
  private userId;
9
+ private endpointType;
8
10
  private listeners;
9
11
  private isConnecting;
10
12
  private reconnectAttempts;
11
13
  private maxReconnectAttempts;
12
14
  private reconnectDelay;
13
15
  private maxReconnectDelay;
14
- constructor(sessionToken: string, userId: string, url: string, supabaseToken?: string);
16
+ constructor(userId: string, url: string, endpointType: RealtimeEndpointType, sessionToken?: string, supabaseToken?: string);
15
17
  connect(): Promise<void>;
16
18
  private connectToWebSocket;
17
19
  private scheduleReconnect;
@@ -36,6 +38,7 @@ export declare const skiKrumb: (options?: {
36
38
  readDeviceDailyDistance: (deviceSerialNumber: string) => Promise<unknown>;
37
39
  readDeviceData: (deviceSerialNumber: string, limit?: number) => Promise<unknown>;
38
40
  readDataForDevices: (query: QueryDevice) => Promise<Device[]>;
41
+ readOrganizationData: () => Promise<Data[]>;
39
42
  readGateways: () => Promise<Gateways>;
40
43
  readShippingRates: (rateRequest: RateRequest) => Promise<Rates>;
41
44
  sendMobileLocation: (payload: {
@@ -71,6 +74,6 @@ export declare const skiKrumb: (options?: {
71
74
  data?: any;
72
75
  error?: any;
73
76
  }>;
74
- createRealtimeClient: (userId: string, sessionToken?: string, supabaseToken?: string) => SkiKrumbRealtimeClient;
77
+ createRealtimeClient: (userId: string, sessionToken?: string, supabaseToken?: string, endpointType?: RealtimeEndpointType) => SkiKrumbRealtimeClient;
75
78
  };
76
- export type { Device, Gateways, QueryDevice, RateRequest, Rates, apiKeys, ExternalUserRequest, ExternalUserResponse, ShareLinkRequest, ShareLinkResponse, SharePreviewResponse, ShareAcceptRequest, ShareAcceptResponse, };
79
+ export type { Device, Gateways, QueryDevice, RateRequest, Rates, apiKeys, ExternalUserRequest, ExternalUserResponse, ShareLinkRequest, ShareLinkResponse, SharePreviewResponse, ShareAcceptRequest, ShareAcceptResponse, RealtimeEndpointType, };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import ky from 'ky';
2
2
  class SkiKrumbRealtimeClient {
3
- constructor(sessionToken, userId, url, supabaseToken) {
3
+ constructor(userId, url, endpointType, sessionToken, supabaseToken) {
4
4
  this.websocket = null;
5
5
  this.listeners = {};
6
6
  this.isConnecting = false;
@@ -8,10 +8,11 @@ class SkiKrumbRealtimeClient {
8
8
  this.maxReconnectAttempts = Infinity; // Never stop trying
9
9
  this.reconnectDelay = 1000; // 1 second base
10
10
  this.maxReconnectDelay = 300000; // 5 minutes max
11
- this.sessionToken = sessionToken;
12
- this.supabaseToken = supabaseToken;
13
11
  this.userId = userId;
14
12
  this.url = url.replace(/\/+$/, ''); // Remove trailing slashes
13
+ this.endpointType = endpointType;
14
+ this.sessionToken = sessionToken;
15
+ this.supabaseToken = supabaseToken;
15
16
  }
16
17
  async connect() {
17
18
  if (this.isConnecting) {
@@ -42,12 +43,16 @@ class SkiKrumbRealtimeClient {
42
43
  connectToWebSocket() {
43
44
  return new Promise((resolve, reject) => {
44
45
  try {
45
- const baseWsUrl = this.url.replace(/^https/, 'wss').replace(/^http/, 'ws') +
46
- '/realtime';
47
- let wsUrl = `${baseWsUrl}?token=${encodeURIComponent(this.sessionToken)}`;
48
- if (this.supabaseToken) {
49
- wsUrl += `&supabaseToken=${encodeURIComponent(this.supabaseToken)}`;
46
+ const baseWsUrl = this.url.replace(/^https/, 'wss').replace(/^http/, 'ws');
47
+ let wsUrl;
48
+ let endpointPath = `/realtime${this.endpointType === 'organization' ? '/organization' : ''}`;
49
+ if (!this.supabaseToken) {
50
+ return reject(new Error('Supabase token is required for organization endpoint.'));
51
+ }
52
+ if (!this.sessionToken) {
53
+ return reject(new Error('Session token is required for user endpoint.'));
50
54
  }
55
+ wsUrl = `${baseWsUrl}${endpointPath}?token=${encodeURIComponent(this.sessionToken)}&supabaseToken=${encodeURIComponent(this.supabaseToken)}`;
51
56
  this.websocket = new WebSocket(wsUrl);
52
57
  this.websocket.onopen = () => {
53
58
  // Authentication is handled automatically via query parameters
@@ -214,7 +219,8 @@ class SkiKrumbRealtimeClient {
214
219
  try {
215
220
  callback(data);
216
221
  }
217
- catch (error) { }
222
+ catch (error) {
223
+ }
218
224
  });
219
225
  }
220
226
  isConnected() {
@@ -235,6 +241,22 @@ export const skiKrumb = (options = {
235
241
  'x-client': options.requestedWith,
236
242
  },
237
243
  });
244
+ const requestWithTimeZone = request.extend({
245
+ hooks: {
246
+ beforeRequest: [
247
+ (request) => {
248
+ // Get the client's timezone
249
+ const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
250
+ // Add the TimeZone header
251
+ request.headers.set('TimeZone', clientTimeZone);
252
+ // Add the supabase token if it exists
253
+ if (options.supabaseToken) {
254
+ request.headers.set('supabase-auth-token', options.supabaseToken);
255
+ }
256
+ },
257
+ ],
258
+ },
259
+ });
238
260
  // Device API endpoints
239
261
  const createDevice = async (device) => {
240
262
  const response = await request
@@ -288,12 +310,17 @@ export const skiKrumb = (options = {
288
310
  const readDataForDevices = async (query) => {
289
311
  if (!query.serial_numbers)
290
312
  throw new Error('Serial number is required');
291
- return request
313
+ return requestWithTimeZone
292
314
  .get('devices/data', {
293
315
  searchParams: new URLSearchParams({ ...query }),
294
316
  })
295
317
  .json();
296
318
  };
319
+ const readOrganizationData = async () => {
320
+ return requestWithTimeZone
321
+ .get('devices/data/organization')
322
+ .json();
323
+ };
297
324
  const readGateways = async () => {
298
325
  try {
299
326
  const response = await request.get('gateways').json();
@@ -532,6 +559,20 @@ export const skiKrumb = (options = {
532
559
  .json();
533
560
  return response;
534
561
  };
562
+ const createRealtimeClient = (userId, sessionToken, supabaseToken, endpointType = 'user') => {
563
+ if (!userId) {
564
+ throw new Error('User ID is required for realtime client');
565
+ }
566
+ const token = sessionToken || options.apiKey;
567
+ const finalSupabaseToken = supabaseToken || options.supabaseToken;
568
+ if (!finalSupabaseToken) {
569
+ throw new Error('A Supabase token is required for the organization endpoint.');
570
+ }
571
+ if (!token) {
572
+ throw new Error('A session token (or API key) is required for the user endpoint.');
573
+ }
574
+ return new SkiKrumbRealtimeClient(userId, options.url || 'https://api.skikrumb.ca', endpointType, token, finalSupabaseToken);
575
+ };
535
576
  return {
536
577
  createDevice,
537
578
  readDevices,
@@ -539,6 +580,7 @@ export const skiKrumb = (options = {
539
580
  readDeviceDailyDistance,
540
581
  readDeviceData,
541
582
  readDataForDevices,
583
+ readOrganizationData,
542
584
  readGateways,
543
585
  readShippingRates,
544
586
  sendMobileLocation,
@@ -554,16 +596,6 @@ export const skiKrumb = (options = {
554
596
  getDailyStats,
555
597
  getAccessibleProfiles,
556
598
  getLatestDeviceData,
557
- createRealtimeClient: (userId, sessionToken, supabaseToken) => {
558
- if (!sessionToken && !options.apiKey) {
559
- throw new Error('Session token or API key required for realtime client');
560
- }
561
- if (!userId) {
562
- throw new Error('User ID is required for realtime client');
563
- }
564
- // Use provided session token or fall back to API key for backward compatibility
565
- const token = sessionToken || options.apiKey;
566
- return new SkiKrumbRealtimeClient(token, userId, options.url || 'https://api.skikrumb.ca', supabaseToken);
567
- },
599
+ createRealtimeClient,
568
600
  };
569
601
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skikrumb-api",
3
- "version": "2.1.9",
3
+ "version": "2.1.11",
4
4
  "description": "Wrapper for the skiKrumb API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,11 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Read(//Users/michael/.config/nvim/**)",
5
- "Read(//Users/michael/.config/**)",
6
- "Read(//Users/michael/Code/skikrumb-api/**)"
7
- ],
8
- "deny": [],
9
- "ask": []
10
- }
11
- }