skikrumb-api 2.0.1 → 2.1.2

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,4 +1,4 @@
1
- import { apiKeys, Device, Gateways, QueryDevice, RateRequest, Rates, ExternalUserRequest, ExternalUserResponse } from './models';
1
+ import { apiKeys, Device, Gateways, QueryDevice, RateRequest, Rates, ExternalUserRequest, ExternalUserResponse, ShareLinkRequest, ShareLinkResponse, SharePreviewResponse, ShareAcceptRequest, ShareAcceptResponse } from './models';
2
2
  declare class SkiKrumbRealtimeClient {
3
3
  private websocket;
4
4
  private sessionToken;
@@ -41,6 +41,9 @@ export declare const skiKrumb: (options?: {
41
41
  }) => Promise<unknown>;
42
42
  authenticateExternalUser: (userData: ExternalUserRequest) => Promise<ExternalUserResponse>;
43
43
  refreshSessionToken: (currentToken: string) => Promise<ExternalUserResponse>;
44
+ createSharingLink: (shareRequest: ShareLinkRequest) => Promise<ShareLinkResponse>;
45
+ previewSharingLink: (token: string) => Promise<SharePreviewResponse>;
46
+ acceptSharingLink: (token: string, acceptRequest: ShareAcceptRequest) => Promise<ShareAcceptResponse>;
44
47
  createRealtimeClient: (userId: string, sessionToken?: string, supabaseToken?: string) => SkiKrumbRealtimeClient;
45
48
  };
46
- export type { Device, Gateways, QueryDevice, RateRequest, Rates, apiKeys, ExternalUserRequest, ExternalUserResponse };
49
+ export type { Device, Gateways, QueryDevice, RateRequest, Rates, apiKeys, ExternalUserRequest, ExternalUserResponse, ShareLinkRequest, ShareLinkResponse, SharePreviewResponse, ShareAcceptRequest, ShareAcceptResponse, };
package/dist/index.js CHANGED
@@ -20,7 +20,9 @@ class SkiKrumbRealtimeClient {
20
20
  return Promise.resolve();
21
21
  }
22
22
  // Additional guard: check if we're already connecting or connected
