@voxgig/sdkgen 4.17.6 → 4.18.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.
Files changed (60) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/AgentGuideContent.js +30 -0
  3. package/dist/cmp/AgentGuideContent.js.map +1 -1
  4. package/dist/cmp/FeatureDocs.d.ts +6 -1
  5. package/dist/cmp/FeatureDocs.js +27 -0
  6. package/dist/cmp/FeatureDocs.js.map +1 -1
  7. package/dist/cmp/ReadmeRefFeatures.js +23 -13
  8. package/dist/cmp/ReadmeRefFeatures.js.map +1 -1
  9. package/dist/helpers/applicability.js +7 -0
  10. package/dist/helpers/applicability.js.map +1 -1
  11. package/dist/helpers/canonSpec.d.ts +12 -0
  12. package/dist/helpers/canonSpec.js +259 -0
  13. package/dist/helpers/canonSpec.js.map +1 -0
  14. package/dist/helpers/optspec.d.ts +4 -0
  15. package/dist/helpers/optspec.js +152 -0
  16. package/dist/helpers/optspec.js.map +1 -0
  17. package/dist/sdkgen.d.ts +3 -1
  18. package/dist/sdkgen.js +12 -3
  19. package/dist/sdkgen.js.map +1 -1
  20. package/dist/tsconfig.tsbuildinfo +1 -1
  21. package/model/sdkgen.aon +125 -0
  22. package/package.json +1 -1
  23. package/project/.sdk/model/feature/audit.aon +15 -0
  24. package/project/.sdk/model/feature/cache.aon +13 -0
  25. package/project/.sdk/model/feature/clienttrack.aon +21 -0
  26. package/project/.sdk/model/feature/cost.aon +15 -0
  27. package/project/.sdk/model/feature/debug.aon +15 -0
  28. package/project/.sdk/model/feature/feature-index.aon +1 -0
  29. package/project/.sdk/model/feature/idempotency.aon +13 -0
  30. package/project/.sdk/model/feature/log.aon +13 -0
  31. package/project/.sdk/model/feature/metrics.aon +13 -0
  32. package/project/.sdk/model/feature/netsim.aon +14 -0
  33. package/project/.sdk/model/feature/paging.aon +15 -0
  34. package/project/.sdk/model/feature/proxy.aon +13 -0
  35. package/project/.sdk/model/feature/ratelimit.aon +15 -0
  36. package/project/.sdk/model/feature/retry.aon +15 -0
  37. package/project/.sdk/model/feature/streaming.aon +15 -0
  38. package/project/.sdk/model/feature/telemetry.aon +19 -0
  39. package/project/.sdk/model/feature/test.aon +13 -0
  40. package/project/.sdk/model/feature/timeout.aon +15 -0
  41. package/project/.sdk/model/feature/validate.aon +73 -0
  42. package/project/.sdk/model/target/js.aon +1 -1
  43. package/project/.sdk/model/target/ts.aon +1 -1
  44. package/project/.sdk/src/cmp/js/Main_js.ts +2 -0
  45. package/project/.sdk/src/cmp/js/Schema_js.ts +66 -0
  46. package/project/.sdk/src/cmp/scala/Main_scala.ts +30 -0
  47. package/project/.sdk/src/cmp/ts/Main_ts.ts +2 -0
  48. package/project/.sdk/src/cmp/ts/Schema_ts.ts +66 -0
  49. package/project/.sdk/tm/js/src/feature/validate/ValidateFeature.js +296 -0
  50. package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +26 -61
  51. package/project/.sdk/tm/ts/src/feature/validate/ValidateFeature.ts +298 -0
  52. package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +24 -61
  53. package/project/sdkgen-package.json +3 -2
  54. package/src/cmp/AgentGuideContent.ts +30 -0
  55. package/src/cmp/FeatureDocs.ts +39 -0
  56. package/src/cmp/ReadmeRefFeatures.ts +24 -13
  57. package/src/helpers/applicability.ts +8 -0
  58. package/src/helpers/canonSpec.ts +301 -0
  59. package/src/helpers/optspec.ts +180 -0
  60. package/src/sdkgen.ts +9 -0
