@kumwe/studio-testkit 0.1.0-alpha.7 → 0.1.0-beta.2

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 (189) hide show
  1. package/README.md +122 -23
  2. package/THIRD_PARTY_NOTICES.md +9 -0
  3. package/conformance/authoring-web/non-drag-move-equivalence.json +199 -0
  4. package/conformance/renderer-web/blob-default-deny.json +62 -0
  5. package/conformance/renderer-web/chart-fallback.json +54 -0
  6. package/conformance/renderer-web/complete-catalog.json +649 -0
  7. package/conformance/renderer-web/escaped-heading.json +43 -0
  8. package/conformance/renderer-web/interactive-behaviors.json +284 -0
  9. package/conformance/renderer-web/presentation-capabilities.json +104 -0
  10. package/conformance/renderer-web/responsive-grid.json +48 -0
  11. package/conformance/renderer-web/security-fallbacks.json +184 -0
  12. package/conformance/rich-text/advanced.first-party.json +67 -0
  13. package/corpus-manifest.json +571 -37
  14. package/dist/contextual-conformance.d.ts +81 -0
  15. package/dist/contextual-conformance.d.ts.map +1 -0
  16. package/dist/contextual-conformance.js +1 -0
  17. package/dist/host-testbed.d.ts +68 -5
  18. package/dist/host-testbed.d.ts.map +1 -1
  19. package/dist/host-testbed.js +1 -547
  20. package/dist/http-authoring-contract.d.ts +3 -0
  21. package/dist/http-authoring-contract.d.ts.map +1 -0
  22. package/dist/http-authoring-contract.js +1 -0
  23. package/dist/http-host-adapter.d.ts +12 -64
  24. package/dist/http-host-adapter.d.ts.map +1 -1
  25. package/dist/http-host-adapter.js +1 -256
  26. package/dist/http-host-responder.d.ts +58 -0
  27. package/dist/http-host-responder.d.ts.map +1 -0
  28. package/dist/http-host-responder.js +1 -0
  29. package/dist/index.d.ts +88 -3
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -140
  32. package/dist/web-conformance.d.ts +112 -0
  33. package/dist/web-conformance.d.ts.map +1 -0
  34. package/dist/web-conformance.js +1 -0
  35. package/fixtures/authoring-message-catalog.en.json +1093 -0
  36. package/fixtures/authoring-save.plan.example.json +48 -0
  37. package/fixtures/authoring-session.example.json +212 -0
  38. package/fixtures/authoring-target.example.json +34 -0
  39. package/fixtures/host-capabilities.example.json +2 -2
  40. package/fixtures/host-operations.example.json +77 -0
  41. package/fixtures/plugin.example.json +12 -0
  42. package/fixtures/preview.render.example.json +1 -0
  43. package/fixtures/reusable-content-type.example.json +26 -0
  44. package/fixtures/studio-config.example.json +3 -3
  45. package/fixtures/studio-deployment.hosted.example.json +152 -0
  46. package/fixtures/studio-deployment.standalone.example.json +9 -0
  47. package/invalid/authoring-save.plan-missing-coordinates.json +16 -0
  48. package/invalid/authoring-save.plan-missing-successor-context.json +28 -0
  49. package/invalid/authoring-save.request-plan-missing-successor-context.json +26 -0
  50. package/invalid/authoring-session.missing-entry-state.json +9 -0
  51. package/invalid/authoring-target.missing-resource-types.json +24 -0
  52. package/invalid/binding-projection-vector.unknown-status.json +85 -0
  53. package/invalid/host-capabilities.invalid-protocol-version.json +1 -1
  54. package/invalid/host-error.retry-delay-without-retry.json +16 -0
  55. package/invalid/host-error.retry-delay-wrong-category.json +16 -0
  56. package/invalid/host-error.revision-without-conflict.json +16 -0
  57. package/invalid/host-sequence.pending-expectation.json +52 -0
  58. package/invalid/host-sequence.preview-render-missing-request-id.json +50 -0
  59. package/invalid/preview-message.activated-unknown-interaction.json +1 -1
  60. package/invalid/preview-message.duplicate-marker.json +24 -0
  61. package/invalid/preview-message.invalid-digest.json +1 -0
  62. package/invalid/preview-message.invalid-marker-grammar.json +19 -0
  63. package/invalid/preview-message.missing-marker-map.json +20 -0
  64. package/invalid/preview-message.missing-render-request-id.json +18 -0
  65. package/invalid/preview-message.unknown-type.json +13 -0
  66. package/invalid/preview-message.viewport-height-too-small.json +13 -0
  67. package/invalid/preview-message.viewport-unsafe-role.json +13 -0
  68. package/invalid/reusable-content-type.entry-values.json +32 -0
  69. package/invalid/studio-chart.script-config.json +10 -0
  70. package/invalid/studio-deployment.long-lived-token.json +24 -0
  71. package/invalid/studio-deployment.missing-required.json +5 -0
  72. package/invalid/studio-deployment.unknown-member.json +15 -0
  73. package/invalid/studio-drawing.svg-payload.json +10 -0
  74. package/invalid/studio-money.float.json +8 -0
  75. package/invalid/studio-presentation.css-injection.json +8 -0
  76. package/invalid/studio-table.html-cell.json +8 -0
  77. package/package.json +8 -4
  78. package/studio-release.json +35 -0
  79. package/vectors/authoring-http/transport-matrix.json +237 -0
  80. package/vectors/binding-projection/app-content-fields.resolved.json +286 -0
  81. package/vectors/binding-projection/field-removed.diagnostic.json +135 -0
  82. package/vectors/binding-projection/model-revision-mismatch.diagnostic.json +124 -0
  83. package/vectors/host/artifact.dependencies.result.json +2 -2
  84. package/vectors/host/artifact.load.stored.json +2 -2
  85. package/vectors/host/artifact.load.unknown.error.json +2 -2
  86. package/vectors/host/artifact.publish.accepted.json +2 -2
  87. package/vectors/host/artifact.publish.forbidden.error.json +1 -1
  88. package/vectors/host/artifact.publish.stale.error.json +2 -2
  89. package/vectors/host/artifact.save.accepted.json +2 -2
  90. package/vectors/host/artifact.save.forbidden.error.json +1 -1
  91. package/vectors/host/artifact.save.stale.error.json +2 -2
  92. package/vectors/host/artifact.unpublish.stale.error.json +2 -2
  93. package/vectors/host/envelope.malformed-context.error.json +2 -2
  94. package/vectors/host/envelope.protocol-version.error.json +1 -1
  95. package/vectors/host/envelope.stale-generation.error.json +2 -2
  96. package/vectors/host/localization.messages.unknown-locale.error.json +2 -2
  97. package/vectors/host/media.abort-upload.unknown.error.json +1 -1
  98. package/vectors/host/media.authorize-upload.granted.json +1 -1
  99. package/vectors/host/media.authorize-upload.path-filename.error.json +1 -1
  100. package/vectors/host/media.authorize-upload.too-large.error.json +1 -1
  101. package/vectors/host/media.complete-upload.unknown.error.json +1 -1
  102. package/vectors/host/media.get.unknown.json +2 -2
  103. package/vectors/host/media.import-external.private-host.error.json +1 -1
  104. package/vectors/host/media.list.cursor.error.json +2 -2
  105. package/vectors/host/media.list.limit.error.json +2 -2
  106. package/vectors/host/media.upload-status.unknown.error.json +1 -1
  107. package/vectors/host/model.get.stored.json +37 -0
  108. package/vectors/host/model.list.authorized.json +31 -0
  109. package/vectors/host/permission.explain.withheld.json +2 -2
  110. package/vectors/host/permission.refresh.snapshot.json +2 -2
  111. package/vectors/host/recovery.load.absent.json +2 -2
  112. package/vectors/host/telemetry.emit.accepted.json +2 -2
  113. package/vectors/host/telemetry.emit.non-primitive.error.json +2 -2
  114. package/vectors/host-sequence/artifact.publish.changed-intent.sequence.json +75 -0
  115. package/vectors/host-sequence/artifact.publish.idempotent-replay.sequence.json +111 -0
  116. package/vectors/host-sequence/preview.cancel.cross-context.sequence.json +78 -0
  117. package/vectors/host-sequence/preview.render.cancelled.sequence.json +75 -0
  118. package/vectors/host-sequence/recovery.store.canonical-number.sequence.json +72 -0
  119. package/vectors/host-sequence/recovery.store.changed-context.sequence.json +61 -0
  120. package/vectors/host-sequence/recovery.store.rate-limited.sequence.json +93 -0
  121. package/vectors/host-sequence/recovery.store.resource-scope.sequence.json +61 -0
  122. package/vectors/host-sequence/recovery.store.wrong-operation-id.sequence.json +56 -0
  123. package/vectors/preview/canonical-preorder.json +102 -0
  124. package/vectors/preview/empty-draft.json +36 -0
  125. package/vectors/schema-profile/alternative-limit.accepted.json +95 -0
  126. package/vectors/schema-profile/alternative-limit.rejected.json +92 -0
  127. package/vectors/schema-profile/array-composition.accepted.json +35 -0
  128. package/vectors/schema-profile/byte-limit.accepted.json +30 -0
  129. package/vectors/schema-profile/byte-limit.rejected.json +26 -0
  130. package/vectors/schema-profile/closed-object.accepted.json +38 -0
  131. package/vectors/schema-profile/decimal-multiple.accepted.json +54 -0
  132. package/vectors/schema-profile/depth-limit.accepted.json +90 -0
  133. package/vectors/schema-profile/depth-limit.rejected.json +88 -0
  134. package/vectors/schema-profile/description-limit.accepted.json +29 -0
  135. package/vectors/schema-profile/description-limit.rejected.json +25 -0
  136. package/vectors/schema-profile/diagnostic-precedence.rejected.json +26 -0
  137. package/vectors/schema-profile/duplicate-dependent-required.rejected.json +21 -0
  138. package/vectors/schema-profile/duplicate-required.rejected.json +18 -0
  139. package/vectors/schema-profile/empty-combinator.rejected.json +17 -0
  140. package/vectors/schema-profile/empty-enum.rejected.json +17 -0
  141. package/vectors/schema-profile/enum-limit.accepted.json +89 -0
  142. package/vectors/schema-profile/enum-limit.rejected.json +84 -0
  143. package/vectors/schema-profile/examples-limit.accepted.json +35 -0
  144. package/vectors/schema-profile/examples-limit.rejected.json +31 -0
  145. package/vectors/schema-profile/format-keyword.rejected.json +17 -0
  146. package/vectors/schema-profile/forward-reference-path-precedence.rejected.json +20 -0
  147. package/vectors/schema-profile/invalid-pointer.rejected.json +18 -0
  148. package/vectors/schema-profile/json-depth-limit.accepted.json +278 -0
  149. package/vectors/schema-profile/json-depth-limit.rejected.json +276 -0
  150. package/vectors/schema-profile/json-item-limit.accepted.json +686 -0
  151. package/vectors/schema-profile/json-item-limit.rejected.json +682 -0
  152. package/vectors/schema-profile/json-property-limit.accepted.json +1031 -0
  153. package/vectors/schema-profile/json-property-limit.rejected.json +1028 -0
  154. package/vectors/schema-profile/local-reference.accepted.json +28 -0
  155. package/vectors/schema-profile/memoized-diagnostic.accepted.json +31 -0
  156. package/vectors/schema-profile/node-limit.accepted.json +1097 -0
  157. package/vectors/schema-profile/node-limit.rejected.json +1094 -0
  158. package/vectors/schema-profile/non-object-root.rejected.json +9 -0
  159. package/vectors/schema-profile/non-schema-reference.rejected.json +21 -0
  160. package/vectors/schema-profile/object-key-limit.accepted.json +32 -0
  161. package/vectors/schema-profile/object-key-limit.rejected.json +28 -0
  162. package/vectors/schema-profile/open-root.rejected.json +13 -0
  163. package/vectors/schema-profile/percent-encoded-pointer.rejected.json +26 -0
  164. package/vectors/schema-profile/property-name-limit.accepted.json +543 -0
  165. package/vectors/schema-profile/property-name-limit.rejected.json +536 -0
  166. package/vectors/schema-profile/recursive-diagnostic-precedence.rejected.json +30 -0
  167. package/vectors/schema-profile/recursive-reference.rejected.json +24 -0
  168. package/vectors/schema-profile/reference-fanout.accepted.json +662 -0
  169. package/vectors/schema-profile/reference-length-limit.accepted.json +45 -0
  170. package/vectors/schema-profile/reference-length-limit.rejected.json +39 -0
  171. package/vectors/schema-profile/reference-limit.accepted.json +416 -0
  172. package/vectors/schema-profile/reference-limit.rejected.json +415 -0
  173. package/vectors/schema-profile/reference-vs-keyword-precedence.rejected.json +22 -0
  174. package/vectors/schema-profile/reserved-pointer.rejected.json +26 -0
  175. package/vectors/schema-profile/root-diagnostic-precedence.rejected.json +16 -0
  176. package/vectors/schema-profile/root-vs-reference-precedence.rejected.json +19 -0
  177. package/vectors/schema-profile/schema-map-limit.accepted.json +539 -0
  178. package/vectors/schema-profile/schema-map-limit.rejected.json +536 -0
  179. package/vectors/schema-profile/semantic-recursion-precedence.rejected.json +21 -0
  180. package/vectors/schema-profile/semantic-reference-precedence.rejected.json +21 -0
  181. package/vectors/schema-profile/title-limit.accepted.json +29 -0
  182. package/vectors/schema-profile/title-limit.rejected.json +25 -0
  183. package/vectors/schema-profile/unresolved-reference.rejected.json +17 -0
  184. package/vectors/schema-profile/unsafe-dependent-required.rejected.json +24 -0
  185. package/vectors/schema-profile/unsafe-member.rejected.json +17 -0
  186. package/vectors/schema-profile/unsafe-required.rejected.json +17 -0
  187. package/dist/host-testbed.js.map +0 -1
  188. package/dist/http-host-adapter.js.map +0 -1
  189. package/dist/index.js.map +0 -1
