@voxgig/sdkgen 4.6.0 → 4.8.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 (144) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/Feature.js +5 -0
  3. package/dist/cmp/Feature.js.map +1 -1
  4. package/dist/cmp/TestControl.d.ts +4 -0
  5. package/dist/cmp/TestControl.js +51 -0
  6. package/dist/cmp/TestControl.js.map +1 -0
  7. package/dist/helpers/featureSource.d.ts +3 -1
  8. package/dist/helpers/featureSource.js +105 -0
  9. package/dist/helpers/featureSource.js.map +1 -1
  10. package/dist/helpers/opShape.js +8 -11
  11. package/dist/helpers/opShape.js.map +1 -1
  12. package/dist/helpers/pointPath.d.ts +10 -0
  13. package/dist/helpers/pointPath.js +54 -0
  14. package/dist/helpers/pointPath.js.map +1 -0
  15. package/dist/sdkgen.d.ts +6 -3
  16. package/dist/sdkgen.js +14 -4
  17. package/dist/sdkgen.js.map +1 -1
  18. package/dist/tsconfig.tsbuildinfo +1 -1
  19. package/dist/utility.d.ts +2 -1
  20. package/dist/utility.js +78 -1
  21. package/dist/utility.js.map +1 -1
  22. package/model/sdkgen.aon +58 -0
  23. package/package.json +2 -2
  24. package/project/.sdk/model/feature/secrets.aon +82 -0
  25. package/project/.sdk/src/cmp/c/Config_c.ts +7 -8
  26. package/project/.sdk/src/cmp/c/TestDirect_c.ts +4 -3
  27. package/project/.sdk/src/cmp/cpp/Main_cpp.ts +2 -1
  28. package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +4 -3
  29. package/project/.sdk/src/cmp/cpp/Test_cpp.ts +5 -1
  30. package/project/.sdk/src/cmp/csharp/Main_csharp.ts +2 -1
  31. package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +34 -9
  32. package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +29 -5
  33. package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -1
  34. package/project/.sdk/src/cmp/dart/Config_dart.ts +7 -8
  35. package/project/.sdk/src/cmp/dart/Main_dart.ts +2 -1
  36. package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +28 -10
  37. package/project/.sdk/src/cmp/dart/TestEntity_dart.ts +28 -7
  38. package/project/.sdk/src/cmp/dart/Test_dart.ts +5 -1
  39. package/project/.sdk/src/cmp/elixir/Config_elixir.ts +9 -8
  40. package/project/.sdk/src/cmp/go/Config_go.ts +1 -7
  41. package/project/.sdk/src/cmp/go/Main_go.ts +2 -1
  42. package/project/.sdk/src/cmp/go/TestDirect_go.ts +5 -4
  43. package/project/.sdk/src/cmp/go/Test_go.ts +5 -1
  44. package/project/.sdk/src/cmp/java/Config_java.ts +7 -7
  45. package/project/.sdk/src/cmp/java/Main_java.ts +2 -1
  46. package/project/.sdk/src/cmp/java/TestDirect_java.ts +5 -4
  47. package/project/.sdk/src/cmp/java/Test_java.ts +5 -1
  48. package/project/.sdk/src/cmp/js/Config_js.ts +7 -8
  49. package/project/.sdk/src/cmp/js/Main_js.ts +2 -1
  50. package/project/.sdk/src/cmp/js/TestDirect_js.ts +34 -8
  51. package/project/.sdk/src/cmp/js/TestEntity_js.ts +35 -5
  52. package/project/.sdk/src/cmp/js/Test_js.ts +5 -1
  53. package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +7 -1
  54. package/project/.sdk/src/cmp/js/fragment/Entity.test.fragment.js +7 -1
  55. package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +7 -7
  56. package/project/.sdk/src/cmp/kotlin/Main_kotlin.ts +2 -1
  57. package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +5 -4
  58. package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +5 -1
  59. package/project/.sdk/src/cmp/lean/Config_lean.ts +9 -8
  60. package/project/.sdk/src/cmp/lua/Config_lua.ts +1 -7
  61. package/project/.sdk/src/cmp/lua/Main_lua.ts +2 -1
  62. package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +32 -7
  63. package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +24 -4
  64. package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -1
  65. package/project/.sdk/src/cmp/ocaml/Gitignore_ocaml.ts +1 -0
  66. package/project/.sdk/src/cmp/perl/Main_perl.ts +2 -1
  67. package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +29 -7
  68. package/project/.sdk/src/cmp/perl/TestEntity_perl.ts +24 -4
  69. package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -1
  70. package/project/.sdk/src/cmp/perl/utility_perl.ts +10 -0
  71. package/project/.sdk/src/cmp/php/Config_php.ts +1 -7
  72. package/project/.sdk/src/cmp/php/Main_php.ts +2 -1
  73. package/project/.sdk/src/cmp/php/TestDirect_php.ts +28 -8
  74. package/project/.sdk/src/cmp/php/TestEntity_php.ts +28 -4
  75. package/project/.sdk/src/cmp/php/Test_php.ts +5 -1
  76. package/project/.sdk/src/cmp/py/Config_py.ts +1 -7
  77. package/project/.sdk/src/cmp/py/Main_py.ts +2 -1
  78. package/project/.sdk/src/cmp/py/TestDirect_py.ts +5 -4
  79. package/project/.sdk/src/cmp/py/Test_py.ts +5 -1
  80. package/project/.sdk/src/cmp/rb/Config_rb.ts +1 -7
  81. package/project/.sdk/src/cmp/rb/Main_rb.ts +2 -1
  82. package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +28 -8
  83. package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +24 -4
  84. package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -1
  85. package/project/.sdk/src/cmp/rb/utility_rb.ts +3 -1
  86. package/project/.sdk/src/cmp/rust/Main_rust.ts +2 -1
  87. package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +35 -7
  88. package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +37 -4
  89. package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -1
  90. package/project/.sdk/src/cmp/scala/Config_scala.ts +9 -7
  91. package/project/.sdk/src/cmp/scala/Main_scala.ts +2 -1
  92. package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +4 -3
  93. package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -1
  94. package/project/.sdk/src/cmp/seneca-provider/Extras_seneca-provider.ts +3 -1
  95. package/project/.sdk/src/cmp/seneca-provider/Main_seneca-provider.ts +9 -5
  96. package/project/.sdk/src/cmp/ts/Config_ts.ts +57 -16
  97. package/project/.sdk/src/cmp/ts/Main_ts.ts +10 -2
  98. package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +15 -7
  99. package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +11 -3
  100. package/project/.sdk/src/cmp/ts/Test_ts.ts +5 -1
  101. package/project/.sdk/tm/csharp/test/Runner.cs +45 -0
  102. package/project/.sdk/tm/dart/test/utility.dart +39 -0
  103. package/project/.sdk/tm/js/test/sdk-test-control.json +19 -0
  104. package/project/.sdk/tm/js/test/utility.js +91 -1
  105. package/project/.sdk/tm/lua/test/runner.lua +40 -0
  106. package/project/.sdk/tm/ocaml/test/harness.ml +14 -4
  107. package/project/.sdk/tm/perl/t/runner.pm +30 -0
  108. package/project/.sdk/tm/php/test/Runner.php +36 -0
  109. package/project/.sdk/tm/rb/test/runner.rb +25 -0
  110. package/project/.sdk/tm/rust/tests/common/mod.rs +32 -0
  111. package/project/.sdk/tm/rust/utility/make_options.rs +1 -1
  112. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +8 -2
  113. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sigv4.ts +29 -5
  114. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +30 -21
  115. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/Registry.ts +90 -0
  116. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/addr.ts +48 -0
  117. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/aws.ts +219 -0
  118. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/azuresecrets.ts +144 -0
  119. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/boru.ts +113 -0
  120. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/doppler.ts +77 -0
  121. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/dotenv.ts +51 -0
  122. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/env.ts +31 -0
  123. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/file.ts +54 -0
  124. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/gcpsecrets.ts +118 -0
  125. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/hashicorp.ts +159 -0
  126. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/http.ts +66 -0
  127. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/infisical.ts +107 -0
  128. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/memory.ts +33 -0
  129. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/onepassword.ts +120 -0
  130. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/support.ts +176 -0
  131. package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +15 -13
  132. package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +25 -19
  133. package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +1 -1
  134. package/project/.sdk/tm/ts/test/vendor/omni/index.ts +1 -1
  135. package/project/.sdk/tm/zig/core/utility.zig +1 -1
  136. package/project/sdkgen-package.json +1 -1
  137. package/src/cmp/Feature.ts +5 -0
  138. package/src/cmp/TestControl.ts +64 -0
  139. package/src/helpers/featureSource.ts +130 -0
  140. package/src/helpers/opShape.ts +9 -14
  141. package/src/helpers/pointPath.ts +88 -0
  142. package/src/sdkgen.ts +18 -0
  143. package/src/utility.ts +92 -1
  144. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Providers.ts +0 -1221