package/model/sdkgen.aon CHANGED
@@ -173,6 +173,10 @@ main: kit: target: &: {
173
173
  # sekreto a vendored sekreto port lives in this target's feature
174
174
  # container, so a feature can resolve secrets through it
175
175
  #
176
+ # schema this target emits the generated `Schema` module — the
177
+ # model's option spec and per-entity struct.validate specs —
178
+ # so a feature can validate against the model's own types
179
+ #
176
180
  # Tags named in the design note but not yet load-bearing
177
181
  # (`per-feature-file`, `deps`, `transport-wrap`, `hooks`, `delegates`)
178
182
  # are deliberately absent until a feature actually gates on one: a tag
@@ -484,6 +488,32 @@ main: kit: feature: &: {
484
488
  # the others.
485
489
  spec: &: string
486
490
 
491
+ # THE FEATURE'S OWN OPTION SCHEMA.
492
+ #
493
+ # `config.options` is the DEFAULTS map: what happens when the caller says
494
+ # nothing. It is also the README's option table, and — read by example —
495
+ # the type of each option in the generated option spec.
496
+ #
497
+ # `config.optspec` is for what a default cannot say:
498
+ # - an option with NO default (a `sink` callback, an injected clock, a
499
+ # value the caller either supplies or does not). Undeclared, these
500
+ # were invisible to the spec AND missing from the docs table.
501
+ # - an option whose default understates its type. netsim's `latency: 0`
502
+ # reads as "a number" while the feature also takes `{ min, max }`.
503
+ #
504
+ # Values are struct.validate sentinels — '`$FUNCTION`', '`$MAP`', or a
505
+ # union ['`$ONE`', '`$NUMBER`', '`$MAP`']. A name in both maps takes its
506
+ # TYPE from here and its default from `config.options`.
507
+ #
508
+ # `config.strict: true` closes the feature's spec, so an option neither
509
+ # map declares is rejected instead of passed through. Off by default: the
510
+ # shipped features are not fully declared yet, and rejecting a working
511
+ # client's option on upgrade is worse than missing a typo.
512
+ config: {
513
+ optspec: &: top
514
+ strict: *false | boolean
515
+ }
516
+
487
517
  # PLUGINS — a feature's optional, separately-trimmed parts.
488
518
  #
489
519
  # A feature whose implementation is a thin layer over a library with
@@ -571,6 +601,101 @@ main: kit: option: &: {
571
601
  }
572
602
 
573
603
 
604
+ # THE SDK CLIENT OPTION SCHEMA — one declaration, every target.
605
+ #
606
+ # A struct.validate SPEC, in struct's own by-example vocabulary: a concrete
607
+ # value is BOTH the type constraint and the default (`base` here means "a
608
+ # string, defaulting to http://localhost:8000"), and a `$SENTINEL` constrains
609
+ # without defaulting. The generated `Spec` module carries it into the SDK,
610
+ # where makeOptions validates the caller's options against it.
611
+ #
612
+ # WHY IT MOVED HERE. It used to be a literal inside every language's
613
+ # make_options template — twenty hand-maintained copies of one schema, two of
614
+ # them (cpp, scala) as JSON string constants. Nothing checked them against
615
+ # each other and nothing checked them against the documented option list, so
616
+ # the runtime contract, the twenty copies and the README were three sources
617
+ # of truth for the same thing. A project that adds an option now adds it in
618
+ # ONE place and every ported target validates it.
619
+ #
620
+ # Keys are the option names a caller passes to the constructor. Unknown
621
+ # top-level keys are DROPPED by validate (not rejected) — that is struct's
622
+ # behaviour, not a choice made here, and it is why `extend` needs an entry:
623
+ # without one the constructor's feature-adoption seam silently received
624
+ # nothing.
625
+ main: kit: optspec: {
626
+
627
+ # Credentials. '' is the documented "not supplied" value; `auth: null`
628
+ # suppresses auth outright and is restored AFTER validate (a stored null
629
+ # reads as "no value", so the default below would otherwise refill it).
630
+ apikey: ''
631
+ secret: ''
632
+
633
+ # The API base URL. A `{name}` placeholder is resolved from `server`.
634
+ base: 'http://localhost:8000'
635
+ prefix: ''
636
+ suffix: ''
637
+
638
+ auth: {
639
+ prefix: ''
640
+ basic: false
641
+ }
642
+
643
+ # Extra headers sent with every request: any name, string values.
644
+ headers: {
645
+ '`$CHILD`': '`$STRING`'
646
+ }
647
+
648
+ # The operation and method allow-lists, as comma-separated strings.
649
+ allow: {
650
+ method: 'GET,PUT,POST,PATCH,DELETE,OPTIONS'
651
+ op: 'create,update,load,list,remove,command,direct,graphql'
652
+ }
653
+
654
+ # Per-entity overrides. `$OPEN` because an entity entry carries
655
+ # target-specific keys (aliases, test data) this schema does not enumerate.
656
+ entity: {
657
+ '`$CHILD`': {
658
+ '`$OPEN`': true
659
+ active: false
660
+ alias: {}
661
+ }
662
+ }
663
+
664
+ # Feature INSTANCES supplied at construction (the station adopt path):
665
+ # class instances, not data, so `$ANY` passes them through verbatim.
666
+ extend: '`$ANY`'
667
+
668
+ # Platform seams. A function value does not survive validate (struct drops
669
+ # it), so `system.fetch` is captured and restored around the call.
670
+ utility: {}
671
+ system: {
672
+ fetch: '`$ANY`'
673
+ }
674
+
675
+ test: {
676
+ active: false
677
+ entity: {
678
+ '`$OPEN`': true
679
+ }
680
+ }
681
+
682
+ clean: {
683
+ keys: 'key,token,id'
684
+ }
685
+
686
+ # Server-variable values for a templated base URL (OpenAPI server
687
+ # variables). Spec defaults arrive through the generated Config; these are
688
+ # the caller's overrides.
689
+ server: {
690
+ '`$CHILD`': ''
691
+ }
692
+
693
+ # `feature` is NOT declared here. It is assembled per target from each
694
+ # active feature's own `config.options`, which is already the feature's
695
+ # by-example schema — see helpers/optspec.
696
+ }
697
+
698
+
574
699
 
575
700
 
576
701
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxgig/sdkgen",
3
- "version": "4.17.6",
3
+ "version": "4.18.0",
4
4
  "main": "dist/sdkgen.js",
5
5
  "type": "commonjs",
6
6
  "engines": {
@@ -22,3 +22,18 @@ main: kit: feature: audit: {
22
22
  PreUnexpected: active: true
23
23
  }
24
24
  }
25
+
26
+
27
+ # TYPES for the options this feature reads but does not default.
28
+ #
29
+ # `config.options` is the defaults map — what happens when you say nothing —
30
+ # so it can only describe an option that HAS a default. A callback has none,
31
+ # and an option the caller either supplies or does not has none either. Left
32
+ # undeclared these were invisible twice over: the generated option spec could
33
+ # not type them, and the README's option table could not list them.
34
+ main: kit: feature: audit: config: optspec: {
35
+ # injected clock, so a test can pin the timestamps
36
+ now: '`$FUNCTION`'
37
+ # receives every audit record
38
+ sink: '`$FUNCTION`'
39
+ }
@@ -23,3 +23,16 @@ main: kit: feature: cache: {
23
23
  # Cache wraps the transport in init(); it dispatches no pipeline hooks.
24
24
  hook: {}
25
25
  }
26
+
27
+
28
+ # TYPES for the options this feature reads but does not default.
29
+ #
30
+ # `config.options` is the defaults map — what happens when you say nothing —
31
+ # so it can only describe an option that HAS a default. A callback has none,
32
+ # and an option the caller either supplies or does not has none either. Left
33
+ # undeclared these were invisible twice over: the generated option spec could
34
+ # not type them, and the README's option table could not list them.
35
+ main: kit: feature: cache: config: optspec: {
36
+ # injected clock, for TTL expiry without waiting
37
+ now: '`$FUNCTION`'
38
+ }
@@ -20,3 +20,24 @@ main: kit: feature: clienttrack: {
20
20
  PreRequest: active: true
21
21
  }
22
22
  }
23
+
24
+
25
+ # TYPES for the options this feature reads but does not default.
26
+ #
27
+ # `config.options` is the defaults map — what happens when you say nothing —
28
+ # so it can only describe an option that HAS a default. A callback has none,
29
+ # and an option the caller either supplies or does not has none either. Left
30
+ # undeclared these were invisible twice over: the generated option spec could
31
+ # not type them, and the README's option table could not list them.
32
+ main: kit: feature: clienttrack: config: optspec: {
33
+ # overrides the SDK name sent in the client header
34
+ clientName: '`$STRING`'
35
+ # overrides the SDK version sent with it
36
+ clientVersion: '`$STRING`'
37
+ # extra headers merged into every tracked request
38
+ headers: '`$MAP`'
39
+ # supplies session and request ids
40
+ idgen: '`$FUNCTION`'
41
+ # pins the session id instead of generating one
42
+ sessionId: '`$STRING`'
43
+ }
@@ -41,3 +41,18 @@ main: kit: feature: cost: {
41
41
  PreUnexpected: active: true
42
42
  }
43
43
  }
