@voxgig/sdkgen 1.3.18 → 1.3.19

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 (68) hide show
  1. package/dist/cmp/Deploy.js +16 -16
  2. package/dist/cmp/Deploy.js.map +1 -1
  3. package/dist/cmp/ReadmeTop.js +13 -11
  4. package/dist/cmp/ReadmeTop.js.map +1 -1
  5. package/dist/helpers/naming.d.ts +3 -1
  6. package/dist/helpers/naming.js +65 -0
  7. package/dist/helpers/naming.js.map +1 -1
  8. package/dist/helpers/serverVars.d.ts +10 -0
  9. package/dist/helpers/serverVars.js +87 -0
  10. package/dist/helpers/serverVars.js.map +1 -0
  11. package/dist/sdkgen.d.ts +3 -2
  12. package/dist/sdkgen.js +6 -1
  13. package/dist/sdkgen.js.map +1 -1
  14. package/dist/tsconfig.tsbuildinfo +1 -1
  15. package/package.json +1 -1
  16. package/project/.sdk/model/target/go-cli.aontu +2 -2
  17. package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +22 -15
  18. package/project/.sdk/src/cmp/go/Config_go.ts +10 -1
  19. package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +54 -35
  20. package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +7 -7
  21. package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +21 -18
  22. package/project/.sdk/src/cmp/js/Config_js.ts +11 -0
  23. package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +2 -2
  24. package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +4 -0
  25. package/project/.sdk/src/cmp/lua/Config_lua.ts +10 -1
  26. package/project/.sdk/src/cmp/php/Config_php.ts +13 -2
  27. package/project/.sdk/src/cmp/py/Config_py.ts +10 -1
  28. package/project/.sdk/src/cmp/rb/Config_rb.ts +12 -1
  29. package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +25 -18
  30. package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +10 -3
  31. package/project/.sdk/src/cmp/ts/Config_ts.ts +11 -0
  32. package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +2 -2
  33. package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +4 -0
  34. package/project/.sdk/tm/csharp/Makefile +6 -6
  35. package/project/.sdk/tm/dart/Makefile +3 -3
  36. package/project/.sdk/tm/go/Makefile +6 -6
  37. package/project/.sdk/tm/go/test/primary_utility_test.go +5 -0
  38. package/project/.sdk/tm/go/utility/make_options.go +48 -0
  39. package/project/.sdk/tm/java/Makefile +6 -6
  40. package/project/.sdk/tm/js/Makefile +6 -6
  41. package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -1
  42. package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +5 -0
  43. package/project/.sdk/tm/kotlin/Makefile +6 -6
  44. package/project/.sdk/tm/lua/Makefile +7 -7
  45. package/project/.sdk/tm/lua/feature/test_feature.lua +29 -1
  46. package/project/.sdk/tm/lua/test/primary_utility_test.lua +4 -0
  47. package/project/.sdk/tm/lua/utility/make_options.lua +39 -0
  48. package/project/.sdk/tm/perl/Makefile +6 -6
  49. package/project/.sdk/tm/php/Makefile +6 -6
  50. package/project/.sdk/tm/php/feature/TestFeature.php +30 -2
  51. package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +5 -0
  52. package/project/.sdk/tm/php/utility/MakeOptions.php +44 -0
  53. package/project/.sdk/tm/py/Makefile +6 -6
  54. package/project/.sdk/tm/py/test/test_primary_utility.py +5 -0
  55. package/project/.sdk/tm/py/utility/make_options.py +42 -0
  56. package/project/.sdk/tm/rb/Makefile +6 -6
  57. package/project/.sdk/tm/rb/test/primary_utility_test.rb +4 -0
  58. package/project/.sdk/tm/rb/utility/make_options.rb +37 -0
  59. package/project/.sdk/tm/rust/Makefile +6 -6
  60. package/project/.sdk/tm/swift/Makefile +6 -6
  61. package/project/.sdk/tm/ts/Makefile +6 -6
  62. package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +39 -1
  63. package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +4 -0
  64. package/src/cmp/Deploy.ts +16 -16
  65. package/src/cmp/ReadmeTop.ts +13 -11
  66. package/src/helpers/naming.ts +71 -0
  67. package/src/helpers/serverVars.ts +105 -0
  68. package/src/sdkgen.ts +6 -1
