@sonatel-os/openapi-runtime 0.1.0 โ†’ 0.2.1

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 CHANGED
@@ -1,29 +1,54 @@
1
- # ๐ŸŠ @sonatel-os/openapi-runtime
1
+ <div align="center">
2
2
 
3
- **Stop generating code. Start calling APIs.**
3
+ # ๐Ÿ”ฅ @sonatel-os/openapi-runtime
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@sonatel-os/openapi-runtime)](https://www.npmjs.com/package/@sonatel-os/openapi-runtime)
6
- ![npm downloads](https://img.shields.io/npm/dm/@sonatel-os/openapi-runtime)
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ ### *"We deleted your SDK. You're welcome."* ๐Ÿ’…
8
6
 
9
- A lightweight, dynamic runtime wrapper for OpenAPI (Swagger) v3.
10
- Consume APIs, validate payloads, and mock responses instantly ; without regenerating thousands of lines of JavaScript SDKs every time your backend changes.
7
+ [![npm version](https://img.shields.io/npm/v/@sonatel-os/openapi-runtime?style=for-the-badge&color=ff6b6b)](https://www.npmjs.com/package/@sonatel-os/openapi-runtime)
8
+ [![npm downloads](https://img.shields.io/npm/dm/@sonatel-os/openapi-runtime?style=for-the-badge&color=4ecdc4)](https://www.npmjs.com/package/@sonatel-os/openapi-runtime)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge&color=ffe66d)](https://opensource.org/licenses/MIT)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg?style=for-the-badge&color=95e1d3)](https://www.typescriptlang.org/)
11
+ [![Zero Codegen](https://img.shields.io/badge/Codegen-Zero-green.svg?style=for-the-badge&color=a8e6cf)](#)
12
+
13
+ **The enterprise-grade, zero-codegen OpenAPI runtime.** โœจ
14
+
15
+ *Load specs dynamically. Execute APIs instantly. Sleep peacefully.* ๐Ÿ˜ด
16
+
17
+ <br>
18
+
19
+ ```diff
20
+ - Before: 47 generated files, 12,000 lines, 3 merge conflicts, 1 existential crisis ๐Ÿ˜ญ
21
+ + After: 1 import, 2 lines, 0 problems, mass enlightenment ๐Ÿง˜
22
+ ```
23
+
24
+ <br>
25
+
26
+ [Get Started](#-quick-start) ยท [Features](#-features-that-slap) ยท [Auth Magic](#-authentication-the-magic-part) ยท [API Reference](#-api-reference)
27
+
28
+ </div>
11
29
 
12
30
  ---
13
31
 
14
- ## ๐Ÿš€ Why?
32
+ ## ๐Ÿ˜ค The Problem
15
33
 
16
- **The Old Way (Codegen):**
17
- 1. Backend updates `swagger.json`.
18
- 2. You run `openapi-generator`.
19
- 3. You wait.
20
- 4. You get 50 new files and a git conflict.
21
- 5. Repeat.
34
+ Every time your backend updates their Swagger spec:
22
35
 
23
- **The Runtime Way:**
24
- 1. Drop `api.json` into your project.
25
- 2. Call `runtime.executeAPI('getUsers')`.
26
- 3. Done.
36
+ ```
37
+ 1. Run openapi-generator โณ (2 minutes of your life)
38
+ 2. Watch 50 files regenerate ๐Ÿ˜ฐ (existential dread intensifies)
39
+ 3. Resolve merge conflicts ๐Ÿ”ฅ (45 minutes + therapy needed)
40
+ 4. Realize half the types broke ๐Ÿ˜ฑ (scream internally)
41
+ 5. Repeat next sprint ๐Ÿ’€ (question career choices)
42
+ ```
43
+
44
+ ## ๐Ÿ˜Ž The Solution
45
+
46
+ ```javascript
47
+ await runtime.executeAPI({ name: 'users', api: 'getUser', params: { id: 42 } })
48
+ // That's it. That's the tweet. ๐Ÿฆ
49
+ ```
50
+
51
+ **Zero generation. Zero maintenance. Zero drama.** ๐Ÿ’†
27
52
 
28
53
  ---
29
54
 
@@ -31,161 +56,517 @@ Consume APIs, validate payloads, and mock responses instantly ; without regenera
31
56
 
32
57
  ```bash
33
58
  npm install @sonatel-os/openapi-runtime
34
- # or
59
+ ```
60
+
61
+ ```bash
35
62
  yarn add @sonatel-os/openapi-runtime
36
63
  ```
37
64
 
38
- -----
65
+ ```bash
66
+ pnpm add @sonatel-os/openapi-runtime
67
+ ```
68
+
69
+ > **Requirements:** Node.js 18+ *(we're not savages)* ๐Ÿฆ–
39
70
 
40
- ## โšก๏ธ Quick Start
71
+ ---
41
72
 
42
- ### 1\. Load a Spec
73
+ ## ๐Ÿš€ Quick Start
43
74
 
44
- You can load multiple specs (e.g., `products`, `users`, `payment`).
75
+ ### Step 1: Load Your Spec ๐Ÿ“„
45
76
 
46
77
  ```javascript
47
- import * as runtime from '@sonatel-os/openapi-runtime';
48
- import mySpec from './specs/products.openapi.json'; // or fetch it
78
+ import * as runtime from '@sonatel-os/openapi-runtime'
49
79
 
50
- // Initialize the registry
51
- await runtime.save({
52
- name: 'products',
53
- specName: mySpec,
54
- autoAuth: true // Magic auth enabled
55
- });
56
- ```
80
+ // From a file
81
+ await runtime.save({
82
+ name: 'products',
83
+ specName: 'products.openapi.json'
84
+ })
57
85
 
58
- ### 2\. Execute a Request
86
+ // Or pass the spec directly (for the rebels ๐Ÿ˜ˆ)
87
+ await runtime.save({
88
+ name: 'products',
89
+ specName: myOpenAPISpecObject
90
+ })
91
+ ```
59
92
 
60
- Use the `operationId` defined in your Swagger file. No need to memorize URLs.
93
+ ### Step 2: Call APIs Like a Boss ๐Ÿ˜Ž
61
94
 
62
95
  ```javascript
63
96
  // GET /products/{id}
64
- const response = await runtime.executeAPI({
97
+ const product = await runtime.executeAPI({
65
98
  name: 'products',
66
- api: 'getProductById',
67
- params: { id: 123 },
68
- qs: { details: true } // Query string
69
- });
99
+ api: 'getProductById', // Uses operationId from your spec
100
+ params: { id: 123 }, // Path + query params
101
+ headers: { 'X-Mood': 'happy' }
102
+ })
70
103
 
71
- console.log(response.body);
104
+ console.log(product.body) // Your data, served fresh ๐Ÿฝ๏ธ
72
105
  ```
73
106
 
74
- -----
107
+ ### Step 3: There Is No Step 3 ๐ŸŽ‰
75
108
 
76
- ## ๐Ÿ” Magic Auto-Authentication
109
+ You're done. Go grab a coffee. You've earned it. โ˜•
77
110
 
78
- Don't hardcode tokens. The runtime automatically injects credentials from `process.env` based on the security scheme names in your Swagger file.
111
+ ---
79
112
 
80
- **Naming Convention:** `OAR_{SPEC_NAME}_{SCHEME_NAME}`
113
+ ## โšก Features That Slap
81
114
 
82
- | Security Scheme (in YAML) | Env Variable Required |
83
- |---------------------------|-----------------------|
84
- | `bearerAuth` (in `products` spec) | `OAR_PRODUCTS_BEARERAUTH` |
85
- | `apiKey` (in `legacy` spec) | `OAR_LEGACY_APIKEY` |
86
- | `oauth2` (ClientId) | `OAUTH_CLIENT_ID_PRODUCTS_OAUTH2` |
115
+ | Feature | What It Does | Vibe |
116
+ |---------|--------------|------|
117
+ | ๐Ÿ—‚๏ธ **Multi-Spec Registry** | Load products, users, payments... all at once | Juggler mode ๐Ÿคน |
118
+ | ๐Ÿ”ฎ **Auto-Auth Magic** | Detects env vars, applies tokens automatically | Mind reader |
119
+ | โœ… **Request Validation** | Validate payloads before sending | Preventive care ๐Ÿฅ |
120
+ | ๐Ÿ” **Response Validation** | Validate what comes back | Trust issues (healthy) |
121
+ | ๐ŸŽญ **Mock Generation** | Generate fake responses from schemas | Backend not ready? No problem |
122
+ | ๐ŸŽฃ **Interceptors** | Hook into request/response lifecycle | Control freak approved |
123
+ | โš›๏ธ **React Hooks** | `useOpenAPI()` for the React gang | Hooks, but make it API |
124
+ | ๐Ÿ“ **TypeScript Ready** | Full JSDoc types, auto-generated .d.ts | IntelliSense heaven ๐Ÿ˜‡ |
87
125
 
88
- **Example:**
89
- If your spec is named `eyone` and uses `BearerAuth`:
126
+ ---
127
+
128
+ ## ๐Ÿ” Authentication (The Magic Part)
129
+
130
+ The runtime auto-detects your auth setup. No config? No problem. โœจ
131
+
132
+ ### ๐ŸŒฑ Option 1: Environment Variables (Zero Config)
133
+
134
+ Just set env vars following this pattern, and watch the magic happen:
90
135
 
91
136
  ```bash
92
- # .env
93
- OAR_EYONE_BEARERAUTH=eyJhbGciOiJIUzI1Ni...
137
+ # ๐ŸŽซ Bearer Token
138
+ BEARER_PRODUCTS_BEARERAUTH=your-jwt-token
139
+
140
+ # ๐Ÿ”‘ API Key
141
+ OAR_PRODUCTS_APIKEY=your-api-key
142
+
143
+ # ๐Ÿ‘ค Basic Auth
144
+ BASIC_USER_PRODUCTS_BASICAUTH=username
145
+ BASIC_PASS_PRODUCTS_BASICAUTH=password
146
+
147
+ # ๐Ÿ”’ OAuth2 Client Credentials
148
+ OAUTH_CLIENT_ID_PRODUCTS_OAUTH2=client-id
149
+ OAUTH_CLIENT_SECRET_PRODUCTS_OAUTH2=client-secret
150
+ OAUTH_TOKEN_URL_PRODUCTS_OAUTH2=https://auth.example.com/token
94
151
  ```
95
152
 
96
- *The runtime handles the rest.*
153
+ > ๐Ÿ“ **Pattern:** `{TYPE}_{SPECNAME}_{SCHEMENAME}`
97
154
 
98
- -----
155
+ The runtime reads your spec's `securitySchemes`, finds matching env vars, and configures everything. You literally do nothing. ๐Ÿช„
99
156
 
100
- ## ๐Ÿ› ๏ธ Features for Power Users
157
+ ### ๐Ÿ“ Option 2: YAML Config (More Control)
101
158
 
102
- ### 1\. The "Poke" System (Mocking & Heuristics)
159
+ Create `openapi.auth.yml` in your project root:
103
160
 
104
- Need to build a UI before the backend is ready? Or check if an API is alive?
161
+ ```yaml
162
+ # ๐ŸŽจ openapi.auth.yml
163
+ auth:
164
+ products:
165
+ schemes:
166
+ bearerAuth:
167
+ type: http
168
+ scheme: bearer
169
+ tokenFromEnv: MY_SECRET_TOKEN # ๐Ÿคซ
170
+
171
+ oauth2:
172
+ type: oauth2
173
+ flow: client_credentials
174
+ tokenUrl: https://auth.example.com/oauth/token
175
+ clientIdFromEnv: OAUTH_CLIENT_ID
176
+ clientSecretFromEnv: OAUTH_CLIENT_SECRET
177
+ scope: "read write"
178
+ audience: https://api.example.com
179
+ ```
105
180
 
106
- **Mock a Response:**
107
- Returns a dummy JSON object based on the schema definition.
181
+ > ๐Ÿ’ก Supports `${ENV_VAR}` interpolation for the extra fancy folks
182
+
183
+ ### ๐ŸŽฎ Option 3: Programmatic (Full Control)
108
184
 
109
185
  ```javascript
110
- const mockData = runtime.mockAPI({
111
- name: 'products',
112
- api: 'createProduct',
113
- status: 201
114
- });
186
+ import { setAuth, bearer, apiKey, basic, clientCredentials } from '@sonatel-os/openapi-runtime'
187
+
188
+ setAuth('products', {
189
+ // ๐ŸŽซ Static or dynamic tokens
190
+ bearerAuth: bearer({
191
+ getToken: async () => await fetchTokenFromVault() // ๐Ÿ”
192
+ }),
193
+
194
+ // ๐Ÿ”‘ API Keys
195
+ apiKeyAuth: apiKey({
196
+ in: 'header',
197
+ name: 'X-API-Key',
198
+ getValue: () => process.env.API_KEY
199
+ }),
200
+
201
+ // ๐Ÿ”’ OAuth2 with automatic token refresh
202
+ oauth2: clientCredentials({
203
+ tokenUrl: 'https://auth.example.com/token',
204
+ clientId: 'my-app',
205
+ clientSecret: process.env.CLIENT_SECRET,
206
+ scope: 'read write'
207
+ })
208
+ })
115
209
  ```
116
210
 
117
- **Auto-Probe (Heuristic Check):**
118
- The runtime can inspect a contract and generate "safe" dummy data to ping an endpoint.
211
+ > ๐Ÿ›ก๏ธ **Security note:** OAuth token URLs must use HTTPS. We're not playing games with your credentials.
212
+
213
+ ---
214
+
215
+ ## ๐Ÿ“š API Reference
216
+
217
+ ### ๐Ÿ—‚๏ธ Spec Management
119
218
 
120
219
  ```javascript
121
- const contract = runtime.showContract({ name: 'products', api: 'searchProducts' });
122
- // Returns: { method: 'POST', path: '/search', parameters: [...] }
123
- ```
220
+ // โž• Register a spec
221
+ await runtime.save({ name: 'api', specName: 'spec.json', autoAuth: true })
222
+
223
+ // ๐Ÿ”„ Update a spec
224
+ await runtime.update({ name: 'api', specName: 'spec-v2.json' })
225
+
226
+ // ๐Ÿ—‘๏ธ Remove a spec
227
+ runtime.remove({ name: 'api' })
124
228
 
125
- ### 2\. Validation
229
+ // ๐Ÿ“‹ List all registered specs
230
+ runtime.listSpecs() // ['products', 'users', 'payments']
231
+
232
+ // ๐Ÿ” List operations in a spec
233
+ runtime.listAPIs({ name: 'products' })
234
+ // [{ operationId: 'getProducts', method: 'get', path: '/products' }, ...]
235
+ ```
126
236
 
127
- Validate data against the OpenAPI schema without making a network request. Great for form validation.
237
+ ### ๐Ÿš€ Execution
128
238
 
129
239
  ```javascript
130
- const result = runtime.validateResponse({
240
+ const response = await runtime.executeAPI({
131
241
  name: 'products',
132
242
  api: 'createProduct',
133
- data: { price: "invalid-string" } // Should be number
134
- });
243
+ params: { category: 'electronics' }, // ๐Ÿ“ Path/query params
244
+ body: { name: 'Widget', price: 9.99 }, // ๐Ÿ“ฆ Request body
245
+ headers: { 'X-Request-ID': 'abc123' }, // ๐Ÿ“จ Extra headers
246
+ qs: { verbose: true } // โ“ Query string
247
+ })
248
+ ```
249
+
250
+ ### โœ… Validation
135
251
 
136
- if (!result.valid) console.error(result.errors);
252
+ ```javascript
253
+ // ๐Ÿ” Validate a response
254
+ const result = runtime.validateResponseData({
255
+ name: 'products',
256
+ api: 'getProduct',
257
+ status: 200,
258
+ data: responseData
259
+ })
260
+
261
+ if (!result.valid) {
262
+ console.error('๐Ÿ’ฅ Schema violations:', result.errors)
263
+ }
264
+
265
+ // ๐Ÿ›ก๏ธ Validate a request body BEFORE sending
266
+ const check = runtime.validateRequestData({
267
+ name: 'products',
268
+ api: 'createProduct',
269
+ body: { name: 'Widget' } // Missing required 'price'? ๐Ÿค”
270
+ })
137
271
  ```
138
272
 
139
- ### 3\. Interceptors
273
+ ### ๐ŸŽญ Mocking (Backend Not Ready? We Got You ๐Ÿ’ช)
140
274
 
141
- Hook into requests before they fly.
275
+ ```javascript
276
+ // ๐ŸŽฒ Generate a mock response
277
+ const mockProduct = runtime.mockAPI({
278
+ name: 'products',
279
+ api: 'getProduct',
280
+ status: 200
281
+ })
282
+ // { id: 123, name: 'string', price: 0, ... }
283
+
284
+ // ๐Ÿ“ Get sample request body
285
+ const sampleBody = runtime.showRequestSample({
286
+ name: 'products',
287
+ api: 'createProduct'
288
+ })
289
+
290
+ // ๐Ÿ”ฌ Inspect the raw contract
291
+ const contract = runtime.showContract({
292
+ name: 'products',
293
+ api: 'getProduct'
294
+ })
295
+ // { method: 'get', path: '/products/{id}', parameters: [...], responses: {...} }
296
+ ```
297
+
298
+ ### ๐ŸŽฃ Interceptors (For Control Freaks ๐ŸŽ›๏ธ)
142
299
 
143
300
  ```javascript
144
301
  runtime.setInterceptors('products', {
145
302
  request: async (req) => {
146
- console.log(`๐Ÿ“ก Calling ${req.url}`);
147
- return req;
303
+ console.log(`๐Ÿ“ก Calling ${req.operationId}`)
304
+ req.headers['X-Timestamp'] = Date.now()
305
+ return req
306
+ },
307
+
308
+ response: async (res) => {
309
+ console.log(`โœ… Got ${res.status} from ${res.url}`)
310
+ return res
148
311
  },
312
+
149
313
  error: (err) => {
150
- console.error("๐Ÿ”ฅ API Fire:", err);
151
- throw err;
314
+ console.error('๐Ÿ’ฅ API Error:', err)
315
+ logToSentry(err)
316
+ throw err
152
317
  }
153
- });
318
+ })
154
319
  ```
155
320
 
156
- -----
321
+ ### ๐Ÿ“จ Headers
157
322
 
158
- ## โš›๏ธ Next.js Best Practices
323
+ ```javascript
324
+ // ๐ŸŒ Global headers (all specs)
325
+ runtime.setGlobalHeaders({
326
+ 'X-Correlation-ID': generateCorrelationId()
327
+ })
328
+
329
+ // ๐ŸŽฏ Per-spec headers
330
+ runtime.setSpecHeaders('products', {
331
+ 'X-Tenant': 'acme-corp'
332
+ })
333
+ ```
159
334
 
160
- This library uses Node.js `fs` module for some operations.
335
+ ---
161
336
 
162
- **Server Components (Recommended):**
163
- Import directly in `page.jsx` or `layout.jsx`.
337
+ ## โš›๏ธ React Integration
164
338
 
165
339
  ```javascript
166
- import 'server-only';
167
- import * as runtime from '@sonatel-os/openapi-runtime';
168
- // Works perfectly
340
+ import { useOpenAPI } from '@sonatel-os/openapi-runtime/react'
341
+
342
+ function ProductList() {
343
+ const api = useOpenAPI('products')
344
+ const [products, setProducts] = useState([])
345
+
346
+ useEffect(() => {
347
+ api.executeAPI('getProducts')
348
+ .then(res => setProducts(res.body))
349
+ }, [])
350
+
351
+ return <div>{/* render products ๐ŸŽจ */}</div>
352
+ }
169
353
  ```
170
354
 
171
- **Client Components:**
172
- Do **not** import the runtime directly in Client Components (`"use client"`).
173
- Instead, fetch data in a Server Action or API Route and pass the pure JSON data to your client component.
355
+ ### ๐Ÿ”„ With Loading State
174
356
 
175
- -----
357
+ ```javascript
358
+ import { useOpenAPIWithState } from '@sonatel-os/openapi-runtime/react'
359
+
360
+ function ProductList() {
361
+ const { api, loading, error, execute } = useOpenAPIWithState('products')
362
+ const [products, setProducts] = useState([])
363
+
364
+ const loadProducts = () => execute(
365
+ () => api.executeAPI('getProducts'),
366
+ (res) => setProducts(res.body)
367
+ )
368
+
369
+ if (loading) return <Spinner /> // โณ
370
+ if (error) return <Error message={error.message} /> // ๐Ÿ’ฅ
371
+
372
+ return <div>{/* render products ๐ŸŽจ */}</div>
373
+ }
374
+ ```
375
+
376
+ ---
377
+
378
+ ## ๐Ÿšจ Error Handling (The Grown-Up Way)
379
+
380
+ We don't just throw generic errors. We throw *specific* errors with attitude:
381
+
382
+ ```javascript
383
+ import {
384
+ AuthenticationError, // ๐Ÿ”
385
+ SpecNotFoundError, // ๐Ÿ”
386
+ OperationNotFoundError, // ๐ŸŽฏ
387
+ ValidationError, // โœ…
388
+ SecurityError // ๐Ÿ›ก๏ธ
389
+ } from '@sonatel-os/openapi-runtime'
390
+
391
+ try {
392
+ await runtime.executeAPI({ name: 'products', api: 'getProduct', params: { id: 1 } })
393
+ } catch (err) {
394
+ if (err instanceof AuthenticationError) {
395
+ console.log('๐Ÿ” Auth failed:', err.failures)
396
+ // [{ schemes: ['bearer'], error: 'token expired' }]
397
+ }
398
+
399
+ if (err instanceof ValidationError) {
400
+ console.log('โŒ Validation errors:', err.errors)
401
+ }
402
+
403
+ if (err instanceof SecurityError) {
404
+ console.log('๐Ÿšจ Security violation:', err.details.violation)
405
+ }
406
+ }
407
+ ```
408
+
409
+ > ๐ŸŽ All errors extend `OpenAPIRuntimeError` with `code`, `details`, and `toJSON()` for easy logging
410
+
411
+ ---
412
+
413
+ ## โ–ฒ Next.js Integration
414
+
415
+ ### ๐Ÿ–ฅ๏ธ Server Components (Recommended)
416
+
417
+ ```javascript
418
+ // app/products/page.jsx
419
+ import 'server-only'
420
+ import * as runtime from '@sonatel-os/openapi-runtime'
421
+
422
+ export default async function ProductsPage() {
423
+ await runtime.save({ name: 'products', specName: 'products.json' })
424
+ const { body } = await runtime.executeAPI({ name: 'products', api: 'getProducts' })
425
+
426
+ return <ProductList products={body} /> // ๐ŸŽจ
427
+ }
428
+ ```
429
+
430
+ ### โšก Server Actions
431
+
432
+ ```javascript
433
+ // app/actions.js
434
+ 'use server'
435
+ import * as runtime from '@sonatel-os/openapi-runtime'
436
+
437
+ export async function getProducts() {
438
+ const { body } = await runtime.executeAPI({
439
+ name: 'products',
440
+ api: 'getProducts'
441
+ })
442
+ return body // ๐Ÿ“ฆ
443
+ }
444
+ ```
445
+
446
+ > โš ๏ธ **Warning:** Don't import the runtime directly in Client Components. Use Server Actions or API Routes instead.
447
+
448
+ ---
449
+
450
+ ## ๐Ÿ—๏ธ Architecture
451
+
452
+ ```
453
+ src/
454
+ โ”œโ”€โ”€ ๐Ÿ“„ index.js # Public API facade
455
+ โ”œโ”€โ”€ ๐Ÿ”ข constants.js # All magic values (none in code!)
456
+ โ”œโ”€โ”€ ๐Ÿ’ฅ errors.js # 9 custom error types
457
+ โ”œโ”€โ”€ ๐Ÿ› ๏ธ utils.js # DRY utilities
458
+ โ”œโ”€โ”€ ๐Ÿ“ฆ core/
459
+ โ”‚ โ”œโ”€โ”€ registry.js # Spec storage (singleton)
460
+ โ”‚ โ””โ”€โ”€ client.js # Swagger client factory
461
+ โ”œโ”€โ”€ ๐Ÿ” auth/
462
+ โ”‚ โ”œโ”€โ”€ providers.js # apiKey, bearer, basic, clientCredentials
463
+ โ”‚ โ”œโ”€โ”€ manager.js # Auth application logic
464
+ โ”‚ โ””โ”€โ”€ config.js # YAML config loader
465
+ โ”œโ”€โ”€ โœ… validation/
466
+ โ”‚ โ””โ”€โ”€ validator.js # AJV-based schema validation
467
+ โ”œโ”€โ”€ ๐ŸŽญ mocking/
468
+ โ”‚ โ””โ”€โ”€ sampler.js # Sample data generation
469
+ โ””โ”€โ”€ โš›๏ธ react/
470
+ โ””โ”€โ”€ useOpenAPI.js # React hooks
471
+ ```
472
+
473
+ **Design Principles:** ๐ŸŽฏ
474
+ - Single Responsibility per module
475
+ - No circular dependencies
476
+ - All magic values in `constants.js`
477
+ - Custom errors for every failure mode
478
+ - 100% JSDoc coverage
479
+
480
+ ---
481
+
482
+ ## ๐Ÿ›ก๏ธ Security
483
+
484
+ We take security seriously (and so should you):
485
+
486
+ | Measure | Implementation |
487
+ |---------|----------------|
488
+ | ๐Ÿ”’ **HTTPS Enforcement** | OAuth token URLs must use HTTPS |
489
+ | ๐Ÿšจ **No Silent Failures** | Auth failures throw with full context |
490
+ | โœ… **Input Validation** | Spec names validated against safe patterns |
491
+ | โฐ **Token Caching** | OAuth tokens cached with 30s expiry buffer |
492
+ | ๐Ÿคซ **No Secrets in Code** | All secrets via env vars or config files |
493
+
494
+ ---
495
+
496
+ ## โšก Performance
497
+
498
+ - ๐Ÿ’ค **Lazy Loading:** Specs loaded on-demand
499
+ - ๐Ÿ—„๏ธ **Schema Caching:** Compiled validators cached per-operation
500
+ - ๐ŸŽซ **Token Caching:** OAuth tokens cached until expiry
501
+ - ๐Ÿšซ **Zero Runtime Codegen:** No parsing or generation at runtime
502
+
503
+ ---
176
504
 
177
505
  ## ๐Ÿค Contributing
178
506
 
179
- This project is part of the **Sonatel Open Source** initiative.
180
- PRs are welcome\!
507
+ We welcome contributions! This project is part of the **Sonatel Open Source** initiative. ๐Ÿงก
508
+
509
+ ```bash
510
+ # ๐Ÿ“ฅ Clone
511
+ git clone https://github.com/sonatel-os/openapi-runtime.git
512
+
513
+ # ๐Ÿ“ฆ Install
514
+ npm install
515
+
516
+ # ๐Ÿ”ง Dev mode
517
+ npm run dev
518
+
519
+ # ๐Ÿ—๏ธ Build
520
+ npm run build
521
+
522
+ # ๐Ÿงช Test
523
+ npm test
524
+ ```
525
+
526
+ ### Guidelines ๐Ÿ“‹
527
+
528
+ 1. ๐Ÿด Fork the repository
529
+ 2. ๐ŸŒฟ Create a feature branch (`git checkout -b feature/amazing-thing`)
530
+ 3. ๐Ÿงช Write tests for new functionality
531
+ 4. โœ… Ensure all tests pass
532
+ 5. ๐Ÿš€ Submit a PR with a clear description
533
+
534
+ ---
535
+
536
+ ## ๐Ÿ—บ๏ธ Roadmap
537
+
538
+ - [x] ๐Ÿ—‚๏ธ Multi-spec registry
539
+ - [x] ๐Ÿ”ฎ Auto-auth from env vars
540
+ - [x] ๐Ÿ“ YAML config support
541
+ - [x] โœ… Request/response validation
542
+ - [x] ๐ŸŽญ Mock generation
543
+ - [x] โš›๏ธ React hooks
544
+ - [x] ๐Ÿ’ฅ Custom error types
545
+ - [ ] ๐Ÿ”‘ OpenID Connect support
546
+ - [ ] ๐Ÿ”„ Retry with exponential backoff
547
+ - [ ] ๐Ÿ—„๏ธ Request caching layer
548
+ - [ ] ๐Ÿ–ฅ๏ธ CLI for spec validation
549
+
550
+ ---
551
+
552
+ ## ๐Ÿ“œ License
553
+
554
+ MIT ยฉ [Sonatel Open Source](https://github.com/sonatel-os)
555
+
556
+ ---
557
+
558
+ <div align="center">
559
+
560
+ ### ๐Ÿ”ฅ Built with mass frustration, deployed with mass relief ๐Ÿ”ฅ
561
+
562
+ **Stop generating. Start shipping.** ๐Ÿš€
563
+
564
+ <br>
565
+
566
+ *Made with ๐Ÿงก by developers who mass mass mass hated regenerating SDKs*
181
567
 
182
- 1. Fork it
183
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
184
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
185
- 4. Push to the branch (`git push origin feature/amazing-feature`)
186
- 5. Open a Pull Request
568
+ <br>
187
569
 
188
- -----
570
+ <!-- โญ **Star us on GitHub** โ€” it mass mass mass motivates us to mass mass mass improve! โญ -->
189
571
 
190
- **License**
191
- MIT ยฉ [Sonatel](#)
572
+ </div>