Skip to content
sergiodxaPublic

About

Resources

Code of conduct

Security policy

Stars

16 stars

Watchers

0 watching

Forks

Repository files navigation

sergiodxa/monorepo

The products, sites and open-source toolkit of Sergio Xalambrí, in one repository.

This is everything I build and run: a monitoring service, a feed reader, a book storefront, an identity provider, my personal site, and the 100+ TypeScript packages they're made of. Every app runs on Cloudflare Workers with Remix v3, every package is published to npm under @sdxc, and all of it shares one toolchain, one set of conventions and one test suite.

Use the apps, borrow the packages, or read the code to see how a full product is put together on the edge.

Products

Know your site is down before your customers do. Uptime watches HTTP endpoints, DNS records, TCP ports, SSL certificates and scheduled jobs, runs multi-step flow checks, and alerts your team through the channels it already uses. It includes public status pages, maintenance windows, response-time analytics, team access and a REST API. Try it on any URL from the landing page, no account needed.

Follow any site that publishes RSS or Atom and read everything in one place. Each feed is refreshed at the pace it actually publishes, posts are searchable with a real query syntax, and posts you want to come back to stay on a saved shelf. Paid plans add labels, filter rules, the full article fetched into the app, and an MCP endpoint so your agent can read along too.

The home of the React Router OAuth2 Handbook: a free sample chapter, live pricing, and an upgrade path for readers who started with an earlier edition.

Sites and Services

App What it does Live at
blog My personal site and CMS: articles, tutorials and bookmarks, with Webmentions and ActivityPub so the fediverse can follow along sergiodxa.com
r3-auth The OAuth 2.0 and OpenID Connect provider every app here signs in with: GitHub or email and password auth.sergiodxa.com
sdxc-site Documentation, guides and changelog for the @sdxc packages sdxc.dev

In the Workshop

Projects under active development, published here as they take shape.

  • auth-saas: a multi-tenant identity platform where every customer gets their own isolated OpenID Connect provider on their own domain.
  • pkmn: a monster-collecting game engine that keeps content, rules and presentation apart, so anyone can build their own game by writing data.
  • demo: a job board built for a Remix v3 conference talk, runnable fully offline.

Packages

The packages are the building blocks the apps above are made of, extracted so anyone can use them. They are small, focused and written to the spec they implement, built on fetch, Request/Response and Web Crypto so most run unchanged on Cloudflare Workers, Bun, Deno and Node. Fallible operations return a typed Result instead of throwing.

A few of them, in the shape they share: declare something once as typed data, then map behavior onto it.

@sdxc/authz: permissions as a typed catalog of abilities, granted by roles and checked synchronously.

import { abilities, ability, allow, context, definePolicy, fact } from "@sdxc/authz";
import { isSuccess } from "@sdxc/result";

let catalog = abilities({
	article: {
		read: ability({ context: context<{ article: Article }>("article"), deniedAs: "notFound" }),
		update: ability({ context: context<{ article: Article }>("article") }),
	},
});

let policy = definePolicy(catalog, {
	facts: { actor: fact<{ id: string }>() },
	everyone: [
		allow("article.read", { when: { op: "eq", field: "article.published", value: true } }),
	],
	roles: {
		author: [
			allow("article.update", { when: { op: "eq", field: "article.authorId", path: "actor.id" } }),
		],
		admin: { inherits: ["author"], grants: [allow("*")] },
	},
});

let access = policy.for({ roles: ["author"], facts: { actor: user } });
if (isSuccess(access)) access.data.can(catalog.article.update, { article }); // true for their own

@sdxc/jobs: background jobs declared in one map, with typed payloads, cron schedules, retries and a pluggable queue.

import { createJobDispatcher, createJobHandler, job, jobs } from "@sdxc/jobs";
import * as cloudflare from "@sdxc/jobs/cloudflare";
import * as s from "remix/data-schema";

let catalog = jobs({
	sendWelcome: job({ input: s.object({ userId: s.string() }) }),
	digests: { daily: job({ cron: "0 8 * * *" }) },
});

