Public
Clark View source: flea medication reminder, 8th of every month
clark-viewsource
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

source-gtb

A Clark View source that reminds to give flea medication on the 8th of every month, and nothing else. Every row carries the same fixed text.

Built on the shared source SDK: protocol v1 over rpc.ts, bearer-authenticated, SQLite owned by this val.

Agent data entry

AGENTS.md owns the add-entry: shortcut for individual custom events, including normalization, conflict handling, and transactional verification. Update it alongside changes to storage or reader selection. It uses direct SQLite access; it is separate from the authoritative monthly reminders.rebuild operation.

Storage

Unlike Moon/Lunar, which store a JSON payload column and derive display text in code, flea_medication_reminders stores main_text and sub_text as real columns — every row's reminder text is identical, so there is nothing a payload blob would buy here:

CREATE TABLE flea_medication_reminders( date_key TEXT PRIMARY KEY, main_text TEXT NOT NULL, sub_text TEXT NOT NULL, starts_at INTEGER NOT NULL, expires_at INTEGER NOT NULL, fetched_at TEXT NOT NULL )

The existing database received an additive nullable expires_at INTEGER column; all existing rows were backfilled with starts_at + 3600. New databases use the NOT NULL schema above. Every write must supply expiry; missing/invalid windows are rejected by the SDK on read. Reads never migrate storage.

Files

FileRole
lib/schedule.tsPure arithmetic: monthly date generation, noon-in-zone-to-UTC conversion. No storage, clock or network.
gtbSource.tsSource definition, offset policy, item text, flea_medication_reminders storage and rebuildSchedule.
rpc.tsHTTP entry: bearer authentication around serveSource.
check.tsContract, schedule, DST, offset, protocol, auth and storage checks. Disposable rows are removed.

Settings and items

Settings are exactly {} — there is nothing to select, and the parent's browser form renders no controls. One item is returned: the next reminder on or after the reader's current civil date.

{ "id": "gtb-2026-10-08", "mainText": "Give Flea medication", "subText": "Gemma, Bron, Tilka 🐈🐈‍⬛🐈", "caption": null, "emphasized": false, "startsAt": 1791486000, "expiresAt": 1791489600 }

(noon Pacific on 2026-10-08, stored as 19:00 UTC — PDT is in effect that date)

startsAt (stored in starts_at) is Unix seconds for local noon in America/Los_Angeles on the reminder date, precomputed and stored in UTC at write time — it does not depend on the reader's timezone. caption is null, unlike Moon's PEAK or Lunar's DAY 15: noon Pacific is the actual reminder instant here, not a whole-day or astronomical event, so the widget renders it as a real clock time in the reader's own zone. expiresAt is stored in expires_at, exactly one hour after the start for rebuilt reminders. It controls lifecycle and refresh timing and is never displayed. The source uses SDK snapshot 12-main and emits no legacy wire timestamp; the parent owns compatibility for older clients.

utcOffsetSeconds: null (used only to pick the reader's "today" for selecting the next row) falls back to America/Los_Angeles, matching Moon/Lunar.

Populating and extending the schedule

The write operation reminders.rebuild replaces the next count monthly reminders authoritatively, starting after after (YYYY-MM-DD):

{ "protocolVersion": 1, "sourceKey": "gtb", "operation": "reminders.rebuild", "payload": { "count": 12, "after": "2026-09-09" } }

The initial 12 months (2026-10-08 through 2027-09-08) were seeded this way at deployment. There is no automatic reseed job — unlike Lunar's annual interval, this schedule is a fixed formula with nothing upstream to poll for, but it still needs a fresh reminders.rebuild call with a later after date before the stored window is exhausted. Add an interval later if ongoing unattended extension is wanted; it was left out here as unbuilt scope, not an oversight.

Deployment

  1. Set SOURCE_GTB_V1_TOKEN on this val.
  2. Register in plusjade/app-clarkview: rpc.ts's endpoint, source key gtb, protocol version 1, and a credential reference holding the same bearer value configured independently in the parent. Then assign it to a device.
  3. Run check.ts after any change. With the token set it also covers the authenticated mount; without it, everything but that one assertion still runs.
  4. Run http-check.ts after merging to verify the deployed authenticated descriptor and nonempty window feed at null and extreme timezone offsets.