@voxgig/sdkgen 1.3.18 → 1.4.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/dist/cmp/Deploy.js +16 -16
- package/dist/cmp/Deploy.js.map +1 -1
- package/dist/cmp/ReadmeTop.js +13 -11
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/helpers/naming.d.ts +3 -1
- package/dist/helpers/naming.js +65 -0
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/serverVars.d.ts +10 -0
- package/dist/helpers/serverVars.js +87 -0
- package/dist/helpers/serverVars.js.map +1 -0
- package/dist/sdkgen.d.ts +3 -2
- package/dist/sdkgen.js +6 -1
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/project/.sdk/model/target/go-cli.aontu +2 -2
- package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +22 -15
- package/project/.sdk/src/cmp/go/Config_go.ts +10 -1
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +54 -35
- package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +7 -7
- package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +21 -18
- package/project/.sdk/src/cmp/js/Config_js.ts +11 -0
- package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +2 -2
- package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +4 -0
- package/project/.sdk/src/cmp/lua/Config_lua.ts +10 -1
- package/project/.sdk/src/cmp/php/Config_php.ts +13 -2
- package/project/.sdk/src/cmp/py/Config_py.ts +10 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +12 -1
- package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +25 -18
- package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +10 -3
- package/project/.sdk/src/cmp/ts/Config_ts.ts +11 -0
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +2 -2
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +4 -0
- package/project/.sdk/tm/c/utility/prepare_method.c +18 -0
- package/project/.sdk/tm/clojure/src/sdk/core.clj +9 -1
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +13 -0
- package/project/.sdk/tm/csharp/Makefile +6 -6
- package/project/.sdk/tm/csharp/utility/PrepareMethod.cs +11 -0
- package/project/.sdk/tm/dart/Makefile +3 -3
- package/project/.sdk/tm/dart/lib/utility/PrepareMethodUtility.dart +10 -0
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +8 -1
- package/project/.sdk/tm/go/Makefile +6 -6
- package/project/.sdk/tm/go/test/primary_utility_test.go +5 -0
- package/project/.sdk/tm/go/utility/make_options.go +48 -0
- package/project/.sdk/tm/go/utility/prepare_method.go +14 -1
- package/project/.sdk/tm/haskell/src/SdkRuntime.hs +13 -4
- package/project/.sdk/tm/java/Makefile +6 -6
- package/project/.sdk/tm/java/utility/PrepareMethod.java +9 -0
- package/project/.sdk/tm/js/Makefile +6 -6
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -1
- package/project/.sdk/tm/js/src/utility/PrepareMethodUtility.js +9 -0
- package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +5 -0
- package/project/.sdk/tm/kotlin/Makefile +6 -6
- package/project/.sdk/tm/kotlin/utility/Prepare.kt +9 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +6 -1
- package/project/.sdk/tm/lua/Makefile +7 -7
- package/project/.sdk/tm/lua/feature/test_feature.lua +29 -1
- package/project/.sdk/tm/lua/test/primary_utility_test.lua +4 -0
- package/project/.sdk/tm/lua/utility/make_options.lua +39 -0
- package/project/.sdk/tm/lua/utility/prepare_method.lua +11 -0
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +9 -3
- package/project/.sdk/tm/perl/Makefile +6 -6
- package/project/.sdk/tm/perl/utility/prepare_method.pm +17 -0
- package/project/.sdk/tm/php/Makefile +6 -6
- package/project/.sdk/tm/php/feature/TestFeature.php +30 -2
- package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +5 -0
- package/project/.sdk/tm/php/utility/MakeOptions.php +44 -0
- package/project/.sdk/tm/php/utility/PrepareMethod.php +11 -0
- package/project/.sdk/tm/py/Makefile +6 -6
- package/project/.sdk/tm/py/test/test_primary_utility.py +5 -0
- package/project/.sdk/tm/py/utility/make_options.py +42 -0
- package/project/.sdk/tm/py/utility/prepare_method.py +10 -0
- package/project/.sdk/tm/rb/Makefile +6 -6
- package/project/.sdk/tm/rb/test/primary_utility_test.rb +4 -0
- package/project/.sdk/tm/rb/utility/make_options.rb +37 -0
- package/project/.sdk/tm/rb/utility/prepare_method.rb +10 -1
- package/project/.sdk/tm/rust/Makefile +6 -6
- package/project/.sdk/tm/rust/utility/prepare_method.rs +12 -0
- package/project/.sdk/tm/scala/utility/Prepare.scala +14 -8
- package/project/.sdk/tm/swift/Makefile +6 -6
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +8 -0
- package/project/.sdk/tm/ts/Makefile +6 -6
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +39 -1
- package/project/.sdk/tm/ts/src/utility/PrepareMethodUtility.ts +9 -0
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +4 -0
- package/project/.sdk/tm/zig/core/utility.zig +15 -0
- package/src/cmp/Deploy.ts +16 -16
- package/src/cmp/ReadmeTop.ts +13 -11
- package/src/helpers/naming.ts +71 -0
- package/src/helpers/serverVars.ts +105 -0
- package/src/sdkgen.ts +6 -1
|
@@ -52,6 +52,11 @@ module ProjectNameUtilities
|
|
|
52
52
|
"system" => {},
|
|
53
53
|
"test" => { "active" => false, "entity" => { "`$OPEN`" => true } },
|
|
54
54
|
"clean" => { "keys" => "key,token,id" },
|
|
55
|
+
# Server-variable values for a templated base URL (OpenAPI server
|
|
56
|
+
# variables): {name} placeholders in "base" are substituted from this
|
|
57
|
+
# map at construction. Spec defaults arrive via the generated config;
|
|
58
|
+
# user values override them.
|
|
59
|
+
"server" => { "`$CHILD`" => "" },
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
sys_fetch = VoxgigStruct.getpath(opts, "system.fetch")
|
|
@@ -60,6 +65,38 @@ module ProjectNameUtilities
|
|
|
60
65
|
validated = VoxgigStruct.validate(merged, optspec)
|
|
61
66
|
opts = validated.is_a?(Hash) ? validated : {}
|
|
62
67
|
|
|
68
|
+
# Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
69
|
+
# Every placeholder must resolve to a non-empty value: from
|
|
70
|
+
# options["server"] (user), else the config default. A placeholder that
|
|
71
|
+
# resolves to "" is a construction ERROR in live mode — the URL cannot
|
|
72
|
+
# work — but in test mode substitutes the deterministic value
|
|
73
|
+
# "test-<name>" so offline tests need no configuration.
|
|
74
|
+
base = opts["base"]
|
|
75
|
+
if base.is_a?(String) && base.include?("{")
|
|
76
|
+
testmode = VoxgigStruct.getpath(opts, "test.active") == true ||
|
|
77
|
+
VoxgigStruct.getpath(opts, "feature.test.active") == true
|
|
78
|
+
server = opts["server"].is_a?(Hash) ? opts["server"] : {}
|
|
79
|
+
sdkname = VoxgigStruct.getpath(config, "main.name")
|
|
80
|
+
sdkname = "SDK" unless sdkname.is_a?(String) && !sdkname.empty?
|
|
81
|
+
opts["base"] = base.gsub(/\{([A-Za-z0-9_]+)\}/) do
|
|
82
|
+
name = Regexp.last_match(1)
|
|
83
|
+
val = server[name]
|
|
84
|
+
val = "" unless val.is_a?(String)
|
|
85
|
+
if val.empty?
|
|
86
|
+
if testmode
|
|
87
|
+
"test-#{name}"
|
|
88
|
+
else
|
|
89
|
+
raise ArgumentError,
|
|
90
|
+
"#{sdkname}: the server variable '#{name}' is required: " \
|
|
91
|
+
"the API base URL is '#{base}' — pass " \
|
|
92
|
+
"{ \"server\" => { \"#{name}\" => \"...\" } } in the SDK options"
|
|
93
|
+
end
|
|
94
|
+
else
|
|
95
|
+
val
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
63
100
|
if sys_fetch
|
|
64
101
|
opts["system"] = {} unless opts["system"].is_a?(Hash)
|
|
65
102
|
opts["system"]["fetch"] = sys_fetch
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# ProjectName SDK utility: prepare_method
|
|
2
|
+
require_relative 'struct/voxgig_struct'
|
|
2
3
|
module ProjectNameUtilities
|
|
3
4
|
METHOD_MAP = { "create"=>"POST", "update"=>"PUT", "load"=>"GET", "list"=>"GET", "remove"=>"DELETE", "patch"=>"PATCH" }
|
|
4
|
-
|
|
5
|
+
|
|
6
|
+
# The API definition is authoritative: a POST-only or PATCH-based API
|
|
7
|
+
# exposes `update` as POST or PATCH, not the PUT the op name implies.
|
|
8
|
+
# Only fall back to the op-name convention when the point has no method.
|
|
9
|
+
PrepareMethod = ->(ctx) {
|
|
10
|
+
method = VoxgigStruct.getprop(ctx.point, "method")
|
|
11
|
+
next method.upcase if method.is_a?(String) && "" != method
|
|
12
|
+
METHOD_MAP[ctx.op.name] || "GET"
|
|
13
|
+
}
|
|
5
14
|
end
|
|
@@ -13,21 +13,21 @@ clean:
|
|
|
13
13
|
# The crates.io registry entry is declared in the model with
|
|
14
14
|
# state: 'pending' — a real deploy publishes the git tag rust/vX.Y.Z only;
|
|
15
15
|
# `cargo publish` starts when the registry state flips to 'active'. Run
|
|
16
|
-
# headless under the
|
|
16
|
+
# headless under the boru key vault, which injects the GitHub token so
|
|
17
17
|
# nothing lands on disk or argv:
|
|
18
|
-
#
|
|
19
|
-
#
|
|
18
|
+
# boru vault exec --for=github=<alias> -- make publish
|
|
19
|
+
# boru `--dry-run` injects a filler token we detect to rehearse (no tag/push).
|
|
20
20
|
# set -e + tag-last: a failed push never leaves a tag behind.
|
|
21
21
|
VERSION := $(shell cat VERSION)
|
|
22
22
|
TAG := rust/v$(VERSION)
|
|
23
|
-
|
|
23
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
24
24
|
publish:
|
|
25
25
|
@if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
|
|
26
26
|
echo "tag $(TAG) already exists — bump VERSION first"; exit 1; fi
|
|
27
27
|
@set -e; \
|
|
28
28
|
token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
|
|
29
|
-
if [ "$$token" = "$(
|
|
30
|
-
echo "[dry-run]
|
|
29
|
+
if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
|
|
30
|
+
echo "[dry-run] boru filler token detected: would tag $(TAG); nothing pushed."; \
|
|
31
31
|
exit 0; \
|
|
32
32
|
fi; \
|
|
33
33
|
git tag -a "$(TAG)" -m "rust v$(VERSION)"; \
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
use std::rc::Rc;
|
|
2
2
|
|
|
3
3
|
use crate::core::context::Context;
|
|
4
|
+
use crate::core::helpers::getp;
|
|
5
|
+
use crate::utility::voxgigstruct::Value;
|
|
4
6
|
|
|
5
7
|
pub fn prepare_method_util(ctx: &Rc<Context>) -> String {
|
|
6
8
|
let opname = ctx.op.borrow().name.clone();
|
|
7
9
|
|
|
10
|
+
// The API definition is authoritative: a POST-only or PATCH-based API
|
|
11
|
+
// exposes `update` as POST or PATCH, not the PUT the op name implies.
|
|
12
|
+
// Only fall back to the op-name convention when the point has no method.
|
|
13
|
+
let point = ctx.point.borrow().clone();
|
|
14
|
+
if let Value::Str(pm) = getp(&point, "method") {
|
|
15
|
+
if !pm.is_empty() {
|
|
16
|
+
return pm.to_uppercase();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
match opname.as_str() {
|
|
9
21
|
"create" => "POST",
|
|
10
22
|
"update" => "PUT",
|
|
@@ -14,14 +14,20 @@ object PreparePath {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
object PrepareMethod {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
case
|
|
22
|
-
case
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
// The API definition is authoritative: a POST-only or PATCH-based API
|
|
18
|
+
// exposes `update` as POST or PATCH, not the PUT the op name implies.
|
|
19
|
+
// Only fall back to the op-name convention when the point has no method.
|
|
20
|
+
def prepareMethod(ctx: Context): String = Struct.getprop(ctx.point, "method") match {
|
|
21
|
+
case s: String if s.nonEmpty => s.toUpperCase
|
|
22
|
+
case _ => ctx.op.name match {
|
|
23
|
+
case "create" => "POST"
|
|
24
|
+
case "update" => "PUT"
|
|
25
|
+
case "load" => "GET"
|
|
26
|
+
case "list" => "GET"
|
|
27
|
+
case "remove" => "DELETE"
|
|
28
|
+
case "patch" => "PATCH"
|
|
29
|
+
case _ => "GET"
|
|
30
|
+
}
|
|
25
31
|
}
|
|
26
32
|
}
|
|
27
33
|
|
|
@@ -13,21 +13,21 @@ clean:
|
|
|
13
13
|
# --- Release: tag for the SwiftPM registry ---------------------------------
|
|
14
14
|
# SwiftPM has no upload step - publishing IS the git tag. Publication is
|
|
15
15
|
# pending (see model/target/swift.aontu publish block); publishing a version
|
|
16
|
-
# currently means pushing the tag swift/vX.Y.Z. Run headless under the
|
|
16
|
+
# currently means pushing the tag swift/vX.Y.Z. Run headless under the boru key
|
|
17
17
|
# vault, which injects the GitHub token so nothing lands on disk or argv:
|
|
18
|
-
#
|
|
19
|
-
#
|
|
18
|
+
# boru vault exec --for=github=<alias> -- make publish
|
|
19
|
+
# boru `--dry-run` injects a filler token we detect to rehearse (no tag/push).
|
|
20
20
|
# set -e + tag-last: a failed push never leaves a tag behind.
|
|
21
21
|
VERSION := $(shell cat VERSION)
|
|
22
22
|
TAG := swift/v$(VERSION)
|
|
23
|
-
|
|
23
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
24
24
|
publish: test
|
|
25
25
|
@if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
|
|
26
26
|
echo "tag $(TAG) already exists - bump VERSION first"; exit 1; fi
|
|
27
27
|
@set -e; \
|
|
28
28
|
token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
|
|
29
|
-
if [ "$$token" = "$(
|
|
30
|
-
echo "[dry-run]
|
|
29
|
+
if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
|
|
30
|
+
echo "[dry-run] boru filler token detected: would tag $(TAG); nothing pushed."; \
|
|
31
31
|
exit 0; \
|
|
32
32
|
fi; \
|
|
33
33
|
git tag -a "$(TAG)" -m "swift v$(VERSION)"; \
|
|
@@ -14,6 +14,14 @@ private let methodMap: [String: String] = [
|
|
|
14
14
|
|
|
15
15
|
func prepareMethodUtil(_ ctx: Context) -> String {
|
|
16
16
|
let opname = ctx.op!.name
|
|
17
|
+
|
|
18
|
+
// The API definition is authoritative: a POST-only or PATCH-based API
|
|
19
|
+
// exposes `update` as POST or PATCH, not the PUT the op name implies.
|
|
20
|
+
// Only fall back to the op-name convention when the point has no method.
|
|
21
|
+
if let pm = gp(ctx.point, "method").asString, !pm.isEmpty {
|
|
22
|
+
return pm.uppercased()
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
return methodMap[opname] ?? "GET"
|
|
18
26
|
}
|
|
19
27
|
|
|
@@ -17,22 +17,22 @@ clean:
|
|
|
17
17
|
|
|
18
18
|
# --- Release: publish to npm ----------------------------------------------
|
|
19
19
|
# Compile, then publish this package to npm and tag ts/vX.Y.Z. Run headless
|
|
20
|
-
# under the
|
|
20
|
+
# under the boru key vault, which injects the npm auth token + the GitHub token
|
|
21
21
|
# (never on disk or argv):
|
|
22
|
-
#
|
|
23
|
-
#
|
|
22
|
+
# boru vault exec --for=npm=<alias> --for=github=<alias> -- make publish
|
|
23
|
+
# boru `--dry-run` injects a filler token we detect to rehearse (build only, no
|
|
24
24
|
# publish/tag). set -e + tag-last: a failed publish never leaves a tag behind.
|
|
25
25
|
SHELL := /bin/bash
|
|
26
26
|
VERSION := $(shell node -p "require('./package.json').version")
|
|
27
27
|
TAG := ts/v$(VERSION)
|
|
28
|
-
|
|
28
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
29
29
|
publish: test
|
|
30
30
|
@if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
|
|
31
31
|
echo "tag $(TAG) already exists — bump package.json version first"; exit 1; fi
|
|
32
32
|
@set -e; \
|
|
33
33
|
token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
|
|
34
|
-
if [ "$$token" = "$(
|
|
35
|
-
echo "[dry-run]
|
|
34
|
+
if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
|
|
35
|
+
echo "[dry-run] boru filler token detected: would publish to npm and tag $(TAG); nothing pushed."; \
|
|
36
36
|
exit 0; \
|
|
37
37
|
fi; \
|
|
38
38
|
npm stage publish --access public --registry https://registry.npmjs.org; \
|
|
@@ -82,16 +82,54 @@ function makeOptions(ctx: Context) {
|
|
|
82
82
|
},
|
|
83
83
|
clean: {
|
|
84
84
|
keys: 'key,token,id'
|
|
85
|
+
},
|
|
86
|
+
// Server-variable values for a templated base URL (OpenAPI server
|
|
87
|
+
// variables): `{name}` placeholders in `base` are substituted from
|
|
88
|
+
// this map at construction. Spec defaults arrive via the generated
|
|
89
|
+
// Config; user values override them.
|
|
90
|
+
server: {
|
|
91
|
+
'`$CHILD`': ''
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
// JavaScript specific option values.
|
|
89
96
|
optspec.system.fetch = opts.system?.fetch || global.fetch
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
// Clone the config side before merging: `config` is a module-level
|
|
99
|
+
// singleton in ts/js, and merge would otherwise use its nested maps as
|
|
100
|
+
// merge TARGETS — one instance's options (server, headers, ...) would
|
|
101
|
+
// contaminate every instance constructed after it.
|
|
102
|
+
opts = merge([{}, struct.clone(cfgopts), opts])
|
|
92
103
|
|
|
93
104
|
opts = validate(opts, optspec)
|
|
94
105
|
|
|
106
|
+
// Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
107
|
+
// Every placeholder must resolve to a non-empty value: from
|
|
108
|
+
// options.server (user), else the Config default. A placeholder that
|
|
109
|
+
// resolves to '' is a construction ERROR in live mode — the URL cannot
|
|
110
|
+
// work — but in test mode substitutes the deterministic value
|
|
111
|
+
// `test-<name>` so offline tests need no configuration.
|
|
112
|
+
if ('string' === typeof opts.base && opts.base.includes('{')) {
|
|
113
|
+
const testmode = true === opts.test.active ||
|
|
114
|
+
true === (opts.feature && opts.feature.test && opts.feature.test.active)
|
|
115
|
+
const server = opts.server || {}
|
|
116
|
+
opts.base = opts.base.replace(/\{([A-Za-z0-9_]+)\}/g,
|
|
117
|
+
(_m: string, name: string) => {
|
|
118
|
+
let val = server[name]
|
|
119
|
+
val = 'string' === typeof val ? val : ''
|
|
120
|
+
if ('' === val) {
|
|
121
|
+
if (testmode) {
|
|
122
|
+
return 'test-' + name
|
|
123
|
+
}
|
|
124
|
+
throw new Error(
|
|
125
|
+
`${config?.main?.name || 'SDK'}: the server variable '${name}' is required: ` +
|
|
126
|
+
`the API base URL is '${opts.base}' — pass { server: { ${name}: '...' } } ` +
|
|
127
|
+
`in the SDK options`)
|
|
128
|
+
}
|
|
129
|
+
return val
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
95
133
|
// Resolve the feature add-order: an explicit array order (above) wins;
|
|
96
134
|
// otherwise order the map test-first, then the remaining names sorted, so
|
|
97
135
|
// the outcome is deterministic and `test` is always the base transport.
|
|
@@ -16,6 +16,15 @@ function prepareMethod(ctx: Context) {
|
|
|
16
16
|
patch: 'PATCH',
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
// The API definition is authoritative: a POST-only or PATCH-based API
|
|
20
|
+
// exposes `update` as POST or PATCH, not the PUT the op name implies.
|
|
21
|
+
// Only fall back to the op-name convention when the point has no method.
|
|
22
|
+
const method = ctx.point?.method
|
|
23
|
+
|
|
24
|
+
if (null != method && '' !== method) {
|
|
25
|
+
return method.toUpperCase()
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
return methodMap[key]
|
|
20
29
|
}
|
|
21
30
|
|
|
@@ -229,6 +229,8 @@ describe('PrimaryUtility', async () => {
|
|
|
229
229
|
body: 'present',
|
|
230
230
|
})
|
|
231
231
|
const reqClient = new (SDK as any)({
|
|
232
|
+
// Concrete base: a live construction must satisfy any server variables a templated base URL declares; a literal base sidesteps the requirement.
|
|
233
|
+
base: 'http://localhost:8080',
|
|
232
234
|
system: { fetch: mockFetch }
|
|
233
235
|
})
|
|
234
236
|
const reqUtility = reqClient.utility()
|
|
@@ -410,6 +412,7 @@ describe('PrimaryUtility', async () => {
|
|
|
410
412
|
test('fetcher-live', async () => {
|
|
411
413
|
const calls: any[] = []
|
|
412
414
|
const liveClient = new (SDK as any)({
|
|
415
|
+
base: 'http://localhost:8080',
|
|
413
416
|
system: {
|
|
414
417
|
fetch: async (url: string, init: any) => {
|
|
415
418
|
calls.push({ url, init })
|
|
@@ -431,6 +434,7 @@ describe('PrimaryUtility', async () => {
|
|
|
431
434
|
|
|
432
435
|
test('fetcher-blocked-test-mode', async () => {
|
|
433
436
|
const blockedClient = new (SDK as any)({
|
|
437
|
+
base: 'http://localhost:8080',
|
|
434
438
|
system: { fetch: async () => ({}) }
|
|
435
439
|
})
|
|
436
440
|
blockedClient._mode = 'test'
|
|
@@ -825,6 +825,21 @@ pub fn param_util(ctx: *Context, paramdef: Value) Value {
|
|
|
825
825
|
|
|
826
826
|
pub fn prepare_method_util(ctx: *Context) []const u8 {
|
|
827
827
|
const opname = ctx.op.name;
|
|
828
|
+
|
|
829
|
+
// The API definition is authoritative: a POST-only or PATCH-based API
|
|
830
|
+
// exposes `update` as POST or PATCH, not the PUT the op name implies.
|
|
831
|
+
// Only fall back to the op-name convention when the point has no method.
|
|
832
|
+
switch (h.getp(ctx.point, "method")) {
|
|
833
|
+
.string => |m| {
|
|
834
|
+
if (0 < m.len) {
|
|
835
|
+
const upper = h.A().alloc(u8, m.len) catch return m;
|
|
836
|
+
for (m, 0..) |c, i| upper[i] = std.ascii.toUpper(c);
|
|
837
|
+
return upper;
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
else => {},
|
|
841
|
+
}
|
|
842
|
+
|
|
828
843
|
if (std.mem.eql(u8, opname, "create")) return "POST";
|
|
829
844
|
if (std.mem.eql(u8, opname, "update")) return "PUT";
|
|
830
845
|
if (std.mem.eql(u8, opname, "load")) return "GET";
|
package/src/cmp/Deploy.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
// `publish` sections (see model/sdkgen.aontu):
|
|
11
11
|
//
|
|
12
12
|
// publish.tag — git release tag `<prefix>/vX.Y.Z`; every port has
|
|
13
|
-
// one, pushed with a token from the
|
|
13
|
+
// one, pushed with a token from the boru key vault
|
|
14
14
|
// (--for recipe + alias, default github/github).
|
|
15
15
|
// publish.registry — package registry details (name, url, vault
|
|
16
16
|
// credential recipe or raw env mapping) plus a
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
// Follows the voxgig/struct root Makefile conventions: per-target deploy
|
|
26
26
|
// targets, deliberately no all-targets real deploy (each upload is
|
|
27
27
|
// irreversible), and an everything-at-once DRY run leaning on
|
|
28
|
-
// `
|
|
28
|
+
// `boru vault exec --dry-run` filler-token cooperation in each target's
|
|
29
29
|
// publish recipe.
|
|
30
30
|
const Deploy = cmp(function Deploy(props: any) {
|
|
31
31
|
const { ctx$ } = props
|
|
@@ -76,7 +76,7 @@ function aliasVarName(name: string): string {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
// The
|
|
79
|
+
// The boru vault exec argument string for a target: `--for=<recipe>=<alias>`
|
|
80
80
|
// flags where a preset recipe exists, or a raw `'alias=ENV_VAR,...'`
|
|
81
81
|
// mapping when any credential lacks a preset (e.g. luarocks). The github
|
|
82
82
|
// token for the tag push is always included.
|
|
@@ -142,10 +142,10 @@ function makeDeployMakefile(model: any, targets: any[]): string {
|
|
|
142
142
|
return `
|
|
143
143
|
deploy-${t.name}:
|
|
144
144
|
\t@echo "deploy-${t.name}: tag-only port — publishing the git tag."
|
|
145
|
-
\
|
|
145
|
+
\tboru vault exec ${ghArgs} -- $(MAKE) tag-push-${t.name}
|
|
146
146
|
|
|
147
147
|
deploy-dry-${t.name}:
|
|
148
|
-
\
|
|
148
|
+
\tboru vault exec --dry-run ${ghArgs} -- $(MAKE) tag-push-${t.name}
|
|
149
149
|
${tagPushRecipe(t.name, 'tag-only port')}
|
|
150
150
|
`
|
|
151
151
|
}
|
|
@@ -157,20 +157,20 @@ ${tagPushRecipe(t.name, 'tag-only port')}
|
|
|
157
157
|
return `
|
|
158
158
|
deploy-${t.name}:
|
|
159
159
|
\t@echo "deploy-${t.name}: ${reg.name} publication is pending — publishing the git tag only."
|
|
160
|
-
\
|
|
160
|
+
\tboru vault exec ${ghArgs} -- $(MAKE) tag-push-${t.name}
|
|
161
161
|
|
|
162
162
|
deploy-dry-${t.name}:
|
|
163
|
-
\
|
|
163
|
+
\tboru vault exec --dry-run ${ghArgs} -- $(MAKE) tag-push-${t.name}
|
|
164
164
|
${tagPushRecipe(t.name, reg.name + ' publication pending — tag-only deploy')}
|
|
165
165
|
`
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
return `
|
|
169
169
|
deploy-${t.name}:
|
|
170
|
-
\
|
|
170
|
+
\tboru vault exec ${args} -- $(MAKE) -C ${t.name} publish
|
|
171
171
|
|
|
172
172
|
deploy-dry-${t.name}:
|
|
173
|
-
\
|
|
173
|
+
\tboru vault exec --dry-run ${args} -- $(MAKE) -C ${t.name} publish
|
|
174
174
|
`
|
|
175
175
|
}).join('')
|
|
176
176
|
|
|
@@ -183,7 +183,7 @@ deploy-dry-${t.name}:
|
|
|
183
183
|
#
|
|
184
184
|
# Every port gets a git release tag <target>/vX.Y.Z. Ports with an ACTIVE
|
|
185
185
|
# registry also publish a package there. Credentials are injected at exec
|
|
186
|
-
# time by the
|
|
186
|
+
# time by the boru key vault (https://github.com/boru-lang/boru) — never
|
|
187
187
|
# stored on disk or passed on the command line.
|
|
188
188
|
#
|
|
189
189
|
# Publication state (from the model):
|
|
@@ -194,7 +194,7 @@ ${summary}
|
|
|
194
194
|
# registry upload is irreversible); while a
|
|
195
195
|
# registry is pending this publishes the
|
|
196
196
|
# port's git tag only
|
|
197
|
-
# make deploy-dry rehearse EVERY target:
|
|
197
|
+
# make deploy-dry rehearse EVERY target: boru --dry-run
|
|
198
198
|
# injects a filler token that each publish
|
|
199
199
|
# recipe detects, so build + test run in full
|
|
200
200
|
# but nothing is uploaded and no tag is cut
|
|
@@ -207,7 +207,7 @@ ${varLines}
|
|
|
207
207
|
|
|
208
208
|
# Lockstep SDK version, read from the canonical ts manifest.
|
|
209
209
|
VERSION := $(shell node -p "require('./ts/package.json').version" 2>/dev/null || echo 0.0.0)
|
|
210
|
-
|
|
210
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
211
211
|
|
|
212
212
|
TARGETS := ${targets.map((t: any) => t.name).join(' ')}
|
|
213
213
|
|
|
@@ -233,7 +233,7 @@ ${deployRules}`
|
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
|
|
236
|
-
// The root-level tag creation + push recipe for a target:
|
|
236
|
+
// The root-level tag creation + push recipe for a target: boru --dry-run
|
|
237
237
|
// filler cooperation, idempotent tag creation, token-authenticated https
|
|
238
238
|
// push (works from an ssh-remote clone without ssh keys).
|
|
239
239
|
function tagPushRecipe(name: string, note: string): string {
|
|
@@ -241,9 +241,9 @@ function tagPushRecipe(name: string, note: string): string {
|
|
|
241
241
|
tag-push-${name}:
|
|
242
242
|
\t@set -e; tag="${name}/v$(VERSION)"; \\
|
|
243
243
|
\ttoken="\$\${GITHUB_TOKEN:-$$GH_TOKEN}"; \\
|
|
244
|
-
\tif [ "$$token" = "$(
|
|
245
|
-
\t echo "[dry-run]
|
|
246
|
-
\tif [ -z "$$token" ]; then echo "tag-push-${name}: no GITHUB_TOKEN in env — run via make deploy-${name} (
|
|
244
|
+
\tif [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \\
|
|
245
|
+
\t echo "[dry-run] boru filler token detected: would create (if missing) and push tag $$tag; nothing pushed."; exit 0; fi; \\
|
|
246
|
+
\tif [ -z "$$token" ]; then echo "tag-push-${name}: no GITHUB_TOKEN in env — run via make deploy-${name} (boru vault exec)"; exit 1; fi; \\
|
|
247
247
|
\tif git rev-parse -q --verify "refs/tags/$$tag" >/dev/null; then \\
|
|
248
248
|
\t echo "tag $$tag already exists — pushing existing tag"; \\
|
|
249
249
|
\telse git tag -a "$$tag" -m "Release $$tag"; fi; \\
|
package/src/cmp/ReadmeTop.ts
CHANGED
|
@@ -549,28 +549,30 @@ Pass custom features via the \`extend\` option at construction time.
|
|
|
549
549
|
`)
|
|
550
550
|
}
|
|
551
551
|
|
|
552
|
-
// 13. Upstream API —
|
|
552
|
+
// 13. Upstream API — always disclose the OpenAPI origin and where the
|
|
553
|
+
// spec(s) live; contact/servers links come from the OpenAPI info block.
|
|
553
554
|
const upstreamUrl = (info.contact && info.contact.url)
|
|
554
555
|
|| (info.servers && info.servers[0] && info.servers[0].url)
|
|
555
556
|
|| homepage
|
|
556
|
-
|
|
557
|
-
Content(`## Upstream API
|
|
557
|
+
Content(`## Upstream API
|
|
558
558
|
|
|
559
559
|
This SDK is generated from the upstream OpenAPI specification. It is an
|
|
560
560
|
unofficial client and is not affiliated with the API provider.
|
|
561
561
|
|
|
562
|
+
The OpenAPI spec(s) this SDK was generated from are kept in the
|
|
563
|
+
[\`.sdk/def/\`](.sdk/def/) folder.
|
|
564
|
+
|
|
562
565
|
`)
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
`)
|
|
566
|
-
}
|
|
567
|
-
if (docsUrl && docsUrl !== upstreamUrl) {
|
|
568
|
-
Content(`- Documentation: [${docsUrl}](${docsUrl})
|
|
566
|
+
if (upstreamUrl) {
|
|
567
|
+
Content(`- Upstream API: [${upstreamUrl}](${upstreamUrl})
|
|
569
568
|
`)
|
|
570
|
-
|
|
571
|
-
|
|
569
|
+
}
|
|
570
|
+
if (docsUrl && docsUrl !== upstreamUrl) {
|
|
571
|
+
Content(`- Documentation: [${docsUrl}](${docsUrl})
|
|
572
572
|
`)
|
|
573
573
|
}
|
|
574
|
+
Content(`
|
|
575
|
+
`)
|
|
574
576
|
|
|
575
577
|
// 13b. Security
|
|
576
578
|
Content(`## Security
|
package/src/helpers/naming.ts
CHANGED
|
@@ -126,6 +126,75 @@ function rbSafeTypeName(Name: string): string {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
|
|
129
|
+
// Swift SDK-OWNED TYPE NAMES — a third hazard, distinct from both sets above.
|
|
130
|
+
//
|
|
131
|
+
// The keyword sets guard local bindings; the Ruby set guards clobbering the
|
|
132
|
+
// LANGUAGE's core. This set guards clobbering OUR OWN runtime, because Swift
|
|
133
|
+
// has no namespacing WITHIN a module: every type the swift templates declare
|
|
134
|
+
// and every generated entity type land in the same module. Two declarations
|
|
135
|
+
// of one name is a hard error, not a silent override:
|
|
136
|
+
//
|
|
137
|
+
// // core/Response.swift (template)
|
|
138
|
+
// public final class Response { ... } // transport wrapper
|
|
139
|
+
// // entity/<Prefix>Types.swift (generated from a spec schema named Response)
|
|
140
|
+
// public struct Response { ... }
|
|
141
|
+
// -> error: invalid redeclaration of 'Response'
|
|
142
|
+
// -> error: 'Response' is ambiguous for type lookup (every core file)
|
|
143
|
+
//
|
|
144
|
+
// Found 2026-08-07: the Hook0 spec has a `Response` schema, which took the
|
|
145
|
+
// whole swift target down. `Response` is merely the first collision to be
|
|
146
|
+
// hit — every name below is equally exposed.
|
|
147
|
+
//
|
|
148
|
+
// Sourced by scanning BOTH `tm/swift/Sources/*/` (templates) and
|
|
149
|
+
// `src/cmp/swift/*.ts` (components) for top-level type declarations —
|
|
150
|
+
// regardless of access level. `internal` is Swift's default and is still
|
|
151
|
+
// module-wide, and `open class BaseFeature` is not `public` either, so an
|
|
152
|
+
// access-level filter under-collects and silently reopens the bug.
|
|
153
|
+
//
|
|
154
|
+
// Nested types (a `typealias Element` inside a struct) and the separate Tests
|
|
155
|
+
// module (`ReadmeExamplesTest`) do NOT share this namespace and are excluded.
|
|
156
|
+
//
|
|
157
|
+
// `swift-sdk-types.test.ts` re-derives this list from the templates and fails
|
|
158
|
+
// on drift, so adding a public type to a swift template cannot silently
|
|
159
|
+
// reopen the bug.
|
|
160
|
+
const SWIFT_SDK_TYPES = new Set<string>([
|
|
161
|
+
// core runtime
|
|
162
|
+
'Context', 'Control', 'Entity', 'Operation', 'Point', 'Response', 'Result',
|
|
163
|
+
'SdkConfig', 'Spec', 'Utility',
|
|
164
|
+
// struct library
|
|
165
|
+
'Injection', 'Injector', 'JSON', 'JSONParseError', 'Modify',
|
|
166
|
+
'OrderedDictionary', 'Sentinel', 'Value', 'VList', 'VMap', 'WalkApply',
|
|
167
|
+
// function/callback aliases
|
|
168
|
+
'FetcherFunc', 'Formatter', 'NativeCall0', 'NativeRef', 'SystemFetch',
|
|
169
|
+
// features
|
|
170
|
+
'AuditFeature', 'BaseFeature', 'CacheFeature', 'ClienttrackFeature',
|
|
171
|
+
'DebugFeature', 'IdempotencyFeature', 'LogFeature', 'MetricsBucket',
|
|
172
|
+
'MetricsFeature', 'NetsimFeature', 'PagingFeature', 'ProxyFeature',
|
|
173
|
+
'RatelimitFeature', 'RbacFeature', 'RetryFeature', 'StreamingFeature',
|
|
174
|
+
'TelemetryFeature', 'TestFeature', 'TimeoutFeature',
|
|
175
|
+
])
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
// Does `Name` collide with a type the swift SDK runtime already declares?
|
|
179
|
+
function isSwiftSdkType(Name: string): boolean {
|
|
180
|
+
return SWIFT_SDK_TYPES.has(Name)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
// A module-safe Swift type name for a generated type: unchanged, unless the
|
|
185
|
+
// swift runtime already declares it, in which case `Type` is appended
|
|
186
|
+
// (`Response` -> `ResponseType`). Mirrors rbSafeTypeName deliberately — same
|
|
187
|
+
// suffix, same "only rename on an actual collision" rule, so SDKs that do not
|
|
188
|
+
// collide are byte-identical to before.
|
|
189
|
+
//
|
|
190
|
+
// Applied ONLY to the bare entity data type. Per-op type names already carry
|
|
191
|
+
// their own suffix (`ResponseCreateData`, `ResponseLoadMatch`) and the entity
|
|
192
|
+
// CLASS is separately suffixed (`ResponseEntity`), so neither ever collided.
|
|
193
|
+
function swiftSafeTypeName(Name: string): string {
|
|
194
|
+
return isSwiftSdkType(Name) ? Name + 'Type' : Name
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
129
198
|
// Is `name` a reserved word (an illegal identifier) in the target language?
|
|
130
199
|
function isReservedName(name: string, lang: string): boolean {
|
|
131
200
|
const set = RESERVED[lang]
|
|
@@ -189,6 +258,8 @@ export {
|
|
|
189
258
|
exampleVarName,
|
|
190
259
|
isRbCoreConstant,
|
|
191
260
|
rbSafeTypeName,
|
|
261
|
+
isSwiftSdkType,
|
|
262
|
+
swiftSafeTypeName,
|
|
192
263
|
jsProp,
|
|
193
264
|
jsOptProp,
|
|
194
265
|
jsKey,
|