44
+
45
+
46
+ # TYPES for the options this feature reads but does not default.
47
+ #
48
+ # `config.options` is the defaults map — what happens when you say nothing —
49
+ # so it can only describe an option that HAS a default. A callback has none,
50
+ # and an option the caller either supplies or does not has none either. Left
51
+ # undeclared these were invisible twice over: the generated option spec could
52
+ # not type them, and the README's option table could not list them.
53
+ main: kit: feature: cost: config: optspec: {
54
+ # who the spend is attributed to
55
+ actor: '`$STRING`'
56
+ # receives every priced attempt
57
+ sink: '`$FUNCTION`'
58
+ }
@@ -25,3 +25,18 @@ main: kit: feature: debug: {
25
25
  PreUnexpected: active: true
26
26
  }
27
27
  }
28
+
29
+
30
+ # TYPES for the options this feature reads but does not default.
31
+ #
32
+ # `config.options` is the defaults map — what happens when you say nothing —
33
+ # so it can only describe an option that HAS a default. A callback has none,
34
+ # and an option the caller either supplies or does not has none either. Left
35
+ # undeclared these were invisible twice over: the generated option spec could
36
+ # not type them, and the README's option table could not list them.
37
+ main: kit: feature: debug: config: optspec: {
38
+ # injected clock, so a trace has stable durations
39
+ now: '`$FUNCTION`'
40
+ # receives each trace entry as it is recorded
41
+ onEntry: '`$FUNCTION`'
42
+ }
@@ -21,6 +21,7 @@
21
21
  @"audit.aon"
