Latest Results
feat(mllp-client)!: tls now boolean | TlsOptions; defaults to TLS-on
Two breaking changes to MllpClientOptions.tls, both grounded in the
fact that HL7v2 messages commonly carry PHI and "secure by default"
is the right stance for a healthcare client.
(1) Reshape: `tls?: boolean | MllpClientTlsOptions`
============================================================
Previously: `tls?: MllpClientTlsOptions` — the implicit "object
provided → TLS on" rule. This was hiding the wire-protocol intent
behind structural type duck-typing and was the root cause of
Copilot's review finding (a `tls.insecure: true` config that
silently downgraded to plain TCP on Workers, because the rule "tls
is on iff tls is set" was applied independently per-runtime with
no shared activator).
Now: `tls: true` is the explicit "use TLS with defaults" form,
matching the mainstream pattern (MongoDB, pg). The object form
still works for custom config. The core normalises `tls: true`
to `tls: {}` before reaching the adapter, so `MllpConnectParams.tls`
stays `MllpClientTlsOptions | undefined` and adapters see only
the object shape.
(2) Default: TLS-on
============================================================
Previously: `tls` undefined → plain TCP.
Now: `tls` undefined → TLS on (same as `tls: true`). Plain TCP
requires explicit `tls: false`.
Migration: every call site that relied on "no tls field → plain
TCP" must now pass `tls: false`. Call sites that already passed
a tls object are unchanged.
Implementation
============================================================
- `MllpClientOptions.tls`: type widened to `boolean | TlsOptions`
with `@default true`. JSDoc explains the four shapes (default,
true, object, false) and when to use each.
- `MllpClient` constructor: normalises the union to
`TlsOptions | undefined` for adapters. `false` → undefined;
`true | undefined` → {} (TLS-on, no config); object passes
through.
- `validateOptions`: accepts `boolean | object | undefined`; rejects
anything else with INVALID_INPUT.
- Workers adapter: removes the now-redundant `params.tls.insecure`
check from the secureTransport calculation (the core normalises
before reaching here; `params.tls` is truthy iff TLS should
negotiate). `rejectUnsupportedTlsMaterial` still rejects
ca/cert/key/passphrase/insecure as before — Workers can't honour
them.
- Node adapter: no logic change; still receives `params.tls` as
`TlsOptions | undefined`.
Test surface
============================================================
- All Node + core tests that assumed plain-TCP-by-default now pass
`tls: false` explicitly. ~50 mechanical edits via awk script.
- New core construction tests verify the default-true behaviour:
one asserts `received.tls` is set when no tls field is passed;
another asserts it's undefined when `tls: false` is passed.
- Workers happy-path and CONNECTION_REFUSED tests pass `tls: false`
to connect to the plain-TCP ack server.
- Workers harness `SendRequest.tls` widened to accept boolean.
Total: 56 Node + 63 workerd = 119 tests, all green. Type-check
clean, build clean.
Changeset bumps `@glion/mllp-client` from minor to major.
https://claude.ai/code/session_01MvBEUcGkRokNw2GWYVHADgclaude/mllp-client-workers-runtime refactor(mllp-client): migrate Workers tests to Hono's wrangler.unstable_dev pattern
Replaces @cloudflare/vitest-pool-workers with the same testing
pattern Hono uses (`runtime-tests/workerd/` in honojs/hono): a
small harness Worker exposes the adapter over HTTP, Node-side
vitest spawns it via wrangler.unstable_dev, and tests assert on
the HTTP response.
Why:
- vitest-pool-workers' coverage instrumentation depends on
node:inspector/promises which workerd doesn't ship; the workers
project couldn't run under pnpm test:coverage.
- The pool also failed to boot reliably across CI runners and
inside containerised environments, leaving us unable to verify
Workers behaviour in CI.
- Hono's pattern works on standard ubuntu-latest GH Actions
runners and is the de-facto standard for multi-runtime libraries.
Test surface (6 tests):
- Happy-path round-trip: harness connects via cloudflare:sockets,
writes the MLLP frame, parses the AA from the Node-side ack
server, returns it over HTTP.
- CONNECTION_REFUSED when the TCP target is closed.
- INVALID_INPUT for tls.ca, tls.cert, tls.key, tls.passphrase.
Files:
- test/workers/harness.ts (new) — harness Worker exposing POST /send
- test/workers/adapter.test.ts (rewritten) — Node-side tests via
wrangler.unstable_dev
- test/workers/wrangler.toml — points at harness.ts; compat date
bumped to 2025-09-23
- test/workers/global-setup.ts — unchanged (TCP ack server)
- vitest.config.ts — drops the cloudflareTest plugin; both projects
are now plain vitest. Bun can load the config cleanly so
vitest.bun.config.ts is no longer needed.
- vitest.bun.config.ts — deleted
- package.json — drops @cloudflare/vitest-pool-workers, adds wrangler
Generic CI scaffolding (so future packages get this for free):
- turbo.json declares test:bun, test:cf, test:deno tasks
- Workspace package.json adds test:bun / test:cf / test:deno scripts
that delegate to turbo
- .github/workflows/ci.yml: e2e-bun renamed to testing-bun and now
runs `pnpm test:bun` (turbo dispatches across all opted-in
packages); new testing-cf job runs `pnpm test:cf` with
NODE_OPTIONS=--max_old_space_size=8192
- @glion/cli gets a test:bun script wrapping its existing e2e
command, so the renamed testing-bun job continues to cover it
Adding multi-runtime tests to a new package is now: define
test:bun / test:cf / test:deno in that package.json. CI picks it up
automatically; no workflow edits.
https://claude.ai/code/session_01MvBEUcGkRokNw2GWYVHADgclaude/mllp-client-workers-runtime feat!: sunset legacy empty-mode; remove loadConfig from @glion/builder
BREAKING CHANGE: Empty fields, repetitions, and components are now always
represented with `children: []`. The `experimental.emptyMode` setting (which
toggled between "legacy" full-skeleton-with-empty-string-leaf and "empty"
empty-children-array) is removed entirely.
Why this matters now
====================
Every @glion/builder factory call (f(), r(), c()) was routing through
loadConfig() from @glion/config to decide which AST shape to produce. That
imported cosmiconfig + Node-only modules (fs, path, os, crypto, module, url)
into every consumer's bundle:
@glion/mllp-client → @glion/ack → @glion/builder
→ @glion/config (loadConfig)
→ cosmiconfig
→ fs, path, os, crypto, ...
This broke runtime portability: Workers and Deno bundles dragged in Node
builtins they couldn't resolve, even though the harness/runtime never invoked
config-loading code. The architectural fix is to remove disk-based config
discovery from leaf factory functions; sunsetting `legacy` mode is the
cleanest way to do that, since it was the only thing the lookup gated.
Migration
=========
Consumers branching on placeholder leaves of empty fields:
-if (field.children[0]?.children[0]?.children[0]?.value === "") { ... }
+if (field.children.length === 0) { ... }
Config files carrying `experimental.emptyMode` are now rejected by the
@glion/config schema validator. Remove that block from .hl7v2rc.* files.
@glion/util-query's `value()` helper already returns `null` for empty
children — most consumers using it need no change.
What changed
============
- @glion/builder: dropped @glion/config dependency entirely; f()/r()/c() now
always emit `children: []` for empty inputs.
- @glion/parser: dropped emptyMode plumbing from parser.ts/processor.ts/
types.ts. parseHL7v2's settings argument no longer accepts
experimental.emptyMode.
- @glion/config: removed ExperimentalSchema from the settings schema. The
`loadConfig`/`loadConfigAsync` API is unchanged but no longer exposes any
experimental keys.
- @glion/util-visit: deleted the test-helpers + legacy/empty fixture configs;
the visit() implementation was already mode-agnostic.
- @glion/jsonify: updated the runtime serializer to materialize empty fields/
repetitions as "" (preserving the existing JSON output shape — empty
children now flow through here, where previously legacy always produced a
full skeleton with "" leaves).
Side effects
============
- @glion/builder/dist/index.js no longer contains `import "@glion/config"`;
consumers' bundles shrink (cosmiconfig + dependencies dropped).
- The Workers and Deno runtime adapters of @glion/mllp-client (PR #615,
#616) bundle cleanly without `nodejs_compat` polyfills; the cosmiconfig
bundle leak is resolved.
Tests
=====
All affected packages green:
- @glion/builder: 25 tests
- @glion/parser: 56 tests (parser.legacy.test.ts + processor.legacy.test.ts
deleted; their behaviour is now the default)
- @glion/config: 34 tests
- @glion/util-query: 224 tests
- @glion/util-visit: 31 tests (visit.legacy.test.ts deleted; redundant)
- @glion/jsonify: 12 tests
- @glion/hl7v2: 9 tests
The pre-existing @glion/cli config-discover.test.ts flake (.js vs .ts) is
unrelated and was already failing on main before this PR.
https://claude.ai/code/session_01MvBEUcGkRokNw2GWYVHADgclaude/sunset-legacy-empty-mode Latest Branches
0%
claude/mllp-client-workers-runtime +12%
claude/sunset-legacy-empty-mode 0%
dependabot/npm_and_yarn/vitest/coverage-v8-4.1.5 © 2026 CodSpeed Technology