clearotron 0.2.1 → 0.2.3

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 (676) hide show
  1. package/.env.example +82 -1
  2. package/.nvmrc +1 -1
  3. package/CONTRIBUTING.md +3 -3
  4. package/INSTALL.md +64 -58
  5. package/README.md +11 -16
  6. package/THIRD-PARTY-NOTICES.md +1 -1
  7. package/bin/brandowner.mjs +1 -1
  8. package/bin/clearotron.mjs +26 -4
  9. package/bin/connect.mjs +2 -2
  10. package/bin/example.mjs +31 -11
  11. package/bin/grant.mjs +3 -3
  12. package/bin/key.mjs +1 -1
  13. package/bin/onboard.mjs +252 -136
  14. package/bin/start.mjs +176 -33
  15. package/bin/stop.mjs +65 -3
  16. package/bin/update.mjs +7 -7
  17. package/bin/uspto-sync.mjs +1 -1
  18. package/build-info.json +2 -2
  19. package/demo/full-country-search/run/_driver/framework.json +1 -1
  20. package/demo/global-preliminary-search/run/_driver/framework.json +1 -1
  21. package/demo/knockout-search/run/_driver/framework.json +1 -1
  22. package/demo/multi-country-focus-search/run/_driver/framework.json +1 -1
  23. package/docs/DELIVERY.md +6 -2
  24. package/docs/E2E.md +5 -5
  25. package/docs/PORTAL.md +2 -2
  26. package/docs/README.md +5 -4
  27. package/docs/SECURITY.md +17 -0
  28. package/docs/architecture/01-product-overview.md +2 -2
  29. package/docs/architecture/02-architecture.md +2 -2
  30. package/docs/architecture/04-configuration-reference.md +8 -3
  31. package/docs/architecture/05-config-governance.md +52 -5
  32. package/docs/architecture/05-customer-profiles.md +2 -2
  33. package/docs/architecture/06-operations-runbook.md +13 -1
  34. package/docs/architecture/09-security-and-data.md +1 -1
  35. package/docs/configuration.md +4 -3
  36. package/docs/decisions/0004-documentation-structure.md +1 -1
  37. package/driver/CHANGELOG.md +121 -1
  38. package/driver/README.md +2 -2
  39. package/driver/ask-ledger.mjs +3 -3
  40. package/driver/authority-trees.mjs +1 -1
  41. package/driver/call-capture.mjs +1 -1
  42. package/driver/card-frame.mjs +1 -1
  43. package/driver/case-law-ledger.mjs +1 -1
  44. package/driver/claim-liveness.mjs +1 -1
  45. package/driver/common-law-receipts.mjs +2 -2
  46. package/driver/commonlaw-carry.mjs +1 -1
  47. package/driver/config-inventory.mjs +1 -1
  48. package/driver/config-staleness.mjs +1 -1
  49. package/driver/connotation-search.mjs +12 -12
  50. package/driver/contract-audit.mjs +5 -5
  51. package/driver/contract-dictation-registry.mjs +4 -4
  52. package/driver/contract-dictation.mjs +2 -2
  53. package/driver/contract-e3-backlog.mjs +6 -6
  54. package/driver/contract-vocabulary.mjs +3 -3
  55. package/driver/corrections-feedforward.mjs +1 -1
  56. package/driver/coverage-form-io.mjs +2 -2
  57. package/driver/coverage-form.mjs +4 -4
  58. package/driver/coverage-ledger.mjs +3 -3
  59. package/driver/coverage-union.mjs +1 -1
  60. package/driver/declination-call.mjs +35 -3
  61. package/driver/declination-duty.mjs +1 -1
  62. package/driver/deliver-trigger.sh +3 -3
  63. package/driver/deploy-live-run-guard.mjs +6 -2
  64. package/driver/dev-portal.mjs +3 -3
  65. package/driver/disposition-call.mjs +4 -4
  66. package/driver/disposition-tool.mjs +4 -4
  67. package/driver/disposition-union.mjs +2 -2
  68. package/driver/doc-constants.mjs +1 -1
  69. package/driver/door-gates.mjs +2 -2
  70. package/driver/doubt-selection.mjs +2 -2
  71. package/driver/drainer-identity.mjs +1 -1
  72. package/driver/driver.config.mjs +64 -12
  73. package/driver/e2e-rounds.mjs +2 -2
  74. package/driver/effort-model.mjs +2 -2
  75. package/driver/engine/anthropic-agent.mjs +24 -24
  76. package/driver/engine/auth.mjs +1 -1
  77. package/driver/engine/cli-version.mjs +103 -0
  78. package/driver/engine/common.mjs +1 -1
  79. package/driver/engine/deny-authority-write.mjs +1 -1
  80. package/driver/engine/jx-turn.mjs +1 -1
  81. package/driver/engine/mcp/clarivate-server.mjs +1 -1
  82. package/driver/engine/mcp/corsearch-server.mjs +1 -1
  83. package/driver/engine/mcp/declination-server.mjs +1 -1
  84. package/driver/engine/mcp/dispositions-server.mjs +1 -1
  85. package/driver/engine/mcp/euipo-server.mjs +1 -1
  86. package/driver/engine/mcp/fetch-server.mjs +1 -1
  87. package/driver/engine/mcp/free-tier-server.mjs +2 -2
  88. package/driver/engine/mcp/gather-config.mjs +11 -11
  89. package/driver/engine/mcp/perplexity-server.mjs +1 -1
  90. package/driver/engine/mcp/recording-server.mjs +8 -4
  91. package/driver/engine/mcp/signa-server.mjs +1 -1
  92. package/driver/engine/mcp/uspto-local-server.mjs +1 -1
  93. package/driver/engine/openai-agent.mjs +2 -2
  94. package/driver/engine-build.mjs +2 -2
  95. package/driver/enqueue-schema.mjs +10 -10
  96. package/driver/enqueue.mjs +1 -1
  97. package/driver/envelope-settle.mjs +1 -1
  98. package/driver/evidence-claim-invariant.mjs +2 -2
  99. package/driver/feedback-store.mjs +1 -1
  100. package/driver/findings-model.mjs +60 -10
  101. package/driver/flag-snapshot.mjs +20 -0
  102. package/driver/floor-duty.mjs +1 -1
  103. package/driver/form-neighbourhood.mjs +1 -1
  104. package/driver/framework.mjs +2 -2
  105. package/driver/gateway.mjs +45 -23
  106. package/driver/grounds-grammar.mjs +1 -1
  107. package/driver/hit-list.mjs +1 -1
  108. package/driver/jurisdiction-systems.mjs +1 -1
  109. package/driver/jx-lanes.mjs +1 -1
  110. package/driver/jx-units.mjs +1 -1
  111. package/driver/jx.mjs +3 -3
  112. package/driver/knockout-assess-record.mjs +5 -1
  113. package/driver/narrative-refutation-record.mjs +3 -3
  114. package/driver/numeric-setting.mjs +1 -1
  115. package/driver/owner-use-check.mjs +184 -0
  116. package/driver/package.json +4 -4
  117. package/driver/party-facts.mjs +2 -2
  118. package/driver/phase0.mjs +2 -2
  119. package/driver/pipeline-knockout.mjs +52 -4
  120. package/driver/pipeline.mjs +180 -67
  121. package/driver/placement-diff.mjs +2 -2
  122. package/driver/placement-form.mjs +4 -4
  123. package/driver/placement-union.mjs +1 -1
  124. package/driver/plain-register.mjs +120 -0
  125. package/driver/portal-access.mjs +1 -1
  126. package/driver/portal-acks.mjs +1 -1
  127. package/driver/portal-config-view.mjs +42 -3
  128. package/driver/portal-families.mjs +1 -1
  129. package/driver/portal-local-auth.mjs +1 -1
  130. package/driver/portal-report.mjs +7 -7
  131. package/driver/portal-service.mjs +41 -22
  132. package/driver/portal-upstream.mjs +2 -2
  133. package/driver/predelivery-lint.mjs +149 -11
  134. package/driver/prelim-variants-record.mjs +2 -2
  135. package/driver/profile-page.html +11 -3
  136. package/driver/profile-selection.mjs +1 -1
  137. package/driver/profile-service.mjs +6 -6
  138. package/driver/profiles/README.md +3 -3
  139. package/driver/profiles.mjs +145 -13
  140. package/driver/progress.mjs +6 -6
  141. package/driver/provider-usage.mjs +1 -1
  142. package/driver/publish/demo-marking.mjs +1 -1
  143. package/driver/publish/index.mjs +49 -8
  144. package/driver/publish/knockout.mjs +42 -14
  145. package/driver/publish/parse.mjs +4 -4
  146. package/driver/publish/publish-inputs.mjs +2 -2
  147. package/driver/publish/register-presence.mjs +1 -1
  148. package/driver/publish/render-knockout.mjs +646 -144
  149. package/driver/publish/render.mjs +2 -2
  150. package/driver/publish/report-data.mjs +13 -3
  151. package/driver/queue-watch-probe.mjs +1 -1
  152. package/driver/queue-watch-verdict.mjs +1 -1
  153. package/driver/recall-reconciliation.mjs +1 -1
  154. package/driver/recipe-service.mjs +1 -1
  155. package/driver/record-carry.mjs +5 -5
  156. package/driver/recording-agreement.mjs +3 -3
  157. package/driver/reference-score.mjs +7 -7
  158. package/driver/reference-strip-signatures.mjs +20 -0
  159. package/driver/refusal-bound.mjs +3 -3
  160. package/driver/register-availability.mjs +2 -2
  161. package/driver/register-count.mjs +1 -1
  162. package/driver/register-grant-vocabulary.mjs +2 -2
  163. package/driver/register-plan.mjs +8 -8
  164. package/driver/register-records.mjs +2 -2
  165. package/driver/registry-fidelity.mjs +3 -3
  166. package/driver/remedy-accounting.mjs +1 -1
  167. package/driver/repair-composers.mjs +2 -2
  168. package/driver/repair-digest.mjs +3 -3
  169. package/driver/repairs.mjs +6 -6
  170. package/driver/replay-archive.mjs +2 -0
  171. package/driver/report-card-record.mjs +2 -2
  172. package/driver/result-noun-fields.mjs +10 -3
  173. package/driver/run-economics.mjs +2 -2
  174. package/driver/run-integrity.mjs +1 -1
  175. package/driver/runner.mjs +22 -22
  176. package/driver/scope-rules.mjs +1 -1
  177. package/driver/search-policy.mjs +5 -5
  178. package/driver/skeptic-search.mjs +1 -1
  179. package/driver/skills/blind-frame/SKILL.md +2 -2
  180. package/driver/skills/case-law-citation/SKILL.md +2 -2
  181. package/driver/skills/knockout-assess/SKILL.md +94 -4
  182. package/driver/skills/matter-frame/SKILL.md +6 -6
  183. package/driver/skills/matter-frame/watchlist-reference.md +2 -2
  184. package/driver/skills/prelim-common-law/SKILL.md +1 -1
  185. package/driver/skills/prelim-search/SKILL.md +3 -3
  186. package/driver/skills/prelim-search/report-prose.md +82 -0
  187. package/driver/skills/prelim-search/risk-framework-demo.manifest.json +1 -1
  188. package/driver/skills/prelim-search/risk-framework-triage.manifest.json +1 -1
  189. package/driver/skills/prelim-search/risk-framework.manifest.json +1 -1
  190. package/driver/skills/prelim-search/synthesis-rules.md +1 -1
  191. package/driver/skills/prelim-search/template-formatting.md +1 -1
  192. package/driver/skills/prelim-search/templates/email/generic.md +1 -1
  193. package/driver/skills/prelim-search/worked-examples.md +1 -1
  194. package/driver/skills/prelim-variants/SKILL.md +5 -5
  195. package/driver/stage-context.mjs +1 -1
  196. package/driver/stages-knockout.mjs +55 -4
  197. package/driver/stages.mjs +101 -44
  198. package/driver/stray-artifacts.mjs +2 -2
  199. package/driver/suite-census.json +275 -65
  200. package/driver/synthesis-record.mjs +1 -1
  201. package/driver/systemd/clearotron-client-mcp.service +1 -1
  202. package/driver/systemd/clearotron-portal.service +1 -1
  203. package/driver/systemd/render-units.mjs +1 -1
  204. package/driver/tokens.mjs +1 -1
  205. package/driver/tool-calls.mjs +1 -1
  206. package/driver/turnaround-bands.mjs +1 -1
  207. package/driver/unit-file-drift.mjs +1 -1
  208. package/driver/unit-inventory.mjs +297 -80
  209. package/driver/unit-state-verdict.mjs +20 -12
  210. package/driver/verify-knockout.mjs +10 -2
  211. package/driver/verify.mjs +13 -13
  212. package/driver/whatif-memo-run.mjs +72 -9
  213. package/driver/whatif-memo.mjs +19 -1
  214. package/driver/whatif-queue.mjs +1 -1
  215. package/driver/whatif-worker.mjs +1 -1
  216. package/examples/README.md +2 -2
  217. package/examples/grants.example.json +6 -7
  218. package/mcp-server/CHANGELOG.md +6 -0
  219. package/mcp-server/README.md +3 -3
  220. package/mcp-server/http-server.mjs +44 -1
  221. package/mcp-server/key-socket.mjs +184 -0
  222. package/mcp-server/lib/audit-view.mjs +69 -2
  223. package/mcp-server/lib/brief.mjs +15 -0
  224. package/mcp-server/lib/driver.mjs +7 -1
  225. package/mcp-server/lib/events.mjs +1 -1
  226. package/mcp-server/lib/http-handler.mjs +1 -1
  227. package/mcp-server/lib/knockout.mjs +435 -0
  228. package/mcp-server/lib/ops.mjs +4 -4
  229. package/mcp-server/lib/options.mjs +1 -1
  230. package/mcp-server/lib/plan.mjs +1 -1
  231. package/mcp-server/lib/runs.mjs +1 -1
  232. package/mcp-server/lib/scrub.mjs +2 -2
  233. package/mcp-server/lib/whatif.mjs +5 -5
  234. package/mcp-server/mint-token.mjs +1 -1
  235. package/mcp-server/package.json +2 -2
  236. package/mcp-server/packs/ops/EXAMPLES.md +2 -2
  237. package/mcp-server/server.mjs +77 -12
  238. package/package.json +30 -12
  239. package/portal-ui/dist/assets/{index-Ct3iQtZ2.css → index-1ziUJX1E.css} +43 -2
  240. package/portal-ui/dist/assets/{index-BUGgiYtF.js → index-CEYvXdqH.js} +226 -49
  241. package/portal-ui/dist/index.html +2 -2
  242. package/portal-ui/package.json +1 -1
  243. package/providers/_shared/enumerate.mjs +1 -1
  244. package/providers/_shared/ledger-path.mjs +3 -3
  245. package/providers/_shared/ledger.mjs +1 -1
  246. package/providers/_shared/result-shape.mjs +3 -3
  247. package/providers/_shared/term-shape.mjs +2 -2
  248. package/providers/corsearch/src/core.js +1 -1
  249. package/providers/jx-subclass/BUILDING.md +1 -1
  250. package/providers/oauth-mcp-bridge/CHANGELOG.md +6 -0
  251. package/providers/oauth-mcp-bridge/package.json +1 -1
  252. package/providers/oauth-mcp-bridge/stdin-guard.mjs +2 -2
  253. package/providers/uspto-local/src/index-store.js +2 -2
  254. package/scripts/README.md +1 -1
  255. package/scripts/added-reference-check.mjs +29 -1
  256. package/scripts/authority-boundary-probe.mjs +1 -1
  257. package/scripts/backfill-started-at.mjs +1 -1
  258. package/scripts/citation-line-check.mjs +124 -5
  259. package/scripts/compare.mjs +2 -2
  260. package/scripts/contract-dictation-scan.mjs +2 -2
  261. package/scripts/dead-names.mjs +1 -1
  262. package/scripts/drain-preflight.mjs +5 -5
  263. package/scripts/e2e-unread-terminals.mjs +1 -1
  264. package/scripts/e2e.mjs +8 -8
  265. package/scripts/env-audit.mjs +7 -7
  266. package/scripts/env-classify.mjs +206 -18
  267. package/scripts/freeze-example-run.mjs +3 -3
  268. package/scripts/head-arrived-gated.mjs +1 -1
  269. package/scripts/headless-page.mjs +51 -2
  270. package/scripts/live-surface-check.mjs +129 -19
  271. package/scripts/main-health.mjs +1 -1
  272. package/scripts/merge-presence-check.mjs +3 -3
  273. package/scripts/mint-suite-census.mjs +6 -6
  274. package/scripts/nightly-notice.mjs +1 -3
  275. package/scripts/preinstall-node-check.mjs +24 -0
  276. package/scripts/reconcile-runs.mjs +1 -1
  277. package/scripts/release-await-cut.mjs +6 -4
  278. package/scripts/release-version-pr-checks.mjs +1 -1
  279. package/scripts/release-version.mjs +2 -2
  280. package/scripts/render-check.mjs +66 -7
  281. package/scripts/report-frame-check.mjs +1 -1
  282. package/scripts/report-screenshot.mjs +1 -1
  283. package/scripts/revisit-render-check.mjs +1 -1
  284. package/scripts/score.mjs +4 -4
  285. package/scripts/strip-tracker-citations.mjs +139 -0
  286. package/scripts/test-run.mjs +19 -3
  287. package/scripts/third-party-notices.mjs +3 -3
  288. package/scripts/travelling-predicates.mjs +3 -3
  289. package/scripts/unexecuted-asserts.mjs +2 -2
  290. package/scripts/verify-publishable.mjs +2 -2
  291. package/scripts/write-up-form-census.mjs +1 -1
  292. package/shared/access-audience.mjs +1 -1
  293. package/shared/anon-overlay.mjs +3 -3
  294. package/shared/brand.mjs +13 -13
  295. package/shared/citation-scan.mjs +1 -1
  296. package/shared/client-door.mjs +7 -7
  297. package/shared/customer-store.mjs +1 -1
  298. package/shared/driver-dir.mjs +1 -1
  299. package/shared/env-aliases.mjs +0 -48
  300. package/shared/env-local.mjs +1 -1
  301. package/shared/identifier-scan.mjs +3 -3
  302. package/shared/invocation.mjs +29 -1
  303. package/shared/names-in-force.mjs +4 -0
  304. package/shared/node-floor.mjs +97 -0
  305. package/shared/product-owned-names.mjs +1 -1
  306. package/shared/register-selection.mjs +1 -1
  307. package/shared/scope.mjs +5 -5
  308. package/shared/server-units.mjs +4 -4
  309. package/shared/staff-domain.mjs +154 -0
  310. package/shared/store-in-repo.mjs +25 -4
  311. package/shared/suite-census.mjs +4 -4
  312. package/shared/tty-style.mjs +1 -1
  313. package/shared/uspto-index-size.mjs +1 -1
  314. package/shared/vacuous-pass.mjs +1 -1
  315. package/skills/clearotron-account/SKILL.md +42 -13
  316. package/skills/clearotron-ops/SKILL.md +1 -1
  317. package/driver/recipes/README.md +0 -49
  318. package/driver/skills/prelim-search/risk-framework-aurora.manifest.json +0 -19
  319. package/driver/skills/prelim-search/risk-framework-aurora.md +0 -77
  320. package/driver/skills/prelim-search/risk-framework-zephyr.manifest.json +0 -14
  321. package/driver/skills/prelim-search/risk-framework-zephyr.md +0 -33
  322. package/driver/skills/prelim-search/worked-examples-aurora.md +0 -10
  323. package/driver/skills/prelim-search/worked-examples-zephyr.md +0 -10
  324. package/driver/systemd/prelim-driver.path +0 -69
  325. package/driver/systemd/prelim-driver.service +0 -86
  326. package/driver/systemd/prelim-driver.timer +0 -14
  327. package/driver/systemd/prelim-outbox.path +0 -27
  328. package/driver/systemd/prelim-outbox.service +0 -37
  329. package/driver/systemd/prelim-outbox.timer +0 -21
  330. package/node_modules/exceljs/README_zh.md +0 -2878
  331. package/node_modules/exceljs/dist/LICENSE +0 -22
  332. package/node_modules/exceljs/dist/es5/csv/csv.js +0 -182
  333. package/node_modules/exceljs/dist/es5/csv/csv.js.map +0 -1
  334. package/node_modules/exceljs/dist/es5/csv/line-buffer.js +0 -68
  335. package/node_modules/exceljs/dist/es5/csv/line-buffer.js.map +0 -1
  336. package/node_modules/exceljs/dist/es5/csv/stream-converter.js +0 -110
  337. package/node_modules/exceljs/dist/es5/csv/stream-converter.js.map +0 -1
  338. package/node_modules/exceljs/dist/es5/doc/anchor.js +0 -73
  339. package/node_modules/exceljs/dist/es5/doc/anchor.js.map +0 -1
  340. package/node_modules/exceljs/dist/es5/doc/cell.js +0 -961
  341. package/node_modules/exceljs/dist/es5/doc/cell.js.map +0 -1
  342. package/node_modules/exceljs/dist/es5/doc/column.js +0 -274
  343. package/node_modules/exceljs/dist/es5/doc/column.js.map +0 -1
  344. package/node_modules/exceljs/dist/es5/doc/data-validations.js +0 -18
  345. package/node_modules/exceljs/dist/es5/doc/data-validations.js.map +0 -1
  346. package/node_modules/exceljs/dist/es5/doc/defined-names.js +0 -173
  347. package/node_modules/exceljs/dist/es5/doc/defined-names.js.map +0 -1
  348. package/node_modules/exceljs/dist/es5/doc/enums.js +0 -49
  349. package/node_modules/exceljs/dist/es5/doc/enums.js.map +0 -1
  350. package/node_modules/exceljs/dist/es5/doc/image.js +0 -69
  351. package/node_modules/exceljs/dist/es5/doc/image.js.map +0 -1
  352. package/node_modules/exceljs/dist/es5/doc/modelcontainer.js +0 -16
  353. package/node_modules/exceljs/dist/es5/doc/modelcontainer.js.map +0 -1
  354. package/node_modules/exceljs/dist/es5/doc/note.js +0 -64
  355. package/node_modules/exceljs/dist/es5/doc/note.js.map +0 -1
  356. package/node_modules/exceljs/dist/es5/doc/range.js +0 -229
  357. package/node_modules/exceljs/dist/es5/doc/range.js.map +0 -1
  358. package/node_modules/exceljs/dist/es5/doc/row.js +0 -382
  359. package/node_modules/exceljs/dist/es5/doc/row.js.map +0 -1
  360. package/node_modules/exceljs/dist/es5/doc/table.js +0 -443
  361. package/node_modules/exceljs/dist/es5/doc/table.js.map +0 -1
  362. package/node_modules/exceljs/dist/es5/doc/workbook.js +0 -202
  363. package/node_modules/exceljs/dist/es5/doc/workbook.js.map +0 -1
  364. package/node_modules/exceljs/dist/es5/doc/worksheet.js +0 -900
  365. package/node_modules/exceljs/dist/es5/doc/worksheet.js.map +0 -1
  366. package/node_modules/exceljs/dist/es5/exceljs.bare.js +0 -14
  367. package/node_modules/exceljs/dist/es5/exceljs.bare.js.map +0 -1
  368. package/node_modules/exceljs/dist/es5/exceljs.browser.js +0 -36
  369. package/node_modules/exceljs/dist/es5/exceljs.browser.js.map +0 -1
  370. package/node_modules/exceljs/dist/es5/exceljs.nodejs.js +0 -15
  371. package/node_modules/exceljs/dist/es5/exceljs.nodejs.js.map +0 -1
  372. package/node_modules/exceljs/dist/es5/index.js +0 -15
  373. package/node_modules/exceljs/dist/es5/stream/xlsx/hyperlink-reader.js +0 -90
  374. package/node_modules/exceljs/dist/es5/stream/xlsx/hyperlink-reader.js.map +0 -1
  375. package/node_modules/exceljs/dist/es5/stream/xlsx/sheet-comments-writer.js +0 -94
  376. package/node_modules/exceljs/dist/es5/stream/xlsx/sheet-comments-writer.js.map +0 -1
  377. package/node_modules/exceljs/dist/es5/stream/xlsx/sheet-rels-writer.js +0 -94
  378. package/node_modules/exceljs/dist/es5/stream/xlsx/sheet-rels-writer.js.map +0 -1
  379. package/node_modules/exceljs/dist/es5/stream/xlsx/workbook-reader.js +0 -362
  380. package/node_modules/exceljs/dist/es5/stream/xlsx/workbook-reader.js.map +0 -1
  381. package/node_modules/exceljs/dist/es5/stream/xlsx/workbook-writer.js +0 -347
  382. package/node_modules/exceljs/dist/es5/stream/xlsx/workbook-writer.js.map +0 -1
  383. package/node_modules/exceljs/dist/es5/stream/xlsx/worksheet-reader.js +0 -392
  384. package/node_modules/exceljs/dist/es5/stream/xlsx/worksheet-reader.js.map +0 -1
  385. package/node_modules/exceljs/dist/es5/stream/xlsx/worksheet-writer.js +0 -652
  386. package/node_modules/exceljs/dist/es5/stream/xlsx/worksheet-writer.js.map +0 -1
  387. package/node_modules/exceljs/dist/es5/utils/auto-drain.js +0 -18
  388. package/node_modules/exceljs/dist/es5/utils/auto-drain.js.map +0 -1
  389. package/node_modules/exceljs/dist/es5/utils/browser-buffer-decode.js +0 -15
  390. package/node_modules/exceljs/dist/es5/utils/browser-buffer-decode.js.map +0 -1
  391. package/node_modules/exceljs/dist/es5/utils/browser-buffer-encode.js +0 -18
  392. package/node_modules/exceljs/dist/es5/utils/browser-buffer-encode.js.map +0 -1
  393. package/node_modules/exceljs/dist/es5/utils/cell-matrix.js +0 -149
  394. package/node_modules/exceljs/dist/es5/utils/cell-matrix.js.map +0 -1
  395. package/node_modules/exceljs/dist/es5/utils/col-cache.js +0 -258
  396. package/node_modules/exceljs/dist/es5/utils/col-cache.js.map +0 -1
  397. package/node_modules/exceljs/dist/es5/utils/copy-style.js +0 -43
  398. package/node_modules/exceljs/dist/es5/utils/copy-style.js.map +0 -1
  399. package/node_modules/exceljs/dist/es5/utils/encryptor.js +0 -58
  400. package/node_modules/exceljs/dist/es5/utils/encryptor.js.map +0 -1
  401. package/node_modules/exceljs/dist/es5/utils/iterate-stream.js +0 -46
  402. package/node_modules/exceljs/dist/es5/utils/iterate-stream.js.map +0 -1
  403. package/node_modules/exceljs/dist/es5/utils/parse-sax.js +0 -47
  404. package/node_modules/exceljs/dist/es5/utils/parse-sax.js.map +0 -1
  405. package/node_modules/exceljs/dist/es5/utils/shared-formula.js +0 -42
  406. package/node_modules/exceljs/dist/es5/utils/shared-formula.js.map +0 -1
  407. package/node_modules/exceljs/dist/es5/utils/shared-strings.js +0 -32
  408. package/node_modules/exceljs/dist/es5/utils/shared-strings.js.map +0 -1
  409. package/node_modules/exceljs/dist/es5/utils/stream-base64.js +0 -66
  410. package/node_modules/exceljs/dist/es5/utils/stream-base64.js.map +0 -1
  411. package/node_modules/exceljs/dist/es5/utils/stream-buf.js +0 -343
  412. package/node_modules/exceljs/dist/es5/utils/stream-buf.js.map +0 -1
  413. package/node_modules/exceljs/dist/es5/utils/string-buf.js +0 -73
  414. package/node_modules/exceljs/dist/es5/utils/string-buf.js.map +0 -1
  415. package/node_modules/exceljs/dist/es5/utils/string-builder.js +0 -32
  416. package/node_modules/exceljs/dist/es5/utils/string-builder.js.map +0 -1
  417. package/node_modules/exceljs/dist/es5/utils/stuttered-pipe.js +0 -61
  418. package/node_modules/exceljs/dist/es5/utils/stuttered-pipe.js.map +0 -1
  419. package/node_modules/exceljs/dist/es5/utils/typed-stack.js +0 -23
  420. package/node_modules/exceljs/dist/es5/utils/typed-stack.js.map +0 -1
  421. package/node_modules/exceljs/dist/es5/utils/under-dash.js +0 -168
  422. package/node_modules/exceljs/dist/es5/utils/under-dash.js.map +0 -1
  423. package/node_modules/exceljs/dist/es5/utils/utils.js +0 -171
  424. package/node_modules/exceljs/dist/es5/utils/utils.js.map +0 -1
  425. package/node_modules/exceljs/dist/es5/utils/xml-stream.js +0 -151
  426. package/node_modules/exceljs/dist/es5/utils/xml-stream.js.map +0 -1
  427. package/node_modules/exceljs/dist/es5/utils/zip-stream.js +0 -79
  428. package/node_modules/exceljs/dist/es5/utils/zip-stream.js.map +0 -1
  429. package/node_modules/exceljs/dist/es5/xlsx/defaultnumformats.js +0 -230
  430. package/node_modules/exceljs/dist/es5/xlsx/defaultnumformats.js.map +0 -1
  431. package/node_modules/exceljs/dist/es5/xlsx/rel-type.js +0 -18
  432. package/node_modules/exceljs/dist/es5/xlsx/rel-type.js.map +0 -1
  433. package/node_modules/exceljs/dist/es5/xlsx/xform/base-xform.js +0 -139
  434. package/node_modules/exceljs/dist/es5/xlsx/xform/base-xform.js.map +0 -1
  435. package/node_modules/exceljs/dist/es5/xlsx/xform/book/defined-name-xform.js +0 -85
  436. package/node_modules/exceljs/dist/es5/xlsx/xform/book/defined-name-xform.js.map +0 -1
  437. package/node_modules/exceljs/dist/es5/xlsx/xform/book/sheet-xform.js +0 -32
  438. package/node_modules/exceljs/dist/es5/xlsx/xform/book/sheet-xform.js.map +0 -1
  439. package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-calc-properties-xform.js +0 -24
  440. package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-calc-properties-xform.js.map +0 -1
  441. package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-properties-xform.js +0 -27
  442. package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-properties-xform.js.map +0 -1
  443. package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-view-xform.js +0 -51
  444. package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-view-xform.js.map +0 -1
  445. package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-xform.js +0 -234
  446. package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-xform.js.map +0 -1
  447. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/comment-xform.js +0 -103
  448. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/comment-xform.js.map +0 -1
  449. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/comments-xform.js +0 -76
  450. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/comments-xform.js.map +0 -1
  451. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/style/vml-position-xform.js +0 -35
  452. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/style/vml-position-xform.js.map +0 -1
  453. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/style/vml-protection-xform.js +0 -32
  454. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/style/vml-protection-xform.js.map +0 -1
  455. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-anchor-xform.js +0 -53
  456. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-anchor-xform.js.map +0 -1
  457. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-client-data-xform.js +0 -97
  458. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-client-data-xform.js.map +0 -1
  459. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-notes-xform.js +0 -107
  460. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-notes-xform.js.map +0 -1
  461. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-shape-xform.js +0 -92
  462. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-shape-xform.js.map +0 -1
  463. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-textbox-xform.js +0 -61
  464. package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-textbox-xform.js.map +0 -1
  465. package/node_modules/exceljs/dist/es5/xlsx/xform/composite-xform.js +0 -51
  466. package/node_modules/exceljs/dist/es5/xlsx/xform/composite-xform.js.map +0 -1
  467. package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-heading-pairs-xform.js +0 -30
  468. package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-heading-pairs-xform.js.map +0 -1
  469. package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-titles-of-parts-xform.js +0 -27
  470. package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-titles-of-parts-xform.js.map +0 -1
  471. package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-xform.js +0 -93
  472. package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-xform.js.map +0 -1
  473. package/node_modules/exceljs/dist/es5/xlsx/xform/core/content-types-xform.js +0 -112
  474. package/node_modules/exceljs/dist/es5/xlsx/xform/core/content-types-xform.js.map +0 -1
  475. package/node_modules/exceljs/dist/es5/xlsx/xform/core/core-xform.js +0 -158
  476. package/node_modules/exceljs/dist/es5/xlsx/xform/core/core-xform.js.map +0 -1
  477. package/node_modules/exceljs/dist/es5/xlsx/xform/core/relationship-xform.js +0 -23
  478. package/node_modules/exceljs/dist/es5/xlsx/xform/core/relationship-xform.js.map +0 -1
  479. package/node_modules/exceljs/dist/es5/xlsx/xform/core/relationships-xform.js +0 -65
  480. package/node_modules/exceljs/dist/es5/xlsx/xform/core/relationships-xform.js.map +0 -1
  481. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/base-cell-anchor-xform.js +0 -47
  482. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/base-cell-anchor-xform.js.map +0 -1
  483. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/blip-fill-xform.js +0 -61
  484. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/blip-fill-xform.js.map +0 -1
  485. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/blip-xform.js +0 -40
  486. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/blip-xform.js.map +0 -1
  487. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/c-nv-pic-pr-xform.js +0 -35
  488. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/c-nv-pic-pr-xform.js.map +0 -1
  489. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/c-nv-pr-xform.js +0 -62
  490. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/c-nv-pr-xform.js.map +0 -1
  491. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/cell-position-xform.js +0 -82
  492. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/cell-position-xform.js.map +0 -1
  493. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/drawing-xform.js +0 -98
  494. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/drawing-xform.js.map +0 -1
  495. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/ext-lst-xform.js +0 -40
  496. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/ext-lst-xform.js.map +0 -1
  497. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/ext-xform.js +0 -38
  498. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/ext-xform.js.map +0 -1
  499. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/hlink-click-xform.js +0 -38
  500. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/hlink-click-xform.js.map +0 -1
  501. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/nv-pic-pr-xform.js +0 -59
  502. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/nv-pic-pr-xform.js.map +0 -1
  503. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/one-cell-anchor-xform.js +0 -63
  504. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/one-cell-anchor-xform.js.map +0 -1
  505. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/pic-xform.js +0 -67
  506. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/pic-xform.js.map +0 -1
  507. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/sp-pr.js +0 -30
  508. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/sp-pr.js.map +0 -1
  509. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/two-cell-anchor-xform.js +0 -62
  510. package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/two-cell-anchor-xform.js.map +0 -1
  511. package/node_modules/exceljs/dist/es5/xlsx/xform/list-xform.js +0 -91
  512. package/node_modules/exceljs/dist/es5/xlsx/xform/list-xform.js.map +0 -1
  513. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/auto-filter-xform.js +0 -40
  514. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/auto-filter-xform.js.map +0 -1
  515. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cell-xform.js +0 -451
  516. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cell-xform.js.map +0 -1
  517. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/cf-rule-xform.js +0 -275
  518. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/cf-rule-xform.js.map +0 -1
  519. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/cfvo-xform.js +0 -25
  520. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/cfvo-xform.js.map +0 -1
  521. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/color-scale-xform.js +0 -38
  522. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/color-scale-xform.js.map +0 -1
  523. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/conditional-formatting-xform.js +0 -45
  524. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/conditional-formatting-xform.js.map +0 -1
  525. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/conditional-formattings-xform.js +0 -77
  526. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/conditional-formattings-xform.js.map +0 -1
  527. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/databar-xform.js +0 -42
  528. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/databar-xform.js.map +0 -1
  529. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/ext-lst-ref-xform.js +0 -71
  530. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/ext-lst-ref-xform.js.map +0 -1
  531. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/formula-xform.js +0 -22
  532. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/formula-xform.js.map +0 -1
  533. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/icon-set-xform.js +0 -43
  534. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/icon-set-xform.js.map +0 -1
  535. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.js +0 -28
  536. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.js.map +0 -1
  537. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js +0 -88
  538. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js.map +0 -1
  539. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.js +0 -38
  540. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.js.map +0 -1
  541. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.js +0 -52
  542. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.js.map +0 -1
  543. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.js +0 -43
  544. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.js.map +0 -1
  545. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/databar-ext-xform.js +0 -75
  546. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/databar-ext-xform.js.map +0 -1
  547. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/f-ext-xform.js +0 -22
  548. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/f-ext-xform.js.map +0 -1
  549. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.js +0 -66
  550. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.js.map +0 -1
  551. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/sqref-ext-xform.js +0 -22
  552. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/sqref-ext-xform.js.map +0 -1
  553. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/col-xform.js +0 -78
  554. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/col-xform.js.map +0 -1
  555. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/data-validations-xform.js +0 -247
  556. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/data-validations-xform.js.map +0 -1
  557. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/dimension-xform.js +0 -28
  558. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/dimension-xform.js.map +0 -1
  559. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/drawing-xform.js +0 -32
  560. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/drawing-xform.js.map +0 -1
  561. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/ext-lst-xform.js +0 -69
  562. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/ext-lst-xform.js.map +0 -1
  563. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/header-footer-xform.js +0 -126
  564. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/header-footer-xform.js.map +0 -1
  565. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/hyperlink-xform.js +0 -50
  566. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/hyperlink-xform.js.map +0 -1
  567. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/merge-cell-xform.js +0 -26
  568. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/merge-cell-xform.js.map +0 -1
  569. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/merges.js +0 -52
  570. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/merges.js.map +0 -1
  571. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/outline-properties-xform.js +0 -35
  572. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/outline-properties-xform.js.map +0 -1
  573. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-breaks-xform.js +0 -24
  574. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-breaks-xform.js.map +0 -1
  575. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-margins-xform.js +0 -46
  576. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-margins-xform.js.map +0 -1
  577. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-setup-properties-xform.js +0 -32
  578. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-setup-properties-xform.js.map +0 -1
  579. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-setup-xform.js +0 -99
  580. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-setup-xform.js.map +0 -1
  581. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/picture-xform.js +0 -32
  582. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/picture-xform.js.map +0 -1
  583. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/print-options-xform.js +0 -45
  584. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/print-options-xform.js.map +0 -1
  585. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/row-breaks-xform.js +0 -37
  586. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/row-breaks-xform.js.map +0 -1
  587. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/row-xform.js +0 -128
  588. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/row-xform.js.map +0 -1
  589. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-format-properties-xform.js +0 -51
  590. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-format-properties-xform.js.map +0 -1
  591. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-properties-xform.js +0 -83
  592. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-properties-xform.js.map +0 -1
  593. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-protection-xform.js +0 -84
  594. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-protection-xform.js.map +0 -1
  595. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-view-xform.js +0 -190
  596. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-view-xform.js.map +0 -1
  597. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/table-part-xform.js +0 -32
  598. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/table-part-xform.js.map +0 -1
  599. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/worksheet-xform.js +0 -513
  600. package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/worksheet-xform.js.map +0 -1
  601. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/boolean-xform.js +0 -27
  602. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/boolean-xform.js.map +0 -1
  603. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/date-xform.js +0 -58
  604. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/date-xform.js.map +0 -1
  605. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/float-xform.js +0 -47
  606. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/float-xform.js.map +0 -1
  607. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/integer-xform.js +0 -53
  608. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/integer-xform.js.map +0 -1
  609. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/string-xform.js +0 -47
  610. package/node_modules/exceljs/dist/es5/xlsx/xform/simple/string-xform.js.map +0 -1
  611. package/node_modules/exceljs/dist/es5/xlsx/xform/static-xform.js +0 -61
  612. package/node_modules/exceljs/dist/es5/xlsx/xform/static-xform.js.map +0 -1
  613. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/phonetic-text-xform.js +0 -98
  614. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/phonetic-text-xform.js.map +0 -1
  615. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/rich-text-xform.js +0 -92
  616. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/rich-text-xform.js.map +0 -1
  617. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/shared-string-xform.js +0 -99
  618. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/shared-string-xform.js.map +0 -1
  619. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/shared-strings-xform.js +0 -114
  620. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/shared-strings-xform.js.map +0 -1
  621. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/text-xform.js +0 -39
  622. package/node_modules/exceljs/dist/es5/xlsx/xform/strings/text-xform.js.map +0 -1
  623. package/node_modules/exceljs/dist/es5/xlsx/xform/style/alignment-xform.js +0 -139
  624. package/node_modules/exceljs/dist/es5/xlsx/xform/style/alignment-xform.js.map +0 -1
  625. package/node_modules/exceljs/dist/es5/xlsx/xform/style/border-xform.js +0 -185
  626. package/node_modules/exceljs/dist/es5/xlsx/xform/style/border-xform.js.map +0 -1
  627. package/node_modules/exceljs/dist/es5/xlsx/xform/style/color-xform.js +0 -66
  628. package/node_modules/exceljs/dist/es5/xlsx/xform/style/color-xform.js.map +0 -1
  629. package/node_modules/exceljs/dist/es5/xlsx/xform/style/dxf-xform.js +0 -106
  630. package/node_modules/exceljs/dist/es5/xlsx/xform/style/dxf-xform.js.map +0 -1
  631. package/node_modules/exceljs/dist/es5/xlsx/xform/style/fill-xform.js +0 -308
  632. package/node_modules/exceljs/dist/es5/xlsx/xform/style/fill-xform.js.map +0 -1
  633. package/node_modules/exceljs/dist/es5/xlsx/xform/style/font-xform.js +0 -175
  634. package/node_modules/exceljs/dist/es5/xlsx/xform/style/font-xform.js.map +0 -1
  635. package/node_modules/exceljs/dist/es5/xlsx/xform/style/numfmt-xform.js +0 -59
  636. package/node_modules/exceljs/dist/es5/xlsx/xform/style/numfmt-xform.js.map +0 -1
  637. package/node_modules/exceljs/dist/es5/xlsx/xform/style/protection-xform.js +0 -53
  638. package/node_modules/exceljs/dist/es5/xlsx/xform/style/protection-xform.js.map +0 -1
  639. package/node_modules/exceljs/dist/es5/xlsx/xform/style/style-xform.js +0 -118
  640. package/node_modules/exceljs/dist/es5/xlsx/xform/style/style-xform.js.map +0 -1
  641. package/node_modules/exceljs/dist/es5/xlsx/xform/style/styles-xform.js +0 -612
  642. package/node_modules/exceljs/dist/es5/xlsx/xform/style/styles-xform.js.map +0 -1
  643. package/node_modules/exceljs/dist/es5/xlsx/xform/style/underline-xform.js +0 -46
  644. package/node_modules/exceljs/dist/es5/xlsx/xform/style/underline-xform.js.map +0 -1
  645. package/node_modules/exceljs/dist/es5/xlsx/xform/table/auto-filter-xform.js +0 -75
  646. package/node_modules/exceljs/dist/es5/xlsx/xform/table/auto-filter-xform.js.map +0 -1
  647. package/node_modules/exceljs/dist/es5/xlsx/xform/table/custom-filter-xform.js +0 -30
  648. package/node_modules/exceljs/dist/es5/xlsx/xform/table/custom-filter-xform.js.map +0 -1
  649. package/node_modules/exceljs/dist/es5/xlsx/xform/table/filter-column-xform.js +0 -89
  650. package/node_modules/exceljs/dist/es5/xlsx/xform/table/filter-column-xform.js.map +0 -1
  651. package/node_modules/exceljs/dist/es5/xlsx/xform/table/filter-xform.js +0 -28
  652. package/node_modules/exceljs/dist/es5/xlsx/xform/table/filter-xform.js.map +0 -1
  653. package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-column-xform.js +0 -42
  654. package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-column-xform.js.map +0 -1
  655. package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-style-info-xform.js +0 -40
  656. package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-style-info-xform.js.map +0 -1
  657. package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-xform.js +0 -123
  658. package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-xform.js.map +0 -1
  659. package/node_modules/exceljs/dist/es5/xlsx/xlsx.js +0 -697
  660. package/node_modules/exceljs/dist/es5/xlsx/xlsx.js.map +0 -1
  661. package/node_modules/exceljs/dist/es5/xlsx/xml/theme1.js +0 -5
  662. package/node_modules/exceljs/dist/es5/xlsx/xml/theme1.js.map +0 -1
  663. package/node_modules/exceljs/dist/exceljs.bare.js +0 -55253
  664. package/node_modules/exceljs/dist/exceljs.bare.js.map +0 -761
  665. package/node_modules/exceljs/dist/exceljs.bare.min.js +0 -45
  666. package/node_modules/exceljs/dist/exceljs.bare.min.js.map +0 -1
  667. package/node_modules/exceljs/dist/exceljs.js +0 -59900
  668. package/node_modules/exceljs/dist/exceljs.js.map +0 -1083
  669. package/node_modules/exceljs/dist/exceljs.min.js +0 -45
  670. package/node_modules/exceljs/dist/exceljs.min.js.map +0 -1
  671. package/scripts/ai-page-render-check.mjs +0 -532
  672. package/scripts/clearances-render-check.mjs +0 -480
  673. package/scripts/composer-render-check.mjs +0 -1027
  674. package/scripts/deploy-test.sh +0 -309
  675. package/scripts/home-render-check.mjs +0 -526
  676. package/scripts/portal-lifecycle-check.mjs +0 -639
