@workos/oagen 0.24.5 → 0.25.0

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.
@@ -98,11 +98,44 @@ function deriveMethodName(op, _service) {
98
98
  return `${verb}_${verb === "list" ? resource : noun}`;
99
99
  }
100
100
  /**
101
+ * Resolve a service name to its mount target.
102
+ *
103
+ * Rule keys are either exact service names or trailing-`*` prefix patterns
104
+ * (e.g. `UserManagement*`). Precedence:
105
+ *
106
+ * 1. An exact key always wins.
107
+ * 2. Otherwise the wildcard with the longest prefix wins, so
108
+ * `UserManagementOrganizationMembership*` beats `UserManagement*`.
109
+ *
110
+ * Matching is plain string comparison (`startsWith`) — `*` is only recognised
111
+ * as the final character and no regex is ever built from rule keys.
112
+ *
113
+ * @param name - The IR service name to resolve.
114
+ * @param mounts - Exact-name or trailing-`*` pattern → target service mappings.
115
+ * @returns The mount target, or `name` unchanged when no rule matches.
116
+ */
117
+ function resolveMountTarget(name, mounts) {
118
+ const exact = mounts[name];
119
+ if (exact !== void 0) return exact;
120
+ let best;
121
+ let bestLen = -1;
122
+ for (const [pattern, target] of Object.entries(mounts)) {
123
+ if (!pattern.endsWith("*")) continue;
124
+ const prefix = pattern.slice(0, -1);
125
+ if (name.startsWith(prefix) && prefix.length > bestLen) {
126
+ best = target;
127
+ bestLen = prefix.length;
128
+ }
129
+ }
130
+ return best ?? name;
131
+ }
132
+ /**
101
133
  * Resolve all operations in the spec, applying hints and mount rules.
102
134
  *
103
135
  * @param spec - The parsed API spec
104
136
  * @param hints - Per-operation overrides keyed by "METHOD /path"
105
- * @param mountRules - Service name → target service mappings
137
+ * @param mountRules - Service name → target service mappings; keys may be
138
+ * exact names or trailing-`*` prefix patterns (see {@link resolveMountTarget})
106
139
  * @returns Resolved operations ready for emitter consumption
107
140
  */