export default createJobHandler(catalog.sendWelcome, async (ctx) => {
	await sendWelcomeEmail(ctx.input.userId); // ctx.input is typed from the schema
});

let dispatcher = createJobDispatcher({ logger, queue: cloudflare.queue(() => env.QUEUE) });
dispatcher.map(catalog.sendWelcome, () => import("./jobs/send-welcome"));

await dispatcher.enqueue(catalog.sendWelcome, { userId: user.id });

@sdxc/mcp: an MCP server for your agent-facing API, served over stateless Streamable HTTP from any fetch handler.

import * as s from "@sdxc/json-schema";
import { createHandler, tool, tools, ToolError } from "@sdxc/mcp";

let toolset = tools({
	search: tool("search_documents", {
		description: "Searches published documents by title, excerpt and tags.",
		input: s.object({ query: s.string() }),
		annotations: { readOnlyHint: true },
	}),
});

let mcp = createHandler({ name: "documents", version: "1.0.0" });

mcp.tools.map(toolset.search, async (ctx) => {
	let documents = await search(ctx.input.query);
	if (documents.length === 0) throw new ToolError("Nothing matched. Try a broader query.");
	return documents;
});

export default { fetch: mcp.fetch };

Versions are calendar dates (2026.9.4), released daily from whatever changed, and packages released together are pinned to each other so they always work together. Guides and API references live at sdxc.dev.

Everything at Once

Package Description
@sdxc/kit The sdxc command line: start a Remix v3 app, generate its files, copy UI components into it and upgrade it

Authentication and Identity

Package Description
@sdxc/auth OAuth 2.0 and OpenID Connect client for any runtime that speaks Request and Response
@sdxc/authz Authorization from a typed catalog of abilities, additive roles and guards, answered from loaded facts
@sdxc/crypto Web Crypto primitives — hashing, HMAC, tokens, TOTP, AES-GCM — plus scrypt passwords
@sdxc/jwt JWT payload classes and the keys that sign them
@sdxc/openpgp OpenPGP (RFC 9580) signing and verification on Web Crypto: armor, keys, cleartext and detached signatures
@sdxc/passkey Passkeys on both sides: a one-call WebAuthn browser API and a relying party for it
@sdxc/password-policy Password acceptance checks: length, common and breached passwords, similarity to the account, and reuse
@sdxc/saml SAML 2.0 service provider: verify a signed assertion and the metadata around it
@sdxc/scim SCIM 2.0 resources, filters, PATCH operations, cursor pagination, discovery documents and events
@sdxc/scitt SCITT Signed Statements, Receipts and a SCRAPI client for registering with a Transparency Service
@sdxc/well-known Typed documents for well-known URIs: security.txt, WebFinger, NodeInfo, OAuth and OIDC metadata, JWKS and more

Security and Abuse Prevention

Package Description
@sdxc/captcha CAPTCHA verification for Turnstile, hCaptcha and reCAPTCHA, with router middleware, widgets and a test provider
@sdxc/email-address Email address parsing and normalization, disposable-domain detection and mail-server checks
@sdxc/email-auth Parse and evaluate a domain's email-authentication DNS policies: DMARC, SPF, MTA-STS, TLS-RPT, BIMI and DKIM
@sdxc/honeypot Honeypot form fields with a signed render timestamp, router middleware and a remix/component component
@sdxc/outbound Check, follow and read URLs a stranger chose: public hosts on every redirect, one deadline, bounded bodies
@sdxc/privacy-pass Privacy Pass for origins: PrivateToken challenges, token redemption and Blind RSA verification
@sdxc/rate-limit Adapter-based rate limiting with standard response headers
@sdxc/security-headers Typed Content-Security-Policy, Permissions-Policy and response security headers, with middleware
@sdxc/spam Spam scoring for user-generated content, with local rules, reputation checks and a trainable classifier

HTTP, APIs and Routing

