@voxgig/sdkgen 4.19.0 → 4.20.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 (112) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/AgentGuideContent.js +1 -1
  3. package/dist/sdkgen.d.ts +2 -2
  4. package/dist/sdkgen.js +6 -3
  5. package/dist/sdkgen.js.map +1 -1
  6. package/dist/testkit.js +2 -2
  7. package/dist/testkit.js.map +1 -1
  8. package/dist/tsconfig.tsbuildinfo +1 -1
  9. package/dist/utility.d.ts +4 -1
  10. package/dist/utility.js +60 -0
  11. package/dist/utility.js.map +1 -1
  12. package/model/sdkgen.aon +10 -0
  13. package/package.json +1 -1
  14. package/project/.sdk/model/feature/feature-index.aon +20 -20
  15. package/project/.sdk/src/cmp/c/Config_c.ts +15 -0
  16. package/project/.sdk/src/cmp/c/Main_c.ts +15 -0
  17. package/project/.sdk/src/cmp/c/PrepareAuth_c.ts +371 -0
  18. package/project/.sdk/src/cmp/clojure/Config_clojure.ts +47 -1
  19. package/project/.sdk/src/cmp/clojure/Main_clojure.ts +11 -1
  20. package/project/.sdk/src/cmp/clojure/PrepareAuth_clojure.ts +374 -0
  21. package/project/.sdk/src/cmp/cpp/Config_cpp.ts +40 -0
  22. package/project/.sdk/src/cmp/cpp/Main_cpp.ts +17 -0
  23. package/project/.sdk/src/cmp/cpp/PrepareAuth_cpp.ts +441 -0
  24. package/project/.sdk/src/cmp/csharp/Config_csharp.ts +42 -1
  25. package/project/.sdk/src/cmp/csharp/Main_csharp.ts +18 -0
  26. package/project/.sdk/src/cmp/csharp/PrepareAuth_csharp.ts +392 -0
  27. package/project/.sdk/src/cmp/elixir/Config_elixir.ts +36 -1
  28. package/project/.sdk/src/cmp/elixir/Main_elixir.ts +15 -0
  29. package/project/.sdk/src/cmp/elixir/PrepareAuth_elixir.ts +418 -0
  30. package/project/.sdk/src/cmp/go/Config_go.ts +12 -1
  31. package/project/.sdk/src/cmp/go/Main_go.ts +14 -0
  32. package/project/.sdk/src/cmp/go/PrepareAuth_go.ts +322 -0
  33. package/project/.sdk/src/cmp/java/Config_java.ts +20 -1
  34. package/project/.sdk/src/cmp/java/Main_java.ts +14 -0
  35. package/project/.sdk/src/cmp/java/PrepareAuth_java.ts +298 -0
  36. package/project/.sdk/src/cmp/js/Config_js.ts +12 -1
  37. package/project/.sdk/src/cmp/js/Main_js.ts +6 -0
  38. package/project/.sdk/src/cmp/js/PrepareAuth_js.ts +244 -0
  39. package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +23 -1
  40. package/project/.sdk/src/cmp/kotlin/Main_kotlin.ts +20 -0
  41. package/project/.sdk/src/cmp/kotlin/PrepareAuth_kotlin.ts +440 -0
  42. package/project/.sdk/src/cmp/lua/Config_lua.ts +15 -1
  43. package/project/.sdk/src/cmp/lua/Main_lua.ts +11 -0
  44. package/project/.sdk/src/cmp/lua/PrepareAuth_lua.ts +364 -0
  45. package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +31 -1
  46. package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +19 -0
  47. package/project/.sdk/src/cmp/ocaml/PrepareAuth_ocaml.ts +454 -0
  48. package/project/.sdk/src/cmp/perl/Config_perl.ts +30 -0
  49. package/project/.sdk/src/cmp/perl/Main_perl.ts +14 -0
  50. package/project/.sdk/src/cmp/perl/PrepareAuth_perl.ts +387 -0
  51. package/project/.sdk/src/cmp/php/Config_php.ts +12 -1
  52. package/project/.sdk/src/cmp/php/Main_php.ts +7 -0
  53. package/project/.sdk/src/cmp/php/PrepareAuth_php.ts +325 -0
  54. package/project/.sdk/src/cmp/py/Config_py.ts +12 -1
  55. package/project/.sdk/src/cmp/py/Main_py.ts +12 -0
  56. package/project/.sdk/src/cmp/py/PrepareAuth_py.ts +389 -0
  57. package/project/.sdk/src/cmp/rb/Config_rb.ts +18 -1
  58. package/project/.sdk/src/cmp/rb/Main_rb.ts +10 -0
  59. package/project/.sdk/src/cmp/rb/PrepareAuth_rb.ts +305 -0
  60. package/project/.sdk/src/cmp/rust/Config_rust.ts +41 -1
  61. package/project/.sdk/src/cmp/rust/Main_rust.ts +16 -0
  62. package/project/.sdk/src/cmp/rust/PrepareAuth_rust.ts +410 -0
  63. package/project/.sdk/src/cmp/scala/Config_scala.ts +21 -1
  64. package/project/.sdk/src/cmp/scala/Main_scala.ts +14 -0
  65. package/project/.sdk/src/cmp/scala/PrepareAuth_scala.ts +415 -0
  66. package/project/.sdk/src/cmp/swift/Config_swift.ts +37 -1
  67. package/project/.sdk/src/cmp/swift/Main_swift.ts +10 -0
  68. package/project/.sdk/src/cmp/swift/PrepareAuth_swift.ts +439 -0
  69. package/project/.sdk/src/cmp/ts/Config_ts.ts +12 -1
  70. package/project/.sdk/src/cmp/ts/Main_ts.ts +5 -0
  71. package/project/.sdk/src/cmp/ts/PrepareAuth_ts.ts +237 -0
  72. package/project/.sdk/src/cmp/zig/Config_zig.ts +33 -1
  73. package/project/.sdk/src/cmp/zig/Main_zig.ts +16 -0
  74. package/project/.sdk/src/cmp/zig/PrepareAuth_zig.ts +545 -0
  75. package/project/.sdk/tm/clojure/src/sdk/core.clj +31 -20
  76. package/project/.sdk/tm/cpp/utility/pipeline.hpp +36 -40
  77. package/project/.sdk/tm/csharp/utility/MakeOptions.cs +11 -0
  78. package/project/.sdk/tm/elixir/lib/projectname/utility.ex +19 -32
  79. package/project/.sdk/tm/java/utility/MakeOptions.java +13 -1
  80. package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +14 -1
  81. package/project/.sdk/tm/kotlin/utility/Prepare.kt +13 -46
  82. package/project/.sdk/tm/ocaml/Makefile +11 -1
  83. package/project/.sdk/tm/ocaml/sdk_helpers.ml +15 -0
  84. package/project/.sdk/tm/ocaml/sdk_runtime.ml +31 -25
  85. package/project/.sdk/tm/ocaml/test/feature/secrets/t_secrets.ml +125 -12
  86. package/project/.sdk/tm/ocaml/test/t_pipeline.ml +64 -6
  87. package/project/.sdk/tm/perl/utility/make_options.pm +10 -1
  88. package/project/.sdk/tm/php/utility/MakeOptions.php +8 -1
  89. package/project/.sdk/tm/rust/utility/make_options.rs +13 -1
  90. package/project/.sdk/tm/scala/utility/Make.scala +14 -1
  91. package/project/.sdk/tm/scala/utility/Prepare.scala +16 -40
  92. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +30 -3
  93. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +21 -39
  94. package/project/.sdk/tm/zig/core/utility.zig +37 -45
  95. package/project/.sdk/tm/zig/test/pipeline_test.zig +34 -0
  96. package/project/sdkgen-package.json +1 -1
  97. package/src/cmp/AgentGuideContent.ts +1 -1
  98. package/src/sdkgen.ts +4 -1
  99. package/src/testkit.ts +2 -2
  100. package/src/utility.ts +75 -0
  101. package/project/.sdk/tm/c/utility/prepare_auth.c +0 -65
  102. package/project/.sdk/tm/csharp/utility/PrepareAuth.cs +0 -54
  103. package/project/.sdk/tm/go/utility/prepare_auth.go +0 -59
  104. package/project/.sdk/tm/java/utility/PrepareAuth.java +0 -66
  105. package/project/.sdk/tm/js/src/utility/PrepareAuthUtility.js +0 -49
  106. package/project/.sdk/tm/lua/utility/prepare_auth.lua +0 -52
  107. package/project/.sdk/tm/perl/utility/prepare_auth.pm +0 -56
  108. package/project/.sdk/tm/php/utility/PrepareAuth.php +0 -45
  109. package/project/.sdk/tm/py/pkg/utility/prepare_auth.py +0 -46
  110. package/project/.sdk/tm/rb/utility/prepare_auth.rb +0 -35
  111. package/project/.sdk/tm/rust/utility/prepare_auth.rs +0 -65
  112. package/project/.sdk/tm/ts/src/utility/PrepareAuthUtility.ts +0 -78
