@gofindme/client 0.1.0

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/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # @gofindme/client
2
+
3
+ Official GoFindMe Location Tracking Client SDK for JavaScript and TypeScript.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @gofindme/client
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { GoFindMeClient } from '@gofindme/client';
15
+
16
+ const client = new GoFindMeClient({
17
+ apiKey: 'your-api-key',
18
+ baseUrl: 'https://api.gofindme.com' // optional, defaults to https://api.gofindme.com
19
+ });
20
+
21
+ // Submit a location update
22
+ await client.submitLocation({
23
+ deviceId: 'device-123',
24
+ latitude: 37.7749,
25
+ longitude: -122.4194,
26
+ recordedAt: new Date()
27
+ });
28
+
29
+ // Stream real-time location updates
30
+ const stream = client.streamLocations();
31
+ stream.addEventListener('location', (event) => {
32
+ const location = JSON.parse(event.data);
33
+ console.log('Location update:', location);
34
+ });
35
+ ```
36
+
37
+ ## API Reference
38
+
39
+ ### `GoFindMeClient`
40
+
41
+ Main client class for interacting with the GoFindMe API.
42
+
43
+ #### Constructor
44
+
45
+ ```typescript
46
+ new GoFindMeClient(config: GoFindMeClientConfig)
47
+ ```
48
+
49
+ **Parameters:**
50
+ - `config.apiKey` (string, required): Your GoFindMe API key
51
+ - `config.baseUrl` (string, optional): Base URL of the GoFindMe API (defaults to `https://api.gofindme.com`)
52
+
53
+ #### Methods
54
+
55
+ ##### `submitLocation(data: LocationUpdatePayload): Promise<LocationResponse>`
56
+
57
+ Submit a location update to the API.
58
+
59
+ **Parameters:**
60
+ - `data.deviceId` (string): Unique identifier for the device
61
+ - `data.latitude` (number): Latitude in decimal degrees (-90 to 90)
62
+ - `data.longitude` (number): Longitude in decimal degrees (-180 to 180)
63
+ - `data.recordedAt` (Date | string): When the location was recorded
64
+ - `data.accuracy` (number, optional): Location accuracy in meters
65
+ - `data.heading` (number, optional): Direction of travel in degrees (0-360)
66
+ - `data.speed` (number, optional): Speed in meters per second
67
+ - `data.metadata` (object, optional): Additional metadata as key-value pairs
68
+ - `data.groupIds` (string[], optional): Array of group IDs to target
69
+
70
+ **Returns:** Promise resolving to `LocationResponse` with `id` and `receivedAt` fields.
71
+
72
+ **Throws:** `GoFindMeError` if the request fails.
73
+
74
+ ##### `streamLocations(): EventSource`
75
+
76
+ Stream location events using Server-Sent Events (SSE).
77
+
78
+ **Returns:** `EventSource` instance that emits the following events:
79
+ - `location`: Emitted when a new location update is received
80
+ - `ready`: Emitted when the stream is ready
81
+ - `heartbeat`: Emitted periodically to keep the connection alive
82
+ - `error`: Emitted when an error occurs
83
+
84
+ **Example:**
85
+ ```typescript
86
+ const stream = client.streamLocations();
87
+
88
+ stream.addEventListener('location', (event) => {
89
+ const location: LocationEvent = JSON.parse(event.data);
90
+ // Handle location update
91
+ });
92
+
93
+ stream.addEventListener('error', (error) => {
94
+ // Handle error
95
+ });
96
+
97
+ // Close the stream when done
98
+ stream.close();
99
+ ```
100
+
101
+ ##### `health(): Promise<HealthResponse>`
102
+
103
+ Check the health status of the GoFindMe API.
104
+
105
+ **Returns:** Promise resolving to `HealthResponse` with `status`, `timestamp`, and `uptime` fields.
106
+
107
+ **Throws:** `GoFindMeError` if the request fails.
108
+
109
+ ## Types
110
+
111
+ ### `LocationUpdatePayload`
112
+
113
+ ```typescript
114
+ interface LocationUpdatePayload {
115
+ deviceId: string;
116
+ latitude: number;
117
+ longitude: number;
118
+ accuracy?: number;
119
+ heading?: number;
120
+ speed?: number;
121
+ recordedAt: Date | string;
122
+ metadata?: Record<string, unknown>;
123
+ payloadVersion?: string;
124
+ groupIds?: string[];
125
+ }
126
+ ```
127
+
128
+ ### `LocationEvent`
129
+
130
+ ```typescript
131
+ interface LocationEvent {
132
+ id: string;
133
+ groupId: string;
134
+ deviceId: string;
135
+ latitude: number;
136
+ longitude: number;
137
+ accuracy?: number | null;
138
+ heading?: number | null;
139
+ speed?: number | null;
140
+ recordedAt: string;
141
+ receivedAt: string;
142
+ metadata?: Record<string, unknown> | null;
143
+ }
144
+ ```
145
+
146
+ ### `LocationResponse`
147
+
148
+ ```typescript
149
+ interface LocationResponse {
150
+ id: string;
151
+ receivedAt: string;
152
+ }
153
+ ```
154
+
155
+ ## Error Handling
156
+
157
+ The client throws `GoFindMeError` instances when API requests fail:
158
+
159
+ ```typescript
160
+ import { GoFindMeClient, GoFindMeError } from '@gofindme/client';
161
+
162
+ try {
163
+ await client.submitLocation({ /* ... */ });
164
+ } catch (error) {
165
+ if (error instanceof GoFindMeError) {
166
+ console.error('API Error:', error.message);
167
+ console.error('Status Code:', error.statusCode);
168
+ console.error('Response:', error.response);
169
+ }
170
+ }
171
+ ```
172
+
173
+ ## License
174
+
175
+ MIT
@@ -0,0 +1,118 @@
1
+ import type { GoFindMeClientConfig, HealthResponse, LocationResponse, LocationUpdatePayload } from './types.js';
2
+ /**
3
+ * GoFindMe Client SDK
4
+ *
5
+ * This client provides methods to interact with the GoFindMe Location Tracking API.
6
+ * It uses API key authentication and supports both submitting locations and
7
+ * streaming real-time location updates.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { GoFindMeClient } from '@gofindme/client';
12
+ *
13
+ * const client = new GoFindMeClient({
14
+ * apiKey: 'your-api-key',
15
+ * baseUrl: 'https://api.gofindme.com'
16
+ * });
17
+ *
18
+ * // Submit a location
19
+ * const response = await client.submitLocation({
20
+ * deviceId: 'device-123',
21
+ * latitude: 37.7749,
22
+ * longitude: -122.4194,
23
+ * recordedAt: new Date()
24
+ * });
25
+ *
26
+ * // Stream locations
27
+ * const stream = client.streamLocations();
28
+ * stream.addEventListener('location', (event) => {
29
+ * const location: LocationEvent = JSON.parse(event.data);
30
+ * console.log('Location update:', location);
31
+ * });
32
+ * ```
33
+ */
34
+ export declare class GoFindMeClient {
35
+ private readonly apiKey;
36
+ private readonly baseUrl;
37
+ /**
38
+ * Create a new GoFindMe client instance
39
+ *
40
+ * @param config - Client configuration
41
+ * @param config.apiKey - Your GoFindMe API key
42
+ * @param config.baseUrl - Base URL of the GoFindMe API (defaults to https://api.gofindme.com)
43
+ */
44
+ constructor(config: GoFindMeClientConfig);
45
+ /**
46
+ * Submit a location update to the GoFindMe API
47
+ *
48
+ * @param data - Location data to submit
49
+ * @returns Promise resolving to the location response
50
+ * @throws {GoFindMeError} If the request fails
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const response = await client.submitLocation({
55
+ * deviceId: 'my-device-123',
56
+ * latitude: 37.7749,
57
+ * longitude: -122.4194,
58
+ * accuracy: 10,
59
+ * speed: 5.2,
60
+ * heading: 45,
61
+ * recordedAt: new Date(),
62
+ * metadata: { battery: 85, signal: 'strong' }
63
+ * });
64
+ * ```
65
+ */
66
+ submitLocation(data: LocationUpdatePayload): Promise<LocationResponse>;
67
+ /**
68
+ * Stream location events using Server-Sent Events (SSE)
69
+ *
70
+ * This method creates a stream that emits location updates in real-time.
71
+ * Since EventSource doesn't support custom headers, this uses fetch() with
72
+ * manual SSE parsing to properly authenticate with the API key.
73
+ *
74
+ * @returns An object with methods to control the stream
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const stream = client.streamLocations();
79
+ *
80
+ * stream.addEventListener('location', (event) => {
81
+ * const location: LocationEvent = event.data;
82
+ * console.log('New location:', location);
83
+ * });
84
+ *
85
+ * stream.addEventListener('error', (error) => {
86
+ * console.error('Stream error:', error);
87
+ * });
88
+ *
89
+ * // Close the stream when done
90
+ * stream.close();
91
+ * ```
92
+ */
93
+ streamLocations(): {
94
+ addEventListener: (event: 'location' | 'ready' | 'heartbeat' | 'error', handler: (event: {
95
+ type: string;
96
+ data: unknown;
97
+ }) => void) => void;
98
+ removeEventListener: (event: 'location' | 'ready' | 'heartbeat' | 'error', handler: (event: {
99
+ type: string;
100
+ data: unknown;
101
+ }) => void) => void;
102
+ close: () => void;
103
+ };
104
+ /**
105
+ * Check the health status of the GoFindMe API
106
+ *
107
+ * @returns Promise resolving to health status
108
+ * @throws {GoFindMeError} If the request fails
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const health = await client.health();
113
+ * console.log('API Status:', health.status);
114
+ * ```
115
+ */
116
+ health(): Promise<HealthResponse>;
117
+ }
118
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC;;;;;;OAMG;gBACS,MAAM,EAAE,oBAAoB;IASxC;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,cAAc,CAClB,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IAuB5B;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,eAAe,IAAI;QACjB,gBAAgB,EAAE,CAChB,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,OAAO,EACnD,OAAO,EAAE,CAAC,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,OAAO,CAAA;SAAE,KAAK,IAAI,KACtD,IAAI,CAAC;QACV,mBAAmB,EAAE,CACnB,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,OAAO,EACnD,OAAO,EAAE,CAAC,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,OAAO,CAAA;SAAE,KAAK,IAAI,KACtD,IAAI,CAAC;QACV,KAAK,EAAE,MAAM,IAAI,CAAC;KACnB;IAsJD;;;;;;;;;;;OAWG;IACG,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;CASxC"}
package/dist/client.js ADDED
@@ -0,0 +1,264 @@
1
+ import { GoFindMeError } from './errors.js';
2
+ /**
3
+ * GoFindMe Client SDK
4
+ *
5
+ * This client provides methods to interact with the GoFindMe Location Tracking API.
6
+ * It uses API key authentication and supports both submitting locations and
7
+ * streaming real-time location updates.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { GoFindMeClient } from '@gofindme/client';
12
+ *
13
+ * const client = new GoFindMeClient({
14
+ * apiKey: 'your-api-key',
15
+ * baseUrl: 'https://api.gofindme.com'
16
+ * });
17
+ *
18
+ * // Submit a location
19
+ * const response = await client.submitLocation({
20
+ * deviceId: 'device-123',
21
+ * latitude: 37.7749,
22
+ * longitude: -122.4194,
23
+ * recordedAt: new Date()
24
+ * });
25
+ *
26
+ * // Stream locations
27
+ * const stream = client.streamLocations();
28
+ * stream.addEventListener('location', (event) => {
29
+ * const location: LocationEvent = JSON.parse(event.data);
30
+ * console.log('Location update:', location);
31
+ * });
32
+ * ```
33
+ */
34
+ export class GoFindMeClient {
35
+ apiKey;
36
+ baseUrl;
37
+ /**
38
+ * Create a new GoFindMe client instance
39
+ *
40
+ * @param config - Client configuration
41
+ * @param config.apiKey - Your GoFindMe API key
42
+ * @param config.baseUrl - Base URL of the GoFindMe API (defaults to https://api.gofindme.com)
43
+ */
44
+ constructor(config) {
45
+ if (!config.apiKey) {
46
+ throw new Error('API key is required');
47
+ }
48
+ this.apiKey = config.apiKey;
49
+ this.baseUrl = config.baseUrl || 'https://api.gofindme.com';
50
+ }
51
+ /**
52
+ * Submit a location update to the GoFindMe API
53
+ *
54
+ * @param data - Location data to submit
55
+ * @returns Promise resolving to the location response
56
+ * @throws {GoFindMeError} If the request fails
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const response = await client.submitLocation({
61
+ * deviceId: 'my-device-123',
62
+ * latitude: 37.7749,
63
+ * longitude: -122.4194,
64
+ * accuracy: 10,
65
+ * speed: 5.2,
66
+ * heading: 45,
67
+ * recordedAt: new Date(),
68
+ * metadata: { battery: 85, signal: 'strong' }
69
+ * });
70
+ * ```
71
+ */
72
+ async submitLocation(data) {
73
+ const response = await fetch(`${this.baseUrl}/api/v1/locations`, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ 'X-API-Key': this.apiKey,
78
+ },
79
+ body: JSON.stringify({
80
+ ...data,
81
+ recordedAt: data.recordedAt instanceof Date
82
+ ? data.recordedAt.toISOString()
83
+ : data.recordedAt,
84
+ }),
85
+ });
86
+ if (!response.ok) {
87
+ throw await GoFindMeError.fromResponse(response);
88
+ }
89
+ return response.json();
90
+ }
91
+ /**
92
+ * Stream location events using Server-Sent Events (SSE)
93
+ *
94
+ * This method creates a stream that emits location updates in real-time.
95
+ * Since EventSource doesn't support custom headers, this uses fetch() with
96
+ * manual SSE parsing to properly authenticate with the API key.
97
+ *
98
+ * @returns An object with methods to control the stream
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * const stream = client.streamLocations();
103
+ *
104
+ * stream.addEventListener('location', (event) => {
105
+ * const location: LocationEvent = event.data;
106
+ * console.log('New location:', location);
107
+ * });
108
+ *
109
+ * stream.addEventListener('error', (error) => {
110
+ * console.error('Stream error:', error);
111
+ * });
112
+ *
113
+ * // Close the stream when done
114
+ * stream.close();
115
+ * ```
116
+ */
117
+ streamLocations() {
118
+ const url = `${this.baseUrl}/api/v1/stream`;
119
+ const eventHandlers = new Map();
120
+ let abortController = null;
121
+ let reader = null;
122
+ let isClosed = false;
123
+ const addEventListener = (event, handler) => {
124
+ if (!eventHandlers.has(event)) {
125
+ eventHandlers.set(event, new Set());
126
+ }
127
+ eventHandlers.get(event).add(handler);
128
+ };
129
+ const removeEventListener = (event, handler) => {
130
+ eventHandlers.get(event)?.delete(handler);
131
+ };
132
+ const emit = (type, data) => {
133
+ const handlers = eventHandlers.get(type);
134
+ if (handlers) {
135
+ handlers.forEach((handler) => handler({ type, data }));
136
+ }
137
+ };
138
+ const close = () => {
139
+ if (isClosed)
140
+ return;
141
+ isClosed = true;
142
+ abortController?.abort();
143
+ reader?.cancel().catch(() => {
144
+ // Ignore cancel errors
145
+ });
146
+ eventHandlers.clear();
147
+ };
148
+ // Start the stream
149
+ abortController = new AbortController();
150
+ fetch(url, {
151
+ method: 'GET',
152
+ headers: {
153
+ 'X-API-Key': this.apiKey,
154
+ Accept: 'text/event-stream',
155
+ },
156
+ signal: abortController.signal,
157
+ })
158
+ .then(async (response) => {
159
+ if (!response.ok) {
160
+ emit('error', {
161
+ status: response.status,
162
+ statusText: response.statusText,
163
+ message: `HTTP ${response.status}: ${response.statusText}`,
164
+ });
165
+ close();
166
+ return;
167
+ }
168
+ if (!response.body) {
169
+ emit('error', { message: 'Response body is null' });
170
+ close();
171
+ return;
172
+ }
173
+ reader = response.body.getReader();
174
+ const decoder = new TextDecoder();
175
+ let buffer = '';
176
+ try {
177
+ while (true) {
178
+ const { value, done } = await reader.read();
179
+ if (done) {
180
+ close();
181
+ break;
182
+ }
183
+ buffer += decoder.decode(value, { stream: true });
184
+ // Process complete SSE messages (separated by double newline)
185
+ let boundary = buffer.indexOf('\n\n');
186
+ while (boundary !== -1) {
187
+ const eventString = buffer.slice(0, boundary).trim();
188
+ buffer = buffer.slice(boundary + 2);
189
+ boundary = buffer.indexOf('\n\n');
190
+ if (eventString) {
191
+ let eventType = 'message';
192
+ let eventData = '';
193
+ // Parse SSE format: "event: <type>\ndata: <data>"
194
+ for (const line of eventString.split('\n')) {
195
+ const colonIndex = line.indexOf(':');
196
+ if (colonIndex === -1)
197
+ continue;
198
+ const field = line.slice(0, colonIndex).trim();
199
+ const value = line.slice(colonIndex + 1).trim();
200
+ if (field === 'event') {
201
+ eventType = value;
202
+ }
203
+ else if (field === 'data') {
204
+ eventData = value;
205
+ }
206
+ }
207
+ try {
208
+ const parsedData = JSON.parse(eventData);
209
+ emit(eventType, parsedData);
210
+ }
211
+ catch {
212
+ // If parsing fails, emit raw data
213
+ emit(eventType, eventData);
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ catch (error) {
220
+ if (!isClosed) {
221
+ emit('error', {
222
+ message: error instanceof Error ? error.message : 'Unknown stream error',
223
+ error,
224
+ });
225
+ close();
226
+ }
227
+ }
228
+ })
229
+ .catch((error) => {
230
+ if (!isClosed && error.name !== 'AbortError') {
231
+ emit('error', {
232
+ message: error instanceof Error ? error.message : 'Connection failed',
233
+ error,
234
+ });
235
+ close();
236
+ }
237
+ });
238
+ return {
239
+ addEventListener,
240
+ removeEventListener,
241
+ close,
242
+ };
243
+ }
244
+ /**
245
+ * Check the health status of the GoFindMe API
246
+ *
247
+ * @returns Promise resolving to health status
248
+ * @throws {GoFindMeError} If the request fails
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * const health = await client.health();
253
+ * console.log('API Status:', health.status);
254
+ * ```
255
+ */
256
+ async health() {
257
+ const response = await fetch(`${this.baseUrl}/api/v1/health`);
258
+ if (!response.ok) {
259
+ throw await GoFindMeError.fromResponse(response);
260
+ }
261
+ return response.json();
262
+ }
263
+ }
264
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Custom error class for GoFindMe API errors
3
+ */
4
+ export declare class GoFindMeError extends Error {
5
+ statusCode?: number | undefined;
6
+ response?: unknown | undefined;
7
+ constructor(message: string, statusCode?: number | undefined, response?: unknown | undefined);
8
+ static fromResponse(response: Response): Promise<GoFindMeError>;
9
+ }
10
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAG7B,UAAU,CAAC,EAAE,MAAM;IACnB,QAAQ,CAAC,EAAE,OAAO;gBAFzB,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,QAAQ,CAAC,EAAE,OAAO,YAAA;WAOd,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC;CAsBtE"}
package/dist/errors.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Custom error class for GoFindMe API errors
3
+ */
4
+ export class GoFindMeError extends Error {
5
+ statusCode;
6
+ response;
7
+ constructor(message, statusCode, response) {
8
+ super(message);
9
+ this.statusCode = statusCode;
10
+ this.response = response;
11
+ this.name = 'GoFindMeError';
12
+ Object.setPrototypeOf(this, GoFindMeError.prototype);
13
+ }
14
+ static async fromResponse(response) {
15
+ let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
16
+ let errorData = null;
17
+ try {
18
+ const contentType = response.headers.get('content-type');
19
+ if (contentType?.includes('application/json')) {
20
+ errorData = await response.json();
21
+ errorMessage = errorData?.message || errorMessage;
22
+ }
23
+ else {
24
+ const text = await response.text();
25
+ if (text) {
26
+ errorMessage = text;
27
+ errorData = text;
28
+ }
29
+ }
30
+ }
31
+ catch {
32
+ // Ignore parsing errors, use default message
33
+ }
34
+ return new GoFindMeError(errorMessage, response.status, errorData);
35
+ }
36
+ }
37
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAG7B;IACA;IAHT,YACE,OAAe,EACR,UAAmB,EACnB,QAAkB;QAEzB,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,eAAU,GAAV,UAAU,CAAS;QACnB,aAAQ,GAAR,QAAQ,CAAU;QAGzB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,QAAkB;QAC1C,IAAI,YAAY,GAAG,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC;QACrE,IAAI,SAAS,GAAY,IAAI,CAAC;QAE9B,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YACzD,IAAI,WAAW,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC9C,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAClC,YAAY,GAAI,SAAkC,EAAE,OAAO,IAAI,YAAY,CAAC;YAC9E,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,IAAI,EAAE,CAAC;oBACT,YAAY,GAAG,IAAI,CAAC;oBACpB,SAAS,GAAG,IAAI,CAAC;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,6CAA6C;QAC/C,CAAC;QAED,OAAO,IAAI,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrE,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ export { GoFindMeClient } from './client.js';
2
+ export type { LocationUpdatePayload, LocationResponse, LocationEvent, GoFindMeClientConfig, HealthResponse, } from './types.js';
3
+ export { GoFindMeError } from './errors.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EACV,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACpB,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { GoFindMeClient } from './client.js';
2
+ export { GoFindMeError } from './errors.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQ7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Location update payload for submitting location data
3
+ */
4
+ export interface LocationUpdatePayload {
5
+ /** Unique identifier for the device */
6
+ deviceId: string;
7
+ /** Latitude in decimal degrees (-90 to 90) */
8
+ latitude: number;
9
+ /** Longitude in decimal degrees (-180 to 180) */
10
+ longitude: number;
11
+ /** Location accuracy in meters (optional) */
12
+ accuracy?: number;
13
+ /** Direction of travel in degrees (0-360, optional) */
14
+ heading?: number;
15
+ /** Speed in meters per second (optional) */
16
+ speed?: number;
17
+ /** When the location was recorded (ISO 8601 string or Date) */
18
+ recordedAt: Date | string;
19
+ /** Additional metadata as key-value pairs (optional) */
20
+ metadata?: Record<string, unknown>;
21
+ /** Payload version (defaults to 'v1') */
22
+ payloadVersion?: string;
23
+ /** Optional array of group IDs to target (optional) */
24
+ groupIds?: string[];
25
+ }
26
+ /**
27
+ * Response from submitting a location update
28
+ */
29
+ export interface LocationResponse {
30
+ /** Unique identifier for the location record */
31
+ id: string;
32
+ /** ISO 8601 timestamp when the location was received */
33
+ receivedAt: string;
34
+ }
35
+ /**
36
+ * Location event received from the stream
37
+ */
38
+ export interface LocationEvent {
39
+ /** Unique identifier for the location record */
40
+ id: string;
41
+ /** Group ID this location belongs to */
42
+ groupId: string;
43
+ /** Device ID that reported this location */
44
+ deviceId: string;
45
+ /** Latitude in decimal degrees */
46
+ latitude: number;
47
+ /** Longitude in decimal degrees */
48
+ longitude: number;
49
+ /** Location accuracy in meters (may be null) */
50
+ accuracy?: number | null;
51
+ /** Direction of travel in degrees (may be null) */
52
+ heading?: number | null;
53
+ /** Speed in meters per second (may be null) */
54
+ speed?: number | null;
55
+ /** ISO 8601 timestamp when the location was recorded */
56
+ recordedAt: string;
57
+ /** ISO 8601 timestamp when the location was received by the server */
58
+ receivedAt: string;
59
+ /** Additional metadata (may be null) */
60
+ metadata?: Record<string, unknown> | null;
61
+ }
62
+ /**
63
+ * Configuration for the GoFindMe client
64
+ */
65
+ export interface GoFindMeClientConfig {
66
+ /** API key for authentication */
67
+ apiKey: string;
68
+ /** Base URL of the GoFindMe API (defaults to https://api.gofindme.com) */
69
+ baseUrl?: string;
70
+ }
71
+ /**
72
+ * Health check response
73
+ */
74
+ export interface HealthResponse {
75
+ /** Health status */
76
+ status: string;
77
+ /** ISO 8601 timestamp */
78
+ timestamp?: string;
79
+ /** Server uptime in seconds */
80
+ uptime?: number;
81
+ }
82
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,UAAU,EAAE,IAAI,GAAG,MAAM,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC3C;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oBAAoB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@gofindme/client",
3
+ "version": "0.1.0",
4
+ "description": "GoFindMe Location Tracking Client SDK",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "type": "module",
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "prepublishOnly": "npm run build",
16
+ "clean": "rm -rf dist"
17
+ },
18
+ "keywords": [
19
+ "location",
20
+ "tracking",
21
+ "gps",
22
+ "geolocation",
23
+ "realtime"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/yourusername/gofindme-server.git",
33
+ "directory": "packages/client"
34
+ },
35
+ "exports": {
36
+ ".": {
37
+ "import": "./dist/index.js",
38
+ "types": "./dist/index.d.ts"
39
+ }
40
+ }
41
+ }