@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
@@ -0,0 +1,237 @@
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.
17
+ //
18
+ // This was a static file in `tm/ts/src/utility/` that hardcoded
19
+ // `Authorization` and a header. apidef has always resolved the scheme's
20
+ // `in` and `name` into `main.kit.info.security` — joplin's says
21
+ // `in: "query", name: "token"` — and generation dropped both. The result
22
+ // was an SDK that sent a header the API does not read and never sent the
23
+ // query parameter it does, so it could not authenticate at all. Four
24
+ // repos in the cedar fleet shipped that way: joplin (`token`), pipedrive
25
+ // (`api_token`), 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
30
+ // a bearer-token SDK, and no runtime `if` on a value that is fixed at
31
+ // generation time.
32
+ const PrepareAuth = cmp(async function PrepareAuth(props: any) {
33
+ const { target } = props
34
+ const { model } = props.ctx$
35
+
36
+ // The ONE signal that can honestly be honoured before runtime: the
37
+ // project saying "this SDK sends no credential, ever". Not
38
+ // `isAuthActive`, which is also false when the SPEC merely declares no
39
+ // scheme — those SDKs have always sent options.apikey.
40
+ const suppressed = isAuthSuppressed(model)
41
+ const where = resolveAuthIn(model)
42
+ // LOWERCASED FOR A HEADER, VERBATIM OTHERWISE. HTTP header names are
43
+ // case-insensitive on the wire, but the SDK's header map is a plain
44
+ // object keyed in lower case: the old template hardcoded
45
+ // `'authorization'`, the shared corpus asserts
46
+ // `ctx:spec:headers:authorization`, and every generatedcompile probe
47
+ // reads the lower-case key. apidef writes `name: "Authorization"`, so
48
+ // emitting it verbatim puts the credential under a key nothing reads.
49
+ // A query parameter and a cookie ARE case-sensitive, so they keep the
50
+ // spec's spelling exactly.
51
+ const resolvedName = resolveAuthName(model)
52
+ const name = 'header' === where ? resolvedName.toLowerCase() : resolvedName
53
+ const prefix = resolveAuthPrefix(model)
54
+ const basic = isHttpBasicAuth(model)
55
+
56
+ // No `src` folder here: Main already opened it, and Config and SdkError
57
+ // write straight into it. Opening a second one puts the file at
58
+ // src/src/utility/ — where nothing imports it, and the stale copy at
59
+ // src/utility/ keeps being used.
60
+ Folder({ name: 'utility' }, () => {
61
+ File({ name: 'PrepareAuthUtility.' + target.ext }, () => {
62
+ Content(render({ suppressed, where, name, prefix, basic }))
63
+ })
64
+ })
65
+ })
66
+
67
+
68
+ function render(spec: {
69
+ suppressed: boolean, where: string, name: string, prefix: string, basic: boolean
70
+ }): string {
71
+ const head = `
72
+ import { Context, Spec } from '../types'
73
+
74
+ `
75
+
76
+ // NO GENERATION-TIME GATE ON WHETHER TO PLACE A CREDENTIAL AT ALL.
77
+ //
78
+ // The obvious move is to emit a no-op when `isAuthActive(model)` is
79
+ // false, and it is wrong. That is false whenever `main.kit.info.auth`
80
+ // is false — i.e. the SPEC declares no security scheme — but the SDK
81
+ // still carries a credential: `optspec` always declares `apikey`, and
82
+ // makeOptions fills `options.auth` from the optspec defaults, so the
83
+ // template's `null == options.auth` guard never actually fired and
84
+ // every such SDK has always sent `options.apikey`. Suppressing that at
85
+ // generation time silently breaks a working credential, which
86
+ // `auth null suppresses the credential` in generatedcompile catches,
87
+ // and takes the secrets feature down with it — the feature resolves a
88
+ // secret into options.apikey and prepareAuth then places nothing.
89
+ //
90
+ // `auth: null` is the DOCUMENTED suppression, it is a runtime value,
91
+ // and the runtime guard below is the one that honours it.
92
+
93
+ // Auth switched off outright by the project. The credential-placing
94
+ // body would be dead code, so it is not emitted — but the function
95
+ // stays, because makeSpec calls it unconditionally.
96
+ if (spec.suppressed) {
97
+ return head + `
98
+ function prepareAuth(ctx: Context): Spec | Error {
99
+ const spec = ctx.spec
100
+
101
+ if (null == spec) {
102
+ return ctx.error('auth_no_spec', 'Expected context spec property to be defined.')
103
+ }
104
+
105
+ return spec
106
+ }
107
+
108
+
109
+ export {
110
+ prepareAuth
111
+ }
112
+ `
113
+ }
114
+
115
+ const preamble = `
116
+ const CRED_name = '${jsstr(spec.name)}'
117
+
118
+ const OPTION_apikey = 'apikey'
119
+ const OPTION_secret = 'secret'
120
+
121
+ const NOTFOUND = '__NOTFOUND__'
122
+
123
+
124
+ function prepareAuth(ctx: Context): Spec | Error {
125
+ const utility = ctx.utility
126
+
127
+ const struct = utility.struct
128
+ const getprop = struct.getprop
129
+ const setprop = struct.setprop
130
+ const delprop = struct.delprop
131
+
132
+ const client = ctx.client
133
+ const spec = ctx.spec
134
+
135
+ if (null == spec) {
136
+ return ctx.error('auth_no_spec', 'Expected context spec property to be defined.')
137
+ }
138
+
139
+ const ${target(spec.where)} = spec.${target(spec.where)}
140
+
141
+ const options = client.options()
142
+
143
+ // Public APIs that need no auth omit the options.auth block entirely.
144
+ if (null == options.auth) {
145
+ ${clear(spec.where)}
146
+ return spec
147
+ }
148
+
149
+ const prefix = options.auth.prefix
150
+
151
+ const apikey = getprop(options, OPTION_apikey, NOTFOUND)
152
+ `
153
+
154
+ // HTTP Basic is header-only by definition: the scheme is
155
+ // `Authorization: Basic base64(user:pass)`. It cannot be expressed as a
156
+ // query parameter or a cookie, so the branch is emitted only where it
157
+ // can mean something.
158
+ const basicBlock = (spec.basic && 'header' === spec.where) ? `
159
+ // True HTTP Basic Auth needs TWO credentials, base64-joined - a single
160
+ // token in the header (the branch below) can never authenticate against
161
+ // an API that actually checks \`Authorization: Basic base64(user:pass)\`.
162
+ if (true === options.auth.basic) {
163
+ const secret = getprop(options, OPTION_secret, NOTFOUND)
164
+ const noApikey = NOTFOUND === apikey || null == apikey || '' === apikey
165
+ const noSecret = NOTFOUND === secret || null == secret || '' === secret
166
+
167
+ if (noApikey || noSecret) {
168
+ delprop(headers, CRED_name)
169
+ }
170
+ else {
171
+ const b64 = Buffer.from(apikey + ':' + secret).toString('base64')
172
+ setprop(headers, CRED_name, prefix ? prefix + ' ' + b64 : b64)
173
+ }
174
+
175
+ return spec
176
+ }
177
+ ` : ''
178
+
179
+ return head + preamble + basicBlock + `
180
+ if (NOTFOUND === apikey || null == apikey || '' === apikey) {
181
+ ${clear(spec.where)}
182
+ }
183
+ else {
184
+ ${place(spec.where)}
185
+ }
186
+
187
+ return spec
188
+ }
189
+
190
+
191
+ export {
192
+ prepareAuth
193
+ }
194
+ `
195
+ }
196
+
197
+
198
+ // The bag the credential lands in, per placement. Cookies ride the header
199
+ // bag because a cookie IS a header.
200
+ function target(where: string): string {
201
+ return 'query' === where ? 'query' : 'headers'
202
+ }
203
+
204
+
205
+ function clear(where: string): string {
206
+ return 'query' === where ? 'delprop(query, CRED_name)' : 'delprop(headers, CRED_name)'
207
+ }
208
+
209
+
210
+ function place(where: string): string {
211
+ if ('query' === where) {
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
+ return ` setprop(query, CRED_name, apikey)`
216
+ }
217
+
218
+ if ('cookie' === where) {
219
+ return ` const existing = getprop(headers, 'cookie', '')
220
+ const pair = CRED_name + '=' + apikey
221
+ setprop(headers, 'cookie', existing ? existing + '; ' + pair : pair)`
222
+ }
223
+
224
+ return ` // A raw credential (empty prefix, e.g. an apiKey scheme) must go in
225
+ // as-is; only a non-empty prefix (Bearer/Basic/OAuth) is space-joined.
226
+ setprop(headers, CRED_name, prefix ? prefix + ' ' + apikey : apikey)`
227
+ }
228
+
229
+
230
+ function jsstr(s: string): string {
231
+ return String(s).replace(/\\/g, '\\\\').replace(/'/g, "\\'")
232
+ }
233
+
234
+
235
+ export {
236
+ PrepareAuth
237
+ }
@@ -9,6 +9,8 @@ import {
9
9
  each,
10
10
  isAuthActive,
11
11
  isConfigData,
12
+ resolveAuthIn,
13
+ resolveAuthName,
12
14
  targetFeatures,
13
15
  } from '@voxgig/sdkgen'
14
16
 
@@ -46,7 +48,37 @@ const Config = cmp(async function Config(props: any) {
46
48
  // omitted entirely. Passing target.name opts this target into the main
47
49
  // slug/version/target identity fields (read by station's descriptor -
48
50
  // see configDefinition).
49
- const { def: config, json: configJson } = configDefinition(model, target.name)
51
+ const { def: config } = configDefinition(model, target.name)
52
+
53
+ // WHERE the credential goes and UNDER WHAT NAME travel with the prefix
54
+ // now. apidef resolved both from the spec's securityScheme all along and
55
+ // generation dropped them, so an apiKey-in-query API got an authorization
56
+ // header it does not read. Emitted ONLY when they differ from the
57
+ // defaults, so every header/Authorization SDK's core/config.zig is
58
+ // byte-identical to what it generated before.
59
+ //
60
+ // Written onto configDefinition's OWN def rather than into a hand-built
61
+ // options literal, and the JSON re-serialised from that same def below -
62
+ // so this target's two representations (the h.jo(...) literal and the
63
+ // embedded CONFIG_DATA string above the size threshold) cannot disagree
64
+ // about where the credential goes. Both render from `config`.
65
+ //
66
+ // make_options_util's optspec must declare the same two keys or this is
67
+ // worse than inert: validate is CLOSED and discards the whole merged
68
+ // options object on an undeclared key. tm/zig/core/utility.zig carries
69
+ // them.
70
+ const authIn = resolveAuthIn(model)
71
+ const authName = resolveAuthName(model)
72
+ if (null != config.options && null != config.options.auth) {
73
+ if ('header' !== authIn) {
74
+ config.options.auth.in = authIn
75
+ }
76
+ if ('Authorization' !== authName) {
77
+ config.options.auth.name = authName
78
+ }
79
+ }
80
+
81
+ const configJson = JSON.stringify(config)
50
82
  const asData = isConfigData(configJson, configReprSetting(model))
51
83
 
52
84
  File({ name: 'config.' + target.ext }, () => {
@@ -24,6 +24,7 @@ import { Config, FeaturePlugins, BUILTIN_FEATURES } from './Config_zig'
24
24
  import { Gitignore } from './Gitignore_zig'
25
25
  import { MainEntity } from './MainEntity_zig'
26
26
  import { Package } from './Package_zig'
27
+ import { PrepareAuth } from './PrepareAuth_zig'
27
28
 
28
29
 
29
30
  // Which features ship a zig test suite under test/feature/<name>/, and the
@@ -259,6 +260,21 @@ const Main = cmp(async function Main(props: any) {
259
260
  // branded error type (error.zig) is a plain template (copied above).
260
261
  Folder({ name: 'core' }, () => {
261
262
 
263
+ // core/prepare_auth.zig is GENERATED, not copied from tm/zig: where the
264
+ // credential goes (header / query / cookie, and under what name) is a
265
+ // fact about the API, and the template it was extracted from -
266
+ // tm/zig/core/utility.zig - could only hold one answer. See
267
+ // PrepareAuth_zig.
268
+ //
269
+ // INSIDE THIS `core` FOLDER, and the component opens none of its own -
270
+ // the Config_zig arrangement, for the same reason. The extracted body
271
+ // lived in core/utility.zig, which `Copy({from: 'tm/zig'})` lands at
272
+ // `<root>/core/`, and core/utility.zig re-exports the function with a
273
+ // SIBLING-relative `@import("prepare_auth.zig")`. A second Folder here
274
+ // would write core/core/prepare_auth.zig, which that import cannot
275
+ // reach and `zig build` never analyses.
276
+ PrepareAuth({ target })
277
+
262
278
  File({ name: 'sdk.' + target.ext }, () => {
263
279
 
264
280
  Fragment(