@ridesafety/sdk 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,44 @@
1
+ # RideSafety JS/TS SDK
2
+
3
+ ## Install
4
+
5
+ ```bash
6
+ pnpm add @ridesafety/sdk
7
+ ```
8
+
9
+ ## Build & publish
10
+
11
+ ```bash
12
+ cd sdk/js
13
+ npm install
14
+ npm run build
15
+ npm login
16
+ npm publish --access public
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```ts
22
+ import { RideSafetyClient } from "@ridesafety/sdk"
23
+
24
+ const client = new RideSafetyClient({
25
+ apiKey: process.env.RIDESAFETY_API_KEY!,
26
+ baseUrl: "https://ridesafety.app",
27
+ })
28
+
29
+ const recalls = await client.getRecalls({ vin: "1HGBH41JXMN109186" })
30
+ const diagnostics = await client.runDiagnostics({
31
+ vin: "1HGBH41JXMN109186",
32
+ symptoms: "Rough idle and engine misfire",
33
+ dtc_codes: ["P0300"],
34
+ })
35
+ const safety = await client.getSafetyRatings({ make: "Honda", model: "Civic", year: 2020 })
36
+ ```
37
+
38
+ ## Auth modes
39
+
40
+ By default the SDK uses `Authorization: Bearer <key>`. To use `x-api-key` instead:
41
+
42
+ ```ts
43
+ const client = new RideSafetyClient({ apiKey, authMode: "x-api-key" })
44
+ ```
@@ -0,0 +1,141 @@
1
+ export type RecallsQuery = {
2
+ vin?: string;
3
+ make?: string;
4
+ model?: string;
5
+ year?: string | number;
6
+ limit?: number;
7
+ offset?: number;
8
+ };
9
+ export type DiagnosticsRequest = {
10
+ vin: string;
11
+ symptoms?: string;
12
+ dtc_codes?: string[];
13
+ };
14
+ export type SafetyRatingsQuery = {
15
+ make: string;
16
+ model: string;
17
+ year: string | number;
18
+ };
19
+ export type RecallsResponse = {
20
+ vehicle: {
21
+ vin: string | null;
22
+ make: string | null;
23
+ model: string | null;
24
+ year: number | null;
25
+ };
26
+ recalls: Array<{
27
+ id: string | null;
28
+ title: string;
29
+ description: string;
30
+ severity: "Low" | "Medium" | "High";
31
+ date_issued: string | null;
32
+ status: string;
33
+ component: string | null;
34
+ remedy: string | null;
35
+ consequence: string | null;
36
+ summary: string | null;
37
+ }>;
38
+ total_recalls: number;
39
+ pagination: {
40
+ limit: number;
41
+ offset: number;
42
+ total: number;
43
+ hasMore: boolean;
44
+ };
45
+ meta: {
46
+ timestamp: string;
47
+ version: string;
48
+ source: string;
49
+ };
50
+ };
51
+ export type DiagnosticsResponse = {
52
+ data: {
53
+ vin: string;
54
+ diagnosis: {
55
+ primary_issue: string;
56
+ confidence: number;
57
+ severity: string;
58
+ estimated_cost: {
59
+ min: number;
60
+ max: number;
61
+ currency: string;
62
+ };
63
+ recommended_actions: string[];
64
+ };
65
+ related_recalls: Array<{
66
+ recall_id: string;
67
+ title: string;
68
+ severity: string;
69
+ affected_components: string[];
70
+ }>;
71
+ dtc_analysis: Array<{
72
+ code: string;
73
+ description: string;
74
+ severity: string;
75
+ }>;
76
+ timestamp: string;
77
+ };
78
+ meta: {
79
+ timestamp: string;
80
+ version: string;
81
+ processing_time_ms: number;
82
+ };
83
+ };
84
+ export type SafetyRatingsResponse = {
85
+ data: {
86
+ vehicle: {
87
+ make: string;
88
+ model: string;
89
+ year: number;
90
+ };
91
+ nhtsa_rating: {
92
+ overall: number;
93
+ frontal_crash: number;
94
+ side_crash: number;
95
+ rollover: number;
96
+ last_updated: string;
97
+ };
98
+ iihs_rating: {
99
+ top_safety_pick: boolean;
100
+ top_safety_pick_plus: boolean;
101
+ awards: string[];
102
+ tests: Record<string, string>;
103
+ };
104
+ safety_features: string[];
105
+ recalls_summary: {
106
+ total_recalls: number;
107
+ open_recalls: number;
108
+ last_recall_date: string;
109
+ };
110
+ };
111
+ meta: {
112
+ timestamp: string;
113
+ version: string;
114
+ data_sources: string[];
115
+ };
116
+ };
117
+ export declare class RideSafetyError extends Error {
118
+ status: number;
119
+ details?: unknown;
120
+ constructor(status: number, message: string, details?: unknown);
121
+ }
122
+ export type RideSafetyClientOptions = {
123
+ apiKey: string;
124
+ baseUrl?: string;
125
+ timeoutMs?: number;
126
+ authMode?: "bearer" | "x-api-key";
127
+ fetchImpl?: typeof fetch;
128
+ };
129
+ export declare class RideSafetyClient {
130
+ private apiKey;
131
+ private baseUrl;
132
+ private timeoutMs;
133
+ private authMode;
134
+ private fetchImpl;
135
+ constructor(options: RideSafetyClientOptions);
136
+ getRecalls(params: RecallsQuery): Promise<RecallsResponse>;
137
+ runDiagnostics(body: DiagnosticsRequest): Promise<DiagnosticsResponse>;
138
+ getSafetyRatings(params: SafetyRatingsQuery): Promise<SafetyRatingsResponse>;
139
+ private buildHeaders;
140
+ private request;
141
+ }
package/dist/index.js ADDED
@@ -0,0 +1,91 @@
1
+ export class RideSafetyError extends Error {
2
+ constructor(status, message, details) {
3
+ super(message);
4
+ this.name = "RideSafetyError";
5
+ this.status = status;
6
+ this.details = details;
7
+ }
8
+ }
9
+ export class RideSafetyClient {
10
+ constructor(options) {
11
+ this.apiKey = options.apiKey;
12
+ this.baseUrl = (options.baseUrl || "https://ridesafety.app").replace(/\/$/, "");
13
+ this.timeoutMs = options.timeoutMs ?? 20000;
14
+ this.authMode = options.authMode ?? "bearer";
15
+ this.fetchImpl = options.fetchImpl ?? fetch;
16
+ }
17
+ async getRecalls(params) {
18
+ return this.request("/api/v1/recalls", {
19
+ method: "GET",
20
+ query: params,
21
+ });
22
+ }
23
+ async runDiagnostics(body) {
24
+ return this.request("/api/v1/diagnostics", {
25
+ method: "POST",
26
+ body,
27
+ });
28
+ }
29
+ async getSafetyRatings(params) {
30
+ return this.request("/api/v1/safety-ratings", {
31
+ method: "GET",
32
+ query: params,
33
+ });
34
+ }
35
+ buildHeaders() {
36
+ const headers = {
37
+ Accept: "application/json",
38
+ "Content-Type": "application/json",
39
+ };
40
+ if (this.authMode === "x-api-key") {
41
+ headers["x-api-key"] = this.apiKey;
42
+ }
43
+ else {
44
+ headers.Authorization = `Bearer ${this.apiKey}`;
45
+ }
46
+ return headers;
47
+ }
48
+ async request(path, options) {
49
+ const url = new URL(`${this.baseUrl}${path}`);
50
+ if (options.query) {
51
+ Object.entries(options.query).forEach(([key, value]) => {
52
+ if (value === undefined || value === null || value === "")
53
+ return;
54
+ url.searchParams.set(key, String(value));
55
+ });
56
+ }
57
+ const controller = new AbortController();
58
+ const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
59
+ let response;
60
+ try {
61
+ response = await this.fetchImpl(url.toString(), {
62
+ method: options.method,
63
+ headers: this.buildHeaders(),
64
+ body: options.body ? JSON.stringify(options.body) : undefined,
65
+ signal: controller.signal,
66
+ });
67
+ }
68
+ catch (error) {
69
+ clearTimeout(timeoutId);
70
+ throw error;
71
+ }
72
+ finally {
73
+ clearTimeout(timeoutId);
74
+ }
75
+ const text = await response.text();
76
+ const data = text ? tryParseJson(text) : null;
77
+ if (!response.ok) {
78
+ const message = data?.error || response.statusText || "Request failed";
79
+ throw new RideSafetyError(response.status, message, data);
80
+ }
81
+ return (data ?? {});
82
+ }
83
+ }
84
+ function tryParseJson(payload) {
85
+ try {
86
+ return JSON.parse(payload);
87
+ }
88
+ catch {
89
+ return payload;
90
+ }
91
+ }
package/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "@ridesafety/sdk",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": ["dist"],
8
+ "scripts": {
9
+ "build": "tsc -p tsconfig.json"
10
+ },
11
+ "devDependencies": {
12
+ "typescript": "^5.5.4"
13
+ }
14
+ }