@voxgig/sdkgen 4.19.1 → 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 (106) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/sdkgen.d.ts +2 -2
  3. package/dist/sdkgen.js +6 -3
  4. package/dist/sdkgen.js.map +1 -1
  5. package/dist/tsconfig.tsbuildinfo +1 -1
  6. package/dist/utility.d.ts +4 -1
  7. package/dist/utility.js +60 -0
  8. package/dist/utility.js.map +1 -1
  9. package/model/sdkgen.aon +10 -0
  10. package/package.json +1 -1
  11. package/project/.sdk/src/cmp/c/Config_c.ts +15 -0
  12. package/project/.sdk/src/cmp/c/Main_c.ts +15 -0
  13. package/project/.sdk/src/cmp/c/PrepareAuth_c.ts +371 -0
  14. package/project/.sdk/src/cmp/clojure/Config_clojure.ts +47 -1
  15. package/project/.sdk/src/cmp/clojure/Main_clojure.ts +11 -1
  16. package/project/.sdk/src/cmp/clojure/PrepareAuth_clojure.ts +374 -0
  17. package/project/.sdk/src/cmp/cpp/Config_cpp.ts +40 -0
  18. package/project/.sdk/src/cmp/cpp/Main_cpp.ts +17 -0
  19. package/project/.sdk/src/cmp/cpp/PrepareAuth_cpp.ts +441 -0
  20. package/project/.sdk/src/cmp/csharp/Config_csharp.ts +42 -1
  21. package/project/.sdk/src/cmp/csharp/Main_csharp.ts +18 -0
  22. package/project/.sdk/src/cmp/csharp/PrepareAuth_csharp.ts +392 -0
  23. package/project/.sdk/src/cmp/elixir/Config_elixir.ts +36 -1
  24. package/project/.sdk/src/cmp/elixir/Main_elixir.ts +15 -0
  25. package/project/.sdk/src/cmp/elixir/PrepareAuth_elixir.ts +418 -0
  26. package/project/.sdk/src/cmp/go/Config_go.ts +12 -1
  27. package/project/.sdk/src/cmp/go/Main_go.ts +14 -0
  28. package/project/.sdk/src/cmp/go/PrepareAuth_go.ts +322 -0
  29. package/project/.sdk/src/cmp/java/Config_java.ts +20 -1
  30. package/project/.sdk/src/cmp/java/Main_java.ts +14 -0
  31. package/project/.sdk/src/cmp/java/PrepareAuth_java.ts +298 -0
  32. package/project/.sdk/src/cmp/js/Config_js.ts +12 -1
  33. package/project/.sdk/src/cmp/js/Main_js.ts +6 -0
  34. package/project/.sdk/src/cmp/js/PrepareAuth_js.ts +244 -0
  35. package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +23 -1
  36. package/project/.sdk/src/cmp/kotlin/Main_kotlin.ts +20 -0
  37. package/project/.sdk/src/cmp/kotlin/PrepareAuth_kotlin.ts +440 -0
  38. package/project/.sdk/src/cmp/lua/Config_lua.ts +15 -1
  39. package/project/.sdk/src/cmp/lua/Main_lua.ts +11 -0
  40. package/project/.sdk/src/cmp/lua/PrepareAuth_lua.ts +364 -0
  41. package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +31 -1
  42. package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +19 -0
  43. package/project/.sdk/src/cmp/ocaml/PrepareAuth_ocaml.ts +454 -0
  44. package/project/.sdk/src/cmp/perl/Config_perl.ts +30 -0
  45. package/project/.sdk/src/cmp/perl/Main_perl.ts +14 -0
  46. package/project/.sdk/src/cmp/perl/PrepareAuth_perl.ts +387 -0
  47. package/project/.sdk/src/cmp/php/Config_php.ts +12 -1
  48. package/project/.sdk/src/cmp/php/Main_php.ts +7 -0
  49. package/project/.sdk/src/cmp/php/PrepareAuth_php.ts +325 -0
  50. package/project/.sdk/src/cmp/py/Config_py.ts +12 -1
  51. package/project/.sdk/src/cmp/py/Main_py.ts +12 -0
  52. package/project/.sdk/src/cmp/py/PrepareAuth_py.ts +389 -0
  53. package/project/.sdk/src/cmp/rb/Config_rb.ts +18 -1
  54. package/project/.sdk/src/cmp/rb/Main_rb.ts +10 -0
  55. package/project/.sdk/src/cmp/rb/PrepareAuth_rb.ts +305 -0
  56. package/project/.sdk/src/cmp/rust/Config_rust.ts +41 -1
  57. package/project/.sdk/src/cmp/rust/Main_rust.ts +16 -0
  58. package/project/.sdk/src/cmp/rust/PrepareAuth_rust.ts +410 -0
  59. package/project/.sdk/src/cmp/scala/Config_scala.ts +21 -1
  60. package/project/.sdk/src/cmp/scala/Main_scala.ts +14 -0
  61. package/project/.sdk/src/cmp/scala/PrepareAuth_scala.ts +415 -0
  62. package/project/.sdk/src/cmp/swift/Config_swift.ts +37 -1
  63. package/project/.sdk/src/cmp/swift/Main_swift.ts +10 -0
  64. package/project/.sdk/src/cmp/swift/PrepareAuth_swift.ts +439 -0
  65. package/project/.sdk/src/cmp/ts/Config_ts.ts +12 -1
  66. package/project/.sdk/src/cmp/ts/Main_ts.ts +5 -0
  67. package/project/.sdk/src/cmp/ts/PrepareAuth_ts.ts +237 -0
  68. package/project/.sdk/src/cmp/zig/Config_zig.ts +33 -1
  69. package/project/.sdk/src/cmp/zig/Main_zig.ts +16 -0
  70. package/project/.sdk/src/cmp/zig/PrepareAuth_zig.ts +545 -0
  71. package/project/.sdk/tm/clojure/src/sdk/core.clj +31 -20
  72. package/project/.sdk/tm/cpp/utility/pipeline.hpp +36 -40
  73. package/project/.sdk/tm/csharp/utility/MakeOptions.cs +11 -0
  74. package/project/.sdk/tm/elixir/lib/projectname/utility.ex +19 -32
  75. package/project/.sdk/tm/java/utility/MakeOptions.java +13 -1
  76. package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +14 -1
  77. package/project/.sdk/tm/kotlin/utility/Prepare.kt +13 -46
  78. package/project/.sdk/tm/ocaml/Makefile +11 -1
  79. package/project/.sdk/tm/ocaml/sdk_helpers.ml +15 -0
  80. package/project/.sdk/tm/ocaml/sdk_runtime.ml +31 -25
  81. package/project/.sdk/tm/ocaml/test/feature/secrets/t_secrets.ml +125 -12
  82. package/project/.sdk/tm/ocaml/test/t_pipeline.ml +64 -6
  83. package/project/.sdk/tm/perl/utility/make_options.pm +10 -1
  84. package/project/.sdk/tm/php/utility/MakeOptions.php +8 -1
  85. package/project/.sdk/tm/rust/utility/make_options.rs +13 -1
  86. package/project/.sdk/tm/scala/utility/Make.scala +14 -1
  87. package/project/.sdk/tm/scala/utility/Prepare.scala +16 -40
  88. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +30 -3
  89. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +21 -39
  90. package/project/.sdk/tm/zig/core/utility.zig +37 -45
  91. package/project/.sdk/tm/zig/test/pipeline_test.zig +34 -0
  92. package/project/sdkgen-package.json +1 -1
  93. package/src/sdkgen.ts +4 -1
  94. package/src/utility.ts +75 -0
  95. package/project/.sdk/tm/c/utility/prepare_auth.c +0 -65
  96. package/project/.sdk/tm/csharp/utility/PrepareAuth.cs +0 -54
  97. package/project/.sdk/tm/go/utility/prepare_auth.go +0 -59
  98. package/project/.sdk/tm/java/utility/PrepareAuth.java +0 -66
  99. package/project/.sdk/tm/js/src/utility/PrepareAuthUtility.js +0 -49
  100. package/project/.sdk/tm/lua/utility/prepare_auth.lua +0 -52
  101. package/project/.sdk/tm/perl/utility/prepare_auth.pm +0 -56
  102. package/project/.sdk/tm/php/utility/PrepareAuth.php +0 -45
  103. package/project/.sdk/tm/py/pkg/utility/prepare_auth.py +0 -46
  104. package/project/.sdk/tm/rb/utility/prepare_auth.rb +0 -35
  105. package/project/.sdk/tm/rust/utility/prepare_auth.rs +0 -65
  106. package/project/.sdk/tm/ts/src/utility/PrepareAuthUtility.ts +0 -78