@@ -1,639 +0,0 @@
1
- #!/usr/bin/env node
2
- // SPDX-License-Identifier: AGPL-3.0-only
3
- // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
4
- // Does the portal call a brand owner by name, and can a person manage their own searches and projects?
5
- //
6
- // node scripts/portal-lifecycle-check.mjs [--keep] [--shot <path>]
7
- //
8
- // ── why this exists ──────────────────────────────────────────────────────────────────────────────────
9
- //
10
- // Three of the four things checked here are LOGIN-DEPENDENT, and that is the whole difficulty. The bug
11
- // this was written for — the same brand owner reading "Vantor Labs" in one place and "vantor" in
12
- // another — was invisible from a staff session, because staff had a name source and clients did not. A
13
- // screenshot from one login is not evidence about the other, and no string test in portal-ui can see a
14
- // rendered label at all.
15
- //
16
- // So this serves the REAL built bundle to a REAL browser, twice — once as staff, once as a client — and
17
- // reads what is actually on screen. Then it drives the two lifecycles that had no controls at all:
18
- // retiring a custom search and bringing it back, and creating a project.
19
- //
20
- // It is deliberately a sibling of composer-render-check.mjs rather than an extension of it: that one
21
- // exercises the one screen that spends money, and it should not grow a second job.
22
- //
23
- // MUST NOT run as a user with a virtual-memory ulimit (`ulimit -v`) — Chrome dumps core under one. Run
24
- // it as a user with `ulimit -v unlimited`.
25
-
26
- import { createServer } from 'node:http'
27
- import { readFileSync, existsSync, writeFileSync, mkdtempSync, rmSync } from 'node:fs'
28
- import { join, extname, dirname } from 'node:path'
29
- import { fileURLToPath } from 'node:url'
30
- import { spawn } from 'node:child_process'
31
- import { tmpdir } from 'node:os'
32
- import { productRow } from '../driver/product-rows.mjs'
33
- import { reportIdentityFor } from '../driver/search-policy.mjs'
34
-
35
- const HERE = dirname(fileURLToPath(import.meta.url))
36
- const DIST = join(HERE, '..', 'portal-ui', 'dist')
37
- const keep = process.argv.includes('--keep')
38
- const shotAt = process.argv.includes('--shot') ? process.argv[process.argv.indexOf('--shot') + 1] : null
39
-
40
- if (!existsSync(join(DIST, 'index.html'))) {
41
- console.error(`no build at ${DIST} — run: npm run build:ui`)
42
- process.exit(2)
43
- }
44
-
45
- // ── the stub portal ─────────────────────────────────────────────────────────────────────────────────
46
- //
47
- // ONE brand owner, whose key and name differ in exactly the way every real one does: a lowercase slug
48
- // against a capitalised name. That difference is the entire subject of the first half of this check, so
49
- // a fixture where they matched would pass while the product was broken.
50
-
51
- const KEY = 'vantor'
52
- const NAME = 'Vantor Labs'
53
-
54
- const KEY2 = 'aurora'
55
- const NAME2 = 'Aurora Interactive'
56
-
57
- /** Which identity /portal/api/me answers as. Flipped between passes. */
58
- let role = 'client'
59
-
60
- const ME = () => {
61
- if (role === 'staff') {
62
- // Staff hold "*", which is not a list — they read names from the staff-only roster. `accountNames`
63
- // is empty for them by design, and a staff pass that still shows the name proves the roster path.
64
- return { role: 'staff', email: 'lawyer@cordillera.test', accounts: '*', accountNames: {} }
65
- }
66
- if (role === 'multi') {
67
- // THE LOGIN THE BUG WAS REPORTED FROM. A client with several grants is the only identity that gets
68
- // the switcher WITHOUT the roster behind it — its options come from `me.accounts` and their labels
69
- // from `me.accountNames`, a path neither of the other two passes renders at all. Staff exercise the
70
- // switcher but read the roster; a single-account client reads the names but has no switcher.
71
- return { role: 'client', email: 'owner@example.test', accounts: [KEY, KEY2],
72
- accountNames: { [KEY]: NAME, [KEY2]: NAME2 } }
73
- }
74
- return { role: 'client', email: 'gundy@apmxc.test', accounts: [KEY], accountNames: { [KEY]: NAME } }
75
- }
76
-
77
- // THE ENGINE'S OWN ROW for a level, not a restatement of it. `available`/`unavailableNote` are the
78
- // only additions — deployment state resolved per request, which productRows knows nothing about. This
79
- // pass deliberately serves a SUBSET of the registry (no knockout-register), so it names its keys.
80
- const level = (key) => ({ ...productRow(key), available: true, unavailableNote: '' })
81
-
82
- /** The saved-search store, mutated by what the page posts — so a retire is observable as state. */
83
- const RECIPES = {
84
- 'launch-screen': {
85
- label: 'Launch screen', components: {},
86
- // A one-country scope on the one-country product: a saved search is a job template, and the engine
87
- // refuses a scope its base product does not accept — at the save door as at every run door.
88
- base: 'full-country-search',
89
- scope: { jurisdictions: ['United States'], platforms: [], classes: [9] },
90
- nativeLanguage: false, notes: 'For the EU launch team.',
91
- // An extra no lever can express. If a composer re-save drops this, the check fails — that is the
92
- // silent capability regression retiring the standalone editor could have caused.
93
- extras: { emailTable: true },
94
- archived: false, version: 3, createdBy: 'seed@test', createdAt: '2026-07-18T00:00:00.000Z',
95
- },
96
- 'old-thing': {
97
- label: 'Old thing', base: 'global-preliminary-search', components: {}, scope: {},
98
- nativeLanguage: false, archived: true, version: 2,
99
- },
100
- }
101
-
102
- // One live, one archived. The archived row now reaches the browser for BOTH roles (that is what makes
103
- // archiving reversible), so "is it still offered when a clearance is set up" stopped being answered by
104
- // the wire and became something the composer has to get right.
105
- const PROJECTS = [
106
- { key: 'eu-launch', name: 'EU launch', archived: false },
107
- { key: 'old-engagement', name: 'Old engagement', archived: true },
108
- ]
109
-
110
- const posted = []
111
- const MIME = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.svg': 'image/svg+xml', '.json': 'application/json' }
112
-
113
- const json = (res, body) => { res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify(body)) }
114
-
115
- const server = createServer((req, res) => {
116
- const url = new URL(req.url, 'http://localhost')
117
- const p = url.pathname
118
-
119
- if (req.method === 'POST') {
120
- let raw = ''
121
- req.on('data', (c) => { raw += c })
122
- req.on('end', () => {
123
- let body = {}
124
- try { body = JSON.parse(raw) } catch { /* recorded as empty */ }
125
- posted.push({ path: p, body })
126
- // A saved-search save REPLACES the record, exactly as recipe-service does — so the next GET sees
127
- // what the page actually sent, and a dropped field shows up as a dropped field.
128
- const rec = /^\/portal\/api\/config\/searches\/([^/]+)\/save$/.exec(p)
129
- if (rec) RECIPES[decodeURIComponent(rec[1])] = { ...body.recipe, version: (body.recipe?.version ?? 0) + 1 }
130
- const prj = /^\/portal\/api\/config\/projects\/([^/]+)\/(validate|save)$/.exec(p)
131
- if (prj && prj[2] === 'save') {
132
- const key = decodeURIComponent(prj[1])
133
- const row = PROJECTS.find((x) => x.key === key)
134
- if (row) row.archived = body.profile?.archived === true
135
- else PROJECTS.push({ key, name: body.profile?.projectName ?? key, archived: false })
136
- }
137
- if (prj && prj[2] === 'validate') return json(res, { ok: true, errors: [], isNew: true })
138
- return json(res, { ok: true, written: true, version: 4 })
139
- })
140
- return
141
- }
142
-
143
- if (p === '/portal/api/me') return json(res, ME())
144
- // Staff-only, and answered as such: a client pass that somehow reached it would be a real finding.
145
- if (p === '/portal/admin/roster') {
146
- if (role !== 'staff') { res.writeHead(404); res.end('{}'); return }
147
- return json(res, { customers: [{ key: KEY, name: NAME }, { key: 'aurora', name: 'Aurora Interactive' }] })
148
- }
149
- if (p === '/portal/api/searches') {
150
- return json(res, {
151
- account: KEY,
152
- products: ['knockout-search', 'global-preliminary-search', 'multi-country-focus-search', 'full-country-search'].map(level),
153
- // The COMPOSER's menu, which filters retired rows out server-side. The list screen must not be
154
- // drawn from this — that is what made a retired search unrecoverable.
155
- recipes: Object.entries(RECIPES).filter(([, r]) => !r.archived)
156
- .map(([slug, r]) => ({ slug, label: r.label, base: r.base, version: r.version ?? null })),
157
- })
158
- }
159
- if (p === '/portal/api/config/searches') {
160
- return json(res, { recipes: Object.entries(RECIPES).map(([slug, r]) => ({
161
- slug, label: r.label, base: r.base, archived: Boolean(r.archived), version: r.version ?? null, updatedAt: null })) })
162
- }
163
- const one = /^\/portal\/api\/config\/searches\/([^/]+)$/.exec(p)
164
- if (one) {
165
- const slug = decodeURIComponent(one[1])
166
- if (!RECIPES[slug]) { res.writeHead(404); res.end('{}'); return }
167
- return json(res, { slug, recipe: RECIPES[slug], sha: `sha-${slug}-${RECIPES[slug].version}` })
168
- }
169
- if (p === '/portal/api/config/projects') return json(res, { projects: PROJECTS })
170
- const prj = /^\/portal\/api\/config\/projects\/([^/]+)$/.exec(p)
171
- if (prj) {
172
- const key = decodeURIComponent(prj[1])
173
- const row = PROJECTS.find((x) => x.key === key)
174
- if (!row) { res.writeHead(404); res.end('{}'); return }
175
- return json(res, { customer: KEY, customerName: NAME, project: key,
176
- overlay: { projectName: row.name, ...(row.archived ? { archived: true } : {}) },
177
- contextPack: '', inherited: {}, effective: {}, origins: {}, derived: null })
178
- }
179
- if (p === '/portal/api/config/profile') {
180
- return json(res, { account: KEY, profile: { platforms: ['gnc.com'], defaultClasses: [9], marketplaceDensity: 'Low' },
181
- readOnly: {}, contextPack: '', framework: null, derived: null })
182
- }
183
- if (p === '/portal/api/usage') {
184
- return json(res, { account: KEY, today: 0, thisMonth: 0, queued: 0, dailyRuns: 3, monthlyRuns: null, maxQueued: null, capped: role !== 'staff' })
185
- }
186
- if (p === '/portal/api/runs') {
187
- // `productName` is what the service sends and what the screen renders. Without it this row
188
- // modelled a run whose LEVEL THE REGISTRY HAS FORGOTTEN — the one class that still falls through to
189
- // the frozen `stageLabel` — so /portal/clearances rendered "Depth 4 · 2026-07-20" here. Nothing in
190
- // this file asserts on that label (it is about owner names, lifecycles and screens, not about where
191
- // the page puts things), so it passed either way. A fixture that quietly models the degenerate case
192
- // is how the next reader concludes the degenerate case is normal. Resolved, never typed.
193
- return json(res, { runs: [{ runId: 'tmp1-ion-2026-07-20', account: KEY, title: 'AQUAPLUS', markName: 'AQUAPLUS',
194
- product: 'global-preliminary-search', stageLabel: 'Depth 4',
195
- productName: reportIdentityFor('global-preliminary-search').identity,
196
- kind: 'clearance', state: 'delivered', date: '2026-07-20',
197
- band: 'Low', tone: 'clear', bands: [{ label: 'Low', tone: 'clear' }], marks: [], reportSchema: 2,
198
- held: false, report: 'report.html', step: null, stepN: null, stepTotal: null, reason: null, failedStage: null }] })
199
- }
200
- if (p === '/portal/admin/families') return json(res, { of: {}, names: {} })
201
- if (p === '/portal/api/mcp-access') return json(res, { url: null, keyUrl: null, email: null, enabled: false })
202
-
203
- const base = p.split('?')[0]
204
- const file = base === '/' || (base.startsWith('/portal') && !base.includes('.')) ? '/index.html' : base.replace(/^\/portal/, '')
205
- const full = join(DIST, file)
206
- if (!existsSync(full)) { res.writeHead(404); res.end('no'); return }
207
- res.writeHead(200, { 'content-type': MIME[extname(full)] ?? 'application/octet-stream' })
208
- res.end(readFileSync(full))
209
- })
210
-
211
- await new Promise((r) => server.listen(0, '127.0.0.1', r))
212
- const origin = `http://127.0.0.1:${server.address().port}`
213
-
214
- // ── the driver ──────────────────────────────────────────────────────────────────────────────────────
215
-
216
- const HELPERS = `
217
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
218
- const settle = async (pred, ms = 8000) => {
219
- const t0 = Date.now();
220
- while (Date.now() - t0 < ms) { if (pred()) return true; await sleep(60); }
221
- return false;
222
- };
223
- const txt = () => document.body.innerText;
224
- // tracker issue 1809 — A MISS THROWS, NAMING WHAT IT MISSED. Same defect as composer-render-check.mjs, in this
225
- // file's own copy of the helper: six sites below dereference the result immediately, so a button that
226
- // had not painted arrived as "Cannot read properties of undefined (reading 'click')".
227
- // maybeByText keeps the undefined return for the one site where absence is the thing being measured.
228
- const maybeByText = (sel, re) => [...document.querySelectorAll(sel)].find((e) => re.test(e.innerText || ''));
229
- const findByText = (sel, re) => {
230
- const el = maybeByText(sel, re);
231
- if (!el) throw new Error('no ' + sel + ' matching ' + re + ' is on screen');
232
- return el;
233
- };
234
-
235
- // Nine of this file's twelve settles discarded their return. Lines 260, 324 and 348 already read it
236
- // and name the wait; this is that shape for the rest.
237
- const mustSettle = async (pred, ms, what) => {
238
- if (!await settle(pred, ms)) throw new Error(what + ' (waited ' + ms + 'ms)');
239
- };
240
- const allByText = (sel, re) => [...document.querySelectorAll(sel)].filter((e) => re.test(e.innerText || ''));
241
- // Navigate the way the shell does — pushState plus a popstate, which is what its usePath listens for.
242
- // Retried once: a screen that navigates itself on save (the composer returns to Custom searches) can
243
- // land its own go() a beat after this one and put the old screen back.
244
- const goto = async (path) => {
245
- for (let i = 0; i < 3; i++) {
246
- history.pushState({}, '', path);
247
- window.dispatchEvent(new PopStateEvent('popstate'));
248
- await sleep(500);
249
- if (location.pathname === path.split('?')[0]) return;
250
- }
251
- };
252
- // React installs its own value setter on these elements, so assigning .value directly updates the DOM
253
- // and leaves React's copy stale — the change handler then sees the OLD value. Going through the
254
- // prototype's setter is what makes a driven control behave like a typed one.
255
- const set = (el, v) => {
256
- const proto = el.tagName === 'TEXTAREA' ? HTMLTextAreaElement
257
- : el.tagName === 'SELECT' ? HTMLSelectElement : HTMLInputElement;
258
- Object.getOwnPropertyDescriptor(proto.prototype, 'value').set.call(el, v);
259
- el.dispatchEvent(new Event(el.tagName === 'SELECT' ? 'change' : 'input', { bubbles: true }));
260
- };
261
- `
262
-
263
- /**
264
- * Pass one, run under BOTH roles: is the brand owner called by its name, everywhere?
265
- *
266
- * The sidebar is read from the DOM rather than from innerText of the page, because "Vantor Labs" also
267
- * appears in the composer's card — a whole-page search would pass on a screen where only one of the two
268
- * was right, which is the exact bug.
269
- */
270
- const NAMES_SCRIPT = `
271
- (async () => {
272
- ${HELPERS}
273
- const out = { steps: [] };
274
- await goto('/portal/clearances');
275
- if (!await settle(() => /Clearances/.test(txt()))) return { fatal: 'the shell never painted', body: txt().slice(0, 600) };
276
-
277
- // WHERE THE NAME LIVES DEPENDS ON HOW MANY OWNERS THE IDENTITY REACHES, and that is a ruling
278
- // (2026-07-28) rather than an accident. An identity that can switch gets a <select> in the rail. A
279
- // single-owner identity IS its own brand owner, so the rail block would print that name a third time
280
- // on one screen — rail, title, Account corner — and it was removed. The name did not go away; it
281
- // MOVED to the topbar Account corner, at the other end of the same bar.
282
- //
283
- // So this reads BOTH ends and asserts per identity below. Reading only the rail is how this check
284
- // spent six days reporting a client-facing defect that had been a design decision since 07-28.
285
- const rail = document.querySelector('.sidebar');
286
- const railSelect = rail && rail.querySelector('select[aria-label="Brand owner"]');
287
- out.railKind = railSelect ? 'select' : 'none';
288
- out.railOwner = railSelect
289
- ? [...railSelect.options].map((o) => o.textContent.trim()).filter((t) => t !== 'All brand owners')
290
- : [];
291
- // The rail must carry NO owner block when there is nothing to switch. Asserted positively, so a
292
- // regression back to naming the owner three times on one screen fails here too.
293
- out.railHasOwnerBlock = !!(rail && [...rail.querySelectorAll('.eyebrow')]
294
- .some((e) => e.textContent.trim() === 'Brand owner'));
295
-
296
- // The topbar Account corner: an "Account" eyebrow with the name in the element after it.
297
- const topbar = document.querySelector('.topbar');
298
- const cornerLabel = topbar && [...topbar.querySelectorAll('.eyebrow')]
299
- .find((e) => e.textContent.trim() === 'Account');
300
- out.accountCorner = cornerLabel && cornerLabel.nextElementSibling
301
- ? cornerLabel.nextElementSibling.innerText.trim()
302
- : null;
303
-
304
- // Staff open on "All brand owners", so pick one — the heading below is scoped to whoever is selected.
305
- if (railSelect) {
306
- set(railSelect, '${KEY}');
307
- await sleep(700);
308
- }
309
-
310
- // The SCREEN's heading, not the top bar's. The top bar carries an <h1> with the nav label ("Clearances")
311
- // and it comes first in the document, so a bare h1 selector reads the one place that is supposed to say
312
- // the screen's name and never the brand owner's.
313
- const h1 = document.querySelector('.main .screen h1');
314
- out.clearancesHeading = h1 ? h1.innerText.trim() : null;
315
- out.topbarHeading = (document.querySelector('.topbar h1') || {}).innerText || null;
316
-
317
- await goto('/portal/new');
318
- // tracker issue 1809 — THIS WAIT WAS IDENTITY-DEPENDENT AND SILENTLY DEAD FOR ONE OF THE THREE. "Brand owner" is
319
- // the rail switcher's eyebrow (AppShell.tsx), which a SINGLE-OWNER client never gets — that identity
320
- // reads its owner in the Account corner instead. So this timed out on every client run, and because
321
- // settle returned false without objecting it degraded into an 8-second sleep. Waits on the context
322
- // card the composer draws for every identity, which is what the next line reads.
323
- await mustSettle(() => Boolean(document.querySelector('.ctx-card')), 8000,
324
- 'the composer never painted its context card');
325
- const card = document.querySelector('.ctx-card');
326
- out.composerCard = card ? card.innerText.replace(/\\s+/g, ' ').trim() : null;
327
-
328
- // THE PROPERTY: no screen prints the slug where the name belongs. Checked over the whole document,
329
- // because the slug appearing anywhere visible is the failure — it has no business on a client screen.
330
- out.slugOnScreen = txt().includes('${KEY}');
331
- out.nameOnScreen = txt().includes('${NAME}');
332
- return out;
333
- })()
334
- `
335
-
336
- /** Pass two (client only): the two lifecycles that had no controls. */
337
- const LIFECYCLE_SCRIPT = `
338
- (async () => {
339
- ${HELPERS}
340
- const out = { steps: [] };
341
- try {
342
-
343
- // ── custom searches: list, retire, bring back ──
344
- await goto('/portal/brand/searches');
345
- if (!await settle(() => /Custom searches/.test(txt()))) return { fatal: 'Custom searches never painted', body: txt().slice(0, 600) };
346
- out.listsRetired = /Retired/.test(txt()); // drawn from the CONFIG list, not the composer menu
347
- out.noEditorFields = !/How deep should it search/.test(txt());
348
- out.retireButtons = allByText('button', /^Retire$/).length;
349
- out.bringBackButtons = allByText('button', /^Bring back$/).length;
350
- out.editButtons = allByText('button', /^Edit$/).length;
351
- out.steps.push('list painted');
352
-
353
- findByText('button', /^Retire$/).click();
354
- await sleep(200);
355
- out.confirmShown = /Confirm — retire/.test(txt());
356
- findByText('button', /Confirm — retire/).click();
357
- await mustSettle(() => allByText('button', /^Bring back$/).length === 2, 6000, 'the retired search never offered Bring back');
358
- out.retiredThenListed = allByText('button', /^Bring back$/).length === 2;
359
- out.steps.push('retired');
360
-
361
- // ...and back, which is the half that did not exist at all before.
362
- findByText('button', /^Bring back$/).click();
363
- await mustSettle(() => allByText('button', /^Retire$/).length === 1, 6000, 'the restored search never became retirable again');
364
- out.broughtBack = allByText('button', /^Retire$/).length === 1;
365
- out.steps.push('brought back');
366
-
367
- // ── the composer, opened OVER a saved search ──
368
- await goto('/portal/new?search=launch-screen');
369
- if (!await settle(() => /Edit a custom search/.test(txt()), 8000)) {
370
- return { ...out, fatal: 'the composer did not open in edit mode', body: txt().slice(0, 700) };
371
- }
372
- out.editHeading = /Edit a custom search/.test(txt());
373
- const nameInput = [...document.querySelectorAll('input')].find((i) => i.getAttribute('aria-label') === 'Name this search');
374
- out.savePrefilled = nameInput ? nameInput.value : null;
375
- const noteInput = [...document.querySelectorAll('input')].find((i) => i.getAttribute('aria-label') === 'Note about this custom search');
376
- out.notePrefilled = noteInput ? noteInput.value : null;
377
- // The stored scope came back as a draft: one territory, one class.
378
- out.territoryHydrated = /United States/.test(txt());
379
- out.steps.push('hydrated');
380
-
381
- const saveBtn = maybeByText('button', /Save changes/);
382
- out.saveChangesLabel = Boolean(saveBtn);
383
- if (saveBtn) saveBtn.click();
384
- await mustSettle(() => /Custom searches/.test(txt()), 8000, 'the custom search list never returned after saving');
385
- out.returnedToList = /Custom searches/.test(txt());
386
- out.steps.push('saved');
387
-
388
- // ── projects: create ──
389
- await goto('/portal/brand/projects');
390
- await mustSettle(() => /New project/.test(txt()), 8000, 'the New project control never appeared');
391
- out.projectPath = location.pathname;
392
- out.projectCreateOffered = /New project/.test(txt());
393
- out.archivedProjectListed = /Old engagement/.test(txt());
394
- out.archivedProjectBadged = /Archived/.test(txt());
395
- out.bringBackOnProject = allByText('button', /^Bring back$/).length >= 1;
396
- out.projectArchiveOnRow = allByText('button', /^Archive$/).length >= 1;
397
- findByText('button', /New project/).click();
398
- // "Project name" since tracker issue 1958's copy pass, which shortened the label from "What is this
399
- // project called?". A driver that opens the real screen is the one thing that notices a rename like
400
- // this, and it noticed: the whole lifecycle failed here rather than anywhere near the cause.
401
- await mustSettle(() => /Project name/.test(txt()), 8000, 'the project name prompt never appeared');
402
- const pname = [...document.querySelectorAll('input')].find((i) => /EU launch 2027/.test(i.placeholder || ''));
403
- set(pname, 'Second engagement');
404
- await sleep(200);
405
- const keyBox = [...document.querySelectorAll('input')].find((i) => /eu-launch-2027/.test(i.placeholder || ''));
406
- out.keyDerived = keyBox ? keyBox.value : null;
407
- findByText('button', /Create project/).click();
408
- // Creating OPENS the new project — everything a project can carry is inherited until it is overridden,
409
- // so landing in its settings is the next thing anyone wants. Asserted, because it is a decision.
410
- await mustSettle(() => /Anything left blank is inherited/.test(txt()), 8000, 'the inheritance note never appeared');
411
- out.landedInEditor = /Anything left blank is inherited/.test(txt());
412
- out.steps.push('project created');
413
-
414
- // Back out the way a person would — the breadcrumb, not the address bar.
415
- findByText('button', /^Projects$/).click();
416
- await mustSettle(() => /New project/.test(txt()), 8000, 'the New project screen never reopened');
417
- out.projectListed = /Second engagement/.test(txt());
418
-
419
- // ...and the composer must not OFFER an archived one. The wire carries it now, so this is the only
420
- // thing standing between a retired engagement and a clearance filed under it.
421
- await goto('/portal/new');
422
- // Same identity-dependent wait as above, same cure.
423
- await mustSettle(() => Boolean(document.querySelector('.ctx-card')), 8000,
424
- 'the composer never painted its context card on return');
425
- const projectSelect = [...document.querySelectorAll('select')].find((s) => s.getAttribute('aria-label') === 'Project');
426
- out.composerProjectOptions = projectSelect ? [...projectSelect.options].map((o) => o.textContent.trim()) : null;
427
- return out;
428
- } catch (e) {
429
- // Without this the driver's own mistakes arrive as an empty object and read as twenty screen
430
- // failures, which is a slower way to find a typo than being told there was one.
431
- return { ...out, fatal: 'driver threw: ' + (e && e.stack ? e.stack : String(e)), body: txt().slice(0, 700) };
432
- }
433
- })()
434
- `
435
-
436
- // ── chrome ──────────────────────────────────────────────────────────────────────────────────────────
437
-
438
- const userDir = mkdtempSync(join(tmpdir(), 'lifecycle-check-'))
439
- const chrome = spawn('google-chrome', [
440
- '--headless=new', '--disable-gpu', '--no-sandbox', '--hide-scrollbars',
441
- `--user-data-dir=${userDir}`, '--window-size=1280,900',
442
- '--remote-debugging-port=0', `${origin}/portal/clearances`,
443
- ], { stdio: ['ignore', 'pipe', 'pipe'] })
444
-
445
- let devtools = ''
446
- const wsUrl = await new Promise((resolve, reject) => {
447
- // 60s, not 20s. The 20s budget was set when CI ran on a paid 4-vCPU larger runner; this workflow now
448
- // runs on the standard 2-vCPU ubuntu-latest, where a cold Chrome start has no margin in 20s — it
449
- // failed once in the first 6 runs there with 'chrome did not report a devtools endpoint'.
450
- //
451
- // WHAT THE NUMBERS DO NOT SHOW, stated because the tempting claim is wrong: this is NOT established
452
- // as a regression from the runner change. The same step failed 6 times in 34 runs on ubuntu-latest-m
453
- // — but all 6 landed inside one 16-minute window on 2026-08-10, across several branches at once,
454
- // which is an infrastructure incident and not a rate. Outside it: 0 in 28. So the evidence is
455
- // consistent with the smaller runner being tighter and does not demonstrate it; n is small on both
456
- // sides. The budget goes up because 20s for a cold Chrome start is thin on any 2-vCPU box, not
457
- // because a measurement proved causation.
458
- //
459
- // And on timeout, SAY WHAT CHROME SAID — the bare message named a symptom and no cause, so the one
460
- // thing the next reader needs was the one thing it withheld.
461
- const t = setTimeout(
462
- () => reject(new Error(`chrome did not report a devtools endpoint within 60s. Its stderr was:\n${devtools || '(nothing)'}`)),
463
- 60000,
464
- )
465
- chrome.stderr.on('data', (c) => {
466
- devtools += c
467
- const m = devtools.match(/ws:\/\/[^\s]+/)
468
- if (m) { clearTimeout(t); resolve(m[0]) }
469
- })
470
- })
471
-
472
- const ws = new WebSocket(wsUrl)
473
- let id = 0
474
- const pending = new Map()
475
- ws.addEventListener('message', (e) => {
476
- const msg = JSON.parse(e.data)
477
- if (msg.id && pending.has(msg.id)) { pending.get(msg.id)(msg); pending.delete(msg.id) }
478
- })
479
- await new Promise((r) => ws.addEventListener('open', r))
480
- const send = (method, params = {}) => new Promise((r) => { const i = ++id; pending.set(i, r); ws.send(JSON.stringify({ id: i, method, params })) })
481
-
482
- const { result: targets } = await send('Target.getTargets')
483
- const page = targets.targetInfos.find((t) => t.type === 'page')
484
- const { result: sess } = await send('Target.attachToTarget', { targetId: page.targetId, flatten: true })
485
- const sessionId = sess.sessionId
486
- const cmd = (method, params) => new Promise((r) => { const i = ++id; pending.set(i, r); ws.send(JSON.stringify({ id: i, sessionId, method, params })) })
487
- const evalIn = (expr) => cmd('Runtime.evaluate', { expression: expr, awaitPromise: true, returnByValue: true })
488
- const value = async (expr) => (await evalIn(expr)).result?.result?.value ?? null
489
-
490
- /** A full reload, so `me` is re-fetched under the role the stub is now serving. */
491
- const reload = async () => {
492
- await cmd('Page.navigate', { url: `${origin}/portal/clearances` })
493
- await new Promise((r) => setTimeout(r, 1800))
494
- }
495
-
496
- await new Promise((r) => setTimeout(r, 1500))
497
-
498
- role = 'client'
499
- await reload()
500
- const asClient = await value(NAMES_SCRIPT)
501
-
502
- role = 'staff'
503
- await reload()
504
- const asStaff = await value(NAMES_SCRIPT)
505
-
506
- role = 'multi'
507
- await reload()
508
- const asMulti = await value(NAMES_SCRIPT)
509
-
510
- role = 'client'
511
- await reload()
512
- const life = await value(LIFECYCLE_SCRIPT)
513
-
514
- if (shotAt) {
515
- await evalIn(`(async () => { history.pushState({}, '', '/portal/brand/searches'); window.dispatchEvent(new PopStateEvent('popstate')); await new Promise(r => setTimeout(r, 700)); })()`)
516
- const shot = await cmd('Page.captureScreenshot', { format: 'png', captureBeyondViewport: true })
517
- const data = shot.result?.result?.data ?? shot.result?.data
518
- if (data) writeFileSync(shotAt, Buffer.from(data, 'base64'))
519
- }
520
-
521
- chrome.kill()
522
- server.close()
523
- await new Promise((r) => setTimeout(r, 400))
524
- if (!keep) { try { rmSync(userDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 }) } catch { /* a stray profile dir is not a test result */ } }
525
-
526
- // ── verdict ─────────────────────────────────────────────────────────────────────────────────────────
527
-
528
- const fail = []
529
- const ok = (cond, msg) => { if (!cond) fail.push(msg) }
530
-
531
- // Which end of the bar must name the owner, per identity. A switcher identity reads it in the rail; a
532
- // single-owner identity reads it in the topbar Account corner. Both are asserted, and so is the
533
- // ABSENCE of the other — a name in both places at once is the repetition the 07-28 ruling removed.
534
- const SWITCHES = { client: false, staff: true, 'multi-account client': true }
535
-
536
- for (const [who, out] of [['client', asClient], ['staff', asStaff], ['multi-account client', asMulti]]) {
537
- if (!out || out.fatal) { fail.push(`${who}: ${out?.fatal ?? 'the driver returned nothing'}`); continue }
538
- if (SWITCHES[who]) {
539
- ok(out.railOwner.some((t) => t.includes(NAME)),
540
- `${who}: the rail switcher does not name the brand owner — read ${JSON.stringify(out.railOwner)}`)
541
- } else {
542
- ok((out.accountCorner ?? '').includes(NAME),
543
- `${who}: the topbar Account corner does not name the brand owner — read ${JSON.stringify(out.accountCorner)}`)
544
- ok(!out.railHasOwnerBlock,
545
- `${who}: the rail carries a brand-owner block for an identity with nothing to switch — the name is printed three times on one screen`)
546
- }
547
- ok(out.clearancesHeading === NAME, `${who}: the Clearances heading reads ${JSON.stringify(out.clearancesHeading)}, not ${JSON.stringify(NAME)}`)
548
- ok(out.composerCard?.includes(NAME), `${who}: the New clearance context card does not name the brand owner — read ${JSON.stringify(out.composerCard)}`)
549
- ok(out.nameOnScreen, `${who}: the brand owner's name is nowhere on the composer`)
550
- ok(!out.slugOnScreen, `${who}: the account KEY "${KEY}" is printed on screen where the name belongs`)
551
- }
552
- // The regression this whole change is for: every login must agree, word for word.
553
- const headings = [['client', asClient], ['staff', asStaff], ['multi-account client', asMulti]]
554
- .filter(([, o]) => o && !o.fatal)
555
- for (const [who, out] of headings) {
556
- ok(out.clearancesHeading === headings[0][1].clearancesHeading,
557
- `the same brand owner reads "${out.clearancesHeading}" to a ${who} and "${headings[0][1].clearancesHeading}" to a ${headings[0][0]}`)
558
- }
559
-
560
- // The multi-account client is the ONLY identity whose switcher is populated from `me` rather than from
561
- // the roster, and it is the login the bug was reported from. Its options must be NAMES.
562
- if (asMulti && !asMulti.fatal) {
563
- ok(asMulti.railKind === 'select', 'a client with several grants must get the brand-owner switcher')
564
- ok(asMulti.railOwner.includes(NAME) && asMulti.railOwner.includes(NAME2),
565
- `the switcher lists keys rather than names for a multi-account client: ${JSON.stringify(asMulti.railOwner)}`)
566
- ok(!asMulti.railOwner.some((t) => t === KEY || t === KEY2),
567
- `a raw account key is in the brand-owner pulldown: ${JSON.stringify(asMulti.railOwner)}`)
568
- // Ordered by what is READ. "Aurora Interactive" before "Vantor Labs" — which is also the opposite of
569
- // the order the grants list them in, so a pass-through would show.
570
- ok(asMulti.railOwner[0] === NAME2, `the switcher is not sorted by name: ${JSON.stringify(asMulti.railOwner)}`)
571
- }
572
-
573
- if (!life || life.fatal) {
574
- fail.push(`lifecycle: ${life?.fatal ?? 'the driver returned nothing'}`)
575
- } else {
576
- ok(life.listsRetired, 'Custom searches does not list a retired search — it is drawn from the wrong list, and retiring is one-way again')
577
- ok(life.noEditorFields, 'the standalone saved-search editor is back on this screen')
578
- ok(life.retireButtons >= 1, 'no Retire control on a saved-search row')
579
- ok(life.bringBackButtons >= 1, 'no Bring back control on a retired row')
580
- ok(life.editButtons >= 1, 'no Edit control — there is no way into the composer from the list')
581
- ok(life.confirmShown, 'Retire fired without a confirm step')
582
- ok(life.retiredThenListed, 'a retired search left the list instead of being greyed and kept')
583
- ok(life.broughtBack, 'a retired search could not be brought back')
584
- ok(life.editHeading, 'the composer did not say it was editing a custom search')
585
- ok(life.savePrefilled === 'Launch screen', `the save name did not prefill with the label — read ${JSON.stringify(life.savePrefilled)}`)
586
- ok(life.notePrefilled === 'For the EU launch team.', `the note did not survive into the editor — read ${JSON.stringify(life.notePrefilled)}`)
587
- ok(life.territoryHydrated, 'the saved scope did not come back as levers — United States is not on screen')
588
- ok(life.saveChangesLabel, 'the footer offered Save rather than Save changes while editing')
589
- ok(life.returnedToList, 'saving an edit did not return to Custom searches')
590
- ok(life.projectCreateOffered, 'Projects offers no way to create one')
591
- ok(life.archivedProjectListed, 'an archived project is not listed — hiding it is what made archiving one-way')
592
- ok(life.archivedProjectBadged, 'an archived project is listed without being marked as archived')
593
- ok(life.bringBackOnProject, 'an archived project has no Bring back control')
594
- ok(life.composerProjectOptions?.includes('EU launch'), `the composer does not offer the live project: ${JSON.stringify(life.composerProjectOptions)}`)
595
- ok(!life.composerProjectOptions?.includes('Old engagement'),
596
- 'the composer offers an ARCHIVED project — archiving means the engagement is over, and the engine refuses the run at admission')
597
- ok(life.projectArchiveOnRow, 'Projects offers no Archive on the row')
598
- ok(life.keyDerived === 'second-engagement', `the project key did not follow the name — read ${JSON.stringify(life.keyDerived)}`)
599
- ok(life.landedInEditor, 'creating a project did not open it — its settings are the next thing anyone wants')
600
- ok(life.projectListed, 'the created project is not in the list')
601
- }
602
-
603
- // ── what reached the wire ───────────────────────────────────────────────────────────────────────────
604
-
605
- const saves = posted.filter((p) => /\/config\/searches\/.+\/save$/.test(p.path))
606
- const edited = saves.find((p) => /launch-screen/.test(p.path))
607
- ok(saves.length >= 3, `expected a retire, a restore and an edit to reach the server — saw ${saves.length}`)
608
- ok(edited != null, 'the composer never saved the search it was editing')
609
- if (edited) {
610
- // THE SILENT REGRESSION THIS EXISTS TO CATCH. A save replaces the record; the composer has no field
611
- // for `extras`, so if it does not carry the prior record through, retiring the old editor quietly
612
- // destroyed data on the first re-save.
613
- ok(edited.body.recipe?.extras?.emailTable === true,
614
- `re-saving from the composer dropped extras: ${JSON.stringify(edited.body.recipe?.extras)}`)
615
- ok(edited.body.recipe?.notes === 'For the EU launch team.', 'the note did not survive the save')
616
- ok(edited.body.expectedVersion === 3, `an edit must name the version it was based on, sent ${JSON.stringify(edited.body.expectedVersion)}`)
617
- ok(!/\/searches\/launch-screen-\d/.test(edited.path), 'the edit was written to a NEW slug — a rename must not fork the record')
618
- }
619
- const retire = saves.find((p) => p.body.recipe?.archived === true)
620
- const restore = saves.find((p) => p.body.recipe?.archived === false)
621
- ok(retire != null, 'no save carried archived:true')
622
- ok(restore != null, 'no save carried an EXPLICIT archived:false — archive state is sticky against omission, so a restore needs it')
623
- ok(retire?.body?.recipe?.scope != null || retire?.body?.recipe?.label != null,
624
- 'the retire posted a stripped record rather than the whole recipe with one flag flipped')
625
-
626
- const projectSaves = posted.filter((p) => /\/config\/projects\/.+\/save$/.test(p.path))
627
- const created = projectSaves.find((p) => p.body.profile?.projectName === 'Second engagement')
628
- ok(posted.some((p) => /\/config\/projects\/.+\/validate$/.test(p.path)), 'a project was written without being validated first')
629
- ok(created != null, 'the new project never reached the server')
630
- ok(created == null || created.body.profile?.name === undefined,
631
- 'a project must NEVER carry `name` — that is the customer identity the self-exclusion check anchors on')
632
-
633
- console.log(JSON.stringify({ asClient, asStaff, asMulti, life, posted: posted.map((p) => p.path) }, null, 2))
634
- if (fail.length) {
635
- console.error(`\n${fail.length} problem(s):`)
636
- for (const f of fail) console.error(` ✗ ${f}`)
637
- process.exit(1)
638
- }
639
- console.log('\nOK — one name for a brand owner under both logins; searches and projects manageable from their own screens.')