clone

a self-hosted sync node for lofi apps: jazz sync over iroh, ticket-gated, with no static ip or cloud needed

docs: JSR score pass — entrypoint module docs + full symbol JSDoc; v0.1.1

Dami committed f377245
All three entrypoints (mod.ts, ./cli, ./testing) carry module docs with
runnable examples; every exported symbol and interface member across the
public surface is documented. Package description updated (mirrored to
the GitHub repo description; JSR-side setting pasted separately).
Version 0.1.1 + regenerated release artifacts manifest.
commit
f377245b06d797642b061bdf18fc608dda4b9407
parent
26f137e2a53835274452939b558deff19d5a9214
author
Dami <dami.etoile@gmail.com>
9 files changed, +111 -14
Mcli.ts22+++++++++++++++++-----
Mdeno.json4++--
Mmod.ts28++++++++++++++++++++++++++--
Msrc/appticket.ts4++++
Msrc/config.ts17+++++++++++++++++
Msrc/errors.ts5+++++
Msrc/native/artifacts.ts4++--
Msrc/node.ts15+++++++++++++++
Mtesting/mod.ts26+++++++++++++++++++++++---
M cli.ts +17 -5
M deno.json +2 -2
M mod.ts +26 -2
M src/appticket.ts +4 -0
M src/config.ts +17 -0
@@ -3,6 +3,8 @@
33 // and persisted — the node's identity and its Jazz credentials both survive44 // restarts, so tickets and client sessions stay stable.55 6+/** Where this node replicates to: nowhere, a direct Jazz server URL (e.g.7+ * Jazz Cloud), or a peer lofi-node named by its iroh pairing ticket. */68 export type UpstreamConfig = "none" | { url: string } | { peer: string };79 810 /** Where node data lives. jazz-napi supports exactly these two today; the
@@ -10,11 +12,18 @@ export type UpstreamConfig = "none" | { url: string } | { peer: string };
1012 * any mounted location (NAS, synced volume) — validated writable at boot. */1113 export type StorageConfig = { type: "sqlite"; path?: string } | { type: "memory" };1214 15+/** Persisted daemon configuration (`<dataDir>/config.json`, version 2 —16+ * v1 files migrate lazily on load). */1317 export interface NodeConfig {18+ /** Config schema version. */1419 v: 2;20+ /** Jazz app id (a UUID — Jazz's catalogue requires UUID ids). */1521 appId: string;22+ /** Jazz backend secret (server-to-server calls). */1623 backendSecret: string;24+ /** Jazz admin secret; in ticket mode it never leaves the node. */1725 adminSecret: string;26+ /** Fixed public port; auto-allocated per start when omitted. */1827 listenPort?: number;1928 /** "ticket": only issued app tickets reach Jazz (CLI init default).2029 * "open": today's behavior (library/test default). */
@@ -28,6 +37,8 @@ export interface NodeConfig {
2837 2938 const SUPPORTED_STORAGE = ["sqlite", "memory"];3039 40+/** Throws with an actionable message for storage types jazz-napi cannot41+ * back today (`sqlite` and `memory` are the supported set). */3142 export function validateStorage(storage: StorageConfig): void {3243 if (!SUPPORTED_STORAGE.includes(storage.type)) {3344 throw new Error(
@@ -56,10 +67,13 @@ function fromHex(text: string): Uint8Array {
5667 return out;5768 }5869 70+/** Path of the daemon config file inside a data directory. */5971 export function configPath(dataDir: string): string {6072 return `${dataDir}/config.json`;6173 }6274 75+/** Read config.json (null when absent); v1 files are mapped to v2 in76+ * memory — persisted as v2 on the next explicit {@link saveConfig}. */6377 export async function loadConfig(dataDir: string): Promise<NodeConfig | null> {6478 try {6579 const raw = await Deno.readTextFile(configPath(dataDir));
@@ -88,11 +102,14 @@ export async function loadConfig(dataDir: string): Promise<NodeConfig | null> {
88102 }89103 }90104 105+/** Write config.json (creates the data directory when needed). */91106 export async function saveConfig(dataDir: string, config: NodeConfig): Promise<void> {92107 await Deno.mkdir(dataDir, { recursive: true });93108 await Deno.writeTextFile(configPath(dataDir), JSON.stringify(config, null, 2) + "\n");94109 }95110 111+/** Create (or return the existing) daemon config; new inits default to112+ * ticket-gated access and SQLite storage, with generated secrets. */96113 export async function initConfig(97114 dataDir: string,98115 overrides: Partial<
M src/errors.ts +5 -0
M src/native/artifacts.ts +2 -2
M src/node.ts +15 -0
@@ -22,9 +22,14 @@ import { type Gate, startGate } from "./gate.ts";
2222 import { type AppTicketRecord, AppTicketStore, encodeAppTicket } from "./appticket.ts";2323 import { MeshUnavailableError } from "./errors.ts";2424 25+/** Options for {@link createSyncNode}. */2526 export interface SyncNodeOptions {27+ /** Jazz app id (a UUID). */2628 appId: string;29+ /** Jazz backend secret. */2730 backendSecret: string;31+ /** Jazz admin secret; in ticket mode the gate injects it server-side and32+ * it never transits clients. */2833 adminSecret: string;2934 /** Omit (or set inMemory) for an ephemeral node — tests, throwaway relays. */3035 dataDir?: string;
@@ -50,11 +55,14 @@ export interface SyncNodeOptions {
5055 irohLibPath?: string;5156 }5257 58+/** iroh mesh state: up (with pairing ticket + live tunnel stats), off, or59+ * unavailable with the precise reason (no silent degradation). */5360 export type MeshStatus =5461 | { state: "up"; nodeId: string; ticket: string; connections: TunnelConnStat[] }5562 | { state: "off" }5663 | { state: "unavailable"; reason: string };5764 65+/** Public view of an issued app-connect ticket (never the secret). */5866 export interface AppTicketInfo {5967 id: string;6068 scope: "sync" | "provision";
@@ -63,6 +71,7 @@ export interface AppTicketInfo {
6371 revoked: boolean;6472 }6573 74+/** Snapshot returned by {@link SyncNode.status}. */6675 export interface SyncNodeStatus {6776 appId: string;6877 access: "open" | "ticket";
@@ -72,6 +81,7 @@ export interface SyncNodeStatus {
7281 mesh: MeshStatus;7382 }7483 84+/** A running sync node — see {@link createSyncNode}. */7585 export interface SyncNode {7686 /** Public URL — what JAZZ_SERVER_URL points at in open mode; in ticket mode7787 * apps use a ticket's own /t/<secret> URL against this same host:port. */
@@ -124,6 +134,11 @@ async function probeWritable(path: string): Promise<void> {
124134 }125135 }126136 137+/**138+ * Start a sync node: an embedded Jazz server, optional iroh mesh, and (in139+ * ticket mode) the public access gate. The returned {@link SyncNode} is the140+ * whole operational surface: tickets, pairing, status, stop.141+ */127142 export async function createSyncNode(options: SyncNodeOptions): Promise<SyncNode> {128143 let upstream: UpstreamConfig = options.upstream ?? "none";129144 const meshMode = options.mesh ?? "auto";
M testing/mod.ts +23 -3