@@ -14,6 +14,8 @@ import {
14
14
  indent,
15
15
  isAuthActive,
16
16
  isConfigData,
17
+ resolveAuthIn,
18
+ resolveAuthName,
17
19
  resolveAuthPrefix,
18
20
  serverVariables,
19
21
  targetFeatures,
@@ -52,9 +54,18 @@ const Config = cmp(async function Config(props: any) {
52
54
  const authActive = isAuthActive(model)
53
55
  // config.auth.prefix override -> spec-derived info.security.prefix -> 'Bearer'
54
56
  const authPrefix = resolveAuthPrefix(model)
57
+ // `in` and `name` travel with the prefix now. They were resolved by
58
+ // apidef all along and dropped here, so an apiKey-in-query API got an
59
+ // Authorization header it does not read. Emitted only when they differ
60
+ // from the defaults, so a header/Authorization SDK is byte-identical to
61
+ // what it generated before.
62
+ const authIn = resolveAuthIn(model)
63
+ const authName = resolveAuthName(model)
55
64
  const authBlock = authActive
56
65
  ? `auth: {
57
- prefix: '${authPrefix}',
66
+ prefix: '${authPrefix}',${'header' === authIn ? '' : `
67
+ in: '${authIn}',`}${'Authorization' === authName ? '' : `
68
+ name: '${authName}',`}
58
69
  },
59
70
 
60
71
  `
@@ -28,6 +28,7 @@ import { Schema } from './Schema_js'
28
28
  import { Gitignore } from './Gitignore_js'
29
29
  import { MainEntity } from './MainEntity_js'
30
30
  import { SdkError } from './SdkError_js'
31
+ import { PrepareAuth } from './PrepareAuth_js'
31
32
  import { EntityBase } from './EntityBase_js'
32
33
  import { EntityTypes } from './EntityTypes_js'
33
34
 
@@ -194,6 +195,11 @@ if (fres instanceof Promise) { await fres }
194
195
  })
195
196
 
196
197
  Config({ target })
198
+
199
+ // GENERATED, NOT COPIED. Where the credential goes is a fact about the
200
+ // API, and tm/ can only hold one answer. See PrepareAuth_js.
201
+ PrepareAuth({ target })
202
+
197
203
  Schema({ target })
198
204
 
199
205
  EntityBase({ target })
@@ -0,0 +1,244 @@
1
+
2
+ import {
3
+ Content,
4
+ File,
5
+ Folder,
6
+ cmp,
7
+ isHttpBasicAuth,
8
+ resolveAuthIn,
9
+ resolveAuthName,
10
+ resolveAuthPrefix,
11
+ } from '@voxgig/sdkgen'
12
+
13
+
14
+ import {
15
+ KIT,
16
+ getModelPath,
17
+ } from '@voxgig/apidef'
18
+
19
+
20
+ // WHERE THE CREDENTIAL GOES IS A FACT ABOUT THE API, so it is generated
21
+ // rather than templated.
22
+ //
23
+ // This was a static file at `tm/js/src/utility/PrepareAuthUtility.js` that
24
+ // hardcoded `authorization` and a header. apidef has always resolved the
25
+ // scheme's `in` and `name` into `main.kit.info.security` — joplin's says
26
+ // `in: "query", name: "token"` — and generation dropped both. The result
27
+ // was an SDK that sent a header the API does not read and never sent the
28
+ // query parameter it does, so it could not authenticate at all. Four
29
+ // repos in the cedar fleet shipped that way: joplin (`token`), pipedrive
30
+ // (`api_token`), trello (`key`), lm-umbrella (`apiKey`).
31
+ //
32
+ // A template cannot fix this, because the three placements need three
33
+ // different bodies and a template has to pick one. A component emits the
34
+ // branch this API actually uses and nothing else — no dead query code in
35
+ // a bearer-token SDK, and no runtime `if` on a value that is fixed at
36
+ // generation time.
37
+ //
38
+ // Ported from PrepareAuth_ts, which is the proven shape. The differences
39
+ // are the language's, not the design's: no type import, `module.exports`
40
+ // instead of `export {}`, and the prefix read inline off `options.auth`
41
+ // exactly as the js template read it, rather than hoisted into a local
42
+ // that the query and cookie bodies would leave unused.
43
+ const PrepareAuth = cmp(async function PrepareAuth(props: any) {
44
+ const { target } = props
45
+ const { model } = props.ctx$
46
+
47
+ const active = isAuthActive_js(model)
48
+ const where = resolveAuthIn(model)
49
+ // LOWERCASED FOR A HEADER, VERBATIM OTHERWISE. The js runtime keys its
50
+ // header map in lower case — the old template hardcoded 'authorization',
51
+ // the shared corpus asserts ctx:spec:headers:authorization, and every
52
+ // generatedcompile probe reads the lower-case key. apidef writes
53
+ // name: "Authorization", so emitting it verbatim hides the credential
54
+ // under a key nothing reads. Query parameters and cookies ARE
55
+ // case-sensitive and keep the spec's spelling.
56
+ const resolvedName = resolveAuthName(model)
57
+ const name = 'header' === where ? resolvedName.toLowerCase() : resolvedName
58
+ const prefix = resolveAuthPrefix(model)
59
+ const basic = isHttpBasicAuth(model)
60
+
61
+ // No `src` folder here: Main_js already opened it, and Config, Schema,
62
+ // SdkError, EntityBase and EntityTypes all write straight into it. The
63
+ // template this replaces lived at `tm/js/src/utility/`, so relative to
64
+ // that open folder the file needs `utility` and nothing more. Opening a
65
+ // second `src` would put it at src/src/utility/ — where nothing imports
66
+ // it, and the stale copy at src/utility/ keeps being used.
67
+ Folder({ name: 'utility' }, () => {
68
+ File({ name: 'PrepareAuthUtility.' + target.ext }, () => {
69
+ Content(render({ active, where, name, prefix, basic }))
70
+ })
71
+ })
72
+ })
73
+
74
+
75
+ function render(spec: {
76
+ active: boolean, where: string, name: string, prefix: string, basic: boolean
77
+ }): string {
78
+
79
+ // NO AUTH AT ALL. A public API's SDK gets a prepareAuth that is honest
80
+ // about it rather than one that deletes a header nobody set.
81
+ if (!spec.active) {
82
+ return `
83
+ // This API declares no authentication, so there is no credential to
84
+ // place. The function stays in the pipeline because makeSpec calls it
85
+ // unconditionally.
86
+ function prepareAuth(ctx) {
87
+ const spec = ctx.spec
88
+
89
+ if (null == spec) {
90
+ return ctx.error('auth_no_spec', 'Expected context spec property to be defined.')
91
+ }
92
+
93
+ return spec
94
+ }
95
+
96
+ module.exports = {
97
+ prepareAuth
98
+ }
99
+ `
100
+ }
101
+
102
+ const preamble = `
103
+ const CRED_name = '${jsstr(spec.name)}'
104
+
105
+ const OPTION_apikey = 'apikey'${spec.basic && 'header' === spec.where ? `
106
+ const OPTION_secret = 'secret'` : ''}
107
+
108
+ const NOTFOUND = '__NOTFOUND__'
109
+
110
+ function prepareAuth(ctx) {
111
+ const utility = ctx.utility
112
+
113
+ const struct = utility.struct
114
+ const getprop = struct.getprop
115
+ const setprop = struct.setprop
116
+ const delprop = struct.delprop
117
+
118
+ const client = ctx.client
119
+ const spec = ctx.spec
120
+
121
+ if (null == spec) {
122
+ return ctx.error('auth_no_spec', 'Expected context spec property to be defined.')
123
+ }
124
+
125
+ const ${bag(spec.where)} = spec.${bag(spec.where)}
126
+
127
+ const options = client.options()
128
+
129
+ // Public APIs that need no auth omit the options.auth block entirely.
130
+ if (null == options.auth) {
131
+ ${clear(spec.where)}
132
+ return spec
133
+ }
134
+
135
+ const apikey = getprop(options, OPTION_apikey, NOTFOUND)
136
+ `
137
+
138
+ // HTTP Basic is header-only by definition: the scheme is
139
+ // `Authorization: Basic base64(user:pass)`. It cannot be expressed as a
140
+ // query parameter or a cookie, so the branch is emitted only where it
141
+ // can mean something.
142
+ const basicBlock = (spec.basic && 'header' === spec.where) ? `
143
+ // True HTTP Basic Auth needs TWO credentials, base64-joined - a single
144
+ // token in the header (the branch below) can never authenticate against
145
+ // an API that actually checks \`Authorization: Basic base64(user:pass)\`.
146
+ if (true === options.auth.basic) {
147
+ const secret = getprop(options, OPTION_secret, NOTFOUND)
148
+ const noApikey = NOTFOUND === apikey || null == apikey || '' === apikey
149
+ const noSecret = NOTFOUND === secret || null == secret || '' === secret
150
+
151
+ if (noApikey || noSecret) {
152
+ delprop(headers, CRED_name)
153
+ }
154
+ else {
155
+ const b64 = Buffer.from(apikey + ':' + secret).toString('base64')
156
+ setprop(headers, CRED_name,
157
+ options.auth.prefix ? options.auth.prefix + ' ' + b64 : b64)
158
+ }
159
+
160
+ return spec
161
+ }
162
+ ` : ''
163
+
164
+ return preamble + basicBlock + `
165
+ if (NOTFOUND === apikey || null == apikey || '' === apikey) {
166
+ ${clear(spec.where)}
167
+ }
168
+ else {
169
+ ${place(spec.where)}
170
+ }
171
+
172
+ return spec
173
+ }
174
+
175
+ module.exports = {
176
+ prepareAuth
177
+ }
178
+ `
179
+ }
180
+
181
+
182
+ // The bag the credential lands in, per placement. Cookies ride the header
183
+ // bag because a cookie IS a header.
184
+ function bag(where: string): string {
185
+ return 'query' === where ? 'query' : 'headers'
186
+ }
187
+
188
+
189
+ function clear(where: string): string {
190
+ return 'query' === where ? 'delprop(query, CRED_name)' : 'delprop(headers, CRED_name)'
191
+ }
192
+
193
+
194
+ function place(where: string): string {
195
+ if ('query' === where) {
196
+ // NO PREFIX IN A QUERY STRING. `?token=Bearer%20abc` is not a thing any
197
+ // API reads; the prefix is a header convention and is dropped here
198
+ // deliberately rather than silently concatenated.
199
+ return ` setprop(query, CRED_name, apikey)`
200
+ }
201
+
202
+ if ('cookie' === where) {
203
+ // APPEND, never clobber: the request may already carry a session
204
+ // cookie set from options.headers, and a cookie header holds a
205
+ // '; '-joined list of pairs.
206
+ return ` const existing = getprop(headers, 'cookie', '')
207
+ const pair = CRED_name + '=' + apikey
208
+ setprop(headers, 'cookie', existing ? existing + '; ' + pair : pair)`
209
+ }
210
+
211
+ return ` // Empty prefix (raw apiKey credential) must not add a leading space.
212
+ setprop(headers, CRED_name,
213
+ options.auth.prefix ? options.auth.prefix + ' ' + apikey : apikey)`
214
+ }
215
+
216
+
217
+ function jsstr(s: string): string {
218
+ return String(s).replace(/\\/g, '\\\\').replace(/'/g, "\\'")
219
+ }
220
+
221
+
222
+ export {
223
+ PrepareAuth
224
+ }
225
+
226
+
227
+ // NOT `isAuthActive`, AND THE DIFFERENCE IS LOAD-BEARING. That helper is
228
+ // also false whenever the SPEC declares no security scheme
229
+ // (`main.kit.info.auth: false`) — a statement about the DEFINITION, not a
230
+ // ban on ever sending a credential. `optspec` still declares `apikey` and
231
+ // makeOptions fills `options.auth` from its defaults, so the runtime
232
+ // `options.auth == null` guard never fired and those SDKs have always sent
233
+ // the credential. Gating the body on `isAuthActive` does not trim dead
234
+ // code, it removes working authentication — which
235
+ // `js: auth null suppresses the credential` catches, and which takes the
236
+ // secrets feature down with it.
237
+ //
238
+ // `main.kit.config.auth.active: false` is the project saying "no credential,
239
+ // ever", and it is the only signal that can be honoured before runtime.
240
+ function isAuthActive_js(model: any): boolean {
241
+ const auth = getModelPath(model, `main.${KIT}.config.auth`,
242
+ { only_active: false, required: false })
243
+ return !(null != auth && false === auth.active)
244
+ }
@@ -6,6 +6,9 @@ import {
6
6
  configDefinition,
7
7
  each,
8
8
  isAuthActive,
9
+ isHttpBasicAuth,
10
+ resolveAuthIn,
11
+ resolveAuthName,
9
12
  resolveAuthPrefix,
10
13
  targetFeatures,
11
14
  } from '@voxgig/sdkgen'
@@ -46,6 +49,17 @@ const Config = cmp(async function Config(props: any) {
46
49
 
47
50
  const authActive = isAuthActive(model)
48
51
  const authPrefix = resolveAuthPrefix(model)
52
+ const authBasic = isHttpBasicAuth(model)
53
+ // `in` and `name` travel with the prefix now. apidef resolved both all
54
+ // along, into main.kit.info.security, and this emitter dropped them - so
55
+ // an apiKey-in-query API got an Authorization header it does not read.
56
+ // The generated utility/PrepareAuth.kt is built from the same two values.
57
+ //
58
+ // Emitted only when they DIFFER from the defaults, so a
59
+ // header/Authorization SDK's Config.kt is byte-identical to what it
60
+ // generated before.
61
+ const authIn = resolveAuthIn(model)
62
+ const authName = resolveAuthName(model)
49
63
 
50
64
  let baseUrl = ''
51
65
  try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
@@ -74,7 +88,15 @@ const Config = cmp(async function Config(props: any) {
74
88
  base: baseUrl,
75
89
  }
76
90
  if (authActive) {
77
- options.auth = { prefix: authPrefix }
91
+ const auth: Record<string, any> = { prefix: authPrefix }
92
+ // `basic` joins them for the same reason: the generated prepareAuth
93
+ // emits the base64(user:pass) branch only for a spec-declared HTTP
94
+ // Basic scheme, and that branch reads this option at runtime - without
95
+ // it the branch could never fire.
96
+ if (authBasic) { auth.basic = true }
97
+ if ('header' !== authIn) { auth.in = authIn }
98
+ if ('Authorization' !== authName) { auth.name = authName }
99
+ options.auth = auth
78
100
  }
79
101
  options.headers = headers
80
102
  options.entity = optionsEntity
@@ -27,6 +27,7 @@ import { MainEntity } from './MainEntity_kotlin'
27
27
  import { EntityBase } from './EntityBase_kotlin'
28
28
  import { EntityTypes } from './EntityTypes_kotlin'
29
29
  import { SdkError } from './SdkError_kotlin'
30
+ import { PrepareAuth } from './PrepareAuth_kotlin'
30
31
  import { kotlinPackage } from './utility_kotlin'
31
32
 
32
33
 
@@ -88,6 +89,25 @@ const Main = cmp(async function Main(props: any) {
88
89
  // Shared entity runtime (entity/EntityBase.kt).
89
90
  EntityBase({ target })
90
91
 
92
+ // utility/PrepareAuth.kt. GENERATED, NOT COPIED: where the credential
93
+ // goes - header, query parameter or cookie, under the name the spec gives
94
+ // - is a fact about the API, and tm/ can only hold one answer. It was
95
+ // embedded in tm/kotlin/utility/Prepare.kt among the other prepare*
96
+ // helpers, hardcoding an `authorization` header; that one function has
97
+ // moved out into its own compilation unit in the same package, so
98
+ // Register.kt's `u.prepareAuth = ::prepareAuth` binds it unchanged.
99
+ //
100
+ // Called HERE, at Main's TOP LEVEL, and deliberately NOT inside the
101
+ // `core` Folder below. The kotlin tree is FLAT: build.gradle.kts declares
102
+ // core/, utility/, feature/ and entity/ as four sibling source roots, and
103
+ // the Copy above lands tm/kotlin/utility/* at <out>/utility/. The
104
+ // component opens `utility` itself, exactly as EntityBase opens `entity`.
105
+ // Nested in `core` it would write core/utility/PrepareAuth.kt - which
106
+ // still COMPILES, because core/ is scanned recursively and the package
107
+ // declaration is what resolves the symbol, so the misfiling would be
108
+ // invisible to every check. See PrepareAuth_kotlin.
109
+ PrepareAuth({ target })
110
+
91
111
  // Generate the client class and config in core/.
92
112
  Folder({ name: 'core' }, () => {
93
113