@stackwright-pro/openapi 0.3.0-alpha.4 → 0.3.0-alpha.6

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.mjs CHANGED
@@ -33,8 +33,18 @@ var OpenAPIParser = class {
33
33
  await SwaggerParser.validate(api);
34
34
  }
35
35
  let document;
36
+ let dereferenced = false;
36
37
  if (dereference) {
37
- document = await SwaggerParser.dereference(api);
38
+ try {
39
+ document = await SwaggerParser.dereference(api);
40
+ dereferenced = true;
41
+ } catch {
42
+ console.warn(
43
+ `[OpenAPIParser] Warning: Could not fully dereference "${specPath}" (dangling $ref or circular ref). Proceeding without full dereferencing \u2014 some schema references may not resolve.`
44
+ );
45
+ document = api;
46
+ dereferenced = false;
47
+ }
38
48
  } else {
39
49
  document = api;
40
50
  }
@@ -42,7 +52,7 @@ var OpenAPIParser = class {
42
52
  return {
43
53
  document,
44
54
  version,
45
- dereferenced: dereference
55
+ dereferenced
46
56
  };
47
57
  } catch (error) {
48
58
  throw this.enhanceError(error, specPath);
@@ -92,6 +102,19 @@ var OpenAPIParser = class {
92
102
  };
93
103
 
94
104
  // src/parser/SchemaResolver.ts
105
+ var SUPPORTED_CONTENT_TYPES = [
106
+ "application/json",
107
+ "application/geo+json",
108
+ // GeoJSON (ORS, mapping APIs)
109
+ "application/vnd.api+json",
110
+ // JSON:API
111
+ "application/ld+json",
112
+ // JSON-LD
113
+ "application/problem+json",
114
+ // RFC 7807 problem details
115
+ "*/*"
116
+ // wildcard fallback
117
+ ];
95
118
  var SchemaResolver = class {
96
119
  /**
97
120
  * @param document - Fully dereferenced OpenAPI document. Pass the result of
@@ -124,16 +147,19 @@ var SchemaResolver = class {
124
147
  const extractSchema = (responseCode) => {
125
148
  const response = responses[responseCode];
126
149
  if (!response) return void 0;
127
- const content = response.content?.["application/json"];
128
- const schema = content?.schema;
129
- if (!schema) return void 0;
130
- if ("$ref" in schema) {
131
- console.warn(
132
- `[SchemaResolver] Unresolved $ref in schema for ${path3}. Ensure the document is fully dereferenced before passing to SchemaResolver.`
133
- );
150
+ for (const contentType of SUPPORTED_CONTENT_TYPES) {
151
+ const content = response.content?.[contentType];
152
+ if (!content?.schema) continue;
153
+ const schema = content.schema;
154
+ if ("$ref" in schema) {
155
+ console.warn(
156
+ `[SchemaResolver] Unresolved $ref in schema for ${path3}. Ensure the document is fully dereferenced before passing to SchemaResolver.`
157
+ );
158
+ return schema;
159
+ }
134
160
  return schema;
135
161
  }
136
- return schema;
162
+ return void 0;
137
163
  };
138
164
  const preferred = extractSchema(preferredResponseCode);
139
165
  if (preferred) return preferred;
@@ -544,9 +570,12 @@ var CollectionProviderGenerator = class {
544
570
  const resolver = new SchemaResolver(this.document);
545
571
  const schema = resolver.getResponseSchema(endpoint, method);
546
572
  if (!schema) {
547
- throw new Error(`No response schema found for ${method.toUpperCase()} ${endpoint}`);
573
+ console.warn(
574
+ ` > No response schema found for ${method.toUpperCase()} ${endpoint} \u2014 falling back to z.unknown()`
575
+ );
548
576
  }
549
- const isArray = schema.type === "array";
577
+ const isArray = schema != null ? schema.type === "array" : false;
578
+ const unknownFallback = schema == null;
550
579
  const schemaName = `${this.capitalize(collectionName)}Schema`;
551
580
  const params = {
552
581
  providerName,
@@ -557,6 +586,7 @@ var CollectionProviderGenerator = class {
557
586
  baseUrl,
558
587
  schemaName,
559
588
  isArray,
589
+ unknownFallback,
560
590
  bare
561
591
  };
562
592
  if (auth !== void 0) {
@@ -578,13 +608,17 @@ var CollectionProviderGenerator = class {
578
608
  auth,
579
609
  schemaName,
580
610
  isArray,
611
+ unknownFallback,
581
612
  bare
582
613
  } = params;
583
614
  const authHeader = this.generateAuthHeader(auth);
584
615
  const arraySchemaName = `${schemaName.replace(/Schema$/, "")}ArraySchema`;
585
- const validationSchema = isArray ? arraySchemaName : schemaName;
586
- const imports = bare ? "" : `import type { CollectionProvider, CollectionItem } from '@stackwright/collections';
587
- import { ${isArray ? arraySchemaName : schemaName}} } from './schemas';
616
+ const validationSchema = unknownFallback ? "z.unknown()" : isArray ? arraySchemaName : schemaName;
617
+ const imports = bare ? "" : unknownFallback ? `import type { CollectionProvider, CollectionItem } from '@stackwright/collections';
618
+ import { z } from 'zod';
619
+
620
+ ` : `import type { CollectionProvider, CollectionItem } from '@stackwright/collections';
621
+ import { ${isArray ? arraySchemaName : schemaName} } from './schemas';
588
622
 
589
623
  `;
590
624
  return `${imports}/**
@@ -648,7 +682,7 @@ export class ${providerName} implements CollectionProvider {
648
682
  * Get a single item by slug
649
683
  */
650
684
  async get(slug: string): Promise<CollectionItem | null> {
651
- ${this.generateGetMethod(endpoint, slugField, isArray, collectionName, schemaName)}
685
+ ${this.generateGetMethod(endpoint, slugField, isArray, collectionName, schemaName, unknownFallback)}
652
686
  }
653
687
 
654
688
  /**
@@ -684,7 +718,8 @@ export class ${providerName} implements CollectionProvider {
684
718
  /**
685
719
  * Generate get method implementation
686
720
  */
687
- generateGetMethod(endpoint, slugField, isArray, collectionName, schemaName) {
721
+ generateGetMethod(endpoint, slugField, isArray, collectionName, schemaName, unknownFallback = false) {
722
+ const validationExpr = unknownFallback ? "z.unknown()" : schemaName;
688
723
  if (endpoint.includes("{id}") || endpoint.includes(":id")) {
689
724
  const detailEndpoint = endpoint.replace("{id}", "${slug}").replace(":id", "${slug}");
690
725
  return `const url = \`\${this.baseUrl}${detailEndpoint}\`;
@@ -702,7 +737,7 @@ export class ${providerName} implements CollectionProvider {
702
737
  }
703
738
 
704
739
  const data = await response.json();
705
- const validated = ${schemaName}.parse(data);
740
+ const validated = ${validationExpr}.parse(data);
706
741
 
707
742
  return this.toCollectionItem(validated);`;
708
743
  } else {
@@ -2804,6 +2839,23 @@ var OpenAPIPlugin = class {
2804
2839
  async processIntegration(config, projectRoot) {
2805
2840
  const { name, spec, auth, mockUrl, collections, endpoints, actions } = config;
2806
2841
  console.log(` - Processing integration: ${name}`);
2842
+ const httpCollections = (collections || []).filter((c) => {
2843
+ if (c.transport === "websocket") {
2844
+ console.warn(
2845
+ ` > Skipping collection "${c.endpoint}" (transport: websocket \u2014 not yet supported)`
2846
+ );
2847
+ return false;
2848
+ }
2849
+ return true;
2850
+ });
2851
+ const hasEndpoints = endpoints && (endpoints.include?.length || endpoints.exclude?.length);
2852
+ const hasActions = actions && actions.length > 0;
2853
+ if (httpCollections.length === 0 && !hasEndpoints && !hasActions) {
2854
+ console.log(
2855
+ " > No HTTP endpoints or REST collections found \u2014 skipping (WebSocket-only integration not yet supported)"
2856
+ );
2857
+ return;
2858
+ }
2807
2859
  const specPath = spec.startsWith("http") ? spec : path2.resolve(projectRoot, spec);
2808
2860
  const parser = new OpenAPIParser();
2809
2861
  const { document } = await parser.parse(specPath);
@@ -2822,13 +2874,13 @@ var OpenAPIPlugin = class {
2822
2874
  fs2.mkdirSync(outputDir, { recursive: true });
2823
2875
  const schemaMapping = await this.generateSchemas(
2824
2876
  document,
2825
- collections || [],
2877
+ httpCollections,
2826
2878
  outputDir,
2827
2879
  name,
2828
2880
  endpointFilter
2829
2881
  );
2830
- await this.generateTypes(document, collections || [], outputDir, name);
2831
- if (collections && collections.length > 0) {
2882
+ await this.generateTypes(document, httpCollections, outputDir, name);
2883
+ if (httpCollections.length > 0) {
2832
2884
  await this.generateProvider(document, config, outputDir, name);
2833
2885
  }
2834
2886
  await this.generateClient(document, outputDir, name, schemaMapping, endpointFilter);