Package Description
@sdxc/api-client Base class for clients of a remote HTTP API
@sdxc/assets-middleware Router middleware that resolves a document's stylesheets and client entry once per request and publishes them on the request context as ctx.assets
@sdxc/bracket-params Read and write nested query strings and form data with bracket syntax, validated by a Standard Schema
@sdxc/catch-response-middleware Router middleware that turns a thrown Response into the request's response
@sdxc/digest-fields RFC 9530 Content-Digest and Repr-Digest, plus the RFC 3230 Digest header
@sdxc/doh Typed DNS over HTTPS lookups
@sdxc/get-client-ip Read the client IP from a Cloudflare Workers request
@sdxc/http Response builders, content negotiation and HTTP caching
@sdxc/http-signatures Sign and verify HTTP requests with RFC 9421 message signatures or draft-cavage-12
@sdxc/idempotency Idempotency-Key requests: replay the first response, refuse conflicting reuse
@sdxc/ip IPv4 and IPv6 addresses and ranges as value objects that classify against the IANA special-purpose registries
@sdxc/json-patch Apply, validate and diff RFC 6902 JSON Patch documents
@sdxc/lazy-route Maps a route to a module imported on the first request that reaches it
@sdxc/link-header Parse and stringify RFC 8288 Link headers and RFC 9264 link sets
@sdxc/location URL-like Location class for URL paths without an origin
@sdxc/mcp MCP servers over stateless Streamable HTTP
@sdxc/merge-patch Apply, diff and read RFC 7396 JSON Merge Patch documents
@sdxc/no-www-middleware Router middleware that permanently redirects a www. hostname to the apex domain
@sdxc/openapi Build, serve and check OpenAPI 3.1 documents from typed operations
@sdxc/pagination Offset and keyset pagination with Link headers
@sdxc/problem RFC 9457 problem details and catalogs of an API's problem types
@sdxc/rdap Domain registration data over RDAP: expiry, status, registrar and nameservers from the registry
@sdxc/response Response builders for JSON APIs and redirects
@sdxc/server-timing Server-Timing measurements written to a response header
@sdxc/structured-fields Parse and serialize RFC 9651 structured HTTP field values
@sdxc/trace-context W3C Trace Context: traceparent and tracestate, one trace per invocation, propagated to jobs and outbound requests
@sdxc/trailing-slash-middleware Router middleware that redirects every path to one canonical trailing-slash form
@sdxc/uri-template Expand, parse and match RFC 6570 URI Templates at all four levels
@sdxc/user-agent Read a User-Agent string into its browser, engine, operating system and device
@sdxc/webhooks Standard Webhooks signing, verification and replay guards, plus Security Event Token push and poll delivery

Jobs, Messaging and Product Infrastructure

Package Description
@sdxc/attribution Campaign parameters, click identifiers and referrers, kept as a visitor's first and last touch
@sdxc/backoff Retry delay schedules with growth, a ceiling, free attempts and seedable jitter
@sdxc/billing Vendor-neutral billing with pluggable providers and a webhook endpoint
@sdxc/cron Cron schedules with zone-aware occurrences and descriptors
@sdxc/expression Boolean conditions over a context, stored as typed JSON or written as text, with operators you add
@sdxc/flags Feature flag evaluation implementing the OpenFeature specification
@sdxc/flags-engine Flag evaluation engine: typed targeting rules, percentage splits and pluggable stores
@sdxc/health Dependency health checks in the application/health+json format, and a reader for other services' reports
@sdxc/jmap A typed JMAP client: session, batched method calls with result references, mail and contacts, blobs and push
@sdxc/jobs Declared background jobs dispatched over a pluggable queue backend
@sdxc/logger One wide event per Worker invocation, attached at the router and the job dispatcher
@sdxc/mail Transactional email with pluggable transports
@sdxc/messaging Send one portable message to Slack, Discord, Teams, Google Chat, Telegram, WhatsApp, ntfy, Pushover and more
@sdxc/newsletter Vendor-neutral newsletter subscriber lists with Buttondown and Kit providers
@sdxc/web-push Web Push from Workers: RFC 8291 encryption, VAPID signing, subscription checks and a browser subscribe helper

