@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
@@ -19,7 +19,7 @@ class Config {
19
19
 
20
20
 
21
21
  main = {
22
- name: 'ProjectName',
22
+ name: '$$const.Name$$',
23
23
  }
24
24
 
25
25
 
@@ -31,7 +31,7 @@ class Config {
31
31
  options = {
32
32
  base: '$$main.kit.info.servers.0.url$$',
33
33
 
34
- 'AUTHBLOCK'headers: 'HEADERS',
34
+ 'SERVERBLOCK''AUTHBLOCK'headers: 'HEADERS',
35
35
 
36
36
  entity: {
37
37
  // #EntityConfigs
@@ -24,6 +24,10 @@ describe('EntityNameDirect', async () => {
24
24
 
25
25
  test('direct-exists', async () => {
26
26
  const sdk = new ProjectNameSDK({
27
+ // Concrete base: a live construction must satisfy any server
28
+ // variables a templated base URL declares; overriding base with a
29
+ // literal (as the direct flow tests do) sidesteps the requirement.
30
+ base: 'http://localhost:8080',
27
31
  system: { fetch: async () => ({}) }
28
32
  })
29
33
  assert('function' === typeof sdk.direct)
@@ -15,21 +15,21 @@ clean:
15
15
  # publishing a version currently means pushing the tag csharp/vX.Y.Z. When the
16
16
  # registry goes live, `dotnet pack` + `dotnet nuget push` slot in before the
17
17
  # tag (mirroring the voxgig/struct csharp Makefile). Run headless under the
18
- # aql key vault, which injects the GitHub token so nothing lands on disk or
18
+ # boru key vault, which injects the GitHub token so nothing lands on disk or
19
19
  # argv:
20
- # aql vault exec --for=github=<alias> -- make publish
21
- # aql `--dry-run` injects a filler token we detect to rehearse (no tag/push).
20
+ # boru vault exec --for=github=<alias> -- make publish
21
+ # boru `--dry-run` injects a filler token we detect to rehearse (no tag/push).
22
22
  # set -e + tag-last: a failed push never leaves a tag behind.
23
23
  VERSION := $(shell cat VERSION)
24
24
  TAG := csharp/v$(VERSION)
25
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
25
+ BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
26
26
  publish: test
27
27
  @if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
28
28
  echo "tag $(TAG) already exists — bump VERSION first"; exit 1; fi
29
29
  @set -e; \
30
30
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
31
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ]; then \
32
- echo "[dry-run] aql filler token detected: would tag $(TAG); nothing pushed."; \
31
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
32
+ echo "[dry-run] boru filler token detected: would tag $(TAG); nothing pushed."; \
33
33
  exit 0; \
34
34
  fi; \
35
35
  git tag -a "$(TAG)" -m "csharp v$(VERSION)"; \
@@ -22,14 +22,14 @@ clean:
22
22
  # the tag. set -e + tag-last: a failed upload never leaves a tag behind.
23
23
  VERSION := $(shell sed -nE 's/^version: *([0-9][^ ]*).*/\1/p' pubspec.yaml | head -1)
24
24
  TAG := dart/v$(VERSION)
25
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
25
+ BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
26
26
  publish: test
27
27
  @if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
28
28
  echo "tag $(TAG) already exists — bump pubspec.yaml version first"; exit 1; fi
29
29
  @set -e; \
30
30
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
31
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ]; then \
32
- echo "[dry-run] aql filler token detected: would publish to pub.dev and tag $(TAG); nothing pushed."; \
31
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
32
+ echo "[dry-run] boru filler token detected: would publish to pub.dev and tag $(TAG); nothing pushed."; \
33
33
  exit 0; \
34
34
  fi; \
35
35
  if [ -n "$$PUB_CREDENTIALS" ]; then \
@@ -13,10 +13,10 @@ clean:
13
13
  # Go modules have no registry upload — publishing a version means pushing the
14
14
  # tag go/vX.Y.Z (this module is the go/ subdir, and Go's submodule-tag
15
15
  # convention is <subdir>/vX.Y.Z), which the module proxy + pkg.go.dev pick up on
16
- # first fetch. Run headless under the aql key vault, which injects the GitHub
16
+ # first fetch. Run headless under the boru key vault, which injects the GitHub
17
17
  # 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
  #
22
22
  # NOTE: publishing the git tag is deliberately NOT gated on `go test` (every
@@ -24,14 +24,14 @@ clean:
24
24
  # block the module tag). Run `make test` separately in CI to gate quality.
25
25
  VERSION := $(shell cat VERSION)
26
26
  TAG := go/v$(VERSION)
27
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
27
+ BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
28
28
  publish:
29
29
  @if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
30
30
  echo "tag $(TAG) already exists — bump VERSION first"; exit 1; fi
31
31
  @set -e; \
32
32
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
33
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ]; then \
34
- echo "[dry-run] aql filler token detected: would tag $(TAG) for pkg.go.dev; nothing pushed."; \
33
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
34
+ echo "[dry-run] boru filler token detected: would tag $(TAG) for pkg.go.dev; nothing pushed."; \
35
35
  exit 0; \
36
36
  fi; \
37
37
  git tag -a "$(TAG)" -m "go v$(VERSION)"; \
@@ -252,6 +252,10 @@ func TestPrimaryUtility(t *testing.T) {
252
252
  t.Run("fetcher-live", func(t *testing.T) {
253
253
  calls := []map[string]any{}
254
254
  liveClient := sdk.NewProjectNameSDK(map[string]any{
255
+ // Concrete base: a live construction must satisfy any server
256
+ // variables a templated base URL declares; a literal base
257
+ // sidesteps the requirement.
258
+ "base": "http://localhost:8080",
255
259
  "system": map[string]any{
256
260
  "fetch": func(url string, fetchdef map[string]any) (map[string]any, error) {
257
261
  calls = append(calls, map[string]any{"url": url, "init": fetchdef})
@@ -282,6 +286,7 @@ func TestPrimaryUtility(t *testing.T) {
282
286
  t.Run("fetcher-blocked-test-mode", func(t *testing.T) {
283
287
  // Create a live SDK then set mode to test (not using TestSDK, which installs test feature)
284
288
  blockedClient := sdk.NewProjectNameSDK(map[string]any{
289
+ "base": "http://localhost:8080",
285
290
  "system": map[string]any{
286
291
  "fetch": func(url string, fetchdef map[string]any) (map[string]any, error) {
287
292
  return map[string]any{}, nil
@@ -1,6 +1,7 @@
1
1
  package utility
2
2
 
3
3
  import (
4
+ "regexp"
4
5
  "sort"
5
6
  "strings"
6
7
 
@@ -9,6 +10,9 @@ import (
9
10
  "GOMODULE/core"
10
11
  )
11
12
 
13
+ // {name} placeholders in a templated server URL (OpenAPI server variables).
14
+ var serverVarRe = regexp.MustCompile(`\{[A-Za-z0-9_]+\}`)
15
+
12
16
  func makeOptionsUtil(ctx *core.Context) map[string]any {
13
17
  options := ctx.Options
14
18
  if options == nil {
@@ -108,6 +112,13 @@ func makeOptionsUtil(ctx *core.Context) map[string]any {
108
112
  "clean": map[string]any{
109
113
  "keys": "key,token,id",
110
114
  },
115
+ // Server-variable values for a templated base URL (OpenAPI server
116
+ // variables): {name} placeholders in "base" are substituted from this
117
+ // map at construction. Spec defaults arrive via the generated config;
118
+ // user values override them.
119
+ "server": map[string]any{
120
+ "`$CHILD`": "",
121
+ },
111
122
  }
112
123
 
113
124
  // Preserve system.fetch before merge/validate.
@@ -120,6 +131,43 @@ func makeOptionsUtil(ctx *core.Context) map[string]any {
120
131
  validated, _ := vs.Validate(merged, optspec)
121
132
  opts = validated.(map[string]any)
122
133
 
134
+ // Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
135
+ // Every placeholder must resolve to a non-empty value: from
136
+ // options["server"] (user), else the config default. A placeholder that
137
+ // resolves to "" is a construction error in live mode — the URL cannot
138
+ // work — but in test mode substitutes the deterministic value
139
+ // "test-<name>" so offline tests need no configuration. The SDK
140
+ // constructor has no error return, so a missing required variable
141
+ // PANICS (construction-time misconfiguration, as regexp.MustCompile).
142
+ if base, ok := opts["base"].(string); ok && strings.Contains(base, "{") {
143
+ testmode := false
144
+ if ta, ok := vs.GetPath([]any{"test", "active"}, opts).(bool); ok && ta {
145
+ testmode = true
146
+ }
147
+ if fa, ok := vs.GetPath([]any{"feature", "test", "active"}, opts).(bool); ok && fa {
148
+ testmode = true
149
+ }
150
+ server := core.ToMapAny(opts["server"])
151
+ sdkname := "SDK"
152
+ if mn, ok := vs.GetPath([]any{"main", "name"}, config).(string); ok && mn != "" {
153
+ sdkname = mn
154
+ }
155
+ resolved := serverVarRe.ReplaceAllStringFunc(base, func(ph string) string {
156
+ name := ph[1 : len(ph)-1]
157
+ val, _ := server[name].(string)
158
+ if val == "" {
159
+ if testmode {
160
+ return "test-" + name
161
+ }
162
+ panic(sdkname + ": the server variable '" + name + "' is required: " +
163
+ "the API base URL is '" + base + "' — pass " +
164
+ `options["server"].(map)["` + name + `"] in the SDK options`)
165
+ }
166
+ return val
167
+ })
168
+ opts["base"] = resolved
169
+ }
170
+
123
171
  // Restore system.fetch.
124
172
  if sysFetch != nil {
125
173
  if sys, ok := opts["system"]; ok {
@@ -12,10 +12,10 @@ clean:
12
12
  # --- Release: tag java/vX.Y.Z ----------------------------------------------
13
13
  # Maven Central publication (Sonatype Central Portal) is pending for this
14
14
  # target; publishing a version currently means pushing the java/vX.Y.Z git
15
- # tag. Run headless under the aql key vault, which injects the GitHub token
15
+ # tag. Run headless under the boru key vault, which injects the GitHub token
16
16
  # so nothing lands on disk or argv:
17
- # aql vault exec --for=github=<alias> -- make publish
18
- # aql `--dry-run` injects a filler token we detect to rehearse (no tag/push).
17
+ # boru vault exec --for=github=<alias> -- make publish
18
+ # boru `--dry-run` injects a filler token we detect to rehearse (no tag/push).
19
19
  # set -e + tag-last: a failed push never leaves a tag behind.
20
20
  #
21
21
  # NOTE: publishing the git tag is deliberately NOT gated on `mvn test` (every
@@ -23,14 +23,14 @@ clean:
23
23
  # block the tag). Run `make test` separately in CI to gate quality.
24
24
  VERSION := $(shell cat VERSION)
25
25
  TAG := java/v$(VERSION)
26
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
26
+ BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
27
27
  publish:
28
28
  @if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
29
29
  echo "tag $(TAG) already exists — bump VERSION first"; exit 1; fi
30
30
  @set -e; \
31
31
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
32
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ]; then \
33
- echo "[dry-run] aql filler token detected: would tag $(TAG); nothing pushed."; \
32
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
33
+ echo "[dry-run] boru filler token detected: would tag $(TAG); nothing pushed."; \
34
34
  exit 0; \
35
35
  fi; \
36
36
  git tag -a "$(TAG)" -m "java v$(VERSION)"; \
@@ -10,23 +10,23 @@ clean:
10
10
  rm -rf node_modules
11
11
 
12
12
  # --- Release: publish to npm ----------------------------------------------
13
- # Publish this package to npm, then tag js/vX.Y.Z. Run headless under the aql
13
+ # Publish this package to npm, then tag js/vX.Y.Z. Run headless under the boru
14
14
  # key vault, which injects the npm auth token + the GitHub token (never on disk
15
15
  # or argv):
16
- # aql vault exec --for=npm=<alias> --for=github=<alias> -- make publish
17
- # aql `--dry-run` injects a filler token we detect to rehearse (no publish/tag).
16
+ # boru vault exec --for=npm=<alias> --for=github=<alias> -- make publish
17
+ # boru `--dry-run` injects a filler token we detect to rehearse (no publish/tag).
18
18
  # set -e + tag-last: a failed publish never leaves a tag behind.
19
19
  SHELL := /bin/bash
20
20
  VERSION := $(shell node -p "require('./package.json').version")
21
21
  TAG := js/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 package.json version first"; exit 1; fi
26
26
  @set -e; \
27
27
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
28
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ]; then \
29
- echo "[dry-run] aql filler token detected: would publish to npm and tag $(TAG); nothing pushed."; \
28
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
29
+ echo "[dry-run] boru filler token detected: would publish to npm and tag $(TAG); nothing pushed."; \
30
30
  exit 0; \
31
31
  fi; \
32
32
  npm stage publish --access public --registry https://registry.npmjs.org; \
@@ -79,16 +79,54 @@ function makeOptions(ctx) {
79
79
  },
80
80
  clean: {
81
81
  keys: 'key,token,id'
82
+ },
83
+ // Server-variable values for a templated base URL (OpenAPI server
84
+ // variables): `{name}` placeholders in `base` are substituted from
85
+ // this map at construction. Spec defaults arrive via the generated
86
+ // Config; user values override them.
87
+ server: {
88
+ '`$CHILD`': ''
82
89
  }
83
90
  }
84
91
 
85
92
  // JavaScript specific option values.
86
93
  optspec.system.fetch = opts.system?.fetch || global.fetch
87
94
 
88
- opts = merge([{}, cfgopts, opts])
95
+ // Clone the config side before merging: `config` is a module-level
96
+ // singleton in ts/js, and merge would otherwise use its nested maps as
97
+ // merge TARGETS — one instance's options (server, headers, ...) would
98
+ // contaminate every instance constructed after it.
99
+ opts = merge([{}, struct.clone(cfgopts), opts])
89
100
 
90
101
  opts = validate(opts, optspec)
91
102
 
103
+ // Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
104
+ // Every placeholder must resolve to a non-empty value: from
105
+ // options.server (user), else the Config default. A placeholder that
106
+ // resolves to '' is a construction ERROR in live mode — the URL cannot
107
+ // work — but in test mode substitutes the deterministic value
108
+ // `test-<name>` so offline tests need no configuration.
109
+ if ('string' === typeof opts.base && opts.base.includes('{')) {
110
+ const testmode = true === opts.test.active ||
111
+ true === (opts.feature && opts.feature.test && opts.feature.test.active)
112
+ const server = opts.server || {}
113
+ opts.base = opts.base.replace(/\{([A-Za-z0-9_]+)\}/g,
114
+ (_m, name) => {
115
+ let val = server[name]
116
+ val = 'string' === typeof val ? val : ''
117
+ if ('' === val) {
118
+ if (testmode) {
119
+ return 'test-' + name
120
+ }
121
+ throw new Error(
122
+ (config?.main?.name || 'SDK') + ": the server variable '" + name +
123
+ "' is required: the API base URL is '" + opts.base +
124
+ "' — pass { server: { " + name + ": '...' } } in the SDK options")
125
+ }
126
+ return val
127
+ })
128
+ }
129
+
92
130
  // Resolve the feature add-order: an explicit array order (above) wins;
93
131
  // otherwise order the map test-first, then the remaining names sorted, so
94
132
  // the outcome is deterministic and `test` is always the base transport.
@@ -205,6 +205,9 @@ describe('PrimaryUtility', async () => {
205
205
  body: 'present',
206
206
  })
207
207
  const reqClient = new SDK({
208
+ // Concrete base: a live construction must satisfy any server variables
209
+ // a templated base URL declares; a literal base sidesteps the requirement.
210
+ base: 'http://localhost:8080',
208
211
  system: { fetch: mockFetch }
209
212
  })
210
213
  const reqUtility = reqClient.utility()
@@ -386,6 +389,7 @@ describe('PrimaryUtility', async () => {
386
389
  test('fetcher-live', async () => {
387
390
  const calls = []
388
391
  const liveClient = new SDK({
392
+ base: 'http://localhost:8080',
389
393
  system: {
390
394
  fetch: async (url, init) => {
391
395
  calls.push({ url, init })
@@ -407,6 +411,7 @@ describe('PrimaryUtility', async () => {
407
411
 
408
412
  test('fetcher-blocked-test-mode', async () => {
409
413
  const blockedClient = new SDK({
414
+ base: 'http://localhost:8080',
410
415
  system: { fetch: async () => ({}) }
411
416
  })
412
417
  blockedClient._mode = 'test'
@@ -16,20 +16,20 @@ clean:
16
16
  # --- Release: tag kotlin/vX.Y.Z ---------------------------------------------
17
17
  # Maven Central publication (Sonatype Central Portal) is pending for this
18
18
  # target; publishing a version currently means pushing the kotlin/vX.Y.Z git
19
- # tag. Run headless under the aql key vault, which injects the GitHub token
19
+ # tag. Run headless under the boru key vault, which injects the GitHub token
20
20
  # so nothing lands on disk or argv:
21
- # aql vault exec --for=github=<alias> -- make publish
22
- # aql `--dry-run` injects a filler token we detect to rehearse (no tag/push).
21
+ # boru vault exec --for=github=<alias> -- make publish
22
+ # boru `--dry-run` injects a filler token we detect to rehearse (no tag/push).
23
23
  VERSION := $(shell cat VERSION)
24
24
  TAG := kotlin/v$(VERSION)
25
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
25
+ BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
26
26
  publish:
27
27
  @if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
28
28
  echo "tag $(TAG) already exists — bump VERSION first"; exit 1; fi
29
29
  @set -e; \
30
30
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
31
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ]; then \
32
- echo "[dry-run] aql filler token detected: would tag $(TAG); nothing pushed."; \
31
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
32
+ echo "[dry-run] boru filler token detected: would tag $(TAG); nothing pushed."; \
33
33
  exit 0; \
34
34
  fi; \
35
35
  git tag -a "$(TAG)" -m "kotlin v$(VERSION)"; \
@@ -10,26 +10,26 @@ clean:
10
10
  @echo "No clean step for Lua"
11
11
 
12
12
  # --- Release: publish to LuaRocks -----------------------------------------
13
- # Upload the rockspec to LuaRocks, then tag lua/vX.Y.Z. LuaRocks has no aql
13
+ # Upload the rockspec to LuaRocks, then tag lua/vX.Y.Z. LuaRocks has no boru
14
14
  # recipe, so inject its API key + the GitHub token as custom env vars
15
- # (all-positional — aql cannot mix --for recipes with positional env):
16
- # aql vault exec '<alias>=LUAROCKS_API_KEY,<gh-alias>=GITHUB_TOKEN' -- make publish
15
+ # (all-positional — boru cannot mix --for recipes with positional env):
16
+ # boru vault exec '<alias>=LUAROCKS_API_KEY,<gh-alias>=GITHUB_TOKEN' -- make publish
17
17
  # --skip-pack uploads only the rockspec (its git+https source is fetched at the
18
18
  # lua/vX.Y.Z tag on install; that tag is pushed in the LAST step, so we must not
19
19
  # pack here). LuaRocks requires the rockspec filename to be
20
- # <package>-<version>.rockspec, so we upload a canonically-named copy. aql
20
+ # <package>-<version>.rockspec, so we upload a canonically-named copy. boru
21
21
  # `--dry-run` rehearses (no upload/tag). set -e + tag-last: a failed upload
22
22
  # never leaves a tag behind.
23
23
  VERSION := $(shell sed -nE 's/^version *= *"([0-9.]+).*/\1/p' *.rockspec | head -1)
24
24
  TAG := lua/v$(VERSION)
25
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
25
+ BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
26
26
  publish: test
27
27
  @if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
28
28
  echo "tag $(TAG) already exists — bump the rockspec version first"; exit 1; fi
29
29
  @set -e; \
30
30
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
31
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ] || [ "$$LUAROCKS_API_KEY" = "$(AQL_DRY_RUN_FILLER)" ]; then \
32
- echo "[dry-run] aql filler token detected: would upload to LuaRocks and tag $(TAG); nothing pushed."; \
31
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ] || [ "$$LUAROCKS_API_KEY" = "$(BORU_DRY_RUN_FILLER)" ]; then \
32
+ echo "[dry-run] boru filler token detected: would upload to LuaRocks and tag $(TAG); nothing pushed."; \
33
33
  exit 0; \
34
34
  fi; \
35
35
  rock=$$(ls *.rockspec | head -1); \
@@ -41,11 +41,39 @@ function TestFeature:init(ctx, options)
41
41
  local test_self = self
42
42
 
43
43
  local function test_fetcher(fctx, _fullurl, _fetchdef)
44
+ -- Shape the mock payload the way the real API would, so the op's
45
+ -- response transform recovers the entity from it. A point carrying
46
+ -- transform.res of `body.item` describes an API that answers
47
+ -- { item = {...} }; handing back the bare entity means the transform
48
+ -- unwraps a property that is not there and the caller gets nil.
49
+ -- The mock has to agree with the model, or it only ever simulates
50
+ -- APIs whose responses happen to be unwrapped. Mirrors the ts/py mocks.
51
+ local function envelope(data)
52
+ local point = fctx.point
53
+ if data == nil or type(point) ~= "table" then
54
+ return data
55
+ end
56
+ local transform = point.transform
57
+ if type(transform) ~= "table" then
58
+ return data
59
+ end
60
+ local restf = transform.res
61
+ if type(restf) ~= "string" then
62
+ return data
63
+ end
64
+ local key = string.match(restf, "^`body%.([^`%.]+)`$")
65
+ if key == nil then
66
+ return data
67
+ end
68
+ return { [key] = data }
69
+ end
70
+
44
71
  local function respond(status, data, extra)
72
+ local payload = envelope(data)
45
73
  local out = {
46
74
  status = status,
47
75
  statusText = "OK",
48
- json = function() return data end,
76
+ json = function() return payload end,
49
77
  body = "not-used",
50
78
  }
51
79
  if type(extra) == "table" then
@@ -576,6 +576,9 @@ describe("PrimaryUtility", function()
576
576
  it("fetcher-live", function()
577
577
  local calls = {}
578
578
  local live_client = sdk.new({
579
+ -- Concrete base: a live construction must satisfy any server variables
580
+ -- a templated base URL declares; a literal base sidesteps the requirement.
581
+ base = "http://localhost:8080",
579
582
  system = {
580
583
  fetch = function(url, fetchdef)
581
584
  table.insert(calls, { url = url, init = fetchdef })
@@ -600,6 +603,7 @@ describe("PrimaryUtility", function()
600
603
 
601
604
  it("fetcher-blocked-test-mode", function()
602
605
  local blocked_client = sdk.new({
606
+ base = "http://localhost:8080",
603
607
  system = {
604
608
  fetch = function(url, fetchdef)
605
609
  return {}, nil
@@ -92,6 +92,13 @@ local function make_options_util(ctx)
92
92
  clean = {
93
93
  keys = "key,token,id",
94
94
  },
95
+ -- Server-variable values for a templated base URL (OpenAPI server
96
+ -- variables): {name} placeholders in `base` are substituted from this
97
+ -- map at construction. Spec defaults arrive via the generated config;
98
+ -- user values override them.
99
+ server = {
100
+ ["`$CHILD`"] = "",
101
+ },
95
102
  }
96
103
 
97
104
  -- Preserve system.fetch before merge/validate.
@@ -104,6 +111,38 @@ local function make_options_util(ctx)
104
111
  end
105
112
  opts = validated
106
113
 
114
+ -- Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
115
+ -- Every placeholder must resolve to a non-empty value: from
116
+ -- options.server (user), else the config default. A placeholder that
117
+ -- resolves to "" is a construction ERROR in live mode — the URL cannot
118
+ -- work — but in test mode substitutes the deterministic value
119
+ -- "test-<name>" so offline tests need no configuration.
120
+ local base = opts.base
121
+ if type(base) == "string" and string.find(base, "{", 1, true) then
122
+ local testmode = vs.getpath(opts, "test.active") == true
123
+ or vs.getpath(opts, "feature.test.active") == true
124
+ local server = type(opts.server) == "table" and opts.server or {}
125
+ local sdkname = vs.getpath(config, "main.name")
126
+ if type(sdkname) ~= "string" or sdkname == "" then
127
+ sdkname = "SDK"
128
+ end
129
+ opts.base = string.gsub(base, "{([%w_]+)}", function(name)
130
+ local val = server[name]
131
+ if type(val) ~= "string" then
132
+ val = ""
133
+ end
134
+ if val == "" then
135
+ if testmode then
136
+ return "test-" .. name
137
+ end
138
+ error(sdkname .. ": the server variable '" .. name .. "' is required: " ..
139
+ "the API base URL is '" .. base .. "' — pass " ..
140
+ "{ server = { " .. name .. " = \"...\" } } in the SDK options", 0)
141
+ end
142
+ return val
143
+ end)
144
+ end
145
+
107
146
  -- Restore system.fetch.
108
147
  if sys_fetch ~= nil then
109
148
  if type(opts["system"]) == "table" then
@@ -20,10 +20,10 @@ clean:
20
20
  # Build a CPAN dist in a throwaway .release/ dir to validate the package,
21
21
  # then tag perl/vX.Y.Z (version from $VERSION in lib/*SDK.pm). The CPAN
22
22
  # registry entry for this port is declared but pending, so publish is
23
- # tag-only: no upload happens. Run headless under the aql key vault, which
23
+ # tag-only: no upload happens. Run headless under the boru key vault, which
24
24
  # injects the GitHub token (never on disk or argv):
25
- # aql vault exec --for=github=<alias> -- make publish
26
- # aql `--dry-run` injects a filler token we detect to rehearse (build only,
25
+ # boru vault exec --for=github=<alias> -- make publish
26
+ # boru `--dry-run` injects a filler token we detect to rehearse (build only,
27
27
  # no tag). set -e + tag-last: a failed build never leaves a tag behind.
28
28
  #
29
29
  # NOTE: `perl Makefile.PL` (ExtUtils::MakeMaker) GENERATES a file named
@@ -31,7 +31,7 @@ clean:
31
31
  # dist build always happens inside .release/, never in place.
32
32
  VERSION := $(shell sed -nE "s/.*VERSION *= *'([^']+)'.*/\1/p" lib/*SDK.pm | head -1)
33
33
  TAG := perl/v$(VERSION)
34
- AQL_DRY_RUN_FILLER := AQL-DRY-RUN-FILLER-NOT-A-REAL-SECRET
34
+ BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
35
35
  publish: test
36
36
  @if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
37
37
  echo "tag $(TAG) already exists — bump VERSION in lib/*SDK.pm first"; exit 1; fi
@@ -42,8 +42,8 @@ publish: test
42
42
  { [ -f README.md ] && cp README.md .release/ || true; }; \
43
43
  (cd .release && $(PERL) Makefile.PL >/dev/null && echo "dist metadata OK"); \
44
44
  rm -rf .release; \
45
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ]; then \
46
- echo "[dry-run] aql filler token detected: would tag $(TAG); nothing pushed."; \
45
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
46
+ echo "[dry-run] boru filler token detected: would tag $(TAG); nothing pushed."; \
47
47
  exit 0; \
48
48
  fi; \
49
49
  git tag -a "$(TAG)" -m "perl v$(VERSION)"; \
@@ -13,20 +13,20 @@ clean:
13
13
  # Packagist has no upload — it tracks the repo and indexes each git tag
14
14
  # php/vX.Y.Z (a configured GitHub webhook, or the Packagist "Update" API,
15
15
  # refreshes the package). So publishing a version means pushing the tag. Run
16
- # headless under the aql key vault, which injects the GitHub token:
17
- # aql vault exec --for=github=<alias> -- make publish
18
- # aql `--dry-run` injects a filler token we detect to rehearse (no tag/push).
16
+ # headless under the boru key vault, which injects the GitHub token:
17
+ # boru vault exec --for=github=<alias> -- make publish
18
+ # boru `--dry-run` injects a filler token we detect to rehearse (no tag/push).
19
19
  # set -e + tag-last: a failed push never leaves a tag behind.
20
20
  VERSION := $(shell cat VERSION)
21
21
  TAG := php/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 VERSION first"; exit 1; fi
26
26
  @set -e; \
27
27
  token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
28
- if [ "$$token" = "$(AQL_DRY_RUN_FILLER)" ]; then \
29
- echo "[dry-run] aql filler token detected: would tag $(TAG) for Packagist; nothing pushed."; \
28
+ if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
29
+ echo "[dry-run] boru filler token detected: would tag $(TAG) for Packagist; nothing pushed."; \
30
30
  exit 0; \
31
31
  fi; \
32
32
  git tag -a "$(TAG)" -m "php v$(VERSION)"; \
@@ -48,11 +48,39 @@ class ProjectNameTestFeature extends ProjectNameBaseFeature
48
48
  $entity->data = $entity_data;
49
49
 
50
50
  $test_fetcher = function (ProjectNameContext $fctx, string $_fullurl, array $_fetchdef) use ($entity): array {
51
- $respond = function (int $status, mixed $data, ?array $extra = null): array {
51
+ // Shape the mock payload the way the real API would, so the op's
52
+ // response transform recovers the entity from it. A point carrying
53
+ // transform.res of `body.item` describes an API that answers
54
+ // {"item": {...}}; handing back the bare entity means the
55
+ // transform unwraps a property that is not there and the caller
56
+ // gets null. The mock has to agree with the model, or it only
57
+ // ever simulates APIs whose responses happen to be unwrapped.
58
+ // Mirrors the ts/py mocks.
59
+ $envelope = function (mixed $data) use ($fctx): mixed {
60
+ $point = $fctx->point ?? null;
61
+ if ($data === null || !is_array($point)) {
62
+ return $data;
63
+ }
64
+ $transform = $point['transform'] ?? null;
65
+ if (!is_array($transform)) {
66
+ return $data;
67
+ }
68
+ $restf = $transform['res'] ?? null;
69
+ if (!is_string($restf)) {
70
+ return $data;
71
+ }
72
+ if (!preg_match('/^`body\.([^`.]+)`$/', $restf, $m)) {
73
+ return $data;
74
+ }
75
+ return [$m[1] => $data];
76
+ };
77
+
78
+ $respond = function (int $status, mixed $data, ?array $extra = null) use ($envelope): array {
79
+ $payload = $envelope($data);
52
80
  $out = [
53
81
  'status' => $status,
54
82
  'statusText' => 'OK',
55
- 'json' => function () use ($data) { return $data; },
83
+ 'json' => function () use ($payload) { return $payload; },
56
84
  'body' => 'not-used',
57
85
  ];
58
86
  if ($extra) {