@apollo-deploy/tesseract 1.9.0 → 2.0.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.
Files changed (194) hide show
  1. package/README.md +218 -110
  2. package/dist/adapters/csharp/index.d.ts +5 -8
  3. package/dist/adapters/csharp/index.d.ts.map +1 -1
  4. package/dist/adapters/csharp/index.js +314 -74
  5. package/dist/adapters/csharp/index.js.map +1 -1
  6. package/dist/adapters/documentation.d.ts +17 -0
  7. package/dist/adapters/documentation.d.ts.map +1 -0
  8. package/dist/adapters/documentation.js +268 -0
  9. package/dist/adapters/documentation.js.map +1 -0
  10. package/dist/adapters/go/index.d.ts +5 -8
  11. package/dist/adapters/go/index.d.ts.map +1 -1
  12. package/dist/adapters/go/index.js +197 -101
  13. package/dist/adapters/go/index.js.map +1 -1
  14. package/dist/adapters/kotlin/index.d.ts +5 -9
  15. package/dist/adapters/kotlin/index.d.ts.map +1 -1
  16. package/dist/adapters/kotlin/index.js +280 -212
  17. package/dist/adapters/kotlin/index.js.map +1 -1
  18. package/dist/adapters/php/index.d.ts +5 -15
  19. package/dist/adapters/php/index.d.ts.map +1 -1
  20. package/dist/adapters/php/index.js +362 -90
  21. package/dist/adapters/php/index.js.map +1 -1
  22. package/dist/adapters/python/index.d.ts +5 -8
  23. package/dist/adapters/python/index.d.ts.map +1 -1
  24. package/dist/adapters/python/index.js +240 -109
  25. package/dist/adapters/python/index.js.map +1 -1
  26. package/dist/adapters/ruby/index.d.ts +3 -3
  27. package/dist/adapters/ruby/index.d.ts.map +1 -1
  28. package/dist/adapters/ruby/index.js +235 -46
  29. package/dist/adapters/ruby/index.js.map +1 -1
  30. package/dist/adapters/rust/index.d.ts +5 -9
  31. package/dist/adapters/rust/index.d.ts.map +1 -1
  32. package/dist/adapters/rust/index.js +237 -169
  33. package/dist/adapters/rust/index.js.map +1 -1
  34. package/dist/adapters/shared.d.ts +7 -0
  35. package/dist/adapters/shared.d.ts.map +1 -0
  36. package/dist/adapters/shared.js +68 -0
  37. package/dist/adapters/shared.js.map +1 -0
  38. package/dist/adapters/type-utils.d.ts +13 -0
  39. package/dist/adapters/type-utils.d.ts.map +1 -0
  40. package/dist/adapters/type-utils.js +105 -0
  41. package/dist/adapters/type-utils.js.map +1 -0
  42. package/dist/adapters/types.d.ts.map +1 -1
  43. package/dist/adapters/typescript/emitter/emitSchema.d.ts +2 -2
  44. package/dist/adapters/typescript/emitter/emitSchema.js +39 -27
  45. package/dist/adapters/typescript/emitter/emitSchema.js.map +1 -1
  46. package/dist/adapters/typescript/emitter/emitTypeScriptModels.d.ts +2 -2
  47. package/dist/adapters/typescript/emitter/emitTypeScriptModels.js +15 -15
  48. package/dist/adapters/typescript/emitter/importCollector.d.ts +2 -4
  49. package/dist/adapters/typescript/emitter/importCollector.d.ts.map +1 -1
  50. package/dist/adapters/typescript/emitter/importCollector.js +40 -50
  51. package/dist/adapters/typescript/emitter/importCollector.js.map +1 -1
  52. package/dist/adapters/typescript/emitter/parsers.d.ts +1 -1
  53. package/dist/adapters/typescript/emitter/parsers.js +13 -13
  54. package/dist/adapters/typescript/emitter/typeHoister.d.ts +1 -1
  55. package/dist/adapters/typescript/emitter/typeHoister.d.ts.map +1 -1
  56. package/dist/adapters/typescript/emitter/typeHoister.js +12 -20
  57. package/dist/adapters/typescript/emitter/typeHoister.js.map +1 -1
  58. package/dist/adapters/typescript/index.d.ts +3 -3
  59. package/dist/adapters/typescript/index.d.ts.map +1 -1
  60. package/dist/adapters/typescript/index.js +148 -166
  61. package/dist/adapters/typescript/index.js.map +1 -1
  62. package/dist/adapters/typescript/shared.d.ts +2 -2
  63. package/dist/adapters/typescript/shared.js +12 -12
  64. package/dist/cli.js +50 -37
  65. package/dist/cli.js.map +1 -1
  66. package/dist/collector.d.ts +13 -3
  67. package/dist/collector.d.ts.map +1 -1
  68. package/dist/collector.js +69 -32
  69. package/dist/collector.js.map +1 -1
  70. package/dist/elysia.js +2 -2
  71. package/dist/elysia.js.map +1 -1
  72. package/dist/express.d.ts.map +1 -1
  73. package/dist/express.js.map +1 -1
  74. package/dist/fastify.d.ts +7 -0
  75. package/dist/fastify.d.ts.map +1 -1
  76. package/dist/fastify.js +39 -20
  77. package/dist/fastify.js.map +1 -1
  78. package/dist/helpers/handlebars.d.ts +7 -16
  79. package/dist/helpers/handlebars.d.ts.map +1 -1
  80. package/dist/helpers/handlebars.js +127 -177
  81. package/dist/helpers/handlebars.js.map +1 -1
  82. package/dist/hono.d.ts.map +1 -1
  83. package/dist/hono.js.map +1 -1
  84. package/dist/index.d.ts +14 -12
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +32 -30
  87. package/dist/index.js.map +1 -1
  88. package/dist/koa.d.ts.map +1 -1
  89. package/dist/koa.js.map +1 -1
  90. package/dist/nestjs.d.ts.map +1 -1
  91. package/dist/nestjs.js +41 -14
  92. package/dist/nestjs.js.map +1 -1
  93. package/dist/pipeline/enrich.d.ts +2 -13
  94. package/dist/pipeline/enrich.d.ts.map +1 -1
  95. package/dist/pipeline/enrich.js +157 -212
  96. package/dist/pipeline/enrich.js.map +1 -1
  97. package/dist/pipeline/intake.d.ts +3 -3
  98. package/dist/pipeline/intake.d.ts.map +1 -1
  99. package/dist/pipeline/intake.js +342 -238
  100. package/dist/pipeline/intake.js.map +1 -1
  101. package/dist/pipeline/write.d.ts +1 -14
  102. package/dist/pipeline/write.d.ts.map +1 -1
  103. package/dist/pipeline/write.js +73 -113
  104. package/dist/pipeline/write.js.map +1 -1
  105. package/dist/types/config.d.ts +14 -26
  106. package/dist/types/config.d.ts.map +1 -1
  107. package/dist/types/config.js +16 -12
  108. package/dist/types/config.js.map +1 -1
  109. package/dist/types/ir.d.ts +12 -8
  110. package/dist/types/ir.d.ts.map +1 -1
  111. package/dist/types/manifest.d.ts +10 -11
  112. package/dist/types/manifest.d.ts.map +1 -1
  113. package/dist/types/manifest.js +54 -14
  114. package/dist/types/manifest.js.map +1 -1
  115. package/dist/types/sdk-module.d.ts +2 -2
  116. package/dist/types/sdk-module.js +1 -1
  117. package/dist/utils/format.d.ts +1 -3
  118. package/dist/utils/format.d.ts.map +1 -1
  119. package/dist/utils/format.js +3 -10
  120. package/dist/utils/format.js.map +1 -1
  121. package/dist/utils/naming.d.ts.map +1 -1
  122. package/dist/utils/naming.js +174 -184
  123. package/dist/utils/naming.js.map +1 -1
  124. package/dist/utils/npm-token.d.ts +1 -17
  125. package/dist/utils/npm-token.d.ts.map +1 -1
  126. package/dist/utils/npm-token.js +27 -76
  127. package/dist/utils/npm-token.js.map +1 -1
  128. package/dist/utils/version.d.ts +14 -0
  129. package/dist/utils/version.d.ts.map +1 -0
  130. package/dist/utils/version.js +60 -0
  131. package/dist/utils/version.js.map +1 -0
  132. package/package.json +4 -3
  133. package/templates/csharp/client.hbs +26 -49
  134. package/templates/csharp/csproj.hbs +7 -0
  135. package/templates/csharp/domain.hbs +48 -130
  136. package/templates/csharp/errors.hbs +17 -25
  137. package/templates/csharp/readme.hbs +31 -44
  138. package/templates/csharp/transport.hbs +238 -136
  139. package/templates/csharp/types.hbs +30 -76
  140. package/templates/go/client.hbs +44 -109
  141. package/templates/go/domain.hbs +83 -25
  142. package/templates/go/go-mod.hbs +1 -4
  143. package/templates/go/readme.hbs +32 -29
  144. package/templates/go/transport.hbs +174 -173
  145. package/templates/go/types.hbs +17 -53
  146. package/templates/go/utils.hbs +3 -2
  147. package/templates/kotlin/build-gradle.hbs +1 -1
  148. package/templates/kotlin/client.hbs +18 -15
  149. package/templates/kotlin/domain.hbs +54 -51
  150. package/templates/kotlin/errors.hbs +1 -1
  151. package/templates/kotlin/readme.hbs +35 -137
  152. package/templates/kotlin/transport.hbs +140 -123
  153. package/templates/kotlin/types.hbs +30 -81
  154. package/templates/php/client.hbs +8 -46
  155. package/templates/php/composer.hbs +2 -1
  156. package/templates/php/domain.hbs +86 -117
  157. package/templates/php/errors.hbs +1 -1
  158. package/templates/php/readme.hbs +42 -49
  159. package/templates/php/transport.hbs +192 -145
  160. package/templates/php/types.hbs +63 -60
  161. package/templates/python/client.hbs +15 -2
  162. package/templates/python/domain.hbs +50 -108
  163. package/templates/python/pyproject.hbs +5 -0
  164. package/templates/python/readme.hbs +47 -30
  165. package/templates/python/resources-init.hbs +1 -1
  166. package/templates/python/transport.hbs +167 -53
  167. package/templates/python/types.hbs +22 -58
  168. package/templates/ruby/client.hbs +10 -6
  169. package/templates/ruby/domain.hbs +48 -67
  170. package/templates/ruby/errors.hbs +3 -3
  171. package/templates/ruby/gemspec.hbs +3 -10
  172. package/templates/ruby/index.hbs +3 -3
  173. package/templates/ruby/readme.hbs +33 -70
  174. package/templates/ruby/transport.hbs +129 -103
  175. package/templates/ruby/types.hbs +11 -16
  176. package/templates/ruby/version.hbs +1 -1
  177. package/templates/rust/cargo.hbs +2 -0
  178. package/templates/rust/client.hbs +10 -1
  179. package/templates/rust/domain.hbs +69 -52
  180. package/templates/rust/error.hbs +3 -1
  181. package/templates/rust/lib.hbs +4 -5
  182. package/templates/rust/readme.hbs +33 -46
  183. package/templates/rust/transport.hbs +170 -159
  184. package/templates/rust/types.hbs +34 -111
  185. package/templates/typescript/domain-class.hbs +14 -6
  186. package/templates/typescript/domain.hbs +13 -5
  187. package/templates/typescript/package-json.hbs +3 -1
  188. package/templates/typescript/readme.hbs +42 -42
  189. package/templates/typescript/transport.hbs +46 -8
  190. package/templates/typescript/types-errors.hbs +1 -1
  191. package/dist/adapters/typescript/model-emitter.d.ts +0 -13
  192. package/dist/adapters/typescript/model-emitter.d.ts.map +0 -1
  193. package/dist/adapters/typescript/model-emitter.js +0 -415
  194. package/dist/adapters/typescript/model-emitter.js.map +0 -1