22
22
  @"clienttrack.aon"
23
23
  @"rbac.aon"
24
+ @"validate.aon"
24
25
 
25
26
  # Test support: network behaviour simulation
26
27
  @"netsim.aon"
@@ -21,3 +21,16 @@ main: kit: feature: idempotency: {
21
21
  PreRequest: active: true
22
22
  }
23
23
  }
24
+
25
+
26
+ # TYPES for the options this feature reads but does not default.
27
+ #
28
+ # `config.options` is the defaults map — what happens when you say nothing —
29
+ # so it can only describe an option that HAS a default. A callback has none,
30
+ # and an option the caller either supplies or does not has none either. Left
31
+ # undeclared these were invisible twice over: the generated option spec could
32
+ # not type them, and the README's option table could not list them.
33
+ main: kit: feature: idempotency: config: optspec: {
34
+ # supplies the idempotency key
35
+ keygen: '`$FUNCTION`'
36
+ }
@@ -38,3 +38,16 @@ main: kit: feature: log: {
38
38
  }
39
39
 
40
40
 
41
+ # TYPES for the options this feature reads but does not default.
42
+ #
43
+ # `config.options` is the defaults map — what happens when you say nothing —
44
+ # so it can only describe an option that HAS a default. A callback has none,
45
+ # and an option the caller either supplies or does not has none either. Left
46
+ # undeclared these were invisible twice over: the generated option spec could
47
+ # not type them, and the README's option table could not list them.
48
+ main: kit: feature: log: config: optspec: {
49
+ # pino level: 'info' unless set
50
+ level: '`$STRING`'
51
+ # an existing logger to use instead of constructing one
52
+ logger: '`$ANY`'
53
+ }
@@ -20,3 +20,16 @@ main: kit: feature: metrics: {
20
20
  PreUnexpected: active: true
21
21
  }
22
22
  }