@@ -0,0 +1,364 @@
1
+
2
+ import {
3
+ Content,
4
+ File,
5
+ Folder,
6
+ cmp,
7
+ isAuthSuppressed,
8
+ isHttpBasicAuth,
9
+ resolveAuthIn,
10
+ resolveAuthName,
11
+ resolveAuthPrefix,
12
+ } from '@voxgig/sdkgen'
13
+
14
+
15
+ // WHERE THE CREDENTIAL GOES IS A FACT ABOUT THE API, so it is generated
16
+ // rather than templated. The lua peer of PrepareAuth_ts.
17
+ //
18
+ // This was a static file at tm/lua/utility/prepare_auth.lua that hardcoded
19
+ // a lower-case "authorization" HEADER. apidef has always resolved the
20
+ // scheme's "in" and "name" into main.kit.info.security - joplin's says
21
+ // in: "query", name: "token" - and generation dropped both. The result was
22
+ // an SDK that sent a header the API does not read and never sent the query
23
+ // parameter it does, so it could not authenticate at all. Four repos in
24
+ // the cedar fleet shipped that way: joplin (token), pipedrive (api_token),
25
+ // trello (key), lm-umbrella (apiKey).
26
+ //
27
+ // A template cannot fix this, because the three placements need three
28
+ // different bodies and a template has to pick one. A component emits the
29
+ // branch this API actually uses and nothing else - no dead query code in a
30
+ // bearer-token SDK, and no runtime branch on a value that is fixed at
31
+ // generation time.
32
+ //
33
+ // The header placement renders BYTE-FOR-BYTE what the template rendered,
34
+ // so every header-based lua SDK regenerates with a zero diff.
35
+ const PrepareAuth = cmp(async function PrepareAuth(props: any) {
36
+ const { target } = props
37
+ const { model } = props.ctx$
38
+
39
+ // `!isAuthSuppressed`, NOT `isAuthActive`. The latter is also false when
40
+ // the SPEC merely declares no security scheme (`main.kit.info.auth:
41
+ // false`), and those SDKs still carry a credential: optspec always
42
+ // declares `apikey` and makeOptions fills `options.auth` from its
43
+ // defaults, so the runtime guard never fired and they have always sent
44
+ // it. Only an explicit `main.kit.config.auth.active: false` means "no
45
+ // credential, ever", which is what isAuthSuppressed reads.
46
+ const active = !isAuthSuppressed(model)
47
+ const where = resolveAuthIn(model)
48
+ const prefix = resolveAuthPrefix(model)
49
+ const basic = isHttpBasicAuth(model)
50
+
51
+ // A HEADER NAME IS LOWER-CASED HERE; A QUERY OR COOKIE NAME IS NOT.
52
+ // Every header key the lua SDK writes is lower case (make_spec's
53
+ // "content-type", the secrets feature's "authorization", fetcher's
54
+ // lower-casing of the response headers), and HTTP header names are
55
+ // case-insensitive on the wire - so "Authorization" must arrive here as
56
+ // the "authorization" the rest of the SDK looks up. A query parameter
57
+ // and a cookie name are case-SENSITIVE: lm-umbrella's "apiKey" is not
58
+ // "apikey", and lower-casing it would break exactly the APIs this
59
+ // change exists to fix.
60
+ const cred = resolveAuthName(model)
61
+ const name = 'header' === where ? cred.toLowerCase() : cred
62
+
63
+ // FOLDER NESTING. Main_lua opens NO folder around this call: its
64
+ // Folder({name:'.'}) around Config is the target root itself, and the
65
+ // lua tree has no src/ wrapper (tm/lua/src holds only feature
66
+ // placeholders and Main's Copy excludes it). The template lived at
67
+ // tm/lua/utility/prepare_auth.lua, which the blanket Copy lands at
68
+ // <root>/utility/prepare_auth.lua - the one path
69
+ // require("utility.prepare_auth") in utility/register.lua resolves. So
70
+ // this component opens the single "utility" folder that path needs.
71
+ // Opening a second one would write <root>/utility/utility/, where
72
+ // nothing requires it.
73
+ Folder({ name: 'utility' }, () => {
74
+ File({ name: 'prepare_auth.' + target.ext }, () => {
75
+ Content(render({
76
+ project: model.const.Name,
77
+ active,
78
+ where,
79
+ name,
80
+ prefix,
81
+ basic,
82
+ }))
83
+ })
84
+ })
85
+ })
86
+
87
+
88
+ function render(spec: {
89
+ project: string, active: boolean, where: string,
90
+ name: string, prefix: string, basic: boolean
91
+ }): string {
92
+ const head = `-- ${spec.project} SDK utility: prepare_auth\n`
93
+
94
+ // NO AUTH AT ALL. A public API's SDK gets a prepare_auth that is honest
95
+ // about it rather than one that deletes a header nobody set.
96
+ if (!spec.active) {
97
+ return head + `
98
+ -- This API declares no authentication, so there is no credential to place.
99
+ -- The function stays in the pipeline because make_spec calls it
100
+ -- unconditionally.
101
+ local function prepare_auth_util(ctx)
102
+ local spec = ctx.spec
103
+ if spec == nil then
104
+ return nil, ctx:make_error("auth_no_spec",
105
+ "Expected context spec property to be defined.")
106
+ end
107
+
108
+ return spec, nil
109
+ end
110
+
111
+ return prepare_auth_util
112
+ `
113
+ }
114
+
115
+ const where = spec.where
116
+
117
+ // HTTP Basic is header-only by definition: the scheme is
118
+ // "Authorization: Basic base64(user:pass)". It cannot be expressed as a
119
+ // query parameter or a cookie, so the branch is emitted only where it
120
+ // can mean something.
121
+ const basic = spec.basic && 'header' === where
122
+
123
+ const CRED = credConst(where)
124
+
125
+ const consts =
126
+ `local ${CRED} = "${luastr(spec.name)}"\n` +
127
+ ('cookie' === where ? `local HEADER_COOKIE = "cookie"\n` : '') +
128
+ `local OPTION_APIKEY = "apikey"\n` +
129
+ (basic ? `local OPTION_SECRET = "secret"\n` : '') +
130
+ `local NOT_FOUND = "__NOTFOUND__"\n`
131
+
132
+ return head + `
133
+ local vs = require("utility.struct.struct")
134
+
135
+ ` + consts + (basic ? BASE64 : '') + ('cookie' === where ? COOKIE_SET : '') + `
136
+ local function prepare_auth_util(ctx)
137
+ local spec = ctx.spec
138
+ if spec == nil then
139
+ return nil, ctx:make_error("auth_no_spec",
140
+ "Expected context spec property to be defined.")
141
+ end
142
+
143
+ ${bag(where)} local options = ctx.client:options_map()
144
+
145
+ -- Public APIs that need no auth omit the options.auth block entirely.
146
+ if options.auth == nil then
147
+ ${clear(where, 4)}
148
+ return spec, nil
149
+ end
150
+
151
+ local apikey = vs.getprop(options, OPTION_APIKEY, NOT_FOUND)
152
+ ` + (basic ? BASIC : '') + `
153
+ if apikey == nil
154
+ or (type(apikey) == "string" and (apikey == NOT_FOUND or apikey == ""))
155
+ then
156
+ ${clear(where, 4)}
157
+ else
158
+ ${place(where)}
159
+ end
160
+
161
+ return spec, nil
162
+ end
163
+
164
+ return prepare_auth_util
165
+ `
166
+ }
167
+
168
+
169
+ // The constant the credential name is bound to, named for where it goes -
170
+ // a reader of the generated file should not have to ask.
171
+ function credConst(where: string): string {
172
+ return 'query' === where ? 'QUERY_AUTH' :
173
+ 'cookie' === where ? 'COOKIE_AUTH' : 'HEADER_AUTH'
174
+ }
175
+
176
+
177
+ // The bag the credential lands in, per placement. A cookie rides the
178
+ // header bag, because a cookie IS a header.
179
+ function bag(where: string): string {
180
+ return 'query' === where ?
181
+ ' local query = spec.query\n' :
182
+ ' local headers = spec.headers\n'
183
+ }
184
+
185
+
186
+ function clear(where: string, indent: number): string {
187
+ const pad = ' '.repeat(indent)
188
+
189
+ if ('query' === where) {
190
+ return pad + 'query[QUERY_AUTH] = nil'
191
+ }
192
+
193
+ if ('cookie' === where) {
194
+ return pad + 'cookie_set(headers, nil)'
195
+ }
196
+
197
+ return pad + 'headers[HEADER_AUTH] = nil'
198
+ }
199
+
200
+
201
+ function place(where: string): string {
202
+ if ('query' === where) {
203
+ // NO PREFIX IN A QUERY STRING. "?token=Bearer%20abc" is not a thing any
204
+ // API reads; the prefix is a header-value convention and is dropped
205
+ // here deliberately rather than silently concatenated.
206
+ return ` -- NO PREFIX IN A QUERY STRING: "?token=Bearer%20abc" is not a thing
207
+ -- any API reads, so the auth.prefix a header placement space-joins is
208
+ -- dropped here deliberately rather than concatenated.
209
+ local apikey_val = ""
210
+ if type(apikey) == "string" then
211
+ apikey_val = apikey
212
+ end
213
+ query[QUERY_AUTH] = apikey_val`
214
+ }
215
+
216
+ if ('cookie' === where) {
217
+ return ` local apikey_val = ""
218
+ if type(apikey) == "string" then
219
+ apikey_val = apikey
220
+ end
221
+ -- The prefix is a header-value convention and has no meaning in a
222
+ -- cookie pair, so it is dropped the way a query placement drops it.
223
+ cookie_set(headers, apikey_val)`
224
+ }
225
+
226
+ // BYTE-FOR-BYTE the template's body, so a header-based SDK regenerates
227
+ // unchanged.
228
+ return ` local auth_prefix = ""
229
+ local ap = vs.getpath(options, "auth.prefix")
230
+ if type(ap) == "string" then
231
+ auth_prefix = ap
232
+ end
233
+ local apikey_val = ""
234
+ if type(apikey) == "string" then
235
+ apikey_val = apikey
236
+ end
237
+ -- Empty prefix (raw apiKey credential) must not add a leading space.
238
+ if auth_prefix == "" then
239
+ headers[HEADER_AUTH] = apikey_val
240
+ else
241
+ headers[HEADER_AUTH] = auth_prefix .. " " .. apikey_val
242
+ end`
243
+ }
244
+
245
+
246
+ // True HTTP Basic Auth: two credentials, base64-joined. Emitted only for a
247
+ // header placement (see render).
248
+ const BASIC = `
249
+ -- True HTTP Basic Auth needs TWO credentials, base64-joined - a single
250
+ -- token in the header (the branch below) can never authenticate against
251
+ -- an API that actually checks "Authorization: Basic base64(user:pass)".
252
+ if vs.getpath(options, "auth.basic") == true then
253
+ local secret = vs.getprop(options, OPTION_SECRET, NOT_FOUND)
254
+
255
+ if apikey == nil or secret == nil
256
+ or (type(apikey) == "string" and (apikey == NOT_FOUND or apikey == ""))
257
+ or (type(secret) == "string" and (secret == NOT_FOUND or secret == ""))
258
+ then
259
+ headers[HEADER_AUTH] = nil
260
+ else
261
+ local auth_prefix = ""
262
+ local ap = vs.getpath(options, "auth.prefix")
263
+ if type(ap) == "string" then
264
+ auth_prefix = ap
265
+ end
266
+ local joined = base64(tostring(apikey) .. ":" .. tostring(secret))
267
+ if auth_prefix == "" then
268
+ headers[HEADER_AUTH] = joined
269
+ else
270
+ headers[HEADER_AUTH] = auth_prefix .. " " .. joined
271
+ end
272
+ end
273
+
274
+ return spec, nil
275
+ end
276
+ `
277
+
278
+
279
+ // Lua 5.4 has no base64, and the vendored sekreto encoder lives inside the
280
+ // OPTIONAL secrets feature - an SDK that never asked for secrets does not
281
+ // ship it - so an HTTP Basic SDK carries its own. Emitted only in that
282
+ // branch, so nothing else pays for it.
283
+ const BASE64 = `
284
+ local B64_ALPHABET =
285
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
286
+
287
+
288
+ local function base64(text)
289
+ local out = {}
290
+ local size = #text
291
+ local index = 1
292
+
293
+ while index <= size do
294
+ local rest = size - index + 1
295
+ local a = string.byte(text, index)
296
+ local b = string.byte(text, index + 1) or 0
297
+ local c = string.byte(text, index + 2) or 0
298
+ local word = (a << 16) | (b << 8) | c
299
+
300
+ local chunk = {}
301
+ for shift = 18, 0, -6 do
302
+ local at = (word >> shift) & 0x3f
303
+ chunk[#chunk + 1] = string.sub(B64_ALPHABET, at + 1, at + 1)
304
+ end
305
+
306
+ -- One trailing source byte yields two characters and "==", two yield
307
+ -- three and "=".
308
+ if rest == 1 then
309
+ chunk[3] = "="
310
+ chunk[4] = "="
311
+ elseif rest == 2 then
312
+ chunk[4] = "="
313
+ end
314
+
315
+ out[#out + 1] = table.concat(chunk)
316
+ index = index + 3
317
+ end
318
+
319
+ return table.concat(out)
320
+ end
321
+
322
+ `
323
+
324
+
325
+ // A cookie header is SHARED: any other cookie the caller set rides in the
326
+ // same string, so the credential pair is rewritten in place and everything
327
+ // else is kept. A plain assignment would throw the caller's cookies away.
328
+ // A nil value removes just our pair.
329
+ const COOKIE_SET = `
330
+ local function cookie_set(headers, value)
331
+ local kept = {}
332
+ local existing = headers[HEADER_COOKIE]
333
+
334
+ if type(existing) == "string" then
335
+ for pair in string.gmatch(existing, "[^;]+") do
336
+ local one = string.match(pair, "^%s*(.-)%s*$")
337
+ if one ~= "" and string.match(one, "^[^=]*") ~= COOKIE_AUTH then
338
+ kept[#kept + 1] = one
339
+ end
340
+ end
341
+ end
342
+
343
+ if value ~= nil then
344
+ kept[#kept + 1] = COOKIE_AUTH .. "=" .. value
345
+ end
346
+
347
+ if #kept == 0 then
348
+ headers[HEADER_COOKIE] = nil
349
+ else
350
+ headers[HEADER_COOKIE] = table.concat(kept, "; ")
351
+ end
352
+ end
353
+
354
+ `
355
+
356
+
357
+ function luastr(s: string): string {
358
+ return String(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
359
+ }
360
+
361
+
362
+ export {
363
+ PrepareAuth
364
+ }
@@ -8,6 +8,8 @@ import {
8
8
  each,
9
9
  isAuthActive,
10
10
  isConfigData,
11
+ resolveAuthIn,
12
+ resolveAuthName,
11
13
  resolveAuthPrefix,
12
14
  targetFeatures,
13
15
  } from '@voxgig/sdkgen'
@@ -148,7 +150,35 @@ const Config = cmp(async function Config(props: any) {
148
150
  // server-variable defaults), which the hand-rolled build here omitted.
149
151
  // Passing target.name opts this target into the main slug/version/target
150
152
  // identity fields (read by station's descriptor - see configDefinition).
151
- const { def: config, json: configJson } = configDefinition(model, target.name)
153
+ const { def: config } = configDefinition(model, target.name)
154
+
155
+ // `in` and `name` TRAVEL WITH THE PREFIX NOW. apidef resolved both from the
156
+ // spec's securityScheme all along and generation dropped them, so an
157
+ // apiKey-in-query API got an `authorization` header it does not read.
158
+ //
159
+ // Added to the shared `def` here rather than in configDefinition, so this
160
+ // change moves ocaml and nothing else - and both representations below
161
+ // render from the SAME object, which is why the JSON is stringified AFTER
162
+ // this rather than taken from configDefinition: the data rung and the
163
+ // literal rung must not be able to describe different configs.
164
+ //
165
+ // ONLY WHEN THEY DIFFER from the header/Authorization default, so every
166
+ // header-based SDK's sdk_config.ml is byte-identical to what it generated
167
+ // before. `options.auth` is absent entirely when auth is inactive
168
+ // (configDefinition's own gate), and there is nothing to qualify then.
169
+ const authIn = resolveAuthIn(model)
170
+ const authName = resolveAuthName(model)
171
+ const authOpts = (config as any).options?.auth
172
+ if (null != authOpts) {
173
+ if ('header' !== authIn) {
174
+ authOpts.in = authIn
175
+ }
176
+ if ('Authorization' !== authName) {
177
+ authOpts.name = authName
178
+ }
179
+ }
180
+
181
+ const configJson = JSON.stringify(config)
152
182
  const asData = isConfigData(configJson, configReprSetting(model))
153
183
 
154
184
  File({ name: 'sdk_config.' + target.ext }, () => {
@@ -24,6 +24,7 @@ import { Config, secretsBuild } from './Config_ocaml'
24
24
  import { Gitignore } from './Gitignore_ocaml'
25
25
  import { MainEntity } from './MainEntity_ocaml'
26
26
  import { SdkError } from './SdkError_ocaml'
27
+ import { PrepareAuth } from './PrepareAuth_ocaml'
27
28
  import { entityModule, ocamlString } from './utility_ocaml'
28
29
 
29
30
 
@@ -185,6 +186,24 @@ FEATURE_LINK =
185
186
  Config({ target })
186
187
  SdkError({ target })
187
188
 
189
+ // sdk_prepare_auth.ml is GENERATED, not templated: WHERE the credential
190
+ // goes (header / query / cookie, and under what name) is a fact about the
191
+ // API, and tm/ can only hold one answer. ocaml had no prepare_auth
192
+ // template to replace - the body was a `let` inside the monolithic
193
+ // tm/ocaml/sdk_runtime.ml - so this is a real extraction: the module
194
+ // keeps the `prepare_auth_util` name by aliasing this one, and every
195
+ // existing caller (the utility record, make_spec, the secrets feature's
196
+ // re-run, the shipped suites) resolves unchanged. See PrepareAuth_ocaml.
197
+ //
198
+ // AT ROOT LEVEL, with no Folder open. The ocaml tree is flat at the
199
+ // target root and the Makefile's `RUNTIME` names `sdk_prepare_auth.ml`
200
+ // by that exact path, between sdk_helpers.ml (which it uses) and
201
+ // sdk_runtime.ml (which uses it) - ocamlc compiles in the order it is
202
+ // handed and has no link-time reordering. Emitting it inside a Folder
203
+ // would put it where neither `RUNTIME` nor `-I .` looks, and
204
+ // sdk_runtime.ml would fail with `Unbound module Sdk_prepare_auth`.
205
+ PrepareAuth({ target })
206
+
188
207
  // sdk_client.ml — the client constructors, direct/prepare, and the
189
208
  // per-entity accessors (twin of the go root package + rust core/sdk.rs).
190
209
  File({ name: 'sdk_client.' + target.ext }, () => {