@workos/oagen-emitters 0.7.2 → 0.7.4
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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/dist/index.mjs +1 -1
- package/dist/{plugin-CGPujyaL.mjs → plugin-BoTAX4nl.mjs} +209 -65
- package/dist/plugin-BoTAX4nl.mjs.map +1 -0
- package/dist/plugin.mjs +1 -1
- package/package.json +2 -2
- package/src/kotlin/path-expression.ts +51 -0
- package/src/kotlin/resources.ts +9 -20
- package/src/kotlin/wrappers.ts +3 -14
- package/src/node/path-expression.ts +37 -0
- package/src/node/resources.ts +2 -2
- package/src/node/wrappers.ts +2 -2
- package/src/php/path-expression.ts +52 -0
- package/src/php/resources.ts +4 -11
- package/src/php/wrappers.ts +3 -5
- package/src/python/path-expression.ts +52 -0
- package/src/python/resources.ts +17 -14
- package/src/python/wrappers.ts +2 -10
- package/src/shared/path-template.ts +64 -0
- package/test/php/resources.test.ts +1 -1
- package/test/python/resources.test.ts +2 -1
- package/test/shared/path-template.test.ts +70 -0
- package/dist/plugin-CGPujyaL.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.4](https://github.com/workos/oagen-emitters/compare/v0.7.3...v0.7.4) (2026-05-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* update dep ([e6145b6](https://github.com/workos/oagen-emitters/commit/e6145b694b9cacaa086234ba97b48c6e4108c084))
|
|
9
|
+
|
|
10
|
+
## [0.7.3](https://github.com/workos/oagen-emitters/compare/v0.7.2...v0.7.3) (2026-05-02)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* url-encode path parameters in php/node/python/kotlin emitters ([#75](https://github.com/workos/oagen-emitters/issues/75)) ([34c08fc](https://github.com/workos/oagen-emitters/commit/34c08fc10510db53f1f989edab5b4d0cead15aa9))
|
|
16
|
+
|
|
3
17
|
## [0.7.2](https://github.com/workos/oagen-emitters/compare/v0.7.1...v0.7.2) (2026-05-01)
|
|
4
18
|
|
|
5
19
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as nodeEmitter, a as rustExtractor, c as pythonExtractor, d as rubyEmitter, f as kotlinEmitter, g as pythonEmitter, h as phpEmitter, i as kotlinExtractor, l as rubyExtractor, m as goEmitter, n as elixirExtractor, o as goExtractor, p as dotnetEmitter, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor } from "./plugin-
|
|
1
|
+
import { _ as nodeEmitter, a as rustExtractor, c as pythonExtractor, d as rubyEmitter, f as kotlinEmitter, g as pythonEmitter, h as phpEmitter, i as kotlinExtractor, l as rubyExtractor, m as goEmitter, n as elixirExtractor, o as goExtractor, p as dotnetEmitter, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor } from "./plugin-BoTAX4nl.mjs";
|
|
2
2
|
export { dotnetEmitter, dotnetExtractor, elixirExtractor, goEmitter, goExtractor, kotlinEmitter, kotlinExtractor, nodeEmitter, nodeExtractor, phpEmitter, phpExtractor, pythonEmitter, pythonExtractor, rubyEmitter, rubyExtractor, rustExtractor, workosEmittersPlugin };
|
|
@@ -4475,6 +4475,79 @@ function formatWrapperDescription(name) {
|
|
|
4475
4475
|
return name.split("_").map((w, i) => i === 0 ? w.charAt(0).toUpperCase() + w.slice(1) : w).join(" ");
|
|
4476
4476
|
}
|
|
4477
4477
|
//#endregion
|
|
4478
|
+
//#region src/shared/path-template.ts
|
|
4479
|
+
/**
|
|
4480
|
+
* Parse an OpenAPI path template into an ordered list of literal and
|
|
4481
|
+
* parameter segments. Adjacent literals are coalesced into a single segment
|
|
4482
|
+
* (the only way two literals can be adjacent is if the input had `{}{}`
|
|
4483
|
+
* which is malformed; we still handle it deterministically).
|
|
4484
|
+
*
|
|
4485
|
+
* Examples:
|
|
4486
|
+
* "/orgs/{id}/users/{uid}" → [
|
|
4487
|
+
* { kind: 'literal', value: '/orgs/' },
|
|
4488
|
+
* { kind: 'param', name: 'id' },
|
|
4489
|
+
* { kind: 'literal', value: '/users/' },
|
|
4490
|
+
* { kind: 'param', name: 'uid' },
|
|
4491
|
+
* ]
|
|
4492
|
+
* "/health" → [{ kind: 'literal', value: '/health' }]
|
|
4493
|
+
* "" → []
|
|
4494
|
+
*/
|
|
4495
|
+
function parsePathTemplate(path, options = {}) {
|
|
4496
|
+
const normalized = options.stripLeadingSlash && path.startsWith("/") ? path.slice(1) : path;
|
|
4497
|
+
if (normalized === "") return [];
|
|
4498
|
+
const segments = [];
|
|
4499
|
+
const re = /\{([^{}]+)\}/g;
|
|
4500
|
+
let cursor = 0;
|
|
4501
|
+
let m;
|
|
4502
|
+
while ((m = re.exec(normalized)) !== null) {
|
|
4503
|
+
if (m.index > cursor) segments.push({
|
|
4504
|
+
kind: "literal",
|
|
4505
|
+
value: normalized.slice(cursor, m.index)
|
|
4506
|
+
});
|
|
4507
|
+
segments.push({
|
|
4508
|
+
kind: "param",
|
|
4509
|
+
name: m[1]
|
|
4510
|
+
});
|
|
4511
|
+
cursor = m.index + m[0].length;
|
|
4512
|
+
}
|
|
4513
|
+
if (cursor < normalized.length) segments.push({
|
|
4514
|
+
kind: "literal",
|
|
4515
|
+
value: normalized.slice(cursor)
|
|
4516
|
+
});
|
|
4517
|
+
return segments;
|
|
4518
|
+
}
|
|
4519
|
+
/** True when at least one segment is a parameter placeholder. */
|
|
4520
|
+
function hasPathParams(segments) {
|
|
4521
|
+
return segments.some((s) => s.kind === "param");
|
|
4522
|
+
}
|
|
4523
|
+
//#endregion
|
|
4524
|
+
//#region src/node/path-expression.ts
|
|
4525
|
+
/**
|
|
4526
|
+
* Build the TypeScript expression that the SDK passes as the request path.
|
|
4527
|
+
*
|
|
4528
|
+
* Every {paramName} placeholder becomes `${encodeURIComponent(name)}` inside a
|
|
4529
|
+
* template literal. encodeURIComponent is used (not encodeURI) because we want
|
|
4530
|
+
* "/" to be encoded too — otherwise a caller-supplied id containing "../" can
|
|
4531
|
+
* be normalized by the underlying HTTP transport (libcurl, fetch, etc.) into
|
|
4532
|
+
* a different endpoint of the WorkOS API while still authenticated with the
|
|
4533
|
+
* application's API key.
|
|
4534
|
+
*
|
|
4535
|
+
* "/orgs" → `'orgs'`
|
|
4536
|
+
* "/orgs/{id}" → `` `orgs/${encodeURIComponent(id)}` ``
|
|
4537
|
+
* "/orgs/{id}/foo" → `` `orgs/${encodeURIComponent(id)}/foo` ``
|
|
4538
|
+
*/
|
|
4539
|
+
function buildNodePathExpression(rawPath) {
|
|
4540
|
+
const segments = parsePathTemplate(rawPath);
|
|
4541
|
+
if (!hasPathParams(segments)) return `'${rawPath}'`;
|
|
4542
|
+
let body = "";
|
|
4543
|
+
for (const seg of segments) body += renderSegment(seg);
|
|
4544
|
+
return `\`${body}\``;
|
|
4545
|
+
}
|
|
4546
|
+
function renderSegment(seg) {
|
|
4547
|
+
if (seg.kind === "literal") return seg.value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
4548
|
+
return `\${encodeURIComponent(${fieldName$5(seg.name)})}`;
|
|
4549
|
+
}
|
|
4550
|
+
//#endregion
|
|
4478
4551
|
//#region src/node/wrappers.ts
|
|
4479
4552
|
/**
|
|
4480
4553
|
* Generate TypeScript wrapper method lines for union split operations.
|
|
@@ -4564,8 +4637,7 @@ function emitWrapperMethod$6(lines, resolvedOp, wrapper, ctx) {
|
|
|
4564
4637
|
}
|
|
4565
4638
|
/** Build a path template string from an Operation. */
|
|
4566
4639
|
function buildPathStr$1(op) {
|
|
4567
|
-
|
|
4568
|
-
return interpolated.includes("${") ? `\`${interpolated}\`` : `'${op.path}'`;
|
|
4640
|
+
return buildNodePathExpression(op.path);
|
|
4569
4641
|
}
|
|
4570
4642
|
/** Convert a JS value to a TypeScript literal. */
|
|
4571
4643
|
function tsLiteral$1(value) {
|
|
@@ -5365,8 +5437,7 @@ function renderQueryExpr(queryParams) {
|
|
|
5365
5437
|
return `options ? { ${parts.join(", ")} } : undefined`;
|
|
5366
5438
|
}
|
|
5367
5439
|
function buildPathStr(op) {
|
|
5368
|
-
|
|
5369
|
-
return interpolated.includes("${") ? `\`${interpolated}\`` : `'${op.path}'`;
|
|
5440
|
+
return buildNodePathExpression(op.path);
|
|
5370
5441
|
}
|
|
5371
5442
|
function buildPathParams(op, specEnumNames) {
|
|
5372
5443
|
const declaredNames = new Set(op.pathParams.map((p) => fieldName$5(p.name)));
|
|
@@ -7638,6 +7709,46 @@ function buildRecursiveHashMap$1(models, enums) {
|
|
|
7638
7709
|
return hashCache;
|
|
7639
7710
|
}
|
|
7640
7711
|
//#endregion
|
|
7712
|
+
//#region src/python/path-expression.ts
|
|
7713
|
+
/**
|
|
7714
|
+
* Build the Python f-string that the SDK passes to the request layer.
|
|
7715
|
+
*
|
|
7716
|
+
* Every {paramName} placeholder is wrapped in
|
|
7717
|
+
* `urllib.parse.quote(str(...), safe="")` so that an unencoded "/" or "../"
|
|
7718
|
+
* in a caller-supplied id cannot be normalized by the underlying HTTP
|
|
7719
|
+
* transport into a different endpoint of the WorkOS API while still
|
|
7720
|
+
* authenticated with the application's API key. `safe=""` is critical:
|
|
7721
|
+
* the stdlib default of `safe="/"` does NOT encode "/" and would leave the
|
|
7722
|
+
* traversal vector open.
|
|
7723
|
+
*
|
|
7724
|
+
* Generated files using this helper must import `quote` (e.g.
|
|
7725
|
+
* `from urllib.parse import quote`).
|
|
7726
|
+
*
|
|
7727
|
+
* "/orgs" → `"orgs"`
|
|
7728
|
+
* "/orgs/{id}" → `f"orgs/{quote(str(id), safe='')}"`
|
|
7729
|
+
* "/orgs/{id}" with id ∈ enums → `f"orgs/{quote(str(enum_value(id)), safe='')}"`
|
|
7730
|
+
*/
|
|
7731
|
+
function buildPythonPathExpression(rawPath, options = {}) {
|
|
7732
|
+
const segments = parsePathTemplate(rawPath, { stripLeadingSlash: true });
|
|
7733
|
+
if (segments.length === 0) return "\"\"";
|
|
7734
|
+
if (!hasPathParams(segments)) {
|
|
7735
|
+
const literal = segments[0].value;
|
|
7736
|
+
return `"${escapePyDoubleQuoted(literal)}"`;
|
|
7737
|
+
}
|
|
7738
|
+
const enums = options.enumParams;
|
|
7739
|
+
let body = "";
|
|
7740
|
+
for (const seg of segments) if (seg.kind === "literal") body += escapePyDoubleQuoted(seg.value);
|
|
7741
|
+
else {
|
|
7742
|
+
const varName = fieldName$4(seg.name);
|
|
7743
|
+
const inner = enums?.has(seg.name) ? `enum_value(${varName})` : varName;
|
|
7744
|
+
body += `{quote(str(${inner}), safe='')}`;
|
|
7745
|
+
}
|
|
7746
|
+
return `f"${body}"`;
|
|
7747
|
+
}
|
|
7748
|
+
function escapePyDoubleQuoted(literal) {
|
|
7749
|
+
return literal.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\{/g, "{{").replace(/\}/g, "}}");
|
|
7750
|
+
}
|
|
7751
|
+
//#endregion
|
|
7641
7752
|
//#region src/python/wrappers.ts
|
|
7642
7753
|
/**
|
|
7643
7754
|
* Generate Python wrapper method lines for split operations.
|
|
@@ -7707,12 +7818,7 @@ function emitWrapperMethod$5(lines, resolvedOp, wrapper, ctx, isAsync) {
|
|
|
7707
7818
|
lines.push(` if ${pyName} is not None:`);
|
|
7708
7819
|
lines.push(` body["${paramName}"] = ${pyName}`);
|
|
7709
7820
|
}
|
|
7710
|
-
|
|
7711
|
-
if (op.pathParams.length > 0) {
|
|
7712
|
-
let path = op.path.replace(/^\//, "");
|
|
7713
|
-
for (const p of op.pathParams) path = path.replace(`{${p.name}}`, `{${fieldName$4(p.name)}}`);
|
|
7714
|
-
pathExpr = `f"${path}"`;
|
|
7715
|
-
} else pathExpr = `"${op.path.replace(/^\//, "")}"`;
|
|
7821
|
+
const pathExpr = buildPythonPathExpression(op.path);
|
|
7716
7822
|
const awaitPrefix = isAsync ? "await " : "";
|
|
7717
7823
|
lines.push("");
|
|
7718
7824
|
if (wrapper.responseModelName) {
|
|
@@ -8397,6 +8503,7 @@ function generateResources$5(services, ctx) {
|
|
|
8397
8503
|
lines.push("from __future__ import annotations");
|
|
8398
8504
|
lines.push("");
|
|
8399
8505
|
lines.push("from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Type, Union, cast");
|
|
8506
|
+
if (allOperations.some((op) => op.pathParams.length > 0) || allOperations.some((op) => /\{[^{}]+\}/.test(op.path))) lines.push("from urllib.parse import quote");
|
|
8400
8507
|
lines.push("");
|
|
8401
8508
|
lines.push("if TYPE_CHECKING:");
|
|
8402
8509
|
lines.push(` from ${importPrefix}_client import AsyncWorkOSClient, WorkOSClient`);
|
|
@@ -8699,15 +8806,12 @@ function buildErrorRaisesBlock(op) {
|
|
|
8699
8806
|
}
|
|
8700
8807
|
/**
|
|
8701
8808
|
* Build a Python f-string path expression from an operation path.
|
|
8702
|
-
* E.g., "/organizations/{id}" -> f"organizations/{id}"
|
|
8809
|
+
* E.g., "/organizations/{id}" -> f"organizations/{quote(str(id), safe='')}"
|
|
8703
8810
|
*/
|
|
8704
8811
|
function buildPathString$1(op) {
|
|
8705
|
-
const
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
for (const param of op.pathParams) if (param.type.kind === "enum" || param.type.kind === "nullable" && param.type.inner?.kind === "enum") fPath = fPath.replace(`{${param.name}}`, `{enum_value(${fieldName$4(param.name)})}`);
|
|
8709
|
-
else fPath = fPath.replace(`{${param.name}}`, `{${fieldName$4(param.name)}}`);
|
|
8710
|
-
return `f"${fPath}"`;
|
|
8812
|
+
const enumParams = /* @__PURE__ */ new Set();
|
|
8813
|
+
for (const p of op.pathParams) if (p.type.kind === "enum" || p.type.kind === "nullable" && p.type.inner?.kind === "enum") enumParams.add(p.name);
|
|
8814
|
+
return buildPythonPathExpression(op.path, { enumParams });
|
|
8711
8815
|
}
|
|
8712
8816
|
//#endregion
|
|
8713
8817
|
//#region src/shared/non-spec-services.ts
|
|
@@ -10794,6 +10898,39 @@ function generateEnums$4(enums, ctx) {
|
|
|
10794
10898
|
return files;
|
|
10795
10899
|
}
|
|
10796
10900
|
//#endregion
|
|
10901
|
+
//#region src/php/path-expression.ts
|
|
10902
|
+
/**
|
|
10903
|
+
* Build the PHP expression that the SDK passes to HttpClient as `path:`.
|
|
10904
|
+
*
|
|
10905
|
+
* Concatenation, not interpolation: PHP does not allow function calls inside
|
|
10906
|
+
* "..." strings, and every parameter must be wrapped in `rawurlencode(...)` so
|
|
10907
|
+
* that an unencoded "../" in a caller-supplied id cannot be normalized by
|
|
10908
|
+
* libcurl into a different endpoint of the WorkOS API while still
|
|
10909
|
+
* authenticated with the application's API key.
|
|
10910
|
+
*
|
|
10911
|
+
* "/orgs" → `'orgs'`
|
|
10912
|
+
* "/orgs/{id}" → `'orgs/' . rawurlencode($id)`
|
|
10913
|
+
* "/orgs/{id}/users" → `'orgs/' . rawurlencode($id) . '/users'`
|
|
10914
|
+
* "/orgs/{id}" with id ∈ valueAccessorParams → `'orgs/' . rawurlencode($id->value)`
|
|
10915
|
+
*/
|
|
10916
|
+
function buildPhpPathExpression(rawPath, options = {}) {
|
|
10917
|
+
const segments = parsePathTemplate(rawPath, { stripLeadingSlash: true });
|
|
10918
|
+
if (segments.length === 0) return "''";
|
|
10919
|
+
if (!hasPathParams(segments)) return phpSingleQuoted(segments[0].value);
|
|
10920
|
+
const valueAccessor = options.valueAccessorParams;
|
|
10921
|
+
const parts = [];
|
|
10922
|
+
for (const seg of segments) if (seg.kind === "literal") parts.push(phpSingleQuoted(seg.value));
|
|
10923
|
+
else {
|
|
10924
|
+
const varName = fieldName$3(seg.name);
|
|
10925
|
+
const accessor = valueAccessor?.has(seg.name) ? `$${varName}->value` : `$${varName}`;
|
|
10926
|
+
parts.push(`rawurlencode(${accessor})`);
|
|
10927
|
+
}
|
|
10928
|
+
return parts.join(" . ");
|
|
10929
|
+
}
|
|
10930
|
+
function phpSingleQuoted(literal) {
|
|
10931
|
+
return `'${literal.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
10932
|
+
}
|
|
10933
|
+
//#endregion
|
|
10797
10934
|
//#region src/php/wrappers.ts
|
|
10798
10935
|
/**
|
|
10799
10936
|
* Generate PHP wrapper methods for split union operations.
|
|
@@ -10853,14 +10990,11 @@ function emitWrapperMethod$4(lines, resolvedOp, wrapper, ctx) {
|
|
|
10853
10990
|
lines.push(` $body['${clientField}'] = ${clientExpr};`);
|
|
10854
10991
|
}
|
|
10855
10992
|
const httpMethod = op.httpMethod.toUpperCase();
|
|
10856
|
-
|
|
10857
|
-
const hasInterpolation = /\{[^}]+\}/.test(path);
|
|
10858
|
-
path = path.replace(/\{([^}]+)\}/g, (_match, param) => `{$${fieldName$3(param)}}`);
|
|
10859
|
-
const pathQuote = hasInterpolation ? "\"" : "'";
|
|
10993
|
+
const pathExpr = buildPhpPathExpression(op.path);
|
|
10860
10994
|
lines.push("");
|
|
10861
10995
|
lines.push(" $response = $this->client->request(");
|
|
10862
10996
|
lines.push(` method: '${httpMethod}',`);
|
|
10863
|
-
lines.push(` path: ${
|
|
10997
|
+
lines.push(` path: ${pathExpr},`);
|
|
10864
10998
|
lines.push(" body: $body,");
|
|
10865
10999
|
lines.push(" options: $options,");
|
|
10866
11000
|
lines.push(" );");
|
|
@@ -11345,16 +11479,9 @@ function buildBodyParamMap(op, bodyModel) {
|
|
|
11345
11479
|
return map;
|
|
11346
11480
|
}
|
|
11347
11481
|
function buildPathString(op) {
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
for (const p of op.pathParams) {
|
|
11352
|
-
const phpName = fieldName$3(p.name);
|
|
11353
|
-
const isEnum = p.type.kind === "enum" || p.type.kind === "model";
|
|
11354
|
-
paramExprs.set(p.name, isEnum ? `{$${phpName}->value}` : `{$${phpName}}`);
|
|
11355
|
-
}
|
|
11356
|
-
path = path.replace(/\{([^}]+)\}/g, (_match, param) => paramExprs.get(param) ?? `{$${fieldName$3(param)}}`);
|
|
11357
|
-
return `"${path}"`;
|
|
11482
|
+
const valueAccessor = /* @__PURE__ */ new Set();
|
|
11483
|
+
for (const p of op.pathParams) if (p.type.kind === "enum" || p.type.kind === "model") valueAccessor.add(p.name);
|
|
11484
|
+
return buildPhpPathExpression(op.path, { valueAccessorParams: valueAccessor });
|
|
11358
11485
|
}
|
|
11359
11486
|
function isEnumType(ref) {
|
|
11360
11487
|
if (ref.kind === "enum") return true;
|
|
@@ -13258,7 +13385,7 @@ function generateMethod$1(serviceType, mountName, method, op, plan, _ctx, resolv
|
|
|
13258
13385
|
if (paramsType) params.push(`params ${paramsType}`);
|
|
13259
13386
|
params.push("opts ...RequestOption");
|
|
13260
13387
|
lines.push(`func (s *${serviceType}) ${method}(${params.join(", ")}) ${returnType} {`);
|
|
13261
|
-
const pathExpr = buildPathExpr$
|
|
13388
|
+
const pathExpr = buildPathExpr$1(op);
|
|
13262
13389
|
if (isUrlBuilder) {
|
|
13263
13390
|
emitUrlBuilderMethod(lines, op, pathExpr, resolvedOp, paramsType);
|
|
13264
13391
|
lines.push("}");
|
|
@@ -13557,7 +13684,7 @@ function needsStringsImport(operations, resolvedLookup) {
|
|
|
13557
13684
|
}
|
|
13558
13685
|
return false;
|
|
13559
13686
|
}
|
|
13560
|
-
function buildPathExpr$
|
|
13687
|
+
function buildPathExpr$1(op) {
|
|
13561
13688
|
if (op.pathParams.length === 0) return `"${op.path}"`;
|
|
13562
13689
|
let fmtStr = op.path;
|
|
13563
13690
|
const args = [];
|
|
@@ -16001,7 +16128,7 @@ function generateMethod(_serviceType, mountName, method, methodStem, op, plan, c
|
|
|
16001
16128
|
for (const field of inferFromClient) if (field === "client_id") lines.push(` options.${fieldName$1(field)} = this.Client.RequireClientId();`);
|
|
16002
16129
|
else lines.push(` options.${fieldName$1(field)} = this.Client.${clientFieldExpression$1(field)} ?? string.Empty;`);
|
|
16003
16130
|
}
|
|
16004
|
-
const pathExpr = buildPathExpr
|
|
16131
|
+
const pathExpr = buildPathExpr(op);
|
|
16005
16132
|
const needsInlineRequest = isUrlBuilder || hasBearerOverride && !!bearerParamName || hasGroups;
|
|
16006
16133
|
const optionsArg = optionsClass ? "options" : "null";
|
|
16007
16134
|
if (needsInlineRequest) {
|
|
@@ -16065,7 +16192,7 @@ function generateAutoPagingMethod(mountName, method, methodStem, op, plan, ctx,
|
|
|
16065
16192
|
params.push("CancellationToken cancellationToken = default");
|
|
16066
16193
|
lines.push(` public virtual IAsyncEnumerable<${itemType}> ${methodStem}AutoPagingAsync(${params.join(", ")})`);
|
|
16067
16194
|
lines.push(" {");
|
|
16068
|
-
const pathExpr = buildPathExpr
|
|
16195
|
+
const pathExpr = buildPathExpr(op);
|
|
16069
16196
|
const optionsArg = optionsClass ? "options" : "null";
|
|
16070
16197
|
lines.push(` return this.ListAutoPagingAsync<${itemType}>(${pathExpr}, ${optionsArg}, requestOptions, cancellationToken);`);
|
|
16071
16198
|
lines.push(" }");
|
|
@@ -16089,7 +16216,7 @@ function optionsClassName(mountName, method) {
|
|
|
16089
16216
|
if (methodStem.startsWith(prefix)) return `${methodStem}Options`;
|
|
16090
16217
|
return `${prefix}${methodStem}Options`;
|
|
16091
16218
|
}
|
|
16092
|
-
function buildPathExpr
|
|
16219
|
+
function buildPathExpr(op) {
|
|
16093
16220
|
if (op.pathParams.length === 0) return `"${op.path}"`;
|
|
16094
16221
|
let interpolated = op.path;
|
|
16095
16222
|
for (const p of sortPathParamsByTemplateOrder$1(op)) interpolated = interpolated.replace(`{${p.name}}`, `{Uri.EscapeDataString(${localName(p.name)})}`);
|
|
@@ -17868,6 +17995,45 @@ function structuralHash(model) {
|
|
|
17868
17995
|
return model.fields.map((f) => `${f.name}:${JSON.stringify(normalizeTypeForHash(f.type))}:${f.required}`).sort().join("|");
|
|
17869
17996
|
}
|
|
17870
17997
|
//#endregion
|
|
17998
|
+
//#region src/kotlin/path-expression.ts
|
|
17999
|
+
/**
|
|
18000
|
+
* The fully-qualified runtime helper that the generated code calls. Kotlin
|
|
18001
|
+
* doesn't ship a path-segment URL encoder out of the box (java.net.URLEncoder
|
|
18002
|
+
* is form-encoding — it encodes space as "+", which is wrong for path
|
|
18003
|
+
* segments). The runtime helper lives in workos-kotlin at
|
|
18004
|
+
* com.workos.common.http.encodePathSegment.
|
|
18005
|
+
*/
|
|
18006
|
+
const KOTLIN_PATH_ENCODE_IMPORT = "com.workos.common.http.encodePathSegment";
|
|
18007
|
+
/**
|
|
18008
|
+
* Build the Kotlin string-template that the SDK passes as the request path.
|
|
18009
|
+
*
|
|
18010
|
+
* Every {paramName} placeholder is wrapped in `encodePathSegment(...)` so a
|
|
18011
|
+
* caller-supplied id containing "../" cannot be normalized by the underlying
|
|
18012
|
+
* HTTP transport into a different endpoint of the WorkOS API while still
|
|
18013
|
+
* authenticated with the application's API key.
|
|
18014
|
+
*
|
|
18015
|
+
* "/orgs" → `"orgs"`
|
|
18016
|
+
* "/orgs/{id}" → `"orgs/${encodePathSegment(id)}"`
|
|
18017
|
+
* "/orgs/{id}/foo" → `"orgs/${encodePathSegment(id)}/foo"`
|
|
18018
|
+
*/
|
|
18019
|
+
function buildKotlinPathExpression(rawPath) {
|
|
18020
|
+
const segments = parsePathTemplate(rawPath);
|
|
18021
|
+
if (!hasPathParams(segments)) return {
|
|
18022
|
+
expression: ktLiteral(rawPath),
|
|
18023
|
+
requiresEncodeImport: false
|
|
18024
|
+
};
|
|
18025
|
+
let body = "";
|
|
18026
|
+
for (const seg of segments) if (seg.kind === "literal") body += escapeKotlinStringLiteral(seg.value);
|
|
18027
|
+
else body += `\${encodePathSegment(${propertyName(seg.name)})}`;
|
|
18028
|
+
return {
|
|
18029
|
+
expression: `"${body}"`,
|
|
18030
|
+
requiresEncodeImport: true
|
|
18031
|
+
};
|
|
18032
|
+
}
|
|
18033
|
+
function escapeKotlinStringLiteral(literal) {
|
|
18034
|
+
return literal.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\$/g, "\\$");
|
|
18035
|
+
}
|
|
18036
|
+
//#endregion
|
|
17871
18037
|
//#region src/kotlin/wrappers.ts
|
|
17872
18038
|
/**
|
|
17873
18039
|
* Emit Kotlin wrapper methods for a union-split operation. Each wrapper
|
|
@@ -17953,7 +18119,7 @@ function emitWrapperMethod$1(resolvedOp, wrapper, ctx) {
|
|
|
17953
18119
|
}
|
|
17954
18120
|
lines.push(` )`);
|
|
17955
18121
|
} else lines.push(` val body = linkedMapOf<String, Any?>()`);
|
|
17956
|
-
const pathExpr =
|
|
18122
|
+
const pathExpr = buildKotlinPathExpression(op.path).expression;
|
|
17957
18123
|
const httpMethod = op.httpMethod.toUpperCase();
|
|
17958
18124
|
lines.push(` val config =`);
|
|
17959
18125
|
lines.push(` RequestConfig(`);
|
|
@@ -17971,17 +18137,6 @@ function emitWrapperMethod$1(resolvedOp, wrapper, ctx) {
|
|
|
17971
18137
|
function escapeKdoc$1(s) {
|
|
17972
18138
|
return s.replace(/\*\//g, "*/");
|
|
17973
18139
|
}
|
|
17974
|
-
function buildPathExpr(path, pathParams) {
|
|
17975
|
-
if (pathParams.length === 0) return ktLiteral(path);
|
|
17976
|
-
let result = path;
|
|
17977
|
-
for (const pp of pathParams) {
|
|
17978
|
-
const placeholder = `{${pp.name}}`;
|
|
17979
|
-
const propName = propertyName(pp.name);
|
|
17980
|
-
const replacement = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(propName) ? `\$${propName}` : `\${${propName}}`;
|
|
17981
|
-
result = result.replaceAll(placeholder, replacement);
|
|
17982
|
-
}
|
|
17983
|
-
return `"${result.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
17984
|
-
}
|
|
17985
18140
|
//#endregion
|
|
17986
18141
|
//#region src/kotlin/overrides.ts
|
|
17987
18142
|
/**
|
|
@@ -18054,6 +18209,7 @@ function generateApiClass(mountName, operations, ctx, resolvedLookup) {
|
|
|
18054
18209
|
for (const rp of resolvedParams) if (rp.field) registerTypeImports(rp.field.type, imports, ctx);
|
|
18055
18210
|
}
|
|
18056
18211
|
imports.add("com.workos.common.http.bodyOf");
|
|
18212
|
+
if (/\{[^{}]+\}/.test(resolvedOp.operation.path)) imports.add(KOTLIN_PATH_ENCODE_IMPORT);
|
|
18057
18213
|
const wrapperLines = generateWrapperMethods$1(resolvedOp, ctx);
|
|
18058
18214
|
if (body.length > 0) body.push("");
|
|
18059
18215
|
for (const line of wrapperLines) body.push(line);
|
|
@@ -18216,7 +18372,9 @@ function renderMethod(_mountName, method, op, ctx, resolvedOp, imports) {
|
|
|
18216
18372
|
const specDeclaresBody = op.requestBody !== void 0;
|
|
18217
18373
|
const hasBody = methodAlwaysHasBody || specDeclaresBody && httpMethod !== "GET" || (httpMethod === "PUT" || httpMethod === "PATCH" || httpMethod === "POST" || httpMethod === "DELETE") && (Object.keys(defaults).length > 0 || inferFromClient.length > 0) && specDeclaresBody;
|
|
18218
18374
|
const appendDefaultsAsQuery = !hasBody && (Object.keys(defaults).length > 0 || inferFromClient.length > 0);
|
|
18219
|
-
const
|
|
18375
|
+
const pathBuilt = buildKotlinPathExpression(op.path);
|
|
18376
|
+
const pathExpr = pathBuilt.expression;
|
|
18377
|
+
if (pathBuilt.requiresEncodeImport) imports.add(KOTLIN_PATH_ENCODE_IMPORT);
|
|
18220
18378
|
if (op.path === "/user_management/authenticate" && httpMethod === "POST" && plan.responseModelName === "AuthenticateResponse") {
|
|
18221
18379
|
imports.add("com.workos.models.AuthenticateResponse");
|
|
18222
18380
|
const grantType = defaults.grant_type ?? "authorization_code";
|
|
@@ -18439,20 +18597,6 @@ function queryParamToString(type, varName) {
|
|
|
18439
18597
|
if (type.kind === "primitive" && type.type === "string") return varName;
|
|
18440
18598
|
return `${varName}.toString()`;
|
|
18441
18599
|
}
|
|
18442
|
-
function buildPathExpression(path, pathParams) {
|
|
18443
|
-
if (pathParams.length === 0) return ktLiteral(path);
|
|
18444
|
-
let result = path;
|
|
18445
|
-
for (const pp of pathParams) {
|
|
18446
|
-
const placeholder = `{${pp.name}}`;
|
|
18447
|
-
const propName = propertyName(pp.name);
|
|
18448
|
-
const replacement = isBareIdentifier(propName) ? `\$${propName}` : `\${${propName}}`;
|
|
18449
|
-
result = result.replaceAll(placeholder, replacement);
|
|
18450
|
-
}
|
|
18451
|
-
return `"${result.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
18452
|
-
}
|
|
18453
|
-
function isBareIdentifier(name) {
|
|
18454
|
-
return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name);
|
|
18455
|
-
}
|
|
18456
18600
|
function pickNamedQueryParam(sorted, name) {
|
|
18457
18601
|
const match = sorted.find((p) => p.name === name);
|
|
18458
18602
|
return match ? propertyName(match.name) : "null";
|
|
@@ -22009,4 +22153,4 @@ const workosEmittersPlugin = {
|
|
|
22009
22153
|
//#endregion
|
|
22010
22154
|
export { nodeEmitter as _, rustExtractor as a, pythonExtractor as c, rubyEmitter as d, kotlinEmitter as f, pythonEmitter as g, phpEmitter as h, kotlinExtractor as i, rubyExtractor as l, goEmitter as m, elixirExtractor as n, goExtractor as o, dotnetEmitter as p, dotnetExtractor as r, phpExtractor as s, workosEmittersPlugin as t, nodeExtractor as u };
|
|
22011
22155
|
|
|
22012
|
-
//# sourceMappingURL=plugin-
|
|
22156
|
+
//# sourceMappingURL=plugin-BoTAX4nl.mjs.map
|