@workos/oagen-emitters 0.18.0 → 0.18.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.18.0"
2
+ ".": "0.18.2"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.18.2](https://github.com/workos/oagen-emitters/compare/v0.18.1...v0.18.2) (2026-06-17)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **node:** adopt spec request interface for owned inline-literal params; dedupe common enums ([#154](https://github.com/workos/oagen-emitters/issues/154)) ([71e2d4f](https://github.com/workos/oagen-emitters/commit/71e2d4f4e05441a41217286b92a555237c3fd794))
9
+
10
+ ## [0.18.1](https://github.com/workos/oagen-emitters/compare/v0.18.0...v0.18.1) (2026-06-17)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **node:** support owning services with hand-owned generic types ([#152](https://github.com/workos/oagen-emitters/issues/152)) ([aa8223d](https://github.com/workos/oagen-emitters/commit/aa8223dbb6b56f5c2ab12ac42e5a1fc9f9e99943))
16
+
3
17
  ## [0.18.0](https://github.com/workos/oagen-emitters/compare/v0.17.0...v0.18.0) (2026-06-16)
4
18
 
5
19
 
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as fieldName$4, B as servicePropertyName, C as apiClassName, D as dotnetEmitter, E as propertyName, F as fieldName$3, H as fieldName$1, I as methodName, L as trimMountedResourceFromMethod, M as trimMountedResourceFromMethod$1, N as goEmitter, O as appendAsyncSuffix, P as className, R as phpEmitter, S as kotlinEmitter, T as packageSegment, U as safeParamName$1, V as pythonEmitter, W as nodeEmitter, _ as rubyEmitter, a as rustExtractor, b as resolveServiceTarget, c as pythonExtractor, d as rustEmitter, f as fieldName$5, g as typeName, h as resourceAccessorName, i as kotlinExtractor, j as methodName$1, k as className$1, l as rubyExtractor, m as moduleName, n as elixirExtractor, o as goExtractor, p as methodName$3, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor, v as buildExportedClassNameSet, w as methodName$2, x as safeParamName, y as fieldName, z as fieldName$2 } from "./plugin-DAa-HsN5.mjs";
1
+ import { A as fieldName$4, B as servicePropertyName, C as apiClassName, D as dotnetEmitter, E as propertyName, F as fieldName$3, H as fieldName$1, I as methodName, L as trimMountedResourceFromMethod, M as trimMountedResourceFromMethod$1, N as goEmitter, O as appendAsyncSuffix, P as className, R as phpEmitter, S as kotlinEmitter, T as packageSegment, U as safeParamName$1, V as pythonEmitter, W as nodeEmitter, _ as rubyEmitter, a as rustExtractor, b as resolveServiceTarget, c as pythonExtractor, d as rustEmitter, f as fieldName$5, g as typeName, h as resourceAccessorName, i as kotlinExtractor, j as methodName$1, k as className$1, l as rubyExtractor, m as moduleName, n as elixirExtractor, o as goExtractor, p as methodName$3, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor, v as buildExportedClassNameSet, w as methodName$2, x as safeParamName, y as fieldName, z as fieldName$2 } from "./plugin-bqfwowQ3.mjs";
2
2
  import { collectSnippetArgs, collectWrapperArgs, toSnakeCase } from "@workos/oagen";
3
3
  //#region src/snippets/ruby.ts
4
4
  const INDENT$6 = " ";
@@ -3626,6 +3626,17 @@ function isNodeOwnedService(ctx, ...names) {
3626
3626
  const owned = new Set(configured.map(normalizeServiceName));
3627
3627
  return names.some((name) => name !== void 0 ? ownedLookupNames(name).some((candidate) => owned.has(normalizeServiceName(candidate))) : false);
3628
3628
  }
3629
+ /**
3630
+ * True when `name` is a hand-owned type (see {@link NodeEmitterOptions.handOwnedTypes}).
3631
+ * Hand-owned types are never generated; the emitter defers to the existing
3632
+ * hand-written declaration and routes imports/barrel exports to it.
3633
+ */
3634
+ function isHandOwnedType(ctx, name) {
3635
+ if (name === void 0) return false;
3636
+ const configured = nodeOptions(ctx).handOwnedTypes;
3637
+ if (!configured || configured.length === 0) return false;
3638
+ return configured.includes(name);
3639
+ }
3629
3640
  //#endregion
3630
3641
  //#region src/node/live-surface.ts
3631
3642
  const SRC_DIR = "src";
@@ -4662,6 +4673,16 @@ function assignEnumsToServices(enums, services, models = [], ctx) {
4662
4673
  for (const name of collectFieldDependencies(model).enums) if (enumNames.has(name) && !enumToService.has(name)) enumToService.set(name, service);
4663
4674
  }