108
141
  function resolveOperations(spec, hints, mountRules) {
@@ -112,7 +145,7 @@ function resolveOperations(spec, hints, mountRules) {
112
145
  for (const service of spec.services) for (const op of service.operations) {
113
146
  const hint = hintMap[`${op.httpMethod.toUpperCase()} ${op.path}`];
114
147
  const methodName = hint?.name ?? deriveMethodName(op, service);
115
- const mountOn = hint?.mountOn ?? mounts[service.name] ?? service.name;
148
+ const mountOn = hint?.mountOn ?? resolveMountTarget(service.name, mounts);
116
149
  let wrappers;
117
150
  if (hint?.split) wrappers = hint.split.map((sh) => ({
118
151
  name: sh.name,
@@ -2967,16 +3000,18 @@ function spliceExtraImports(existingLines, resultLines) {
2967
3000
  *
2968
3001
  * Matching is on the POST-MOUNT name. Mount resolution never mutates
2969
3002
  * `spec.services` — the post-mount target lives on `ResolvedOperation.mountOn`
2970
- * (`mountOn = hint?.mountOn ?? mountRules[service.name] ?? service.name`) — so the
2971
- * post-mount name of a source service is derived here as
2972
- * `mountRules[service.name] ?? service.name`. Selecting a target (e.g.
3003
+ * (`mountOn = hint?.mountOn ?? resolveMountTarget(service.name, mountRules)`) — so
3004
+ * the post-mount name of a source service is derived here with the same
3005
+ * `resolveMountTarget` (exact rules and trailing-`*` prefix rules, longest
3006
+ * prefix wins). Selecting a target (e.g.
2973
3007
  * `DirectorySync`) is valid because every source tag that mounts into it
2974
3008
  * (`DirectoryUsers`, `DirectoryGroups`, …) shares that post-mount name, and the
2975
3009
  * emitters group resources by mount, so all siblings emit together.
2976
3010
  *
2977
3011
  * @param spec - The parsed API spec (never mutated; never filtered).
2978
3012
  * @param selected - Post-mount service names from `--services` (normalized/trimmed).
2979
- * @param mountRules - Source-service-name → post-mount-target mappings.
3013
+ * @param mountRules - Source-service-name (exact or trailing-`*` prefix pattern)
3014
+ * → post-mount-target mappings.
2980
3015
  * @returns The validated selection as a `Set` of post-mount names.
2981
3016
  * @throws A `ConfigError` listing valid post-mount names when a selection is
2982
3017
  * unknown — scoped generation never silently emits the wrong set.
@@ -2994,8 +3029,7 @@ function canonicalServiceKey(name) {
2994
3029
  }
2995
3030
  function resolveScopedServices(spec, selected, mountRules) {
2996
3031
  const mounts = mountRules ?? {};
2997
- const postMountName = (name) => mounts[name] ?? name;
2998
- const validPostMount = new Set(spec.services.map((s) => postMountName(s.name)));
3032
+ const validPostMount = new Set(spec.services.map((s) => resolveMountTarget(s.name, mounts)));
2999
3033
  const selectedSet = new Set(selected);
3000
3034
  const unknown = [...selectedSet].filter((s) => !validPostMount.has(s));
3001
3035
  if (unknown.length > 0) {
@@ -3431,7 +3465,7 @@ async function readManifest(dir) {
3431
3465
  }
3432
3466
  try {
3433
3467
  const parsed = JSON.parse(raw);
3434
- if (typeof parsed.version !== "number" || typeof parsed.language !== "string" || typeof parsed.generatedAt !== "string" || !Array.isArray(parsed.files) || !parsed.files.every((p) => typeof p === "string")) return null;
3468
+ if (typeof parsed.version !== "number" || typeof parsed.language !== "string" || !Array.isArray(parsed.files) || !parsed.files.every((p) => typeof p === "string")) return null;
3435
3469
  if (parsed.version > MANIFEST_VERSION) {
3436
3470
  console.warn(`[oagen] ${MANIFEST_FILENAME} schema version ${parsed.version} is newer than supported (${MANIFEST_VERSION}); ignoring for pruning.`);
3437
3471
  return null;
@@ -3448,7 +3482,6 @@ async function writeManifest(dir, opts) {
3448
3482
  version: MANIFEST_VERSION,
3449
3483
  language: opts.language,
3450
3484
  ...opts.sdkName !== void 0 ? { sdkName: opts.sdkName } : {},
3451
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3452
3485
  ...opts.specSha !== void 0 ? { specSha: opts.specSha } : {},
3453
3486
  ...opts.specPath !== void 0 ? { specPath: opts.specPath } : {},
3454
3487
  ...opts.emitterSha !== void 0 ? { emitterSha: opts.emitterSha } : {},
@@ -3458,16 +3491,9 @@ async function writeManifest(dir, opts) {
3458
3491
  files: [...new Set(opts.files)].sort(),
3459
3492
  ...opts.operations !== void 0 ? { operations: opts.operations } : {}
3460
3493
  };
3461
- const previous = await readManifest(dir);
3462
- if (previous && sameManifestExceptGeneratedAt(previous, manifest)) manifest.generatedAt = previous.generatedAt;
3463
3494
  await fs.mkdir(dir, { recursive: true });
3464
3495
  await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
3465
3496
  }
3466
- function sameManifestExceptGeneratedAt(a, b) {
3467
- const { generatedAt: _aGeneratedAt, ...aComparable } = a;
3468
- const { generatedAt: _bGeneratedAt, ...bComparable } = b;
3469
- return JSON.stringify(aComparable) === JSON.stringify(bComparable);
3470
- }
3471
3497
  /** Return the set of previous paths no longer present in the current emission. */
3472
3498
  function computeStalePaths(prev, currentPaths) {
3473
3499
  const current = new Set(currentPaths);
@@ -4159,4 +4185,4 @@ function summarize(changes) {
4159
4185
  //#endregion
4160
4186
  export { MANIFEST_FILENAME as a, treeShakeFiles as c, collectReferencedNames as d, generateAllFiles as f, resolveOperations as h, generate as i, applyFileHeaders as l, deriveMethodName as m, getEmitter as n, integrateGeneratedFiles as o, generateFiles as p, registerEmitter as r, mapFilesForTargetIntegration as s, diffSpecs as t, buildEmitterContext as u };
4161
4187
 
4162
- //# sourceMappingURL=diff-DPnw1wPB.mjs.map
4188
+ //# sourceMappingURL=diff-BQn8Nv2c.mjs.map