@@ -0,0 +1,120 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/onepassword.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ /* Copyright (c) 2025 Voxgig Ltd, MIT License */
5
+
6
+ import {
7
+ ProviderSpec, Provider, SekretoError, checkname, vaultref,
8
+ } from './support'
9
+ import { checkaddr } from './addr'
10
+ import { fetchjson } from './http'
11
+
12
+ export function onepasswordprovider(options?: {
13
+ addr?: string
14
+ token?: string
15
+ vault?: string
16
+ }): Provider {
17
+ const opts = options || {}
18
+
19
+ let vaultid: string | undefined
20
+
21
+ const auth = (): Record<string, string> => ({
22
+ authorization: 'Bearer ' + (opts.token || ''),
23
+ })
24
+
25
+ const resolvevault = async (addr: string): Promise<string> => {
26
+ const want = opts.vault || ''
27
+ if ('' === want) {
28
+ throw new SekretoError('sekreto: onepassword: no vault')
29
+ }
30
+
31
+ const res = await fetchjson('GET', addr + '/v1/vaults', auth())
32
+
33
+ if (200 !== res.status || !Array.isArray(res.body)) {
34
+ throw new SekretoError('sekreto: onepassword error: ' + res.status + ': listing vaults')
35
+ }
36
+
37
+ for (const entry of res.body) {
38
+ if (entry && (want === entry.id || want === entry.name)) {
39
+ return String(entry.id)
40
+ }
41
+ }
42
+
43
+ throw new SekretoError('sekreto: onepassword: no vault named ' + want)
44
+ }
45
+
46
+ return {
47
+ lookup: async (name: string) => {
48
+ checkname(name)
49
+
50
+ const addr = (opts.addr || '').replace(/\/$/, '')
51
+ if ('' === addr) {
52
+ throw new SekretoError('sekreto: onepassword: no addr')
53
+ }
54
+ checkaddr(addr)
55
+
56
+ if (undefined === vaultid) {
57
+ vaultid = await resolvevault(addr)
58
+ }
59
+
60
+ const filter = encodeURIComponent('title eq "' + name + '"')
61
+ const found = await fetchjson(
62
+ 'GET',
63
+ addr + '/v1/vaults/' + vaultid + '/items?filter=' + filter,
64
+ auth(),
65
+ )
66
+
67
+ if (200 !== found.status || !Array.isArray(found.body)) {
68
+ throw new SekretoError('sekreto: onepassword error: ' + found.status + ': finding ' + name)
69
+ }
70
+
71
+ if (0 === found.body.length) {
72
+ return undefined
73
+ }
74
+
75
+ const item = await fetchjson(
76
+ 'GET',
77
+ addr + '/v1/vaults/' + vaultid + '/items/' + found.body[0].id,
78
+ auth(),
79
+ )
80
+
81
+ if (200 !== item.status) {
82
+ throw new SekretoError('sekreto: onepassword error: ' + item.status + ': reading ' + name)
83
+ }
84
+
85
+ const fields = (item.body && item.body.fields) || []
86
+
87
+ for (const field of fields) {
88
+ if (field && 'PASSWORD' === field.purpose) {
89
+ return undefined === field.value || null === field.value ? undefined : String(field.value)
90
+ }
91
+ }
92
+ for (const field of fields) {
93
+ if (field && 'value' === field.label) {
94
+ return undefined === field.value || null === field.value ? undefined : String(field.value)
95
+ }
96
+ }
97
+
98
+ return undefined
99
+ },
100
+ describe: () => 'onepassword:' + (opts.vault || ''),
101
+ }
102
+ }
103
+
104
+ /** Doppler.
105
+ *
106
+ * The whole config is downloaded once - Doppler's own bulk endpoint -
107
+ * and answered from memory, like a remote .env: `api.token` is the
108
+ * `API_TOKEN` entry. A service token is config-scoped, so project and
109
+ * config are only needed with broader tokens. */
110
+
111
+
112
+ // Registering at import is what makes this module's presence the only
113
+ // thing that decides whether the kind exists in a build.
114
+ import { register } from './Registry'
115
+
116
+ register({
117
+ name: 'onepassword',
118
+ needs: ['fetch'],
119
+ define: (spec: ProviderSpec) => onepasswordprovider(spec),
120
+ })
@@ -0,0 +1,176 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/support.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ // The providers a Sekreto chains together.
5
+ //
6
+ // A provider answers one question: "do you have this secret?" It returns
7
+ // the value, or undefined to mean "ask the next one". Nothing else about
8
+ // a provider is visible to the caller - which is the point: an app reads
9
+ // `api.token` and never learns whether it came from the environment, a
10
+ // .env file, HashiCorp Vault, AWS, GCP, Azure or a boru vault.
11
+ //
12
+ // Two failure shapes, and they are never interchangeable. A store that
13
+ // does not hold the secret is a MISS (undefined) - the chain carries on.
14
+ // A store that could not answer - bad credentials, unreachable host,
15
+ // missing configuration - is an ERROR: falling through there would
16
+ // quietly reach for a weaker store.
17
+
18
+ import {
19
+ SekretoError,
20
+ awsparam,
21
+ checkname,
22
+ envkey,
23
+ flatname,
24
+ parsedotenv,
25
+ vaultref,
26
+ } from '../Sekreto'
27
+
28
+ // NODE BUILTINS, LOADED ON FIRST USE.
29
+ //
30
+ // These were top-level imports, which made them a side effect of importing
31
+ // sekreto AT ALL: `child_process`, `fs` and `path` entered the module graph
32
+ // for a caller who only ever used a `memory` or `env` provider, and any
33
+ // runtime lacking them failed at import time rather than at the point of
34
+ // use. Sekreto.ts imports makeprovider from this module, so the chain
35
+ // reached everything.
36
+ //
37
+ // A plain require(), not `await import()`: dotenvprovider, fileprovider and
38
+ // boruprovider all have SYNCHRONOUS lookups, and making them async to
39
+ // accommodate a dynamic import would change observable behaviour for anyone
40
+ // calling a provider directly. The package is CommonJS ("type":
41
+ // "commonjs"), so require is available and synchronous.
42
+ //
43
+ // What this buys and what it does not: the builtins are no longer evaluated
44
+ // at import time, so importing sekreto is safe in a runtime that lacks them
45
+ // and a bundler can drop an unreachable provider along with its edge. It is
46
+ // NOT by itself a complete browser story — a bundler still resolves a
47
+ // require it can see statically, so a browser build wants conditional
48
+ // exports ("browser" field) as well. That is a packaging change, tracked
49
+ // separately.
50
+ const nodemods: Record<string, any> = {}
51
+
52
+ function nodemod<T = any>(name: string): T {
53
+ let mod = nodemods[name]
54
+
55
+ if (undefined === mod) {
56
+ try {
57
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
58
+ mod = nodemods[name] = require(name)
59
+ } catch (err: any) {
60
+ throw new SekretoError(
61
+ 'sekreto: this provider needs ' +
62
+ name +
63
+ ', which this runtime does not provide: ' +
64
+ err.message,
65
+ )
66
+ }
67
+ }
68
+
69
+ return mod as T
70
+ }
71
+
72
+ export type Provider = {
73
+ /** The value, or undefined if this provider does not have it. */
74
+ lookup: (name: string) => Promise<string | undefined> | string | undefined
75
+ /** A short description, shown by `Sekreto.sources()`. */
76
+ describe: () => string
77
+ }
78
+
79
+ /** The declarative form of a provider, as used in config and in the
80
+ * shared spec. */
81
+ export type ProviderSpec = {
82
+ kind:
83
+ | 'env'
84
+ | 'dotenv'
85
+ | 'memory'
86
+ | 'file'
87
+ | 'hashicorp'
88
+ | 'boru'
89
+ | 'awssecrets'
90
+ | 'awsparams'
91
+ | 'gcpsecrets'
92
+ | 'azuresecrets'
93
+ | 'onepassword'
94
+ | 'doppler'
95
+ | 'infisical'
96
+ /** The store name `Sekreto.getfrom` addresses. Defaults to `kind`. */
97
+ name?: string
98
+ prefix?: string
99
+ /** dotenv: the file to read. */
100
+ file?: string
101
+ /** memory: literal values, keyed like environment variables. */
102
+ values?: Record<string, string>
103
+ /** file: the directory of one-secret-per-file entries. */
104
+ dir?: string
105
+ /** hashicorp / boru (wire) / gcp / 1password / doppler / infisical:
106
+ * the base URL. */
107
+ addr?: string
108
+ /** hashicorp / boru (wire) / gcp / azure / 1password / doppler /
109
+ * infisical: the access token. */
110
+ token?: string
111
+ /** hashicorp / boru (wire): the KV mount (default `secret`). */
112
+ mount?: string
113
+ /** hashicorp: KV engine version, 1 or 2 (default 2). */
114
+ kv?: number
115
+ /** hashicorp: Vault Enterprise namespace (X-Vault-Namespace). */
116
+ vaultnamespace?: string
117
+ /** hashicorp: log in for a token instead of being handed one. */
118
+ auth?: {
119
+ method: 'kubernetes' | 'approle'
120
+ /** The auth mount, defaulting to the method name. */
121
+ mount?: string
122
+ /** kubernetes: the Vault role to log in as. */
123
+ role?: string
124
+ /** kubernetes: the service-account JWT itself (tests). */
125
+ jwt?: string
126
+ /** kubernetes: where the JWT lives; the conventional pod path by
127
+ * default. */
128
+ jwtfile?: string
129
+ /** approle: the role and secret ids. */
130
+ roleid?: string
131
+ secretid?: string
132
+ }
133
+ /** boru: the executable to run (default `boru`). */
134
+ command?: string
135
+ /** boru: the namespace qualifying the alias. */
136
+ namespace?: string
137
+ /** boru: the vault home, passed as BORU_HOME. */
138
+ home?: string
139
+ /** aws: region and credentials; the standard AWS_* environment
140
+ * variables fill whichever are not given. */
141
+ region?: string
142
+ keyid?: string
143
+ secret?: string
144
+ session?: string
145
+ /** gcp / doppler / infisical: the project (GCP project id, Doppler
146
+ * project slug, Infisical workspace id). */
147
+ project?: string
148
+ /** azure: the Key Vault name or full URL. 1password: the vault name
149
+ * or id. */
150
+ vault?: string
151
+ /** azure: client-credential login. infisical: universal-auth login
152
+ * (tenant is Azure-only). */
153
+ tenant?: string
154
+ clientid?: string
155
+ clientsecret?: string
156
+ /** azure: where to log in / where IMDS answers. gcp: where the
157
+ * metadata server answers. Overridable for tests and for clouds with
158
+ * nonstandard endpoints. */
159
+ loginaddr?: string
160
+ imdsaddr?: string
161
+ metadataaddr?: string
162
+ /** azure: the Key Vault API version (default 7.4). */
163
+ apiversion?: string
164
+ /** doppler: the config slug (with `project`). */
165
+ config?: string
166
+ /** infisical: the environment slug and secret path. */
167
+ environment?: string
168
+ path?: string
169
+ }
170
+
171
+ /** Environment variables: `api.token` from `API_TOKEN`. */
172
+
173
+ export {
174
+ SekretoError, awsparam, checkname, envkey, flatname, parsedotenv, vaultref,
175
+ }
176
+ export { nodemod }
@@ -1,5 +1,5 @@
1
1
  // VENDORED: @voxgig/omni 0.1.2 (typescript/src/Runner.ts)