23
- if (this.websocket && (this.websocket.readyState === WebSocket.CONNECTING || this.websocket.readyState === WebSocket.OPEN)) {
23
+ if (this.websocket &&
24
+ (this.websocket.readyState === WebSocket.CONNECTING ||
25
+ this.websocket.readyState === WebSocket.OPEN)) {
24
26
  return Promise.resolve();
25
27
  }
26
28
  // Clean up any stale websocket before creating new one
@@ -39,7 +41,8 @@ class SkiKrumbRealtimeClient {
39
41
  connectToWebSocket() {
40
42
  return new Promise((resolve, reject) => {
41
43
  try {
42
- const baseWsUrl = this.url.replace(/^https/, 'wss').replace(/^http/, 'ws') + '/realtime';
44
+ const baseWsUrl = this.url.replace(/^https/, 'wss').replace(/^http/, 'ws') +
45
+ '/realtime';
43
46
  let wsUrl = `${baseWsUrl}?token=${encodeURIComponent(this.sessionToken)}`;
44
47
  if (this.supabaseToken) {
45
48
  wsUrl += `&supabaseToken=${encodeURIComponent(this.supabaseToken)}`;
@@ -59,7 +62,8 @@ class SkiKrumbRealtimeClient {
59
62
  this.emit('connected', message);
60
63
  resolve();
61
64
  }
62
- else if (message.type === 'auth_error' || message.type === 'error') {
65
+ else if (message.type === 'auth_error' ||
66
+ message.type === 'error') {
63
67
  console.error('❌ Authentication/Connection failed:', message.message || message.error);
64
68
  (_a = this.websocket) === null || _a === void 0 ? void 0 : _a.close();
65
69
  reject(new Error(`Connection failed: ${message.message || message.error}`));
@@ -77,12 +81,18 @@ class SkiKrumbRealtimeClient {
77
81
  // Transform device data to match expected React Native format
78
82
  const deviceData = {
79
83
  ...message.data,
80
- device_id: ((_b = message.data.deveui) === null || _b === void 0 ? void 0 : _b.replace(/'/g, '')) || message.data.device_id,
81
- serial_number: ((_c = message.data.serial_number) === null || _c === void 0 ? void 0 : _c.replace(/'/g, '')) || message.data.serial_number,
82
- gps_fix: ((_d = message.data.gps_fix) === null || _d === void 0 ? void 0 : _d.replace(/'/g, '')) || message.data.gps_fix,
83
- gateway_id: ((_e = message.data.gateway_uuid) === null || _e === void 0 ? void 0 : _e.replace(/'/g, '')) || message.data.gateway_id,
84
- created_at: ((_f = message.data.recorded_at) === null || _f === void 0 ? void 0 : _f.replace(/'/g, '')) || message.data.created_at || message.timestamp,
85
- timestamp: message.timestamp
84
+ device_id: ((_b = message.data.deveui) === null || _b === void 0 ? void 0 : _b.replace(/'/g, '')) ||
85
+ message.data.device_id,
86
+ serial_number: ((_c = message.data.serial_number) === null || _c === void 0 ? void 0 : _c.replace(/'/g, '')) ||
87
+ message.data.serial_number,
88
+ gps_fix: ((_d = message.data.gps_fix) === null || _d === void 0 ? void 0 : _d.replace(/'/g, '')) ||
89
+ message.data.gps_fix,
90
+ gateway_id: ((_e = message.data.gateway_uuid) === null || _e === void 0 ? void 0 : _e.replace(/'/g, '')) ||
91
+ message.data.gateway_id,
92
+ created_at: ((_f = message.data.recorded_at) === null || _f === void 0 ? void 0 : _f.replace(/'/g, '')) ||
93
+ message.data.created_at ||
94
+ message.timestamp,
95
+ timestamp: message.timestamp,
86
96
  };
87
97
  this.emit('device_data', deviceData);
88
98
  }
@@ -103,7 +113,7 @@ class SkiKrumbRealtimeClient {
103
113
  }
104
114
  };
105
115
  this.websocket.onerror = (error) => {
106
- console.error(' Realtime connection error:', error);
116
+ console.warn('⚠️ Realtime connection event');
107
117
  this.isConnecting = false;
108
118
  this.emit('error', error);
109
119
  reject(error);
@@ -161,7 +171,8 @@ class SkiKrumbRealtimeClient {
161
171
  this.websocket.onerror = null;
162
172
  this.websocket.onclose = null;
163
173
  // Close the connection if it's still open
164
- if (this.websocket.readyState === WebSocket.OPEN || this.websocket.readyState === WebSocket.CONNECTING) {
174
+ if (this.websocket.readyState === WebSocket.OPEN ||
175
+ this.websocket.readyState === WebSocket.CONNECTING) {
165
176
  this.websocket.close(1000, 'Manual disconnect');
166
177
  }
167
178
  this.websocket = null;
@@ -174,7 +185,10 @@ class SkiKrumbRealtimeClient {
174
185
  }
175
186
  requestRefresh() {
176
187
  if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
177
- this.websocket.send(JSON.stringify({ type: 'request_refresh', timestamp: new Date().toISOString() }));
188
+ this.websocket.send(JSON.stringify({
189
+ type: 'request_refresh',
190
+ timestamp: new Date().toISOString(),
191
+ }));
178
192
  }
179
193
  }
180
194
  on(event, callback) {
@@ -339,9 +353,7 @@ export const skiKrumb = (options = {
339
353
  'x-client': options.requestedWith,
340
354
  },
341
355
  });
342
- const response = await refreshRequest
343
- .post('auth/external/refresh')
344
- .json();
356
+ const response = await refreshRequest.post('auth/external/refresh').json();
345
357
  return {
346
358
  success: response.success,
347
359
  sessionToken: response.sessionToken,
@@ -355,6 +367,68 @@ export const skiKrumb = (options = {
355
367
  throw error;
356
368
  }
357
369
  };
370
+ const createSharingLink = async (shareRequest) => {
371
+ try {
372
+ const requestWithAuth = ky.create({
373
+ prefixUrl: options.url,
374
+ headers: {
375
+ 'Content-Type': 'application/json',
376
+ Authorization: `Bearer ${options.apiKey}`,
377
+ 'supabase-auth-token': options.supabaseToken || '',
378
+ 'x-client': options.requestedWith,
379
+ },
380
+ });
381
+ const response = await requestWithAuth
382
+ .post('sharing/create', { json: shareRequest })
383
+ .json();
384
+ return response;
385
+ }
386
+ catch (error) {
387
+ console.error('❌ Create Sharing Link Error:', error);
388
+ throw error;
389
+ }
390
+ };
391
+ const previewSharingLink = async (token) => {
392
+ try {
393
+ const requestWithAuth = ky.create({
394
+ prefixUrl: options.url,
395
+ headers: {
396
+ Authorization: `Bearer ${options.apiKey}`,
397
+ 'supabase-auth-token': options.supabaseToken || '',
398
+ 'x-client': options.requestedWith,
399
+ },
400
+ });
401
+ const response = await requestWithAuth
402
+ .get(`sharing/accept/${token}`)
403
+ .json();
404
+ return response;
405
+ }
406
+ catch (error) {
407
+ console.error('❌ Preview Sharing Link Error:', error);
408
+ throw error;
409
+ }
410
+ };
411
+ const acceptSharingLink = async (token, acceptRequest) => {
412
+ try {
413
+ const requestWithAuth = ky.create({
414
+ prefixUrl: options.url,
415
+ headers: {
416
+ 'Content-Type': 'application/json',
417
+ Authorization: `Bearer ${options.apiKey}`,
418
+ 'supabase-auth-token': options.supabaseToken || '',
419
+ 'x-client': options.requestedWith,
420
+ },
421
+ });
422
+ const response = await requestWithAuth
423
+ .post(`sharing/accept/${token}`, { json: acceptRequest })
424
+ .json();
425
+ return response;
426
+ }
427
+ catch (error) {
428
+ console.error('❌ Accept Sharing Link Error:', error);
429
+ throw error;
430
+ }
431
+ };
358
432
  return {
359
433
  createDevice,
360
434
  readDevices,
@@ -366,6 +440,9 @@ export const skiKrumb = (options = {
366
440
  sendMobileLocation,
367
441
  authenticateExternalUser,
368
442
  refreshSessionToken,
443
+ createSharingLink,
444
+ previewSharingLink,
445
+ acceptSharingLink,
369
446
  createRealtimeClient: (userId, sessionToken, supabaseToken) => {
370
447
  if (!sessionToken && !options.apiKey) {
371
448
  throw new Error('Session token or API key required for realtime client');
package/dist/models.d.ts CHANGED
@@ -114,3 +114,95 @@ export interface ExternalUserResponse {
114
114
  serialsCount?: number;
115
115
  timestamp?: string;
116
116
  }
117
+ export interface ShareLinkRequest {
118
+ invited_by: string;
119
+ profiles?: string[];
120
+ share_all: boolean;
121
+ duration_days?: number;
122
+ invited_email?: string;
123
+ }
124
+ export interface ShareLinkResponse {
125
+ success: boolean;
126
+ data?: {
127
+ sharing_link: {
128
+ id: string;
129
+ token: string;
130
+ status: string;
131
+ invited_by: string;
132
+ profiles: string[];
133
+ share_all: boolean;
134
+ link_expiry_date: string | null;
135
+ share_expiry_date: string | null;
136
+ };
137
+ family: {
138
+ id: string;
139
+ account: string;
140
+ invited_account: string | null;
141
+ sharing_link: string;
142
+ share_all: boolean;
143
+ accepted: boolean;
144
+ };
145
+ token: string;
146
+ share_url: string;
147
+ share_type: 'admin' | 'specific_profiles';
148
+ profiles_count: number | 'all';
149
+ expires_at: string | null;
150
+ };
151
+ error?: {
152
+ status: number;
153
+ message: string;
154
+ };
155
+ }
156
+ export interface SharePreviewResponse {
157
+ success: boolean;
158
+ data?: {
159
+ token: string;
160
+ sharing_link: {
161
+ id: string;
162
+ status: string;
163
+ share_all: boolean;
164
+ link_expiry_date: string | null;
165
+ share_expiry_date: string | null;
166
+ };
167
+ inviter: {
168
+ account_id: string;
169
+ name: string;
170
+ email: string;
171
+ };
172
+ share_type: 'admin' | 'specific_profiles';
173
+ profiles: Array<{
174
+ id: string;
175
+ first_name: string;
176
+ last_name: string;
177
+ avatar: string | null;
178
+ }>;
179
+ profiles_count: number | 'all';
180
+ is_expired: boolean;
181
+ can_accept: boolean;
182
+ };
183
+ error?: {
184
+ status: number;
185
+ message: string;
186
+ };
187
+ }
188
+ export interface ShareAcceptRequest {
189
+ accept: boolean;
190
+ invitee_account: string;
191
+ invitee_name?: string;
192
+ invitee_email?: string;
193
+ }
194
+ export interface ShareAcceptResponse {
195
+ success: boolean;
196
+ data?: {
197
+ operation: 'accepted' | 'declined';
198
+ bidirectional: boolean;
199
+ family: any;
200
+ reciprocal_family: any | null;
201
+ accessible_profiles: any[];
202
+ accessible_registrations: any[];
203
+ };
204
+ error?: {
205
+ status: number;
206
+ message: string;
207
+ };
208
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skikrumb-api",
3
- "version": "2.0.1",
3
+ "version": "2.1.2",
4
4
  "description": "Wrapper for the skiKrumb API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",