@@ -1,74 +1,22 @@
1
+ import { type HttpAuthenticationResolver, type HttpFetchLike, type HttpRequestInit, type HttpSchemaValidator, type HttpTimeoutHandle } from '@kumwe/studio-core';
1
2
  import { type HostAdapter } from '@kumwe/studio-protocol';
2
- /**
3
- * Minimal structural view of an HTTP response the adapter needs: the status
4
- * code and the raw body text. Deliberately narrower than any platform
5
- * response class so implementations from any runtime satisfy it.
6
- */
7
- export interface HttpResponseLike {
8
- status: number;
9
- text(): Promise<string>;
10
- }
11
- /** The request shape the adapter hands to the injected transport. */
12
- export interface HttpRequestInit {
13
- body: string;
14
- headers: Record<string, string>;
15
- method: 'POST';
16
- /** Opaque abort signal produced by the injected timeout factory, if any. */
17
- signal?: unknown;
18
- }
19
- /**
20
- * The injected fetch-like transport — the adapter's portability seam.
21
- *
22
- * Testkit source is deliberately free of host globals (no fetch, no DOM, no
23
- * Node), so the embedder supplies the platform transport: a Node test injects
24
- * a `node:http`-backed implementation, a browser host would inject the
25
- * platform fetch, and either stays outside this package. The function must
26
- * resolve with the terminal HTTP response (any status) and reject only for
27
- * transport-level failures: network refusal, connection loss, or an abort
28
- * raised by the injected timeout signal.
29
- */
30
- export type HttpFetchLike = (url: string, init: HttpRequestInit) => Promise<HttpResponseLike>;
31
- /**
32
- * An abort signal handle minted per request by the injected timeout factory.
33
- * `signal` is passed through to the transport untouched; `release` (when
34
- * present) is invoked once the request settles so timer-backed factories can
35
- * clean up.
36
- */
37
- export interface HttpTimeoutHandle {
38
- release?(): void;
39
- signal: unknown;
40
- }
3
+ export { HTTP_HOST_OPERATION_ROUTES } from '@kumwe/studio-core';
4
+ export type { ConfiguredHttpHostAdapterOptions, HttpAuthenticationConfiguration, HttpAuthenticationRequest, HttpAuthenticationResolver, HttpBearerTokenAuthentication, HttpFetchLike, HttpHeaderTokenAuthentication, HttpHostOperationEndpoints, HttpHostOperationRoute, HttpHostRoutingConfiguration, HttpHostTransportConfiguration, HttpRequestInit, HttpResponseLike, HttpSameOriginSessionAuthentication, HttpTimeoutHandle, } from '@kumwe/studio-core';
5
+ /** Historical conventional-route options retained only for test conformance. */
41
6
  export interface HttpHostAdapterOptions {
42
- /**
43
- * Second half of the portability seam: mints the per-request timeout
44
- * signal. When omitted, requests carry no deadline. A rejection whose
45
- * reason is named `AbortError` or `TimeoutError` is mapped to the canonical
46
- * deadline failure.
47
- */
48
7
  createTimeoutSignal?: (timeoutMilliseconds: number) => HttpTimeoutHandle;
8
+ credentials?: HttpRequestInit['credentials'];
49
9
  fetchImplementation: HttpFetchLike;
50
- /** Transport deadline handed to `createTimeoutSignal`. Defaults to 10 000. */
10
+ maximumResponseBytes?: number;
11
+ requestHeaders?: () => Readonly<Record<string, string>>;
12
+ resolveAuthentication?: HttpAuthenticationResolver;
51
13
  timeoutMilliseconds?: number;
14
+ validateSchema?: HttpSchemaValidator;
52
15
  }
