@thymian/plugin-sampler 0.3.0-canary.20261007-e6cb8dc → 0.3.0-canary.20261007-cdbe1d3

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 (264) hide show
  1. package/dist/cli/check-result.d.ts +88 -0
  2. package/dist/cli/check-result.d.ts.map +1 -0
  3. package/dist/cli/check-result.js +160 -0
  4. package/dist/cli/check-result.js.map +1 -0
  5. package/dist/cli/commands/sampler/check.d.ts +32 -4
  6. package/dist/cli/commands/sampler/check.d.ts.map +1 -1
  7. package/dist/cli/commands/sampler/check.js +126 -88
  8. package/dist/cli/commands/sampler/check.js.map +1 -1
  9. package/dist/cli/commands/sampler/init.d.ts +4 -6
  10. package/dist/cli/commands/sampler/init.d.ts.map +1 -1
  11. package/dist/cli/commands/sampler/init.js +33 -49
  12. package/dist/cli/commands/sampler/init.js.map +1 -1
  13. package/dist/cli/commands/sampler/show.d.ts +11 -0
  14. package/dist/cli/commands/sampler/show.d.ts.map +1 -0
  15. package/dist/cli/commands/sampler/show.js +36 -0
  16. package/dist/cli/commands/sampler/show.js.map +1 -0
  17. package/dist/cli/commands/sampler/sync.d.ts +11 -0
  18. package/dist/cli/commands/sampler/sync.d.ts.map +1 -0
  19. package/dist/cli/commands/sampler/sync.js +65 -0
  20. package/dist/cli/commands/sampler/sync.js.map +1 -0
  21. package/dist/cli/commands/sampler/validate.d.ts +3 -10
  22. package/dist/cli/commands/sampler/validate.d.ts.map +1 -1
  23. package/dist/cli/commands/sampler/validate.js +57 -126
  24. package/dist/cli/commands/sampler/validate.js.map +1 -1
  25. package/dist/generation/closed-schema.d.ts +22 -0
  26. package/dist/generation/closed-schema.d.ts.map +1 -0
  27. package/dist/generation/closed-schema.js +45 -0
  28. package/dist/generation/closed-schema.js.map +1 -0
  29. package/dist/generation/content-type-strategies/json.content-type-strategy.d.ts.map +1 -1
  30. package/dist/generation/content-type-strategies/json.content-type-strategy.js +3 -1
  31. package/dist/generation/content-type-strategies/json.content-type-strategy.js.map +1 -1
  32. package/dist/generation/content-type-strategies/xml.content-type-strategy.d.ts.map +1 -1
  33. package/dist/generation/content-type-strategies/xml.content-type-strategy.js +3 -1
  34. package/dist/generation/content-type-strategies/xml.content-type-strategy.js.map +1 -1
  35. package/dist/generation/generate-request-sample.d.ts +12 -0
  36. package/dist/generation/generate-request-sample.d.ts.map +1 -0
  37. package/dist/generation/{generate-samples.js → generate-request-sample.js} +11 -4
  38. package/dist/generation/generate-request-sample.js.map +1 -0
  39. package/dist/generation/request-generators/default-request-generator.d.ts +14 -0
  40. package/dist/generation/request-generators/default-request-generator.d.ts.map +1 -1
  41. package/dist/generation/request-generators/default-request-generator.js +18 -1
  42. package/dist/generation/request-generators/default-request-generator.js.map +1 -1
  43. package/dist/generation/types/declaration-set.d.ts +124 -0
  44. package/dist/generation/types/declaration-set.d.ts.map +1 -0
  45. package/dist/generation/types/declaration-set.js +389 -0
  46. package/dist/generation/types/declaration-set.js.map +1 -0
  47. package/dist/generation/types/example-reflection.d.ts +21 -0
  48. package/dist/generation/types/example-reflection.d.ts.map +1 -0
  49. package/dist/generation/types/example-reflection.js +135 -0
  50. package/dist/generation/types/example-reflection.js.map +1 -0
  51. package/dist/generation/types/generate-type-surface.d.ts +23 -0
  52. package/dist/generation/types/generate-type-surface.d.ts.map +1 -0
  53. package/dist/generation/types/generate-type-surface.js +671 -0
  54. package/dist/generation/types/generate-type-surface.js.map +1 -0
  55. package/dist/generation/types/schema-type.d.ts +20 -0
  56. package/dist/generation/types/schema-type.d.ts.map +1 -0
  57. package/dist/generation/types/schema-type.js +203 -0
  58. package/dist/generation/types/schema-type.js.map +1 -0
  59. package/dist/generation/types/self-check-surface.d.ts +32 -0
  60. package/dist/generation/types/self-check-surface.d.ts.map +1 -0
  61. package/dist/generation/types/self-check-surface.js +92 -0
  62. package/dist/generation/types/self-check-surface.js.map +1 -0
  63. package/dist/generation/types/type-names.d.ts +135 -0
  64. package/dist/generation/types/type-names.d.ts.map +1 -0
  65. package/dist/generation/types/type-names.js +213 -0
  66. package/dist/generation/types/type-names.js.map +1 -0
  67. package/dist/generation/types/write-type-surface.d.ts +58 -0
  68. package/dist/generation/types/write-type-surface.d.ts.map +1 -0
  69. package/dist/generation/types/write-type-surface.js +119 -0
  70. package/dist/generation/types/write-type-surface.js.map +1 -0
  71. package/dist/hooks/create-hook-utils.d.ts +22 -6
  72. package/dist/hooks/create-hook-utils.d.ts.map +1 -1
  73. package/dist/hooks/create-hook-utils.js +74 -96
  74. package/dist/hooks/create-hook-utils.js.map +1 -1
  75. package/dist/hooks/hook-api.d.ts +49 -0
  76. package/dist/hooks/hook-api.d.ts.map +1 -0
  77. package/dist/hooks/hook-api.js +105 -0
  78. package/dist/hooks/hook-api.js.map +1 -0
  79. package/dist/hooks/hook-diagnostics.d.ts +45 -0
  80. package/dist/hooks/hook-diagnostics.d.ts.map +1 -0
  81. package/dist/hooks/hook-diagnostics.js +80 -0
  82. package/dist/hooks/hook-diagnostics.js.map +1 -0
  83. package/dist/hooks/hook-errors.d.ts +33 -0
  84. package/dist/hooks/hook-errors.d.ts.map +1 -1
  85. package/dist/hooks/hook-errors.js +46 -0
  86. package/dist/hooks/hook-errors.js.map +1 -1
  87. package/dist/hooks/hook-registration.d.ts +108 -0
  88. package/dist/hooks/hook-registration.d.ts.map +1 -0
  89. package/dist/hooks/hook-registration.js +69 -0
  90. package/dist/hooks/hook-registration.js.map +1 -0
  91. package/dist/hooks/hook-runner.d.ts +111 -11
  92. package/dist/hooks/hook-runner.d.ts.map +1 -1
  93. package/dist/hooks/hook-runner.js +309 -142
  94. package/dist/hooks/hook-runner.js.map +1 -1
  95. package/dist/hooks/hook-utils-factory.d.ts +19 -0
  96. package/dist/hooks/hook-utils-factory.d.ts.map +1 -0
  97. package/dist/hooks/hook-utils-factory.js +2 -0
  98. package/dist/hooks/hook-utils-factory.js.map +1 -0
  99. package/dist/hooks/hook-utils.d.ts +80 -12
  100. package/dist/hooks/hook-utils.d.ts.map +1 -1
  101. package/dist/hooks/invoke-hook.d.ts +71 -0
  102. package/dist/hooks/invoke-hook.d.ts.map +1 -0
  103. package/dist/hooks/invoke-hook.js +161 -0
  104. package/dist/hooks/invoke-hook.js.map +1 -0
  105. package/dist/hooks/load-user-hooks.d.ts +96 -0
  106. package/dist/hooks/load-user-hooks.d.ts.map +1 -0
  107. package/dist/hooks/load-user-hooks.js +432 -0
  108. package/dist/hooks/load-user-hooks.js.map +1 -0
  109. package/dist/hooks/nested-request.d.ts +21 -0
  110. package/dist/hooks/nested-request.d.ts.map +1 -0
  111. package/dist/hooks/nested-request.js +24 -0
  112. package/dist/hooks/nested-request.js.map +1 -0
  113. package/dist/hooks/overlay-args.d.ts +40 -0
  114. package/dist/hooks/overlay-args.d.ts.map +1 -0
  115. package/dist/hooks/overlay-args.js +84 -0
  116. package/dist/hooks/overlay-args.js.map +1 -0
  117. package/dist/hooks/resolve-targeting.d.ts +16 -0
  118. package/dist/hooks/resolve-targeting.d.ts.map +1 -0
  119. package/dist/hooks/resolve-targeting.js +168 -0
  120. package/dist/hooks/resolve-targeting.js.map +1 -0
  121. package/dist/hooks/run-scoped-hooks.d.ts +83 -0
  122. package/dist/hooks/run-scoped-hooks.d.ts.map +1 -0
  123. package/dist/hooks/run-scoped-hooks.js +153 -0
  124. package/dist/hooks/run-scoped-hooks.js.map +1 -0
  125. package/dist/index.d.ts +42 -19
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +152 -165
  128. package/dist/index.js.map +1 -1
  129. package/dist/request-sampler.d.ts +40 -11
  130. package/dist/request-sampler.d.ts.map +1 -1
  131. package/dist/request-sampler.js +51 -76
  132. package/dist/request-sampler.js.map +1 -1
  133. package/dist/sampler-paths.d.ts +19 -0
  134. package/dist/sampler-paths.d.ts.map +1 -0
  135. package/dist/sampler-paths.js +22 -0
  136. package/dist/sampler-paths.js.map +1 -0
  137. package/dist/selectors/nearest-paths.d.ts +14 -0
  138. package/dist/selectors/nearest-paths.d.ts.map +1 -0
  139. package/dist/selectors/nearest-paths.js +32 -0
  140. package/dist/selectors/nearest-paths.js.map +1 -0
  141. package/dist/selectors/path-glob.d.ts +94 -0
  142. package/dist/selectors/path-glob.d.ts.map +1 -0
  143. package/dist/selectors/path-glob.js +136 -0
  144. package/dist/selectors/path-glob.js.map +1 -0
  145. package/dist/selectors/selector-errors.d.ts +17 -0
  146. package/dist/selectors/selector-errors.d.ts.map +1 -0
  147. package/dist/selectors/selector-errors.js +139 -0
  148. package/dist/selectors/selector-errors.js.map +1 -0
  149. package/dist/selectors/selector.d.ts +55 -0
  150. package/dist/selectors/selector.d.ts.map +1 -0
  151. package/dist/selectors/selector.js +305 -0
  152. package/dist/selectors/selector.js.map +1 -0
  153. package/dist/selectors/transaction-catalog.d.ts +96 -0
  154. package/dist/selectors/transaction-catalog.d.ts.map +1 -0
  155. package/dist/selectors/transaction-catalog.js +193 -0
  156. package/dist/selectors/transaction-catalog.js.map +1 -0
  157. package/dist/selectors/transaction-filter.d.ts +119 -0
  158. package/dist/selectors/transaction-filter.d.ts.map +1 -0
  159. package/dist/selectors/transaction-filter.js +191 -0
  160. package/dist/selectors/transaction-filter.js.map +1 -0
  161. package/dist/ts-path.d.ts +36 -0
  162. package/dist/ts-path.d.ts.map +1 -0
  163. package/dist/ts-path.js +46 -0
  164. package/dist/ts-path.js.map +1 -0
  165. package/dist/utils.d.ts +1 -2
  166. package/dist/utils.d.ts.map +1 -1
  167. package/dist/utils.js +2 -20
  168. package/dist/utils.js.map +1 -1
  169. package/dist/validation/canonicalize.d.ts +17 -0
  170. package/dist/validation/canonicalize.d.ts.map +1 -0
  171. package/dist/validation/canonicalize.js +29 -0
  172. package/dist/validation/canonicalize.js.map +1 -0
  173. package/dist/validation/shared-compiler-host.d.ts +17 -0
  174. package/dist/validation/shared-compiler-host.d.ts.map +1 -0
  175. package/dist/validation/shared-compiler-host.js +58 -0
  176. package/dist/validation/shared-compiler-host.js.map +1 -0
  177. package/dist/validation/typecheck-hooks.d.ts +37 -0
  178. package/dist/validation/typecheck-hooks.d.ts.map +1 -0
  179. package/dist/validation/typecheck-hooks.js +169 -0
  180. package/dist/validation/typecheck-hooks.js.map +1 -0
  181. package/dist/validation/validate-sampler.d.ts +79 -0
  182. package/dist/validation/validate-sampler.d.ts.map +1 -0
  183. package/dist/validation/validate-sampler.js +89 -0
  184. package/dist/validation/validate-sampler.js.map +1 -0
  185. package/package.json +7 -11
  186. package/dist/cli/commands/sampler/generate/hook.d.ts +0 -10
  187. package/dist/cli/commands/sampler/generate/hook.d.ts.map +0 -1
  188. package/dist/cli/commands/sampler/generate/hook.js +0 -19
  189. package/dist/cli/commands/sampler/generate/hook.js.map +0 -1
  190. package/dist/cli/generate-hook.d.ts +0 -4
  191. package/dist/cli/generate-hook.d.ts.map +0 -1
  192. package/dist/cli/generate-hook.js +0 -96
  193. package/dist/cli/generate-hook.js.map +0 -1
  194. package/dist/cli/templates.d.ts +0 -4
  195. package/dist/cli/templates.d.ts.map +0 -1
  196. package/dist/cli/templates.js +0 -28
  197. package/dist/cli/templates.js.map +0 -1
  198. package/dist/constants.d.ts +0 -12
  199. package/dist/constants.d.ts.map +0 -1
  200. package/dist/constants.js +0 -16
  201. package/dist/constants.js.map +0 -1
  202. package/dist/generation/generate-samples-for-thymian-format.d.ts +0 -4
  203. package/dist/generation/generate-samples-for-thymian-format.d.ts.map +0 -1
  204. package/dist/generation/generate-samples-for-thymian-format.js +0 -18
  205. package/dist/generation/generate-samples-for-thymian-format.js.map +0 -1
  206. package/dist/generation/generate-samples.d.ts +0 -4
  207. package/dist/generation/generate-samples.d.ts.map +0 -1
  208. package/dist/generation/generate-samples.js.map +0 -1
  209. package/dist/hooks/generate-request-types.d.ts +0 -34
  210. package/dist/hooks/generate-request-types.d.ts.map +0 -1
  211. package/dist/hooks/generate-request-types.js +0 -458
  212. package/dist/hooks/generate-request-types.js.map +0 -1
  213. package/dist/hooks/hook-types.d.ts +0 -7
  214. package/dist/hooks/hook-types.d.ts.map +0 -1
  215. package/dist/hooks/hook-types.js +0 -2
  216. package/dist/hooks/hook-types.js.map +0 -1
  217. package/dist/hooks/load-hooks-from-samples.d.ts +0 -3
  218. package/dist/hooks/load-hooks-from-samples.d.ts.map +0 -1
  219. package/dist/hooks/load-hooks-from-samples.js +0 -22
  220. package/dist/hooks/load-hooks-from-samples.js.map +0 -1
  221. package/dist/hooks/ts-config.d.ts +0 -10
  222. package/dist/hooks/ts-config.d.ts.map +0 -1
  223. package/dist/hooks/ts-config.js +0 -10
  224. package/dist/hooks/ts-config.js.map +0 -1
  225. package/dist/samples-structure/file-request-sample.d.ts +0 -20
  226. package/dist/samples-structure/file-request-sample.d.ts.map +0 -1
  227. package/dist/samples-structure/file-request-sample.js +0 -5
  228. package/dist/samples-structure/file-request-sample.js.map +0 -1
  229. package/dist/samples-structure/get-path-transaction-id.d.ts +0 -3
  230. package/dist/samples-structure/get-path-transaction-id.d.ts.map +0 -1
  231. package/dist/samples-structure/get-path-transaction-id.js +0 -22
  232. package/dist/samples-structure/get-path-transaction-id.js.map +0 -1
  233. package/dist/samples-structure/merge-tree.d.ts +0 -5
  234. package/dist/samples-structure/merge-tree.d.ts.map +0 -1
  235. package/dist/samples-structure/merge-tree.js +0 -118
  236. package/dist/samples-structure/merge-tree.js.map +0 -1
  237. package/dist/samples-structure/read-samples-from-dir.d.ts +0 -13
  238. package/dist/samples-structure/read-samples-from-dir.d.ts.map +0 -1
  239. package/dist/samples-structure/read-samples-from-dir.js +0 -205
  240. package/dist/samples-structure/read-samples-from-dir.js.map +0 -1
  241. package/dist/samples-structure/samples-from-transactions.d.ts +0 -5
  242. package/dist/samples-structure/samples-from-transactions.d.ts.map +0 -1
  243. package/dist/samples-structure/samples-from-transactions.js +0 -120
  244. package/dist/samples-structure/samples-from-transactions.js.map +0 -1
  245. package/dist/samples-structure/samples-tree-structure.d.ts +0 -106
  246. package/dist/samples-structure/samples-tree-structure.d.ts.map +0 -1
  247. package/dist/samples-structure/samples-tree-structure.js +0 -26
  248. package/dist/samples-structure/samples-tree-structure.js.map +0 -1
  249. package/dist/samples-structure/structure-meta-on-disc.d.ts +0 -11
  250. package/dist/samples-structure/structure-meta-on-disc.d.ts.map +0 -1
  251. package/dist/samples-structure/structure-meta-on-disc.js +0 -2
  252. package/dist/samples-structure/structure-meta-on-disc.js.map +0 -1
  253. package/dist/samples-structure/traverse.d.ts +0 -4
  254. package/dist/samples-structure/traverse.d.ts.map +0 -1
  255. package/dist/samples-structure/traverse.js +0 -13
  256. package/dist/samples-structure/traverse.js.map +0 -1
  257. package/dist/samples-structure/write-samples-to-dir.d.ts +0 -37
  258. package/dist/samples-structure/write-samples-to-dir.d.ts.map +0 -1
  259. package/dist/samples-structure/write-samples-to-dir.js +0 -183
  260. package/dist/samples-structure/write-samples-to-dir.js.map +0 -1
  261. package/dist/validation/validate-sampler-output.d.ts +0 -38
  262. package/dist/validation/validate-sampler-output.d.ts.map +0 -1
  263. package/dist/validation/validate-sampler-output.js +0 -288
  264. package/dist/validation/validate-sampler-output.js.map +0 -1
