@workos/oagen-emitters 0.14.0 → 0.14.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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.14.0"
2
+ ".": "0.14.1"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.1](https://github.com/workos/oagen-emitters/compare/v0.14.0...v0.14.1) (2026-05-22)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * emit non-paginated list wrappers, dotnet member/class collisions, rust glob ambiguity ([#120](https://github.com/workos/oagen-emitters/issues/120)) ([6df9822](https://github.com/workos/oagen-emitters/commit/6df98221dfa707800babce0d6a4cf1a653923743))
9
+ * **node:** carry forward prior-manifest paths so prune diffs stay accurate ([#117](https://github.com/workos/oagen-emitters/issues/117)) ([a03e4db](https://github.com/workos/oagen-emitters/commit/a03e4dbf2733e33ae4c31be568c2a12ea8361be1))
10
+ * **shared:** prevent synthetic-enum collision with IR enums ([#119](https://github.com/workos/oagen-emitters/issues/119)) ([0211f66](https://github.com/workos/oagen-emitters/commit/0211f669b51da3a14717dfa61941c954dc7edaa6))
11
+
3
12
  ## [0.14.0](https://github.com/workos/oagen-emitters/compare/v0.13.0...v0.14.0) (2026-05-21)
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":";;;;;cAoYa,WAAA,EAAa,OAuGzB;;;cCpcY,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":";;;;;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"}
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-BxVeu2v9.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-DRGwxN88.mjs";
2
2
  export { dotnetEmitter, dotnetExtractor, elixirExtractor, goEmitter, goExtractor, kotlinEmitter, kotlinExtractor, nodeEmitter, nodeExtractor, phpEmitter, phpExtractor, pythonEmitter, pythonExtractor, rubyEmitter, rubyExtractor, rustEmitter, rustExtractor, workosEmittersPlugin };
@@ -2286,6 +2286,24 @@ dumper.dump;
2286
2286
  //#endregion
2287
2287
  //#region src/shared/model-utils.ts
2288
2288
  /**
2289
+ * Collect model names referenced as the return type of any non-paginated
2290
+ * operation. The list-wrapper skip rule below assumes a wrapper is always
2291
+ * replaced by the SDK's pagination machinery — but a few endpoints
2292
+ * (e.g. `GET /vault/v1/kv/{id}/versions`) have a list-envelope response
2293
+ * shape with no pagination params, so the parser leaves them as a plain
2294
+ * model reference. We must still emit those wrappers as regular models;
2295
+ * otherwise the generated resource code references an undefined name.
2296
+ */
2297
+ function collectNonPaginatedResponseModelNames(services) {
2298
+ const names = /* @__PURE__ */ new Set();
2299
+ for (const service of services) for (const op of service.operations) {
2300
+ if (op.pagination) continue;
2301
+ walkTypeRef(op.response, { model: (r) => names.add(r.name) });
2302
+ for (const sr of op.successResponses ?? []) walkTypeRef(sr.type, { model: (r) => names.add(r.name) });
2303
+ }
2304
+ return names;
2305
+ }
2306
+ /**
2289
2307
  * Detect whether a model is a list wrapper -- the standard paginated
2290
2308
  * list envelope with `data` (array), `list_metadata`, and optionally `object: 'list'`.
2291
2309
  *
@@ -2636,7 +2654,7 @@ function detectDiscriminators(models) {
2636
2654
  * Returns a new array of enriched models (original models are not mutated).
2637
2655
  * Synthetic enums are stored internally; retrieve them via `getSyntheticEnums()`.
2638
2656
  */
2639
- function enrichModelsFromSpec(models) {
2657
+ function enrichModelsFromSpec(models, enums = []) {
2640
2658
  if (!loadRawSpec()) {
2641
2659
  _lastSyntheticEnums = [];
2642
2660
  return models;
@@ -2646,6 +2664,10 @@ function enrichModelsFromSpec(models) {
2646
2664
  collector.usedNames.add(m.name);
2647
2665
  collector.usedNames.add(toSnakeCase(m.name));
2648
2666
  }
2667
+ for (const e of enums) {
2668
+ collector.usedNames.add(e.name);
2669
+ collector.usedNames.add(toSnakeCase(e.name));
2670
+ }
2649
2671
  const enriched2 = models.map((model) => {
2650
2672
  const rawSchema = lookupRawSchema(model.name);
2651
2673
  if (!rawSchema) return model;
@@ -5991,12 +6013,13 @@ function generateModels$7(models, ctx, shared) {
5991
6013
  }
5992
6014
  }
5993
6015
  const discriminatedSkip = ctx._discriminatedModelNames;
6016
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
5994
6017
  for (const originalModel of models) {
5995
6018
  const model = projectedByName.get(originalModel.name) ?? originalModel;
5996
6019
  if (!reachableModels.has(model.name)) continue;
5997
6020
  if (interfaceEligibleModels && !interfaceEligibleModels.has(model.name)) continue;
5998
6021
  if (isListMetadataModel(model)) continue;
5999
- if (isListWrapperModel(model)) continue;
6022
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
6000
6023
  if (discriminatedSkip?.has(model.name)) continue;
6001
6024
  const service = modelToService.get(model.name);
6002
6025
  const isOwnedModel = isNodeOwnedService(ctx, service);
@@ -6330,13 +6353,14 @@ function generateSerializers(models, ctx, shared) {
6330
6353
  }
6331
6354
  }
6332
6355
  const discriminatedSerializerSkip = ctx._discriminatedModelNames;
6356
+ const serializerNonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
6333
6357
  const eligibleModels = [];
6334
6358
  for (const originalModel of models) {
6335
6359
  const model = projectedByName.get(originalModel.name) ?? originalModel;
6336
6360
  if (!serializerReachable.has(model.name)) continue;
6337
6361
  if (serializerEligibleModels && !serializerEligibleModels.has(model.name)) continue;
6338
6362
  if (isListMetadataModel(model)) continue;
6339
- if (isListWrapperModel(model)) continue;
6363
+ if (isListWrapperModel(model) && !serializerNonPaginatedRefs.has(model.name)) continue;
6340
6364
  if (discriminatedSerializerSkip?.has(model.name)) continue;
6341
6365
  if (!isNodeOwnedService(ctx, modelToService.get(model.name)) && !modelHasNewFields(model, ctx) && !forceGenerateSerializer.has(model.name)) continue;
6342
6366
  eligibleModels.push(model);
@@ -8183,6 +8207,22 @@ function withNodeOperationOverrides(ctx) {
8183
8207
  * one oagen run, so we walk the target SDK once and reuse it.
8184
8208
  */
8185
8209
  const surfaceCache = /* @__PURE__ */ new WeakMap();
8210
+ /**
8211
+ * Paths the node emitter has produced so far in this ctx, accumulated across
8212
+ * `applyLiveSurface` calls. Drives `carryForwardManagedFiles` so files in the
8213
+ * prior manifest that we did not re-emit this run still land in the new
8214
+ * manifest as "still managed" — without that, the orchestrator's prune diff
8215
+ * treats every untouched autogen file as stale.
8216
+ */
8217
+ const emittedPathsCache = /* @__PURE__ */ new WeakMap();
8218
+ function getEmittedPaths(ctx) {
8219
+ let set = emittedPathsCache.get(ctx);
8220
+ if (!set) {
8221
+ set = /* @__PURE__ */ new Set();
8222
+ emittedPathsCache.set(ctx, set);
8223
+ }
8224
+ return set;
8225
+ }
8186
8226
  function getSurface(ctx) {
8187
8227
  let surface = surfaceCache.get(ctx);
8188
8228
  if (surface) return surface;
@@ -8229,8 +8269,10 @@ function getSurface(ctx) {
8229
8269
  * `integrateTarget: false` files (smoke-manifest.json etc.) are also dropped:
8230
8270
  * with no `--target` step they would otherwise land as untracked cruft.
8231
8271
  *
8232
- * Note: pairing this with `--no-prune` is required for stable behavior — see
8233
- * `scripts/sdk-generate.sh` in the spec repo, which enables it for `--lang node`.
8272
+ * Note: the carry-forward step in `generateTests` re-declares prior-manifest
8273
+ * paths we didn't touch this run, so the orchestrator's prune diff stays
8274
+ * accurate without needing `--no-prune` at the call site. See
8275
+ * `carryForwardManagedFiles` below.
8234
8276
  */
8235
8277
  /**
8236
8278
  * `*.spec.ts`, `*.test.ts`, and JSON fixtures under `fixtures/` are owned by
@@ -8380,6 +8422,52 @@ function applyLiveSurface(files, ctx, surface) {
8380
8422
  if (f.content && !f.content.endsWith("\n")) f.content += "\n";
8381
8423
  out.push(f);
8382
8424
  }
8425
+ const emitted = getEmittedPaths(ctx);
8426
+ for (const f of out) emitted.add(f.path);
8427
+ return out;
8428
+ }
8429
+ /**
8430
+ * Re-declare prior-manifest paths that we did not emit this run so manifest
8431
+ * pruning can tell "intentionally removed" from "untouched but still managed."
8432
+ *
8433
+ * The node emitter only outputs files it actually wants to write each run —
8434
+ * untouched-but-up-to-date autogen files don't come back through any
8435
+ * `generateXxx` method. Without this carry-forward, the orchestrator's
8436
+ * `prevManifest.files − currentEmission` diff treats every such file as stale
8437
+ * and prunes the whole tree on a regen. That's why `scripts/sdk-generate.sh`
8438
+ * historically paired the node emitter with `--no-prune` — at the cost of
8439
+ * never pruning legitimately-removed files (e.g. an enum file orphaned by a
8440
+ * `schemaNameTransform` rename like `RadarAction` → `RadarListAction`).
8441
+ *
8442
+ * The carry-forward entry uses `skipIfExists: true`, so writer.ts skips the
8443
+ * write and only ensures the header is present (no-op for files that already
8444
+ * have it). The path still lands in `outputEmittedPaths` and therefore in the
8445
+ * new manifest, which restores correct prune semantics.
8446
+ *
8447
+ * Files dropped from the carry-forward set:
8448
+ * - Not on disk anymore (file was hand-deleted — let prune confirm absence).
8449
+ * - `@oagen-ignore-file` protected (user has explicitly taken ownership).
8450
+ * - `.ts` files that no longer carry the auto-gen header (user has taken
8451
+ * ownership in-place; the next prune cycle will clear the manifest entry).
8452
+ */
8453
+ function carryForwardManagedFiles(ctx, surface) {
8454
+ const priorPaths = ctx.priorTargetManifestPaths;
8455
+ if (!priorPaths || priorPaths.size === 0) return [];
8456
+ const emitted = getEmittedPaths(ctx);
8457
+ const out = [];
8458
+ for (const relPath of priorPaths) {
8459
+ if (emitted.has(relPath)) continue;
8460
+ if (!surface.files.has(relPath)) continue;
8461
+ if (surface.protectedFiles.has(relPath)) continue;
8462
+ if (relPath.endsWith(".ts") && !surface.autogenFiles.has(relPath)) continue;
8463
+ out.push({
8464
+ path: relPath,
8465
+ content: "",
8466
+ skipIfExists: true,
8467
+ headerPlacement: "skip"
8468
+ });
8469
+ emitted.add(relPath);
8470
+ }
8383
8471
  return out;
8384
8472
  }
8385
8473
  /**
@@ -8446,9 +8534,8 @@ const nodeEmitter = {
8446
8534
  },
8447
8535
  generateTests(spec, ctx) {
8448
8536
  const nodeCtx = withNodeOperationOverrides(ctx);
8449
- if (!nodeOptions(nodeCtx).regenerateOwnedTests) return [];
8450
8537
  const surface = getSurface(nodeCtx);
8451
- return applyLiveSurface(generateTests$7(spec, nodeCtx), nodeCtx, surface);
8538
+ return [...nodeOptions(nodeCtx).regenerateOwnedTests ? applyLiveSurface(generateTests$7(spec, nodeCtx), nodeCtx, surface) : [], ...carryForwardManagedFiles(nodeCtx, surface)];
8452
8539
  },
8453
8540
  buildOperationsMap() {
8454
8541
  return {};
@@ -9225,8 +9312,9 @@ function generateModels$6(models, ctx) {
9225
9312
  const symbolToFile = /* @__PURE__ */ new Map();
9226
9313
  const symbolToOriginalService = /* @__PURE__ */ new Map();
9227
9314
  const emittedFilePaths = /* @__PURE__ */ new Set();
9315
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
9228
9316
  for (const model of models) {
9229
- if (isListWrapperModel(model)) continue;
9317
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
9230
9318
  if (isListMetadataModel(model)) continue;
9231
9319
  const dirName = resolveDir(modelToService.get(model.name));
9232
9320
  const modelClassName = className$5(model.name);
@@ -10640,7 +10728,9 @@ function generateResources$6(services, ctx) {
10640
10728
  }
10641
10729
  for (const op of allOperations) {
10642
10730
  const plan = planOperation(op);
10643
- if (plan.responseModelName && !listWrapperNames.has(plan.responseModelName)) modelImports.add(plan.responseModelName);
10731
+ if (plan.responseModelName) {
10732
+ if (!listWrapperNames.has(plan.responseModelName) || !plan.isPaginated) modelImports.add(plan.responseModelName);
10733
+ }
10644
10734
  if (op.requestBody?.kind === "model") {
10645
10735
  const requestBodyRef = op.requestBody;
10646
10736
  modelImports.add(requestBodyRef.name);
@@ -12769,9 +12859,10 @@ function generateModels$5(models, ctx) {
12769
12859
  ].join("\n"),
12770
12860
  overwriteExisting: true
12771
12861
  });
12862
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
12772
12863
  for (const model of models) {
12773
12864
  if (isListMetadataModel(model)) continue;
12774
- if (isListWrapperModel(model)) continue;
12865
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
12775
12866
  const name = className$4(model.name);
12776
12867
  const lines = [];
12777
12868
  lines.push(`namespace ${ctx.namespacePascal}\\Resource;`);
@@ -14671,10 +14762,12 @@ function generateModels$4(models, ctx) {
14671
14762
  lines.push(`package ${ctx.namespace}`);
14672
14763
  lines.push("");
14673
14764
  const requestBodyOnly = collectRequestBodyOnlyModelNames$1(ctx.spec.services, models);
14765
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
14766
+ const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
14674
14767
  const modelHashMap = /* @__PURE__ */ new Map();
14675
14768
  const hashGroups = /* @__PURE__ */ new Map();
14676
14769
  for (const model of models) {
14677
- if (isListWrapperModel(model) || isListMetadataModel(model)) continue;
14770
+ if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
14678
14771
  if (requestBodyOnly.has(model.name)) continue;
14679
14772
  const hash = structuralHash$2(model);
14680
14773
  modelHashMap.set(model.name, hash);
@@ -14691,7 +14784,7 @@ function generateModels$4(models, ctx) {
14691
14784
  }
14692
14785
  const batchedAliases = /* @__PURE__ */ new Set();
14693
14786
  for (const model of models) {
14694
- if (isListWrapperModel(model) || isListMetadataModel(model)) continue;
14787
+ if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
14695
14788
  if (requestBodyOnly.has(model.name)) continue;
14696
14789
  const structName = className$3(model.name);
14697
14790
  const canonicalName = aliasOf.get(model.name);
@@ -17324,7 +17417,15 @@ function isEnumRef(ref) {
17324
17417
  * omission so the API returns a clear `missing required field` error instead
17325
17418
  * of a confusing 422.
17326
17419
  */
17327
- function emitJsonPropertyAttributes(_wireName, options = {}) {
17420
+ function emitJsonPropertyAttributes(wireName, options = {}) {
17421
+ if (options.explicitWireName) {
17422
+ if (options.isRequiredEnum) return [
17423
+ ` [JsonProperty("${wireName}", DefaultValueHandling = DefaultValueHandling.Ignore)]`,
17424
+ ` [STJS.JsonIgnore(Condition = STJS.JsonIgnoreCondition.WhenWritingDefault)]`,
17425
+ ` [STJS.JsonPropertyName("${wireName}")]`
17426
+ ];
17427
+ return [` [JsonProperty("${wireName}")]`, ` [STJS.JsonPropertyName("${wireName}")]`];
17428
+ }
17328
17429
  if (options.isRequiredEnum) return [` [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]`, ` [STJS.JsonIgnore(Condition = STJS.JsonIgnoreCondition.WhenWritingDefault)]`];
17329
17430
  return [];
17330
17431
  }
@@ -17377,16 +17478,23 @@ function generateModels$3(models, ctx, discCtx) {
17377
17478
  const files = [];
17378
17479
  primeModelAliases(models);
17379
17480
  const requestBodyOnlyNames = collectRequestBodyOnlyModelNames(ctx.spec.services, models);
17481
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
17482
+ const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
17380
17483
  const baseFieldLookup = /* @__PURE__ */ new Map();
17381
17484
  if (discCtx) {
17382
17485
  for (const model of models) if (discCtx.discriminatorBases.has(model.name)) {
17486
+ const baseClassName = modelClassName(model.name);
17383
17487
  const fieldMap = /* @__PURE__ */ new Map();
17384
- for (const field of model.fields) fieldMap.set(fieldName$2(field.name), mapTypeRef$3(field.type));
17488
+ for (const field of model.fields) {
17489
+ let csName = fieldName$2(field.name);
17490
+ if (csName === baseClassName) csName = `${csName}Value`;
17491
+ fieldMap.set(csName, mapTypeRef$3(field.type));
17492
+ }
17385
17493
  baseFieldLookup.set(model.name, fieldMap);
17386
17494
  }
17387
17495
  }
17388
17496
  for (const model of models) {
17389
- if (isListWrapperModel(model) || isListMetadataModel(model)) continue;
17497
+ if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
17390
17498
  if (requestBodyOnlyNames.has(model.name)) continue;
17391
17499
  const csClassName = modelClassName(model.name);
17392
17500
  if (isModelAlias(model.name)) continue;
@@ -17394,7 +17502,7 @@ function generateModels$3(models, ctx, discCtx) {
17394
17502
  const fieldTypes = model.fields.map((f) => mapTypeRef$3(f.type));
17395
17503
  const needsCollections = fieldTypes.some((t) => t.startsWith("List<") || t.startsWith("Dictionary<"));
17396
17504
  const needsSystem = fieldTypes.some((t) => t.includes("DateTimeOffset"));
17397
- const needsJsonAttrs = model.fields.some((f) => f.required && isEnumRef(f.type));
17505
+ const needsJsonAttrs = model.fields.some((f) => fieldName$2(f.name) === csClassName) || model.fields.some((f) => f.required && isEnumRef(f.type));
17398
17506
  lines.push(`namespace ${ctx.namespacePascal}`);
17399
17507
  lines.push("{");
17400
17508
  if (needsSystem) lines.push(" using System;");
@@ -17420,7 +17528,9 @@ function generateModels$3(models, ctx, discCtx) {
17420
17528
  const dictObjectFields = [];
17421
17529
  const seenFieldNames = /* @__PURE__ */ new Set();
17422
17530
  for (const field of model.fields) {
17423
- const csFieldName = fieldName$2(field.name);
17531
+ let csFieldName = fieldName$2(field.name);
17532
+ const collidesWithClassName = csFieldName === csClassName;
17533
+ if (collidesWithClassName) csFieldName = `${csFieldName}Value`;
17424
17534
  if (seenFieldNames.has(csFieldName)) continue;
17425
17535
  seenFieldNames.add(csFieldName);
17426
17536
  let useNewModifier = false;
@@ -17465,7 +17575,10 @@ function generateModels$3(models, ctx, discCtx) {
17465
17575
  lines.push(` [System.Obsolete("${msg}")]`);
17466
17576
  }
17467
17577
  const isRequiredEnum = field.required && isEnumRef(field.type) && constInit === null;
17468
- lines.push(...emitJsonPropertyAttributes(field.name, { isRequiredEnum }));
17578
+ lines.push(...emitJsonPropertyAttributes(field.name, {
17579
+ isRequiredEnum,
17580
+ explicitWireName: collidesWithClassName
17581
+ }));
17469
17582
  const discriminatedUnionConverter = discriminatedUnionConverterName(field.type);
17470
17583
  if (discriminatedUnionConverter) lines.push(` [Newtonsoft.Json.JsonConverter(typeof(${discriminatedUnionConverter}))]`);
17471
17584
  const newMod = useNewModifier ? "new " : "";
@@ -20050,14 +20163,16 @@ function promoteFieldType$1(f) {
20050
20163
  * List wrappers (`{ data, list_metadata }`) and the shared `ListMetadata`
20051
20164
  * model are skipped — the hand-maintained runtime provides [Page]/[ListMetadata].
20052
20165
  */
20053
- function generateModels$2(models, _ctx) {
20166
+ function generateModels$2(models, ctx) {
20054
20167
  if (models.length === 0) return [];
20055
20168
  for (const model of models) for (const field of model.fields) mapTypeRef$2(field.type);
20056
20169
  const files = [];
20170
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
20171
+ const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
20057
20172
  modelAliasMap = null;
20058
20173
  const hashGroupsPass1 = /* @__PURE__ */ new Map();
20059
20174
  for (const model of models) {
20060
- if (isListWrapperModel(model) || isListMetadataModel(model)) continue;
20175
+ if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20061
20176
  if (model.fields.length === 0 && discriminatedUnions.has(className$1(model.name))) continue;
20062
20177
  const hash = structuralHash(model);
20063
20178
  if (!hashGroupsPass1.has(hash)) hashGroupsPass1.set(hash, []);
@@ -20076,7 +20191,7 @@ function generateModels$2(models, _ctx) {
20076
20191
  modelAliasMap = aliasOf;
20077
20192
  const hashGroupsPass2 = /* @__PURE__ */ new Map();
20078
20193
  for (const model of models) {
20079
- if (isListWrapperModel(model) || isListMetadataModel(model)) continue;
20194
+ if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20080
20195
  if (model.fields.length === 0 && discriminatedUnions.has(className$1(model.name))) continue;
20081
20196
  if (aliasOf.has(model.name)) continue;
20082
20197
  const hash = structuralHash(model);
@@ -20094,7 +20209,7 @@ function generateModels$2(models, _ctx) {
20094
20209
  }
20095
20210
  }
20096
20211
  for (const model of models) {
20097
- if (isListWrapperModel(model) || isListMetadataModel(model)) continue;
20212
+ if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20098
20213
  const typeName = className$1(model.name);
20099
20214
  if (model.fields.length === 0 && discriminatedUnions.has(typeName)) {
20100
20215
  files.push(emitSealedUnion(typeName, discriminatedUnions.get(typeName)));
@@ -20122,7 +20237,7 @@ function generateModels$2(models, _ctx) {
20122
20237
  }
20123
20238
  const eventMapping = [];
20124
20239
  for (const model of models) {
20125
- if (isListWrapperModel(model) || isListMetadataModel(model)) continue;
20240
+ if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20126
20241
  if (aliasOf.has(model.name)) continue;
20127
20242
  if (!isEventEnvelopeModel(model)) continue;
20128
20243
  const eventField = model.fields.find((f) => f.name === "event");
@@ -22839,10 +22954,12 @@ function generateModels$1(models, ctx) {
22839
22954
  return mountDirMap.get(service) ?? classifyUnassignedModel(modelName);
22840
22955
  };
22841
22956
  const files = [];
22957
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
22958
+ const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
22842
22959
  const recursiveHashes = buildRecursiveHashMap(models, enumNames);
22843
22960
  const hashGroups = /* @__PURE__ */ new Map();
22844
22961
  for (const m of models) {
22845
- if (isListWrapperModel(m) || isListMetadataModel(m)) continue;
22962
+ if (skipAsListWrapper(m) || isListMetadataModel(m)) continue;
22846
22963
  const h = recursiveHashes.get(m.name) ?? "";
22847
22964
  if (!hashGroups.has(h)) hashGroups.set(h, []);
22848
22965
  hashGroups.get(h).push(m.name);
@@ -22855,7 +22972,7 @@ function generateModels$1(models, ctx) {
22855
22972
  for (let i = 1; i < sorted.length; i++) aliasOf.set(sorted[i], canonical);
22856
22973
  }
22857
22974
  for (const model of models) {
22858
- if (isListWrapperModel(model) || isListMetadataModel(model)) continue;
22975
+ if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
22859
22976
  const cls = className(model.name);
22860
22977
  const file = fileName(model.name);
22861
22978
  const canonical = aliasOf.get(model.name);
@@ -24986,8 +25103,8 @@ function ensureTrailingNewlines$1(files) {
24986
25103
  * has its original fields restored — otherwise `ConnectApplication`-style
24987
25104
  * bases would silently lose every variant field they had previously.
24988
25105
  */
24989
- function enrichModelsForRuby(models) {
24990
- const enriched = enrichModelsFromSpec(models);
25106
+ function enrichModelsForRuby(models, enums) {
25107
+ const enriched = enrichModelsFromSpec(models, enums);
24991
25108
  const originalByName = new Map(models.map((m) => [m.name, m]));
24992
25109
  return enriched.map((m) => {
24993
25110
  if (m.discriminator && m.fields.length === 0) {
@@ -25003,7 +25120,7 @@ function enrichModelsForRuby(models) {
25003
25120
  const rubyEmitter = {
25004
25121
  language: "ruby",
25005
25122
  generateModels(models, ctx) {
25006
- return ensureTrailingNewlines$1(generateModels$1(enrichModelsForRuby(models), ctx));
25123
+ return ensureTrailingNewlines$1(generateModels$1(enrichModelsForRuby(models, ctx.spec.enums), ctx));
25007
25124
  },
25008
25125
  generateEnums(enums, ctx) {
25009
25126
  const syntheticEnums = getSyntheticEnums();
@@ -25469,7 +25586,7 @@ function renderField(field, rustField, modelName, registry) {
25469
25586
  function renderModelsBarrel(modules) {
25470
25587
  const sorted = [...new Set(modules)].sort();
25471
25588
  const lines = [];
25472
- for (const m of sorted) lines.push(`pub mod ${m};`);
25589
+ for (const m of sorted) lines.push(`mod ${m};`);
25473
25590
  lines.push("");
25474
25591
  for (const m of sorted) lines.push(`pub use ${m}::*;`);
25475
25592
  return lines.join("\n") + "\n";
@@ -26552,7 +26669,7 @@ function renderResourcesBarrel(exports) {
26552
26669
  }
26553
26670
  unique.sort((a, b) => a.module.localeCompare(b.module));
26554
26671
  const lines = [];
26555
- for (const { module } of unique) lines.push(`pub mod ${module};`);
26672
+ for (const { module } of unique) lines.push(`mod ${module};`);
26556
26673
  lines.push("");
26557
26674
  for (const { module, struct } of unique) lines.push(`pub use ${module}::${struct};`);
26558
26675
  return lines.join("\n") + "\n";
@@ -27402,4 +27519,4 @@ const workosEmittersPlugin = {
27402
27519
  //#endregion
27403
27520
  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 };
27404
27521
 
27405
- //# sourceMappingURL=plugin-BxVeu2v9.mjs.map
27522
+ //# sourceMappingURL=plugin-DRGwxN88.mjs.map