Add v4 hook-registration + thrown-hook envelope repro#104
Conversation
Mirrors CM's hook registration pattern in a sibling repro script to
the existing v4-routing-repro. The fixture:
- config.yaml declares jsResource:resources.js (auto-load) + the
OAuth plugin with one static provider literally named "oauth"
(kept as a decoy for routing regressions).
- resources.js calls `registerHooks({ onResolveProvider: ... })`
at module top level. The hook returns a generic provider config
for any oac-* providerName.
The script hits /oauth/oac-test-config/login and asserts the redirect
went to the URL the hook returned — empirical proof that on harperdb
v4 the hook DOES fire when registered from a sibling resources.js.
Why this matters. We previously suspected (from a v5 fixture attempt
on oauth main) that the same registerHooks-from-resources.js pattern
suffers from module isolation between resources.js's import of
@harperfast/oauth and the plugin's own pluginModule load. CM
demonstrably works in production, but on harper v5 the same pattern
broke. This script narrows that to a v4-vs-v5 component-loader
behavior split — and confirms that CM's setup is correct for v4.
For Dawson's actual 500: the hook IS registered on v4 (this script
proves it), so the 500 must come from inside CM's handleResolveProvider
itself — most likely a SecretManager.decrypt failure or DB error.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a second test case to v4-hook-repro: when the hook throws, the
plugin surfaces the harperdb-v4 error envelope
HTTP/1.1 200 OK
Content-Type: application/json
{"status":500,"body":{"error":"Failed to resolve OAuth provider"}}
which is byte-for-byte what Dawson pasted in Slack on 2026-05-22. We
were reading that string as an HTTP 500 the whole time; it's actually
an HTTP 200 with the plugin's intended status nested in the body —
harperdb v4 doesn't translate a Resource's `return { status: 500, ... }`
to an HTTP 500 (harper v5 does).
This finalizes the repro:
case 1: hook fires and returns config → 302 to the hook's URL
case 2: hook throws → v4 envelope with 'Failed to resolve OAuth
provider' as the inner body
For Dawson's investigation: the actual throw on his system is inside
CM's handleResolveProvider — SecretManager.decrypt, OrganizationOAuthConfig.get,
or SecretManager.create. To narrow further, CM needs try/catch + log
inside that function on his deployment.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Reviewed; no blockers found. |
|
Reviewed; no blockers found. |
|
Closing — superseded by HarperFast/central-manager#372 (merged). #372 adds structured try/catch logging + rethrow inside CM's real This repro already paid out its real value by being run, not merged — it proved two things that are now banked:
Its only residual value would be a plugin-side regression guard ("does The script remains on branch 🤖 Posted by Claude on Nathan's behalf |
Summary
Adds `scripts/v4-hook-repro.mjs` to the v1.x line. Sibling of the existing `scripts/v4-routing-repro.mjs` (merged in #103). Where the routing-repro covers static-provider URL parsing, this one covers the `onResolveProvider` hook — registered from a sibling `resources.js`, the pattern CM uses.
Two test cases:
Both pass on `harperdb 4.7.19` + the in-tree plugin source. The script:
Two findings landed in memory during this work
v4 vs v5 Resource return-shape translation differs: `return { status: 500, body: ... }` from a Resource method surfaces as HTTP 500 on harper v5 but as HTTP 200 with the envelope as the JSON body on harperdb v4. We had been reading Dawson's reported string as an HTTP 500 the whole time; it's actually a 200-with-envelope.
Latent v5 regression in `registerHooks` from `resources.js` (observed during PR Add integration test: OAuth Resource path-segment routing #102 work, not yet formally repro'd): hooks register correctly on harperdb v4 but silently never fire on harper v5. When CM eventually migrates to v5, the documented multi-tenant SSO pattern breaks.
Companion PR
HarperFast/central-manager#372 adds the log-and-rethrow inside CM's `handleResolveProvider`, which combined with this repro should let Dawson actually see the underlying exception on his next failing request.
Test plan
🤖 Generated with Claude Code