@websublime/vite-plugin-open-api-server 0.24.0-next.1 → 0.24.0-next.3
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 +277 -8
- package/dist/index.js +401 -3
- package/dist/index.js.map +1 -1
- package/package.json +21 -11
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Plugin, ViteDevServer } from 'vite';
|
|
2
|
-
import { Logger, HandlerFn, AnySeedFn } from '@websublime/vite-plugin-open-api-core';
|
|
2
|
+
import { Logger, SpecInfo, OpenApiServer, HandlerFn, AnySeedFn } from '@websublime/vite-plugin-open-api-core';
|
|
3
3
|
export { HandlerContext, HandlerDefinition, HandlerFn, HandlerReturn, SecurityContext, SeedContext, SeedDefinition, SeedFn, SeedHelper, defineHandlers, defineSeeds } from '@websublime/vite-plugin-open-api-core';
|
|
4
|
+
import { OpenAPIV3_1 } from '@scalar/openapi-types';
|
|
5
|
+
import { Hono } from 'hono';
|
|
4
6
|
import { App } from 'vue';
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -42,6 +44,16 @@ declare class ValidationError extends Error {
|
|
|
42
44
|
readonly code: ValidationErrorCode;
|
|
43
45
|
constructor(code: ValidationErrorCode, message: string);
|
|
44
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* How a proxy path was determined.
|
|
49
|
+
*
|
|
50
|
+
* - `'explicit'` — set directly in SpecConfig.proxyPath
|
|
51
|
+
* - `'auto'` — auto-derived from the OpenAPI document's servers[0].url
|
|
52
|
+
*
|
|
53
|
+
* Used by both DeriveProxyPathResult and ResolvedSpecConfig to ensure
|
|
54
|
+
* the two sources of this value stay in sync.
|
|
55
|
+
*/
|
|
56
|
+
type ProxyPathSource = 'auto' | 'explicit';
|
|
45
57
|
/**
|
|
46
58
|
* Configuration for a single OpenAPI spec instance
|
|
47
59
|
*
|
|
@@ -175,18 +187,18 @@ interface OpenApiServerOptions {
|
|
|
175
187
|
*/
|
|
176
188
|
interface ResolvedSpecConfig {
|
|
177
189
|
spec: string;
|
|
178
|
-
/**
|
|
190
|
+
/** Empty string until orchestrator resolution; guaranteed non-empty after `createOrchestrator()` */
|
|
179
191
|
id: string;
|
|
180
|
-
/**
|
|
192
|
+
/** Empty string until orchestrator resolution; guaranteed non-empty after `createOrchestrator()` */
|
|
181
193
|
proxyPath: string;
|
|
182
194
|
/**
|
|
183
195
|
* How proxyPath was determined — used for banner display.
|
|
184
196
|
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
197
|
+
* Written back by the orchestrator after document processing.
|
|
198
|
+
* Used by the startup banner to display `(auto-derived)` vs
|
|
199
|
+
* `(explicit)` next to each proxy path.
|
|
188
200
|
*/
|
|
189
|
-
proxyPathSource:
|
|
201
|
+
proxyPathSource: ProxyPathSource;
|
|
190
202
|
handlersDir: string;
|
|
191
203
|
seedsDir: string;
|
|
192
204
|
idFields: Record<string, string>;
|
|
@@ -208,6 +220,25 @@ interface ResolvedOptions {
|
|
|
208
220
|
silent: boolean;
|
|
209
221
|
logger?: Logger;
|
|
210
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Validate that specs array is non-empty and each entry has a valid spec field.
|
|
225
|
+
*
|
|
226
|
+
* @param specs - Array of spec configurations to validate
|
|
227
|
+
* @throws {ValidationError} SPECS_EMPTY if specs array is missing or empty
|
|
228
|
+
* @throws {ValidationError} SPEC_NOT_FOUND if a spec entry has empty spec field
|
|
229
|
+
*/
|
|
230
|
+
declare function validateSpecs(specs: SpecConfig[]): void;
|
|
231
|
+
/**
|
|
232
|
+
* Resolve options with defaults.
|
|
233
|
+
*
|
|
234
|
+
* Note: spec ID and proxyPath resolution requires processing the OpenAPI document
|
|
235
|
+
* first, so they are resolved later in the orchestrator.
|
|
236
|
+
* This function only resolves static defaults.
|
|
237
|
+
*
|
|
238
|
+
* @param options - User-provided options
|
|
239
|
+
* @returns Resolved options with all defaults applied
|
|
240
|
+
*/
|
|
241
|
+
declare function resolveOptions(options: OpenApiServerOptions): ResolvedOptions;
|
|
211
242
|
|
|
212
243
|
/**
|
|
213
244
|
* Vite Plugin Implementation
|
|
@@ -221,6 +252,244 @@ interface ResolvedOptions {
|
|
|
221
252
|
|
|
222
253
|
declare function openApiServer(options: OpenApiServerOptions): Plugin;
|
|
223
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Spec ID Derivation
|
|
257
|
+
*
|
|
258
|
+
* What: Functions to derive and validate spec identifiers
|
|
259
|
+
* How: Slugifies explicit IDs or auto-derives from OpenAPI info.title
|
|
260
|
+
* Why: Each spec instance needs a unique, URL-safe identifier for routing,
|
|
261
|
+
* DevTools grouping, logging, and default directory names
|
|
262
|
+
*
|
|
263
|
+
* @module spec-id
|
|
264
|
+
*/
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Slugify a string for use as a spec identifier
|
|
268
|
+
*
|
|
269
|
+
* Rules:
|
|
270
|
+
* - Lowercase
|
|
271
|
+
* - Replace spaces and special chars with hyphens
|
|
272
|
+
* - Remove consecutive hyphens
|
|
273
|
+
* - Trim leading/trailing hyphens
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* slugify("Swagger Petstore") → "swagger-petstore"
|
|
277
|
+
* slugify("Billing API v2") → "billing-api-v2"
|
|
278
|
+
* slugify("café") → "cafe"
|
|
279
|
+
*/
|
|
280
|
+
declare function slugify(input: string): string;
|
|
281
|
+
/**
|
|
282
|
+
* Derive a spec ID from the processed OpenAPI document
|
|
283
|
+
*
|
|
284
|
+
* Priority:
|
|
285
|
+
* 1. Explicit id from config (if non-empty)
|
|
286
|
+
* 2. Slugified info.title from the processed document
|
|
287
|
+
*
|
|
288
|
+
* @param explicitId - ID from SpecConfig.id (may be empty)
|
|
289
|
+
* @param document - Processed OpenAPI document
|
|
290
|
+
* @returns Stable, URL-safe spec identifier
|
|
291
|
+
* @throws {ValidationError} SPEC_ID_MISSING if no ID can be derived (missing title and no explicit id)
|
|
292
|
+
*/
|
|
293
|
+
declare function deriveSpecId(explicitId: string, document: OpenAPIV3_1.Document): string;
|
|
294
|
+
/**
|
|
295
|
+
* Validate spec IDs are unique across all specs
|
|
296
|
+
*
|
|
297
|
+
* Collects all duplicated IDs and reports them in a single error.
|
|
298
|
+
*
|
|
299
|
+
* @param ids - Array of resolved spec IDs
|
|
300
|
+
* @throws {ValidationError} SPEC_ID_DUPLICATE if duplicate IDs found
|
|
301
|
+
*/
|
|
302
|
+
declare function validateUniqueIds(ids: string[]): void;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Proxy Path Auto-Detection
|
|
306
|
+
*
|
|
307
|
+
* What: Functions to derive and validate proxy paths for spec instances
|
|
308
|
+
* How: Extracts path from explicit config or auto-derives from servers[0].url
|
|
309
|
+
* Why: Each spec instance needs a unique, non-overlapping proxy path for
|
|
310
|
+
* Vite proxy configuration and request routing
|
|
311
|
+
*
|
|
312
|
+
* @module proxy-path
|
|
313
|
+
*/
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Result of proxy path derivation
|
|
317
|
+
*
|
|
318
|
+
* Includes the normalized path and how it was determined,
|
|
319
|
+
* so the startup banner can display "(auto-derived)" vs "(explicit)".
|
|
320
|
+
*/
|
|
321
|
+
interface DeriveProxyPathResult {
|
|
322
|
+
/** Normalized proxy path (e.g., "/api/v3") */
|
|
323
|
+
proxyPath: string;
|
|
324
|
+
/** How the path was determined */
|
|
325
|
+
proxyPathSource: ProxyPathSource;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Derive the proxy path from config or OpenAPI document's servers field
|
|
329
|
+
*
|
|
330
|
+
* Priority:
|
|
331
|
+
* 1. Explicit proxyPath from config (if non-empty after trimming)
|
|
332
|
+
* 2. Path portion of servers[0].url
|
|
333
|
+
*
|
|
334
|
+
* Full URLs (e.g., "https://api.example.com/api/v3") have their path
|
|
335
|
+
* extracted via the URL constructor. Relative paths (e.g., "/api/v3")
|
|
336
|
+
* are used directly.
|
|
337
|
+
*
|
|
338
|
+
* @param explicitPath - proxyPath from SpecConfig (may be empty)
|
|
339
|
+
* @param document - Processed OpenAPI document
|
|
340
|
+
* @param specId - Spec ID for error messages
|
|
341
|
+
* @returns Normalized proxy path with source indication
|
|
342
|
+
* @throws {ValidationError} PROXY_PATH_MISSING if path cannot be derived
|
|
343
|
+
* @throws {ValidationError} PROXY_PATH_TOO_BROAD if path resolves to "/" (e.g., "/", ".", "..")
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* // Explicit path
|
|
347
|
+
* deriveProxyPath('/api/v3', document, 'petstore')
|
|
348
|
+
* // → { proxyPath: '/api/v3', proxyPathSource: 'explicit' }
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* // Auto-derived from servers[0].url = "https://api.example.com/api/v3"
|
|
352
|
+
* deriveProxyPath('', document, 'petstore')
|
|
353
|
+
* // → { proxyPath: '/api/v3', proxyPathSource: 'auto' }
|
|
354
|
+
*/
|
|
355
|
+
declare function deriveProxyPath(explicitPath: string, document: OpenAPIV3_1.Document, specId: string): DeriveProxyPathResult;
|
|
356
|
+
/**
|
|
357
|
+
* Normalize and validate a proxy path
|
|
358
|
+
*
|
|
359
|
+
* Rules:
|
|
360
|
+
* - Strip query strings and fragments
|
|
361
|
+
* - Ensure leading slash
|
|
362
|
+
* - Collapse consecutive slashes
|
|
363
|
+
* - Resolve dot segments ("." and ".." per RFC 3986 §5.2.4)
|
|
364
|
+
* - Remove trailing slash
|
|
365
|
+
* - Reject "/" as too broad (would capture all requests, including dot-segments that resolve to "/")
|
|
366
|
+
*
|
|
367
|
+
* @param path - Raw path string to normalize
|
|
368
|
+
* @param specId - Spec ID for error messages
|
|
369
|
+
* @returns Normalized path (e.g., "/api/v3")
|
|
370
|
+
* @throws {ValidationError} PROXY_PATH_TOO_BROAD if path resolves to "/" (e.g., "/", ".", "..")
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* normalizeProxyPath('api/v3', 'petstore') → '/api/v3'
|
|
374
|
+
* normalizeProxyPath('/api/v3/', 'petstore') → '/api/v3'
|
|
375
|
+
*/
|
|
376
|
+
declare function normalizeProxyPath(path: string, specId: string): string;
|
|
377
|
+
/**
|
|
378
|
+
* Validate proxy paths are unique and non-overlapping
|
|
379
|
+
*
|
|
380
|
+
* Checks for:
|
|
381
|
+
* 1. Duplicate paths — two specs with the same proxyPath
|
|
382
|
+
* 2. Overlapping paths — one path is a prefix of another (e.g., "/api" and "/api/v1")
|
|
383
|
+
* which would cause routing ambiguity
|
|
384
|
+
*
|
|
385
|
+
* @remarks
|
|
386
|
+
* Entries with an empty or falsy `proxyPath` are silently skipped. These
|
|
387
|
+
* represent specs whose proxy path has not yet been resolved (e.g., during
|
|
388
|
+
* early option resolution before the OpenAPI document is processed). Callers
|
|
389
|
+
* should expect unresolved entries to be excluded from uniqueness checks
|
|
390
|
+
* rather than triggering false-positive PROXY_PATH_DUPLICATE or
|
|
391
|
+
* PROXY_PATH_OVERLAP errors.
|
|
392
|
+
*
|
|
393
|
+
* @param specs - Array of spec entries with id and proxyPath.
|
|
394
|
+
* Entries with empty/falsy proxyPath are skipped (unresolved).
|
|
395
|
+
* @throws {ValidationError} PROXY_PATH_DUPLICATE if duplicate paths found
|
|
396
|
+
* @throws {ValidationError} PROXY_PATH_OVERLAP if overlapping paths found
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* // Throws PROXY_PATH_DUPLICATE
|
|
400
|
+
* validateUniqueProxyPaths([
|
|
401
|
+
* { id: 'petstore', proxyPath: '/api/v3' },
|
|
402
|
+
* { id: 'inventory', proxyPath: '/api/v3' },
|
|
403
|
+
* ]);
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* // Throws PROXY_PATH_OVERLAP
|
|
407
|
+
* validateUniqueProxyPaths([
|
|
408
|
+
* { id: 'petstore', proxyPath: '/api' },
|
|
409
|
+
* { id: 'inventory', proxyPath: '/api/v1' },
|
|
410
|
+
* ]);
|
|
411
|
+
*/
|
|
412
|
+
declare function validateUniqueProxyPaths(specs: Array<{
|
|
413
|
+
id: string;
|
|
414
|
+
proxyPath: string;
|
|
415
|
+
}>): void;
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Multi-Spec Orchestrator
|
|
419
|
+
*
|
|
420
|
+
* What: Central orchestrator that creates N spec instances and mounts them on a single Hono app
|
|
421
|
+
* How: Three phases — process specs, validate uniqueness, build main Hono app with dispatch middleware
|
|
422
|
+
* Why: Enables multiple OpenAPI specs to run on a single server with isolated stores and handlers
|
|
423
|
+
*
|
|
424
|
+
* @module orchestrator
|
|
425
|
+
*/
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Deterministic color palette for spec identification in DevTools.
|
|
429
|
+
*
|
|
430
|
+
* Colors are assigned by index: spec 0 gets green, spec 1 gets blue, etc.
|
|
431
|
+
* Wraps around for >8 specs.
|
|
432
|
+
*/
|
|
433
|
+
declare const SPEC_COLORS: readonly string[];
|
|
434
|
+
/**
|
|
435
|
+
* Resolved spec instance with all runtime data.
|
|
436
|
+
*
|
|
437
|
+
* Created during Phase 1 of orchestration. Each instance owns
|
|
438
|
+
* an isolated core `OpenApiServer` with its own store, registry,
|
|
439
|
+
* handlers, seeds, and timeline.
|
|
440
|
+
*/
|
|
441
|
+
interface SpecInstance {
|
|
442
|
+
/** Unique spec identifier (explicit or auto-derived from info.title) */
|
|
443
|
+
id: string;
|
|
444
|
+
/** Spec metadata for DevTools display and WebSocket protocol */
|
|
445
|
+
info: SpecInfo;
|
|
446
|
+
/** Core server instance (isolated Hono app, store, registry, etc.) */
|
|
447
|
+
server: OpenApiServer;
|
|
448
|
+
/** Resolved configuration for this spec */
|
|
449
|
+
config: ResolvedSpecConfig;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Orchestrator result — returned by `createOrchestrator()`.
|
|
453
|
+
*
|
|
454
|
+
* Provides access to the main Hono app (all specs mounted),
|
|
455
|
+
* individual spec instances, aggregated metadata, and lifecycle methods.
|
|
456
|
+
*/
|
|
457
|
+
interface OrchestratorResult {
|
|
458
|
+
/** Main Hono app with all specs mounted via X-Spec-Id dispatch */
|
|
459
|
+
app: Hono;
|
|
460
|
+
/** All spec instances (in config order) */
|
|
461
|
+
instances: SpecInstance[];
|
|
462
|
+
/** Spec metadata array for WebSocket `connected` event */
|
|
463
|
+
specsInfo: SpecInfo[];
|
|
464
|
+
/** Start the shared HTTP server on the configured port */
|
|
465
|
+
start(): Promise<void>;
|
|
466
|
+
/** Stop the HTTP server and clean up resources */
|
|
467
|
+
stop(): Promise<void>;
|
|
468
|
+
/** Actual bound port after start() resolves (0 before start or after stop) */
|
|
469
|
+
readonly port: number;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Create the multi-spec orchestrator.
|
|
473
|
+
*
|
|
474
|
+
* Flow:
|
|
475
|
+
* 1. **Phase 1 — Process specs**: For each spec config, load handlers/seeds,
|
|
476
|
+
* create a core `OpenApiServer` instance, derive ID and proxy path.
|
|
477
|
+
* 2. **Phase 2 — Validate uniqueness**: Ensure all spec IDs and proxy paths
|
|
478
|
+
* are unique and non-overlapping.
|
|
479
|
+
* 3. **Phase 3 — Build main app**: Create a single Hono app with CORS,
|
|
480
|
+
* DevTools, Internal API, and X-Spec-Id dispatch middleware.
|
|
481
|
+
*
|
|
482
|
+
* **Note**: This function mutates `options.specs[i]` to write back resolved
|
|
483
|
+
* values (id, proxyPath, proxyPathSource, handlersDir, seedsDir) so that
|
|
484
|
+
* downstream consumers (banner, file watcher, plugin.ts) see the final values.
|
|
485
|
+
*
|
|
486
|
+
* @param options - Resolved plugin options (from `resolveOptions()`)
|
|
487
|
+
* @param vite - Vite dev server instance (for ssrLoadModule)
|
|
488
|
+
* @param cwd - Project root directory
|
|
489
|
+
* @returns Orchestrator result with app, instances, and lifecycle methods
|
|
490
|
+
*/
|
|
491
|
+
declare function createOrchestrator(options: ResolvedOptions, vite: ViteDevServer, cwd: string): Promise<OrchestratorResult>;
|
|
492
|
+
|
|
224
493
|
/**
|
|
225
494
|
* Handler Loading
|
|
226
495
|
*
|
|
@@ -517,4 +786,4 @@ declare function registerDevTools(app: App, options?: RegisterDevToolsOptions):
|
|
|
517
786
|
*/
|
|
518
787
|
declare function getDevToolsUrl(port?: number, host?: string, protocol?: 'http' | 'https'): string;
|
|
519
788
|
|
|
520
|
-
export { type FileWatcher, type FileWatcherOptions, type LoadHandlersResult, type LoadSeedsResult, type OpenApiServerOptions, type RegisterDevToolsOptions, type ResolvedOptions, type ResolvedSpecConfig, type SpecConfig, ValidationError, type ValidationErrorCode, createFileWatcher, debounce, getDevToolsUrl, getHandlerFiles, getSeedFiles, loadHandlers, loadSeeds, openApiServer, registerDevTools };
|
|
789
|
+
export { type DeriveProxyPathResult, type FileWatcher, type FileWatcherOptions, type LoadHandlersResult, type LoadSeedsResult, type OpenApiServerOptions, type OrchestratorResult, type ProxyPathSource, type RegisterDevToolsOptions, type ResolvedOptions, type ResolvedSpecConfig, SPEC_COLORS, type SpecConfig, type SpecInstance, ValidationError, type ValidationErrorCode, createFileWatcher, createOrchestrator, debounce, deriveProxyPath, deriveSpecId, getDevToolsUrl, getHandlerFiles, getSeedFiles, loadHandlers, loadSeeds, normalizeProxyPath, openApiServer, registerDevTools, resolveOptions, slugify, validateSpecs, validateUniqueIds, validateUniqueProxyPaths };
|