@apollo-deploy/tesseract 1.9.0 → 2.1.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 +32 -7
  67. package/dist/collector.d.ts.map +1 -1
  68. package/dist/collector.js +149 -49
  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 +9 -2
  75. package/dist/fastify.d.ts.map +1 -1
  76. package/dist/fastify.js +40 -21
  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,142 +1,65 @@
1
1
  use serde::{Deserialize, Serialize};
2
2
 
3
3
  {{#each schemas}}
4
- {{#if (and (not ownership) (not isEnum) (not isTypeAlias) (not isUnionType) (not isIntersectionType))}}
5
- {{#if (or externalImport (eq ownership.kind "external"))}}
6
- // {{name}} is imported from an external schema package.
7
- {{else}}
8
- {{#if description}}
9
- /// {{description}}
10
- {{/if}}
11
- #[derive(Debug, Clone, Serialize, Deserialize)]
12
- {{#if additionalPropertiesType}}
13
- {{! Additional properties means we need to use a flattened map }}
14
- #[serde(rename_all = "camelCase")]
15
- pub struct {{name}} {
16
- {{#each properties}}
17
- {{#if description}}
18
- /// {{description}}
19
- {{/if}}
20
- {{#if deprecated}}
21
- #[deprecated]
22
- {{/if}}
23
- {{#if (and nullable (not required))}}
24
- #[serde(skip_serializing_if = "Option::is_none")]
25
- pub {{snakeCase name}}: Option<{{{rustType type}}}>,
26
- {{else if nullable}}
27
- #[serde(skip_serializing_if = "Option::is_none")]
28
- pub {{snakeCase name}}: Option<{{{rustType type}}}>,
29
- {{else if required}}
30
- pub {{snakeCase name}}: {{{rustType type}}},
31
- {{else}}
32
- #[serde(skip_serializing_if = "Option::is_none")]
33
- pub {{snakeCase name}}: Option<{{{rustType type}}}>,
34
- {{/if}}
35
- {{/each}}
36
- }
37
- {{else}}
38
- #[serde(rename_all = "camelCase")]
39
- pub struct {{name}} {
40
- {{#each properties}}
41
- {{#if description}}
42
- /// {{description}}
43
- {{/if}}
44
- {{#if deprecated}}
45
- #[deprecated]
46
- {{/if}}
47
- {{#if (and nullable (not required))}}
48
- #[serde(skip_serializing_if = "Option::is_none")]
49
- pub {{snakeCase name}}: Option<{{{rustType type}}}>,
50
- {{else if nullable}}
51
- #[serde(skip_serializing_if = "Option::is_none")]
52
- pub {{snakeCase name}}: Option<{{{rustType type}}}>,
53
- {{else if required}}
54
- pub {{snakeCase name}}: {{{rustType type}}},
55
- {{else}}
56
- #[serde(skip_serializing_if = "Option::is_none")]
57
- pub {{snakeCase name}}: Option<{{{rustType type}}}>,
58
- {{/if}}
59
- {{/each}}
60
- }
61
- {{/if}}
62
- {{/if}}
63
- {{/if}}
4
+ {{#if external}}
5
+ /// External schema placeholder. Configure a language-specific package mapping to replace it.
6
+ pub type {{name}} = serde_json::Value;
64
7
 
65
- {{#if isEnum}}
8
+ {{else if isEnum}}
9
+ {{#if stringEnum}}
66
10
  {{#if description}}
67
11
  /// {{description}}
68
12
  {{/if}}
69
13
  #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
70
- {{#if enumValues}}
71
- #[serde(rename_all = "camelCase")]
72
- {{/if}}
73
14
  pub enum {{name}} {
74
- {{#each enumValues}}
75
- #[serde(rename = "{{this}}")]
76
- {{pascalCase this}},
77
- {{/each}}
15
+ {{#each enumValues}}
16
+ #[serde(rename = "{{value}}")] {{name}},
17
+ {{/each}}
78
18
  }
19
+ {{else}}
20
+ pub type {{name}} = f64;
79
21
  {{/if}}
80
22
 
81
- {{#if isTypeAlias}}
23
+ {{else if isUnionType}}
82
24
  {{#if description}}
83
25
  /// {{description}}
84
26
  {{/if}}
85
- {{#if properties.length}}
86
- {{! Type alias with shape — emit as struct }}
87
27
  #[derive(Debug, Clone, Serialize, Deserialize)]
88
- #[serde(rename_all = "camelCase")]
89
- pub struct {{name}} {
90
- {{#each properties}}
91
- {{#if description}}
92
- /// {{description}}
93
- {{/if}}
94
- {{#if required}}
95
- pub {{snakeCase name}}: {{{rustType type}}},
96
- {{else}}
97
- #[serde(skip_serializing_if = "Option::is_none")]
98
- pub {{snakeCase name}}: Option<{{{rustType type}}}>,
99
- {{/if}}
100
- {{/each}}
101
- }
102
- {{else}}
103
- {{! Simple type alias — skip, referenced by name }}
104
- // {{name}} is a type alias — referenced inline.
105
- {{/if}}
106
- {{/if}}
28
+ #[serde(transparent)]
29
+ pub struct {{name}}(pub serde_json::Value);
107
30
 
108
- {{#if isUnionType}}
31
+ {{else if isIntersectionType}}
109
32
  {{#if description}}
110
33
  /// {{description}}
111
34
  {{/if}}
112
- {{#if unionMembers.length}}
113
- {{! Union type with named members — emit as enum }}
114
- #[derive(Debug, Clone, Serialize, Deserialize)]
115
- #[serde(untagged)]
116
- pub enum {{name}} {
117
- {{#each unionMembers}}
118
- {{pascalCase this}}({{{rustType this}}}),
119
- {{/each}}
120
- }
121
- {{/if}}
35
+ #[derive(Debug, Clone, Serialize, Deserialize, Default)]
36
+ #[serde(transparent)]
37
+ pub struct {{name}}(pub std::collections::HashMap<String, serde_json::Value>);
38
+
39
+ {{else if isTypeAlias}}
40
+ {{#if description}}
41
+ /// {{description}}
122
42
  {{/if}}
43
+ pub type {{name}} = {{{aliasType}}};
123
44
 
124
- {{#if isIntersectionType}}
45
+ {{else}}
125
46
  {{#if description}}
126
47
  /// {{description}}
127
48
  {{/if}}
128
- {{#if intersectionMembers.length}}
129
- {{! Intersection type — flatten into a struct combining all members }}
130
49
  #[derive(Debug, Clone, Serialize, Deserialize)]
131
- #[serde(rename_all = "camelCase")]
132
50
  pub struct {{name}} {
133
- {{#each intersectionMembers}}
134
- // Fields from {{this}} are expected to be inlined by the code generator.
135
- {{/each}}
136
- // Intersection types require manual field specification.
137
- // TODO: inline fields from {{join intersectionMembers ", "}}
138
- }
51
+ {{#each properties}}
52
+ {{#if description}}
53
+ /// {{description}}
54
+ {{/if}}
55
+ #[serde(rename = "{{name}}"{{#if optional}}, skip_serializing_if = "Option::is_none"{{/if}})]
56
+ pub {{fieldName}}: {{targetType}},
57
+ {{/each}}
58
+ {{#if additionalType}}
59
+ #[serde(flatten)]
60
+ pub additional_properties: std::collections::HashMap<String, {{additionalType}}>,
139
61
  {{/if}}
62
+ }
140
63
  {{/if}}
141
64
 
142
65
  {{/each}}
@@ -70,10 +70,12 @@ export class {{interfaceName}} {
70
70
  }
71
71
  }
72
72
  {{/if}}
73
- {{#if (or (hasRequestBody this) (needsRequestHeaders this))}}
73
+ {{#if (or (hasRequestBody this) (needsRequestHeaders this) (sendsEmptyBody this))}}
74
74
  const sseHeaders: Record<string, string> = {};
75
75
  {{#if (hasRequestBody this)}}
76
76
  sseHeaders['Content-Type'] = '{{requestBody.contentType}}';
77
+ {{else if (sendsEmptyBody this)}}
78
+ sseHeaders['Content-Type'] = 'application/json';
77
79
  {{/if}}
78
80
  {{#if (and headerParams.length headerType)}}
79
81
  if (headerOptions) {
@@ -98,14 +100,16 @@ export class {{interfaceName}} {
98
100
  }
99
101
  {{/if}}
100
102
  {{/if}}
101
- return createSSEStream<{{#if sseReturnType}}{{sseReturnType}}{{else}}{{{sseEventType this}}}{{/if}}>(
103
+ return createSSEStream<{{#if sseReturnType}}{{sseReturnType}}{{else}}SSEEvent<{{{sseEventType this}}}>{{/if}}>(
102
104
  sseUrl.toString(),
103
105
  {
104
106
  method: '{{httpMethod}}',
105
107
  {{#if (hasRequestBody this)}}
106
108
  body: JSON.stringify(input),
109
+ {{else if (sendsEmptyBody this)}}
110
+ body: '{}',
107
111
  {{/if}}
108
- {{#if (or (hasRequestBody this) (needsRequestHeaders this))}}
112
+ {{#if (or (hasRequestBody this) (needsRequestHeaders this) (sendsEmptyBody this))}}
109
113
  headers: Object.keys(sseHeaders).length > 0 ? sseHeaders : undefined,
110
114
  {{/if}}
111
115
  },
@@ -133,9 +137,11 @@ export class {{interfaceName}} {
133
137
  {{else if queryType}}
134
138
  const params = query;
135
139
  {{/if}}
136
- {{#if (needsRequestHeaders this)}}
140
+ {{#if (or (needsRequestHeaders this) (sendsEmptyBody this))}}
137
141
  const requestHeaders: Record<string, string> = {};
138
- {{#if (and (hasRequestBody this) (and (neq requestBody.contentType "application/json") (neq requestBody.contentType "multipart/form-data")))}}
142
+ {{#if (sendsEmptyBody this)}}
143
+ requestHeaders['Content-Type'] = 'application/json';
144
+ {{else if (and (hasRequestBody this) (and (neq requestBody.contentType "application/json") (neq requestBody.contentType "multipart/form-data")))}}
139
145
  requestHeaders['Content-Type'] = '{{requestBody.contentType}}';
140
146
  {{/if}}
141
147
  {{#if (and headerParams.length headerType)}}
@@ -167,11 +173,13 @@ export class {{interfaceName}} {
167
173
  url: `{{path}}`,
168
174
  {{#if (hasRequestBody this)}}
169
175
  data: input,
176
+ {{else if (sendsEmptyBody this)}}
177
+ data: {},
170
178
  {{/if}}
171
179
  {{#if (or (hasQueryParams this) queryType)}}
172
180
  params,
173
181
  {{/if}}
174
- {{#if (needsRequestHeaders this)}}
182
+ {{#if (or (needsRequestHeaders this) (sendsEmptyBody this))}}
175
183
  headers: Object.keys(requestHeaders).length > 0 ? requestHeaders : undefined,
176
184
  {{/if}}
177
185
  },
@@ -84,10 +84,12 @@ export function {{factoryName}}(transport: SDKTransport): {{interfaceName}} {
84
84
  }
85
85
  }
86
86
  {{/if}}
87
- {{#if (or (hasRequestBody this) (needsRequestHeaders this))}}
87
+ {{#if (or (hasRequestBody this) (needsRequestHeaders this) (sendsEmptyBody this))}}
88
88
  const sseHeaders: Record<string, string> = {};
89
89
  {{#if (hasRequestBody this)}}
90
90
  sseHeaders['Content-Type'] = '{{requestBody.contentType}}';
91
+ {{else if (sendsEmptyBody this)}}
92
+ sseHeaders['Content-Type'] = 'application/json';
91
93
  {{/if}}
92
94
  {{#if (and headerParams.length headerType)}}
93
95
  if (headerOptions) {
@@ -118,8 +120,10 @@ export function {{factoryName}}(transport: SDKTransport): {{interfaceName}} {
118
120
  method: '{{httpMethod}}',
119
121
  {{#if (hasRequestBody this)}}
120
122
  body: JSON.stringify(input),
123
+ {{else if (sendsEmptyBody this)}}
124
+ body: '{}',
121
125
  {{/if}}
122
- {{#if (or (hasRequestBody this) (needsRequestHeaders this))}}
126
+ {{#if (or (hasRequestBody this) (needsRequestHeaders this) (sendsEmptyBody this))}}
123
127
  headers: Object.keys(sseHeaders).length > 0 ? sseHeaders : undefined,
124
128
  {{/if}}
125
129
  },
@@ -142,9 +146,11 @@ export function {{factoryName}}(transport: SDKTransport): {{interfaceName}} {
142
146
  {{else if queryType}}
143
147
  const params = query;
144
148
  {{/if}}
145
- {{#if (needsRequestHeaders this)}}
149
+ {{#if (or (needsRequestHeaders this) (sendsEmptyBody this))}}
146
150
  const requestHeaders: Record<string, string> = {};
147
- {{#if (and (hasRequestBody this) (and (neq requestBody.contentType "application/json") (neq requestBody.contentType "multipart/form-data")))}}
151
+ {{#if (sendsEmptyBody this)}}
152
+ requestHeaders['Content-Type'] = 'application/json';
153
+ {{else if (and (hasRequestBody this) (and (neq requestBody.contentType "application/json") (neq requestBody.contentType "multipart/form-data")))}}
148
154
  requestHeaders['Content-Type'] = '{{requestBody.contentType}}';
149
155
  {{/if}}
150
156
  {{#if (and headerParams.length headerType)}}
@@ -176,11 +182,13 @@ export function {{factoryName}}(transport: SDKTransport): {{interfaceName}} {
176
182
  url: `{{path}}`,
177
183
  {{#if (hasRequestBody this)}}
178
184
  data: input,
185
+ {{else if (sendsEmptyBody this)}}
186
+ data: {},
179
187
  {{/if}}
180
188
  {{#if (or (hasQueryParams this) queryType)}}
181
189
  params,
182
190
  {{/if}}
183
- {{#if (needsRequestHeaders this)}}
191
+ {{#if (or (needsRequestHeaders this) (sendsEmptyBody this))}}
184
192
  headers: Object.keys(requestHeaders).length > 0 ? requestHeaders : undefined,
185
193
  {{/if}}
186
194
  },
@@ -24,6 +24,8 @@
24
24
  },
25
25
  "files": [
26
26
  "dist",
27
- "README.md"
27
+ "docs",
28
+ "README.md",
29
+ "LICENSE"
28
30
  ]
29
31
  }
@@ -1,10 +1,8 @@
1
1
  # {{title}} SDK
2
2
 
3
- {{#if description}}
4
- {{description}}
3
+ {{#if description}}{{description}}{{else}}TypeScript client for the {{title}} API.{{/if}}
5
4
 
6
- {{/if}}
7
- > This SDK was automatically generated by [Tesseract](https://www.npmjs.com/package/@apollo-deploy/tesseract).
5
+ > Generated by [Tesseract](https://www.npmjs.com/package/@apollo-deploy/tesseract). Generated source files should not be edited manually.
8
6
 
9
7
  ## Installation
10
8
 
@@ -12,7 +10,7 @@
12
10
  npm install {{packageName}}
13
11
  ```
14
12
 
15
- ## Quick Start
13
+ ## Quick start
16
14
 
17
15
  ```typescript
18
16
  import { create{{clientName}}Client } from '{{packageName}}';
@@ -20,66 +18,68 @@ import { create{{clientName}}Client } from '{{packageName}}';
20
18
  const client = create{{clientName}}Client({
21
19
  baseUrl: '{{baseUrl}}',
22
20
  {{#each securitySchemes}}
23
- {{configKey}}: 'your-{{kebabCase name}}-credential',
21
+ {{configKey}}: process.env.{{upperCase (snakeCase configKey)}},
24
22
  {{/each}}
23
+ timeoutMs: 15_000,
25
24
  });
25
+
26
+ {{#if groups.length}}
27
+ // Domain clients are available directly on the client.
26
28
  const api = client.{{groups.[0].name}};
29
+ {{/if}}
27
30
  ```
28
31
 
29
- ## Request Options
32
+ ## Configuration and reliability
30
33
 
31
- ```typescript
32
- import { create{{clientName}}Client } from '{{packageName}}';
34
+ The generated transport supports:
33
35
 
34
- const client = create{{clientName}}Client();
36
+ - Bounded request timeouts and `AbortSignal` cancellation
37
+ - Exponential-backoff retries for transient failures
38
+ - `Retry-After` handling for rate limits
39
+ - Per-request headers, timeout, and retry overrides
40
+ - Structured `SDKError` values with HTTP status, error code, and request ID
41
+ - Request/response hooks and transport plugins for logging or telemetry
35
42
 
36
- const result = await client.{{groups.[0].name}}.{{groups.[0].operations.[0].name}}(
37
- /* params */,
38
- {
39
- timeoutMs: 30_000,
40
- headers: {
41
- 'X-Trace-Id': 'trace_123',
42
- },
43
+ ```typescript
44
+ const client = create{{clientName}}Client({
45
+ timeoutMs: 30_000,
46
+ defaultHeaders: { 'X-Application': 'my-service' },
47
+ retries: {
48
+ attempts: 3,
49
+ backoffMs: 400,
50
+ jitter: true,
43
51
  },
44
- );
52
+ });
45
53
  ```
46
54
 
47
- ## API Reference
48
-
49
- {{#each groups}}
50
- ### {{interfaceName}}
55
+ Mutating requests are retried only when the request is considered idempotent, carries an idempotency key, or the retry policy explicitly allows it.
51
56
 
52
- {{#if description}}
53
- {{description}}
57
+ ## Documentation
54
58
 
55
- {{/if}}
56
- | Method | HTTP | Path | Description |
57
- |--------|------|------|-------------|
58
- {{#each operations}}
59
- | `{{name}}` | {{httpMethod}} | `{{path}}` | {{#if description}}{{description}}{{else}}-{{/if}} |
60
- {{/each}}
61
-
62
- {{/each}}
63
- ## Types
59
+ - [Documentation index](./docs/README.md)
60
+ - [Generated types](./docs/types.md)
64
61
 
65
- {{#each schemas}}
66
- {{#if isEnum}}
67
- - `{{name}}` — enum: {{#each enumValues}}`{{this}}`{{#unless @last}}, {{/unless}}{{/each}}
68
- {{else}}
69
- - `{{name}}`{{#if description}} — {{description}}{{/if}}
70
- {{/if}}
62
+ | Domain | Description |
63
+ |---|---|
64
+ {{#each groups}}
65
+ | [{{interfaceName}}](./docs/domains/{{fileName}}.md) | {{#if description}}{{description}}{{else}}{{name}} operations{{/if}} |
71
66
  {{/each}}
72
67
 
73
- ## Error Handling
68
+ ## Error handling
74
69
 
75
70
  ```typescript
76
71
  import { SDKError } from '{{packageName}}';
77
72
 
78
73
  try {
79
- const result = await client.someApi.someMethod();
74
+ // await client.someDomain.someOperation();
80
75
  } catch (error) {
81
76
  if (error instanceof SDKError) {
82
- console.error(`Error ${error.status}: ${error.message} (${error.code})`);
77
+ console.error(error.status, error.code, error.requestId);
83
78
  }
79
+ throw error;
84
80
  }
85
81
  ```
82
+
83
+ ## License
84
+
85
+ MIT
@@ -59,8 +59,12 @@ function calculateBackoff(attempt: number, baseMs: number, useJitter: boolean, m
59
59
  function parseRetryAfterMs(error: unknown): number | undefined {
60
60
  if (!isAxiosError(error)) return undefined;
61
61
 
62
- const rawRetryAfter = error.response?.headers?.['retry-after'];
63
- if (typeof rawRetryAfter !== 'string' || rawRetryAfter.length === 0) {
62
+ const header = error.response?.headers?.['retry-after'];
63
+ const rawRetryAfter = Array.isArray(header) ? header[0] : header;
64
+ if (
65
+ (typeof rawRetryAfter !== 'string' && typeof rawRetryAfter !== 'number') ||
66
+ String(rawRetryAfter).length === 0
67
+ ) {
64
68
  return undefined;
65
69
  }
66
70
 
@@ -71,7 +75,7 @@ function parseRetryAfterMs(error: unknown): number | undefined {
71
75
  }
72
76
 
73
77
  // Try HTTP-date format
74
- const absoluteTime = Date.parse(rawRetryAfter);
78
+ const absoluteTime = Date.parse(String(rawRetryAfter));
75
79
  if (!Number.isNaN(absoluteTime)) {
76
80
  return Math.max(absoluteTime - Date.now(), 0);
77
81
  }
@@ -213,6 +217,11 @@ export interface TransportConfig {
213
217
  * Default: ['POST', 'PUT', 'PATCH', 'DELETE']
214
218
  */
215
219
  idempotentMethods?: string[];
220
+ /**
221
+ * HTTP methods eligible for automatic retries without an idempotency key.
222
+ * Default: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE']
223
+ */
224
+ retryMethods?: string[];
216
225
  }
217
226
 
218
227
  // ── Telemetry Meta Types ────────────────────────────
@@ -244,6 +253,7 @@ export interface ResolvedTransportConfig extends TransportConfig {
244
253
  retries: RetryConfig;
245
254
  plugins: SDKPlugin[];
246
255
  idempotentMethods: string[];
256
+ retryMethods: string[];
247
257
  }
248
258
 
249
259
  /**
@@ -365,14 +375,16 @@ export function createTransport(config: TransportConfig): SDKTransport {
365
375
  },
366
376
  plugins: config.plugins ?? [],
367
377
  idempotentMethods: config.idempotentMethods ?? ['POST', 'PUT', 'PATCH', 'DELETE'],
378
+ retryMethods: config.retryMethods ?? ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE'],
368
379
  };
369
380
 
370
381
  const instance = axios.create({
371
382
  baseURL: resolvedConfig.baseUrl,
372
383
  timeout: resolvedConfig.timeoutMs,
373
384
  withCredentials: resolvedConfig.withCredentials ?? false,
385
+ // Content-Type is set per-request when a body is present (see domain methods).
386
+ // Avoid advertising application/json on GET/HEAD with no body.
374
387
  headers: {
375
- 'Content-Type': 'application/json',
376
388
  ...(resolvedConfig.defaultHeaders ?? {}),
377
389
  },
378
390
  ...resolvedConfig.axiosConfig,
@@ -483,6 +495,17 @@ export function createTransport(config: TransportConfig): SDKTransport {
483
495
 
484
496
  // ── Request Execution ───────────────────────────────
485
497
 
498
+ function hasIdempotencyKey(headers: AxiosRequestConfig['headers']): boolean {
499
+ if (!headers) return false;
500
+ return Object.entries(headers as Record<string, unknown>).some(
501
+ ([name, value]) =>
502
+ name.toLowerCase() === 'x-idempotency-key' &&
503
+ value !== undefined &&
504
+ value !== null &&
505
+ String(value).length > 0,
506
+ );
507
+ }
508
+
486
509
  /**
487
510
  * Execute an HTTP request with automatic retries and error mapping.
488
511
  */
@@ -545,9 +568,13 @@ export async function executeRequest<T>(
545
568
  const duration = startTime === undefined ? 0 : Date.now() - startTime;
546
569
 
547
570
  // Determine if we should retry
571
+ const method = (effectiveConfig.method ?? 'GET').toUpperCase();
572
+ const methodCanRetry =
573
+ transport.config.retryMethods.includes(method) ||
574
+ hasIdempotencyKey(effectiveConfig.headers);
548
575
  const shouldRetry = retries.shouldRetry
549
576
  ? retries.shouldRetry(sdkError, attempt)
550
- : sdkError.isRetryable();
577
+ : methodCanRetry && sdkError.isRetryable();
551
578
 
552
579
  const willRetry = attempt < maxAttempts && shouldRetry;
553
580
 
@@ -578,7 +605,7 @@ export async function executeRequest<T>(
578
605
  let delayMs: number;
579
606
 
580
607
  if (sdkError.status === 429 && retryAfterMs !== undefined) {
581
- delayMs = retryAfterMs;
608
+ delayMs = Math.min(retryAfterMs, maxBackoff);
582
609
  } else {
583
610
  delayMs = calculateBackoff(attempt, retries.backoffMs, retries.jitter, maxBackoff);
584
611
  }
@@ -648,15 +675,26 @@ function mapAxiosError(error: unknown): SDKError {
648
675
 
649
676
  const status = error.response.status;
650
677
  const data = error.response.data as any;
678
+ const headerRequestId =
679
+ error.response.headers?.['x-request-id'] ??
680
+ error.response.headers?.['request-id'];
681
+ const requestId = Array.isArray(headerRequestId)
682
+ ? headerRequestId[0]
683
+ : typeof headerRequestId === 'string'
684
+ ? headerRequestId
685
+ : undefined;
651
686
 
652
687
  if (data && typeof data === 'object' && typeof data.error === 'string' && typeof data.message === 'string') {
653
- return new SDKError(data as ApiErrorEnvelope, status);
688
+ return new SDKError(
689
+ { ...data, request_id: data.request_id ?? requestId } as ApiErrorEnvelope,
690
+ status,
691
+ );
654
692
  }
655
693
 
656
694
  return new SDKError(
657
695
  data?.message || error.message || resolveMessage(status),
658
696
  status,
659
697
  data?.error || resolveErrorCode(status),
660
- data?.request_id,
698
+ data?.request_id ?? requestId,
661
699
  );
662
700
  }
@@ -167,7 +167,7 @@ export class SDKError extends Error {
167
167
 
168
168
  /** Check if this error is retryable */
169
169
  isRetryable(): boolean {
170
- return this.code === 'network_error' || this.code === 'gateway_timeout' || this.status === 429 || this.status >= 500;
170
+ return this.code === 'network_error' || this.code === 'gateway_timeout' || this.status === 408 || this.status === 425 || this.status === 429 || this.status >= 500;
171
171
  }
172
172
 
173
173
  /** Convert to a plain object for logging/serialization */
@@ -1,13 +0,0 @@
1
- /**
2
- * TypeScript model emitter (ts-morph based).
3
- *
4
- * Emits schema definitions as TypeScript interfaces, type aliases,
5
- * and enums using ts-morph AST construction.
6
- */
7
- import type { EnrichedSDKIR } from '../../types/ir.js';
8
- import type { EmittedFile } from '../../pipeline/write.js';
9
- export declare function emitTypeScriptModels(enriched: EnrichedSDKIR, outputDir: string): {
10
- files: EmittedFile[];
11
- domainTypeFiles: string[];
12
- };
13
- //# sourceMappingURL=model-emitter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"model-emitter.d.ts","sourceRoot":"","sources":["../../../src/adapters/typescript/model-emitter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,aAAa,EAAoC,MAAM,mBAAmB,CAAC;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAA;CAAE,CAmErD"}