23
+
24
+
25
+ # TYPES for the options this feature reads but does not default.
26
+ #
27
+ # `config.options` is the defaults map — what happens when you say nothing —
28
+ # so it can only describe an option that HAS a default. A callback has none,
29
+ # and an option the caller either supplies or does not has none either. Left
30
+ # undeclared these were invisible twice over: the generated option spec could
31
+ # not type them, and the README's option table could not list them.
32
+ main: kit: feature: metrics: config: optspec: {
33
+ # injected clock, for deterministic durations
34
+ now: '`$FUNCTION`'
35
+ }
@@ -31,6 +31,20 @@ main: kit: feature: netsim: {
31
31
  # hard outage: every call fails at the transport level
32
32
  offline: false
33
33
  }
34
+
35
+ # TYPES for the options whose kind the default cannot state.
36
+ # `config.optspec` wins over `config.options` when a name is in both, so
37
+ # the default above still documents the value and this states what the
38
+ # feature actually accepts.
39
+ optspec: {
40
+ # `latency: 0` reads as "a number", but the feature also takes
41
+ # `{ min, max }` for a uniform sample — the comment above said so and
42
+ # the spec would have rejected it.
43
+ latency: ['`$ONE`', '`$NUMBER`', '`$MAP`']
44
+
45
+ # Injected clock, for tests that must not really wait.
46
+ sleep: '`$FUNCTION`'
47
+ }
34
48
  }
35
49
 
36
50
  # Netsim wraps the transport in init(); it dispatches no pipeline hooks.
@@ -30,3 +30,18 @@ main: kit: feature: paging: {
30
30
  PreResult: active: true
31
31
  }
32
32
  }
33
+
34
+
35
+ # TYPES for the options this feature reads but does not default.
36
+ #
37
+ # `config.options` is the defaults map — what happens when you say nothing —
38
+ # so it can only describe an option that HAS a default. A callback has none,
39
+ # and an option the caller either supplies or does not has none either. Left
40
+ # undeclared these were invisible twice over: the generated option spec could
41
+ # not type them, and the README's option table could not list them.
42
+ main: kit: feature: paging: config: optspec: {
43
+ # page size to request
44
+ limit: '`$NUMBER`'
45
+ # which operations paginate
46
+ ops: '`$LIST`'
47
+ }
@@ -23,3 +23,16 @@ main: kit: feature: proxy: {
23
23
  # Proxy wraps the transport in init(); it dispatches no pipeline hooks.
24
24
  hook: {}
25
25
  }
26
+
27
+
28
+ # TYPES for the options this feature reads but does not default.
29
+ #
30
+ # `config.options` is the defaults map — what happens when you say nothing —
31
+ # so it can only describe an option that HAS a default. A callback has none,
32
+ # and an option the caller either supplies or does not has none either. Left
33
+ # undeclared these were invisible twice over: the generated option spec could
34
+ # not type them, and the README's option table could not list them.
35
+ main: kit: feature: proxy: config: optspec: {
36
+ # builds the transport agent for a proxy URL
37
+ agent: '`$FUNCTION`'
38
+ }
@@ -21,3 +21,18 @@ main: kit: feature: ratelimit: {
21
21
  # Ratelimit wraps the transport in init(); it dispatches no pipeline hooks.
22
22
  hook: {}
23
23
  }
24
+
25
+
26
+ # TYPES for the options this feature reads but does not default.
27
+ #
28
+ # `config.options` is the defaults map — what happens when you say nothing —
29
+ # so it can only describe an option that HAS a default. A callback has none,
30
+ # and an option the caller either supplies or does not has none either. Left
31
+ # undeclared these were invisible twice over: the generated option spec could
32
+ # not type them, and the README's option table could not list them.
33
+ main: kit: feature: ratelimit: config: optspec: {
34
+ # injected clock
35
+ now: '`$FUNCTION`'
36
+ # injected delay, so a test need not really wait
37
+ sleep: '`$FUNCTION`'
38
+ }
@@ -23,3 +23,18 @@ main: kit: feature: retry: {
23
23
  # Retry wraps the transport in init(); it dispatches no pipeline hooks.
24
24
  hook: {}
25
25
  }
