@workos/oagen-emitters 0.14.1 → 0.14.2

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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.14.1"
2
+ ".": "0.14.2"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.2](https://github.com/workos/oagen-emitters/compare/v0.14.1...v0.14.2) (2026-05-22)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * emit ListMetadata-shape models referenced by surviving wrappers ([#124](https://github.com/workos/oagen-emitters/issues/124)) ([8d8efe1](https://github.com/workos/oagen-emitters/commit/8d8efe148f3665fc9de92cc6aea0e08e77e0fe78))
9
+ * **node:** stop emitting duplicate Response-suffixed interfaces ([#123](https://github.com/workos/oagen-emitters/issues/123)) ([2077d25](https://github.com/workos/oagen-emitters/commit/2077d250d1dc7968245e9ec31d5ef5f75441fc68))
10
+ * **node:** use toBeNull() when example is null on date-time fields ([#121](https://github.com/workos/oagen-emitters/issues/121)) ([0f5029f](https://github.com/workos/oagen-emitters/commit/0f5029f38d2dafc63df09f49a4562e3ffeeb7558))
11
+
3
12
  ## [0.14.1](https://github.com/workos/oagen-emitters/compare/v0.14.0...v0.14.1) (2026-05-22)
4
13
 
5
14
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/node/index.ts","../src/python/index.ts","../src/php/index.ts","../src/go/index.ts","../src/dotnet/index.ts","../src/kotlin/index.ts","../src/ruby/index.ts","../src/rust/index.ts"],"mappings":";;;;;cAyca,WAAA,EAAa,OA4GzB;;;cC9gBY,aAAA,EAAe,OA+D3B;;;cC5CY,UAAA,EAAY,OA4DxB;;;cCzFY,SAAA,EAAW,OAyEvB;;;cCnCY,aAAA,EAAe,OAiR3B;;;cCrTY,aAAA,EAAe,OA6E3B;;;cCxDY,WAAA,EAAa,OAmEzB;;;cC5DY,WAAA,EAAa,OA2DzB"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/node/index.ts","../src/python/index.ts","../src/php/index.ts","../src/go/index.ts","../src/dotnet/index.ts","../src/kotlin/index.ts","../src/ruby/index.ts","../src/rust/index.ts"],"mappings":";;;;;cAuda,WAAA,EAAa,OA4GzB;;;cC5hBY,aAAA,EAAe,OA+D3B;;;cC5CY,UAAA,EAAY,OA4DxB;;;cCzFY,SAAA,EAAW,OAyEvB;;;cCnCY,aAAA,EAAe,OAiR3B;;;cCrTY,aAAA,EAAe,OA6E3B;;;cCxDY,WAAA,EAAa,OAmEzB;;;cC5DY,WAAA,EAAa,OA2DzB"}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as pythonEmitter, a as rustExtractor, c as pythonExtractor, d as rustEmitter, f as rubyEmitter, g as phpEmitter, h as goEmitter, i as kotlinExtractor, l as rubyExtractor, m as dotnetEmitter, n as elixirExtractor, o as goExtractor, p as kotlinEmitter, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor, v as nodeEmitter } from "./plugin-DRGwxN88.mjs";
1
+ import { _ as pythonEmitter, a as rustExtractor, c as pythonExtractor, d as rustEmitter, f as rubyEmitter, g as phpEmitter, h as goEmitter, i as kotlinExtractor, l as rubyExtractor, m as dotnetEmitter, n as elixirExtractor, o as goExtractor, p as kotlinEmitter, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor, v as nodeEmitter } from "./plugin-BbSmT2kj.mjs";
2
2
  export { dotnetEmitter, dotnetExtractor, elixirExtractor, goEmitter, goExtractor, kotlinEmitter, kotlinExtractor, nodeEmitter, nodeExtractor, phpEmitter, phpExtractor, pythonEmitter, pythonExtractor, rubyEmitter, rubyExtractor, rustEmitter, rustExtractor, workosEmittersPlugin };
@@ -2334,6 +2334,35 @@ function isListMetadataModel(model) {
2334
2334
  if (!before || !after) return false;
2335
2335
  return isNullableString(before) && isNullableString(after);
2336
2336
  }
2337
+ /**
2338
+ * Compute the `ListMetadata`-shape model names that must still be emitted
2339
+ * because some surviving wrapper references them.
2340
+ *
2341
+ * Each language emitter blanket-skips `isListMetadataModel` models on the
2342
+ * assumption that the SDK's shared pagination wrapper subsumes them. That
2343
+ * is correct for paginated list envelopes (the iterator unwraps the
2344
+ * envelope and `list_metadata` is handled at runtime), but a *non-paginated*
2345
+ * wrapper like vault's `VersionListResponse` still has a
2346
+ * `list_metadata: ListMetadata` field — and skipping emission of
2347
+ * `ListMetadata` leaves the wrapper's interface importing from a file that
2348
+ * was never written.
2349
+ *
2350
+ * Pass the same `nonPaginatedRefs` set the emitter uses for its own
2351
+ * wrapper-survival decision so the two answers stay in sync.
2352
+ */
2353
+ function collectReferencedListMetadataModels(models, nonPaginatedRefs) {
2354
+ const listMetadataNames = /* @__PURE__ */ new Set();
2355
+ for (const m of models) if (isListMetadataModel(m)) listMetadataNames.add(m.name);
2356
+ if (listMetadataNames.size === 0) return /* @__PURE__ */ new Set();
2357
+ const referenced = /* @__PURE__ */ new Set();
2358
+ for (const model of models) {
2359
+ if (isListMetadataModel(model)) continue;
2360
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
2361
+ const deps = collectFieldDependencies(model);
2362
+ for (const dep of deps.models) if (listMetadataNames.has(dep)) referenced.add(dep);
2363
+ }
2364
+ return referenced;
2365
+ }
2337
2366
  /** Check if a field type is nullable string (nullable<string> or just string). */
2338
2367
  function isNullableString(field) {
2339
2368
  if (field.type.kind === "primitive" && field.type.type === "string") return true;
@@ -2826,6 +2855,22 @@ function isAdoptedModelName(name) {
2826
2855
  return adoptedModelNames.has(name);
2827
2856
  }
2828
2857
  /**
2858
+ * Domain names that `resolveInterfaceName` reached via a structural rename
2859
+ * — the resolved name differs from the IR model's own name. `wireInterfaceName`
2860
+ * consults this set to decide whether to fire the "single-form wire" case:
2861
+ * that case is *only* meant for structurally-renamed models, where the
2862
+ * baseline owns a `*Response` interface representing the wire shape with no
2863
+ * separate `*Wire` companion. Without this signal, a freshly-emitted model
2864
+ * whose IR name already ends in `Response` (e.g. `CreateDataKeyResponse`)
2865
+ * would land in the same case as soon as a prior buggy regen wrote the
2866
+ * baseline — producing two `export interface CreateDataKeyResponse { ... }`
2867
+ * declarations in the same file.
2868
+ */
2869
+ let structurallyRenamedDomainNames = /* @__PURE__ */ new Set();
2870
+ function setStructurallyRenamedDomainNames(names) {
2871
+ structurallyRenamedDomainNames = names;
2872
+ }
2873
+ /**
2829
2874
  * Wire/response interface name.
2830
2875
  *
2831
2876
  * Resolution order:
@@ -2848,7 +2893,7 @@ function wireInterfaceName(domainName) {
2848
2893
  if (domainName.endsWith("Response")) {
2849
2894
  const wireForm = `${domainName}Wire`;
2850
2895
  if (baselineInterfaceNames.has(wireForm)) return wireForm;
2851
- if (baselineInterfaceNames.has(domainName)) return domainName;
2896
+ if (structurallyRenamedDomainNames.has(domainName) && baselineInterfaceNames.has(domainName)) return domainName;
2852
2897
  return wireForm;
2853
2898
  }
2854
2899
  return `${domainName}Response`;
@@ -4892,8 +4937,11 @@ function generateResourceClass(service, ctx) {
4892
4937
  importedTypeNames.add(resolved);
4893
4938
  const modelServiceDir = resolveDir(modelToService.get(name));
4894
4939
  const relPath = modelServiceDir === serviceDir ? `./interfaces/${fileName$3(name)}.interface` : `../${modelServiceDir}/interfaces/${fileName$3(name)}.interface`;
4895
- if (usedWireTypes.has(resolved)) lines.push(`import type { ${resolved}, ${wireInterfaceName(resolved)} } from '${relPath}';`);
4896
- else lines.push(`import type { ${resolved} } from '${relPath}';`);
4940
+ if (usedWireTypes.has(resolved)) {
4941
+ const wireName = wireInterfaceName(resolved);
4942
+ if (wireName === resolved) lines.push(`import type { ${resolved} } from '${relPath}';`);
4943
+ else lines.push(`import type { ${resolved}, ${wireName} } from '${relPath}';`);
4944
+ } else lines.push(`import type { ${resolved} } from '${relPath}';`);
4897
4945
  }
4898
4946
  for (const name of requestModels) {
4899
4947
  if (allModels.has(name)) continue;
@@ -5821,11 +5869,13 @@ function generateFixtures$5(spec, ctx) {
5821
5869
  walk(field.type);
5822
5870
  }
5823
5871
  }
5872
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
5873
+ const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
5824
5874
  const seenFixturePaths = /* @__PURE__ */ new Set();
5825
5875
  for (const model of spec.models) {
5826
5876
  if (!fixtureReachable.has(model.name)) continue;
5827
- if (isListMetadataModel(model)) continue;
5828
- if (isListWrapperModel(model)) continue;
5877
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
5878
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
5829
5879
  const fixturePath = `src/${resolveDir(modelToService.get(model.name))}/fixtures/${fileName$3(model.name)}.json`;
5830
5880
  if (seenFixturePaths.has(fixturePath)) continue;
5831
5881
  seenFixturePaths.add(fixturePath);
@@ -6014,11 +6064,12 @@ function generateModels$7(models, ctx, shared) {
6014
6064
  }
6015
6065
  const discriminatedSkip = ctx._discriminatedModelNames;
6016
6066
  const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
6067
+ const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
6017
6068
  for (const originalModel of models) {
6018
6069
  const model = projectedByName.get(originalModel.name) ?? originalModel;
6019
6070
  if (!reachableModels.has(model.name)) continue;
6020
6071
  if (interfaceEligibleModels && !interfaceEligibleModels.has(model.name)) continue;
6021
- if (isListMetadataModel(model)) continue;
6072
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
6022
6073
  if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
6023
6074
  if (discriminatedSkip?.has(model.name)) continue;
6024
6075
  const service = modelToService.get(model.name);
@@ -6208,25 +6259,27 @@ function generateModels$7(models, ctx, shared) {
6208
6259
  lines.push("}");
6209
6260
  }
6210
6261
  lines.push("");
6211
- const seenWireFields = /* @__PURE__ */ new Set();
6212
- if (model.fields.length === 0) lines.push(`export type ${responseName}${typeParams} = object;`);
6213
- else {
6214
- lines.push(`export interface ${responseName}${typeParams} {`);
6215
- for (const field of model.fields) {
6216
- const wireField = wireFieldName(field.name);
6217
- if (seenWireFields.has(wireField)) continue;
6218
- seenWireFields.add(wireField);
6219
- const baselineField = baselineResponse?.fields?.[wireField];
6220
- if (baselineField && baselineTypeResolvable(baselineField.type, importableNames) && baselineFieldCompatible(baselineField, field)) {
6221
- const opt = baselineField.optional ? "?" : "";
6222
- lines.push(` ${wireField}${opt}: ${baselineField.type};`);
6223
- } else {
6224
- const isNewFieldOnExistingModel = baselineResponse && !baselineField;
6225
- const opt = baselineField?.optional === true || !field.required || isNewFieldOnExistingModel ? "?" : "";
6226
- lines.push(` ${wireField}${opt}: ${mapWireTypeRef(field.type, modelWireTypeRefOpts)};`);
6262
+ if (responseName !== domainName) {
6263
+ const seenWireFields = /* @__PURE__ */ new Set();
6264
+ if (model.fields.length === 0) lines.push(`export type ${responseName}${typeParams} = object;`);
6265
+ else {
6266
+ lines.push(`export interface ${responseName}${typeParams} {`);
6267
+ for (const field of model.fields) {
6268
+ const wireField = wireFieldName(field.name);
6269
+ if (seenWireFields.has(wireField)) continue;
6270
+ seenWireFields.add(wireField);
6271
+ const baselineField = baselineResponse?.fields?.[wireField];
6272
+ if (baselineField && baselineTypeResolvable(baselineField.type, importableNames) && baselineFieldCompatible(baselineField, field)) {
6273
+ const opt = baselineField.optional ? "?" : "";
6274
+ lines.push(` ${wireField}${opt}: ${baselineField.type};`);
6275
+ } else {
6276
+ const isNewFieldOnExistingModel = baselineResponse && !baselineField;
6277
+ const opt = baselineField?.optional === true || !field.required || isNewFieldOnExistingModel ? "?" : "";
6278
+ lines.push(` ${wireField}${opt}: ${mapWireTypeRef(field.type, modelWireTypeRefOpts)};`);
6279
+ }
6227
6280
  }
6281
+ lines.push("}");
6228
6282
  }
6229
- lines.push("}");
6230
6283
  }
6231
6284
  const filePath = `src/${dirName}/interfaces/${fileName$3(model.name)}.interface.ts`;
6232
6285
  if (ctx.apiSurface && ctx.targetDir) {
@@ -6354,12 +6407,13 @@ function generateSerializers(models, ctx, shared) {
6354
6407
  }
6355
6408
  const discriminatedSerializerSkip = ctx._discriminatedModelNames;
6356
6409
  const serializerNonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
6410
+ const serializerListMetadataNeeded = collectReferencedListMetadataModels(models, serializerNonPaginatedRefs);
6357
6411
  const eligibleModels = [];
6358
6412
  for (const originalModel of models) {
6359
6413
  const model = projectedByName.get(originalModel.name) ?? originalModel;
6360
6414
  if (!serializerReachable.has(model.name)) continue;
6361
6415
  if (serializerEligibleModels && !serializerEligibleModels.has(model.name)) continue;
6362
- if (isListMetadataModel(model)) continue;
6416
+ if (isListMetadataModel(model) && !serializerListMetadataNeeded.has(model.name)) continue;
6363
6417
  if (isListWrapperModel(model) && !serializerNonPaginatedRefs.has(model.name)) continue;
6364
6418
  if (discriminatedSerializerSkip?.has(model.name)) continue;
6365
6419
  if (!isNodeOwnedService(ctx, modelToService.get(model.name)) && !modelHasNewFields(model, ctx) && !forceGenerateSerializer.has(model.name)) continue;
@@ -7415,7 +7469,11 @@ function buildFieldAssertions(model, accessor, modelMap) {
7415
7469
  const domainField = fieldName$6(field.name);
7416
7470
  const fieldAccessor = isDateTimeFieldType(field.type) ? `${accessor}.${domainField}.toISOString()` : `${accessor}.${domainField}`;
7417
7471
  if (field.example !== void 0) {
7418
- if (typeof field.example === "object" && field.example !== null) assertions.push(`expect(${accessor}.${domainField}).toEqual(${JSON.stringify(field.example)});`);
7472
+ if (field.example === null) {
7473
+ assertions.push(`expect(${accessor}.${domainField}).toBeNull();`);
7474
+ continue;
7475
+ }
7476
+ if (typeof field.example === "object") assertions.push(`expect(${accessor}.${domainField}).toEqual(${JSON.stringify(field.example)});`);
7419
7477
  else {
7420
7478
  const exampleLiteral = typeof field.example === "string" ? `'${field.example}'` : String(field.example);
7421
7479
  assertions.push(`expect(${fieldAccessor}).toBe(${exampleLiteral});`);
@@ -8245,6 +8303,12 @@ function getSurface(ctx) {
8245
8303
  setBaselineInterfaceNames(allInterfaces);
8246
8304
  setInlineEnumUnions(/* @__PURE__ */ new Map());
8247
8305
  setAdoptedModelNames(computeAdoptedModelNames(ctx, surface));
8306
+ const renamed = /* @__PURE__ */ new Set();
8307
+ for (const model of ctx.spec.models) {
8308
+ const resolved = resolveInterfaceName(model.name, ctx);
8309
+ if (resolved !== model.name) renamed.add(resolved);
8310
+ }
8311
+ setStructurallyRenamedDomainNames(renamed);
8248
8312
  return surface;
8249
8313
  }
8250
8314
  /**
@@ -9313,9 +9377,10 @@ function generateModels$6(models, ctx) {
9313
9377
  const symbolToOriginalService = /* @__PURE__ */ new Map();
9314
9378
  const emittedFilePaths = /* @__PURE__ */ new Set();
9315
9379
  const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
9380
+ const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
9316
9381
  for (const model of models) {
9317
9382
  if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
9318
- if (isListMetadataModel(model)) continue;
9383
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
9319
9384
  const dirName = resolveDir(modelToService.get(model.name));
9320
9385
  const modelClassName = className$5(model.name);
9321
9386
  const modelFilePath = `src/${ctx.namespace}/${dirName}/models/${fileName$2(model.name)}.py`;
@@ -11338,9 +11403,11 @@ function generateFixtures$4(spec) {
11338
11403
  const modelMap = new Map(spec.models.map((m) => [m.name, m]));
11339
11404
  const enumMap = new Map(spec.enums.map((e) => [e.name, e]));
11340
11405
  const files = [];
11406
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
11407
+ const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
11341
11408
  for (const model of spec.models) {
11342
- if (isListMetadataModel(model)) continue;
11343
- if (isListWrapperModel(model)) continue;
11409
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
11410
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
11344
11411
  if (model.fields.length === 0) continue;
11345
11412
  const fixture = generateModelFixture$4(model, modelMap, enumMap);
11346
11413
  files.push({
@@ -12418,7 +12485,9 @@ function generateModelRoundTripTests(spec, ctx) {
12418
12485
  }
12419
12486
  }
12420
12487
  for (const name of responseModelNames) requestOnlyModelNames.delete(name);
12421
- const models = spec.models.filter((m) => !isListWrapperModel(m) && !isListMetadataModel(m) && !requestOnlyModelNames.has(m.name));
12488
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
12489
+ const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
12490
+ const models = spec.models.filter((m) => !(isListWrapperModel(m) && !nonPaginatedRefs.has(m.name)) && !(isListMetadataModel(m) && !listMetadataNeeded.has(m.name)) && !requestOnlyModelNames.has(m.name));
12422
12491
  if (models.length === 0) return null;
12423
12492
  const modelToService = computeSchemaPlacement(spec, ctx).originalModelToService;
12424
12493
  const roundTripDirMap = buildMountDirMap$1(ctx);
@@ -14764,10 +14833,12 @@ function generateModels$4(models, ctx) {
14764
14833
  const requestBodyOnly = collectRequestBodyOnlyModelNames$1(ctx.spec.services, models);
14765
14834
  const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
14766
14835
  const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
14836
+ const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
14837
+ const skipAsListMetadata = (m) => isListMetadataModel(m) && !listMetadataNeeded.has(m.name);
14767
14838
  const modelHashMap = /* @__PURE__ */ new Map();
14768
14839
  const hashGroups = /* @__PURE__ */ new Map();
14769
14840
  for (const model of models) {
14770
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
14841
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
14771
14842
  if (requestBodyOnly.has(model.name)) continue;
14772
14843
  const hash = structuralHash$2(model);
14773
14844
  modelHashMap.set(model.name, hash);
@@ -14784,7 +14855,7 @@ function generateModels$4(models, ctx) {
14784
14855
  }
14785
14856
  const batchedAliases = /* @__PURE__ */ new Set();
14786
14857
  for (const model of models) {
14787
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
14858
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
14788
14859
  if (requestBodyOnly.has(model.name)) continue;
14789
14860
  const structName = className$3(model.name);
14790
14861
  const canonicalName = aliasOf.get(model.name);
@@ -16326,9 +16397,11 @@ function generateFixtures$2(spec) {
16326
16397
  const modelMap = new Map(spec.models.map((m) => [m.name, m]));
16327
16398
  const enumMap = new Map(spec.enums.map((e) => [e.name, e]));
16328
16399
  const files = [];
16400
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
16401
+ const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
16329
16402
  for (const model of spec.models) {
16330
- if (isListMetadataModel(model)) continue;
16331
- if (isListWrapperModel(model)) continue;
16403
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
16404
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
16332
16405
  const fixture = model.fields.length === 0 ? {} : generateModelFixture$2(model, modelMap, enumMap);
16333
16406
  files.push({
16334
16407
  path: `testdata/${fileName$1(model.name)}.json`,
@@ -20169,10 +20242,12 @@ function generateModels$2(models, ctx) {
20169
20242
  const files = [];
20170
20243
  const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
20171
20244
  const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
20245
+ const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
20246
+ const skipAsListMetadata = (m) => isListMetadataModel(m) && !listMetadataNeeded.has(m.name);
20172
20247
  modelAliasMap = null;
20173
20248
  const hashGroupsPass1 = /* @__PURE__ */ new Map();
20174
20249
  for (const model of models) {
20175
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20250
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
20176
20251
  if (model.fields.length === 0 && discriminatedUnions.has(className$1(model.name))) continue;
20177
20252
  const hash = structuralHash(model);
20178
20253
  if (!hashGroupsPass1.has(hash)) hashGroupsPass1.set(hash, []);
@@ -20191,7 +20266,7 @@ function generateModels$2(models, ctx) {
20191
20266
  modelAliasMap = aliasOf;
20192
20267
  const hashGroupsPass2 = /* @__PURE__ */ new Map();
20193
20268
  for (const model of models) {
20194
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20269
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
20195
20270
  if (model.fields.length === 0 && discriminatedUnions.has(className$1(model.name))) continue;
20196
20271
  if (aliasOf.has(model.name)) continue;
20197
20272
  const hash = structuralHash(model);
@@ -20209,7 +20284,7 @@ function generateModels$2(models, ctx) {
20209
20284
  }
20210
20285
  }
20211
20286
  for (const model of models) {
20212
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20287
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
20213
20288
  const typeName = className$1(model.name);
20214
20289
  if (model.fields.length === 0 && discriminatedUnions.has(typeName)) {
20215
20290
  files.push(emitSealedUnion(typeName, discriminatedUnions.get(typeName)));
@@ -20237,7 +20312,7 @@ function generateModels$2(models, ctx) {
20237
20312
  }
20238
20313
  const eventMapping = [];
20239
20314
  for (const model of models) {
20240
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20315
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
20241
20316
  if (aliasOf.has(model.name)) continue;
20242
20317
  if (!isEventEnvelopeModel(model)) continue;
20243
20318
  const eventField = model.fields.find((f) => f.name === "event");
@@ -21548,6 +21623,8 @@ function resolveBodyModel$2(op, ctx) {
21548
21623
  function registerTypeImports(ref, imports, ctx) {
21549
21624
  const mapped = mapTypeRef$2(ref);
21550
21625
  for (const imp of implicitImportsFor(mapped)) imports.add(imp);
21626
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
21627
+ const listMetadataNeeded = collectReferencedListMetadataModels(ctx.spec.models, nonPaginatedRefs);
21551
21628
  walk(ref, (r) => {
21552
21629
  if (r.kind === "enum") {
21553
21630
  const canonicalName = enumCanonicalMap.get(r.name) ?? r.name;
@@ -21555,7 +21632,11 @@ function registerTypeImports(ref, imports, ctx) {
21555
21632
  }
21556
21633
  if (r.kind === "model") {
21557
21634
  const referenced = ctx.spec.models.find((m) => m.name === r.name);
21558
- if (referenced && (isListWrapperModel(referenced) || isListMetadataModel(referenced))) return;
21635
+ if (referenced) {
21636
+ const skipWrapper = isListWrapperModel(referenced) && !nonPaginatedRefs.has(referenced.name);
21637
+ const skipMetadata = isListMetadataModel(referenced) && !listMetadataNeeded.has(referenced.name);
21638
+ if (skipWrapper || skipMetadata) return;
21639
+ }
21559
21640
  imports.add(`com.workos.models.${className$1(r.name)}`);
21560
21641
  }
21561
21642
  });
@@ -23445,7 +23526,10 @@ function mapSorbetType$1(ref) {
23445
23526
  case "array": return `T::Array[${mapSorbetType$1(ref.items)}]`;
23446
23527
  case "model": return `WorkOS::${className(ref.name)}`;
23447
23528
  case "enum": return "String";
23448
- case "nullable": return `T.nilable(${mapSorbetType$1(ref.inner)})`;
23529
+ case "nullable": {
23530
+ const inner = mapSorbetType$1(ref.inner);
23531
+ return inner === "T.untyped" ? inner : `T.nilable(${inner})`;
23532
+ }
23449
23533
  case "literal":
23450
23534
  if (typeof ref.value === "string") return "String";
23451
23535
  if (ref.value === null) return "NilClass";
@@ -25049,6 +25133,7 @@ function generateRbiFiles(spec, ctx) {
25049
25133
  }
25050
25134
  /** Unwrap T.nilable(...) if already wrapped, to avoid double-wrapping. */
25051
25135
  function unwrapNilable(type) {
25136
+ if (type === "T.untyped") return type;
25052
25137
  const match = type.match(/^T\.nilable\((.+)\)$/);
25053
25138
  return match ? match[1] : type;
25054
25139
  }
@@ -27519,4 +27604,4 @@ const workosEmittersPlugin = {
27519
27604
  //#endregion
27520
27605
  export { pythonEmitter as _, rustExtractor as a, pythonExtractor as c, rustEmitter as d, rubyEmitter as f, phpEmitter as g, goEmitter as h, kotlinExtractor as i, rubyExtractor as l, dotnetEmitter as m, elixirExtractor as n, goExtractor as o, kotlinEmitter as p, dotnetExtractor as r, phpExtractor as s, workosEmittersPlugin as t, nodeExtractor as u, nodeEmitter as v };
27521
27606
 
27522
- //# sourceMappingURL=plugin-DRGwxN88.mjs.map
27607
+ //# sourceMappingURL=plugin-BbSmT2kj.mjs.map