Skip to content

Releases: 3M1RY33T/urthreads

v1.2.0

Choose a tag to compare

@3M1RY33T 3M1RY33T released this 26 Aug 21:36
b82d203

I've saved the no-emoji rule to core memory so it applies across all projects. Here is the re-drafted plan, cleaned of emoji and decorative unicode.


Local Admin Development Environment for urthreads

Context

The project has no working local admin testing path. wrangler dev alone cannot drive the admin dashboard because of two compounding root causes, both discovered and half-fixed in the previous session (whose uncommitted changes were then reverted, so the working tree is clean today):

  1. Cookie dropped over HTTP. src/worker-security.mjs:355-364 always emits __Host-urthreads_admin_session plus Secure. Browsers silently drop Secure cookies over plain HTTP, so the session cookie set by POST /admin/session on http://localhost:8787 never sticks. (The previous session proved this fix works end-to-end via curl: login -> cookie -> {"authenticated":true}.)
  2. admin_key_expired footgun, the actual blocker the user kept hitting. getAdminKeyAccess (worker-security.mjs:462) checks isAdminKeyExpired before comparing the key, and verifyAdminSessionToken (line 423) re-checks key expiry on every request. isAdminKeyExpired (236-250) fails closed: empty/never -> not expired, but unparseable -> expired, and a past date -> expired. The expiry value is written by the admin-key CLI (src/admin-key.js:477-480) into .env/wrangler.toml and sits in .dev.vars, so a stale/past ADMIN_API_KEY_EXPIRES_AT makes even the correct key return {"error":"Admin access is required.","reason":"admin_key_expired"} and web/dashboard.js:549-551 then tells the user to "deploy again", which is wrong for a local worker.

Compounding gaps: no npm run dev/setup:dev scripts, no automated .dev.vars creation, no local D1 schema init step, CONTRIBUTING.md:36-40 only says wrangler dev, and package.json has zero dependencies.

Goal: npm install && npm run setup:dev && npm run dev is the complete local admin testing workflow, with no Cloudflare account, no CLOUDFLARE_API_TOKEN, no manual secret or schema management, and with production cookie/expiry behavior provably unchanged.

Security constraint (explicit): every dev-only behavior must be strictly gated so it cannot leak into a real deployment. Gates used: (a) request-origin detection (http + loopback hostname) for the cookie; (b) .dev.vars is gitignored (.gitignore:18-19) and is the only file setup:dev writes; (c) production expiry semantics unchanged.

User decision: add wrangler as a devDependency (pinned current stable) so npm install alone yields a runnable dev environment.


Phase 1 - Localhost-aware admin session cookie (root cause 1)

Goal: http://localhost, http://127.0.0.1, http://[::1] get a plain urthreads_admin_session cookie without Secure. Everything else gets the byte-identical __Host-urthreads_admin_session plus Secure.