26
+
27
+
28
+ # TYPES for the options this feature reads but does not default.
29
+ #
30
+ # `config.options` is the defaults map — what happens when you say nothing —
31
+ # so it can only describe an option that HAS a default. A callback has none,
32
+ # and an option the caller either supplies or does not has none either. Left
33
+ # undeclared these were invisible twice over: the generated option spec could
34
+ # not type them, and the README's option table could not list them.
35
+ main: kit: feature: retry: config: optspec: {
36
+ # randomise the backoff delay
37
+ jitter: '`$BOOLEAN`'
38
+ # injected delay, so a test need not really wait
39
+ sleep: '`$FUNCTION`'
40
+ }
@@ -22,3 +22,18 @@ main: kit: feature: streaming: {
22
22
  PreResult: active: true
23
23
  }
24
24
  }
25
+
26
+
27
+ # TYPES for the options this feature reads but does not default.
28
+ #
29
+ # `config.options` is the defaults map — what happens when you say nothing —
30
+ # so it can only describe an option that HAS a default. A callback has none,
31
+ # and an option the caller either supplies or does not has none either. Left
32
+ # undeclared these were invisible twice over: the generated option spec could
33
+ # not type them, and the README's option table could not list them.
34
+ main: kit: feature: streaming: config: optspec: {
35
+ # which operations stream
36
+ ops: '`$LIST`'
37
+ # injected delay for paced delivery
38
+ sleep: '`$FUNCTION`'
39
+ }
@@ -21,3 +21,22 @@ main: kit: feature: telemetry: {
21
21
  PreUnexpected: active: true
22
22
  }
23
23
  }
24
+
25
+
26
+ # TYPES for the options this feature reads but does not default.
27
+ #
28
+ # `config.options` is the defaults map — what happens when you say nothing —
29
+ # so it can only describe an option that HAS a default. A callback has none,
30
+ # and an option the caller either supplies or does not has none either. Left
31
+ # undeclared these were invisible twice over: the generated option spec could
32
+ # not type them, and the README's option table could not list them.
33
+ main: kit: feature: telemetry: config: optspec: {
34
+ # receives each finished span
35
+ exporter: '`$FUNCTION`'
36
+ # extra headers merged into the propagated context
37
+ headers: '`$MAP`'
38
+ # supplies trace and span ids
39
+ idgen: '`$FUNCTION`'
40
+ # injected clock
41
+ now: '`$FUNCTION`'
42
+ }
@@ -30,3 +30,16 @@ main: kit: feature: test: {
30
30
  }
31
31
 
32
32
 
33
+ # TYPES for the options this feature reads but does not default.
34
+ #
35
+ # `config.options` is the defaults map — what happens when you say nothing —
36
+ # so it can only describe an option that HAS a default. A callback has none,
37
+ # and an option the caller either supplies or does not has none either. Left
38
+ # undeclared these were invisible twice over: the generated option spec could
39
+ # not type them, and the README's option table could not list them.
40
+ main: kit: feature: test: config: optspec: {
41
+ # seeded records, keyed by entity name
42
+ entity: '`$MAP`'
43
+ # netsim-shaped conditions for the mock transport
44
+ net: '`$MAP`'
45
+ }
@@ -18,3 +18,18 @@ main: kit: feature: timeout: {
18
18
  # Timeout wraps the transport in init(); it dispatches no pipeline hooks.
19
19
  hook: {}
20
20
  }
