@voxgig/sdkgen 4.5.3 → 4.6.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.
- package/bin/voxgig-sdkgen +1 -1
- package/dist/action/check.js +15 -0
- package/dist/action/check.js.map +1 -1
- package/dist/cmp/AgentGuide.js +1 -1
- package/dist/cmp/AgentGuide.js.map +1 -1
- package/dist/cmp/AgentGuideContent.d.ts +1 -1
- package/dist/cmp/AgentGuideContent.js +8 -2
- package/dist/cmp/AgentGuideContent.js.map +1 -1
- package/dist/cmp/Feature.js +17 -0
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/FeatureDocs.d.ts +1 -1
- package/dist/cmp/FeatureDocs.js +6 -1
- package/dist/cmp/FeatureDocs.js.map +1 -1
- package/dist/cmp/ReadmeExplanation.js +3 -1
- package/dist/cmp/ReadmeExplanation.js.map +1 -1
- package/dist/cmp/ReadmeFeatures.js +1 -1
- package/dist/cmp/ReadmeFeatures.js.map +1 -1
- package/dist/cmp/ReadmeRefFeatures.js +1 -1
- package/dist/cmp/ReadmeRefFeatures.js.map +1 -1
- package/dist/helpers/applicability.d.ts +6 -0
- package/dist/helpers/applicability.js +103 -0
- package/dist/helpers/applicability.js.map +1 -0
- package/dist/helpers/collectDeps.js +4 -2
- package/dist/helpers/collectDeps.js.map +1 -1
- package/dist/helpers/serverVars.d.ts +2 -1
- package/dist/helpers/serverVars.js +17 -0
- package/dist/helpers/serverVars.js.map +1 -1
- package/dist/sdkgen.d.ts +3 -2
- package/dist/sdkgen.js +9 -2
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.js +7 -1
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aon +39 -0
- package/package.json +1 -1
- package/project/.sdk/model/feature/feature-index.aon +1 -0
- package/project/.sdk/model/feature/secrets.aon +118 -0
- package/project/.sdk/model/target/ts.aon +8 -1
- package/project/.sdk/src/cmp/c/Config_c.ts +5 -1
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +5 -1
- package/project/.sdk/src/cmp/csharp/Config_csharp.ts +5 -1
- package/project/.sdk/src/cmp/dart/Config_dart.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Main_elixir.ts +5 -1
- package/project/.sdk/src/cmp/go/Config_go.ts +5 -1
- package/project/.sdk/src/cmp/go/Main_go.ts +6 -2
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +16 -3
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +16 -3
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +28 -4
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +43 -10
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +5 -5
- package/project/.sdk/src/cmp/java/Config_java.ts +22 -1
- package/project/.sdk/src/cmp/java/Main_java.ts +5 -1
- package/project/.sdk/src/cmp/java/ReadmeQuick_java.ts +17 -3
- package/project/.sdk/src/cmp/java/ReadmeTopQuick_java.ts +17 -3
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +23 -4
- package/project/.sdk/src/cmp/java/TestEntity_java.ts +29 -4
- package/project/.sdk/src/cmp/js/Config_js.ts +5 -1
- package/project/.sdk/src/cmp/js/Main_js.ts +5 -1
- package/project/.sdk/src/cmp/js/Package_js.ts +4 -1
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +5 -1
- package/project/.sdk/src/cmp/lean/Config_lean.ts +5 -1
- package/project/.sdk/src/cmp/lua/Config_lua.ts +5 -1
- package/project/.sdk/src/cmp/lua/Main_lua.ts +5 -1
- package/project/.sdk/src/cmp/lua/Package_lua.ts +4 -1
- package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +5 -1
- package/project/.sdk/src/cmp/perl/Main_perl.ts +5 -1
- package/project/.sdk/src/cmp/php/Config_php.ts +5 -1
- package/project/.sdk/src/cmp/php/Main_php.ts +5 -1
- package/project/.sdk/src/cmp/py/Config_py.ts +5 -1
- package/project/.sdk/src/cmp/py/Main_py.ts +5 -1
- package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +16 -3
- package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +16 -3
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +24 -5
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +23 -3
- package/project/.sdk/src/cmp/rb/Config_rb.ts +5 -1
- package/project/.sdk/src/cmp/rb/Main_rb.ts +5 -1
- package/project/.sdk/src/cmp/rust/Config_rust.ts +5 -1
- package/project/.sdk/src/cmp/rust/Main_rust.ts +5 -1
- package/project/.sdk/src/cmp/scala/Config_scala.ts +5 -1
- package/project/.sdk/src/cmp/scala/Main_scala.ts +5 -1
- package/project/.sdk/src/cmp/swift/Config_swift.ts +5 -1
- package/project/.sdk/src/cmp/ts/Config_ts.ts +5 -1
- package/project/.sdk/src/cmp/ts/Main_ts.ts +57 -1
- package/project/.sdk/src/cmp/ts/Package_ts.ts +4 -1
- package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +15 -3
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +18 -5
- package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +19 -5
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +67 -7
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +27 -4
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +9 -2
- package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +9 -2
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +7 -0
- package/project/.sdk/src/cmp/zig/Config_zig.ts +5 -1
- package/project/.sdk/tm/c/utility/make_options.c +22 -0
- package/project/.sdk/tm/clojure/src/sdk/core.clj +18 -1
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +23 -0
- package/project/.sdk/tm/csharp/test/CustomUtilityTest.cs +15 -0
- package/project/.sdk/tm/csharp/utility/MakeOptions.cs +23 -0
- package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +22 -0
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +19 -0
- package/project/.sdk/tm/go/core/context.go +1 -1
- package/project/.sdk/tm/go/feature/cost_feature.go +1 -1
- package/project/.sdk/tm/go/feature/paging_feature.go +5 -5
- package/project/.sdk/tm/go/feature/test_feature.go +12 -5
- package/project/.sdk/tm/go/test/custom_utility_test.go +15 -0
- package/project/.sdk/tm/go/test/feature_corpus_test.go +7 -0
- package/project/.sdk/tm/go/test/runner_test.go +46 -0
- package/project/.sdk/tm/go/test/struct_runner_test.go +7 -7
- package/project/.sdk/tm/go/test/struct_utility_test.go +63 -27
- package/project/.sdk/tm/go/utility/fetcher.go +2 -2
- package/project/.sdk/tm/go/utility/make_options.go +24 -5
- package/project/.sdk/tm/go/utility/make_point.go +1 -1
- package/project/.sdk/tm/go/utility/make_spec.go +17 -1
- package/project/.sdk/tm/go/utility/prepare_auth.go +1 -1
- package/project/.sdk/tm/go/utility/struct/voxgigstruct.go +370 -307
- package/project/.sdk/tm/go/utility/transform_request.go +29 -1
- package/project/.sdk/tm/go/utility/transform_response.go +20 -1
- package/project/.sdk/tm/java/test/CustomUtilityTest.java +10 -0
- package/project/.sdk/tm/java/test/FeatureCorpusTest.java +7 -0
- package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +6 -0
- package/project/.sdk/tm/java/test/RunnerSupport.java +43 -0
- package/project/.sdk/tm/java/utility/MakeOptions.java +84 -1
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +24 -0
- package/project/.sdk/tm/js/src/utility/StructUtility.js +2076 -1837
- package/project/.sdk/tm/js/test/feature/Corpus.test.js +9 -0
- package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +21 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +12 -1
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +11 -0
- package/project/.sdk/tm/perl/utility/make_options.pm +18 -0
- package/project/.sdk/tm/php/test/FeatureCorpusTest.php +10 -1
- package/project/.sdk/tm/php/utility/MakeOptions.php +24 -0
- package/project/.sdk/tm/py/pkg/utility/make_options.py +20 -0
- package/project/.sdk/tm/py/test/runner.py +32 -0
- package/project/.sdk/tm/py/test/test_feature_corpus.py +10 -1
- package/project/.sdk/tm/rb/test/feature_corpus_test.rb +9 -1
- package/project/.sdk/tm/rb/utility/make_options.rb +17 -0
- package/project/.sdk/tm/rust/utility/make_options.rs +25 -0
- package/project/.sdk/tm/scala/utility/Make.scala +17 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +21 -0
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +419 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Providers.ts +1221 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +381 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sigv4.ts +151 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +42 -0
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +18 -0
- package/project/.sdk/tm/ts/src/utility/StructUtility.ts +1321 -710
- package/project/.sdk/tm/ts/test/feature/Corpus.test.ts +9 -0
- package/project/.sdk/tm/ts/test/feature/secrets/Secrets.test.ts +764 -0
- package/project/.sdk/tm/ts/test/omni.test.ts +84 -0
- package/project/.sdk/tm/ts/test/omni.ts +86 -0
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +6 -2
- package/project/.sdk/tm/ts/test/utility/StructUtility.test.ts +2 -2
- package/project/.sdk/tm/ts/test/utility.ts +122 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +692 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +238 -0
- package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +188 -0
- package/project/.sdk/tm/ts/test/vendor/omni/index.ts +38 -0
- package/project/.sdk/tm/zig/core/utility.zig +23 -0
- package/project/sdkgen-package.json +2 -1
- package/src/action/check.ts +18 -0
- package/src/cmp/AgentGuide.ts +1 -1
- package/src/cmp/AgentGuideContent.ts +9 -2
- package/src/cmp/Feature.ts +19 -0
- package/src/cmp/FeatureDocs.ts +7 -1
- package/src/cmp/ReadmeExplanation.ts +4 -1
- package/src/cmp/ReadmeFeatures.ts +1 -1
- package/src/cmp/ReadmeRefFeatures.ts +1 -1
- package/src/helpers/applicability.ts +123 -0
- package/src/helpers/collectDeps.ts +5 -1
- package/src/helpers/serverVars.ts +19 -0
- package/src/sdkgen.ts +9 -1
- package/src/utility.ts +10 -1
- package/project/.sdk/tm/ts/test/runner.ts +0 -425
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Smoke tests for the vendored omni runner itself: a runner that cannot
|
|
2
|
+
// FAIL a bad entry would turn every corpus suite vacuously green, so pin
|
|
3
|
+
// the failure paths, not just the happy one.
|
|
4
|
+
|
|
5
|
+
import { test, describe } from 'node:test'
|
|
6
|
+
import assert from 'node:assert'
|
|
7
|
+
|
|
8
|
+
import { SDK } from '..'
|
|
9
|
+
|
|
10
|
+
import { OmniError, makeRunner } from './omni'
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// A minimal in-memory spec: no fixture file, no OMNI block (lenient v0,
|
|
14
|
+
// like the shared corpus).
|
|
15
|
+
const SPEC = {
|
|
16
|
+
primary: {
|
|
17
|
+
smoke: {
|
|
18
|
+
basic: {
|
|
19
|
+
set: [
|
|
20
|
+
{ in: 1, out: 2 },
|
|
21
|
+
{ in: 41, out: 42 },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
bad: {
|
|
25
|
+
set: [
|
|
26
|
+
{ in: 1, out: 999 },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
err: {
|
|
30
|
+
set: [
|
|
31
|
+
{ in: 0, err: 'zero refused' },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const inc = (n: number) => {
|
|
39
|
+
if (0 === n) {
|
|
40
|
+
throw new Error('smoke: zero refused')
|
|
41
|
+
}
|
|
42
|
+
return n + 1
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
describe('omni', () => {
|
|
47
|
+
|
|
48
|
+
test('runset passes a correct subject', async () => {
|
|
49
|
+
const runner = await makeRunner(SPEC, SDK.test())
|
|
50
|
+
const R: any = await runner('smoke')
|
|
51
|
+
await R.runset(R.spec.basic, inc)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
test('runset FAILS a wrong result, with OmniError', async () => {
|
|
56
|
+
const runner = await makeRunner(SPEC, SDK.test())
|
|
57
|
+
const R: any = await runner('smoke')
|
|
58
|
+
await assert.rejects(
|
|
59
|
+
() => R.runset(R.spec.bad, inc),
|
|
60
|
+
(err: any) => {
|
|
61
|
+
assert.equal(err.name, 'OmniError')
|
|
62
|
+
assert.ok(err instanceof OmniError)
|
|
63
|
+
assert.match(err.message, /result mismatch/)
|
|
64
|
+
return true
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
test('an expected error is matched, an unexpected one fails', async () => {
|
|
70
|
+
const runner = await makeRunner(SPEC, SDK.test())
|
|
71
|
+
const R: any = await runner('smoke')
|
|
72
|
+
|
|
73
|
+
await R.runset(R.spec.err, inc)
|
|
74
|
+
|
|
75
|
+
await assert.rejects(
|
|
76
|
+
() => R.runset(R.spec.err, (n: number) => n),
|
|
77
|
+
(err: any) => {
|
|
78
|
+
assert.equal(err.name, 'OmniError')
|
|
79
|
+
assert.match(err.message, /expected error did not occur/)
|
|
80
|
+
return true
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
})
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// The corpus test runner: vendored @voxgig/omni behind the struct-runner
|
|
2
|
+
// API the corpus tests already use (`import { makeRunner } from '../omni'`
|
|
3
|
+
// instead of the old hand-vendored '../runner').
|
|
4
|
+
//
|
|
5
|
+
// Two local decisions, both required (see vendor/omni/compat.ts):
|
|
6
|
+
//
|
|
7
|
+
// 1. SPEC PATH. The compat shim's caller-directory heuristic resolves a
|
|
8
|
+
// relative test-file path one level too deep for this layout (loader in
|
|
9
|
+
// dist-test/, test files in dist-test/utility/) - its own header says a
|
|
10
|
+
// port must resolve the path itself. This module compiles to
|
|
11
|
+
// dist-test/omni.js, the same depth as the old dist-test/runner.js, so
|
|
12
|
+
// the existing TEST_JSON_FILE constant keeps working verbatim.
|
|
13
|
+
//
|
|
14
|
+
// 2. PROVIDER DELEGATION. Corpus-driven contexts get `ctx.client` set to
|
|
15
|
+
// the runner's provider. The stock structprovider forwards utility()
|
|
16
|
+
// and tester() but not options()/_features/_rootctx/_mode, which the
|
|
17
|
+
// corpus subjects and pipeline utilities (prepareHeaders via
|
|
18
|
+
// client.options(), test helpers via client._rootctx) do reach. The
|
|
19
|
+
// provider below is built by PROTOTYPE DELEGATION over the live SDK
|
|
20
|
+
// instance, so every SDK member resolves while the four omni hooks sit
|
|
21
|
+
// on top. Upstream omni's compat shim could adopt the same shape.
|
|
22
|
+
|
|
23
|
+
import { isAbsolute, join } from 'node:path'
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
EXISTSMARK,
|
|
27
|
+
NULLMARK,
|
|
28
|
+
UNDEFMARK,
|
|
29
|
+
nullModifier,
|
|
30
|
+
structprovider,
|
|
31
|
+
} from './vendor/omni/compat'
|
|
32
|
+
|
|
33
|
+
import type { StructProvider, StructRunner } from './vendor/omni/compat'
|
|
34
|
+
|
|
35
|
+
import { OmniError, makeRunner as omnimakerunner } from './vendor/omni/index'
|
|
36
|
+
|
|
37
|
+
import type { Json } from './vendor/omni/index'
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// Wrap the SDK as an omni provider WITHOUT hiding it: hooks from the stock
|
|
41
|
+
// structprovider, everything else through the prototype chain.
|
|
42
|
+
function sdkprovider(sdk: any): StructProvider {
|
|
43
|
+
const hooks = structprovider(sdk)
|
|
44
|
+
const provider = Object.assign(Object.create(sdk), hooks)
|
|
45
|
+
|
|
46
|
+
// DEF.client entries become SDK instances too - rewrap with the same
|
|
47
|
+
// delegating shape, not the stock one.
|
|
48
|
+
provider.client = async (options: Json) => sdkprovider(await sdk.tester(options))
|
|
49
|
+
|
|
50
|
+
return provider
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
// struct's makeRunner(testfile, client) signature, backed by vendored omni.
|
|
55
|
+
// Also accepts an already-parsed spec object (omni's own capability), which
|
|
56
|
+
// keeps smoke tests free of fixture files.
|
|
57
|
+
async function makeRunner(testfile: string | Json, client: any): Promise<StructRunner> {
|
|
58
|
+
const specref = 'string' !== typeof testfile ? testfile
|
|
59
|
+
: isAbsolute(testfile) ? testfile
|
|
60
|
+
: join(__dirname, testfile)
|
|
61
|
+
|
|
62
|
+
const provider = sdkprovider(client)
|
|
63
|
+
const runner = await omnimakerunner(specref, provider)
|
|
64
|
+
|
|
65
|
+
return async function structrunner(name: string, store?: any) {
|
|
66
|
+
const runpack = await runner(name, store)
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
spec: runpack.spec,
|
|
70
|
+
runset: runpack.runset,
|
|
71
|
+
runsetflags: runpack.runsetflags,
|
|
72
|
+
subject: runpack.subject,
|
|
73
|
+
client: provider,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
EXISTSMARK,
|
|
81
|
+
NULLMARK,
|
|
82
|
+
UNDEFMARK,
|
|
83
|
+
OmniError,
|
|
84
|
+
makeRunner,
|
|
85
|
+
nullModifier,
|
|
86
|
+
}
|
|
@@ -5,7 +5,7 @@ import assert from 'node:assert'
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
makeRunner,
|
|
8
|
-
} from '../
|
|
8
|
+
} from '../omni'
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
SDK,
|
|
@@ -70,7 +70,11 @@ describe('PrimaryUtility', async () => {
|
|
|
70
70
|
spec = run.spec
|
|
71
71
|
runset = run.runset
|
|
72
72
|
runsetflags = run.runsetflags
|
|
73
|
-
|
|
73
|
+
// Under the old hand-vendored runner, run.client WAS the SDK; under
|
|
74
|
+
// omni it is the provider wrapping it. This suite treats the client as
|
|
75
|
+
// the SDK — including ASSIGNING to client._features, which prototype
|
|
76
|
+
// delegation cannot forward — so unwrap the real instance.
|
|
77
|
+
client = (run.client as any).sdk
|
|
74
78
|
utility = client.utility()
|
|
75
79
|
struct = utility.struct
|
|
76
80
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// VERSION: @voxgig/struct 0.
|
|
1
|
+
// VERSION: @voxgig/struct 0.3.2 (vendored via omni compat; see ../omni.ts)
|
|
2
2
|
// RUN: npm test
|
|
3
3
|
// RUN-SOME: npm run test-some --pattern=getpath
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
makeRunner,
|
|
10
10
|
nullModifier,
|
|
11
11
|
NULLMARK,
|
|
12
|
-
} from '../
|
|
12
|
+
} from '../omni'
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
import {
|
|
@@ -90,6 +90,7 @@ type TestControl = {
|
|
|
90
90
|
unit?: { direct?: any[], entityOp?: any[] }
|
|
91
91
|
}
|
|
92
92
|
live?: { delayMs?: number }
|
|
93
|
+
client?: { options?: Record<string, any> }
|
|
93
94
|
[k: string]: any
|
|
94
95
|
}
|
|
95
96
|
[k: string]: any
|
|
@@ -167,6 +168,55 @@ function skipIfMissingIds(t: any, setup: any, requiredKeys: string[]): boolean {
|
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
|
|
171
|
+
// Extra SDK options every LIVE client is constructed with, from
|
|
172
|
+
// sdk-test-control.json `test.client.options`.
|
|
173
|
+
//
|
|
174
|
+
// The generated live client knows two things: the base URL (from the spec)
|
|
175
|
+
// and the credential (from the environment). Everything else about how a
|
|
176
|
+
// particular API wants to be talked to — which features to switch on, and
|
|
177
|
+
// with what settings — is a property of THAT API, known to the project and
|
|
178
|
+
// to nothing in the toolchain.
|
|
179
|
+
//
|
|
180
|
+
// The concrete case: an API that issues short-lived access tokens needs the
|
|
181
|
+
// `secrets` feature's exchange turned on and pointed at its token endpoint,
|
|
182
|
+
// or the live suite gets a handful of calls in and then fails 401 with
|
|
183
|
+
// nothing explaining why. There was no seam for that, so the suite could
|
|
184
|
+
// not be run at all.
|
|
185
|
+
//
|
|
186
|
+
// A committed FILE rather than an environment variable, because it is
|
|
187
|
+
// configuration, not a secret: it belongs in the repo next to the API it
|
|
188
|
+
// describes, where it can be read and reviewed. Secrets still come from the
|
|
189
|
+
// environment (the providers this block names read them).
|
|
190
|
+
//
|
|
191
|
+
// Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
192
|
+
// values win — this adds to the live client, it does not redirect it.
|
|
193
|
+
//
|
|
194
|
+
// That contract is enforced HERE rather than left to each merge site: the
|
|
195
|
+
// generated object only names a field when the model calls for one, so a
|
|
196
|
+
// `base` in this block would face no competing value and would silently
|
|
197
|
+
// redirect the whole suite — credential included — to another host. The
|
|
198
|
+
// reserved fields are stripped once, where the block is read, so every
|
|
199
|
+
// caller gets the same guarantee whether or not it happens to emit them.
|
|
200
|
+
const LIVE_RESERVED = ['base', 'prefix', 'suffix', 'server', 'apikey', 'secret']
|
|
201
|
+
|
|
202
|
+
function liveClientOptions(): Record<string, any> {
|
|
203
|
+
const opts = loadTestControl()?.test?.client?.options
|
|
204
|
+
|
|
205
|
+
if (null == opts || 'object' !== typeof opts) {
|
|
206
|
+
return {}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const out: Record<string, any> = {}
|
|
210
|
+
for (const key of Object.keys(opts)) {
|
|
211
|
+
if (!LIVE_RESERVED.includes(key)) {
|
|
212
|
+
out[key] = (opts as any)[key]
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return out
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
170
220
|
// Per-test live pacing delay (ms). Read from sdk-test-control.json
|
|
171
221
|
// `test.live.delayMs`; defaults to 500ms if absent or invalid.
|
|
172
222
|
function liveDelayMs(): number {
|
|
@@ -188,6 +238,76 @@ function liveDelay(liveEnvVar: string): () => Promise<void> {
|
|
|
188
238
|
}
|
|
189
239
|
|
|
190
240
|
|
|
241
|
+
// Load a .env.local file into process.env, replacing the `dotenv`
|
|
242
|
+
// devDependency — the SDK's last non-tooling package.
|
|
243
|
+
//
|
|
244
|
+
// Same semantics dotenv gave these tests: a missing file is fine, and a key
|
|
245
|
+
// already present in the environment is never overridden, so an explicit
|
|
246
|
+
// export still beats the file.
|
|
247
|
+
//
|
|
248
|
+
// WHY NOT sekreto's parsedotenv, which does the same job and is already
|
|
249
|
+
// vendored: sekreto lives INSIDE the secrets feature container, so `target
|
|
250
|
+
// add` removes it whenever a project does not select that feature — while
|
|
251
|
+
// these entity tests need the loader either way. Importing it here would
|
|
252
|
+
// couple every generated test suite to an optional feature. The parser is
|
|
253
|
+
// small enough that a second, independent copy is cheaper than that
|
|
254
|
+
// coupling; it deliberately handles only what a .env.local holds.
|
|
255
|
+
function loadEnvLocal(file: string): void {
|
|
256
|
+
let text: string
|
|
257
|
+
try {
|
|
258
|
+
text = Fs.readFileSync(file, 'utf8')
|
|
259
|
+
}
|
|
260
|
+
catch (err: any) {
|
|
261
|
+
if ('ENOENT' === err.code) {
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
throw err
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
268
|
+
const line = raw.trim()
|
|
269
|
+
|
|
270
|
+
// Blank and comment lines. A '#' INSIDE a value is not a comment.
|
|
271
|
+
if ('' === line || line.startsWith('#')) {
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const eq = line.indexOf('=')
|
|
276
|
+
if (0 >= eq) {
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const key = line.slice(0, eq).trim().replace(/^export\s+/, '')
|
|
281
|
+
let val = line.slice(eq + 1).trim()
|
|
282
|
+
|
|
283
|
+
const quote = ("'" === val[0] || '"' === val[0]) ? val[0] : ''
|
|
284
|
+
|
|
285
|
+
if ('' !== quote) {
|
|
286
|
+
// Quoted: the value runs to the CLOSING quote, and a '#' inside it is
|
|
287
|
+
// part of the value. Anything after the closing quote is a comment.
|
|
288
|
+
const close = val.indexOf(quote, 1)
|
|
289
|
+
val = 0 < close ? val.slice(1, close) : val.slice(1)
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
// Unquoted: the first '#' starts an inline comment, with or without
|
|
293
|
+
// preceding whitespace — `A=a#b` is `a` to dotenv, not `a#b`.
|
|
294
|
+
// Dropping this made `KEY=secret # note` resolve to the whole string
|
|
295
|
+
// including the note, and a generated live test would then send that
|
|
296
|
+
// as the credential. Verified against dotenv's own parse().
|
|
297
|
+
const hash = val.indexOf('#')
|
|
298
|
+
if (0 <= hash) {
|
|
299
|
+
val = val.slice(0, hash)
|
|
300
|
+
}
|
|
301
|
+
val = val.trim()
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (undefined === process.env[key]) {
|
|
305
|
+
process.env[key] = val
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
|
|
191
311
|
export {
|
|
192
312
|
makeStepData,
|
|
193
313
|
makeMatch,
|
|
@@ -199,6 +319,8 @@ export {
|
|
|
199
319
|
isControlSkipped,
|
|
200
320
|
maybeSkipControl,
|
|
201
321
|
skipIfMissingIds,
|
|
322
|
+
liveClientOptions,
|
|
202
323
|
liveDelayMs,
|
|
203
324
|
liveDelay,
|
|
325
|
+
loadEnvLocal,
|
|
204
326
|
}
|