Content, Feeds and the Social Web

Package Description
@sdxc/activitypub ActivityPub protocol logic: vocabulary, actors, discovery, a verified inbox and signed delivery
@sdxc/atom Atom 1.0 feed parser and builder
@sdxc/diagram Mermaid sequence, class, state and flowchart diagrams to SVG, with a markdown visitor and a component
@sdxc/distill Distill the article out of a web page: fetch under bounds, score, sanitize
@sdxc/feed One feed API over RSS, Atom and JSON Feed, with conditional fetching and autodiscovery
@sdxc/highlight Syntax highlighting as tokens, with a markdown visitor that paints code blocks
@sdxc/html Read a served page: fetch or parse HTML, then query it by role and accessible name
@sdxc/json-feed JSON Feed 1.1 builder and parser
@sdxc/markdown GitHub Flavored Markdown: parse to a typed AST, transform it, write it back
@sdxc/math TeX math to MathML Core, with a markdown visitor and a component
@sdxc/microformats Parse, read and write microformats2
@sdxc/micropub Read Micropub requests into typed operations and build the spec's responses
@sdxc/opml Read and write OPML subscription lists
@sdxc/robots Read, write and evaluate robots.txt and robots directives
@sdxc/rss RSS 2.0 feed builder and parser
@sdxc/search Full-text search over SQLite tables: safe query parsing, FTS5 and LIKE matching, ranking, highlighting
@sdxc/seo Canonical URLs, schema.org builders and head metadata
@sdxc/sitemap Sitemap generation and parsing
@sdxc/webmention Receive, verify, discover and send Webmentions
@sdxc/websub WebSub subscriber and publisher: subscribe, verify intent and signatures, notify hubs

Formats and Parsers

Package Description
@sdxc/cbor CBOR (RFC 8949) decoding and deterministic encoding, bounded for untrusted input
@sdxc/codemod Source-to-source edits of JavaScript and TypeScript imports and declarations, changing only the edited ranges
@sdxc/csv Read and write RFC 4180 CSV, with a streaming writer and formula neutralization
@sdxc/epub Build EPUB 3.3 publications from XHTML chapters, checked against what epubcheck rejects
@sdxc/font TrueType font reader: glyph lookup, metrics, kerning, outlines and line layout
@sdxc/icalendar Read and write iCalendar documents, with recurrence rules and time zones
@sdxc/jscalendar Read, validate and write RFC 8984 JSCalendar, expand recurrences, and convert to and from iCalendar
@sdxc/jscontact Read, validate and write RFC 9553 JSContact Cards, and convert them to and from vCard and jCard
@sdxc/jsdoc Read JSDoc out of source text into a JSON documentation model
@sdxc/json-canonical RFC 8785 JSON Canonicalization Scheme: one byte-exact serialization for hashing and signing JSON
@sdxc/json-pointer Parse, stringify, get and set RFC 6901 JSON Pointers
@sdxc/json-schema Schema builders that validate like remix/data-schema and describe themselves as JSON Schema 2020-12
@sdxc/jsonc JSON with comments and trailing commas, parsed with errors that point at the line and column
@sdxc/jsonl JSON Lines reading and writing, streamed with a bounded buffer and line numbers in every failure
@sdxc/jsonpath RFC 9535 JSONPath queries over JSON values, with normalized paths and every function extension
@sdxc/messageformat Unicode MessageFormat 2 parser and formatter shaped like Intl.MessageFormat
@sdxc/png PNG encoder and decoder over Web Streams, with no WebAssembly
@sdxc/qr QR Code Model 2 encoder with optimal segmentation, SVG path data and a remix/component renderer
@sdxc/raster 2D canvas for Workers: antialiased paths, gradients, masks and text, out to PNG
@sdxc/semver SemVer 2.0.0 parsing, precedence ordering and range-free version comparisons
@sdxc/xml XML parser and serializer for RSS-style feeds
@sdxc/yaml YAML reading and writing over a documented subset
@sdxc/zip Streaming ZIP archive writer with CRC-32, storing every entry uncompressed
@sdxc/zone-file Read and write RFC 1035 DNS zone files, with the record data codec for every typed record