21
+
22
+
23
+ # TYPES for the options this feature reads but does not default.
24
+ #
25
+ # `config.options` is the defaults map — what happens when you say nothing —
26
+ # so it can only describe an option that HAS a default. A callback has none,
27
+ # and an option the caller either supplies or does not has none either. Left
28
+ # undeclared these were invisible twice over: the generated option spec could
29
+ # not type them, and the README's option table could not list them.
30
+ main: kit: feature: timeout: config: optspec: {
31
+ # injected clearTimeout
32
+ clearTimer: '`$FUNCTION`'
33
+ # injected setTimeout
34
+ setTimer: '`$FUNCTION`'
35
+ }
@@ -0,0 +1,73 @@
1
+
2
+ main: kit: feature: validate: {
3
+
4
+ name: key()
5
+ title: "Payload validation against the model's own field types"
6
+ version: '0.0.1'
7
+ active: true
8
+ base: 'BASE'
9
+ transport: 'none'
10
+
11
+ # Applicability (docs/design/feature-tags.md): this feature is nothing
12
+ # without the generated `Schema` module, so it applies only to targets that
13
+ # emit one. ts and js today; a target joins by emitting Schema from its
14
+ # Main and declaring the tag.
15
+ needs: { schema: true }
16
+
17
+ # The one feature whose schema is not hand-written: the specs come from
18
+ # `fields[].type`, the canonical type sentinels apidef already records for
19
+ # every entity field and operation parameter, mapped into struct.validate's
20
+ # vocabulary at generation time (helpers/canonSpec) and emitted into the
21
+ # generated `Spec` module. Turning this on costs the model nothing extra;
22
+ # turning it off keeps those specs out of the generated source entirely.
23
+ config: {
24
+ options: {
25
+ active: false
26
+
27
+ # Check outbound payloads: what the caller asked to send, against the
28
+ # operation's request shape (the same partiality policy that decides
29
+ # what the generated `<Name>CreateData` type requires).
30
+ request: true
31
+
32
+ # Check inbound records against the entity's field types. OFF by
33
+ # default, and deliberately: a server that adds a field is not breaking
34
+ # its clients, and a spec built from a snapshot of the API would turn
35
+ # that into an error for every caller at once. Turn it on in tests and
36
+ # in staging, where an unannounced change is news rather than an
37
+ # outage.
38
+ response: false
39
+
40
+ # Reject keys the model does not declare. The generated specs are
41
+ # `$OPEN`, because apidef records the properties a spec declared and
42
+ # that is not a promise the payload carries nothing else; `strict`
43
+ # drops the `$OPEN` marker at init and closes them.
44
+ strict: false
45
+
46
+ # 'throw' — a failure rejects the operation (a validate_failed error).
47
+ # 'report' — a failure is collected and the call proceeds.
48
+ mode: 'throw'
49
+ }
50
+
51
+ optspec: {
52
+ # A callback receiving every failure, whatever `mode` does with it, so
53
+ # a client can log or count invalid payloads without changing what the
54
+ # SDK returns. No default: it is supplied or it is not.
55
+ onInvalid: '`$FUNCTION`'
56
+
57
+ # CLOSED, unlike the default above. Read by example, `mode: 'throw'`
58
+ # is just "a string", and the runtime treats anything that is not
59
+ # 'report' as throw — so `mode: 'repot'` would have quietly kept
60
+ # enforcement on while its author believed they had turned it off.
61
+ # Naming the two values makes the typo a construction error.
62
+ mode: ['`$ONE`', ['`$EXACT`', 'throw'], ['`$EXACT`', 'report']]
63
+ }
64
+ }
65
+
66
+ hook: {
67
+ # Outbound, before the HTTP spec is built from the payload.
68
+ PreSpec: active: true
69
+
70
+ # Inbound, once the result data has been extracted from the response.
71
+ PreDone: active: true
72
+ }
73
+ }
@@ -10,7 +10,7 @@ main: kit: target: js: {
10
10
  # Applicability (docs/design/feature-tags.md). A vendored sekreto port
11
11
  # lives in this target's feature container, so a feature that resolves
12
12
  # secrets through sekreto can apply here.
13
- provides: { sekreto: true }
13
+ provides: { sekreto: true, schema: true }
14
14
 
15
15
  # Files earlier toolchains generated that this target has RETIRED
16
16
  # (vendor-tag rollout): the single fused runner. `doctor` reports
@@ -10,7 +10,7 @@ main: kit: target: ts: {
10
10
  # Applicability (docs/design/feature-tags.md). A vendored sekreto port
11
11
  # lives in this target's feature container, so a feature that resolves
12
12
  # secrets through sekreto can apply here.
13
- provides: { sekreto: true }
13
+ provides: { sekreto: true, schema: true }
14
14
 
15
15
  # Files earlier toolchains generated that this target has RETIRED
16
16
  # (vendor-tag rollout): the hand-written runner and the omni compat
@@ -24,6 +24,7 @@ import {
24
24
 
25
25
  import { Package } from './Package_js'
26
26
  import { Config } from './Config_js'
27
+ import { Schema } from './Schema_js'
27
28
  import { Gitignore } from './Gitignore_js'
28
29
  import { MainEntity } from './MainEntity_js'
29
30
  import { SdkError } from './SdkError_js'
@@ -193,6 +194,7 @@ if (fres instanceof Promise) { await fres }
193
194
  })
194
195
 
195
196
  Config({ target })
197
+ Schema({ target })
196
198
 
197
199
  EntityBase({ target })
198
200