@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,305 @@
1
+
2
+ import {
3
+ Content,
4
+ File,
5
+ Folder,
6
+ cmp,
7
+ isHttpBasicAuth,
8
+ resolveAuthIn,
9
+ resolveAuthName,
10
+ } from '@voxgig/sdkgen'
11
+
12
+
13
+ import {
14
+ KIT,
15
+ getModelPath,
16
+ } from '@voxgig/apidef'
17
+
18
+
19
+ // WHERE THE CREDENTIAL GOES IS A FACT ABOUT THE API, so it is generated
20
+ // rather than templated.
21
+ //
22
+ // This was a static file at `tm/rb/utility/prepare_auth.rb` that hardcoded
23
+ // `HEADER_AUTH = "authorization"`. apidef has always resolved the scheme's
24
+ // `in` and `name` into `main.kit.info.security` — joplin's says
25
+ // `in: "query", name: "token"` — and generation dropped both. The result
26
+ // was an SDK that sent a header the API does not read and never sent the
27
+ // query parameter it does, so it could not authenticate at all. Four repos
28
+ // in the cedar fleet shipped that way: joplin (`token`), pipedrive
29
+ // (`api_token`), trello (`key`), lm-umbrella (`apiKey`).
30
+ //
31
+ // A template cannot fix this, because the three placements need three
32
+ // different bodies and a template has to pick one. A component emits the
33
+ // branch this API actually uses and nothing else — no dead query code in a
34
+ // bearer-token SDK, and no runtime `if` on a value that is fixed at
35
+ // generation time.
36
+ //
37
+ // The ts port is the reference (cmp/ts/PrepareAuth_ts.ts). Two things are
38
+ // deliberately NOT the same here, both recorded at their site below: the
39
+ // header name is lower-cased, and the cookie clear removes our own pair
40
+ // instead of a header that was never set.
41
+ const PrepareAuth = cmp(async function PrepareAuth(props: any) {
42
+ const { target } = props
43
+ const { model } = props.ctx$
44
+
45
+ const active = authSwitchedOn(model)
46
+ const where = resolveAuthIn(model)
47
+ const name = resolveAuthName(model)
48
+ const basic = isHttpBasicAuth(model)
49
+
50
+ // RB'S LAYOUT IS FLAT, WHICH IS WHY THIS FOLDER IS OPENED HERE AND THE TS
51
+ // PORT OPENS NONE. In ts, Main wraps its whole body in
52
+ // `Folder({name:'src'})` and the utilities live at `src/utility/`, so a
53
+ // second `src` there would write `src/src/utility/`. Main_rb opens no such
54
+ // folder: `Package`, `Gitignore`, the SDK file and `Copy({from:'tm/rb'})`
55
+ // all land at the target root, and `Config` sits inside a `Folder({name:
56
+ // '.'})` that is the root too. The template this replaces was
57
+ // `tm/rb/utility/prepare_auth.rb`, and that Copy's root IS the target root,
58
+ // so the file it produced was `<root>/utility/prepare_auth.rb`. One folder,
59
+ // `utility`, reproduces exactly that path — and register.rb's
60
+ // `require_relative 'prepare_auth'` (from `utility/`) only resolves there.
61
+ Folder({ name: 'utility' }, () => {
62
+ File({ name: 'prepare_auth.' + target.ext }, () => {
63
+ Content(render({ Name: model.const.Name, active, where, name, basic }))
64
+ })
65
+ })
66
+ })
67
+
68
+
69
+ function render(spec: {
70
+ Name: string, active: boolean, where: string, name: string, basic: boolean
71
+ }): string {
72
+ const head = `# ${spec.Name} SDK utility: prepare_auth
73
+ require_relative 'struct/voxgig_struct'
74
+ module ${spec.Name}Utilities
75
+ `
76
+
77
+ const guard = ` PrepareAuth = ->(ctx) {
78
+ spec = ctx.spec
79
+ return nil, ctx.make_error("auth_no_spec", "Expected context spec property to be defined.") unless spec
80
+ `
81
+
82
+ // NO AUTH AT ALL. A public API's SDK gets a prepare_auth that is honest
83
+ // about it rather than one that deletes a header nobody set.
84
+ if (!spec.active) {
85
+ return head + ` # This API declares no authentication, so there is no credential to
86
+ # place. The utility stays in the pipeline because make_spec calls it
87
+ # unconditionally, and register.rb binds it unconditionally.
88
+ ${guard}
89
+ return spec, nil
90
+ }
91
+ end
92
+ `
93
+ }
94
+
95
+ const cookie = 'cookie' === spec.where
96
+ const query = 'query' === spec.where
97
+
98
+ // HTTP Basic is header-only by definition: the scheme is
99
+ // `Authorization: Basic base64(user:pass)`. It cannot be expressed as a
100
+ // query parameter or a cookie, so the branch is emitted only where it can
101
+ // mean something.
102
+ const basicHere = spec.basic && 'header' === spec.where
103
+
104
+ // The constant keeps the template's name per placement, so a
105
+ // header-based SDK regenerates the file it already had.
106
+ const CRED = query ? 'QUERY_AUTH' : cookie ? 'COOKIE_AUTH' : 'HEADER_AUTH'
107
+
108
+ // HEADER NAMES ARE LOWER-CASED; QUERY AND COOKIE NAMES ARE NOT.
109
+ //
110
+ // `resolveAuthName` answers 'Authorization' by default, but the whole rb
111
+ // runtime spells header names in lower case — the template's
112
+ // `HEADER_AUTH = "authorization"`, secrets_feature.rb's
113
+ // `headers["authorization"]`, debug_feature.rb's mask list. A Ruby Hash key
114
+ // is case-sensitive, so emitting "Authorization" here would leave the
115
+ // secrets feature writing a SECOND, separate header and the copied
116
+ // pipeline_test.rb assertions on `headers["authorization"]` failing. HTTP
117
+ // header names are case-insensitive on the wire, so lower-casing costs
118
+ // nothing. Query parameter and cookie names ARE case-sensitive (`?Token=`
119
+ // is not `?token=`), so those go in verbatim.
120
+ const credName = query || cookie ? spec.name : spec.name.toLowerCase()
121
+
122
+ const consts =
123
+ ` ${CRED} = ${rbstr(credName)}
124
+ ` +
125
+ (cookie ? ` HEADER_COOKIE = "cookie"
126
+ ` : '') +
127
+ ` OPTION_APIKEY = "apikey"
128
+ ` +
129
+ (basicHere ? ` OPTION_SECRET = "secret"
130
+ ` : '') +
131
+ ` NOT_FOUND = "__NOTFOUND__"
132
+
133
+ `
134
+
135
+ // The bag the credential lands in. A cookie rides the header bag, because
136
+ // a cookie IS a header.
137
+ const bag = query
138
+ ? ` query = spec.query
139
+ `
140
+ : ` headers = spec.headers
141
+ `
142
+
143
+ // Removing OUR pair, not the whole cookie header. The ts port deletes
144
+ // `headers[CRED_name]` for the cookie case, which is a header nothing ever
145
+ // set — so a stale cookie survives a withdrawn credential there. This
146
+ // splits the header, drops the one pair we own, and puts the rest back.
147
+ const dropCookie = !cookie ? '' : `
148
+ # Our own pair, and only ours: another cookie the caller set survives.
149
+ drop_cookie = ->(hs) {
150
+ cookie = hs[HEADER_COOKIE]
151
+ return unless cookie.is_a?(String)
152
+ rest = cookie.split("; ").reject { |pair| pair.start_with?("#{COOKIE_AUTH}=") }
153
+ if rest.empty?
154
+ hs.delete(HEADER_COOKIE)
155
+ else
156
+ hs[HEADER_COOKIE] = rest.join("; ")
157
+ end
158
+ }
159
+ `
160
+
161
+ const clear = cookie ? 'drop_cookie.call(headers)'
162
+ : query ? `query.delete(${CRED})`
163
+ : `headers.delete(${CRED})`
164
+
165
+ const preamble = guard + `
166
+ ` + bag + ` options = ctx.client.options_map
167
+ ` + dropCookie + `
168
+ # Public APIs that need no auth omit the options.auth block entirely.
169
+ if options["auth"].nil?
170
+ ${clear}
171
+ return spec, nil
172
+ end
173
+
174
+ apikey = VoxgigStruct.getprop(options, OPTION_APIKEY, NOT_FOUND)
175
+ `
176
+
177
+ const basicBlock = !basicHere ? '' : `
178
+ # True HTTP Basic Auth needs TWO credentials, base64-joined - a single
179
+ # token in the header (the branch below) can never authenticate against
180
+ # an API that actually checks \`Authorization: Basic base64(user:pass)\`.
181
+ if VoxgigStruct.getpath(options, "auth.basic") == true
182
+ secret = VoxgigStruct.getprop(options, OPTION_SECRET, NOT_FOUND)
183
+ no_apikey = apikey.nil? || !apikey.is_a?(String) || apikey == NOT_FOUND || apikey == ""
184
+ no_secret = secret.nil? || !secret.is_a?(String) || secret == NOT_FOUND || secret == ""
185
+
186
+ if no_apikey || no_secret
187
+ headers.delete(HEADER_AUTH)
188
+ else
189
+ auth_prefix = VoxgigStruct.getpath(options, "auth.prefix") || ""
190
+ # \`pack("m0")\` rather than \`Base64.strict_encode64\`: base64 left
191
+ # Ruby's default gems in 3.4, and pack is core.
192
+ b64 = ["#{apikey}:#{secret}"].pack("m0")
193
+ headers[HEADER_AUTH] =
194
+ auth_prefix.empty? ? b64 : "#{auth_prefix} #{b64}"
195
+ end
196
+
197
+ return spec, nil
198
+ end
199
+ `
200
+
201
+ return head + consts + preamble + basicBlock + place(spec.where, clear) + `
202
+ return spec, nil
203
+ }
204
+ end
205
+ `
206
+ }
207
+
208
+
209
+ // The one thing that actually differs between placements: where the
210
+ // credential is written, and whether the prefix travels with it.
211
+ function place(where: string, clear: string): string {
212
+ // NO PREFIX IN A QUERY STRING. `?token=Bearer%20abc` is not a thing any
213
+ // API reads; the prefix is a header convention and is dropped here
214
+ // deliberately rather than silently concatenated.
215
+ if ('query' === where) {
216
+ return `
217
+ if apikey.nil? || (apikey.is_a?(String) && (apikey == NOT_FOUND || apikey == ""))
218
+ ${clear}
219
+ else
220
+ apikey_val = apikey.is_a?(String) ? apikey : ""
221
+ # NO PREFIX IN A QUERY STRING: \`?token=Bearer%20abc\` is not a thing
222
+ # any API reads, so options.auth.prefix is dropped rather than joined.
223
+ query[QUERY_AUTH] = apikey_val
224
+ end
225
+ `
226
+ }
227
+
228
+ if ('cookie' === where) {
229
+ return `
230
+ # Dropped before writing, so a retry cannot accumulate the pair and a
231
+ # withdrawn credential leaves no stale cookie behind.
232
+ ${clear}
233
+
234
+ unless apikey.nil? || (apikey.is_a?(String) && (apikey == NOT_FOUND || apikey == ""))
235
+ apikey_val = apikey.is_a?(String) ? apikey : ""
236
+ # A cookie IS a header, so the pair is appended to the cookie header
237
+ # rather than clobbering it. No prefix: \`token=Bearer abc\` is not a
238
+ # cookie value any API reads.
239
+ existing = headers[HEADER_COOKIE]
240
+ pair = "#{COOKIE_AUTH}=#{apikey_val}"
241
+ headers[HEADER_COOKIE] =
242
+ (existing.is_a?(String) && !existing.empty?) ? "#{existing}; #{pair}" : pair
243
+ end
244
+ `
245
+ }
246
+
247
+ // HEADER: the template's body, unchanged.
248
+ return `
249
+ if apikey.nil? || (apikey.is_a?(String) && (apikey == NOT_FOUND || apikey == ""))
250
+ ${clear}
251
+ else
252
+ auth_prefix = VoxgigStruct.getpath(options, "auth.prefix") || ""
253
+ apikey_val = apikey.is_a?(String) ? apikey : ""
254
+ # Empty prefix (raw apiKey credential) must not add a leading space.
255
+ headers[HEADER_AUTH] =
256
+ auth_prefix.empty? ? apikey_val : "#{auth_prefix} #{apikey_val}"
257
+ end
258
+ `
259
+ }
260
+
261
+
262
+ // NOT `isAuthActive`, AND THE DIFFERENCE IS LOAD-BEARING (the py port found
263
+ // this first; same reasoning, same fix).
264
+ //
265
+ // `isAuthActive` is false whenever the SPEC declares no security scheme
266
+ // (`main.kit.info.auth: false`). That is a statement about the DEFINITION,
267
+ // not a ban on ever sending a credential: apidef writes it for every spec
268
+ // with no securitySchemes block, and those SDKs are still expected to honour
269
+ // an `apikey` the caller passes. The template placed the credential
270
+ // unconditionally, so they did.
271
+ //
272
+ // Gating the body on `isAuthActive` therefore does not trim dead code, it
273
+ // deletes working authentication. MEASURED, not assumed: with the wider gate
274
+ // this component emitted the no-op for generatedcompile's own fixture
275
+ // (`main: kit: info: { ... auth: false }`) and two running rb lanes went red
276
+ // —
277
+ //
278
+ // rb: auth null beats an explicit apikey
279
+ // FAIL: baseline broken: an ordinary apikey was not sent
280
+ // rb: the secrets feature runs with the feature active
281
+ // expected the authorization header to carry OPTKEY01, got: nil
282
+ //
283
+ // So the no-op is emitted only when the PROJECT says so: `config.auth.active:
284
+ // false`, an explicit per-SDK switch nobody sets by accident. A spec that is
285
+ // merely silent keeps the credential path it has always had.
286
+ function authSwitchedOn(model: any): boolean {
287
+ const auth = getModelPath(model, `main.${KIT}.config.auth`,
288
+ { only_active: false, required: false })
289
+ return !(null != auth && false === auth.active)
290
+ }
291
+
292
+
293
+ // A Ruby double-quoted literal. `#` is escaped only where it would OPEN an
294
+ // interpolation, matching utility_rb.formatRubyValue.
295
+ function rbstr(s: string): string {
296
+ return '"' + String(s)
297
+ .replace(/\\/g, '\\\\')
298
+ .replace(/"/g, '\\"')
299
+ .replace(/#(?=[{$@])/g, '\\#') + '"'
300
+ }
301
+
302
+
303
+ export {
304
+ PrepareAuth
305
+ }
@@ -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'
@@ -58,7 +60,45 @@ const Config = cmp(async function Config(props: any) {
58
60
  // slug/version/target identity fields (station descriptor input, mirrors
59
61
  // Config_ts) - both reps below render from this same def, so the data
60
62
  // and literal branches pick the fields up together.
61
- const { def: config, json: configJson } = configDefinition(model, target.name)
63
+ const { def: config, json: baseJson } = configDefinition(model, target.name)
64
+
65
+ // `in` and `name` TRAVEL WITH THE PREFIX NOW.
66
+ //
67
+ // apidef resolved both from the spec's securityScheme all along and this
68
+ // generator dropped them, so an apiKey-in-query API got an `authorization`
69
+ // header it does not read (see PrepareAuth_rust). The generated
70
+ // prepare_auth is built from the same two values, and the config carries
71
+ // them so the placement is a visible, overridable runtime option beside
72
+ // auth.prefix - which is also what keeps the SDK from rejecting its own
73
+ // config: the auth optspec in tm/rust/utility/make_options.rs is a CLOSED
74
+ // map, and an undeclared key there fails validate with "Unexpected keys at
75
+ // field auth".
76
+ //
77
+ // Emitted ONLY when they differ from header/Authorization, so a
78
+ // header-based SDK's config.rs is byte-identical to what it generated
79
+ // before. Both representations are patched through the one object, so the
80
+ // literal (formatRustValue) and the data rep (rustRawString) cannot
81
+ // disagree - the json is re-derived from the def, exactly as
82
+ // configDefinition derives it.
83
+ const authIn = resolveAuthIn(model)
84
+ const authName = resolveAuthName(model)
85
+ let configJson = baseJson
86
+
87
+ if (authActive && null != config.options && null != config.options.auth) {
88
+ let changed = false
89
+ if ('header' !== authIn) {
90
+ config.options.auth.in = authIn
91
+ changed = true
92
+ }
93
+ if ('Authorization' !== authName) {
94
+ config.options.auth.name = authName
95
+ changed = true
96
+ }
97
+ if (changed) {
98
+ configJson = JSON.stringify(config)
99
+ }
100
+ }
101
+
62
102
  const asData = isConfigData(configJson, configReprSetting(model))
63
103
 
64
104
  File({ name: 'config.' + target.ext }, () => {
@@ -24,6 +24,7 @@ import {
24
24
 
25
25
  import { Package } from './Package_rust'
26
26
  import { Config } from './Config_rust'
27
+ import { PrepareAuth } from './PrepareAuth_rust'
27
28
  import { Gitignore } from './Gitignore_rust'
28
29
  import { MainEntity } from './MainEntity_rust'
29
30
  import { EntityBase } from './EntityBase_rust'
@@ -67,6 +68,21 @@ const Main = cmp(async function Main(props: any) {
67
68
  }
68
69
  })
69
70
 
71
+ // utility/prepare_auth.rs is GENERATED, not templated: where the
72
+ // credential goes (header / query / cookie, and under what name) is a
73
+ // fact about the API, and tm/ can only hold one answer. See
74
+ // PrepareAuth_rust.
75
+ //
76
+ // AT ROOT LEVEL, and outside the `core` Folder below. The rust crate root
77
+ // IS the target root - lib.rs, core/, feature/ and utility/ all sit there
78
+ // - the component opens `utility` itself, and that is the same path
79
+ // `Copy({from:'tm/rust'})` used for the template it replaces. Calling it
80
+ // beside Config, inside `Folder({name:'core'})`, would emit
81
+ // core/utility/prepare_auth.rs instead: a file no module declares, so
82
+ // rustc never compiles it, while utility/mod.rs's `pub mod prepare_auth;`
83
+ // keeps binding whatever utility/ actually holds.
84
+ PrepareAuth({ target })
85
+
70
86
  // Generated core files: the client (sdk.rs), the API config and the
71
87
  // branded error type.
72
88
  Folder({ name: 'core' }, () => {