2
- // Source: https://github.com/voxgig/omni @ bc9535d655564c0833f6eff003b0b13dad8b350f
2
+ // Source: https://github.com/voxgig/omni @ 5956cc4e5ecdaeebd11eab8bb4b9462dfc76e018
3
3
  // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
4
  // Omni: the shared multi-language test runner.
5
5
  //
@@ -352,20 +352,22 @@ function fixjsonval(val: Json, donull: boolean): Json {
352
352
  }
353
353
 
354
354
  // The JSON form of an error: always at least {name,message}.
355
- // PATCH (solardemo prototype, pending upstream fix), here and in
356
- // errmessage below: handle error-shaped MAPS. The shared corpus throws
357
- // plain objects in some ports (this SDK's makeError rethrows the
358
- // fixture's ctrl.err verbatim), and the struct repos' original runner
359
- // matched err.message regardless of the thrown value's class. Upstream
360
- // collapses any non-Error to String(err) '[object Object]' — which
361
- // fails both the err check and every match.err.* leaf.
355
+ //
356
+ // A thrown value need not be an Error. Ports commonly rethrow an
357
+ // error-SHAPED map ({name, message, ...}) - voxgig/sdkgen's generated
358
+ // makeError rethrows the fixture's own error object verbatim - and
359
+ // collapsing that to String(err) yields '[object Object]', which fails both
360
+ // the `err` check and every `match.err.*` leaf. The struct repository's
361
+ // original runner read `.message` regardless of the thrown value's class.
362
362
  function errify(err: any): Json {
363
363
  if (err instanceof Error) {
364
364
  return { ...err, name: err.name, message: err.message }
365
365
  }
366
+
366
367
  if (null != err && 'object' === typeof err) {
367
368
  return { name: 'Error', ...err }
368
369
  }
370
+
369
371
  return { name: 'Error', message: String(err) }
370
372
  }