@@ -1,61 +1,46 @@
1
1
  import { randomBytes } from 'node:crypto';
2
- import { getContentType, } from '@thymian/core';
3
- import { serializeRequest } from '@thymian/core';
2
+ import { readFileSync } from 'node:fs';
3
+ import { isAbsolute, resolve } from 'node:path';
4
+ import { getContentType, ThymianBaseError, } from '@thymian/core';
4
5
  import { FailError, SkipError } from './hook-errors.js';
5
6
  const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
6
- export function toHttpRequestTemplate(methodAndUrl, req) {
7
- const [method, url] = methodAndUrl.split(' ');
8
- if (!method || !url) {
9
- throw new Error(`Invalid url format: ${url}. Expected format: <METHOD> <PATH>`);
7
+ export function createHookUtils(context) {
8
+ const { dir, results } = context;
9
+ /**
10
+ * The request a setter writes into.
11
+ *
12
+ * A hook that has none is one that shapes nothing — the run-scoped pair. A
13
+ * setter there is a mistake worth naming rather than a silent no-op.
14
+ */
15
+ function request(setter) {
16
+ if (!context.request) {
17
+ throw new ThymianBaseError(`utils.${setter} needs a request to write into, and this hook has none.`, {
18
+ name: 'NoRequestToShapeError',
19
+ suggestions: [
20
+ 'beforeAll and afterAll run once per run rather than per transaction, so there is no request to shape there.',
21
+ ],
22
+ });
23
+ }
24
+ return context.request;
25
+ }
26
+ function filePath(path) {
27
+ return isAbsolute(path) ? path : resolve(dir, path);
10
28
  }
11
- const urlInstance = new URL(url);
12
- return {
13
- authorize: false,
14
- cookies: req.cookies ?? {},
15
- headers: req.headers ?? {},
16
- method,
17
- origin: urlInstance.origin,
18
- path: decodeURI(urlInstance.pathname),
19
- pathParameters: req.path ?? {},
20
- query: req.query ?? {},
21
- body: req.body,
22
- };
23
- }
24
- export function createHookUtils(format, runRequest, hookRunner, urlToTransactionId, results, logger) {
25
29
  return {
26
30
  assertionFailure(message, details = {}) {
27
- results.push({
28
- type: 'assertion-failure',
29
- message,
30
- ...details,
31
- });
31
+ results.push({ type: 'assertion-failure', message, ...details });
32
32
  },
33
33
  assertionSuccess(message, assertion) {
34
- results.push({
35
- type: 'assertion-success',
36
- message,
37
- assertion,
38
- });
34
+ results.push({ type: 'assertion-success', message, assertion });
39
35
  },
40
36
  info(message) {
41
- results.push({
42
- type: 'info',
43
- message,
44
- });
37
+ results.push({ type: 'info', message });
45
38
  },
46
39
  timeout(message, durationMs) {
47
- results.push({
48
- type: 'timeout',
49
- message,
50
- durationMs,
51
- });
40
+ results.push({ type: 'timeout', message, durationMs });
52
41
  },
53
42
  warn(message, details) {
54
- results.push({
55
- type: 'warning',
56
- message,
57
- details,
58
- });
43
+ results.push({ type: 'warning', message, details });
59
44
  },
60
45
  randomString(length = 10) {
61
46
  const bytes = randomBytes(length);
@@ -65,58 +50,46 @@ export function createHookUtils(format, runRequest, hookRunner, urlToTransaction
65
50
  }
66
51
  return result.join('');
67
52
  },
68
- async request(url, args, _options = {}) {
69
- if (typeof url !== 'string') {
70
- throw new Error('Invalid url format.');
71
- }
72
- const options = {
73
- runHooks: true,
74
- ..._options,
75
- };
76
- const key = `${url}${options.forStatusCode ? `->${options.forStatusCode}` : ''}`;
77
- const transactionId = urlToTransactionId[key];
78
- if (!transactionId) {
79
- throw new Error(`Could not find transaction ID for ${key}`);
80
- }
81
- const transaction = format.getThymianHttpTransactionById(transactionId);
82
- let reqTemplate = toHttpRequestTemplate(url, args);
83
- if (options.runHooks) {
84
- logger.debug(`Running beforeEach hooks for ${key}.`);
85
- const res = await hookRunner.beforeEachRequest({
86
- value: reqTemplate,
87
- ctx: transaction,
88
- });
89
- reqTemplate = res.result;
90
- }
91
- if (options.runHooks || options.authorize) {
92
- logger.debug(`Running authorize hook for ${key}.`);
93
- const res = await hookRunner.authorize({
94
- value: reqTemplate,
95
- ctx: transaction,
96
- });
97
- reqTemplate = res.result;
53
+ setHeader(name, value) {
54
+ request('setHeader').headers[name] = value;
55
+ },
56
+ setQuery(name, value) {
57
+ request('setQuery').query[name] = value;
58
+ },
59
+ setPathParam(name, value) {
60
+ request('setPathParam').pathParameters[name] = value;
61
+ },
62
+ setCookie(name, value) {
63
+ request('setCookie').cookies[name] = value;
64
+ },
65
+ setBody(body) {
66
+ request('setBody').body = body;
67
+ },
68
+ setAuthorize(authorize) {
69
+ request('setAuthorize').authorize = authorize;
70
+ },
71
+ readFile(path) {
72
+ return readFileSync(filePath(path));
73
+ },
74
+ readText(path, encoding = 'utf-8') {
75
+ return readFileSync(filePath(path), encoding);
76
+ },
77
+ readJson(path) {
78
+ return JSON.parse(readFileSync(filePath(path), 'utf-8'));
79
+ },
80
+ async request(selector, args = {}, options = {}) {
81
+ if (typeof selector !== 'string') {
82
+ throw new ThymianBaseError('utils.request takes a transaction selector as its first argument.', { name: 'MalformedSelectorError' });
98
83
  }
99
- const req = serializeRequest({
100
- requestTemplate: reqTemplate,
101
- source: transaction,
102
- });
103
- let response = await runRequest(req);
104
- if (options.runHooks) {
105
- logger.debug(`Running afterEach hook for ${key}.`);
106
- const resHookResult = await hookRunner.afterEachResponse({
107
- value: response,
108
- ctx: {
109
- requestTemplate: reqTemplate,
110
- request: req,
111
- },
84
+ if (!context.requestOther) {
85
+ throw new ThymianBaseError(`Cannot run a cross-endpoint request for "${selector}" from this hook.`, {
86
+ name: 'NoNestedRequestError',
87
+ suggestions: [
88
+ 'A defineSample hook runs before any request exists, so there is no pipeline for a nested request to run through. Seed from beforeAll or beforeEach instead.',
89
+ ],
112
90
  });
113
- response = resHookResult.result;
114
91
  }
115
- return {
116
- body: parseResponseBody(response),
117
- headers: response.headers,
118
- statusCode: response.statusCode,
119
- };
92
+ return (await context.requestOther(selector, args, options));
120
93
  },
121
94
  fail(msg) {
122
95
  throw new FailError(msg);
@@ -126,12 +99,17 @@ export function createHookUtils(format, runRequest, hookRunner, urlToTransaction
126
99
  },
127
100
  };
128
101
  }
102
+ /**
103
+ * The body a hook sees, parsed when the response says it is JSON and left as
104
+ * the raw string when it does not.
105
+ */
129
106
  export function parseResponseBody(res) {
130
- const ct = getContentType(res.headers);
107
+ const contentType = getContentType(res.headers);
131
108
  if (typeof res.body === 'string' &&
132
- (ct.match(/^application\/json/i) || ct.match(/^.*\/.*\+json/i))) {
109
+ (/^application\/json/i.test(contentType) ||
110
+ /^.*\/.*\+json/i.test(contentType))) {
133
111
  return JSON.parse(res.body);
134
112
  }
135
- return res;
113
+ return res.body;
136
114
  }
137
115
  //# sourceMappingURL=create-hook-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-hook-utils.js","sourceRoot":"","sources":["../../src/hooks/create-hook-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create-hook-utils.js","sourceRoot":"","sources":["../../src/hooks/create-hook-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The module `@thymian/hooks` resolves to.
3
+ *
4
+ * The plugin's jiti instance aliases the bare specifier `@thymian/hooks` to this
5
+ * file's absolute path, which is what lets a hook file import runtime values in
6
+ * a workspace where `sampler init` was never run.
7
+ *
8
+ * Two consequences, both load-bearing:
9
+ *
10
+ * - **It must live under `src/`.** `package.json`'s `files: ["dist"]` is what
11
+ * puts the built module in the published package; a module outside `src/`
12
+ * never reaches `dist/`.
13
+ * - **Its runtime import graph must stay minimal.** jiti evaluates this file,
14
+ * and everything it imports at runtime, in its own registry. That graph is
15
+ * two leaf modules: `hook-registration.js` and `hook-errors.js`, neither of
16
+ * which imports anything. Everything else here is `import type`, which is
17
+ * erased — in particular `@thymian/core` is not on it, so a hook file
18
+ * resolves with nothing installed alongside it.
19
+ *
20
+ * Callbacks are stored here, never invoked.
21
+ */
22
+ import { UndeclaredResponseError } from './hook-errors.js';
23
+ import { type HookCallback, type HookRegistration, type HookTarget } from './hook-registration.js';
24
+ /**
25
+ * Re-exported so a hook can `catch` it. Letting it escape is equally valid —
26
+ * the transaction boundary catches it and skips the transaction, naming this
27
+ * seed and its actual status.
28
+ */
29
+ export { UndeclaredResponseError };
30
+ /** Shapes the generated request Sample of the targeted Transaction(s). */
31
+ export declare function defineSample(target: HookTarget, callback: HookCallback): HookRegistration;
32
+ /** Runs before each request of the targeted Transaction(s). */
33
+ export declare function beforeEach(target: HookTarget, callback: HookCallback): HookRegistration;
34
+ /** Runs after each response of the targeted Transaction(s). */
35
+ export declare function afterEach(target: HookTarget, callback: HookCallback): HookRegistration;
36
+ /**
37
+ * Supplies credentials. Two arities, one representation:
38
+ *
39
+ * - `authorize(callback)` — the **global** hook, stored as `target: undefined`.
40
+ * - `authorize(target, callback)` — **targeted**, and it wins over the global
41
+ * one for the Transactions it covers.
42
+ */
43
+ export declare function authorize(callback: HookCallback): HookRegistration;
44
+ export declare function authorize(target: HookTarget, callback: HookCallback): HookRegistration;
45
+ /** Runs once before the first request of the run. Carries no target. */
46
+ export declare function beforeAll(callback: HookCallback): HookRegistration;
47
+ /** Runs once when the run closes. Carries no target. */
48
+ export declare function afterAll(callback: HookCallback): HookRegistration;
49
+ //# sourceMappingURL=hook-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-api.d.ts","sourceRoot":"","sources":["../../src/hooks/hook-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAEhB,MAAM,wBAAwB,CAAC;AAEhC;;;;GAIG;AACH,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAyBnC,0EAA0E;AAC1E,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,YAAY,GACrB,gBAAgB,CAIlB;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,YAAY,GACrB,gBAAgB,CAIlB;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CACvB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,YAAY,GACrB,gBAAgB,CAIlB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB,CAAC;AACpE,wBAAgB,SAAS,CACvB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,YAAY,GACrB,gBAAgB,CAAC;AAiDpB,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB,CAIlE;AAED,wDAAwD;AACxD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB,CAIjE"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * The module `@thymian/hooks` resolves to.
3
+ *
4
+ * The plugin's jiti instance aliases the bare specifier `@thymian/hooks` to this
5
+ * file's absolute path, which is what lets a hook file import runtime values in
6
+ * a workspace where `sampler init` was never run.
7
+ *
8
+ * Two consequences, both load-bearing:
9
+ *
10
+ * - **It must live under `src/`.** `package.json`'s `files: ["dist"]` is what
11
+ * puts the built module in the published package; a module outside `src/`
12
+ * never reaches `dist/`.
13
+ * - **Its runtime import graph must stay minimal.** jiti evaluates this file,
14
+ * and everything it imports at runtime, in its own registry. That graph is
15
+ * two leaf modules: `hook-registration.js` and `hook-errors.js`, neither of
16
+ * which imports anything. Everything else here is `import type`, which is
17
+ * erased — in particular `@thymian/core` is not on it, so a hook file
18
+ * resolves with nothing installed alongside it.
19
+ *
20
+ * Callbacks are stored here, never invoked.
21
+ */
22
+ import { UndeclaredResponseError } from './hook-errors.js';
23
+ import { registerHook, } from './hook-registration.js';
24
+ /**
25
+ * Re-exported so a hook can `catch` it. Letting it escape is equally valid —
26
+ * the transaction boundary catches it and skips the transaction, naming this
27
+ * seed and its actual status.
28
+ */
29
+ export { UndeclaredResponseError };
30
+ /**
31
+ * Rejects a missing or non-callable callback at the call site the user wrote.
32
+ *
33
+ * A one-argument `beforeEach(fn)` type-checks nowhere but runs fine in a plain
34
+ * `.js` hook file, and unchecked it would store `target: fn, callback:
35
+ * undefined` and then be reported as a target that matched nothing — naming a
36
+ * target the user never wrote instead of the argument they forgot.
37
+ *
38
+ * A plain `TypeError` rather than a `ThymianBaseError`: keeping `@thymian/core`
39
+ * off this module's runtime graph is what keeps `@thymian/hooks` resolvable from
40
+ * a hook file with nothing installed alongside it.
41
+ */
42
+ function requireCallback(callback, signature) {
43
+ if (typeof callback !== 'function') {
44
+ throw new TypeError(`${signature} needs a function as its callback argument.`);
45
+ }
46
+ }
47
+ /** Shapes the generated request Sample of the targeted Transaction(s). */
48
+ export function defineSample(target, callback) {
49
+ requireCallback(callback, 'defineSample(target, callback)');
50
+ return registerHook({ kind: 'defineSample', target, callback });
51
+ }
52
+ /** Runs before each request of the targeted Transaction(s). */
53
+ export function beforeEach(target, callback) {
54
+ requireCallback(callback, 'beforeEach(target, callback)');
55
+ return registerHook({ kind: 'beforeEach', target, callback });
56
+ }
57
+ /** Runs after each response of the targeted Transaction(s). */
58
+ export function afterEach(target, callback) {
59
+ requireCallback(callback, 'afterEach(target, callback)');
60
+ return registerHook({ kind: 'afterEach', target, callback });
61
+ }
62
+ export function authorize(...args) {
63
+ // Dispatch on **arity**, never on the type of the first argument. Typing the
64
+ // dispatch escalates scope silently in both directions: after a rename,
65
+ // `authorize(SELECTORS.login, fn)` leaves the first argument `undefined`,
66
+ // which is not a function — so a check on the first argument passes, the call
67
+ // falls through to the global form, and a hook aimed at one endpoint
68
+ // authorizes every Transaction in the API. In an authorization hook that is
69
+ // the wrong direction to fail.
70
+ if (args.length > 2) {
71
+ throw authorizeArityError();
72
+ }
73
+ if (args.length === 1) {
74
+ const [callback] = args;
75
+ if (typeof callback !== 'function') {
76
+ throw authorizeArityError();
77
+ }
78
+ return registerHook({ kind: 'authorize', target: undefined, callback });
79
+ }
80
+ const [target, callback] = args;
81
+ if (typeof callback !== 'function') {
82
+ throw authorizeArityError();
83
+ }
84
+ if (target === undefined || typeof target === 'function') {
85
+ throw new TypeError('authorize(target, callback) was called with no target. ' +
86
+ 'Check that the selector you passed is defined, ' +
87
+ 'or call authorize(callback) for the global hook.');
88
+ }
89
+ return registerHook({ kind: 'authorize', target, callback });
90
+ }
91
+ function authorizeArityError() {
92
+ return new TypeError('authorize(target, callback) needs a callback as its second argument. ' +
93
+ 'Call authorize(callback) for the global hook.');
94
+ }
95
+ /** Runs once before the first request of the run. Carries no target. */
96
+ export function beforeAll(callback) {
97
+ requireCallback(callback, 'beforeAll(callback)');
98
+ return registerHook({ kind: 'beforeAll', callback });
99
+ }
100
+ /** Runs once when the run closes. Carries no target. */
101
+ export function afterAll(callback) {
102
+ requireCallback(callback, 'afterAll(callback)');
103
+ return registerHook({ kind: 'afterAll', callback });
104
+ }
105
+ //# sourceMappingURL=hook-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-api.js","sourceRoot":"","sources":["../../src/hooks/hook-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { ThymianBaseError } from '@thymian/core';
2
+ /** What went wrong with one hook, and where. */
3
+ export type HookDiagnostic = {
4
+ /** Hooks-dir-relative path of the file at fault, `/`-normalized. */
5
+ file: string;
6
+ /** The export the registration arrived on, when it is known. */
7
+ exportName?: string;
8
+ /** One sentence, lowercase, completing "…: <reason>". */
9
+ reason: string;
10
+ suggestions?: string[];
11
+ };
12
+ /**
13
+ * The run cannot start: at least one hook does not resolve.
14
+ *
15
+ * Every diagnostic is reported, not just the first — one broken hook must not
16
+ * hide the other nine — and each names its own file so the reader knows which
17
+ * line to edit. A dangling selector is never auto-rebound to a "close enough"
18
+ * Transaction, which is the whole point of anchoring a hook to a fully-qualified
19
+ * Selector.
20
+ */
21
+ export declare function unresolvedHooksError(diagnostics: readonly HookDiagnostic[]): ThymianBaseError;
22
+ /**
23
+ * Two hooks resolve but cannot both apply.
24
+ *
25
+ * Separate from {@link unresolvedHooksError} because the fault is different: the
26
+ * selector is fine and the file loaded: the pair of hooks is the problem, so the
27
+ * sentence has to say so rather than send the reader looking for a bad selector.
28
+ */
29
+ export declare function hookConflictError(conflicts: readonly HookDiagnostic[]): ThymianBaseError;
30
+ /**
31
+ * A hook was created but never exported.
32
+ *
33
+ * Separate from {@link unresolvedHooksError} because the fault is a different
34
+ * one and needs a different sentence: the selector resolves, the file loaded,
35
+ * and the hook is simply unreachable. Sending the reader to look at their
36
+ * selectors would be sending them to the one thing that is fine.
37
+ *
38
+ * This is an error rather than a warning because the outcome is silence. A hook
39
+ * that does not fire looks exactly like a hook that had nothing to do, so
40
+ * there is no run in which the author would rather find out later.
41
+ */
42
+ export declare function unexportedHooksError(unexported: readonly HookDiagnostic[]): ThymianBaseError;
43
+ /** A hook file could not be imported at all. */
44
+ export declare function hookFileImportError(file: string, cause: unknown): ThymianBaseError;
45
+ //# sourceMappingURL=hook-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-diagnostics.d.ts","sourceRoot":"","sources":["../../src/hooks/hook-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,gDAAgD;AAChD,MAAM,MAAM,cAAc,GAAG;IAC3B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAUF;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,SAAS,cAAc,EAAE,GACrC,gBAAgB,CAqBlB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,cAAc,EAAE,GACnC,gBAAgB,CAclB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,SAAS,cAAc,EAAE,GACpC,gBAAgB,CAclB;AAED,gDAAgD;AAChD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,gBAAgB,CASlB"}
@@ -0,0 +1,80 @@
1
+ import { ThymianBaseError } from '@thymian/core';
2
+ function describe(diagnostic) {
3
+ const where = diagnostic.exportName
4
+ ? `${diagnostic.file} (export "${diagnostic.exportName}")`
5
+ : diagnostic.file;
6
+ return `${where}: ${diagnostic.reason}`;
7
+ }
8
+ /**
9
+ * The run cannot start: at least one hook does not resolve.
10
+ *
11
+ * Every diagnostic is reported, not just the first — one broken hook must not
12
+ * hide the other nine — and each names its own file so the reader knows which
13
+ * line to edit. A dangling selector is never auto-rebound to a "close enough"
14
+ * Transaction, which is the whole point of anchoring a hook to a fully-qualified
15
+ * Selector.
16
+ */
17
+ export function unresolvedHooksError(diagnostics) {
18
+ // Hooks, not diagnostics: one hook with two vacuous globs draws two
19
+ // diagnostics, and reporting "2 hooks" for one hook is a lie the reader has
20
+ // to reconcile against the list below.
21
+ const count = new Set(diagnostics.map((diagnostic) => `${diagnostic.file}#${diagnostic.exportName ?? ''}`)).size;
22
+ return new ThymianBaseError(`${count} sampler ${count === 1 ? 'hook does' : 'hooks do'} not resolve against the loaded API description.`, {
23
+ name: 'UnresolvedHooksError',
24
+ ref: 'https://thymian.dev/references/errors/unresolved-hooks-error/',
25
+ suggestions: [
26
+ ...diagnostics.map(describe),
27
+ ...diagnostics.flatMap((diagnostic) => diagnostic.suggestions ?? []),
28
+ ],
29
+ });
30
+ }
31
+ /**
32
+ * Two hooks resolve but cannot both apply.
33
+ *
34
+ * Separate from {@link unresolvedHooksError} because the fault is different: the
35
+ * selector is fine and the file loaded: the pair of hooks is the problem, so the
36
+ * sentence has to say so rather than send the reader looking for a bad selector.
37
+ */
38
+ export function hookConflictError(conflicts) {
39
+ const count = conflicts.length;
40
+ return new ThymianBaseError(`${count} sampler ${count === 1 ? 'hook conflicts' : 'hooks conflict'} with another hook on the same transaction.`, {
41
+ name: 'HookConflictError',
42
+ ref: 'https://thymian.dev/references/errors/hook-conflict-error/',
43
+ suggestions: [
44
+ ...conflicts.map(describe),
45
+ ...conflicts.flatMap((conflict) => conflict.suggestions ?? []),
46
+ ],
47
+ });
48
+ }
49
+ /**
50
+ * A hook was created but never exported.
51
+ *
52
+ * Separate from {@link unresolvedHooksError} because the fault is a different
53
+ * one and needs a different sentence: the selector resolves, the file loaded,
54
+ * and the hook is simply unreachable. Sending the reader to look at their
55
+ * selectors would be sending them to the one thing that is fine.
56
+ *
57
+ * This is an error rather than a warning because the outcome is silence. A hook
58
+ * that does not fire looks exactly like a hook that had nothing to do, so
59
+ * there is no run in which the author would rather find out later.
60
+ */
61
+ export function unexportedHooksError(unexported) {
62
+ const count = unexported.length;
63
+ return new ThymianBaseError(`${count} sampler ${count === 1 ? 'hook is' : 'hooks are'} created but never exported, so nothing can reach ${count === 1 ? 'it' : 'them'}.`, {
64
+ name: 'UnexportedHooksError',
65
+ ref: 'https://thymian.dev/references/errors/unexported-hooks-error/',
66
+ suggestions: [
67
+ ...unexported.map(describe),
68
+ ...unexported.flatMap((diagnostic) => diagnostic.suggestions ?? []),
69
+ ],
70
+ });
71
+ }
72
+ /** A hook file could not be imported at all. */
73
+ export function hookFileImportError(file, cause) {
74
+ return new ThymianBaseError(`The hook file "${file}" could not be imported.`, {
75
+ name: 'HookFileImportError',
76
+ ref: 'https://thymian.dev/references/errors/hook-file-import-error/',
77
+ cause,
78
+ });
79
+ }
80
+ //# sourceMappingURL=hook-diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-diagnostics.js","sourceRoot":"","sources":["../../src/hooks/hook-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAajD,SAAS,QAAQ,CAAC,UAA0B;IAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU;QACjC,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,aAAa,UAAU,CAAC,UAAU,IAAI;QAC1D,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;IAEpB,OAAO,GAAG,KAAK,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAAsC;IAEtC,oEAAoE;IACpE,4EAA4E;IAC5E,uCAAuC;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,WAAW,CAAC,GAAG,CACb,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,UAAU,IAAI,EAAE,EAAE,CACpE,CACF,CAAC,IAAI,CAAC;IAEP,OAAO,IAAI,gBAAgB,CACzB,GAAG,KAAK,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,kDAAkD,EAC5G;QACE,IAAI,EAAE,sBAAsB;QAC5B,GAAG,EAAE,+DAA+D;QACpE,WAAW,EAAE;YACX,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC5B,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,WAAW,IAAI,EAAE,CAAC;SACrE;KACF,CACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAoC;IAEpC,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IAE/B,OAAO,IAAI,gBAAgB,CACzB,GAAG,KAAK,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,6CAA6C,EAClH;QACE,IAAI,EAAE,mBAAmB;QACzB,GAAG,EAAE,4DAA4D;QACjE,WAAW,EAAE;YACX,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC1B,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC;SAC/D;KACF,CACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAAqC;IAErC,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC;IAEhC,OAAO,IAAI,gBAAgB,CACzB,GAAG,KAAK,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,qDAAqD,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,EAC5I;QACE,IAAI,EAAE,sBAAsB;QAC5B,GAAG,EAAE,+DAA+D;QACpE,WAAW,EAAE;YACX,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC3B,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,WAAW,IAAI,EAAE,CAAC;SACpE;KACF,CACF,CAAC;AACJ,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,KAAc;IAEd,OAAO,IAAI,gBAAgB,CACzB,kBAAkB,IAAI,0BAA0B,EAChD;QACE,IAAI,EAAE,qBAAqB;QAC3B,GAAG,EAAE,+DAA+D;QACpE,KAAK;KACN,CACF,CAAC;AACJ,CAAC"}
@@ -2,4 +2,37 @@ export declare class SkipError extends Error {
2
2
  }
3
3
  export declare class FailError extends Error {
4
4
  }
5
+ /**
6
+ * A cross-endpoint call was answered with a status the description never
7
+ * declares for that operation.
8
+ *
9
+ * `utils.request` answers a union of every **declared** response, so an
10
+ * undeclared one has no member to be. Throwing is what keeps that union
11
+ * truthful: the alternative is a value whose type is a lie, read by a hook that
12
+ * has no branch for it.
13
+ *
14
+ * A plain `Error` rather than a `ThymianBaseError`, deliberately: this class is
15
+ * re-exported from `@thymian/hooks`, whose runtime import graph must stay free
16
+ * of `@thymian/core` so a hook file resolves with nothing installed beside it.
17
+ * The sentence a user reads is composed at the transaction boundary, which is
18
+ * where the remediation lives.
19
+ */
20
+ export declare class UndeclaredResponseError extends Error {
21
+ readonly selector: string;
22
+ readonly statusCode: number;
23
+ readonly headers: Record<string, string | string[] | undefined>;
24
+ readonly body: unknown;
25
+ /**
26
+ * `instanceof` by **shape**, not by identity.
27
+ *
28
+ * The hooks runtime is loaded through jiti, in its own module registry, so a
29
+ * hook file that imports `@thymian/hooks` gets a different evaluation of
30
+ * this module than the runner's — and its own class object. Identity
31
+ * comparison would then be false for the very error the runner threw, which
32
+ * makes the one documented way to react to an off-spec response silently
33
+ * never fire.
34
+ */
35
+ static [Symbol.hasInstance](value: unknown): boolean;
36
+ constructor(selector: string, statusCode: number, headers: Record<string, string | string[] | undefined>, body: unknown);
37
+ }
5
38
  //# sourceMappingURL=hook-errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hook-errors.d.ts","sourceRoot":"","sources":["../../src/hooks/hook-errors.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAEvC,qBAAa,SAAU,SAAQ,KAAK;CAAG"}
1
+ {"version":3,"file":"hook-errors.d.ts","sourceRoot":"","sources":["../../src/hooks/hook-errors.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAEvC,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAEvC;;;;;;;;;;;;;;GAcG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAsB9C,QAAQ,CAAC,QAAQ,EAAE,MAAM;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/D,QAAQ,CAAC,IAAI,EAAE,OAAO;IAxBxB;;;;;;;;;OASG;WACa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;gBAWlD,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,IAAI,EAAE,OAAO;CAQzB"}
@@ -2,4 +2,50 @@ export class SkipError extends Error {
2
2
  }
3
3
  export class FailError extends Error {
4
4
  }
5
+ /**
6
+ * A cross-endpoint call was answered with a status the description never
7
+ * declares for that operation.
8
+ *
9
+ * `utils.request` answers a union of every **declared** response, so an
10
+ * undeclared one has no member to be. Throwing is what keeps that union
11
+ * truthful: the alternative is a value whose type is a lie, read by a hook that
12
+ * has no branch for it.
13
+ *
14
+ * A plain `Error` rather than a `ThymianBaseError`, deliberately: this class is
15
+ * re-exported from `@thymian/hooks`, whose runtime import graph must stay free
16
+ * of `@thymian/core` so a hook file resolves with nothing installed beside it.
17
+ * The sentence a user reads is composed at the transaction boundary, which is
18
+ * where the remediation lives.
19
+ */
20
+ export class UndeclaredResponseError extends Error {
21
+ selector;
22
+ statusCode;
23
+ headers;
24
+ body;
25
+ /**
26
+ * `instanceof` by **shape**, not by identity.
27
+ *
28
+ * The hooks runtime is loaded through jiti, in its own module registry, so a
29
+ * hook file that imports `@thymian/hooks` gets a different evaluation of
30
+ * this module than the runner's — and its own class object. Identity
31
+ * comparison would then be false for the very error the runner threw, which
32
+ * makes the one documented way to react to an off-spec response silently
33
+ * never fire.
34
+ */
35
+ static [Symbol.hasInstance](value) {
36
+ return (typeof value === 'object' &&
37
+ value !== null &&
38
+ value.name === 'UndeclaredResponseError' &&
39
+ 'selector' in value &&
40
+ 'statusCode' in value);
41
+ }
42
+ constructor(selector, statusCode, headers, body) {
43
+ super(`The seed "${selector}" was answered with ${statusCode}, which the specification does not declare for that operation.`);
44
+ this.selector = selector;
45
+ this.statusCode = statusCode;
46
+ this.headers = headers;
47
+ this.body = body;
48
+ this.name = 'UndeclaredResponseError';
49
+ }
50
+ }
5
51
  //# sourceMappingURL=hook-errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hook-errors.js","sourceRoot":"","sources":["../../src/hooks/hook-errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;CAAG;AAEvC,MAAM,OAAO,SAAU,SAAQ,KAAK;CAAG"}
1
+ {"version":3,"file":"hook-errors.js","sourceRoot":"","sources":["../../src/hooks/hook-errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;CAAG;AAEvC,MAAM,OAAO,SAAU,SAAQ,KAAK;CAAG;AAEvC;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAsBrC;IACA;IACA;IACA;IAxBX;;;;;;;;;OASG;IACH,MAAM,CAAU,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAc;QACjD,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,KAAK,IAAI;YACb,KAA4B,CAAC,IAAI,KAAK,yBAAyB;YAChE,UAAU,IAAI,KAAK;YACnB,YAAY,IAAI,KAAK,CACtB,CAAC;IACJ,CAAC;IAED,YACW,QAAgB,EAChB,UAAkB,EAClB,OAAsD,EACtD,IAAa;QAEtB,KAAK,CACH,aAAa,QAAQ,uBAAuB,UAAU,gEAAgE,CACvH,CAAC;QAPO,aAAQ,GAAR,QAAQ,CAAQ;QAChB,eAAU,GAAV,UAAU,CAAQ;QAClB,YAAO,GAAP,OAAO,CAA+C;QACtD,SAAI,GAAJ,IAAI,CAAS;QAMtB,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF"}