@voxgig/sdkgen 4.26.0 → 4.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/voxgig-sdkgen CHANGED
@@ -8,7 +8,7 @@ const { Shape, One, Skip } = require('shape')
8
8
 
9
9
  const { SdkGen } = require('../dist/sdkgen.js')
10
10
 
11
- const VERSION = '4.26.0'
11
+ const VERSION = '4.26.1'
12
12
  const KONSOLE = console
13
13
 
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxgig/sdkgen",
3
- "version": "4.26.0",
3
+ "version": "4.26.1",
4
4
  "main": "dist/sdkgen.js",
5
5
  "type": "commonjs",
6
6
  "engines": {
@@ -11,8 +11,10 @@
11
11
  NATIVE ?=
12
12
  -include $(wildcard feature/*/native.mk)
13
13
 
14
+ # One Lua state for the whole suite, as the other targets share one process:
15
+ # insulating each file re-requires the SDK and re-decodes its config per file.
14
16
  test: build
15
- busted -p _test test/
17
+ busted --no-auto-insulate -p _test test/
16
18
 
17
19
  build: $(NATIVE)
18
20
  @echo "lua: build complete$(if $(NATIVE), ($(NATIVE)),: no compile step)"
@@ -0,0 +1,92 @@
1
+ -- ProjectName SDK option defaults test
2
+ --
3
+ -- make_options validates the configured entity defaults once per Lua state
4
+ -- rather than per client: struct's lua getprop scans the parent to classify
5
+ -- it, which made validating n entities cost n^2 on every construction.
6
+
7
+ local sdk = require("project-name-_sdk")
8
+ local vs = require("utility.struct.struct")
9
+ local schema = require("schema")
10
+ local config = require("config_shared")()
11
+
12
+
13
+ local function configured()
14
+ local names = {}
15
+ for name, _ in pairs(config.options.entity or {}) do
16
+ table.insert(names, name)
17
+ end
18
+ table.sort(names)
19
+ return names
20
+ end
21
+
22
+
23
+ local function whole(user)
24
+ local merged = vs.merge({ {}, vs.clone(config.options.entity or {}), vs.clone(user or {}) })
25
+ local out = vs.validate({ entity = merged }, { entity = schema.OPTSPEC["entity"] })
26
+ return out.entity
27
+ end
28
+
29
+
30
+ describe("make_options entity", function()
31
+
32
+ it("matches validating the whole entity map at once", function()
33
+ assert.are.same(whole(nil), sdk.test().options.entity)
34
+
35
+ local name = configured()[1]
36
+ if name ~= nil then
37
+ local user = {
38
+ [name] = { active = true, alias = { a = "b" } },
39
+ not_configured = { active = true },
40
+ }
41
+ assert.are.same(whole(user), sdk.test(nil, { entity = user }).options.entity)
42
+ end
43
+ end)
44
+
45
+
46
+ it("keeps each client's entity options its own", function()
47
+ local name = configured()[1]
48
+ if name == nil then
49
+ return
50
+ end
51
+ local a = sdk.test()
52
+ a.options.entity[name].active = true
53
+ a.options.entity[name].alias.leak = true
54
+ local b = sdk.test()
55
+ assert.are.equal(false, b.options.entity[name].active)
56
+ assert.is_nil(b.options.entity[name].alias.leak)
57
+ end)
58
+
59
+
60
+ it("validates the configured entity map at most once for many clients", function()
61
+ local names = configured()
62
+ local full = 0
63
+ local validate = vs.validate
64
+ vs.validate = function(data, spec, injdef)
65
+ local ent = type(data) == "table" and data.entity or nil
66
+ if type(ent) == "table" and 1 < #names then
67
+ local all = true
68
+ for _, name in ipairs(names) do
69
+ if ent[name] == nil then
70
+ all = false
71
+ break
72
+ end
73
+ end
74
+ if all then
75
+ full = full + 1
76
+ end
77
+ end
78
+ return validate(data, spec, injdef)
79
+ end
80
+
81
+ local ok, err = pcall(function()
82
+ for _ = 1, 3 do
83
+ sdk.test()
84
+ end
85
+ end)
86
+ vs.validate = validate
87
+
88
+ assert.is_true(ok, tostring(err))
89
+ assert.is_true(full <= 1, "entity map validated " .. full .. " times for 3 clients")
90
+ end)
91
+
92
+ end)
@@ -48,6 +48,40 @@ local function densify_lists(v, seen)
48
48
  return v
49
49
  end
50
50
 
51
+ local function copy_data(v)
52
+ if type(v) ~= 'table' then
53
+ return v
54
+ end
55
+ local out = {}
56
+ for k, e in pairs(v) do
57
+ out[k] = copy_data(e)
58
+ end
59
+ return setmetatable(out, getmetatable(v))
60
+ end
61
+
62
+ -- struct's lua getprop scans every key of the parent to classify it, so
63
+ -- validating a map of n entities costs n^2. Each entity entry validates on its
64
+ -- own, and the config's entries are fixed for this Lua state: validate them
65
+ -- once, and per client only the entries the caller passes.
66
+ local entity_defaults_src = nil
67
+ local entity_defaults = nil
68
+
69
+ local function validate_entities(entities, spec)
70
+ local out = vs.validate({ entity = densify_lists(entities) }, { entity = spec })
71
+ if type(out) == 'table' and type(out.entity) == 'table' then
72
+ return out.entity
73
+ end
74
+ return {}
75
+ end
76
+
77
+ local function validated_entity_defaults(cfgentity, spec)
78
+ if entity_defaults_src ~= cfgentity then
79
+ entity_defaults = validate_entities(vs.clone(cfgentity), spec)
80
+ entity_defaults_src = cfgentity
81
+ end
82
+ return entity_defaults
83
+ end
84
+
51
85
  local function make_options_util(ctx)
52
86
  local options = ctx.options or {}
53
87
 
@@ -150,6 +184,22 @@ local function make_options_util(ctx)
150
184
  -- singleton (see config_shared), and merge would otherwise use its nested
151
185
  -- tables as merge TARGETS — one instance's options (server, headers, ...)
152
186
  -- would contaminate every instance constructed after it.
187
+ local cfgentity = cfgopts["entity"]
188
+ local userentity = opts["entity"]
189
+ local split = type(cfgentity) == 'table' and vs.ismap(cfgentity)
190
+ and (userentity == nil or vs.ismap(userentity))
191
+
192
+ if split then
193
+ local rest = {}
194
+ for k, v in pairs(cfgopts) do
195
+ if k ~= "entity" then
196
+ rest[k] = v
197
+ end
198
+ end
199
+ cfgopts = rest
200
+ opts["entity"] = nil
201
+ end
202
+
153
203
  local merged = vs.merge({ {}, vs.clone(cfgopts), opts })
154
204
 
155
205
  -- LUA CANNOT STORE NIL, so `{ a, nil, b }` is a table holding keys 1 and 3
@@ -171,6 +221,21 @@ local function make_options_util(ctx)
171
221
  end
172
222
  opts = validated
173
223
 
224
+ if split then
225
+ local entity = copy_data(validated_entity_defaults(cfgentity, optspec["entity"]))
226
+ if userentity ~= nil then
227
+ local picked = {}
228
+ for name, _ in pairs(userentity) do
229
+ picked[name] = cfgentity[name]
230
+ end
231
+ local own = vs.merge({ {}, vs.clone(picked), userentity })
232
+ for name, e in pairs(validate_entities(own, optspec["entity"])) do
233
+ entity[name] = e
234
+ end
235
+ end
236
+ opts["entity"] = entity
237
+ end
238
+
174
239
  -- Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
175
240
  -- Every placeholder must resolve to a non-empty value: from
176
241
  -- options.server (user), else the config default. A placeholder that
@@ -3,7 +3,7 @@
3
3
  "package": 1
4
4
  },
5
5
  "name": "@voxgig/sdkgen",
6
- "version": "4.26.0",
6
+ "version": "4.26.1",
7
7
  "provides": {
8
8
  "target": [
9
9
  "c",