53
16
  /**
54
- * A `HostAdapter` that speaks JSON over an injected fetch-like transport to a
55
- * host server: every port operation becomes
56
- * `POST {baseUrl}/ports/{port}/{operation}` with a
57
- * `{ arguments, context }` JSON body.
58
- *
59
- * Success responses (2xx) must carry a `HostPortResult` JSON body. Failure
60
- * responses that carry a guard-conforming `HostPortError` body are re-thrown
61
- * as that canonical error, so a host-authored category (with its safe
62
- * revision on conflicts) crosses the transport intact. Everything else is
63
- * mapped onto the canonical host error categories without disclosing
64
- * transport details: network refusal and deadline expiry become
65
- * `unavailable`, HTTP statuses map by class (401 `unauthenticated`, 403
66
- * `forbidden`, 404 `not-found`, 409 `conflict`, 413 `limit-exceeded`, 422
67
- * `validation-failed`, 429 `rate-limited`, 5xx `internal`/`unavailable`), and
68
- * a malformed body — unparseable JSON, a result without `value`, or an error
69
- * document the guard rejects — becomes `internal`. Every rejection is a
70
- * `TestbedHostError` whose `error` satisfies `isHostPortError`, and no
71
- * message ever echoes response bodies, addresses, or underlying reasons.
17
+ * Backward-compatible testkit facade over the production core transport.
18
+ * Canonical `HostPortFailure` rejections are translated to the historical
19
+ * `TestbedHostError` subclass without duplicating any HTTP behavior.
72
20
  */
73
21
  export declare function createHttpHostAdapter(baseUrl: string, options: HttpHostAdapterOptions): HostAdapter;
74
22
  //# sourceMappingURL=http-host-adapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-host-adapter.d.ts","sourceRoot":"","sources":["../src/http-host-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,WAAW,EAqBjB,MAAM,wBAAwB,CAAC;AAGhC;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAE9F;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,CAAC,mBAAmB,EAAE,MAAM,KAAK,iBAAiB,CAAC;IACzE,mBAAmB,EAAE,aAAa,CAAC;IACnC,8EAA8E;IAC9E,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,sBAAsB,GAC9B,WAAW,CA8Lb"}