4664
4675
  }
4676
+ if (ctx) {
4677
+ const serviceNameMap = buildServiceNameMap(services, ctx);
4678
+ const toUnassign = [];
4679
+ for (const [name, service] of enumToService) {
4680
+ if (!isNodeOwnedService(ctx, service, serviceNameMap.get(service))) continue;
4681
+ const home = (ctx.apiSurface?.enums?.[name])?.sourceFile ?? (ctx.apiSurface?.typeAliases?.[name])?.sourceFile ?? liveSurfaceInterfacePath(name);
4682
+ if (home && home.startsWith("src/common/")) toUnassign.push(name);
4683
+ }
4684
+ for (const name of toUnassign) enumToService.delete(name);
4685
+ }
4665
4686
  return enumToService;
4666
4687
  }
4667
4688
  //#endregion
@@ -5573,7 +5594,18 @@ function operationHasOptionsInput(op, plan, resolvedOp) {
5573
5594
  }
5574
5595
  function optionsObjectInfo(service, method, op, plan, ctx, baselineMethod, resolvedOp) {
5575
5596
  const baseline = optionsObjectParam$1(baselineMethod);
5576
- if (baseline) return baseline;
5597
+ if (baseline) {
5598
+ if (baseline.type.trimStart().startsWith("{") && isNodeOwnedService(ctx, service.name, resolveResourceClassName$3(service, ctx))) {
5599
+ const body = extractRequestBodyType(op, ctx);
5600
+ if (body?.kind === "model") return {
5601
+ name: "options",
5602
+ type: resolveInterfaceName(body.name, ctx),
5603
+ optional: optionsObjectShouldBeOptional(op, plan, resolvedOp),
5604
+ generated: false
5605
+ };
5606
+ }
5607
+ return baseline;
5608
+ }
5577
5609
  const overrideType = operationOverrideFor$1(ctx, op)?.optionsType;
5578
5610
  if (overrideType) return {
5579
5611
  name: "options",
@@ -5582,9 +5614,15 @@ function optionsObjectInfo(service, method, op, plan, ctx, baselineMethod, resol
5582
5614
  generated: baselineTypeSourceFile(ctx, overrideType) === void 0
5583
5615
  };
5584
5616
  if (!operationHasOptionsInput(op, plan, resolvedOp)) return void 0;
5617
+ const resolvedService = resolveResourceClassName$3(service, ctx);
5618
+ let optionsType = methodOptionsName$1(method, resolvedService);
5619
+ if (method !== "list") {
5620
+ const baselineDir = baselineTypeSourceFile(ctx, optionsType)?.match(/^src\/([^/]+)\//)?.[1];
5621
+ if (baselineDir && baselineDir !== resolveResourceDir(service, ctx)) optionsType = `${toPascalCase(resolvedService)}${toPascalCase(method)}Options`;
5622
+ }
5585
5623
  return {
5586
5624
  name: "options",
5587
- type: methodOptionsName$1(method, resolveResourceClassName$3(service, ctx)),
5625
+ type: optionsType,
5588
5626
  optional: optionsObjectShouldBeOptional(op, plan, resolvedOp),
5589
5627
  generated: true
5590
5628
  };
@@ -6079,7 +6117,7 @@ function generateResourceClass(service, ctx) {
6079
6117
  const resolved = lookupResolved(op, resolvedLookup);
6080
6118
  const optionInfo = optionsObjectInfo(service, method, op, plan, ctx, baselineMethodFor$1(service, method, ctx), resolved);
6081
6119
  if (plan.isPaginated) {
6082
- const extraParams = op.queryParams.filter((p) => !PAGINATION_PARAM_NAMES.has(p.name));
6120
+ const extraParams = op.queryParams.filter((p) => !PAGINATION_PARAM_NAMES.has(p.name) && !p.deprecated);
6083
6121
  if (extraParams.length > 0) {
6084
6122
  const optionsName = optionInfo?.type ?? paginatedOptionsName(method, resolvedName);
6085
6123
  if (extraParams.some((p) => fieldName$6(p.name) !== wireFieldName(p.name))) {
@@ -7336,6 +7374,7 @@ function generateModels$7(models, ctx, shared) {
7336
7374
  if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
7337
7375
  if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
7338
7376
  if (discriminatedSkip?.has(model.name)) continue;
7377
+ if (isHandOwnedType(ctx, model.name) || isHandOwnedType(ctx, resolveInterfaceName(model.name, ctx, { skipTypeAlias: true }))) continue;
7339
7378
  const service = modelToService.get(model.name);
7340
7379
  const isOwnedModel = isNodeOwnedService(ctx, service);
7341
7380
  if (!isOwnedModel && !modelHasNewFields(model, ctx) && !forceGenerate.has(model.name)) continue;
@@ -7410,6 +7449,7 @@ function generateModels$7(models, ctx, shared) {
7410
7449
  const crossServiceImports = /* @__PURE__ */ new Map();
7411
7450
  const unresolvableNames = /* @__PURE__ */ new Set();
7412
7451
  const enumToService = assignEnumsToServices(ctx.spec.enums, ctx.spec.services, ctx.spec.models, ctx);
7452
+ const serviceNameMap = buildServiceNameMap(ctx.spec.services, ctx);
7413
7453
  const resolvedEnumNames = /* @__PURE__ */ new Map();
7414
7454
  for (const e of ctx.spec.enums) resolvedEnumNames.set(resolveInterfaceName(e.name, ctx), e.name);
7415
7455
  for (const field of model.fields) {
@@ -7429,7 +7469,7 @@ function generateModels$7(models, ctx, shared) {
7429
7469
  const eDir = resolveDir(eService);
7430
7470
  const bEnum = ctx.apiSurface?.enums?.[irEnumName];
7431
7471
  const bAlias = ctx.apiSurface?.typeAliases?.[irEnumName];
7432
- const bSrc = isNodeOwnedService(ctx, eService) ? void 0 : bEnum?.sourceFile ?? bAlias?.sourceFile;
7472
+ const bSrc = isNodeOwnedService(ctx, eService, eService ? serviceNameMap.get(eService) : void 0) ? void 0 : bEnum?.sourceFile ?? bAlias?.sourceFile;
7433
7473
  const gPath = `src/${eDir}/interfaces/${fileName$3(irEnumName)}.interface.ts`;
7434
7474
  const cPath = `src/${dirName}/interfaces/${fileName$3(model.name)}.interface.ts`;
7435
7475
  if (bSrc === cPath) {
@@ -7474,7 +7514,7 @@ function generateModels$7(models, ctx, shared) {
7474
7514
  const baselineEnum = ctx.apiSurface?.enums?.[dep];
7475
7515
  const baselineAlias = ctx.apiSurface?.typeAliases?.[dep];
7476
7516
  const depService = enumToService.get(dep);
7477
- const baselineSrc = isNodeOwnedService(ctx, depService) ? void 0 : baselineEnum?.sourceFile ?? baselineAlias?.sourceFile ?? liveSurfaceInterfacePath(dep);
7517
+ const baselineSrc = isNodeOwnedService(ctx, depService, depService ? serviceNameMap.get(depService) : void 0) ? void 0 : baselineEnum?.sourceFile ?? baselineAlias?.sourceFile ?? liveSurfaceInterfacePath(dep);
7478
7518
  const depDir = resolveDir(depService);
7479
7519
  const generatedPath = `src/${depDir}/interfaces/${fileName$3(dep)}.interface.ts`;
7480
7520
  const currentFilePath = `src/${dirName}/interfaces/${fileName$3(model.name)}.interface.ts`;
@@ -7697,6 +7737,7 @@ function generateSerializers(models, ctx, shared) {
7697
7737
  if (isListMetadataModel(model) && !serializerListMetadataNeeded.has(model.name)) continue;
7698
7738
  if (isListWrapperModel(model) && !serializerNonPaginatedRefs.has(model.name)) continue;
7699
7739
  if (discriminatedSerializerSkip?.has(model.name)) continue;
7740
+ if (isHandOwnedType(ctx, model.name) || isHandOwnedType(ctx, resolveInterfaceName(model.name, ctx, { skipTypeAlias: true }))) continue;
7700
7741
  if (!isNodeOwnedService(ctx, modelToService.get(model.name)) && !modelHasNewFields(model, ctx) && !forceGenerateSerializer.has(model.name)) continue;
7701
7742
  eligibleModels.push(model);
7702
7743
  }
@@ -7780,12 +7821,20 @@ function generateSerializers(models, ctx, shared) {
7780
7821
  }
7781
7822
  const liveRootForBarrel = ctx.outputDir ?? ctx.targetDir;
7782
7823
  for (const [dir, stems] of serializersByDir) {
7783
- if (liveRootForBarrel && !isNodeOwnedService(ctx, dir)) {
7824
+ if (liveRootForBarrel) {
7825
+ const dirIsOwned = isNodeOwnedService(ctx, dir);
7784
7826
  const serializersDir = path.join(liveRootForBarrel, "src", dir, "serializers");
7785
7827
  try {
7786
7828
  for (const entry of fs.readdirSync(serializersDir)) {
7787
7829
  if (!entry.endsWith(".serializer.ts")) continue;
7788
- stems.add(entry.replace(/\.serializer\.ts$/, ""));
7830
+ const stem = entry.replace(/\.serializer\.ts$/, "");
7831
+ if (stems.has(stem)) continue;
7832
+ if (dirIsOwned) {
7833
+ const content = fs.readFileSync(path.join(serializersDir, entry), "utf-8");
7834
+ if (/auto-generated by oagen/i.test(content.slice(0, 400))) continue;
7835
+ if (![...content.matchAll(/export\s+(?:const|function)\s+((?:de)?serialize[A-Za-z0-9_]+)/g)].map((m) => m[1].replace(/^(?:de)?serialize/, "")).some((typeName) => isHandOwnedType(ctx, typeName))) continue;
7836
+ }
7837
+ stems.add(stem);
7789
7838
  }
7790
7839
  } catch {}
7791
7840
  }
@@ -8069,12 +8118,12 @@ function exportedNamesForSource(ctx, sourceFile) {
8069
8118
  */
8070
8119
  function generateServiceBarrels(spec, ctx) {
8071
8120
  const files = [];
8072
- const { modelToService, resolveDir } = createServiceDirResolver(spec.models, spec.services, ctx);
8121
+ const { modelToService, resolveDir, serviceNameMap } = createServiceDirResolver(spec.models, spec.services, ctx);
8073
8122
  const enumToService = assignEnumsToServices(spec.enums, spec.services, spec.models, ctx);
8074
8123
  const dirExports = /* @__PURE__ */ new Map();
8075
8124
  const dirSymbols = /* @__PURE__ */ new Map();
8076
8125
  const ownedDirNames = /* @__PURE__ */ new Set();
8077
- for (const service of spec.services) if (isNodeOwnedService(ctx, service.name)) {
8126
+ for (const service of spec.services) if (isNodeOwnedService(ctx, service.name, serviceNameMap.get(service.name))) {
8078
8127
  const dir = resolveDir(service.name);
8079
8128
  ownedDirNames.add(dir);
8080
8129
  if (!dirExports.has(dir)) {
@@ -8845,12 +8894,12 @@ function buildOptionsObjectTestArg(op, plan, baselineMethod, modelMap, ctx) {
8845
8894
  entries.push(`${optionField}: ${JSON.stringify(pathParamTestValue(param, localName))}`);
8846
8895
  }
8847
8896
  if (plan.isPaginated) entries.push("order: 'desc'");
8848
- const queryParams = plan.isPaginated ? op.queryParams.filter((param) => ![
8897
+ const queryParams = (plan.isPaginated ? op.queryParams.filter((param) => ![
8849
8898
  "limit",
8850
8899
  "before",
8851
8900
  "after",
8852
8901
  "order"
8853
- ].includes(param.name)) : op.queryParams;
8902
+ ].includes(param.name)) : op.queryParams).filter((param) => !param.deprecated);
8854
8903
  for (const param of queryParams) {
8855
8904
  const localName = fieldName$6(param.name);
8856
8905
  const value = queryParamTestValue(param, modelMap);
@@ -29869,4 +29918,4 @@ const workosEmittersPlugin = {
29869
29918
  //#endregion
29870
29919
  export { fieldName$2 as A, servicePropertyName$2 as B, apiClassName as C, dotnetEmitter as D, propertyName as E, fieldName$3 as F, fieldName$5 as H, methodName$3 as I, trimMountedResourceFromMethod$2 as L, trimMountedResourceFromMethod$1 as M, goEmitter as N, appendAsyncSuffix as O, className$3 as P, phpEmitter as R, kotlinEmitter as S, packageSegment as T, safeParamName$1 as U, pythonEmitter as V, nodeEmitter as W, rubyEmitter as _, rustExtractor as a, resolveServiceTarget as b, pythonExtractor as c, rustEmitter as d, fieldName as f, typeName as g, resourceAccessorName as h, kotlinExtractor as i, methodName$2 as j, className$2 as k, rubyExtractor as l, moduleName as m, elixirExtractor as n, goExtractor as o, methodName as p, dotnetExtractor as r, phpExtractor as s, workosEmittersPlugin as t, nodeExtractor as u, buildExportedClassNameSet as v, methodName$1 as w, safeParamName as x, fieldName$1 as y, fieldName$4 as z };
29871
29920
 
29872
- //# sourceMappingURL=plugin-DAa-HsN5.mjs.map
29921
+ //# sourceMappingURL=plugin-bqfwowQ3.mjs.map