371
373
 
@@ -481,11 +483,11 @@ function handleerror(flags: Flags, index: number, entry: Json, err: any) {
481
483
 
482
484
  // Check that every leaf of `check` is present, and matches, in `base`.
483
485
  function match(flags: Flags, index: number, entry: Json, check: Json, base: Json) {
484
- // PATCH (solardemo prototype, pending upstream fix): read the base
485
- // directly instead of cloning it. The clone gained nothing (the walk
486
- // below only READS via getpath) and blew the stack on cyclic bases —
487
- // which every corpus ctx entry produces, because a live Context reaches
488
- // its client and the client's root context reaches the client again.
486
+ // Read the base DIRECTLY. The clone bought nothing - the walk below only
487
+ // reads, via getpath - and it blows the stack on a cyclic base. A port
488
+ // that drives entries with live objects rather than pure JSON produces
489
+ // those routinely: voxgig/sdkgen's corpus matches against a live client
490
+ // context whose root context reaches the client again.
489
491
  const cbase = base
490
492
 
491
493
  const at = (path: Json[]) => (0 === path.length ? '<root>' : pathify(path))
@@ -1,5 +1,5 @@
1
1
  // VENDORED: @voxgig/omni 0.1.2 (typescript/src/Util.ts)
2
- // Source: https://github.com/voxgig/omni @ bc9535d655564c0833f6eff003b0b13dad8b350f
2
+ // Source: https://github.com/voxgig/omni @ 5956cc4e5ecdaeebd11eab8bb4b9462dfc76e018
3
3
  // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
4
  // Omni internal JSON utilities.
5
5
  //
@@ -158,12 +158,17 @@ function deepequal(a: Json, b: Json): boolean {
158
158
 
159
159
  // Compact JSON text with map keys sorted, so that messages are identical
160
160
  // in every port regardless of local map ordering.
161
- // PATCH (solardemo prototype, pending upstream fix): cycle guard. The
162
- // corpus drives LIVE Context objects through entries (entry.ctx, and the
163
- // entry bookkeeping fail() prints with jsonstr), and a live ctx is cyclic
164
- // (sdk._rootctx.client === sdk). Upstream jsonstr recursed forever; the
165
- // struct repos' original runner emitted '[Circular]', restored here.
166
- function jsonstr(val: Json, seen?: WeakSet<object>): string {
161
+ //
162
+ // CYCLE SAFE. Building a FAILURE MESSAGE must never be the thing that
163
+ // crashes: a port driving entries with live objects rather than pure JSON
164
+ // can carry a cyclic value in the entry bookkeeping fail() prints, and this
165
+ // recursed until the stack gave out. A cycle renders as "[Circular]", as
166
+ // the struct repository's original runner did.
167
+ //
168
+ // `seen` tracks the ANCESTORS of the current value, not every value
169
+ // visited: it is removed again on the way out, so the same object appearing
170
+ // twice as siblings - a DAG, not a cycle - still renders in full.
171
+ function jsonstr(val: Json, seen?: Set<any>): string {
167
172
  if (undefined === val) {
168
173
  return 'undefined'
169
174
  }
@@ -184,23 +189,24 @@ function jsonstr(val: Json, seen?: WeakSet<object>): string {
184
189
  return val ? 'true' : 'false'
185
190
  }
186
191
 
187
- if (islist(val)) {
188
- seen = seen || new WeakSet()
189
- if (seen.has(val)) {
190
- return '"[Circular]"'
191
- }
192
- seen.add(val)
193
- return '[' + val.map((entry: Json) => jsonstr(entry, seen)).join(',') + ']'
194
- }
192
+ if (islist(val) || ismap(val)) {
193
+ seen = seen || new Set()
195
194
 
196
- if (ismap(val)) {
197
- seen = seen || new WeakSet()
198
195
  if (seen.has(val)) {
199
196
  return '"[Circular]"'
200
197
  }
198
+
201
199
  seen.add(val)
202
- const keys = Object.keys(val).sort()
203
- return '{' + keys.map((key) => JSON.stringify(key) + ':' + jsonstr(val[key], seen)).join(',') + '}'
200
+
201
+ const out = islist(val)
202
+ ? '[' + val.map((entry: Json) => jsonstr(entry, seen)).join(',') + ']'
203
+ : '{' + Object.keys(val).sort()
204
+ .map((key) => JSON.stringify(key) + ':' + jsonstr((val as any)[key], seen))
205
+ .join(',') + '}'
206
+
207
+ seen.delete(val)
208
+
209
+ return out
204
210
  }
205
211
 
206
212
  if ('function' === typeof val) {
@@ -1,5 +1,5 @@
1
1
  // VENDORED: @voxgig/omni 0.1.2 (typescript/compat/struct.ts), import path adapted ('../src' -> './index').
2
- // Source: https://github.com/voxgig/omni @ bc9535d655564c0833f6eff003b0b13dad8b350f
2
+ // Source: https://github.com/voxgig/omni @ 5956cc4e5ecdaeebd11eab8bb4b9462dfc76e018
3
3
  // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
4
  // Drop-in replacement for the in-situ test runner in the voxgig/struct
5
5
  // repository (`typescript/test/runner.ts`).
@@ -1,5 +1,5 @@
1
1
  // VENDORED: @voxgig/omni 0.1.2 (typescript/src/index.ts)
2
- // Source: https://github.com/voxgig/omni @ bc9535d655564c0833f6eff003b0b13dad8b350f
2
+ // Source: https://github.com/voxgig/omni @ 5956cc4e5ecdaeebd11eab8bb4b9462dfc76e018
3
3
  // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
4
  // @voxgig/omni - shared multi-language test runner.
5
5
 
@@ -372,7 +372,7 @@ pub fn make_options_util(ctx: *Context) Value {
372
372
  .{ "base", h.vstr("http://localhost:8000") },
373
373
  .{ "prefix", h.vstr("") },
374
374
  .{ "suffix", h.vstr("") },
375
- .{ "auth", h.jo(&.{.{ "prefix", h.vstr("") }}) },
375
+ .{ "auth", h.jo(&.{ .{ "prefix", h.vstr("") }, .{ "basic", h.vbool(false) } }) },
376
376
  .{ "headers", h.jo(&.{.{ "`$CHILD`", h.vstr("`$STRING`") }}) },
377
377
  .{ "allow", h.jo(&.{
378
378
  .{ "method", h.vstr("GET,PUT,POST,PATCH,DELETE,OPTIONS") },
@@ -3,7 +3,7 @@
3
3
  "package": 1
4
4
  },
5
5
  "name": "@voxgig/sdkgen",
6
- "version": "4.6.0",
6
+ "version": "4.8.0",
7
7
  "provides": {
8
8
  "target": [
9
9
  "c",
@@ -3,6 +3,7 @@ import { cmp, Copy, Folder } from 'jostraca'
3
3
 
4
4
  import { ensureStdrep } from '../helpers/stdrep'
5
5
  import { featureApplies, featureTags } from '../helpers/applicability'
6
+ import { pluginExcludesFor } from '../helpers/featureSource'
6
7
 
7
8
  const Feature = cmp(function Feature(props: any) {
8
9
  const { target, feature, ctx$ } = props
@@ -31,6 +32,10 @@ const Feature = cmp(function Feature(props: any) {
31
32
  // TODO: Copy should just warn if from not found
32
33
  Copy({
33
34
  from: 'tm/' + target.name + '/src/feature/' + feature.name,
35
+ // An ACTIVE feature's INACTIVE plugins do not come with it. This
36
+ // is the copy that decides it: Main's exclude never sees these
37
+ // files, because this Copy has already written them.
38
+ exclude: pluginExcludesFor(ctx$.model, feature.name),
34
39
  replace: {
35
40
  // Feature templates reference the SDK class by placeholder — e.g.
36
41
  // tm/ts/.../TestFeature.ts imports `ProjectNameSDK`. Without the
@@ -0,0 +1,64 @@
1
+ import Path from 'node:path'
2
+
3
+ import {
4
+ cmp,
5
+ File,
6
+ Fragment,
7
+ } from 'jostraca'
8
+
9
+
10
+ const TEST_CONTROL_FILE = 'sdk-test-control.json'
11
+
12
+
13
+ // Keep the blanket per-target `Copy({ from: 'tm/<lang>' })` from restoring the
14
+ // template default over a project's edited control file. One regex for every
15
+ // target: the file sits under `test/`, `t/`, `tests/` or `sdktest/` depending
16
+ // on the language, and the name is what identifies it either way.
17
+ const TEST_CONTROL_EXCLUDE = new RegExp('(^|/)' + TEST_CONTROL_FILE + '$')
18
+
19
+
20
+ // `sdk-test-control.json` is the ONE generated file a project is meant to edit
21
+ // by hand: it names the tests to skip, the live pacing, and the extra client
22
+ // options a live run needs (`test.client.options`).
23
+ //
24
+ // It shipped as part of each target's blanket `Copy({ from: 'tm/<lang>' })`,
25
+ // and a Copy has no per-file "leave it alone if it already exists" — so every
26
+ // `npm run generate` overwrote whatever the project had put there. The
27
+ // documented workaround, editing the template master under `.sdk/tm/`, is
28
+ // worse: `doctor` reports it as drift and the next `target add <lang>` reverts
29
+ // it.
30
+ //
31
+ // So it is emitted HERE instead, write-once: `File({ exclude: true })` returns
32
+ // early when the file already exists (FileOp), which is exactly the semantics
33
+ // the file is documented to have. A project without one yet gets the
34
+ // template's default; a project that has edited one keeps its edits across
35
+ // both `generate` and `target add`.
36
+ //
37
+ // The content still comes from the target's own template, so there remains
38
+ // exactly one copy of the default on disk.
39
+ //
40
+ // The template is addressed the SAME way the Copy this replaces addressed it:
41
+ // `tm/<lang>/...` relative to the working directory, which is the project's
42
+ // `.sdk`. Resolved to absolute here because Fragment resolves a RELATIVE
43
+ // `from` against the OUTPUT folder instead — a different base, and the one
44
+ // place these two could silently disagree.
45
+ const TestControl = cmp(function TestControl(props: {
46
+ target: { name: string }
47
+ dir: string
48
+ ctx$?: any
49
+ }) {
50
+ const { target, dir } = props
51
+
52
+ File({ name: TEST_CONTROL_FILE, exclude: true }, () => {
53
+ Fragment({
54
+ from: Path.resolve('tm', target.name, dir, TEST_CONTROL_FILE)
55
+ })
56
+ })
57
+ })
58
+
59
+
60
+ export {
61
+ TestControl,
62
+ TEST_CONTROL_FILE,
63
+ TEST_CONTROL_EXCLUDE,
64
+ }