Cloudflare

Package Description
@sdxc/cache Cache contract with adapters for memory and Cloudflare KV
@sdxc/cloudflare-mocks In-memory Cloudflare binding mocks for tests
@sdxc/cloudflare-pricing Cloudflare Developer Platform list prices, one module per service
@sdxc/data-table-d1 Remix Data Table adapter for Cloudflare D1
@sdxc/data-table-sqlstorage Remix Data Table adapter for Durable Object SQL
@sdxc/file-storage-r2 File storage adapter for Cloudflare R2
@sdxc/hostname Cloudflare for SaaS custom-hostname client: register, poll and delete customer domains
@sdxc/session-storage-kv Session storage adapter for Cloudflare KV
@sdxc/workers-cache Cloudflare cache tags, purging and cache-status reads

UI and Internationalization

Package Description
@sdxc/i18n Language detection and MessageFormat 2 translators for Remix routers and remix/component
@sdxc/icons Lucide icons for Remix UI
@sdxc/lazy-frame A remix/component frame that loads once the reader scrolls near it or opens its dialog
@sdxc/u Tailwind-like Remix UI styling utilities
@sdxc/ui Remix v3 UI component library

Foundations

Package Description
@sdxc/cli Build command-line tools with generated help, prompts bound to flags, tasks and a test harness
@sdxc/data-model Models over remix/data-table tables with scopes, async callbacks and typed meta fields
@sdxc/database-middleware Middleware that publishes a remix/data-table database as ctx.db on a request, a job or a command
@sdxc/dates Zone-aware date operations with Intl-only formatting
@sdxc/duration Typed duration strings converted to milliseconds or seconds
@sdxc/iife Immediately invoke a callback where an expression is needed
@sdxc/random Seeded and system random streams with integer, float, pick and shuffle draws, and resumable state
@sdxc/result Result type for error handling
@sdxc/sample Seeded generation of believable people, places, prose, numbers and identifiers
@sdxc/spec Executable specification runner for .spec files
@sdxc/strings Inflection, Chicago title case, slugs and grapheme-safe text
@sdxc/typeid TypeID values: a UUID and the prefix naming it
@sdxc/types Shared TypeScript types
@sdxc/uuid Branded UUID type with validation and generation
@sdxc/validate Standard Schema validation utilities

How It's Built

  • One stack everywhere. Remix v3 for routing and server-rendered UI, Cloudflare Workers for hosting, D1 and Durable Object SQLite for data, Queues for background jobs.
  • Packages first. When two apps need the same thing, it becomes a package with its own README, tests and npm release. The apps stay thin and product-focused.
  • Tested against the real platform. Tests run under Vitest, and tests that touch KV, D1 or R2 run inside workerd with real Cloudflare bindings instead of hand-written stubs.
  • Decisions on the record. Significant architectural choices are written up as Architecture Decision Records, so the reasoning travels with the code.
  • The platform does the work. Dialogs, popovers and disclosures use native HTML, and JavaScript is reserved for what the browser can't do on its own.

Working on the Repository

You need Bun and Node.js 22.5 or newer.

bun install
bun check
bun run test

bun check formats, lints and type checks everything in one pass, and bun run test runs every test. To run an app locally, cd apps/<name> and bun run dev; each app's README lists its setup. The conventions the codebase follows are written down in AGENTS.md.

License

The packages are MIT licensed. The applications are licensed under the O'Saasy License: you can self-host them for personal or internal use, but not offer them as a competing hosted service. Names, logos and site content are not covered by either license. See LICENSE.md for the details.

About

Resources

Code of conduct

Security policy

Stars

16 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages