@altimist/did-publisher
v0.3.0
Published
Mounts altimist-id's Resolver API on altimist-web's resolver-surface paths (DID document, revocations, team issuer keys). Phase 2a of F-010.
Readme
@altimist/did-publisher
Proxy altimist-id's Resolver API to the public did:web URLs (<handle>.altimist.com/.well-known/did.json, altimist.com/users/<handle>/did.json, altimist.com/.well-known/revocations.json, altimist.com/.well-known/team-issuers/<team>.json). Two consumption shapes:
routeResolverRequest()— single fetch handler dispatcher for Cloudflare Workers / Bun.serve / Deno.serve. The recommended path (ADR-012 Option W).didJsonHandler/revocationsHandler/teamIssuersHandler— Next.js App Router route-handler factories. v0.1 API; retained for any consumer that wants to mount per-route handlers under file-based routing.
Decision rationale in ADR-011 (original placement on altimist-web, never deployed) and ADR-012 (Cloudflare Worker placement, current direction).
Install
npm install @altimist/did-publisherUsage — Cloudflare Workers (recommended)
// src/index.ts
import { routeResolverRequest } from '@altimist/did-publisher';
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const response = await routeResolverRequest(request, {
origin: env.ALTIMIST_ID_ORIGIN, // e.g. "https://id.altimist.ai"
apex: env.ALTIMIST_ID_APEX, // "altimist.com" / "staging.altimist.com"
});
return response ?? new Response('Not Found', { status: 404 });
},
};routeResolverRequest() returns:
- A
Responsefor the three resolver-surface URLs. nullfor everything else — the caller decides what to do (404, fall through to another origin, etc).
Usage — Next.js App Router (v0.1 API)
In a Next.js project that owns *.altimist.com, mount three route handlers:
// app/.well-known/did.json/route.ts
import { didJsonHandler } from '@altimist/did-publisher';
export const GET = didJsonHandler({
origin: process.env.ALTIMIST_ID_URL!, // e.g. "https://id.altimist.ai"
apex: process.env.RESOLVER_APEX || 'altimist.com',
});// app/.well-known/revocations.json/route.ts
import { revocationsHandler } from '@altimist/did-publisher';
export const GET = revocationsHandler({
origin: process.env.ALTIMIST_ID_URL!,
});// app/.well-known/team-issuers/[team]/route.ts
import { teamIssuersHandler } from '@altimist/did-publisher';
export const GET = teamIssuersHandler({
origin: process.env.ALTIMIST_ID_URL!,
});What each route does
| Path | Behaviour | Cache |
|---|---|---|
| <handle>.<apex>/.well-known/did.json | Proxies ${origin}/api/resolver/did/<handle> | s-maxage=300, stale-while-revalidate=86400 |
| <apex>/users/<handle>/did.json | Proxies ${origin}/api/resolver/did/<handle>?form=path (F-011 path-form DID hosting) | s-maxage=300, stale-while-revalidate=86400 |
| <apex>/.well-known/revocations.json | Proxies ${origin}/api/resolver/revocations | s-maxage=60, stale-while-revalidate=86400 (per F-010's 60s revocation-latency AC) |
| <apex>/.well-known/team-issuers/<team>.json | Proxies ${origin}/api/resolver/team-issuers/<team> | s-maxage=300, stale-while-revalidate=86400 |
<apex> is configured per environment (altimist.com for production, staging.altimist.com for staging). Handle URLs require a single-label subdomain (patrick.altimist.com); apex paths require the host to be exactly the apex (returns 404 otherwise).
Failure modes
- Upstream 4xx (404 unknown handle, etc.): pass through with the same status, no cache header.
- Upstream 5xx or timeout: returns
503so consumer apps fail-closed (DID resolution unavailable).
Cloudflare cache purge
altimist-id is responsible for purging the edge cache on every mutation (device enrolment, revocation, etc.). This package is read-only — see altimist-id's src/lib/cache-purge.ts for the purge side.
License
UNLICENSED — internal Altimist.
