pipework 0.211.1 → 0.242.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/REFERENCE.md +95 -2
  3. package/dist/async/jobs/claims.d.ts +1 -1
  4. package/dist/async/jobs/claims.d.ts.map +1 -1
  5. package/dist/async/jobs/claims.js +2 -1
  6. package/dist/async/jobs/claims.js.map +1 -1
  7. package/dist/async/jobs/queue.d.ts +11 -2
  8. package/dist/async/jobs/queue.d.ts.map +1 -1
  9. package/dist/async/jobs/queue.js +93 -25
  10. package/dist/async/jobs/queue.js.map +1 -1
  11. package/dist/async/jobs/table.d.ts +4 -0
  12. package/dist/async/jobs/table.d.ts.map +1 -1
  13. package/dist/async/jobs/table.js +12 -1
  14. package/dist/async/jobs/table.js.map +1 -1
  15. package/dist/cli/commands/openapi.d.ts +8 -0
  16. package/dist/cli/commands/openapi.d.ts.map +1 -0
  17. package/dist/cli/commands/openapi.js +49 -0
  18. package/dist/cli/commands/openapi.js.map +1 -0
  19. package/dist/cli/commands/serve.d.ts +8 -0
  20. package/dist/cli/commands/serve.d.ts.map +1 -1
  21. package/dist/cli/commands/serve.js +22 -3
  22. package/dist/cli/commands/serve.js.map +1 -1
  23. package/dist/cli/dev-bootstrap.js +6 -1
  24. package/dist/cli/dev-bootstrap.js.map +1 -1
  25. package/dist/cli/index.d.ts.map +1 -1
  26. package/dist/cli/index.js +15 -1
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/cli/surface-kinds.d.ts +5 -0
  29. package/dist/cli/surface-kinds.d.ts.map +1 -0
  30. package/dist/cli/surface-kinds.js +15 -0
  31. package/dist/cli/surface-kinds.js.map +1 -0
  32. package/dist/core/config/load.d.ts +1 -0
  33. package/dist/core/config/load.d.ts.map +1 -1
  34. package/dist/core/config/load.js +1 -0
  35. package/dist/core/config/load.js.map +1 -1
  36. package/dist/core/config/namespace.d.ts +6 -0
  37. package/dist/core/config/namespace.d.ts.map +1 -1
  38. package/dist/core/config/schema.d.ts +15 -0
  39. package/dist/core/config/schema.d.ts.map +1 -1
  40. package/dist/core/config/schema.js +11 -2
  41. package/dist/core/config/schema.js.map +1 -1
  42. package/dist/core/lifecycle/health.js +2 -2
  43. package/dist/core/lifecycle/health.js.map +1 -1
  44. package/dist/core/lifecycle/types.d.ts +2 -0
  45. package/dist/core/lifecycle/types.d.ts.map +1 -1
  46. package/dist/core/pipework.d.ts +14 -1
  47. package/dist/core/pipework.d.ts.map +1 -1
  48. package/dist/core/pipework.js +18 -2
  49. package/dist/core/pipework.js.map +1 -1
  50. package/dist/core/surface/http.d.ts +3 -0
  51. package/dist/core/surface/http.d.ts.map +1 -1
  52. package/dist/core/surface/http.js +27 -8
  53. package/dist/core/surface/http.js.map +1 -1
  54. package/dist/core/surface/start.d.ts.map +1 -1
  55. package/dist/core/surface/start.js +19 -3
  56. package/dist/core/surface/start.js.map +1 -1
  57. package/dist/core/surface/types.d.ts +9 -1
  58. package/dist/core/surface/types.d.ts.map +1 -1
  59. package/dist/data/db/filter.d.ts +3 -0
  60. package/dist/data/db/filter.d.ts.map +1 -1
  61. package/dist/data/db/filter.js +3 -0
  62. package/dist/data/db/filter.js.map +1 -1
  63. package/dist/data/db/in-list.d.ts +15 -0
  64. package/dist/data/db/in-list.d.ts.map +1 -0
  65. package/dist/data/db/in-list.js +51 -0
  66. package/dist/data/db/in-list.js.map +1 -0
  67. package/dist/data/db/namespace.d.ts +2 -0
  68. package/dist/data/db/namespace.d.ts.map +1 -1
  69. package/dist/data/db/pool.d.ts +1 -1
  70. package/dist/data/db/pool.d.ts.map +1 -1
  71. package/dist/data/db/pool.js +4 -2
  72. package/dist/data/db/pool.js.map +1 -1
  73. package/dist/data/db/reservation.d.ts +40 -0
  74. package/dist/data/db/reservation.d.ts.map +1 -0
  75. package/dist/data/db/reservation.js +108 -0
  76. package/dist/data/db/reservation.js.map +1 -0
  77. package/dist/data/domain/build-table.js +32 -1
  78. package/dist/data/domain/build-table.js.map +1 -1
  79. package/dist/data/domain/index.d.ts +2 -1
  80. package/dist/data/domain/index.d.ts.map +1 -1
  81. package/dist/data/domain/types.d.ts +9 -1
  82. package/dist/data/domain/types.d.ts.map +1 -1
  83. package/dist/data/domain/types.js.map +1 -1
  84. package/dist/data/migrate/apply.d.ts.map +1 -1
  85. package/dist/data/migrate/apply.js +3 -11
  86. package/dist/data/migrate/apply.js.map +1 -1
  87. package/dist/data/migrate/check.d.ts.map +1 -1
  88. package/dist/data/migrate/check.js +3 -6
  89. package/dist/data/migrate/check.js.map +1 -1
  90. package/dist/data/migrate/diff.d.ts +16 -0
  91. package/dist/data/migrate/diff.d.ts.map +1 -1
  92. package/dist/data/migrate/diff.js +44 -4
  93. package/dist/data/migrate/diff.js.map +1 -1
  94. package/dist/data/migrate/generate.d.ts +1 -1
  95. package/dist/data/migrate/generate.d.ts.map +1 -1
  96. package/dist/data/migrate/generate.js +19 -51
  97. package/dist/data/migrate/generate.js.map +1 -1
  98. package/dist/data/migrate/history.d.ts +36 -0
  99. package/dist/data/migrate/history.d.ts.map +1 -0
  100. package/dist/data/migrate/history.js +185 -0
  101. package/dist/data/migrate/history.js.map +1 -0
  102. package/dist/data/migrate/internal-definitions.d.ts.map +1 -1
  103. package/dist/data/migrate/internal-definitions.js +22 -1
  104. package/dist/data/migrate/internal-definitions.js.map +1 -1
  105. package/dist/data/migrate/provision-framework.d.ts +2 -0
  106. package/dist/data/migrate/provision-framework.d.ts.map +1 -1
  107. package/dist/data/migrate/provision-framework.js +11 -3
  108. package/dist/data/migrate/provision-framework.js.map +1 -1
  109. package/dist/data/migrate/snapshot.d.ts +4 -0
  110. package/dist/data/migrate/snapshot.d.ts.map +1 -1
  111. package/dist/data/migrate/snapshot.js +2 -0
  112. package/dist/data/migrate/snapshot.js.map +1 -1
  113. package/dist/data/migrate/sql-emit.js +66 -12
  114. package/dist/data/migrate/sql-emit.js.map +1 -1
  115. package/dist/data/query/pg-core/foreign-keys.d.ts +5 -0
  116. package/dist/data/query/pg-core/foreign-keys.d.ts.map +1 -1
  117. package/dist/data/query/pg-core/foreign-keys.js +9 -0
  118. package/dist/data/query/pg-core/foreign-keys.js.map +1 -1
  119. package/dist/data/query/pg-core/indexes.d.ts +5 -0
  120. package/dist/data/query/pg-core/indexes.d.ts.map +1 -1
  121. package/dist/data/query/pg-core/indexes.js +7 -0
  122. package/dist/data/query/pg-core/indexes.js.map +1 -1
  123. package/dist/data/schema/json-schema.js +29 -1
  124. package/dist/data/schema/json-schema.js.map +1 -1
  125. package/dist/data/schema/types.d.ts +2 -2
  126. package/dist/data/schema/types.d.ts.map +1 -1
  127. package/dist/index.d.ts +18 -9
  128. package/dist/index.d.ts.map +1 -1
  129. package/dist/index.js +5 -1
  130. package/dist/index.js.map +1 -1
  131. package/dist/infra/alerts/handle.d.ts +33 -5
  132. package/dist/infra/alerts/handle.d.ts.map +1 -1
  133. package/dist/infra/alerts/handle.js +56 -12
  134. package/dist/infra/alerts/handle.js.map +1 -1
  135. package/dist/infra/alerts/http.d.ts +2 -2
  136. package/dist/infra/alerts/http.d.ts.map +1 -1
  137. package/dist/infra/alerts/http.js +21 -3
  138. package/dist/infra/alerts/http.js.map +1 -1
  139. package/dist/infra/alerts/index.d.ts +1 -1
  140. package/dist/infra/alerts/index.d.ts.map +1 -1
  141. package/dist/infra/alerts/schema.d.ts +5 -0
  142. package/dist/infra/alerts/schema.d.ts.map +1 -1
  143. package/dist/infra/alerts/schema.js +1 -0
  144. package/dist/infra/alerts/schema.js.map +1 -1
  145. package/dist/infra/crawl/audit.d.ts +6 -0
  146. package/dist/infra/crawl/audit.d.ts.map +1 -0
  147. package/dist/infra/crawl/audit.js +38 -0
  148. package/dist/infra/crawl/audit.js.map +1 -0
  149. package/dist/infra/crawl/errors.d.ts +14 -0
  150. package/dist/infra/crawl/errors.d.ts.map +1 -0
  151. package/dist/infra/crawl/errors.js +22 -0
  152. package/dist/infra/crawl/errors.js.map +1 -0
  153. package/dist/infra/crawl/handle.d.ts +149 -0
  154. package/dist/infra/crawl/handle.d.ts.map +1 -0
  155. package/dist/infra/crawl/handle.js +550 -0
  156. package/dist/infra/crawl/handle.js.map +1 -0
  157. package/dist/infra/crawl/index.d.ts +7 -0
  158. package/dist/infra/crawl/index.d.ts.map +1 -0
  159. package/dist/infra/crawl/index.js +5 -0
  160. package/dist/infra/crawl/index.js.map +1 -0
  161. package/dist/infra/crawl/links.d.ts +9 -0
  162. package/dist/infra/crawl/links.d.ts.map +1 -0
  163. package/dist/infra/crawl/links.js +194 -0
  164. package/dist/infra/crawl/links.js.map +1 -0
  165. package/dist/infra/crawl/namespace.d.ts +36 -0
  166. package/dist/infra/crawl/namespace.d.ts.map +1 -0
  167. package/dist/infra/crawl/namespace.js +36 -0
  168. package/dist/infra/crawl/namespace.js.map +1 -0
  169. package/dist/infra/crawl/robots.d.ts +16 -0
  170. package/dist/infra/crawl/robots.d.ts.map +1 -0
  171. package/dist/infra/crawl/robots.js +98 -0
  172. package/dist/infra/crawl/robots.js.map +1 -0
  173. package/dist/infra/crawl/schema.d.ts +222 -0
  174. package/dist/infra/crawl/schema.d.ts.map +1 -0
  175. package/dist/infra/crawl/schema.js +84 -0
  176. package/dist/infra/crawl/schema.js.map +1 -0
  177. package/dist/infra/credit-line/handle.d.ts +250 -0
  178. package/dist/infra/credit-line/handle.d.ts.map +1 -0
  179. package/dist/infra/credit-line/handle.js +618 -0
  180. package/dist/infra/credit-line/handle.js.map +1 -0
  181. package/dist/infra/credit-line/index.d.ts +3 -0
  182. package/dist/infra/credit-line/index.d.ts.map +1 -0
  183. package/dist/infra/credit-line/index.js +2 -0
  184. package/dist/infra/credit-line/index.js.map +1 -0
  185. package/dist/infra/credit-line/namespace.d.ts +7 -0
  186. package/dist/infra/credit-line/namespace.d.ts.map +1 -0
  187. package/dist/infra/credit-line/namespace.js +7 -0
  188. package/dist/infra/credit-line/namespace.js.map +1 -0
  189. package/dist/infra/credit-line/schema.d.ts +194 -0
  190. package/dist/infra/credit-line/schema.d.ts.map +1 -0
  191. package/dist/infra/credit-line/schema.js +89 -0
  192. package/dist/infra/credit-line/schema.js.map +1 -0
  193. package/dist/infra/email/inbound.d.ts +14 -2
  194. package/dist/infra/email/inbound.d.ts.map +1 -1
  195. package/dist/infra/email/inbound.js +5 -1
  196. package/dist/infra/email/inbound.js.map +1 -1
  197. package/dist/infra/email/index.d.ts +2 -2
  198. package/dist/infra/email/index.d.ts.map +1 -1
  199. package/dist/infra/email/index.js.map +1 -1
  200. package/dist/infra/email/mail.d.ts +43 -5
  201. package/dist/infra/email/mail.d.ts.map +1 -1
  202. package/dist/infra/email/mail.js +124 -9
  203. package/dist/infra/email/mail.js.map +1 -1
  204. package/dist/infra/email/mime.d.ts +6 -0
  205. package/dist/infra/email/mime.d.ts.map +1 -1
  206. package/dist/infra/email/mime.js +10 -2
  207. package/dist/infra/email/mime.js.map +1 -1
  208. package/dist/infra/email/schema.d.ts +17 -3
  209. package/dist/infra/email/schema.d.ts.map +1 -1
  210. package/dist/infra/email/schema.js +15 -4
  211. package/dist/infra/email/schema.js.map +1 -1
  212. package/dist/infra/email/sns.js +2 -2
  213. package/dist/infra/email/sns.js.map +1 -1
  214. package/dist/infra/email/unsubscribe.d.ts +13 -0
  215. package/dist/infra/email/unsubscribe.d.ts.map +1 -0
  216. package/dist/infra/email/unsubscribe.js +43 -0
  217. package/dist/infra/email/unsubscribe.js.map +1 -0
  218. package/dist/infra/fetch/handle.d.ts +20 -1
  219. package/dist/infra/fetch/handle.d.ts.map +1 -1
  220. package/dist/infra/fetch/handle.js +60 -28
  221. package/dist/infra/fetch/handle.js.map +1 -1
  222. package/dist/infra/fetch/index.d.ts +2 -2
  223. package/dist/infra/fetch/index.d.ts.map +1 -1
  224. package/dist/infra/fetch/index.js +1 -1
  225. package/dist/infra/fetch/index.js.map +1 -1
  226. package/dist/infra/fetch/namespace.d.ts +20 -2
  227. package/dist/infra/fetch/namespace.d.ts.map +1 -1
  228. package/dist/infra/fetch/namespace.js +20 -2
  229. package/dist/infra/fetch/namespace.js.map +1 -1
  230. package/dist/infra/join-requests/handle.d.ts +86 -0
  231. package/dist/infra/join-requests/handle.d.ts.map +1 -0
  232. package/dist/infra/join-requests/handle.js +233 -0
  233. package/dist/infra/join-requests/handle.js.map +1 -0
  234. package/dist/infra/join-requests/index.d.ts +3 -0
  235. package/dist/infra/join-requests/index.d.ts.map +1 -0
  236. package/dist/infra/join-requests/index.js +2 -0
  237. package/dist/infra/join-requests/index.js.map +1 -0
  238. package/dist/infra/join-requests/namespace.d.ts +7 -0
  239. package/dist/infra/join-requests/namespace.d.ts.map +1 -0
  240. package/dist/infra/join-requests/namespace.js +7 -0
  241. package/dist/infra/join-requests/namespace.js.map +1 -0
  242. package/dist/infra/join-requests/schema.d.ts +58 -0
  243. package/dist/infra/join-requests/schema.d.ts.map +1 -0
  244. package/dist/infra/join-requests/schema.js +31 -0
  245. package/dist/infra/join-requests/schema.js.map +1 -0
  246. package/dist/infra/outbox/core.d.ts +9 -0
  247. package/dist/infra/outbox/core.d.ts.map +1 -1
  248. package/dist/infra/outbox/core.js +14 -0
  249. package/dist/infra/outbox/core.js.map +1 -1
  250. package/dist/infra/support/handle.d.ts +43 -0
  251. package/dist/infra/support/handle.d.ts.map +1 -1
  252. package/dist/infra/support/handle.js +35 -7
  253. package/dist/infra/support/handle.js.map +1 -1
  254. package/dist/infra/support/http.d.ts +28 -0
  255. package/dist/infra/support/http.d.ts.map +1 -0
  256. package/dist/infra/support/http.js +217 -0
  257. package/dist/infra/support/http.js.map +1 -0
  258. package/dist/infra/support/index.d.ts +2 -0
  259. package/dist/infra/support/index.d.ts.map +1 -1
  260. package/dist/infra/support/index.js +1 -0
  261. package/dist/infra/support/index.js.map +1 -1
  262. package/dist/infra/support/namespace.d.ts +3 -0
  263. package/dist/infra/support/namespace.d.ts.map +1 -1
  264. package/dist/infra/support/namespace.js +3 -0
  265. package/dist/infra/support/namespace.js.map +1 -1
  266. package/dist/infra/support/schema.d.ts +4 -4
  267. package/dist/infra/webhook/outbound.d.ts +16 -0
  268. package/dist/infra/webhook/outbound.d.ts.map +1 -1
  269. package/dist/infra/webhook/outbound.js +78 -27
  270. package/dist/infra/webhook/outbound.js.map +1 -1
  271. package/dist/request/di/builder.d.ts +24 -1
  272. package/dist/request/di/builder.d.ts.map +1 -1
  273. package/dist/request/di/builder.js +35 -0
  274. package/dist/request/di/builder.js.map +1 -1
  275. package/dist/request/di/types.d.ts +30 -0
  276. package/dist/request/di/types.d.ts.map +1 -1
  277. package/dist/request/http/server.d.ts.map +1 -1
  278. package/dist/request/http/server.js +111 -20
  279. package/dist/request/http/server.js.map +1 -1
  280. package/dist/test/auto-setup.js +2 -2
  281. package/dist/test/auto-setup.js.map +1 -1
  282. package/dist/test/crawl-fixture.d.ts +53 -0
  283. package/dist/test/crawl-fixture.d.ts.map +1 -0
  284. package/dist/test/crawl-fixture.js +130 -0
  285. package/dist/test/crawl-fixture.js.map +1 -0
  286. package/dist/test/index.d.ts +2 -1
  287. package/dist/test/index.d.ts.map +1 -1
  288. package/dist/test/index.js +2 -1
  289. package/dist/test/index.js.map +1 -1
  290. package/dist/test/progress.d.ts +7 -1
  291. package/dist/test/progress.d.ts.map +1 -1
  292. package/dist/test/progress.js +6 -0
  293. package/dist/test/progress.js.map +1 -1
  294. package/dist/test/reap-after-run.d.ts +3 -0
  295. package/dist/test/reap-after-run.d.ts.map +1 -0
  296. package/dist/test/reap-after-run.js +29 -0
  297. package/dist/test/reap-after-run.js.map +1 -0
  298. package/dist/test/reap.d.ts +11 -2
  299. package/dist/test/reap.d.ts.map +1 -1
  300. package/dist/test/reap.js +19 -12
  301. package/dist/test/reap.js.map +1 -1
  302. package/dist/test/setup.d.ts +2 -0
  303. package/dist/test/setup.d.ts.map +1 -1
  304. package/dist/test/setup.js +87 -30
  305. package/dist/test/setup.js.map +1 -1
  306. package/dist/test/vitest-plugin.d.ts.map +1 -1
  307. package/dist/test/vitest-plugin.js +8 -1
  308. package/dist/test/vitest-plugin.js.map +1 -1
  309. package/dist/test/vitest-workspace.d.ts +1 -0
  310. package/dist/test/vitest-workspace.d.ts.map +1 -1
  311. package/dist/test/vitest-workspace.js +1 -1
  312. package/dist/test/vitest-workspace.js.map +1 -1
  313. package/dist/test/vitest.d.ts +20 -0
  314. package/dist/test/vitest.d.ts.map +1 -1
  315. package/dist/test/vitest.js +41 -1
  316. package/dist/test/vitest.js.map +1 -1
  317. package/dist/trace/partition/sync.d.ts +8 -2
  318. package/dist/trace/partition/sync.d.ts.map +1 -1
  319. package/dist/trace/partition/sync.js +6 -3
  320. package/dist/trace/partition/sync.js.map +1 -1
  321. package/dist/workspace/generate.d.ts.map +1 -1
  322. package/dist/workspace/generate.js +1 -0
  323. package/dist/workspace/generate.js.map +1 -1
  324. package/package.json +1 -1
