monitor-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 11d38ef641b0
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 9383f719c9b37ff76411858f
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
src/lib/store.ts
// What Monitor remembers on this device: the baby station it runs, the stations it watches,
// and settings. Nothing here leaves the device. Storage can be unavailable (private windows),
// so every read falls back to a default.
import type { Facing, Sensitivity } from "./protocol";

export interface BabyConfig { room: string; name: string; camera: Facing }
export interface Pairing { key: string; room: string; name: string; addedAt: number }
export interface WatchSettings { sensitivity: Sensitivity; night: boolean; audioOnly: boolean; soundVolume: number; soundMinutes: number }

function read<T>(key: string, fallback: T): T {
  try {
    const raw = localStorage.getItem(key);
    return raw ? { ...fallback, ...JSON.parse(raw) } : fallback;
  } catch {
    return fallback;
  }
}

function write(key: string, value: unknown) {
  try {
    if (value === null) localStorage.removeItem(key); else localStorage.setItem(key, JSON.stringify(value));
  } catch { /* storage unavailable: settings last for this visit */ }
}

export const baby = {
  get: (): BabyConfig | null => read<BabyConfig | null>("monitor:baby", null),
  set: (c: BabyConfig | null) => write("monitor:baby", c),
};

export const pairings = {
  list(): Pairing[] {
    try {
      const raw = JSON.parse(localStorage.getItem("monitor:pairings") || "[]");
      return Array.isArray(raw) ? raw.filter((p) => p && typeof p.room === "string" && typeof p.key === "string") : [];
    } catch {
      return [];
    }
  },
  byKey: (key: string) => pairings.list().find((p) => p.key === key) || null,
  /** Adds or refreshes a pairing and returns its local key (the room id stays out of URLs). */
  save(room: string, name: string, key: string): Pairing {
    const list = pairings.list();
    const existing = list.find((p) => p.room === room);
    const p: Pairing = existing ? { ...existing, name } : { key, room, name, addedAt: Date.now() };
    write("monitor:pairings", [p, ...list.filter((x) => x.room !== room)]);
    return p;
  },
  rename(room: string, name: string) {
    write("monitor:pairings", pairings.list().map((p) => (p.room === room && p.name !== name ? { ...p, name } : p)));
  },
  remove(room: string) {
    write("monitor:pairings", pairings.list().filter((p) => p.room !== room));
  },
};

const DEFAULT_SETTINGS: WatchSettings = { sensitivity: "medium", night: false, audioOnly: false, soundVolume: 0.4, soundMinutes: 30 };
export const settings = {
  get: (room: string) => read<WatchSettings>(`monitor:settings:${room}`, DEFAULT_SETTINGS),
  set: (room: string, s: WatchSettings) => write(`monitor:settings:${room}`, s),
};

/** A friendly default name for this device, shown on the baby station's list of watchers. */
export function guessDeviceName(): string {
  const ua = navigator.userAgent;
  if (/iPad/.test(ua) || (/Macintosh/.test(ua) && navigator.maxTouchPoints > 1)) return "iPad";
  if (/iPhone/.test(ua)) return "iPhone";
  if (/Android/.test(ua)) return /Mobile/.test(ua) ? "Android phone" : "Android tablet";
  if (/Macintosh/.test(ua)) return "Mac";
  if (/Windows/.test(ua)) return "Windows computer";
  if (/CrOS/.test(ua)) return "Chromebook";
  return "Parent device";
}

export const deviceName = {
  get: () => read<{ name: string }>("monitor:device", { name: guessDeviceName() }).name,
  set: (name: string) => write("monitor:device", { name }),
};

Change history

Move store links to openapps.free
11d38ef641 · 17 hours ago
Release with preview
41c8af3ee5 · 19 hours ago
Bind agent address in policy
5b2d792529 · 19 hours ago
Use OpenApps service URLs and add contribution strip (retry)
be4477dcb3 · 19 hours ago
Bounded source sync
5c9ec00c29 · 2 days ago
Bounded source sync
b33aa231f4 · 2 days ago
Bounded source sync
6cb67b3c8e · 2 days ago
Bounded source sync
e054acaa29 · 2 days ago