@@ -1,90 +1,41 @@
1
- /**
2
- * Resolves a private npm registry auth token from multiple sources.
3
- *
4
- * Works across npm, yarn, pnpm, and bun — all respect .npmrc files.
5
- */
6
- import { execSync } from "node:child_process";
7
- import { readFileSync } from "node:fs";
8
- import { homedir } from "node:os";
9
- import { join } from "node:path";
10
- const REGISTRY_HOST = "//registry.npmjs.org/";
11
- const AUTH_TOKEN_KEY = `${REGISTRY_HOST}:_authToken`;
12
- /**
13
- * Resolves the npm auth token for registry.npmjs.org.
14
- *
15
- * Tries sources in order:
16
- * 1. Explicit token (passed by user)
17
- * 2. NPM_TOKEN environment variable
18
- * 3. `npm config get` (works with npm installed alongside any runtime)
19
- * 4. User-level ~/.npmrc (parsed directly — works for npm, yarn, pnpm, bun)
20
- * 5. Project-local .npmrc
21
- *
22
- * Returns undefined if no token is found (caller falls back gracefully).
23
- */
1
+ /** Resolves the npm registry token without spawning a package-manager process. */
2
+ import { readFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ const AUTH_TOKEN_KEY = '//registry.npmjs.org/:_authToken';
6
+ const ENV_REFERENCE = /\$\{([^}]+)\}/g;
24
7
  export function resolveNpmToken(explicitToken) {
25
- // 1. Explicit token passed by user
26
8
  if (explicitToken)
27
9
  return explicitToken;
28
- // 2. Environment variable (most common in CI/CD)
29
- const envToken = process.env.NPM_TOKEN;
10
+ const envToken = process.env.NPM_TOKEN ?? process.env.NODE_AUTH_TOKEN;
30
11
  if (envToken)
31
12
  return envToken;
32
- // 3. npm config get — authoritative source for npm-based setups.
33
- // Uses execSync so it works synchronously in config resolution.
34
- try {
35
- const token = execSync(`npm config get ${JSON.stringify(AUTH_TOKEN_KEY)}`, {
36
- encoding: "utf-8",
37
- timeout: 3000,
38
- stdio: ["ignore", "pipe", "ignore"],
39
- }).trim();
40
- // npm config get returns the literal string "undefined" when unset
41
- if (token && token !== "undefined")
42
- return token;
43
- }
44
- catch {
45
- // npm not available, timed out, or failed — fall through
46
- }
47
- // 4. Parse ~/.npmrc directly (universal — all package managers respect this)
48
- try {
49
- const token = parseNpmrcForToken(join(homedir(), ".npmrc"));
50
- if (token)
51
- return token;
52
- }
53
- catch {
54
- // file doesn't exist or can't be read
55
- }
56
- // 5. Project-local .npmrc
13
+ return readToken('.npmrc') ?? readToken(join(homedir(), '.npmrc'));
14
+ }
15
+ function readToken(filePath) {
16
+ let contents;
57
17
  try {
58
- const token = parseNpmrcForToken(".npmrc");
59
- if (token)
60
- return token;
18
+ contents = readFileSync(filePath, 'utf8');
61
19
  }
62
20
  catch {
63
- // no local .npmrc
21
+ return undefined;
64
22
  }
65
- return undefined;
66
- }
67
- /**
68
- * Parses an .npmrc-style file for the auth token of registry.npmjs.org.
69
- *
70
- * Supported formats:
71
- * //registry.npmjs.org/:_authToken=npm_abc123
72
- * //registry.npmjs.org/:_authToken = npm_abc123
73
- */
74
- function parseNpmrcForToken(filePath) {
75
- const contents = readFileSync(filePath, "utf-8");
76
- for (const line of contents.split("\n")) {
77
- const trimmed = line.trim();
78
- if (!trimmed || trimmed.startsWith("#"))
23
+ for (const line of contents.split(/\r?\n/)) {
24
+ const separator = line.indexOf('=');
25
+ if (separator < 0)
79
26
  continue;
80
- const eqIdx = trimmed.indexOf("=");
81
- if (eqIdx === -1)
27
+ const key = line.slice(0, separator).trim();
28
+ if (key !== AUTH_TOKEN_KEY)
82
29
  continue;
83
- const key = trimmed.slice(0, eqIdx).trim();
84
- const value = trimmed.slice(eqIdx + 1).trim();
85
- if (key === AUTH_TOKEN_KEY && value) {
86
- return value;
87
- }
30
+ const rawValue = line.slice(separator + 1).trim();
31
+ if (!rawValue)
32
+ return undefined;
33
+ const value = rawValue.length >= 2 &&
34
+ rawValue[0] === rawValue.at(-1) &&
35
+ ['"', "'"].includes(rawValue[0])
36
+ ? rawValue.slice(1, -1)
37
+ : rawValue;
38
+ return value.replace(ENV_REFERENCE, (_, name) => process.env[name] ?? '');
88
39
  }
89
40
  return undefined;
90
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"npm-token.js","sourceRoot":"","sources":["../../src/utils/npm-token.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAC9C,MAAM,cAAc,GAAG,GAAG,aAAa,aAAa,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,aAAsB;IACpD,mCAAmC;IACnC,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IAExC,iDAAiD;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;IACvC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,iEAAiE;IACjE,mEAAmE;IACnE,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,EAAE;YACzE,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,mEAAmE;QACnE,IAAI,KAAK,IAAI,KAAK,KAAK,WAAW;YAAE,OAAO,KAAK,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;IAC3D,CAAC;IAED,6EAA6E;IAC7E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC5D,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,sCAAsC;IACxC,CAAC;IAED,0BAA0B;IAC1B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAEjD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAElD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,SAAS;QAE3B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE9C,IAAI,GAAG,KAAK,cAAc,IAAI,KAAK,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"npm-token.js","sourceRoot":"","sources":["../../src/utils/npm-token.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,cAAc,GAAG,kCAAkC,CAAC;AAC1D,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAEvC,MAAM,UAAU,eAAe,CAAC,aAAsB;IACpD,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IAExC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACtE,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,OAAO,SAAS,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,SAAS,CAAC,QAAgB;IACjC,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,SAAS,GAAG,CAAC;YAAE,SAAS;QAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,GAAG,KAAK,cAAc;YAAE,SAAS;QAErC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAClD,IAAI,CAAC,QAAQ;YAAE,OAAO,SAAS,CAAC;QAEhC,MAAM,KAAK,GACT,QAAQ,CAAC,MAAM,IAAI,CAAC;YACpB,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC9B,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACvB,CAAC,CAAC,QAAQ,CAAC;QACf,OAAO,KAAK,CAAC,OAAO,CAClB,aAAa,EACb,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAC7C,CAAC;IACJ,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { VersionBump } from '../types/ir.js';
2
+ /**
3
+ * Converts an existing numeric version to Tesseract's decimal-carry format.
4
+ * Patch and minor components remain in the 0-9 range.
5
+ */
6
+ export declare function normalizeVersion(version: string): string;
7
+ export declare function bumpVersion(version: string, bump?: VersionBump): string;
8
+ export interface ResolvePackageVersionOptions {
9
+ currentVersion: string;
10
+ packageVersion?: string;
11
+ bump?: VersionBump;
12
+ }
13
+ export declare function resolvePackageVersion({ currentVersion, packageVersion, bump, }: ResolvePackageVersionOptions): string;
14
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/utils/version.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAiBlD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASxD;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,WAAqB,GAC1B,MAAM,CA4BR;AAED,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,cAAc,EACd,cAAc,EACd,IAAI,GACL,EAAE,4BAA4B,GAAG,MAAM,CAQvC"}
@@ -0,0 +1,60 @@
1
+ const VERSION_PATTERN = /^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
2
+ function parseVersion(version) {
3
+ const value = version.trim();
4
+ const match = VERSION_PATTERN.exec(value);
5
+ if (!match)
6
+ throw new Error(`Invalid version: "${version}"`);
7
+ const parts = match.slice(1, 4).map(Number);
8
+ if (parts.some((part) => !Number.isSafeInteger(part))) {
9
+ throw new Error(`Invalid version: "${version}"`);
10
+ }
11
+ return parts;
12
+ }
13
+ /**
14
+ * Converts an existing numeric version to Tesseract's decimal-carry format.
15
+ * Patch and minor components remain in the 0-9 range.
16
+ */
17
+ export function normalizeVersion(version) {
18
+ let [major, minor, patch] = parseVersion(version);
19
+ minor += Math.floor(patch / 10);
20
+ patch %= 10;
21
+ major += Math.floor(minor / 10);
22
+ minor %= 10;
23
+ return `${major}.${minor}.${patch}`;
24
+ }
25
+ export function bumpVersion(version, bump = 'patch') {
26
+ let [major, minor, patch] = normalizeVersion(version).split('.').map(Number);
27
+ switch (bump) {
28
+ case 'major':
29
+ major += 1;
30
+ minor = 0;
31
+ patch = 0;
32
+ break;
33
+ case 'minor':
34
+ minor += 1;
35
+ patch = 0;
36
+ break;
37
+ case 'patch':
38
+ patch += 1;
39
+ break;
40
+ }
41
+ if (patch >= 10) {
42
+ minor += Math.floor(patch / 10);
43
+ patch %= 10;
44
+ }
45
+ if (minor >= 10) {
46
+ major += Math.floor(minor / 10);
47
+ minor %= 10;
48
+ }
49
+ return `${major}.${minor}.${patch}`;
50
+ }
51
+ export function resolvePackageVersion({ currentVersion, packageVersion, bump, }) {
52
+ if (packageVersion) {
53
+ parseVersion(packageVersion);
54
+ return packageVersion.trim();
55
+ }
56
+ return bump
57
+ ? bumpVersion(currentVersion, bump)
58
+ : normalizeVersion(currentVersion);
59
+ }
60
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/utils/version.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GACnB,gEAAgE,CAAC;AAEnE,SAAS,YAAY,CAAC,OAAe;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,OAAO,GAAG,CAAC,CAAC;IAE7D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAA6B,CAAC;IACxE,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,qBAAqB,OAAO,GAAG,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAElD,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IAChC,KAAK,IAAI,EAAE,CAAC;IACZ,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IAChC,KAAK,IAAI,EAAE,CAAC;IAEZ,OAAO,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,OAAe,EACf,OAAoB,OAAO;IAE3B,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE7E,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO;YACV,KAAK,IAAI,CAAC,CAAC;YACX,KAAK,GAAG,CAAC,CAAC;YACV,KAAK,GAAG,CAAC,CAAC;YACV,MAAM;QACR,KAAK,OAAO;YACV,KAAK,IAAI,CAAC,CAAC;YACX,KAAK,GAAG,CAAC,CAAC;YACV,MAAM;QACR,KAAK,OAAO;YACV,KAAK,IAAI,CAAC,CAAC;YACX,MAAM;IACV,CAAC;IAED,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;QAChB,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;QAChC,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IACD,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;QAChB,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;QAChC,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,OAAO,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;AACtC,CAAC;AAQD,MAAM,UAAU,qBAAqB,CAAC,EACpC,cAAc,EACd,cAAc,EACd,IAAI,GACyB;IAC7B,IAAI,cAAc,EAAE,CAAC;QACnB,YAAY,CAAC,cAAc,CAAC,CAAC;QAC7B,OAAO,cAAc,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,IAAI;QACT,CAAC,CAAC,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC;QACnC,CAAC,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;AACvC,CAAC"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@apollo-deploy/tesseract",
3
- "version": "1.9.0",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
- "description": "Manifest-first SDK generator turns sdk-manifold/v1 manifests into production-ready TypeScript SDKs",
5
+ "description": "Manifest-first SDK generator for TypeScript, Python, Ruby, PHP, Go, Rust, Kotlin, and C#",
6
6
  "bin": {
7
7
  "tesseract": "./dist/cli.js"
8
8
  },
@@ -59,7 +59,8 @@
59
59
  "scripts": {
60
60
  "build": "tsc",
61
61
  "dev": "bun src/cli.ts",
62
- "prepublishOnly": "bun run build"
62
+ "prepublishOnly": "npm test",
63
+ "test": "npm run build && node --test test/*.test.mjs"
63
64
  },
64
65
  "dependencies": {
65
66
  "change-case": "^5.4.4",
@@ -2,94 +2,71 @@ namespace {{namespace}};
2
2
 
3
3
  using System;
4
4
  using System.Collections.Generic;
5
+ using System.Net.Http;
5
6
  using {{namespace}}.Api;
6
7
 
7
- /// <summary>
8
- /// Configuration for the {{clientName}} API client.
9
- /// </summary>
10
- public class {{clientName}}ClientConfig
8
+ /// <summary>Configuration for the {{clientName}} API client.</summary>
9
+ public sealed class {{clientName}}ClientConfig
11
10
  {
12
- /// <summary>
13
- /// Base URL for all API requests.
14
- /// </summary>
15
11
  public string BaseUrl { get; set; } = "{{baseUrl}}";
16
12
  {{#each securitySchemes}}
17
13
  {{#if (eq type "apiKey")}}
18
- /// <summary>
19
- /// API key for the {{name}} security scheme.
20
- /// </summary>
14
+ /// <summary>API key for the {{name}} security scheme.</summary>
21
15
  public string? {{pascalCase configKey}} { get; set; }
22
16
  {{/if}}
23
17
  {{#if (and (eq type "http") (eq scheme "bearer"))}}
24
- /// <summary>
25
- /// Bearer token for the {{name}} security scheme.
26
- /// </summary>
18
+ /// <summary>Bearer token for the {{name}} security scheme.</summary>
27
19
  public string? {{pascalCase configKey}} { get; set; }
28
20
  {{/if}}
29
21
  {{#if (eq type "oauth2")}}
30
- /// <summary>
31
- /// OAuth2 access token for the {{name}} security scheme.
32
- /// </summary>
22
+ /// <summary>OAuth2 access token for the {{name}} security scheme.</summary>
33
23
  public string? {{pascalCase configKey}} { get; set; }
34
24
  {{/if}}
35
25
  {{#if (eq type "openIdConnect")}}
36
- /// <summary>
37
- /// OpenID Connect token for the {{name}} security scheme.
38
- /// </summary>
26
+ /// <summary>OpenID Connect token for the {{name}} security scheme.</summary>
39
27
  public string? {{pascalCase configKey}} { get; set; }
40
28
  {{/if}}
41
29
  {{/each}}
42
- /// <summary>
43
- /// Request timeout in milliseconds.
44
- /// </summary>
45
30
  public int TimeoutMs { get; set; } = 15000;
46
-
47
- /// <summary>
48
- /// Maximum number of retry attempts for transient failures.
49
- /// </summary>
50
31
  public int MaxRetries { get; set; } = 3;
51
-
52
- /// <summary>
53
- /// Default headers sent with every request.
54
- /// </summary>
32
+ public bool RetryUnsafeRequests { get; set; }
55
33
  public Dictionary<string, string>? DefaultHeaders { get; set; }
34
+ /// <summary>Optional shared HttpClient. The SDK will not dispose an injected client.</summary>
35
+ public HttpClient? HttpClient { get; set; }
56
36
  }
57
37
 
58
- /// <summary>
59
- /// Primary API client for {{title}}.
60
- /// </summary>
61
- public class {{clientName}}Client
38
+ /// <summary>Primary API client for {{title}}.</summary>
39
+ public sealed class {{clientName}}Client : IDisposable
62
40
  {
63
41
  private readonly Transport _transport;
64
42
 
65
43
  {{#each groups}}
66
- /// <summary>
67
- /// {{#if description}}{{description}}{{else}}{{name}} operations{{/if}}
68
- /// </summary>
44
+ /// <summary>{{#if description}}{{description}}{{else}}{{name}} operations{{/if}}</summary>
69
45
  public {{interfaceName}} {{pascalCase name}} { get; }
70
46
  {{/each}}
71
47
 
72
- /// <summary>
73
- /// Creates a new {{clientName}} API client.
74
- /// </summary>
75
- /// <param name="config">Client configuration. If null, defaults are used.</param>
76
48
  public {{clientName}}Client({{clientName}}ClientConfig? config = null)
77
49
  {
78
50
  config ??= new {{clientName}}ClientConfig();
79
51
 
80
- _transport = new Transport(new TransportConfig
81
- {
82
- BaseUrl = config.BaseUrl,
52
+ _transport = new Transport(
53
+ new TransportConfig
54
+ {
55
+ BaseUrl = config.BaseUrl,
83
56
  {{#each securitySchemes}}
84
- {{pascalCase configKey}} = config.{{pascalCase configKey}},
57
+ {{pascalCase configKey}} = config.{{pascalCase configKey}},
85
58
  {{/each}}
86
- TimeoutMs = config.TimeoutMs,
87
- MaxRetries = config.MaxRetries,
88
- DefaultHeaders = config.DefaultHeaders,
89
- });
59
+ TimeoutMs = config.TimeoutMs,
60
+ MaxRetries = config.MaxRetries,
61
+ RetryUnsafeRequests = config.RetryUnsafeRequests,
62
+ DefaultHeaders = config.DefaultHeaders,
63
+ },
64
+ config.HttpClient);
90
65
 
91
66
  {{#each groups}}
92
67
  {{pascalCase name}} = new {{interfaceName}}(_transport);
93
68
  {{/each}}
94
69
  }
70
+
71
+ public void Dispose() => _transport.Dispose();
95
72
  }
@@ -9,8 +9,15 @@
9
9
  <ImplicitUsings>enable</ImplicitUsings>
10
10
  <RootNamespace>{{namespace}}</RootNamespace>
11
11
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
12
+ <PackageReadmeFile>README.md</PackageReadmeFile>
12
13
  </PropertyGroup>
13
14
 
15
+ <ItemGroup>
16
+ <None Update="README.md" Pack="true" PackagePath="\" />
17
+ <None Update="LICENSE" Pack="true" PackagePath="\" />
18
+ <None Update="docs/**/*.md" Pack="true" PackagePath="docs/%(RecursiveDir)%(Filename)%(Extension)" />
19
+ </ItemGroup>
20
+
14
21
  <ItemGroup>
15
22
  <PackageReference Include="System.Text.Json" Version="8.0.*" />
16
23
  </ItemGroup>
@@ -4,180 +4,98 @@ using System;
4
4
  using System.Collections.Generic;
5
5
  using System.IO;
6
6
  using System.Net.Http;
7
- using System.Text;
8
- using System.Text.Json;
9
7
  using System.Threading;
10
8
  using System.Threading.Tasks;
11
9
 
12
- /// <summary>
13
- /// Provides access to {{name}} API operations.
14
- /// </summary>
10
+ /// <summary>{{#if description}}{{description}}{{else}}{{interfaceName}} API operations.{{/if}}</summary>
15
11
  public class {{interfaceName}}
16
12
  {
17
13
  private readonly Transport _transport;
18
14
 
19
- /// <summary>
20
- /// Creates a new {{interfaceName}} instance.
21
- /// </summary>
22
15
  public {{interfaceName}}(Transport transport)
23
16
  {
24
17
  _transport = transport;
25
18
  }
26
19
 
27
20
  {{#each operations}}
28
- {{#if isEventStream}}
29
- /// <summary>
30
- {{#if summary}}
31
- /// {{summary}}
32
- {{/if}}
33
- {{#if description}}
34
- /// {{description}}
35
- {{/if}}
36
- {{#if deprecated}}
37
- /// [Obsolete] {{#if deprecationMessage}}{{deprecationMessage}}{{/if}}
38
- {{/if}}
39
- /// </summary>
40
21
  {{#if deprecated}}
41
- [Obsolete({{#if deprecationMessage}}"{{deprecationMessage}}"{{/if}})]
42
- {{/if}}
43
- public async IAsyncEnumerable<string> {{pascalCase name}}Async(
44
- {{#each pathParams}}
45
- {{type}}{{#if (not required)}}?{{/if}} {{name}},
46
- {{/each}}
47
- {{#if requestBody}}
48
- {{requestBody.type}}{{#if (not requestBody.required)}}?{{/if}} body,
22
+ [Obsolete{{#if deprecationMessage}}("{{deprecationMessage}}"){{/if}}]
49
23
  {{/if}}
50
- {{#if queryType}}
51
- {{queryType}}? query = null,
24
+ {{#if isEventStream}}
25
+ public async IAsyncEnumerable<string> {{methodName}}Async(
26
+ {{#if hasParameters}}
27
+ {{{signature}}},
52
28
  {{/if}}
53
- CancellationToken cancellationToken = default)
29
+ [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
54
30
  {
55
- var path = $"{{path}}"
31
+ var path = "{{path}}";
56
32
  {{#each pathParams}}
57
- .Replace("{{{originalName}}}", Uri.EscapeDataString({{name}}?.ToString() ?? ""))
33
+ path = path.Replace("{{placeholder}}", Uri.EscapeDataString({{parameterName}}.ToString() ?? ""));
58
34
  {{/each}}
59
- ;
60
-
61
- var queryParams = new Dictionary<string, string>();
62
- {{#if queryType}}
63
- if (query != null)
35
+ var queryParams = BuildQuery({{#if hasQuery}}query{{else}}null{{/if}});
36
+ Dictionary<string, string>? requestHeaders = {{#if hasHeaders}}headers == null ? null : new Dictionary<string, string>(headers){{else}}null{{/if}};
37
+ var response = await _transport.StreamAsync(new Transport.Request
64
38
  {
65
- var json = JsonSerializer.Serialize(query);
66
- var dict = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(json);
67
- if (dict != null)
68
- {
69
- foreach (var (key, value) in dict)
70
- {
71
- if (value.ValueKind != JsonValueKind.Null)
72
- queryParams[key] = value.ToString();
73
- }
74
- }
75
- }
76
- {{/if}}
77
- {{#if (hasQueryParams this)}}
78
- {{#each queryParams}}
79
- if ({{name}} != null)
80
- queryParams["{{originalName}}"] = {{name}}.ToString();
81
- {{/each}}
82
- {{/if}}
83
-
84
- var response = await _transport.StreamAsync(
85
- new Transport.Request
86
- {
87
- Method = HttpMethod.{{httpMethod}},
88
- Path = path,
89
- Query = queryParams.Count > 0 ? queryParams : null,
39
+ Method = new HttpMethod("{{httpMethod}}"),
40
+ Path = path,
41
+ Query = queryParams,
42
+ Headers = requestHeaders,
90
43
  {{#if requestBody}}
91
- Body = body,
92
- ContentType = "{{requestBody.contentType}}",
44
+ Body = body,
45
+ ContentType = "{{requestBody.contentType}}",
93
46
  {{/if}}
94
- },
95
- cancellationToken);
47
+ }, cancellationToken);
96
48
 
97
49
  using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
98
50
  using var reader = new StreamReader(stream);
99
-
100
51
  while (!reader.EndOfStream)
101
52
  {
102
53
  cancellationToken.ThrowIfCancellationRequested();
103
54
  var line = await reader.ReadLineAsync(cancellationToken);
104
- if (line == null) break;
105
-
106
- // Forward raw SSE lines
55
+ if (line is null) yield break;
107
56
  yield return line;
108
57
  }
109
58
  }
110
59
 
111
60
  {{else}}
112
- /// <summary>
113
- {{#if summary}}
114
- /// {{summary}}
115
- {{/if}}
116
- {{#if description}}
117
- /// {{description}}
118
- {{/if}}
119
- {{#if deprecated}}
120
- /// [Obsolete] {{#if deprecationMessage}}{{deprecationMessage}}{{/if}}
121
- {{/if}}
122
- /// </summary>
123
- {{#if deprecated}}
124
- [Obsolete({{#if deprecationMessage}}"{{deprecationMessage}}"{{/if}})]
125
- {{/if}}
126
- public async Task<{{#if responseType}}{{responseType}}{{else}}object{{/if}}> {{pascalCase name}}Async(
127
- {{#each pathParams}}
128
- {{type}}{{#if (not required)}}?{{/if}} {{name}},
129
- {{/each}}
130
- {{#if requestBody}}
131
- {{requestBody.type}}{{#if (not requestBody.required)}}?{{/if}} body,
132
- {{/if}}
133
- {{#if queryType}}
134
- {{queryType}}? query = null,
61
+ public async {{#if isVoid}}Task{{else}}Task<{{targetResponseType}}>{{/if}} {{methodName}}Async(
62
+ {{#if hasParameters}}
63
+ {{{signature}}},
135
64
  {{/if}}
136
65
  CancellationToken cancellationToken = default)
137
66
  {
138
- var path = $"{{path}}"
67
+ var path = "{{path}}";
139
68
  {{#each pathParams}}
140
- .Replace("{{{originalName}}}", Uri.EscapeDataString({{name}}?.ToString() ?? ""))
69
+ path = path.Replace("{{placeholder}}", Uri.EscapeDataString({{parameterName}}.ToString() ?? ""));
141
70
  {{/each}}
142
- ;
143
-
144
- var queryParams = new Dictionary<string, string>();
145
- {{#if queryType}}
146
- if (query != null)
71
+ var request = new Transport.Request
147
72
  {
148
- var json = JsonSerializer.Serialize(query);
149
- var dict = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(json);
150
- if (dict != null)
151
- {
152
- foreach (var (key, value) in dict)
153
- {
154
- if (value.ValueKind != JsonValueKind.Null)
155
- queryParams[key] = value.ToString();
156
- }
157
- }
158
- }
159
- {{/if}}
160
- {{#if (hasQueryParams this)}}
161
- {{#each queryParams}}
162
- if ({{name}} != null)
163
- queryParams["{{originalName}}"] = {{name}}.ToString();
164
- {{/each}}
165
- {{/if}}
166
-
167
- return await _transport.ExecuteAsync<{{#if responseType}}{{responseType}}{{else}}object{{/if}}>(
168
- new Transport.Request
169
- {
170
- Method = HttpMethod.{{httpMethod}},
171
- Path = path,
172
- Query = queryParams.Count > 0 ? queryParams : null,
73
+ Method = new HttpMethod("{{httpMethod}}"),
74
+ Path = path,
75
+ Query = BuildQuery({{#if hasQuery}}query{{else}}null{{/if}}),
76
+ Headers = {{#if hasHeaders}}headers == null ? null : new Dictionary<string, string>(headers){{else}}null{{/if}},
173
77
  {{#if requestBody}}
174
- Body = body,
175
- ContentType = "{{requestBody.contentType}}",
78
+ Body = body,
79
+ ContentType = "{{requestBody.contentType}}",
80
+ {{/if}}
81
+ };
82
+ {{#if isVoid}}
83
+ await _transport.ExecuteRawAsync(request, cancellationToken);
84
+ {{else}}
85
+ return await _transport.ExecuteAsync<{{targetResponseType}}>(request, cancellationToken);
176
86
  {{/if}}
177
- },
178
- cancellationToken);
179
87
  }
180
88
 
181
89
  {{/if}}
182
90
  {{/each}}
91
+ private static Dictionary<string, string>? BuildQuery(IReadOnlyDictionary<string, object?>? query)
92
+ {
93
+ if (query is null || query.Count == 0) return null;
94
+ var result = new Dictionary<string, string>();
95
+ foreach (var (key, value) in query)
96
+ {
97
+ if (value is not null) result[key] = value.ToString() ?? "";
98
+ }
99
+ return result.Count == 0 ? null : result;
100
+ }
183
101
  }