Embeddable customer-facing widget for Paw OS pockets. The frontend side of the full-stack decision loop Palantir cannot offer: events on a brand-embedded widget flow into a Pocket, Instinct nudges the owner, approved actions flow back.
- Zero framework dependencies.
- Under 10 KB gzipped, enforced by
scripts/check-size.mjs. - Mounts on every
[data-paw-print]element in the DOM atDOMContentLoaded.
<script src="https://pp.pocketpaw.dev/widget.js"></script>
<div data-paw-print="pp_your_widget_id"
data-endpoint="https://runtime.pocketpaw.dev/api/v1"></div>Point data-endpoint at your paw-runtime install. Omit it in production and the bundle falls back to the default host.
The host element emits native CustomEvents that embedders can listen for:
pp.ready— spec loaded and DOM rendered.pp.event— a user action (button click, form submit) was accepted by the server.detail.result.fabric_object_idis set when anevent_mappingturned it into a Fabric object.pp.error— spec load or event post failed.detail.reasonholds the message.
bun install # or npm install
bun run build # produces dist/widget.js
bun run test:size # enforces the 10KB gzipped budget
bun run test # Playwright integration testsPlaywright serves tests/fixtures/ over HTTP and mocks the paw-runtime API, so you do not need the full stack running locally to iterate on the bundle.
customer_refis a SHA-256 hash of a random seed stored inlocalStorage. No email, no IP, no PII.- Widget never uses
innerHTMLwith spec-provided content. All strings land viatextContent. Images requirehttp:orhttps:URLs; other schemes are rejected. - Button
hrefvalues are URL-validated before opening in a new tab withnoopener,noreferrer. - The server enforces the origin allowlist + rate limits; the client is a renderer, not a security boundary.
See LICENSE.