@@ -587,6 +587,10 @@ class PrimaryUtilityTest extends TestCase
587
587
  {
588
588
  $calls = [];
589
589
  $live_client = new ProjectNameSDK([
590
+ // Concrete base: a live construction must satisfy any server
591
+ // variables a templated base URL declares; a literal base
592
+ // sidesteps the requirement.
593
+ 'base' => 'http://localhost:8080',
590
594
  'system' => [
591
595
  'fetch' => function (string $url, array $fetchdef) use (&$calls) {
592
596
  $calls[] = ['url' => $url, 'init' => $fetchdef];
@@ -614,6 +618,7 @@ class PrimaryUtilityTest extends TestCase
614
618
  public function test_fetcher_blocked_test_mode(): void
615
619
  {
616
620
  $blocked_client = new ProjectNameSDK([
621
+ 'base' => 'http://localhost:8080',
617
622
  'system' => [
618
623
  'fetch' => function (string $url, array $fetchdef) {
619
624
  return [[], null];
@@ -88,6 +88,11 @@ class ProjectNameMakeOptions
88
88
  'system' => (object)[],
89
89
  'test' => ['active' => false, 'entity' => ['`$OPEN`' => true]],
90
90
  'clean' => ['keys' => 'key,token,id'],
91
+ // Server-variable values for a templated base URL (OpenAPI server
92
+ // variables): {name} placeholders in 'base' are substituted from
93
+ // this map at construction. Spec defaults arrive via the generated
94
+ // config; user values override them.
95
+ 'server' => ['`$CHILD`' => ''],
91
96
  ];
92
97
 
93
98
  // Empty [] would be treated as a list and clobber the map under merge;
@@ -101,6 +106,45 @@ class ProjectNameMakeOptions
101
106
  $opts = [];
102
107
  }
103
108
 
109
+ // Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
110
+ // Every placeholder must resolve to a non-empty value: from
111
+ // $options['server'] (user), else the config default. A placeholder
112
+ // that resolves to '' is a construction ERROR in live mode — the URL
113
+ // cannot work — but in test mode substitutes the deterministic value
114
+ // "test-<name>" so offline tests need no configuration.
115
+ $base = $opts['base'] ?? null;
116
+ if (is_string($base) && strpos($base, '{') !== false) {
117
+ $testmode =
118
+ \Voxgig\Struct\Struct::getpath($opts, 'test.active') === true
119
+ || \Voxgig\Struct\Struct::getpath($opts, 'feature.test.active') === true;
120
+ $server = is_array($opts['server'] ?? null) ? $opts['server'] : [];
121
+ $sdkname = \Voxgig\Struct\Struct::getpath($config, 'main.name');
122
+ if (!is_string($sdkname) || $sdkname === '') {
123
+ $sdkname = 'SDK';
124
+ }
125
+ $opts['base'] = preg_replace_callback(
126
+ '/\{([A-Za-z0-9_]+)\}/',
127
+ function ($m) use ($server, $testmode, $sdkname, $base) {
128
+ $name = $m[1];
129
+ $val = $server[$name] ?? '';
130
+ if (!is_string($val)) {
131
+ $val = '';
132
+ }
133
+ if ($val === '') {
134
+ if ($testmode) {
135
+ return 'test-' . $name;
136
+ }
137
+ throw new \InvalidArgumentException(
138
+ $sdkname . ": the server variable '" . $name . "' is required: " .
139
+ "the API base URL is '" . $base . "' — pass " .
140
+ "['server' => ['" . $name . "' => '...']] in the SDK options");
141
+ }
142
+ return $val;
143
+ },
144
+ $base
145
+ );
146
+ }
147
+
104
148
  if ($sys_fetch) {
105
149
  if (!is_array($opts['system'] ?? null)) {
106
150
  $opts['system'] = [];
@@ -10,16 +10,16 @@ clean:
10
10
  find . -name __pycache__ -exec rm -rf {} + 2>/dev/null; true
11
11
 
12
12
  # --- Release: publish to PyPI ---------------------------------------------
13
- # Publish this package to PyPI, then tag py/vX.Y.Z. Run headless under the aql
13
+ # Publish this package to PyPI, then tag py/vX.Y.Z. Run headless under the boru
14
14
  # key vault, which injects the PyPI + GitHub tokens as environment variables
15
15
  # (never written to disk or argv):
16
- # aql vault exec --for=pypi=<alias> --for=github=<alias> -- make publish
17
- # aql `--dry-run` injects a filler token we detect to rehearse: builds the dist
16
+ # boru vault exec --for=pypi=<alias> --for=github=<alias> -- make publish
17
+ # boru `--dry-run` injects a filler token we detect to rehearse: builds the dist
18
18
  # but performs no upload, tag, or push. set -e + tag-last: a failed upload never
19
19
  # leaves a tag behind. Needs python `build` + `twine` (pip install build twine).
20
20
  VERSION := $(shell sed -nE 's/^version *= *"([^"]+)".*/\1/p' pyproject.toml | head -1)
21
21
  TAG := py/v$(VERSION)
22
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
22
+ BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
23
23
  publish: test
24
24
  @if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
25
25
  echo "tag $(TAG) already exists — bump pyproject.toml version first"; exit 1; fi
@@ -27,8 +27,8 @@ publish: test
27
27
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
28
28
  rm -rf dist; \
29
29
  python3 -m build; \
30
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ] || [ "$$TWINE_PASSWORD" = "$(AQL_DRY_RUN_FILLER)" ]; then \
31
- echo "[dry-run] aql filler token detected: built the dist; would upload to PyPI and tag $(TAG); nothing pushed."; \
30
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ] || [ "$$TWINE_PASSWORD" = "$(BORU_DRY_RUN_FILLER)" ]; then \
31
+ echo "[dry-run] boru filler token detected: built the dist; would upload to PyPI and tag $(TAG); nothing pushed."; \
32
32
  exit 0; \
33
33
  fi; \
34
34
  python3 -m twine upload dist/*; \
@@ -468,6 +468,10 @@ class TestPrimaryUtility:
468
468
  return {"status": 200, "statusText": "OK"}, None
469
469
 
470
470
  live_client = ProjectNameSDK({
471
+ # Concrete base: a live construction must satisfy any server
472
+ # variables a templated base URL declares; a literal base
473
+ # sidesteps the requirement.
474
+ "base": "http://localhost:8080",
471
475
  "system": {
472
476
  "fetch": mock_fetch,
473
477
  },
@@ -490,6 +494,7 @@ class TestPrimaryUtility:
490
494
  return {}, None
491
495
 
492
496
  blocked_client = ProjectNameSDK({
497
+ "base": "http://localhost:8080",
493
498
  "system": {
494
499
  "fetch": mock_fetch,
495
500
  },
@@ -84,6 +84,13 @@ def make_options_util(ctx):
84
84
  "clean": {
85
85
  "keys": "key,token,id",
86
86
  },
87
+ # Server-variable values for a templated base URL (OpenAPI server
88
+ # variables): {name} placeholders in "base" are substituted from this
89
+ # map at construction. Spec defaults arrive via the generated config;
90
+ # user values override them.
91
+ "server": {
92
+ "`$CHILD`": "",
93
+ },
87
94
  }
88
95
 
89
96
  # Preserve system.fetch before merge/validate.
@@ -95,6 +102,41 @@ def make_options_util(ctx):
95
102
  validated = {}
96
103
  opts = validated
97
104
 
105
+ # Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
106
+ # Every placeholder must resolve to a non-empty value: from
107
+ # options["server"] (user), else the config default. A placeholder that
108
+ # resolves to "" is a construction ERROR in live mode — the URL cannot
109
+ # work — but in test mode substitutes the deterministic value
110
+ # "test-<name>" so offline tests need no configuration.
111
+ base = opts.get("base")
112
+ if isinstance(base, str) and "{" in base:
113
+ import re as _re
114
+ testmode = (
115
+ vs.getpath(opts, "test.active") is True
116
+ or vs.getpath(opts, "feature.test.active") is True
117
+ )
118
+ server = opts.get("server") if isinstance(opts.get("server"), dict) else {}
119
+ sdkname = "SDK"
120
+ if isinstance(config, dict):
121
+ mn = vs.getpath(config, "main.name")
122
+ if isinstance(mn, str) and mn != "":
123
+ sdkname = mn
124
+
125
+ def _sub(m):
126
+ name = m.group(1)
127
+ val = server.get(name)
128
+ val = val if isinstance(val, str) else ""
129
+ if val == "":
130
+ if testmode:
131
+ return "test-" + name
132
+ raise ValueError(
133
+ sdkname + ": the server variable '" + name + "' is required: "
134
+ "the API base URL is '" + base + "' — pass "
135
+ '{"server": {"' + name + '": "..."}} in the SDK options')
136
+ return val
137
+
138
+ opts["base"] = _re.sub(r"\{([A-Za-z0-9_]+)\}", _sub, base)
139
+
98
140
  # Restore system.fetch.
99
141
  if sys_fetch is not None:
100
142
  if isinstance(opts.get("system"), dict):
@@ -13,14 +13,14 @@ clean:
13
13
 
14
14
  # --- Release: publish to RubyGems -----------------------------------------
15
15
  # Build the gem and push it to RubyGems, then tag rb/vX.Y.Z. Run headless under
16
- # the aql key vault, which injects GEM_HOST_API_KEY + the GitHub token (never on
16
+ # the boru key vault, which injects GEM_HOST_API_KEY + the GitHub token (never on
17
17
  # disk or argv):
18
- # aql vault exec --for=gem=<alias> --for=github=<alias> -- make publish
19
- # aql `--dry-run` injects a filler token we detect to rehearse (build only, no
18
+ # boru vault exec --for=gem=<alias> --for=github=<alias> -- make publish
19
+ # boru `--dry-run` injects a filler token we detect to rehearse (build only, no
20
20
  # push/tag). set -e + tag-last: a failed push never leaves a tag behind.
21
21
  VERSION := $(shell sed -nE 's/.*\.version *= *"([^"]+)".*/\1/p' *.gemspec | head -1)
22
22
  TAG := rb/v$(VERSION)
23
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
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 the gemspec version first"; exit 1; fi
@@ -28,8 +28,8 @@ publish: test
28
28
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
29
29
  rm -f *.gem; \
30
30
  gem build *.gemspec; \
31
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ] || [ "$$GEM_HOST_API_KEY" = "$(AQL_DRY_RUN_FILLER)" ]; then \
32
- echo "[dry-run] aql filler token detected: built the gem; would push to RubyGems and tag $(TAG); nothing pushed."; \
31
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ] || [ "$$GEM_HOST_API_KEY" = "$(BORU_DRY_RUN_FILLER)" ]; then \
32
+ echo "[dry-run] boru filler token detected: built the gem; would push to RubyGems and tag $(TAG); nothing pushed."; \
33
33
  exit 0; \
34
34
  fi; \
35
35
  gem push *.gem; \
@@ -176,6 +176,9 @@ class PrimaryUtilityTest < Minitest::Test
176
176
  def test_fetcher_live
177
177
  calls = []
178
178
  live_client = ProjectNameSDK.new({
179
+ # Concrete base: a live construction must satisfy any server variables
180
+ # a templated base URL declares; a literal base sidesteps the requirement.
181
+ "base" => "http://localhost:8080",
179
182
  "system" => {
180
183
  "fetch" => ->(url, fetchdef) {
181
184
  calls << { "url" => url, "init" => fetchdef }
@@ -199,6 +202,7 @@ class PrimaryUtilityTest < Minitest::Test
199
202
 
200
203
  def test_fetcher_blocked_test_mode
201
204
  blocked_client = ProjectNameSDK.new({
205
+ "base" => "http://localhost:8080",
202
206
  "system" => {
203
207
  "fetch" => ->(url, fetchdef) {
204
208
  return {}, nil
@@ -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
@@ -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 aql key vault, which injects the GitHub token so
16
+ # headless under the boru key vault, which injects the GitHub token so
17
17
  # nothing lands on disk or argv:
18
- # aql vault exec --for=github=<alias> -- make publish
19
- # aql `--dry-run` injects a filler token we detect to rehearse (no tag/push).
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
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
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" = "$(AQL_DRY_RUN_FILLER)" ]; then \
30
- echo "[dry-run] aql filler token detected: would tag $(TAG); nothing pushed."; \
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)"; \
@@ -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 aql key
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
- # aql vault exec --for=github=<alias> -- make publish
19
- # aql `--dry-run` injects a filler token we detect to rehearse (no tag/push).
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
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
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" = "$(AQL_DRY_RUN_FILLER)" ]; then \
30
- echo "[dry-run] aql filler token detected: would tag $(TAG); nothing pushed."; \
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)"; \
@@ -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 aql key vault, which injects the npm auth token + the GitHub token
20
+ # under the boru key vault, which injects the npm auth token + the GitHub token
21
21
  # (never on disk or argv):
22
- # aql vault exec --for=npm=<alias> --for=github=<alias> -- make publish
23
- # aql `--dry-run` injects a filler token we detect to rehearse (build only, no
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
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
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" = "$(AQL_DRY_RUN_FILLER)" ]; then \
35
- echo "[dry-run] aql filler token detected: would publish to npm and tag $(TAG); nothing pushed."; \
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
- opts = merge([{}, cfgopts, opts])
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.
@@ -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'
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 aql key vault
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
- // `aql vault exec --dry-run` filler-token cooperation in each target's
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 aql vault exec argument string for a target: `--for=<recipe>=<alias>`
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
- \taql vault exec ${ghArgs} -- $(MAKE) tag-push-${t.name}
145
+ \tboru vault exec ${ghArgs} -- $(MAKE) tag-push-${t.name}
146
146
 
147
147
  deploy-dry-${t.name}:
148
- \taql vault exec --dry-run ${ghArgs} -- $(MAKE) tag-push-${t.name}
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
- \taql vault exec ${ghArgs} -- $(MAKE) tag-push-${t.name}
160
+ \tboru vault exec ${ghArgs} -- $(MAKE) tag-push-${t.name}
161
161
 
162
162
  deploy-dry-${t.name}:
163
- \taql vault exec --dry-run ${ghArgs} -- $(MAKE) tag-push-${t.name}
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
- \taql vault exec ${args} -- $(MAKE) -C ${t.name} publish
170
+ \tboru vault exec ${args} -- $(MAKE) -C ${t.name} publish
171
171
 
172
172
  deploy-dry-${t.name}:
173
- \taql vault exec --dry-run ${args} -- $(MAKE) -C ${t.name} publish
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 aql key vault (https://github.com/aql-lang/aql) — never
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: aql --dry-run
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
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
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: aql --dry-run
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" = "$(AQL_DRY_RUN_FILLER)" ]; then \\
245
- \t echo "[dry-run] aql 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} (aql vault exec)"; exit 1; fi; \\
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; \\
@@ -549,28 +549,30 @@ Pass custom features via the \`extend\` option at construction time.
549
549
  `)
550
550
  }
551
551
 
552
- // 13. Upstream API — contact/servers from the OpenAPI info block
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
- if (upstreamUrl || docsUrl) {
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
- if (upstreamUrl) {
564
- Content(`- Upstream API: [${upstreamUrl}](${upstreamUrl})
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
- Content(`
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