@@ -0,0 +1,9 @@
1
+ /** Decodes `&` `"` `'` `<` `>` `&#NN;` and `&#xNN;`; anything else is left as written. */
2
+ export declare function decodeEntities(value: string): string;
3
+ /**
4
+ * The http(s) URLs `html` links to, resolved against `pageUrl` (or the page's first `<base href>`), without fragments,
5
+ * each once, in document order. Reads `href` of `a`, `area` and `link`, and `src` of `iframe` and `frame`; skips comments
6
+ * and the bodies of `script`, `style` and `template`.
7
+ */
8
+ export declare function extractLinks(html: string, pageUrl: string): string[];
9
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../../src/infra/crawl/links.ts"],"names":[],"mappings":"AASA,8GAA8G;AAC9G,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA+BpD;AA4DD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAqDpE"}
@@ -0,0 +1,194 @@
1
+ // Link extraction from untrusted HTML: a single forward scan, no DOM, nothing executed, no backtracking patterns.
2
+ // The caller bounds the input size; the scan is linear in it apart from the search for a raw-text element's end.
3
+ const RAW_TEXT = new Set(['script', 'style', 'template']);
4
+ const HREF_TAGS = new Set(['a', 'area', 'link']);
5
+ const SRC_TAGS = new Set(['iframe', 'frame']);
6
+ const NAMED = { amp: '&', quot: '"', apos: "'", lt: '<', gt: '>' };
7
+ /** Decodes `&amp;` `&quot;` `&apos;` `&lt;` `&gt;` `&#NN;` and `&#xNN;`; anything else is left as written. */
8
+ export function decodeEntities(value) {
9
+ let at = value.indexOf('&');
10
+ if (at === -1)
11
+ return value;
12
+ let out = '';
13
+ let from = 0;
14
+ while (at !== -1) {
15
+ const semi = value.indexOf(';', at + 1);
16
+ let replaced = null;
17
+ if (semi !== -1 && semi - at <= 10) {
18
+ const body = value.slice(at + 1, semi);
19
+ if (body[0] === '#') {
20
+ const hex = body[1] === 'x' || body[1] === 'X';
21
+ const digits = body.slice(hex ? 2 : 1);
22
+ if (digits !== '' && (hex ? /^[0-9a-fA-F]+$/ : /^[0-9]+$/).test(digits)) {
23
+ const code = parseInt(digits, hex ? 16 : 10);
24
+ if (code > 0 && code <= 0x10ffff && !(code >= 0xd800 && code <= 0xdfff))
25
+ replaced = String.fromCodePoint(code);
26
+ }
27
+ }
28
+ else {
29
+ replaced = NAMED[body] ?? null;
30
+ }
31
+ }
32
+ if (replaced === null) {
33
+ out += value.slice(from, at + 1);
34
+ from = at + 1;
35
+ }
36
+ else {
37
+ out += value.slice(from, at) + replaced;
38
+ from = semi + 1;
39
+ }
40
+ at = value.indexOf('&', from);
41
+ }
42
+ return out + value.slice(from);
43
+ }
44
+ function isSpace(c) {
45
+ return c === ' ' || c === '\t' || c === '\n' || c === '\r' || c === '\f';
46
+ }
47
+ /** Index of `needle` (lower-case) in `html` at or after `from`, ignoring the case of `html`; -1 when absent. */
48
+ function indexOfIgnoreCase(html, needle, from) {
49
+ const first = needle.charCodeAt(0);
50
+ const firstUpper = needle.toUpperCase().charCodeAt(0);
51
+ const last = html.length - needle.length;
52
+ for (let i = from; i <= last; i++) {
53
+ const c = html.charCodeAt(i);
54
+ if (c !== first && c !== firstUpper)
55
+ continue;
56
+ if (html.slice(i, i + needle.length).toLowerCase() === needle)
57
+ return i;
58
+ }
59
+ return -1;
60
+ }
61
+ /** Reads a start tag whose `<` is at `start`; `end` is the index after its `>`; `closed` is false when the input ended first. */
62
+ function readTag(html, start) {
63
+ let i = start + 1;
64
+ const n = html.length;
65
+ const nameStart = i;
66
+ if (!/[A-Za-z]/.test(html[i] ?? ''))
67
+ return null;
68
+ while (i < n && /[A-Za-z0-9:-]/.test(html[i]))
69
+ i++;
70
+ if (i === nameStart)
71
+ return null;
72
+ const name = html.slice(nameStart, i).toLowerCase();
73
+ const attrs = new Map();
74
+ while (i < n) {
75
+ while (i < n && (isSpace(html[i]) || html[i] === '/'))
76
+ i++;
77
+ if (i >= n)
78
+ break;
79
+ if (html[i] === '>') {
80
+ i++;
81
+ return { name, attrs, end: i, closed: true };
82
+ }
83
+ const attrStart = i;
84
+ while (i < n && !isSpace(html[i]) && html[i] !== '=' && html[i] !== '>' && html[i] !== '/')
85
+ i++;
86
+ const attr = html.slice(attrStart, i).toLowerCase();
87
+ while (i < n && isSpace(html[i]))
88
+ i++;
89
+ let value = '';
90
+ if (html[i] === '=') {
91
+ i++;
92
+ while (i < n && isSpace(html[i]))
93
+ i++;
94
+ const q = html[i];
95
+ if (q === '"' || q === "'") {
96
+ const close = html.indexOf(q, i + 1);
97
+ const stop = close === -1 ? n : close;
98
+ value = html.slice(i + 1, stop);
99
+ i = close === -1 ? n : close + 1;
100
+ }
101
+ else {
102
+ const valueStart = i;
103
+ while (i < n && !isSpace(html[i]) && html[i] !== '>')
104
+ i++;
105
+ value = html.slice(valueStart, i);
106
+ }
107
+ }
108
+ if (attr !== '' && !attrs.has(attr))
109
+ attrs.set(attr, decodeEntities(value));
110
+ }
111
+ return { name, attrs, end: n, closed: false };
112
+ }
113
+ /**
114
+ * The http(s) URLs `html` links to, resolved against `pageUrl` (or the page's first `<base href>`), without fragments,
115
+ * each once, in document order. Reads `href` of `a`, `area` and `link`, and `src` of `iframe` and `frame`; skips comments
116
+ * and the bodies of `script`, `style` and `template`.
117
+ */
118
+ export function extractLinks(html, pageUrl) {
119
+ const raw = [];
120
+ let baseHref = null;
121
+ const n = html.length;
122
+ let i = 0;
123
+ while (i < n) {
124
+ const lt = html.indexOf('<', i);
125
+ if (lt === -1)
126
+ break;
127
+ if (html.startsWith('<!--', lt)) {
128
+ const close = html.indexOf('-->', lt + 4);
129
+ i = close === -1 ? n : close + 3;
130
+ continue;
131
+ }
132
+ const next = html[lt + 1];
133
+ if (next === '!' || next === '?' || next === '/') {
134
+ const close = html.indexOf('>', lt + 2);
135
+ i = close === -1 ? n : close + 1;
136
+ continue;
137
+ }
138
+ const tag = readTag(html, lt);
139
+ if (tag === null) {
140
+ i = lt + 1;
141
+ continue;
142
+ }
143
+ i = tag.end;
144
+ if (!tag.closed)
145
+ break;
146
+ if (RAW_TEXT.has(tag.name)) {
147
+ const close = indexOfIgnoreCase(html, `</${tag.name}`, i);
148
+ i = close === -1 ? n : close;
149
+ continue;
150
+ }
151
+ if (tag.name === 'base') {
152
+ const href = tag.attrs.get('href');
153
+ if (baseHref === null && href !== undefined)
154
+ baseHref = href;
155
+ }
156
+ else if (HREF_TAGS.has(tag.name)) {
157
+ const href = tag.attrs.get('href');
158
+ if (href !== undefined)
159
+ raw.push(href);
160
+ }
161
+ else if (SRC_TAGS.has(tag.name)) {
162
+ const src = tag.attrs.get('src');
163
+ if (src !== undefined)
164
+ raw.push(src);
165
+ }
166
+ }
167
+ let base = pageUrl;
168
+ if (baseHref !== null) {
169
+ try {
170
+ base = new URL(baseHref.trim(), pageUrl).href;
171
+ }
172
+ catch { /* an unusable base is ignored */ }
173
+ }
174
+ const seen = new Set();
175
+ const out = [];
176
+ for (const value of raw) {
177
+ let url;
178
+ try {
179
+ url = new URL(value.trim(), base);
180
+ }
181
+ catch {
182
+ continue;
183
+ }
184
+ if (url.protocol !== 'http:' && url.protocol !== 'https:')
185
+ continue;
186
+ url.hash = '';
187
+ if (!seen.has(url.href)) {
188
+ seen.add(url.href);
189
+ out.push(url.href);
190
+ }
191
+ }
192
+ return out;
193
+ }
194
+ //# sourceMappingURL=links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.js","sourceRoot":"","sources":["../../../src/infra/crawl/links.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { createCrawl } from './handle.js';
2
+ /** Crawl — a polite, sandboxed site crawler that runs as a durable job. */
3
+ export declare const crawl: {
4
+ /**
5
+ * Creates a site crawler at boot and returns its handle: `job` (add to a worker surface's `jobs`), `start`, `approve`,
6
+ * `status`, `resources` and `refusals`. Throws `CrawlNotEnabledError` when the Blueprint has no `crawl` block.
7
+ *
8
+ * ```ts
9
+ * const gov = crawl.create({ instance, name: 'gov', queue, userAgent: 'VerityBot/1.0 (+https://verity.example/bot)',
10
+ * accept: ({ contentType }) => contentType === 'application/pdf' })
11
+ * const { id } = await gov.start({ seed: 'https://www.example.gov.uk/', scope: { domain: 'example.gov.uk' } })
12
+ * ```
13
+ *
14
+ * Every request goes through `untrustedFetch.get`: http(s) only, public addresses only (checked at connect), a byte
15
+ * limit and a time limit per request, one trace step `pipework/fetch:get` each. robots.txt is read once per host before any
16
+ * other request to it and obeyed (RFC 9309: the group for the User-Agent's product token, longest match, `Crawl-delay`;
17
+ * 4xx allows everything; 5xx or no answer disallows, retried three times, then the crawl stops with `stoppedBy: 'robots_unreachable'`).
18
+ * Requests to a host are `perHostConcurrency` (default 1) at a time and at least the larger of `minGapMs` (default 1000) and
19
+ * `Crawl-delay` apart. A redirect is not followed inside a request: its target is queued like a link, so it meets scope,
20
+ * robots and the gap; a target outside the scope is refused as `scope`.
21
+ *
22
+ * `accept({ url, contentType })` says which resources are listed; in-scope html is followed for links (read by a scanner that
23
+ * runs nothing); anything that is neither html nor accepted is refused before its body is read. A crawl that reaches a limit
24
+ * (`maxPages`, `maxDepth`, `maxBytes`, `maxWallMs`) ends `stopped` with `stoppedBy` naming it.
25
+ *
26
+ * State is in the database. The job claims queued URLs one at a time and records each URL's outcome, its links and its
27
+ * listed resource in one transaction, so a job that dies is retried by the queue and carries on from the queued rows. A URL
28
+ * finished before the death is never fetched again; the one in flight at the death may be. A later crawl of the same seed
29
+ * sends `If-None-Match` / `If-Modified-Since` for the resources the earlier one listed and records a 304 as `unchanged`.
30
+ *
31
+ * With `crawl: { requireApproval: true }` in the Blueprint, `start` records the crawl as `awaiting_approval` and queues nothing
32
+ * until `approve(id)`. `start` and `approve` each write one `Crawl` audit record.
33
+ */
34
+ readonly create: typeof createCrawl;
35
+ };
36
+ //# sourceMappingURL=namespace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/infra/crawl/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,2EAA2E;AAC3E,eAAO,MAAM,KAAK;IAChB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;;CAEK,CAAA"}
@@ -0,0 +1,36 @@
1
+ import { createCrawl } from './handle.js';
2
+ /** Crawl — a polite, sandboxed site crawler that runs as a durable job. */
3
+ export const crawl = {
4
+ /**
5
+ * Creates a site crawler at boot and returns its handle: `job` (add to a worker surface's `jobs`), `start`, `approve`,
6
+ * `status`, `resources` and `refusals`. Throws `CrawlNotEnabledError` when the Blueprint has no `crawl` block.
7
+ *
8
+ * ```ts
9
+ * const gov = crawl.create({ instance, name: 'gov', queue, userAgent: 'VerityBot/1.0 (+https://verity.example/bot)',
10
+ * accept: ({ contentType }) => contentType === 'application/pdf' })
11
+ * const { id } = await gov.start({ seed: 'https://www.example.gov.uk/', scope: { domain: 'example.gov.uk' } })
12
+ * ```
13
+ *
14
+ * Every request goes through `untrustedFetch.get`: http(s) only, public addresses only (checked at connect), a byte
15
+ * limit and a time limit per request, one trace step `pipework/fetch:get` each. robots.txt is read once per host before any
16
+ * other request to it and obeyed (RFC 9309: the group for the User-Agent's product token, longest match, `Crawl-delay`;
17
+ * 4xx allows everything; 5xx or no answer disallows, retried three times, then the crawl stops with `stoppedBy: 'robots_unreachable'`).
18
+ * Requests to a host are `perHostConcurrency` (default 1) at a time and at least the larger of `minGapMs` (default 1000) and
19
+ * `Crawl-delay` apart. A redirect is not followed inside a request: its target is queued like a link, so it meets scope,
20
+ * robots and the gap; a target outside the scope is refused as `scope`.
21
+ *
22
+ * `accept({ url, contentType })` says which resources are listed; in-scope html is followed for links (read by a scanner that
23
+ * runs nothing); anything that is neither html nor accepted is refused before its body is read. A crawl that reaches a limit
24
+ * (`maxPages`, `maxDepth`, `maxBytes`, `maxWallMs`) ends `stopped` with `stoppedBy` naming it.
25
+ *
26
+ * State is in the database. The job claims queued URLs one at a time and records each URL's outcome, its links and its
27
+ * listed resource in one transaction, so a job that dies is retried by the queue and carries on from the queued rows. A URL
28
+ * finished before the death is never fetched again; the one in flight at the death may be. A later crawl of the same seed
29
+ * sends `If-None-Match` / `If-Modified-Since` for the resources the earlier one listed and records a 304 as `unchanged`.
30
+ *
31
+ * With `crawl: { requireApproval: true }` in the Blueprint, `start` records the crawl as `awaiting_approval` and queues nothing
32
+ * until `approve(id)`. `start` and `approve` each write one `Crawl` audit record.
33
+ */
34
+ create: createCrawl,
35
+ };
36
+ //# sourceMappingURL=namespace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/infra/crawl/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,MAAM,EAAE,WAAW;CACX,CAAA"}
@@ -0,0 +1,16 @@
1
+ /** What a robots.txt says to one crawler. */
2
+ export interface RobotsRules {
3
+ /** Whether the crawler may fetch this path and query (`/a/b?x=1`). */
4
+ allows(pathAndQuery: string): boolean;
5
+ /** Seconds the matched group asks between requests; null when it names none. */
6
+ readonly crawlDelaySeconds: number | null;
7
+ }
8
+ /** Every path is allowed (what a 4xx answer means). */
9
+ export declare const ALLOW_ALL: RobotsRules;
10
+ /** No path is allowed (what an unreachable robots.txt means). */
11
+ export declare const DISALLOW_ALL: RobotsRules;
12
+ /** The product token of a User-Agent: its leading letters, `-` and `_` (`VerityBot/1.2 (+url)` is `VerityBot`), lower-case. */
13
+ export declare function productToken(userAgent: string): string;
14
+ /** Reads robots.txt `text` for the crawler named by `userAgent`: the groups naming its product token, else the `*` groups. */
15
+ export declare function parseRobots(text: string, userAgent: string): RobotsRules;
16
+ //# sourceMappingURL=robots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../../../src/infra/crawl/robots.ts"],"names":[],"mappings":"AAGA,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAA;IACrC,gFAAgF;IAChF,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1C;AAID,uDAAuD;AACvD,eAAO,MAAM,SAAS,EAAE,WAA6D,CAAA;AACrF,iEAAiE;AACjE,eAAO,MAAM,YAAY,EAAE,WAA8D,CAAA;AAEzF,+HAA+H;AAC/H,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAItD;AAsDD,8HAA8H;AAC9H,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,CAqBxE"}
@@ -0,0 +1,98 @@
1
+ // robots.txt per RFC 9309: groups by user agent, longest-match Allow/Disallow with `*` and `$`, Allow wins a tie,
2
+ // Crawl-delay from the matched group. Pure: the text in, a decision function out.
3
+ /** Every path is allowed (what a 4xx answer means). */
4
+ export const ALLOW_ALL = { allows: () => true, crawlDelaySeconds: null };
5
+ /** No path is allowed (what an unreachable robots.txt means). */
6
+ export const DISALLOW_ALL = { allows: () => false, crawlDelaySeconds: null };
7
+ /** The product token of a User-Agent: its leading letters, `-` and `_` (`VerityBot/1.2 (+url)` is `VerityBot`), lower-case. */
8
+ export function productToken(userAgent) {
9
+ let end = 0;
10
+ while (end < userAgent.length && /[A-Za-z_-]/.test(userAgent[end]))
11
+ end++;
12
+ return userAgent.slice(0, end).toLowerCase();
13
+ }
14
+ function parseGroups(text) {
15
+ const groups = [];
16
+ let current = null;
17
+ let inAgents = false;
18
+ const lines = text.replace(/^/, '').split(/\r\n|\r|\n/);
19
+ for (const raw of lines) {
20
+ const hash = raw.indexOf('#');
21
+ const line = (hash === -1 ? raw : raw.slice(0, hash)).trim();
22
+ const colon = line.indexOf(':');
23
+ if (colon === -1)
24
+ continue;
25
+ const name = line.slice(0, colon).trim().toLowerCase();
26
+ const value = line.slice(colon + 1).trim();
27
+ if (name === 'user-agent') {
28
+ if (current === null || !inAgents) {
29
+ current = { agents: [], rules: [], delay: null };
30
+ groups.push(current);
31
+ }
32
+ current.agents.push(value.toLowerCase());
33
+ inAgents = true;
34
+ continue;
35
+ }
36
+ inAgents = false;
37
+ if (current === null)
38
+ continue;
39
+ if (name === 'allow' || name === 'disallow') {
40
+ if (value !== '')
41
+ current.rules.push({ allow: name === 'allow', pattern: value });
42
+ }
43
+ else if (name === 'crawl-delay') {
44
+ const n = Number(value);
45
+ if (Number.isFinite(n) && n >= 0 && current.delay === null)
46
+ current.delay = n;
47
+ }
48
+ }
49
+ return groups;
50
+ }
51
+ /** Whether `pattern` (with `*` wildcards and an optional trailing `$`) matches the start of `path`; linear in the sizes. */
52
+ function patternMatches(pattern, path) {
53
+ const anchored = pattern.endsWith('$');
54
+ const body = anchored ? pattern.slice(0, -1) : pattern;
55
+ const parts = body.split('*');
56
+ const first = parts[0];
57
+ if (!path.startsWith(first))
58
+ return false;
59
+ let pos = first.length;
60
+ if (parts.length === 1)
61
+ return anchored ? pos === path.length : true;
62
+ for (let i = 1; i < parts.length - 1; i++) {
63
+ const found = path.indexOf(parts[i], pos);
64
+ if (found === -1)
65
+ return false;
66
+ pos = found + parts[i].length;
67
+ }
68
+ const last = parts[parts.length - 1];
69
+ if (!anchored)
70
+ return path.indexOf(last, pos) !== -1;
71
+ return path.length - last.length >= pos && path.endsWith(last);
72
+ }
73
+ /** Reads robots.txt `text` for the crawler named by `userAgent`: the groups naming its product token, else the `*` groups. */
74
+ export function parseRobots(text, userAgent) {
75
+ const groups = parseGroups(text);
76
+ const token = productToken(userAgent);
77
+ let matched = groups.filter(g => token !== '' && g.agents.includes(token));
78
+ if (matched.length === 0)
79
+ matched = groups.filter(g => g.agents.includes('*'));
80
+ const rules = matched.flatMap(g => g.rules);
81
+ const delay = matched.map(g => g.delay).find(d => d !== null) ?? null;
82
+ return {
83
+ crawlDelaySeconds: delay,
84
+ allows(pathAndQuery) {
85
+ let best = null;
86
+ for (const rule of rules) {
87
+ if (!patternMatches(rule.pattern, pathAndQuery))
88
+ continue;
89
+ const length = rule.pattern.length;
90
+ if (best === null || length > best.length || (length === best.length && rule.allow && !best.allow)) {
91
+ best = { allow: rule.allow, length };
92
+ }
93
+ }
94
+ return best === null ? true : best.allow;
95
+ },
96
+ };
97
+ }
98
+ //# sourceMappingURL=robots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"robots.js","sourceRoot":"","sources":["../../../src/infra/crawl/robots.ts"],"names":[],"mappings":"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"}