Upgrade Harper to v5#2
Conversation
…inPath fix - Add harper@^5.0.28 as explicit dependency (was runtime-provided global) - Add @harperfast/integration-testing and typescript dev dependencies - Regenerate package-lock.json with --os=linux --cpu=x64 --include=optional to include bufferutil/utf-8-validate/node-gyp-build for Linux CI - Add integrationTests/twilio-sms.test.ts covering optInStatus POST endpoint and PhoneNumbers REST table (Harper layer only; Twilio credentials not available in CI — SMS sending not tested) - Apply harperBinPath fix (ERR_PACKAGE_PATH_NOT_EXPORTED workaround) - Add .github/workflows/integration-tests.yml with Node 22/24/26 matrix - Update dev script: harperdb dev → harper dev - Branding: "HarperDB" → "Harper" in README prose; update install command to npm i -g harper; fix description in package.json - Add tsconfig.json Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
| ok([200, 201, 204].includes(res.status), `expected 2xx for opt-out, got HTTP ${res.status}`); | ||
|
|
||
| // Verify the record was written to the PhoneNumbers table | ||
| const record = await authFetch(ctx, `/PhoneNumbers/${encodeURIComponent(from)}`); |
There was a problem hiding this comment.
Bug: Verification GET uses encodeURIComponent but the record key was written as a raw phone number
tables.PhoneNumbers.put({ phoneNumber: From, ... }) stores the key as the literal From value (e.g. +15551110001). The verification fetch here uses encodeURIComponent(from) → /PhoneNumbers/%2B15551110001, which is a different URL path than /PhoneNumbers/+15551110001. Other Harper repos (puppeteer-component, realtime-pubsub-example) consistently use encodeURIComponent for all REST path operations. The same asymmetry affects lines 135, 150, and 165.
Either:
- Remove
encodeURIComponenthere (if Harper normalises%2B→+in path lookups), or - Use
encodeURIComponentin the earlier direct PUT tests too (lines 68, 78, 84) — this is the recommended pattern.
| const record = await authFetch(ctx, `/PhoneNumbers/${encodeURIComponent(from)}`); | |
| const record = await authFetch(ctx, `/PhoneNumbers/${from}`); |
| @@ -0,0 +1,180 @@ | |||
| import { suite, test, before, after } from 'node:test'; | |||
| import { strictEqual, ok, deepStrictEqual } from 'node:assert/strict'; | |||
There was a problem hiding this comment.
Cleanup: deepStrictEqual is imported but never used
deepStrictEqual is imported on this line but does not appear anywhere else in the file. Remove it to keep the import clean.
| import { strictEqual, ok, deepStrictEqual } from 'node:assert/strict'; | |
| import { strictEqual, ok } from 'node:assert/strict'; |
|
Code review finding on unchanged file
Suggested fix: function updateStatus(data) {
const { OptOutType, From } = data;
if (!OptOutType || !From) return;
const optOut = OptOutType.toLowerCase();
// ...
}This finding is on |
|
|
||
| void test('Harper starts successfully and root is reachable', async () => { | ||
| const res = await authFetch(ctx, '/'); | ||
| ok([200, 400, 404].includes(res.status), `Unexpected status ${res.status}`); |
There was a problem hiding this comment.
Smoke test accepts HTTP 400 — a request error masquerading as success
A 400 response means Harper rejected the request (bad input, config error, routing issue). Accepting it as a passing smoke test means startup failures that cause malformed responses would go undetected. The smoke test should only accept 200 (or at most 404 for a missing root route).
| // See also https://aka.ms/tsconfig/module | ||
| "module": "nodenext", | ||
| "target": "esnext", | ||
| "types": [], |
There was a problem hiding this comment.
Cleanup: tsconfig.json sets "types": [] but the test file uses Buffer (line 25)
With "types": [], ambient Node.js type declarations are excluded, so tsc --noEmit would fail on the Buffer.from(...) call in authFetch. At runtime this is fine (Node native TS stripping ignores tsconfig), but the tsconfig is misleading and would block any future type-checking step.
Either add @types/node to devDependencies and include "node" in "types", or add a // @ts-ignore / use btoa() instead of Buffer.from(...).toString("base64").
…false-pass, and updateStatus null guard Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Summary
harper@^5.0.28as an explicit dependency (was previously a runtime-provided global; noharperdbwas ever listed inpackage.json)integrationTests/twilio-sms.test.tscovering thePOST /optInStatusendpoint (opt-in/opt-out keyword handling) and thePhoneNumbersREST table (CRUD operations).github/workflows/integration-tests.ymlwith Node.js 22/24/26 matrix onubuntu-latestharperBinPathfix: AppliedcreateRequire-based bin path resolution to bypassERR_PACKAGE_PATH_NOT_EXPORTED(harper'sexportsmap only exposes".")package-lock.jsonwith--os=linux --cpu=x64 --include=optionalto includebufferutil,utf-8-validate, andnode-gyp-buildfor Linux CIHarperDB→Harperin README prose;npm i -g harperdb→npm i -g harper;harperdb dev→harper devtsconfig.jsonMigration items
harperdb→harperpackage renameharper@^5Table.get()returns plain/frozen recordsresources.jsuses.put()only, no.get()blob.save()→saveBeforeCommitwasLoadedFromSource()→.loadedFromSourcechild_processusagepostis an instance method onoptInStatusclassharperdb dev→harper devdevscriptTest scope and known limitations
Twilio credentials are not available in CI. Tests validate the Harper integration layer only:
POST /optInStatusendpoint routing and data persistence (OptOutTypekeyword →PhoneNumberstable write)GET /PhoneNumbersREST table interfaceLocal test note:
npm run test:integrationcannot run on macOS without loopback alias configuration (sudo npx harper-integration-test-setup-loopback). CI (ubuntu-latest) supports the full127.0.0.0/8range natively and is the test gate.npm scope
The package is currently unscoped (
twilio-sms). If it should be published under the Harper npm scope, that migration is manual and flagged for human decision (per upgrade plan §11.1).🤖 Generated with Claude Code