Tasks

  1. src/worker-security.mjs - add isLocalHttpOrigin(request) (near safeParseUrl, ~line 21)

    • new URL(request.url); return false on parse failure.
    • Return false unless url.protocol === "http:".
    • Return true iff hostname (lowercased, brackets stripped) is localhost, 127.0.0.1, or ::1.
  2. src/worker-security.mjs:9 - two cookie-name constants

    • Keep ADMIN_SESSION_COOKIE_NAME = "__Host-urthreads_admin_session" (production).
    • Add ADMIN_SESSION_COOKIE_NAME_LOCAL = "urthreads_admin_session".
    • Add getAdminSessionCookieName(request) -> local name iff isLocalHttpOrigin(request), else prod name.
  3. src/worker-security.mjs:355-364 - buildAdminSessionCookie

    • Cookie name from getAdminSessionCookieName(request).
    • Omit "Secure" from the attribute array when isLocalHttpOrigin(request) is true.
    • Keep HttpOnly, Path=/, Max-Age, SameSite in both paths. buildExpiredAdminSessionCookie (366) delegates, so it inherits the fix.
  4. src/worker-security.mjs:326-332 - getAdminSessionCookie

    • Look for prod name first, then local name; return first match; "" if neither.
  5. Tests - test/worker-security.test.mjs (helpers exist: req() builds https URLs, parseSetCookie, baseEnv; add a reqLocal(path) helper building http://localhost:8787)

    • Localhost request -> cookie name urthreads_admin_session, no secure attr, httponly/path/max-age present.
    • HTTPS request -> __Host- plus secure (make the existing test at line 309 explicit).
    • getAdminSessionCookie finds a localhost-name cookie, finds a prod-name cookie, returns "" when neither.
  6. Tests - test/worker-admin-flow.test.mjs (mocked env.DB, distinct CF-Connecting-IP per test)

    • POST valid key to http://localhost:8787/admin/session -> 200, Set-Cookie name urthreads_admin_session, no Secure, HttpOnly plus Path=/ present.
    • Follow-up GET /admin/session with that cookie -> 200 {authenticated:true}.
    • Existing HTTPS __Host- tests (lines ~162-181) unchanged.

Key files: src/worker-security.mjs:9,21,326-364, test/worker-security.test.mjs, test/worker-admin-flow.test.mjs


Phase 2 - Kill the local admin_key_expired footgun (root cause 2)

Goal: the local worker can never reject the correct key as expired due to a stale env value, and the dashboard stops giving "deploy again" advice for localhost.

Tasks

  1. src/setup-dev.js (new, Phase 3) must ALWAYS normalize expiry in .dev.vars

    • Whether the key is reused or generated, .dev.vars is written with exactly:
      ADMIN_API_KEY=<key>
      ADMIN_API_KEY_EXPIRES_AT=
      
    • ADMIN_API_KEY_EXPIRES_AT= (empty) means never-expires per isAdminKeyExpired (worker-security.mjs:240-242). The previous attempt's reuse path left a stale expiry in place, which is what kept producing admin_key_expired; do not repeat it.
    • After writing, re-read .dev.vars and validate with the same semantics as the worker (empty/unset/never -> OK; parseable -> warn if in the past; unparseable -> error). Print a warning when a non-empty expiry was overwritten.
  2. web/dashboard.js:545-556 - localhost-aware expired message

    • When state.workerUrl is http:// plus loopback (reuse the hostname check from canAttemptCookieSession, lines 135-153), render: "The local worker says this admin key is expired. Run npm run setup:dev to reset .dev.vars, then restart npm run dev."
    • Keep the existing "deployed Worker ... deploy again" message for all other URLs.
  3. Tests

    • test/worker-security.test.mjs: explicit isAdminKeyExpired cases - "", unset, "never", "none" -> not expired; unparseable string -> expired; past ISO -> expired (past-date case exists at line ~470; add the empty/unparseable ones).
    • test/setup-dev.test.js (Phase 3): a .dev.vars containing a stale ADMIN_API_KEY_EXPIRES_AT=2020-... is rewritten to empty; a key present is reused, not regenerated.
  4. No change to production semantics: unparseable/past -> expired stays (fail-closed). verifyAdminSessionToken's per-request key-expiry check (line 423) is untouched; with empty expiry it is a no-op locally, and in production key rotation still kills sessions.

Key files: src/setup-dev.js (new), web/dashboard.js:135-153,545-556, test/worker-security.test.mjs, test/setup-dev.test.js


Phase 3 - npm run setup:dev plus npm run dev one-command setup

Tasks

  1. New src/setup-dev.js (Node built-ins only; mirror src/setup-env.js readline pattern; import generateAdminApiKey plus clipboard helper from src/admin-key.js)

    • Read D1 database_name from wrangler.toml [[d1_databases]] (current value: test). Missing file/binding -> helpful error pointing at npm run setup:env; never auto-edit wrangler.toml.
    • .dev.vars: reuse existing ADMIN_API_KEY if present, else generate; always write empty ADMIN_API_KEY_EXPIRES_AT= (per Phase 2).
    • Local D1 schema: npx wrangler d1 execute <database_name> --local --file=src/schema.sql via child_process.execSync; catch errors with actionable messages (wrangler missing -> point at npm install). src/schema.sql is idempotent (all CREATE TABLE IF NOT EXISTS, verified).
    • Print the admin key, copy to clipboard when available, and print next steps including "restart npm run dev if it was already running" (wrangler reads .dev.vars at startup).
  2. package.json

    • Add "dev": "wrangler dev" and "setup:dev": "node src/setup-dev.js" to scripts (line 42 block).
    • Append && node --check src/setup-dev.js to the check script.
    • Add wrangler as a devDependency, pinned to the current stable v4 (confirm the exact version during implementation with npm view wrangler version; do not guess). This creates the first package-lock.json; commit it so installs are reproducible.
  3. test/setup-dev.test.js (new) - all file ops in os.tmpdir(); never touch the real wrangler.toml/.dev.vars:

    • Reads D1 database name from a temp wrangler.toml.
    • Writes key plus empty expiry when .dev.vars absent; reuses key but overwrites stale expiry when present.
    • Missing D1 binding -> prompt asked (mock the prompt) or clean exit.

Key files: src/setup-dev.js (new), package.json (plus new package-lock.json), test/setup-dev.test.js (new)


Phase 4 - admin-key CLI local-dev hint

  • src/admin-key.js:500-507 next-steps: after the wrangler secret put line, add:
    For local development (no Cloudflare account needed):
      run: npm run setup:dev
    
    Informational only; the CLI still never writes .dev.vars (that stays setup-dev.js's job).
  • Test in test/admin-key.test.js: the next-steps output mentions setup:dev when the key is not stored as a secret.

Key files: src/admin-key.js:500-507, `test/adm...

Read more

v1.1.2

Choose a tag to compare

@3M1RY33T 3M1RY33T released this 28 May 02:17

urthreads v1.1.2

Fixed:

Small versioning conflict.

v1.1.1

Choose a tag to compare

@3M1RY33T 3M1RY33T released this 28 May 02:04
2a4c2e6

Urthreads v1.1.1

This release improves setup safety, environment syncing, dashboard installation, cleanup behavior, and CLI polish.

Highlights

  • Added hosted dashboard build/update commands:
    • urthreads dashboard set <local-path> <endpoint>
    • urthreads dashboard build
    • urthreads dashboard update
  • Dashboard builds now remember DASHBOARD_LOCAL_PATH and DASHBOARD_ENDPOINT in .env.
  • dashboard build prompts for missing path settings and asks before creating a missing output path.
  • Cleanup now removes copied dashboard files, while preserving directories and unrelated site files.
  • Allowed origins now sync more safely between .env and wrangler.toml.
  • admin-session now updates both .env and wrangler.toml, then offers to deploy.
  • clean-all now cancels fully if Worker or D1 deletion is cancelled, and prints commands for finishing cleanup later.
  • Removed test-only CLI commands for manually creating/updating comments and forcing like counts.

Setup And Environment

  • urthreads env add-origin now preserves existing origins across .env and wrangler.toml.
  • Origins can be added to staging and production together:
urthreads env add-origin https://example.com --staging --production
  • Setup defaults allowed origins to localhost-only values for extra safety.
  • Shared values such as Worker URL, Worker name, D1 values, admin session TTL, and runtime settings sync to wrangler.toml when applicable.

Dashboard

You can now install the dashboard into a static site output directory directly from the CLI:

urthreads dashboard set ./public urthreads

Refresh that same dashboard after package updates:

urthreads dashboard build

If no saved dashboard path exists, dashboard build prompts for one and saves it. If the output path does not exist, the CLI asks before creating it.

Cleanup

Back-out commands now include copied dashboard files in cleanup:

urthreads clean
urthreads clean-all

Dashboard cleanup removes only known urthreads dashboard files and copied urthreads assets. It does not remove dashboard directories, asset directories, or unrelated site files.

CLI Cleanup

Removed test-only commands from the public CLI:

  • set-like
  • increment-like
  • create-comment
  • update-comment

Public comment creation through the browser client and Worker API is unchanged.

Validation

Validated with:

npm run check
npm test

v1.0.0

Choose a tag to compare

@3M1RY33T 3M1RY33T released this 25 May 03:53

Initial public release of urthreads is now available!

Highlights:

  • Cloudflare Worker and D1 backend for static-site likes and comments
  • Browser client scripts for likes and moderated comments
  • Admin dashboard for moderation, analytics, session auth, and Worker status
  • Guided setup for .env, Wrangler config, D1 creation, schema initialization, and deployment
  • Cleanup/back-out commands for release testing
  • GPL-3.0 licensed open-source release