1
+ {"version":3,"file":"http-host-adapter.d.ts","sourceRoot":"","sources":["../src/http-host-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAEhE,YAAY,EACV,gCAAgC,EAChC,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,aAAa,EACb,6BAA6B,EAC7B,0BAA0B,EAC1B,sBAAsB,EACtB,4BAA4B,EAC5B,8BAA8B,EAC9B,eAAe,EACf,gBAAgB,EAChB,mCAAmC,EACnC,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAE5B,gFAAgF;AAChF,MAAM,WAAW,sBAAsB;IACrC,mBAAmB,CAAC,EAAE,CAAC,mBAAmB,EAAE,MAAM,KAAK,iBAAiB,CAAC;IACzE,WAAW,CAAC,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC;IAC7C,mBAAmB,EAAE,aAAa,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,qBAAqB,CAAC,EAAE,0BAA0B,CAAC;IACnD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,mBAAmB,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,sBAAsB,GAC9B,WAAW,CAiEb"}
@@ -1,256 +1 @@
1
- import { isHostPortError, STUDIO_CONTRACT_VERSION, } from '@kumwe/studio-protocol';
2
- import { TestbedHostError } from './host-testbed.js';
3
- /**
4
- * A `HostAdapter` that speaks JSON over an injected fetch-like transport to a
5
- * host server: every port operation becomes
6
- * `POST {baseUrl}/ports/{port}/{operation}` with a
7
- * `{ arguments, context }` JSON body.
8
- *
9
- * Success responses (2xx) must carry a `HostPortResult` JSON body. Failure
10
- * responses that carry a guard-conforming `HostPortError` body are re-thrown
11
- * as that canonical error, so a host-authored category (with its safe
12
- * revision on conflicts) crosses the transport intact. Everything else is
13
- * mapped onto the canonical host error categories without disclosing
14
- * transport details: network refusal and deadline expiry become
15
- * `unavailable`, HTTP statuses map by class (401 `unauthenticated`, 403
16
- * `forbidden`, 404 `not-found`, 409 `conflict`, 413 `limit-exceeded`, 422
17
- * `validation-failed`, 429 `rate-limited`, 5xx `internal`/`unavailable`), and
18
- * a malformed body — unparseable JSON, a result without `value`, or an error
19
- * document the guard rejects — becomes `internal`. Every rejection is a
20
- * `TestbedHostError` whose `error` satisfies `isHostPortError`, and no
21
- * message ever echoes response bodies, addresses, or underlying reasons.
22
- */
23
- export function createHttpHostAdapter(baseUrl, options) {
24
- const base = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
25
- const timeoutMilliseconds = options.timeoutMilliseconds ?? 10_000;
26
- let correlationSerial = 0;
27
- function createError(failure) {
28
- correlationSerial += 1;
29
- const error = {
30
- category: failure.category,
31
- contractVersion: STUDIO_CONTRACT_VERSION,
32
- correlationId: `http-transport-${correlationSerial}`,
33
- kind: 'host-error',
34
- message: { defaultMessage: failure.defaultMessage, key: failure.key },
35
- retryable: failure.retryable,
36
- };
37
- return new TestbedHostError(error);
38
- }
39
- async function call(portName, operation, callArguments, context) {
40
- const handle = options.createTimeoutSignal?.(timeoutMilliseconds);
41
- let response;
42
- try {
43
- response = await options.fetchImplementation(`${base}/ports/${portName}/${operation}`, {
44
- body: JSON.stringify({ arguments: callArguments, context }),
45
- headers: { 'content-type': 'application/json' },
46
- method: 'POST',
47
- ...(handle === undefined ? {} : { signal: handle.signal }),
48
- });
49
- }
50
- catch (reason) {
51
- throw createError(classifyTransportFailure(reason));
52
- }
53
- finally {
54
- handle?.release?.();
55
- }
56
- let bodyText;
57
- try {
58
- bodyText = await response.text();
59
- }
60
- catch {
61
- throw createError(malformedResponse());
62
- }
63
- if (response.status >= 200 && response.status < 300) {
64
- const parsed = parseJson(bodyText);
65
- if (!isHostPortResult(parsed)) {
66
- throw createError(malformedResponse());
67
- }
68
- const result = {
69
- ...(parsed.revision === undefined ? {} : { revision: parsed.revision }),
70
- value: parsed.value,
71
- };
72
- return result;
73
- }
74
- const parsed = parseJson(bodyText);
75
- if (isHostPortError(parsed)) {
76
- // The host authored a canonical error; transport it verbatim.
77
- throw new TestbedHostError(parsed);
78
- }
79
- throw createError(statusFailure(response.status));
80
- }
81
- return {
82
- artifact: {
83
- dependencies(reference, context) {
84
- return call('artifact', 'dependencies', { reference: asJson(reference) }, context);
85
- },
86
- load(reference, context) {
87
- return call('artifact', 'load', { reference: asJson(reference) }, context);
88
- },
89
- publish(reference, context) {
90
- return call('artifact', 'publish', { reference: asJson(reference) }, context);
91
- },
92
- save(document, context) {
93
- return call('artifact', 'save', { document: asJson(document) }, context);
94
- },
95
- unpublish(reference, context) {
96
- return call('artifact', 'unpublish', { reference: asJson(reference) }, context);
97
- },
98
- },
99
- localization: {
100
- messages(locale, namespaces, context) {
101
- return call('localization', 'messages', { locale, namespaces }, context);
102
- },
103
- },
104
- media: {
105
- abortUpload(uploadId, context) {
106
- return call('media', 'abort-upload', { uploadId }, context);
107
- },
108
- authorizeUpload(request, context) {
109
- return call('media', 'authorize-upload', { request: asJson(request) }, context);
110
- },
111
- completeUpload(uploadId, context) {
112
- return call('media', 'complete-upload', { uploadId }, context);
113
- },
114
- get(assetId, context) {
115
- return call('media', 'get', { assetId }, context);
116
- },
117
- importExternal(url, context) {
118
- return call('media', 'import-external', { url }, context);
119
- },
120
- list(query, context) {
121
- return call('media', 'list', { query: asJson(query) }, context);
122
- },
123
- uploadStatus(assetId, context) {
124
- return call('media', 'upload-status', { assetId }, context);
125
- },
126
- },
127
- permission: {
128
- explain(operation, context) {
129
- return call('permission', 'explain', { operation }, context);
130
- },
131
- refresh(context) {
132
- return call('permission', 'refresh', {}, context);
133
- },
134
- },
135
- preview: {
136
- cancel(draftDigest, context) {
137
- return call('preview', 'cancel', { draftDigest }, context);
138
- },
139
- render(payload, context) {
140
- return call('preview', 'render', { payload: asJson(payload) }, context);
141
- },
142
- },
143
- recovery: {
144
- discard(context) {
145
- return call('recovery', 'discard', {}, context);
146
- },
147
- load(context) {
148
- return call('recovery', 'load', {}, context);
149
- },
150
- store(envelope, context) {
151
- return call('recovery', 'store', { envelope }, context);
152
- },
153
- },
154
- resource: {
155
- search(query, context) {
156
- return call('resource', 'search', { query: asJson(query) }, context);
157
- },
158
- },
159
- telemetry: {
160
- emit(event, context) {
161
- return call('telemetry', 'emit', { event: asJson(event) }, context);
162
- },
163
- },
164
- };
165
- }
166
- /** Serializable typed values cross the wire as their JSON projections. */
167
- function asJson(value) {
168
- return JSON.parse(JSON.stringify(value));
169
- }
170
- function parseJson(text) {
171
- try {
172
- return JSON.parse(text);
173
- }
174
- catch {
175
- return undefined;
176
- }
177
- }
178
- function isHostPortResult(value) {
179
- if (typeof value !== 'object' || value === null || Array.isArray(value)) {
180
- return false;
181
- }
182
- const record = value;
183
- if (!Object.hasOwn(record, 'value')) {
184
- return false;
185
- }
186
- const revision = record.revision;
187
- if (revision !== undefined && (typeof revision !== 'string' || revision.length === 0)) {
188
- return false;
189
- }
190
- return Object.keys(record).every((key) => key === 'value' || key === 'revision');
191
- }
192
- function classifyTransportFailure(reason) {
193
- const name = typeof reason === 'object' && reason !== null && 'name' in reason ? reason.name : undefined;
194
- if (name === 'AbortError' || name === 'TimeoutError') {
195
- // The injected deadline signal fired before the host answered.
196
- return {
197
- category: 'unavailable',
198
- defaultMessage: 'The host did not respond within the transport deadline.',
199
- key: 'studio.testkit/http-timeout',
200
- retryable: true,
201
- };
202
- }
203
- return {
204
- category: 'unavailable',
205
- defaultMessage: 'The host could not be reached.',
206
- key: 'studio.testkit/http-unreachable',
207
- retryable: true,
208
- };
209
- }
210
- function malformedResponse() {
211
- return {
212
- category: 'internal',
213
- defaultMessage: 'The host response could not be interpreted.',
214
- key: 'studio.testkit/http-malformed-response',
215
- retryable: false,
216
- };
217
- }
218
- function statusFailure(status) {
219
- const category = categoryForStatus(status);
220
- return {
221
- category,
222
- defaultMessage: 'The host rejected the request.',
223
- key: `studio.testkit/http-status-${category}`,
224
- retryable: category === 'rate-limited' || category === 'unavailable',
225
- };
226
- }
227
- function categoryForStatus(status) {
228
- switch (status) {
229
- case 401:
230
- return 'unauthenticated';
231
- case 403:
232
- return 'forbidden';
233
- case 404:
234
- return 'not-found';
235
- case 408:
236
- return 'unavailable';
237
- case 409:
238
- return 'conflict';
239
- case 413:
240
- return 'limit-exceeded';
241
- case 422:
242
- return 'validation-failed';
243
- case 429:
244
- return 'rate-limited';
245
- case 502:
246
- case 503:
247
- case 504:
248
- return 'unavailable';
249
- default:
250
- if (status >= 400 && status < 500) {
251
- return 'invalid-request';
252
- }
253
- return 'internal';
254
- }
255
- }
256
- //# sourceMappingURL=http-host-adapter.js.map
1
+ import{HTTP_HOST_OPERATION_ROUTES as e,createHttpHostAdapter as t}from"@kumwe/studio-core";import{isHostPortFailure as n}from"@kumwe/studio-protocol";import{TestbedHostError as r}from"./host-testbed.js";export{HTTP_HOST_OPERATION_ROUTES}from"@kumwe/studio-core";export function createHttpHostAdapter(n,r){let i=r.createTimeoutSignal,s=a(n),l=Object.fromEntries(e.map(e=>[e,`${s}/ports/${e}`])),u=r.timeoutMilliseconds??1e4,d=r.maximumResponseBytes??67108864;if(!Number.isSafeInteger(u)||u<=0)throw TypeError(`timeoutMilliseconds must be a positive safe integer.`);if(!Number.isSafeInteger(d)||d<=0)throw TypeError(`maximumResponseBytes must be a positive safe integer.`);let f=async(e,t)=>{let n;try{n=o(t.headers,r.requestHeaders?.())}catch{let e=Error(`The testkit HTTP request headers are invalid.`);throw e.name=`InvalidRequestError`,e}let i=await r.fetchImplementation(e,{...t,credentials:r.credentials??`same-origin`,headers:n});return{...i.contentType===void 0?{}:{contentType:i.contentType},status:i.status,text:()=>i.text(d)}};return c(t({authentication:{credentials:`omit`,expiresAt:`1970-01-01T00:10:00Z`,headerName:`X-Studio-Testkit-Transport`,issuedAt:`1970-01-01T00:00:00Z`,kind:`header-token`,token:`conformance`},kind:`http`,maximumResponseBytes:Math.min(67108864,Math.max(1024,d)),requestTimeoutMilliseconds:1e4,routing:{endpoints:l,kind:`operation-map`}},{...i===void 0?{}:{createTimeoutSignal:()=>i(u)},currentTimeMilliseconds:()=>0,fetchImplementation:f,...r.resolveAuthentication===void 0?{}:{resolveAuthentication:r.resolveAuthentication},...r.validateSchema===void 0?{}:{validateSchema:r.validateSchema}}))}function a(e){if(e===``)return``;if(e.trim()!==e||/\s/u.test(e)||e.includes(`?`)||e.includes(`#`)||e.includes(`\\`))throw TypeError(`baseUrl must not contain whitespace, a query, or a fragment.`);let t=e.endsWith(`/`)?e.slice(0,-1):e,n;if(t.startsWith(`https://`)||t.startsWith(`http://`)){let e=t.indexOf(`://`)+3,r=t.indexOf(`/`,e),i=r===-1?t.slice(e):t.slice(e,r);if(i.length===0||i.includes(`@`))throw TypeError(`baseUrl must contain a host and must not embed credentials.`);n=r===-1?``:t.slice(r)}else{if(!t.startsWith(`/`)||t.startsWith(`//`))throw TypeError(`baseUrl must be an HTTP(S) URL or a same-origin absolute path.`);n=t}if(n.includes(`//`))throw TypeError(`baseUrl path must be normalized without empty segments.`);for(let e of n.split(`/`))if(e===`.`||e===`..`||/%2e/iu.test(e))throw TypeError(`baseUrl path must not contain dot segments.`);return t}function o(e,t){let n={...e};for(let[e,r]of Object.entries(t??{})){let t=e.toLowerCase();if(e.length>100||!/^[!#$%&'*+.^_`|~0-9a-z-]+$/u.test(t)||r.length>8192||r.trim()!==r||s(r)||t===`accept`||t===`content-type`||t===`x-studio-operation`||Object.hasOwn(n,t))throw TypeError(`Invalid HTTP request header.`);n[t]=r}return n}function s(e){for(let t=0;t<e.length;t+=1){let n=e.charCodeAt(t);if(n<=8||n>=10&&n<=31||n===127||n>255)return!0}return!1}function c(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,l(t)]))}function l(e){return new Proxy(e,{get(e,t,i){let a=Reflect.get(e,t,i);return typeof a==`function`?(...t)=>Promise.resolve(Reflect.apply(a,e,t)).catch(e=>{throw n(e)&&!(e instanceof r)?new r(e.error):e}):a}})}
@@ -0,0 +1,58 @@
1
+ import { type AuthoringPort, type QualifiedName } from '@kumwe/studio-protocol';
2
+ import { type AuthoringHttpRoute, type HttpSchemaValidator } from './http-authoring-contract.js';
3
+ export interface HttpResponderRequest {
4
+ /** Raw JSON body after the HTTP server has decoded transport bytes as UTF-8. */
5
+ body: string;
6
+ /** Header names are matched case-insensitively. Duplicate spellings fail closed. */
7
+ headers: Readonly<Record<string, string | undefined>>;
8
+ method: string;
9
+ /** Pathname only. A query string is not a Studio port route. */
10
+ path: string;
11
+ }
12
+ export interface HttpResponderResponse {
13
+ body: string;
14
+ headers: Readonly<Record<string, string>>;
15
+ status: number;
16
+ }
17
+ export interface HttpTransportSecurityDecision {
18
+ /** Authentication was derived from trusted transport evidence, never the JSON body. */
19
+ authenticated: boolean;
20
+ /** A CSRF token, strict same-origin proof, or non-browser service credential bound this call. */
21
+ requestIntegrity: boolean;
22
+ }
23
+ export interface HttpTransportSecurityInput {
24
+ capability: QualifiedName;
25
+ headers: Readonly<Record<string, string | undefined>>;
26
+ method: 'POST';
27
+ mutating: boolean;
28
+ path: string;
29
+ route: AuthoringHttpRoute;
30
+ }
31
+ export type HttpTransportSecurityVerifier = (input: HttpTransportSecurityInput) => HttpTransportSecurityDecision | Promise<HttpTransportSecurityDecision>;
32
+ /**
33
+ * Validates one value against the exact canonical schema reference supplied
34
+ * by the responder. A PHP host performs the equivalent call in its PHP JSON
35
+ * Schema library; the reference responder deliberately does not own Ajv.
36
+ */
37
+ export interface AuthoringHttpResponderOptions {
38
+ /** Defaults to 64 MiB; hosts may set a stricter deployment-specific limit. */
39
+ maximumRequestBytes?: number;
40
+ /** Defaults to `/ports`. */
41
+ routePrefix?: string;
42
+ validateSchema: HttpSchemaValidator;
43
+ /** Required fail-closed authentication plus CSRF/origin/service-integrity boundary. */
44
+ verifyTransportSecurity: HttpTransportSecurityVerifier;
45
+ }
46
+ /**
47
+ * Creates a platform-neutral reference responder for all seven contextual
48
+ * authoring routes. It receives and returns plain values, so an HTTP server,
49
+ * Service Worker, browser mock, or PHP interoperability test can bind it
50
+ * without importing a server framework.
51
+ *
52
+ * The responder validates transport method/content type/size, performs the
53
+ * trusted authentication and request-integrity check before parsing JSON,
54
+ * validates the exact operation schema, checks capability and resource
55
+ * context binding, and only then invokes the host-authoritative port.
56
+ */
57
+ export declare function createAuthoringHttpResponder(authoring: AuthoringPort, options: AuthoringHttpResponderOptions): (request: HttpResponderRequest) => Promise<HttpResponderResponse>;
58
+ //# sourceMappingURL=http-host-responder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-host-responder.d.ts","sourceRoot":"","sources":["../src/http-host-responder.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EAalB,KAAK,aAAa,EACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,8BAA8B,CAAC;AAEtC,MAAM,WAAW,oBAAoB;IACnC,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,6BAA6B;IAC5C,uFAAuF;IACvF,aAAa,EAAE,OAAO,CAAC;IACvB,iGAAiG;IACjG,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,kBAAkB,CAAC;CAC3B;AAED,MAAM,MAAM,6BAA6B,GAAG,CAC1C,KAAK,EAAE,0BAA0B,KAC9B,6BAA6B,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAAC;AAE5E;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAC5C,8EAA8E;IAC9E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,mBAAmB,CAAC;IACpC,uFAAuF;IACvF,uBAAuB,EAAE,6BAA6B,CAAC;CACxD;AA8CD;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,6BAA6B,GACrC,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CA0JnE"}
@@ -0,0 +1 @@
1
+ import{isHostPortFailure as e,STUDIO_CONTRACT_VERSION as t}from"@kumwe/studio-protocol";import{AUTHORING_HTTP_OPERATIONS as n,AUTHORING_HTTP_OPERATIONS_BY_ROUTE as r}from"./http-authoring-contract.js";const i=Object.freeze({"cache-control":`no-store`,"content-type":`application/json; charset=utf-8`,"x-content-type-options":`nosniff`}),a=Object.freeze({"authoring/list-types":(e,t)=>e.listTypes(t.arguments.query,t.context),"authoring/plan-save":(e,t)=>e.planSave(t.arguments.intent,t.context),"authoring/resolve-target":(e,t)=>e.resolveTarget(t.arguments.request,t.context),"authoring/save-as-new-type":(e,t)=>e.saveAsNewType(t.arguments.request,t.context),"authoring/save-item":(e,t)=>e.saveItem(t.arguments.request,t.context),"authoring/save-new-type-version":(e,t)=>e.saveNewTypeVersion(t.arguments.request,t.context),"authoring/start":(e,t)=>e.start(t.arguments.request,t.context)});export function createAuthoringHttpResponder(n,r){let i=r.maximumRequestBytes??67108864;if(!Number.isSafeInteger(i)||i<=0)throw TypeError(`maximumRequestBytes must be a positive safe integer.`);let o=c(r.routePrefix??`/ports`),y=0,b=(e,n,r,i=!1)=>(y+=1,h({category:e,contractVersion:t,correlationId:`http-responder/${y}`,kind:`host-error`,message:{defaultMessage:r,key:n},retryable:i},m(e)));return async t=>{let c=s(t.path,o);if(c===void 0)return b(`not-found`,`studio.testkit/http-route-not-found`,`The requested Studio host operation is unavailable.`);if(t.method!==`POST`)return _(b(`invalid-request`,`studio.testkit/http-method-invalid`,`Studio host operations require POST.`));if(!u(l(t.headers,`content-type`)))return b(`invalid-request`,`studio.testkit/http-content-type-invalid`,`Studio host operations require an application/json content type.`);if(v(t.body)>i)return b(`limit-exceeded`,`studio.testkit/http-request-too-large`,`The Studio host request exceeds the configured transport limit.`);let y;try{y=await r.verifyTransportSecurity({capability:c.capability,headers:t.headers,method:`POST`,mutating:c.mutating,path:t.path,route:c.route})}catch{return b(`internal`,`studio.testkit/http-security-check-failed`,`The host could not verify request security.`)}if(!y.authenticated)return b(`unauthenticated`,`studio.testkit/http-unauthenticated`,`Authentication is required for Studio authoring.`);if(!y.requestIntegrity)return b(`forbidden`,`studio.testkit/http-request-integrity-failed`,`The Studio authoring request failed request-integrity verification.`);let x=d(t.body);if(x===void 0)return b(`invalid-request`,`studio.testkit/http-request-malformed`,`The Studio host request body is not valid JSON.`);let S;try{S=r.validateSchema(c.requestSchema,x)}catch{return b(`internal`,`studio.testkit/http-schema-validator-failed`,`The host could not validate the Studio request.`)}if(!S||!f(x)||x.context.operationId!==c.capability)return b(`invalid-request`,`studio.testkit/http-request-invalid`,`The Studio host request does not match the operation contract.`);if(!p(c.route,x))return b(`invalid-request`,`studio.testkit/http-resource-context-mismatch`,`The operation resource context does not match the request envelope.`);let C;try{C=await a[c.route](n,x)}catch(t){return e(t)?h(t.error,m(t.error.category)):b(`internal`,`studio.testkit/http-host-failure`,`The host could not complete the Studio operation.`)}try{S=r.validateSchema(c.responseSchema,C)}catch{S=!1}return S?g(200,C):b(`internal`,`studio.testkit/http-response-invalid`,`The host produced an invalid Studio operation result.`)}}function s(e,t){if(!e.startsWith(`${t}/`)||e.includes(`?`)||e.includes(`#`))return;let n=e.slice(t.length+1);return r.get(n)}function c(e){if(!e.startsWith(`/`)||e.includes(`?`)||e.includes(`#`))throw TypeError(`routePrefix must be an absolute pathname without a query or fragment.`);let t=e.endsWith(`/`)?e.slice(0,-1):e;if(t.length===0||t.includes(`//`))throw TypeError(`routePrefix must identify one normalized absolute pathname.`);return t}function l(e,t){let n=Object.entries(e).filter(([e])=>e.toLowerCase()===t);return n.length===1?n[0]?.[1]:void 0}function u(e){return e?.split(`;`,1)[0]?.trim().toLowerCase()===`application/json`}function d(e){try{return JSON.parse(e)}catch{return}}function f(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=e;return typeof t.arguments==`object`&&t.arguments!==null&&!Array.isArray(t.arguments)&&typeof t.context==`object`&&t.context!==null&&!Array.isArray(t.context)}function p(e,t){let r;switch(e){case n.resolveTarget.route:case n.start.route:r=t.arguments.request?.resourceContext;break;case n.listTypes.route:r=t.arguments.query?.resourceContext;break;default:return!0}return typeof r==`object`&&!!r&&!Array.isArray(r)&&r.key===t.context.resourceContextKey}function m(e){switch(e){case`unauthenticated`:return 401;case`forbidden`:return 403;case`not-found`:return 404;case`conflict`:return 409;case`limit-exceeded`:return 413;case`validation-failed`:return 422;case`rate-limited`:return 429;case`unavailable`:return 503;case`internal`:return 500;case`cancelled`:case`incompatible`:case`invalid-request`:return 400}}function h(e,t){return g(t,e)}function g(e,t){return{body:JSON.stringify(t),headers:i,status:e}}function _(e){return{...e,headers:{...e.headers,allow:`POST`}}}function v(e){let t=0;for(let n of e){let e=n.codePointAt(0)??0;t+=e<=127?1:e<=2047?2:e<=65535?3:4}return t}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,11 @@
1
- import { type BlockDefinition, type BlockSlotDefinition, type BlockType, type BlueprintDocument, type BlueprintBlockLock, type BlueprintNode, type JsonSchema, type StudioConfiguration, type StudioDiagnostic } from '@kumwe/studio-protocol';
2
- export { createHostRequestContextFixture, createTestbedHost, TestbedHostError, type HostRequestContextFixtureOptions, type TestbedControls, type TestbedHost, type TestbedHostOptions, type TestbedPortName, } from './host-testbed.js';
3
- export { createHttpHostAdapter, type HttpFetchLike, type HttpHostAdapterOptions, type HttpRequestInit, type HttpResponseLike, type HttpTimeoutHandle, } from './http-host-adapter.js';
1
+ import { type StudioSchemaProfileErrorCode } from '@kumwe/studio-core';
2
+ import { type BlockDefinition, type BlockSlotDefinition, type BlockType, type BlueprintDocument, type BlueprintBlockLock, type BlueprintNode, type ContentFieldKind, type ContentModelDocument, type DiagnosticLocation, type FieldDefinition, type JsonSchema, type StudioConfiguration, type StudioDiagnostic } from '@kumwe/studio-protocol';
3
+ export { createHostRequestContextFixture, createTestbedHost, TestbedHostError, type HostRequestContextFixtureOptions, type TestbedAuthoringOperation, type TestbedAuthoringOptions, type TestbedAuthoringPlanFixture, type TestbedAuthoringSaveFixture, type TestbedAuthoringSaveRequest, type TestbedAuthoringStartFixture, type TestbedAuthoringTargetFixture, type TestbedAuthoringTypeFixture, type TestbedControls, type TestbedHost, type TestbedHostOptions, type TestbedPortName, type TestbedRateLimitPolicy, } from './host-testbed.js';
4
+ export { createHttpHostAdapter, HTTP_HOST_OPERATION_ROUTES, type ConfiguredHttpHostAdapterOptions, type HttpAuthenticationConfiguration, type HttpAuthenticationRequest, type HttpAuthenticationResolver, type HttpBearerTokenAuthentication, type HttpFetchLike, type HttpHeaderTokenAuthentication, type HttpHostAdapterOptions, type HttpHostOperationEndpoints, type HttpHostOperationRoute, type HttpHostRoutingConfiguration, type HttpHostTransportConfiguration, type HttpRequestInit, type HttpResponseLike, type HttpSameOriginSessionAuthentication, type HttpTimeoutHandle, } from './http-host-adapter.js';
5
+ export { AUTHORING_HTTP_OPERATIONS, AUTHORING_HTTP_OPERATIONS_BY_ROUTE, AUTHORING_HTTP_SCHEMA_ID, type AuthoringHttpOperationContract, type AuthoringHttpRoute, type HttpSchemaValidator, } from './http-authoring-contract.js';
6
+ export { createAuthoringHttpResponder, type AuthoringHttpResponderOptions, type HttpResponderRequest, type HttpResponderResponse, type HttpTransportSecurityDecision, type HttpTransportSecurityInput, type HttpTransportSecurityVerifier, } from './http-host-responder.js';
7
+ export { runAuthoringWebVector, type AuthoringWebAction, type AuthoringWebCommandObservation, type AuthoringWebConformanceAdapter, type AuthoringWebConformanceSession, type AuthoringWebGiven, type AuthoringWebLane, type AuthoringWebLaneResult, type AuthoringWebObservation, type AuthoringWebRegion, type AuthoringWebVector, type AuthoringWebVectorResult, } from './web-conformance.js';
8
+ export { runContextualAuthoringStrideVector, type ContextualAuthoringCommandAssertion, type ContextualAuthoringConformanceAdapter, type ContextualAuthoringConformanceSession, type ContextualAuthoringLaunchAssertion, type ContextualAuthoringSaveAssertion, type ContextualAuthoringSaveRequest, type ContextualAuthoringStrideResult, type ContextualAuthoringStrideVector, } from './contextual-conformance.js';
4
9
  export interface BlueprintFixtureOptions {
5
10
  blockLocks?: BlueprintBlockLock[];
6
11
  id?: string;
@@ -19,6 +24,86 @@ export interface StudioConfigurationFixtureOptions {
19
24
  mode?: 'blueprint' | 'content' | 'model';
20
25
  sessionState?: 'editable' | 'read-only';
21
26
  }
27
+ export interface SchemaProfileVectorInstance {
28
+ value: unknown;
29
+ valid: boolean;
30
+ }
31
+ /** Portable input consumed by `studio.profile/binding-projection-v1`. */
32
+ export interface BindingProjectionVectorInput {
33
+ blockDefinitions: readonly BlockDefinition[];
34
+ blueprint: BlueprintDocument;
35
+ model: ContentModelDocument;
36
+ }
37
+ export interface BindingProjectionVectorCandidateResult {
38
+ cardinality: FieldDefinition['cardinality'];
39
+ control?: string;
40
+ fieldPath: string[];
41
+ itemKind?: Exclude<ContentFieldKind, 'collection'>;
42
+ kind: ContentFieldKind;
43
+ }
44
+ export interface BindingProjectionVectorPortResult {
45
+ bindingSourceKind?: string;
46
+ boundFieldPath?: string[];
47
+ candidates: BindingProjectionVectorCandidateResult[];
48
+ multiple?: boolean;
49
+ port: string;
50
+ required?: boolean;
51
+ status: 'invalid' | 'non-field-source' | 'resolved' | 'unbound';
52
+ valueType?: string;
53
+ }
54
+ export interface BindingProjectionVectorRunResult {
55
+ diagnostics: {
56
+ code: string;
57
+ location?: DiagnosticLocation;
58
+ severity: StudioDiagnostic['severity'];
59
+ }[];
60
+ model: BlueprintDocument['model'];
61
+ nodes: {
62
+ nodeId: string;
63
+ ports: BindingProjectionVectorPortResult[];
64
+ }[];
65
+ }
66
+ /**
67
+ * Replays a binding vector without consulting its expected projection. The
68
+ * normalized result intentionally excludes localized labels and prose so a
69
+ * non-TypeScript host compares stable coordinates, controls, outcomes, and
70
+ * diagnostic locations rather than an English rendering.
71
+ */
72
+ export declare function runBindingProjectionVector(vector: BindingProjectionVectorInput): BindingProjectionVectorRunResult;
73
+ export interface SchemaProfileVectorInput {
74
+ expect: {
75
+ outcome: 'accepted' | 'rejected';
76
+ };
77
+ schema: unknown;
78
+ }
79
+ export interface SchemaProfileVectorInstanceResult {
80
+ diagnostic?: {
81
+ instancePath: string;
82
+ keyword: string;
83
+ };
84
+ value: unknown;
85
+ valid: boolean;
86
+ }
87
+ export type SchemaProfileVectorRunResult = {
88
+ instances: SchemaProfileVectorInstanceResult[];
89
+ outcome: 'accepted';
90
+ } | {
91
+ code: StudioSchemaProfileErrorCode;
92
+ outcome: 'rejected';
93
+ schemaPath: string;
94
+ };
95
+ /**
96
+ * Replay a portable `studio.profile/schema-property` vector against the
97
+ * reference implementation. Only each case's input `value` is read from the
98
+ * accepted expectation; expected verdicts and diagnostics are not consulted.
99
+ * Callers compare this independently produced outcome with the published
100
+ * `expect` member.
101
+ */
102
+ export declare function runSchemaProfileVector(vector: SchemaProfileVectorInput & {
103
+ expect: {
104
+ instances?: SchemaProfileVectorInstance[];
105
+ };
106
+ }): SchemaProfileVectorRunResult;
22
107
  export declare function createBlueprintFixture(options?: BlueprintFixtureOptions): BlueprintDocument;
23
108
  export declare function defineTestBlock(options: TestBlockOptions): BlockDefinition;
24
109
  export declare function createStudioConfigurationFixture(options?: StudioConfigurationFixtureOptions): StudioConfiguration;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,+BAA+B,EAC/B,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,gCAAgC,EACrC,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,GACvB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAClC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,KAAK,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iCAAiC;IAChD,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAChC,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;IACzC,YAAY,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;CACzC;AAED,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,iBAAiB,CAiB/F;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA2B1E;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,iCAAsC,GAC9C,mBAAmB,CAqErB;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,iBAAiB,EAC5B,WAAW,EAAE,SAAS,eAAe,EAAE,GACtC,IAAI,CAKN;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAgB,WAAW,EAAE,gBAAgB,EAAE,CAAC;gBAE7B,WAAW,EAAE,gBAAgB,EAAE;CASnD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}