Skip to main content

Module Reference

Modules live under js/. The app has hundreds of focused top-level JavaScript modules. This page is a guided implementation map, not a promise that every small hook, delegate, or helper file has its own long section. It is grouped by layer; lower layers have no dependencies on higher ones.

Layer 1 — Foundation

schema.js and marker-schema/

schema.js is the stable compatibility facade for the modular biomarker catalog, range registries, unit conversions, pricing, and environment thresholds. Category definitions and immutable marker identities are authored in category modules under marker-schema/, composed by marker-schema/index.js, and generated into marker-schema.js; contributors must not edit the generated file directly. Key exports:
  • MARKER_SCHEMA — 196 core entries across 19 categories, including the 22-entry calculatedRatios category
  • UNIT_CONVERSIONS — keyed by "category.markerKey": { type: 'multiply', factor, unit } for EU→US conversions
  • OPTIMAL_RANGES — keyed by "category.markerKey": { optimalMin, optimalMax, optimalMin_f?, optimalMax_f? }
  • PHASE_RANGES — keyed by "category.markerKey": { menstrual: { min, max }, follicular: {...}, ovulatory: {...}, luteal: {...} } — covers hormones.estradiol, hormones.progesterone, hormones.lh, and hormones.fsh
  • CONTEXT_REFERENCE_RANGES / CONTEXT_OPTIMAL_RANGES — age-, sex-, and date-resolved guidance consumed by the active-data pipeline
  • SPECIALTY_MARKER_DEFS — re-exported from adapters.js as ADAPTER_MARKERS. Used by migrateProfileData() and buildMarkerReference()
  • BUILTIN_MARKER_IDENTITIES, BUILTIN_MARKER_DOT_KEY_ALIASES, getBuiltinMarkerId(), getBuiltinMarkerDotKey(), and resolveBuiltinMarkerDotKey() — immutable gb:marker:* IDs plus current and legacy location compatibility exports
  • CHIP_COLORS — status → CSS color string
  • MODEL_PRICING — AI model pricing metadata, keyed by provider/model
Window exports: none

marker-schema/index.js and marker-schema.js

marker-schema/index.js is the authoring composition root. It imports the category source modules in stable order and exports the catalog inputs. scripts/build-marker-schema.mjs turns those inputs into the generated runtime module marker-schema.js; contributors must not edit the generated file directly. Key generated exports: MARKER_SCHEMA, BUILTIN_MARKER_IDENTITIES, BUILTIN_MARKER_DOT_KEY_ALIASES, getBuiltinMarkerId(), getBuiltinMarkerDotKey(), resolveBuiltinMarkerDotKey(), CUSTOM_MARKER_ID_PREFIX, and isCustomMarkerId(). See Marker model and category placement for the authoring and migration contract.

custom-marker-identity.js

Creates and migrates category-independent custom:* IDs while preserving existing custom-marker dot keys. Legacy IDs are deterministic and migration is idempotent so offline devices converge. Key exports: createCustomMarkerId(), deriveLegacyCustomMarkerId(), ensureCustomMarkerIdentity(), migrateCustomMarkerIdentities(), getCustomMarkerId(), getCustomMarkerDotKey(), and resolveCustomMarkerDotKey().

marker-placement.js

Pure marker placement engine and storage/display boundary. It validates visual category assignments, keeps unknown metadata forward-compatible, applies placement as the final active-data projection, and resolves mutation keys back to immutable storage locations. Key exports: migrateMarkerPlacements(), resolveMarkerIdentity(), getMarkerPlacementPlan(), setMarkerPlacement(), clearMarkerPlacement(), applyMarkerPlacements(), getMarkerStorageDotKey(), and active-marker lookup helpers.

marker-terminology.js

Generated, optional mapping registry for LOINC, NPU, NČLP, and UCUM metadata. It is not part of application startup, profile persistence, import/export, backup, sharing, or sync. Key exports: TERMINOLOGY_CATALOGS, MARKER_TERMINOLOGY_REGISTRY, getMarkerTerminologyMappings(), and findMarkerTerminologyMapping(). See Laboratory terminology registry for the mapping and verification contract.

adapters.js

Parser adapter registry for specialty lab detection and normalization. Single source of truth for all specialty marker definitions (OAT, fatty acids, Metabolomix+, BioStarks). Key exports:
  • ADAPTER_MARKERS — flat object keyed by "category.markerKey": { name, unit, refMin, refMax, categoryLabel, icon, group, singlePoint? } (220 entries). Re-exported from schema.js as SPECIALTY_MARKER_DEFS
  • getAllAdapterMarkers() — returns merged marker map from all registered adapters
  • detectProduct(fileName, pdfText) — runs all adapter detect() functions, returns { adapter, product: { prefix, label } } or null
  • normalizeWithAdapter(adapter, markers, fileName, pdfText, product) — dispatches to adapter.normalize() for post-AI marker key/category rewriting
  • getAdapterByTestType(testType) — looks up adapter by AI-returned test type string
Adapter registry: array of { id, testTypes[], markers, detect?, normalize? }:
  • fattyAcids — 29 markers, detects Spadia/ZinZino/OmegaQuant by filename/text, normalizes to product-prefixed categories under “Fatty Acids” sidebar group
  • metabolomix — no unique markers (reuses OAT + FA), detects Genova Metabolomix+ reports, routes FA add-on markers to metabolomixFA prefix
  • oat — 165 markers, no detect/normalize (AI handles OAT categorization directly)
  • biostarks — 23 markers, detects BioStarks dried blood spot reports by filename/text, normalizes specialty markers (amino acids, serum FA, intracellular minerals, hormones, vitamins) while passing standard blood markers through to schema categories (hybrid import)
Window exports: none

constants.js

Static arrays and string constants used across modules. Key exports:
  • CHAT_PERSONALITIES — array of { id, name, icon, promptText } for the 3 built-in personalities
  • CHAT_SYSTEM_PROMPT — the base system prompt string injected into all AI chat requests
  • COUNTRY_LATITUDES{ countryCode: latitudeBand } (~70 countries, 5 bands: arctic/north/temperate/subtropical/tropical)
  • FAKE_DATA — synthetic name/address/DOB data for PII obfuscation
  • Per-card option arrays: SLEEP_DURATIONS, SLEEP_QUALITIES, SLEEP_SCHEDULES, SLEEP_ISSUES, SLEEP_ENVIRONMENTS, SLEEP_PRACTICES, LIGHT_AM, LIGHT_DAYTIME, LIGHT_UV, LIGHT_EVENING, LIGHT_SCREEN, LIGHT_TECH_ENV, LIGHT_COLD, LIGHT_GROUNDING, LIGHT_MEAL_TIMING, STRESS_LEVELS, STRESS_SOURCES, STRESS_MANAGEMENT, ENV_SETTING, ENV_CLIMATE, ENV_WATER, ENV_WATER_CONCERNS, ENV_EMF, ENV_EMF_MITIGATION, ENV_HOME_LIGHT, ENV_AIR, ENV_TOXINS, ENV_BUILDING, LOVE_STATUS, LOVE_RELATIONSHIP, LOVE_SATISFACTION, LOVE_LIBIDO, LOVE_FREQUENCY, LOVE_ORGASM, LOVE_CONCERNS, PERIOD_SYMPTOMS, DIET_TYPES, DIET_RESTRICTIONS, DIET_PATTERNS, EXERCISE_FREQUENCIES, EXERCISE_TYPES, EXERCISE_INTENSITIES, EXERCISE_DAILY_MOVEMENT
Window exports: none

state.js

Single shared mutable state object. Import state to read or write. No logic. Key exports:
  • state — the mutable singleton:
window._labState = state is set for debugging in the browser console. Window exports: none (state is accessed via import)

utils.js

Shared pure utility functions. Key exports:
  • escapeHTML(str) — escapes <>&"' for safe innerHTML insertion
  • hashString(str) — djb2 hash, returns integer
  • getStatus(value, refMin, refMax)'normal' | 'high' | 'low' | 'missing'. Returns 'normal' when refs are null
  • formatValue(value, unit) — formats a numeric value with appropriate decimal places
  • showNotification(message, type) — toast notification ('info' | 'success' | 'error' | 'warning')
  • showConfirmDialog(message) — returns Promise<boolean>, styled confirm dialog
  • linearRegression(points){ slope, intercept, r2 } from [{ x, y }] array
  • hasCardContent(obj) — generic empty-card gate: returns true if any field has content (strings non-empty, arrays non-empty, note trimmed). Used by buildLabContext() for 7 context card gates
  • bindModalSyncRefresh(opts) / bindDetailModalSyncRefresh(kind, refresh) / bindDetachedModalSyncRefresh(opts) — shared labcharts-sync-applied modal refresh bindings with dirty-form guards and scroll restoration
Window exports: showNotification, showConfirmDialog, setDebugMode, setPIIReviewEnabled, hasCardContent

Layer 2 — Core Services

Shared modal backdrop, focus-trap, and body-scroll lock helpers. Owns the cross-module scroll-lock registry used by Light & Sun modals; sun.js re-exports the legacy names for compatibility. Key exports:
  • wireBackdropClose(overlay, closeFn?) / _wireBackdropClose(overlay, closeFn?) — backdrop click close wiring with inside-click guard
  • trapModalFocus(overlay) — locks background scroll, restores focus/overflow on removal, and handles Escape close
Window exports: none directly; sun.js still exposes compatibility globals.

theme.js

Theme management and Chart.js color helpers. Key exports:
  • getTheme() / setTheme(theme) / toggleTheme()'dark' | 'light'; setTheme sets data-theme on <html>
  • getChartColors() — reads live CSS custom properties and returns a chart color config object
  • formatDateLabel(dateStr) — formats ISO date for chart x-axis
  • getTimeFormat() / setTimeFormat(fmt)'24h' | '12h', stored in labcharts-time-format
  • formatTime(timeStr) — formats a 24h time string for display using the active format
  • parseTimeInput(input) — accepts both '14:30' and '2:30 PM', always returns 24h format
Window exports: toggleTheme

hardware.js

GPU detection and model fitness advisor for Local AI settings. Pure functions, no DOM manipulation. Key exports:
  • detectHardware() — async, returns { gpu: { name, vram, unified, renderer, source }, ram: { gb, source }, cpuThreads }. GPU detected via WebGL WEBGL_debug_renderer_info matched against 75-entry GPU_DB (Apple Silicon M1–M4, NVIDIA RTX 30/40/50, AMD RX 6000/7000, Intel Arc, Vega)
  • assessModel(modelObj, hardware) — returns { tier, badge, vramNeeded, label } where tier is 'fits' / 'tight' / 'toobig' / 'unknown'
  • assessFitness(modelName) — rates a model for getbased lab analysis: { tier, note } where tier is 'recommended' / 'capable' / 'underpowered' / 'inadequate'. Benchmarked against Sonnet 4.6
  • getBestModel(modelDetails, hardware) — picks the highest-fitness installed model that fits in VRAM
  • getUpgradeSuggestion(modelDetails, hardware) — returns a pull recommendation if no installed model is “recommended” tier
  • saveHardwareOverride(vram) / getHardwareOverride() — manual VRAM override in localStorage
Window exports: none (imported by settings.js)

api.js

AI provider routing and model management. All AI calls flow through callClaudeAPI. Key exports:
  • callClaudeAPI(opts) — main router: delegates to the active provider based on getAIProvider()
  • callOpenRouterAPI(opts) — OpenRouter via callOpenAICompatibleAPI
  • callRoutstrAPI(opts) — Routstr via callOpenAICompatibleAPI
  • callPPQAPI(opts) — PPQ via callOpenAICompatibleAPI
  • callVeniceAPI(opts) — Venice AI via callOpenAICompatibleAPI
  • callOpenAICompatibleLocalAPI(opts) — compatibility re-export for Local AI request planning and adapter inference in api-local.js
  • callOpenAICompatibleAPI(endpoint, key, model, providerName, opts, extraHeaders) — shared OpenAI-format helper
  • getAIProvider() / setAIProvider(provider)'openrouter' | 'routstr' | 'ppq' | 'venice' | 'ollama' (internal key for Local)
  • hasAIProvider() — returns true if any provider is configured; gates AI features
  • getOpenRouterModel(), getRoutstrModel(), getPPQModel(), getVeniceModel(), getOllamaMainModel()
  • fetchOpenRouterModels(), fetchRoutstrModels(), fetchPPQModels(), fetchVeniceModels() — dynamic model lists
  • getModelPricing(modelId) — checks dynamic OpenRouter pricing cache, falls back to MODEL_PRICING
  • OPENROUTER_CURATED — whitelist of latest-gen medically capable models (prefix-matched)
  • OPENROUTER_EXCLUDE — blocklist filtering codex/audio/image/oss variants
Window exports: getRoutstrNodeUrl (used by settings UI for node URL access)

api-transport.js

Shared AI API transport helpers used by api.js. Key exports:
  • fetchWithRetry(url, options, config) — wraps fetch with request timeout, transient network retry, and 429 backoff
  • createProxyFetch(shouldUseProxy) — builds the Custom API proxy fetch wrapper
  • readWithStallTimeout(reader, label, timeoutMs?) — guards one streaming read; Local AI uses the extended allowance only before its first token
  • STREAM_STALL_TIMEOUT_MS, LOCAL_AI_FIRST_TOKEN_STALL_MS, FETCH_REQUEST_TIMEOUT_MS, AI_IMPORT_REQUEST_TIMEOUT_MS — transport timeout constants
Window exports: none

Local AI provider modules

Local AI uses a normalized adapter layer so compatible endpoints work without hiding richer Ollama and LM Studio capabilities. Key modules and exports:
  • local-ai-provider-registry.jsLOCAL_AI_PROVIDER_ADAPTERS, getLocalAiProviderAdapter(), capability lookup, and detection precedence
  • local-ai-provider-ollama.js — native discovery, streaming inference, context override, performance diagnostics, and unload
  • local-ai-provider-lmstudio.js — native discovery/model enrichment, guarded unload/load-at-context, streaming compatible generation, native fallback, and truncation diagnostics
  • local-ai-provider-openai-compatible.js — generic /v1/models discovery and /v1/chat/completions inference
  • local-ai-provider-shared.js — base URL normalization, execution-location classification, compatible-model normalization, and secret redaction
  • local-ai-discovery.js — short-lived discovery cache and loaded-model metadata updates
  • api-local.js — prompt-token estimation, context/output replanning after a native load, adapter selection, and normalized inference diagnostics
  • local-ai-lifecycle.js — memory-only runtime handoff and best-effort model release across same-machine endpoints
See AI provider internals for the capability and lifecycle contract.

Import model-testing modules

import-benchmarks.js captures durable, device-local diagnostics around production PDF/image imports. import-reference-benchmark.js runs and scores the bundled reference report. settings-import-benchmark-controller.js and the benchmark helpers in settings-data.js own the user-facing history and comparison UI. See AI model testing internals for record statuses, scoring layers, same-input comparison, persistence, and fixture maintenance.

cashu-wallet.js

In-app Cashu eCash wallet for decentralized AI payments. Proofs stored in IndexedDB, BIP-39 seed encrypted in localStorage. Key exports:
  • getMintUrl() / setMintUrl(url) — configured Cashu mint
  • generateWalletSeed() — creates 12-word BIP-39 mnemonic
  • restoreWalletFromSeed(mnemonic) — restores proofs from mint via batchRestore
  • getWalletBalance() — sum of unspent proofs for current mint
  • createFundingInvoice(amountSats) / checkFundingStatus(quoteId) — Lightning deposit flow
  • receiveToken(tokenString) — deposit a Cashu token
  • depositToNode(nodeUrl, amountSats, existingKey) — swap proofs for a node session key
  • sendAsToken(amountSats) — withdraw as shareable Cashu token
  • createWithdrawQuote(bolt11) / executeWithdraw(quoteId) — Lightning withdrawal
  • withdrawToAddress(address, amountSats) — LNURL-pay withdrawal
  • recoverPendingDeposit() / recoverPendingWithdraw() — failed operation recovery
  • exportWallet() / importWallet(tokenString) — backup/restore
  • getFeePct() — current fee percentage (0 during beta)
Window exports: all functions prefixed with cashu (e.g., cashuGetBalance, cashuDepositToNode)

nostr-discovery.js

Discovers Routstr AI nodes via Nostr relays (Kind 38421 events). Key exports:
  • discoverNodes(forceRefresh) — queries relays in parallel, deduplicates, health-checks, returns sorted node array
  • getSelectedNodeUrl() / setSelectedNodeUrl(url) — persisted node selection
  • clearNodeCache() — force re-discovery on next call
Window exports: nostrDiscoverNodes, nostrGetSelectedNode, nostrSetSelectedNode, nostrClearNodeCache

Layer 3 — Data & Profile

profile.js

Profile lifecycle and settings persistence. Key exports:
  • profileStorageKey(profileId, suffix) — builds labcharts-{profileId}-{suffix}
  • createDefaultProfileData() — returns the empty importedData shape used for new/metadata-only profile sync
  • loadProfiles() / saveProfiles() — profile index CRUD
  • switchProfile(profileId) — loads importedData from localStorage for the given profile
  • deleteProfile(profileId) — removes all keys for the profile
  • migrateProfileData() — upgrades legacy field formats on load (old sleepCircadiansleepRest + lightCircadian, old fieldExperts/fieldLensinterpretiveLens, initializes missing fields with null)
  • getProfileLocation() / setProfileLocation(country, zip) — country+ZIP storage
  • getLatitudeFromLocation() — looks up latitude band from COUNTRY_LATITUDES
  • renderProfileDropdown() — renders the profile selector UI
Window exports: openProfileEditor, switchProfile, deleteProfile, addProfile, saveProfile

data.js

The central data pipeline. Every view gets its data from getActiveData(). Key exports:
  • getActiveData() — builds or reuses the active projection: schema and custom markers, personal ranges, date-aligned values and entry context, phase/context ranges, deterministic calculated markers, unit conversion, and final display placements
  • invalidateActiveDataCache() — clears the projection cache after a tracked mutation
  • saveImportedData() — persists state.importedData to localStorage (or encrypted store), triggers backup
  • filterDatesByRange(data, options?) — returns a date-filtered projection without mutating the cached active dataset
  • registerRefreshCallback(fn) — registers the refresh function from app-event-listeners.js
  • getFocusCardFingerprint() — hash of lab/profile inputs relevant to the Focus card
  • Compatibility re-exports from marker-analysis.js keep existing window.* helper access stable.
Window exports: saveImportedData, clearAllData (via export.js), filterDatesByRange

Lab marker projection helpers

  • data-calculated-markers.js — direct-result-first calculated ratios, indices, free water deficit, PhenoAge, Bortz Age, combined Biological Age, and dated calculation guidance.
  • marker-context-ranges.js — whole-age-at-draw, sex/age band selection, collection-time parsing, and cortisol range resolution.
  • cycle-draw-phases.js — normalization of explicit recorded phase, phase detail, cycle day, and recorded/predicted source.
  • marker-range-suggestions.js — privacy-safe public issue payload and gating to untouched built-in ranges.
  • profile-marker-alias-migrations.js — canonical dotKey migrations across values, snapshots, custom markers, ranges, notes, labels, and date-scoped manual metadata.
See Lab markers and range internals for precedence and invariants.

marker-analysis.js

Read-only marker range, status, and trend helpers. This module owns pure marker analysis so chart, dashboard, AI context, and export code do not need to import the storage/sync-heavy data.js when they only need derived marker calculations. Key exports:
  • getEffectiveRange(marker) — returns { min, max } respecting state.rangeMode
  • getEffectiveRangeForDate(marker, dateIndex) — dated phase, contextual optimal/reference, and static/personal range lookup
  • getEffectiveRangeLabelForDate(marker, dateIndex) — matching user-facing source/policy label such as Lab reference, Target, or a phase label
  • getPhaseRefEnvelope(marker) — widest span across all cycle phases for chart ref bands
  • getContextRefEnvelope(marker) / getContextOptimalEnvelope(marker) — chart envelopes across dated context ranges
  • getLatestValueIndex(values) — index of the latest non-null marker value
  • countFlagged(markers) / getAllFlaggedMarkers(data) — out-of-range marker helpers
  • statusIcon(status) — status-to-symbol mapping used by category cards
  • detectTrendAlerts(data) — sudden-change (25% of ref range, 2+ values) and linear-regression (slope >0.02, R²>0.5 for 4+ points) alerts
  • getKeyTrendMarkers(filteredData) — dashboard key-trend selection
Window exports: none directly; data.js keeps compatibility exports.

pii.js

Two-path PII obfuscation for PDF text before AI submission, with streaming review modal. Key exports:
  • sanitizeWithOllamaStreaming(pdfText, onChunk, signal) — preferred path: SSE streaming via OpenAI-compatible API, calls onChunk(delta) per token, supports AbortSignal
  • sanitizeWithOllama(pdfText) — non-streaming path: same endpoint, used when review is disabled
  • obfuscatePDFText(pdfText) — regex fallback: label-based + pattern-based replacement, returns { obfuscated, original, replacements }
  • reviewPIIBeforeSend(originalText, { obfuscatedText, streamFn }) — review modal: streaming mode (pass streamFn) or static mode (pass obfuscatedText). Returns edited text or 'cancel'
  • checkOllamaPII() — checks PII server availability via /v1/models
  • getOllamaConfig() / saveOllamaConfig(config) — local AI config: { url, model, apiKey }
  • showPIIDiffViewer(original, obfuscated, replacements) — debug diff viewer (requires labcharts-debug flag)
Window exports: setOllamaPIIModel

image-utils.js

Shared image utilities for chat attachments and PDF image fallback. Key exports:
  • resizeImage(file, maxDim?, quality?) — resizes an image to fit within maxDim pixels (default 1024), returns { base64, mediaType, width, height, origWidth, origHeight, quality_warnings }
  • isValidImageType(type) — validates MIME type against image/(jpeg|png|gif|webp)
  • formatImageBlock(base64, mediaType, provider) — returns a provider-specific image content block (type:'image_url' for OpenAI-compatible providers)
  • buildVisionContent(imageBlocks, text, provider) — assembles a content array with image blocks + text block
Internal:
  • analyzeImageQuality(ctx, width, height) — canvas-based pixel sampling (~100k samples): brightness (dark/overexposed) + Laplacian variance (blur detection). Returns string[] warnings
Window exports: resizeImage, isValidImageType, formatImageBlock, buildVisionContent

Layer 4 — Domain Modules

charts.js

Chart.js configuration and all custom plugins. Key exports:
  • createLineChart(canvasId, marker, data, phaseLabels?) — creates a Chart.js line chart with all plugins applied
  • destroyAllCharts() — destroys all instances in state.chartInstances to prevent memory leaks
  • Five Chart.js plugins (registered globally):
    • refBandPlugin — shaded reference range band
    • optimalBandPlugin — green dashed optimal range band
    • noteAnnotationPlugin — yellow dot annotations at note dates with hover tooltips
    • supplementBarPlugin — colored timeline bars for supplements
    • phaseBandPlugin — compact phase pills at observed points, with optional cycle day and recorded/predicted tooltip context
Window exports: none

notes.js

Standalone note management (independent of lab entries). Key exports:
  • openNoteEditor(date?) — opens the note editor modal, pre-filled if date provided
  • saveNote() — saves the current editor content to importedData.notes
  • deleteNote(date) — removes a note by date
Window exports: openNoteEditor, saveNote, deleteNote

Supplement and medication modules

The feature is split by responsibility. supplements.js orchestrates the editor and persistence; supplement-medication-domain.js owns identity, lifecycle, periods, schedules, quantities, units, and additive migration; supplement-form-ui.js and supplement-import-controller.js own the structured form and reviewed import workflow; supplement-dashboard.js and supplement-impact.js own current display and historical analysis; supplement-quality.js, supplement-context.js, and supplement-warnings.js own evidence and bounded projections. Key exports:
  • openSupplementsEditor(index?) — opens the supplement editor modal
  • saveSupplement(idx) — persists current form state to importedData.supplements
  • pauseSupplement(idx) / endSupplement(idx) — close the current period while preserving history
  • restartSupplement(idx) / beginSupplementDoseChange(idx) — append or edit period-based lifecycle state
  • deleteSupplement(idx) — removes by index
  • renderSupplementsSection() — renders current records and claim-grouped mitochondrial evidence
  • renderSupplementImpact(supp, editIdx) — per-supp impact card (shimmer → cached AI summary)
  • computeSupplementImpact(supp, markerKey, ...) — before/after mean comparison for one marker
  • computeAllImpacts(supp, data) — impact vectors across all markers, sorted by |pctChange|
  • getSupplementStatus() / getSupplementsOverlappingRange() — period-derived current/history selection
  • buildSupplementAIContext() — compact/detail source-quality context with hard character limits
  • parseSupplementQuantity(str) — structured quantity parser; parseAmount() remains the impact compatibility wrapper
  • effectiveTimesPerDay(ing, supp) — row override wins, else supp-level default
  • ingredientDailyTotal(ing, supp) — computed amount × effectiveTimesPerDay
Record model: schema-v2 rows have stable IDs and explicit use periods. Product-label directions, active ingredients, other label materials, personal regimen, and source laboratory evidence remain separate. Legacy fields and unknown keys are retained for compatibility. Impact cache: per-supp cache in labcharts-{profileId}-suppImpact keyed by supp name with a fingerprint that includes dosage, outer timesPerDay, per-ingredient fields, periods, and lab dates — any edit auto-invalidates only that supp’s cache entry. Concurrent renders are coalesced via a 50ms debounced queue (scheduleAnalyzeflushAnalyses).

cycle.js

Menstrual cycle tracking, helpers, and dashboard rendering. Key exports:
  • getCyclePhase(dateStr, mc){ cycleDay, phase, phaseName } for a date against a cycle object
  • getNextBestDrawDate(mc) — next early follicular window (days 3–5)
  • getBloodDrawPhases(mc, dates) — maps lab dates to phases
  • calculateCycleStats(periods) — auto-computes { cycleLength, periodLength, regularity } from period log
  • detectPerimenopausePattern(mc, dob) — flags perimenopause pattern (age 35+, 4+ periods, 2+ of 4 indicators)
  • detectCycleIronAlerts(mc, data) — cross-references heavy flow with ferritin/hemoglobin/iron
  • openMenstrualCycleEditor() — opens the cycle editor modal
  • saveMenstrualCycle() — saves to importedData.menstrualCycle, triggers cycle tour
  • renderMenstrualCycleSection(data) — renders the full cycle dashboard section
  • startCycleTour(auto) — triggers the 8-step cycle spotlight tour
Window exports: openMenstrualCycleEditor, saveMenstrualCycle, addPeriod, deletePeriod, startCycleTour

context-cards.js

Health-context card rendering and lifecycle facade. It owns the grid, save-and-refresh flow, context notes, demo live-AI confirmation controls, card-tip launchers, and compatibility exports for the split editor, summary, dashboard-AI, and health-dot modules. Key exports:
  • renderProfileContextCards() — renders the responsive nine-card grid, progress, demo AI status, and additional-context notes
  • renderInterpretiveLensSection() — renders the lens row (when set) + KB status row (when configured) + AI personalize CTA pill + Data protection CTA pill
  • renderKnowledgeBaseSection() — pure-render helper for the KB status row (returns '' when no library configured)
  • renderDataProtectionCta(stateOverride?) — pure render of the data-protection pill; accepts an explicit state override for testability
  • openPersonalizeAIPicker() — 2-card picker (Lens / Knowledge Base) shown when both are unset
  • openDataProtectionPicker() — 3-card picker (Encryption / Sync / Auto-backup) with configured cards grayed out
  • triggerDNAFilePicker() — programmatic file input trigger that routes through window.handleDNAFile; used by the genetics empty-state stub
  • loadContextHealthDots() — compatibility facade for stale-card assessment in context-card-health-dots.js
  • getCardFingerprint(key) — djb2 hash of lab data, card data, shared notes/lens, sex, and DOB for cache invalidation
  • Per-card editor functions: openDiagnosesEditor, openDietEditor, openExerciseEditor, openSleepRestEditor, openLightCircadianEditor, openStressEditor, openLoveLifeEditor, openEnvironmentEditor, openHealthGoalsEditor; Medical History helpers come from context-card-medical-history-editor.js, and lifestyle editors come through the cold-safe context-card-lifestyle-editors.js facade
  • Matching save/clear functions for all nine context areas are re-exported from their owning editor modules
  • selectCtxOption(el, group, multi) — compatibility re-export from context-card-editor-ui.js
  • getSelectedOption(group) — reads selected value from a .ctx-btn-group
  • Summary helpers such as getDietSummary() and getEnvironmentSummary() — compatibility re-exports from context-card-summaries.js
  • debounceContextNotes() — auto-saves the free-form context notes textarea
  • recordChange(field) — snapshots a context field and appends a timestamped entry to importedData.changeHistory (dedup: same-day overwrite, identical skip, 200 cap)
Window exports: none; context-card actions are module-only and use delegated data attributes or explicit lazy facades.

context-card-health-dots.js

AI-backed profile summaries, colored health dots, and short marker-linked tips for context cards. It fingerprints and caches each card independently, sends only stale cards, normalizes model output, and falls back to gray on malformed or failed responses. Demo profiles use bundled precomputed insights; local models can refresh them automatically, while cloud or paid models require in-memory consent bound to the current demo profile, provider, and model. Key exports: getDemoContextAIMode(), enableDemoContextLiveAI(), disableDemoContextLiveAI(), applyDotColor(), applyAISummary(), applyAIProfileSummary(), getCardFingerprint(), loadContextHealthDots(), refreshAllHealthDots(). Window exports: none directly; compatibility functions are exposed through context-cards.js.

context-card-summaries.js

Context card metadata, filled-state checks, dashboard summary strings, and the EMF assessment launcher/summary. Kept side-effect-light so card rendering, chat/onboarding callers, and tests can share one source of truth without pulling in every editor modal. Key exports: CONTEXT_CARD_KEYS, getContextCardDefs(), isContextFilled(key), getConditionsSummary(), getDietSummary(), getExerciseSummary(), getSleepSummary(), getLightCircadianSummary(), getStressSummary(), getLoveLifeSummary(), getEnvironmentSummary(), getGoalsSummary(), getEMFAssessments(), renderEMFAssessmentLauncher(). Window exports: none.

context-card-editor-ui.js

Shared context editor modal shell and field-control render/read helpers used by the 9 card editors. Key exports: renderContextEditorModal(), renderSelectField(), selectCtxOption(), getSelectedOption(), renderTagsField(), toggleCtxTag(), getSelectedTags(), renderNoteField(), contextEditorActions(). Window exports: none.

context-card-medical-history-editor.js

Medical History editor module for personal conditions and family history. Owns the condition autocomplete, relative allowlist, add/delete flows, modal rendering, note sync, and save/clear handlers for importedData.diagnoses. Key exports: configureMedicalHistoryEditor(), openDiagnosesEditor(), renderDiagnosesModal(), filterConditionSuggestions(), selectConditionSuggestion(), closeSuggestionsOnClickOutside(), syncDiagnosesNote(), addCondition(), editCondition(), cancelConditionEdit(), deleteCondition(), addFamilyHistoryEntry(), editFamilyHistoryEntry(), cancelFamilyHistoryEdit(), deleteFamilyHistoryEntry(), filterFamilyConditionSuggestions(), selectFamilyConditionSuggestion(), saveDiagnoses(), closeDiagnoses(), clearDiagnoses(). Window exports: none.

context-card-lifestyle-editors.js

Cold-safe facade for all lifestyle context editors. It keeps the small diet-contaminant badge path available during dashboard render, lazy-loads context-card-lifestyle-editors-impl.js on first editor action, retries a failed module fetch once with a fixed alternate URL, and forwards the save/change callbacks owned by context-cards.js. Key exports: configureLifestyleContextEditors(), renderDietContaminantsBadge(), openDietEditor(), saveDiet(), clearDiet(), openSleepRestEditor(), saveSleepRest(), clearSleepRest(), openLightCircadianEditor(), saveLightCircadian(), clearLightCircadian(), openExerciseEditor(), saveExercise(), clearExercise(), openStressEditor(), saveStress(), clearStress(), openLoveLifeEditor(), saveLoveLife(), clearLoveLife(), openEnvironmentEditor(), saveEnvironment(), clearEnvironment(), openHealthGoalsEditor(), renderHealthGoalsModal(), addHealthGoal(), deleteHealthGoal(), closeHealthGoals(), clearHealthGoals(), openInterpretiveLensEditor(), saveInterpretiveLens(), clearInterpretiveLens(), showDietContaminantsModal(). Window exports: none.

context-card-lifestyle-editors-impl.js

Main editor implementation for Diet & Digestion, Sleep & Rest, Exercise, Stress, Love Life & Relationships, and Environment. It renders the current option sets, progressive detail sections, SI/US hydration labels, diet contaminant badge, and save/clear handlers. Light, goals, interpretive lens, and the contaminant detail modal are delegated to context-card-lifestyle-special-editors.js and re-exported. Window exports: none; called through the cold-safe lifestyle facade.

context-card-lifestyle-special-editors.js

Specialized editors for Light & Circadian, prioritized Health Goals, Interpretive Lens, and diet contaminant details. It mirrors relevant Light setup values and keeps Health Goals sorted by priority. Window exports: none; re-exported through the lifestyle editor modules and context-cards.js.

Layer 5 — Feature Modules

Genome modules

The Genome feature is a lazy-loaded 10-module family. dna.js is the public orchestration barrel; parsing, evidence, UI, mtDNA, and shell integration remain separated by responsibility.
  • dna-actions.js — delegated Genome action handlers.
  • dna-evidence.js — association/evidence/relevance labels, ranking, focused Ask AI prompts, publication labels, and privacy-safe catalog issue links.
  • dna-file-detection.js — provider, annotated-report, 23andMe MT/Y, and Living DNA motherline classification.
  • dna-genotype.js — allele/repeat normalization and strand-aware catalog matching.
  • dna-mtdna.js — mutation parsing, parent/subclade resolution, mitochondrial climate-adaptation context, preview, persistence, and manual haplogroup entry.
  • dna-parser.js — Web Worker raw-file parser plus deterministic annotated/clinical report extraction.
  • dna-runtime-bridge.js — cold-safe function registry used before the Genome bundle is loaded.
  • dna-runtime.js — lazy stylesheet, pending-import, shell refresh, profile, and chat dependencies.
  • dna-ui.js — Genome section, raw/report/manual entry, association groups, evidence controls, and import previews.
  • dna.js — catalog loading, persistence, APOE resolution, re-import merge rules, AI context assembly, and public bridge registration.
Key exports:
  • detectDNAFile(text) — detects AncestryDNA, 23andMe autosomal/MT/Y, MyHeritage/FTDNA CSV, Living DNA autosomal/motherline, Illumina GSGT, and annotated SNP report formats by content.
  • parseDNAFile(file) — scans a raw file in a Web Worker against the 60-entry data/snp-health.json catalog and returns normalized matches with association, evidence, and relevance metadata; preview/save resolve APOE from the two component calls.
  • parseClinicalSnpReportText() / parseManualSnpRows() — deterministic report and small-list entry paths, including allele calls and supported numeric repeats such as 6/7.
  • upsertGeneticsSnp(profileData, rsid, genotype, source) — validates one catalog call and preserves source metadata for an explicit manual/report override.
  • saveGeneticsData(profileData, result) — refreshes raw-file calls while preserving mtDNA and manual/report overrides; an overlapping explicit override remains authoritative.
  • buildGeneticsContext(genetics, activeMarkerKeys, options) — serializes separately gated APOE/mtDNA, bounded priority findings, and optional all-call inventory. Full evidence scope/context is opt-in.
  • buildFullGeneticsContext(genetics) — explicit genetics-question path with inventory and evidence details.
  • buildSnpAIInterpretationPrompt(rsid, stored, entry) — focused, editable Ask AI baseline for one finding.
  • getRelevantSNPs(markerKey) — marker-linked findings sorted by association, relevance, and evidence presentation rank.
  • renderGeneticsSection() — Genome content with evidence/source/correction controls and raw/report/manual entry actions.
  • handleDNAFile(file) / handleSnpReportFile(file) — preview and confirm flows for raw exports and report files.
  • parseMtDNAMutations() / resolveHaplogroup() / detectMtDNAMismatch() — maternal marker parsing, specific-subclade resolution, and mitochondrial climate-adaptation latitude context.
The lazy public surface is registered through configureDnaModuleBridge(). Shell and dashboard callers use health-data-loader.js or dna-runtime-bridge.js; Genome functions are no longer installed as a broad set of window globals.

pdf-import.js

PDF/image/text-to-lab-data import pipeline and confirm/save merge logic. Key exports:
  • extractPDFText(file) — pdf.js text extraction with x/y coordinates, returns page-aware formatted text
  • parseLabPDFWithAI(pdfText, fileName, onProgress) — sends text + buildMarkerReference() to AI, extracts explicit collection time and fasting status, reports reading/writing phases, rejects truncated output, and maps complete results to marker keys
  • handleImageFile(file) — imports lab reports from JPG/PNG/WebP images via AI image pipeline
  • handleBatchPDFs(files) — sequential multi-file import with per-file confirm/skip
  • showImportPreview(parsed) — re-export from pdf-import-review.js
  • confirmImport(parsed) — merges parsed data into importedData.entries
  • setupDropZone() — legacy eager drop-zone binding retained for compatibility; page shells use import-drop-zone.js so the PDF import module stays lazy-loaded
Window exports: confirmImport, skipImport, importNextPDF, syncImportStatusFab, handleImportStatusClick, isImportRunning

pdf-import-preflight.js

Pre-AI import checks for duplicate PDF hashes, previous-model mismatch prompts, and unsupported specialty-test warnings. Key exports:
  • runPreflightChecks(pdfText, fileName) — returns false when the user cancels before token-spending import work starts
  • normalizeImportModelId(id) — shared model ID canonicalization for cross-provider import mismatch checks
Window exports: none directly; pdf-import.js calls this during PDF/batch import.

pdf-import-progress.js

Import progress bar, header import-button status, and batch progress rendering. Key exports:
  • showImportProgress(step, fileName) / hideImportProgress(reason) — render and clear the import progress UI
  • showBatchImportProgress(step, fileName, current, total) — render per-file batch progress
  • updateImportProgressPct(pct, stageLabel?) — streaming AI progress and reading/writing phase-label hook
  • syncImportStatusFab() / handleImportStatusClick() / isImportRunning() — status bridge used by pdf-import.js window exports; the legacy function name now syncs the header import button
Window exports: via pdf-import.js

pdf-import-ai-utils.js

Shared AI-import transport helpers. Key exports:
  • callImportAIWithStreamFallback(request, label) — retries browser-aborted import streams once without streaming
  • createImportAIProgress(options) — estimates prefill from prior per-model performance, then switches from Reading report to Writing results on the first generated text
  • saveImportAIPerf(key, result) — persists bounded per-model timing used by later progress estimates
  • tryParseJSON(text) / formatImportError(error) — tolerant parse and user-facing error helpers; caller-side truncation checks run before review
  • IMPORT_COLLECTION_CONTEXT_PROMPT / normalizeImportedCollectionContext() — accept only explicit specimen collection time and fasting state; reject processing/report-time substitution and clock-based fasting inference

pdf-import-marker-normalization.js

Shared AI marker normalization for PDF text import and image import. Key exports:
  • normalizeParsedImportMarkers(parsed, options) — sanitizes AI marker keys, runs product/test-type adapters, applies specialty guard rules, reconciles marker mappings, and returns { testType, markers }
Window exports: none directly; pdf-import.js calls this after AI JSON parsing.

PDF import marker and unit helpers

  • pdf-import-marker-mapping.js — canonical schema/custom/specialty matching, alias resolution, allowed calculated destinations, and the buildMarkerReference() prompt catalog.
  • pdf-import-ratio-units.js — importable calculated-marker allowlist and SI-versus-conventional convention metadata for unitless report ratios.
  • pdf-import-unit-conversions.js — valid-unit lists plus round-trip display/SI conversion for recognized and custom markers.
  • pdf-import-review-formatting.js — responsive unit controls, viewport-safe picker positioning, and range formatting used by the review modal.
These helpers keep the modal presentation separate from normalization and commit semantics. A unit change must convert the value and range together; it must not relabel unchanged numeric data.

pdf-import-persistence.js

Durable imported-data persistence helpers for PDF import flows. Key exports:
  • snapshotImportedData() / restoreImportedDataSnapshot(snapshot) — rollback guard used when durable import saves fail
  • refreshImportedDataViews() — rebuilds sidebar/header and restores the current route after imported data changes
  • removeImportedEntry(date) / renameImportedEntryDate(oldDate) — entry delete and date-edit mutations with tombstones, immediate sync save, rollback, and success refresh
Window exports: via pdf-import.js

pdf-import-review.js

Import review modal rendering and interaction state. Key exports:
  • showImportPreview(parsed) — modal with matched, new custom, unmatched, and excluded marker rows
  • applyManualImportDate(date) — updates pending review date and confirm button state
  • applyManualImportCollectionContext(patch) — updates review-time sampleTime or tri-state fasting
  • mapUnmatchedMarkerInput(input) / toggleImportRow(button) — review-row mapping and exclusion controls
  • getPendingImport() / getExcludedImportIndices() — narrow state access used by confirmImport()
  • showImportPreviewAsync(result, current, total) — batch import preview promise bridge
Window exports: via pdf-import.js

pdf-import-commit.js

Snapshot-aware import commit, re-review, deletion, range adoption, and collection-context ownership. Key contracts:
  • direct lab-reported ratios and indices normalize to their canonical Calculated Ratios destination; computed fallbacks fill only missing dates;
  • active adopted ranges are recomputed by collection date and then import time, while manual overrides preserve a stashed lab fallback;
  • collectionContextSources tracks sampleTime and fasting independently so same-date snapshot removal restores the newest remaining owner;
  • mutation paths maintain marker/snapshot tombstones and roll back on durable-save failure.
Window exports: via pdf-import.js and import-history controls.

import-drop-zone.js

Lazy drop-zone event binding shared by Dashboard, Labs, and mobile dashboard shells. It imports loadPdfImport() from import-loader.js, classifies dropped files only after interaction, and routes JSON, lab PDFs/images, text imports, and DNA files to the same handlers used by the file input path. Key exports:
  • setupDropZone() — idempotently binds click, drag, and drop handlers to #drop-zone

import-file-input.js

Lazy file-picker import binding for the hidden #pdf-input. It shares loadPdfImport() with the drop-zone path, classifies files on change, clears stale selections on failure, and routes JSON, lab PDFs/images, text imports, and DNA files through the import/DNA handlers exposed on window. Key exports:
  • bindImportFileInput() — idempotently binds #pdf-input change handling and document-level drag/drop prevention
  • handleImportInputChange(e) — routes one file-picker change event through the lazy import classifier

export.js

Data export, import, and reset. Key exports:
  • exportToJSON() — exports v2 JSON for the current profile, including entries, context, custom marker identities, markerPlacements, notes, supplements, biometrics, genetics, Light/Sun data, and supported chat state
  • buildClientExportObject(profileId, includeChat?) — module-only helper that returns the reusable v2 single-profile export object used by JSON export and encrypted profile sharing. It includes profile metadata, labs, context, supplements, genetics, biometrics, marker notes, wearables summaries/preferences, and Light/Sun data, while excluding OAuth/wearable connection credentials and raw per-device wearable rows
  • exportClientJSON(profileId) — exports a single client’s data (used from Client List ⋮ menu)
  • exportAllDataJSON() — exports a full database bundle with all profiles, chat threads, custom personalities, and settings
  • buildAllDataBundle() — builds the bundle object used by both exportAllDataJSON() and folder backup
  • importFromJSON(file) — merges entries by date, deduplicates notes, overwrites context fields, merges healthGoals by text. Auto-detects database bundles and handles multi-profile merge
  • exportToPDF() — generates a printable PDF report with all data, charts, and context cards
  • clearAllData() — confirms and wipes all imported data for the current profile
Window exports: exportToJSON, exportDataJSON, exportClientJSON, exportAllDataJSON, importFromJSON, exportToPDF, clearAllData

profile-share.js

Encrypted single-profile share links. The module creates a profile export through the module-only buildClientExportObject() helper, encrypts it in the browser with a password, posts only the ciphertext envelope to /api/share, and imports shared profiles from #share/{id} deep links after local password decryption. Shared envelopes require at least 100,000 PBKDF2-SHA256 iterations; the normal generated value is 600,000. Key exports:
  • createProfileShare({ profileId, password, expiresDays }) — builds, encrypts, uploads, and records a managed share link for one profile
  • encryptProfileShareEnvelope(exportObj, secret, options?) / decryptProfileShareEnvelope(envelope, secret) — AES-256-GCM envelope helpers using PBKDF2-SHA256
  • generateProfileSharePassword() — generates a user-copyable random password
  • buildProfileShareUrl(id) / parseProfileShareIdFromLocation(loc?) — link construction and deep-link parsing
  • openProfileShareModal(profileId?) / openSharedProfileImportModal(id) — create/load modal entry points
  • handleProfileShareDeepLink() / initProfileShareLinks() — startup hash handling for shared links
Storage: active links created in the current browser are tracked in localStorage under getbased-profile-shares-v1. Records store share metadata and the management token needed to stop sharing; they do not store the profile password or plaintext profile data. Window exports: openProfileShareModal, closeProfileShareModal, openSharedProfileImportModal, createProfileShare, deleteProfileShareEnvelope, encryptProfileShareEnvelope, decryptProfileShareEnvelope, parseProfileShareIdFromLocation, buildProfileShareUrl

chat.js

Chat public barrel and startup entry point. Importing this module installs chat-window-bindings.js and re-exports the public helpers from the feature modules. The composer/draft, bounded transcript, scroll, edit/fork, recommendation-disclosure, persona persistence, and discussion-round modules keep durable state and high-churn UI behavior out of the public barrel. See Chat internals for the end-to-end ownership, storage, Sync, and backup contract. Key exports:
  • sendChatMessage() — re-exported from chat-send.js for existing callers
  • renderChatMessages() — re-exported from chat-render.js for existing callers
  • askAIAboutMarker(markerKey) — re-exported from chat-marker-prompts.js; opens chat with a marker-specific prompt
  • askAIAboutCorrelations() — re-exported from chat-marker-prompts.js; opens chat with a selected-marker correlation prompt
  • Thread management: createNewThread(), loadThread(id), deleteThread(id), renameThread(id)
Window exports: sendChatMessage, setChatPersonality, openChatPanel, closeChatPanel, createNewThread, loadThread, deleteThread, renameThread, generateCustomPersonality, saveCustomPersonality, askAIAboutMarker, addImageAttachment, toggleHDMode

chat-window-bindings.js

Chat callback wiring and legacy window.* compatibility exports. Owns _resumeAI, configures chat-discussion.js, chat-onboarding.js, and chat-panel.js callbacks, and exposes the chat handlers needed by inline HTML and cross-module window.fn() call sites. Key exports: none; loaded for side effects by chat.js. Window exports: sendChatMessage, renderChatMessages, setChatPersonality, openChatPanel, closeChatPanel, discussion handlers, onboarding handlers, summary handlers, action-bar handlers, and per-marker Ask AI handlers.

chat-marker-prompts.js

Per-marker and selected-correlation chat prompt builders. Owns askAIAboutMarker() and askAIAboutCorrelations(), including phase-aware marker values, effective reference ranges, latest status, and trend text before opening the chat panel with a prefilled prompt. Key exports: askAIAboutMarker, askAIAboutCorrelations Window exports: assigned by chat-window-bindings.js for existing inline Ask AI buttons.

chat-send.js

Direct chat send and streaming state. Owns sendChatMessage(), Enter-key handling, thread-bound abort state, send-button icon mode, typewriter trickle, image attachment payload injection, API message assembly, usage footnotes, live EMF/product recommendation injection, and partial-message persistence on abort. It delegates textarea/draft behavior to chat-composer.js, concise assistive status to chat-stream-status.js, continuation handling to chat-continuation.js, and collapsed recommendation state to chat-recommendation-disclosure.js. Key exports: sendChatMessage, handleChatKeydown, isChatStreaming, createTypewriter, getChatAbortController, setChatAbortController, setSendButtonMode, updateSendButtonState Window exports: updateSendButtonState is assigned by this module for chat-images.js; other user-facing handlers are assigned by chat-window-bindings.js.

chat-render.js

Chat transcript rendering. Owns renderChatMessages() for persisted messages, latest-turn and fork action placement, lens-source disclosures, assistant footnotes, image badges, EMF hints, and persisted recommendation sections. It renders only the range supplied by chat-render-range.js, delegates scroll ownership to chat-scroll.js, and reveals earlier batches without truncating stored history. Key exports: renderChatMessages, showEarlierChatMessages, revealChatMessage, _getNoDataPrompts, _renderLensSources Window exports: renderChatMessages is assigned by chat-window-bindings.js for existing inline handlers and cross-module callbacks.

chat-empty-state.js

Empty chat and chat-first onboarding message composition. Owns the profile setup bubble, paused-AI prompt, explicit provider quiz entry state, no-lab optional setup cards, no-data prompt selection, and the default empty prompt buttons used before a real thread has messages. Key exports: renderEmptyChatState, _getNoDataPrompts Window exports: none; called by chat-render.js.

chat-panel.js

Chat panel chrome and entry-state helpers. Owns open/close/fullscreen behavior, persisted fullscreen preference, web-search toggle persistence/visibility, and composer disabled state. It imports thread/history/personality helpers directly, delegates FAB nudge dismissal to chat-nudge.js, and receives the active-discussion restore callback through configureChatPanel() to avoid importing chat-discussion.js. Key exports: configureChatPanel, toggleChatPanel, toggleChatFullscreen, openChatPanel, closeChatPanel, updateChatInputState, getChatWebSearchEnabled, setChatWebSearchEnabled, refreshWebSearchToggle; also re-exports setChatNudge and updateChatNudge from chat-nudge.js for compatibility. Window exports: assigned by chat-window-bindings.js for existing inline handlers and cross-module callbacks.

chat-composer.js

Growing textarea and active-thread draft coordinator. It binds visible input to { profileId, threadId }, restores drafts after async thread switches, clears a sent draft, and prevents a late decrypt from writing into a newly selected thread. Key exports: configureChatComposer, initChatComposer, resizeChatInput, saveChatDraft, getChatDraft, restoreChatDraft, clearChatDraft, resetChatComposer, setChatInputValue. Window exports: none.

chat-draft-storage.js

Device-local draft cache and 300 ms debounced persistence. Draft keys use the sensitive storage wrapper but are intentionally excluded from Sync and every backup/export path. Its ordered write chain prevents a pending save from resurrecting a cleared draft. Key exports: chatDraftStorageKey, getCachedChatDraft, loadChatDraft, rememberChatDraft, clearStoredChatDraft, flushStoredChatDraft. Window exports: none.

chat-render-range.js, chat-scroll.js, and chat-stream-status.js

Transcript-scale and interaction helpers. chat-render-range.js exposes the latest 120 records and expands in 120-record batches; chat-scroll.js follows streaming only while the user remains near the latest message; chat-stream-status.js emits concise ARIA status changes without making every streamed token a live-region update. Window exports: none.

chat-nudge.js

Chat FAB nudge badge state. Owns nudge stage persistence, per-profile dismissal, badge/pulse DOM updates, and the profile/API/data/context card readiness check used by startup, settings, onboarding, DNA import, and panel-open flows. Key exports: setChatNudge, dismissCurrentChatNudge, updateChatNudge Window exports: assigned by chat-window-bindings.js for existing inline handlers and cross-module callbacks.

chat-onboarding.js

Chat-first onboarding helpers. Owns the provider quiz render helper, onboarding progress crumbs, profile/location/cycle/supplement handlers, lab-import CTA behavior, context-card nudge callback, and prompt CTA helper. It receives renderChatMessages, sendChatMessage, closeChatPanel, and nudge callbacks from chat-window-bindings.js through configureChatOnboarding() so it can update the shared chat UI without importing chat UI modules directly. Key exports: configureChatOnboarding, useChatPrompt, requestOnboardingLabImportProvider, startOnboardingLabImport, _renderOnboardCrumbs, _renderProviderQuiz, _countFilledCards, setChatProfileSex, saveChatProfile, saveChatLocation, onboardHeightUnitChanged, saveChatPeriod, addChatSupplement, removeChatSupplement, setProviderQuizBranch, backToProviderQuiz, skipProviderSetup, skipOnboardingExtras, showCycleNoMensesOptions, showCyclePeriodEntry, saveCycleStatus, _updatePeriodBtn, onContextCardSaved Window exports: assigned by chat-window-bindings.js for existing inline handlers and context-cards.js callbacks.

chat-discussion.js

Multi-persona discussion public barrel. Re-exports discussion flow handlers from chat-discussion-flow.js, callback configuration from chat-discussion-callbacks.js, UI compatibility helpers from chat-discussion-ui.js, and persona/thread state helpers from chat-discussion-state.js. Key exports: configureChatDiscussion, getThreadPersonaCount, updateDiscussButton, getCurrentDiscussionState, sendDiscussionUserTurn, restoreDiscussionContinuePrompt, showDiscussContinuePrompt, removeDiscussContinuePrompt, cleanupDiscussionState, startDiscussion, startDiscussionFromPicker, continueDiscussion, endDiscussion Window exports: assigned by chat-window-bindings.js for existing inline handlers and chat-threads.js callbacks.

chat-discussion-flow.js

Multi-persona discussion public user-action handlers. Owns manual-message entry, Continue, Discuss, and picker-start actions. It delegates cleanup/completion to chat-discussion-lifecycle.js, turn execution to chat-discussion-turns.js, and picker/prompt DOM through chat-discussion-ui.js. Key exports: sendDiscussionUserTurn, restoreDiscussionContinuePrompt, showDiscussContinuePrompt, cleanupDiscussionState, startDiscussion, startDiscussionFromPicker, continueDiscussion, endDiscussion Window exports: none directly; chat-discussion.js re-exports the public handlers and chat-window-bindings.js assigns the compatibility handlers.

chat-discussion-lifecycle.js

Discussion cleanup and completion helpers. Owns active-discussion restore, continuation prompt persistence, transient UI cleanup, explicit end lifecycle, original-persona restore, Discuss button/header refresh, and post-round Continue prompt handoff. Key exports: restoreDiscussionContinuePrompt, showDiscussContinuePrompt, cleanupDiscussionState, endDiscussion, finishDiscussionRound Window exports: none directly; chat-discussion-flow.js re-exports the public lifecycle handlers.

chat-discussion-turns.js

Discussion turn execution helpers. Owns continuation round dispatch, first debate turn dispatch, single joined-persona turn dispatch, joined-persona marker insertion, thread-bound discussion state persistence, and round completion handoff. Key exports: runDiscussionContinuation, runSingleDiscussionTurn, runDiscussion Window exports: none.

chat-discussion-callbacks.js

Discussion callback bridge. Owns configureChatDiscussion() and the callback wrappers that let discussion rounds reuse chat-send streaming state, send-button mode, transcript rendering, and typewriter behavior without importing chat-send.js. Key exports: configureChatDiscussion, getChatAbortController, setChatAbortController, renderChatMessages, setSendButtonMode, createDiscussionTypewriter Window exports: none directly; chat-discussion.js re-exports configureChatDiscussion for chat-window-bindings.js.

chat-discussion-round-runner.js

Discussion round execution loop. Owns sequential per-persona API calls, progress and assistive status, pause/abort state, origin-thread persistence, typewriter updates, usage footnotes, partial-response preservation, and targeted failure records. It returns the remaining participants so resume and per-participant retry do not replay successful responses. Key exports: runDiscussionRound Window exports: none.

chat-discussion-round-prompts.js

Discussion round prompt helpers. Owns the default follow-up prompt, initial-analysis prompt, joined-persona prompt, auto-message shape, joined-persona marker shape, and the first-turn versus rebuttal prompt selection logic. Key exports: DEFAULT_DISCUSS_PROMPT, INITIAL_DISCUSS_PROMPT, DISCUSSION_JOIN_PROMPT, hasExistingDiscussionResponses, getDiscussionPromptText, buildDiscussionAutoMessage, buildDiscussionJoinMessage Window exports: none.

chat-discussion-round-request.js

Discussion round API request helpers. Owns lab-context and lens enrichment, active personality prompt assembly, provider/model/web-search snapshots, tagged history messages, assistant message metadata, and usage tracking for multi-persona rounds. Key exports: buildDiscussionRoundRequest, buildDiscussionAssistantMessage, trackDiscussionUsage Window exports: none.

chat-discussion-round-state.js

Thread-bound discussion round persistence helpers. Owns origin-thread activity checks, discussion metadata writes, active-thread repaint handoff, and off-thread history persistence during streaming rounds. Key exports: isRoundThreadActive, persistDiscussionThreadState, renderRoundMessages, saveRoundChatHistory Window exports: none.

chat-discussion-round-view.js

Live discussion round DOM helpers. Owns typing indicators, persona labels, streamed assistant message nodes, final markdown replacement, usage footnotes, and active-thread-only error rendering for multi-persona rounds. Key exports: createDiscussionTypingIndicator, createDiscussionPersonaLabel, appendRoundPersonaLabel, createDiscussionAiMessage, renderFinalDiscussionMessage, appendDiscussionUsageFootnote, renderDiscussionRoundError Window exports: none.

chat-discussion-ui.js

Multi-persona discussion button and continuation prompt controls. Owns the Discuss button visibility/add-persona state and transient state handoff used by continueDiscussion() and endDiscussion(). Re-exports picker helpers from chat-discussion-picker.js so existing discussion flow imports stay stable. Key exports: updateDiscussButton, showDiscussContinuePrompt, removeDiscussContinuePrompt, removeDiscussPersonaPicker, readDiscussPersonaPickerSelection, showDiscussPersonaPicker Window exports: none directly; chat-discussion.js wraps/re-exports public controls and chat-window-bindings.js assigns the compatibility handlers.

chat-discussion-picker.js

Multi-persona discussion picker controls. Owns persona picker markup, active-persona locking, one-at-a-time participant addition, request-count/charge disclosure, keyboard dismissal, checkbox limiting, and picker selection reads. Key exports: removeDiscussPersonaPicker, readDiscussPersonaPickerSelection, showDiscussPersonaPicker Window exports: none.

chat-discussion-state.js

Multi-persona discussion state helpers. Owns per-thread active discussion detection, history fallback persona collection, current-thread lookup, unique assistant-persona counts, and current-thread discussion lifecycle metadata. Key exports: getThreadPersonaCount, collectDiscussionPersonas, getCurrentThread, clearCurrentDiscussionThreadState, reopenCurrentDiscussionThread, getCurrentDiscussionState Window exports: none directly; chat-discussion.js re-exports the public count/state helpers and chat-window-bindings.js assigns them.

chat-personalities.js

Personality selection and workflow facade. It renders the picker and chat header, invokes the dedicated custom-persona dialog, streams an editable generated draft, persists through chat-personality-storage.js, and updates the active thread’s personality metadata. Key exports: getActivePersonality, getCustomPersonalities, loadCustomPersonalities, saveCustomPersonalities, getCustomPersonality, setChatPersonality, loadChatPersonality, updateChatHeaderTitle, updateChatHeaderModel, updatePersonalityBar, togglePersonalityBar, generateCustomPersonality, saveCustomPersonality, startNewCustomPersonality, editCustomPersonality, deleteCustomPersonality. Window exports: assigned by chat-window-bindings.js for existing inline handlers and cross-module callbacks.

chat-personality-editor.js

Custom persona modal and host policy. The official getbased.health host requires a versioned acknowledgement that a persona is an AI-generated interpretation and cannot be used to impersonate or imply endorsement. Self-hosted origins receive the responsibility notice without a required checkbox. Key exports: isOfficialHostedPersonaApp, hasCurrentPersonaAgreement, isCustomPersonalityUsable, buildPersonaAgreementRecord, openPersonaEditorDialog. Window exports: none.

chat-personality-storage.js and chat-personality-merge.js

Encrypted-wrapper persistence, synchronous decrypted cache, deletion tombstones, and deterministic per-persona Sync merge. Persona updates resolve by updatedAt/createdAt; a tombstone at least as new as the record removes it without replacing unrelated personas. Key exports: storage-key helpers, load/save/cache helpers, recordCustomPersonalityDeletion, customPersonalityUpdatedAtMs, and mergeCustomPersonalityState. Window exports: none.

chat-history.js

Thread-aware chat message persistence and clearing. The module owns the legacy storage key helper, encrypted/plain thread message load/save, thread metadata updates, saved-summary cleanup, and the clear-history confirmation flow. It uses window.renderChatMessages?.() and window.updateDiscussButton?.() callbacks for repaint/discussion hooks that would otherwise create a chat.js import cycle. Key exports: getChatStorageKey, loadChatHistory, saveChatHistory, clearChatHistory Window exports: assigned by chat-window-bindings.js for existing inline handlers and chat-threads.js callbacks.

chat-threads.js

Conversation index CRUD, active-thread switching, linked fork creation, rail rendering, and thread deletion tombstones. pruneOldThreads() is a compatibility no-op. An existing index that cannot be decrypted or parsed blocks writes and new-chat creation rather than replacing saved conversations with an empty index. Key exports: loadChatThreads, saveChatThreadIndex, ensureActiveThread, createNewThread, createForkedThread, switchToThread, deleteThread, renameThread, renderThreadList, and the search compatibility exports. Window exports: assigned through chat-window-bindings.js where legacy callers still require them.

chat-thread-search.js

Thread rail message-content search and match highlighting. It owns the debounced per-thread content search, encrypted/plain message reads, result rendering, cache invalidation, jump-to-result behavior, and in-message mark/highlight cleanup while receiving thread key, rail render, and switch callbacks from chat-threads.js. Key exports: configureChatThreadSearch, filterThreadList, invalidateThreadContentCache, jumpToSearchResult Window exports: re-exported and assigned by chat-threads.js for existing inline handlers.

chat-actions.js

Chat message action rendering and delegated handlers. It owns Retry/Regenerate, Copy, Listen, context details, responsive overflow actions, discussion pause/resume/retry controls, and callbacks into latest-message editing and linked forks. Voice actions cross the lazy boundary through voice-loader.js. Key exports: configureChatMessageActionDeps, installChatMessageActionDelegates, buildActionBar, buildUserActionBar, buildForkSourceNotice, regenerateLastMessage, copyMessage, toggleContextDetails. Window exports: assigned by the module directly and re-exported by chat.js for existing inline handlers.

chat-message-edit.js

Latest-turn inline editor and non-destructive assistant-reply forks. Edit-and-retry is limited to the latest visible text-only user message while no response is streaming; fork creation copies normalized history through the selected assistant message into a linked thread. Key exports: configureChatMessageEditDeps, getLatestUserMessageIndex, beginChatMessageEdit, cancelChatMessageEdit, submitChatMessageEdit, prepareChatMessageEditSend, forkChatFromMessage. Window exports: none; chat-actions.js receives callbacks.

chat-recommendation-disclosure.js and chat-storage-safety.js

chat-recommendation-disclosure.js persists related suggestions collapsed and marks only the first or materially changed slot set as new. chat-storage-safety.js normalizes untrusted chat, thread, persona, tombstone, discussion/fork, usage, and image shapes before import, restore, or Sync apply. Window exports: none.

chat-icons.js

Shared chat SVG icon strings and icon-button DOM helper extracted from chat.js. Keeps action buttons and streaming send/stop button state changes using the same symbols without keeping SVG construction code in the chat orchestration module. Key exports: CHAT_ICON_COPY, CHAT_ICON_REFRESH, CHAT_ICON_EDIT, CHAT_ICON_X, setIconButtonContent Window exports: none

chat-attestation.js

Private-transport attestation display helpers shared by the chat header and assistant-message cost footnotes. Tinfoil uses 🔒 verified after its full policy passes. Venice uses 🔒 TEE + GPU after its required DCAP and signed NRAS checks pass, while the tooltip keeps code-measurement, co-location, and response-source limits visible. Key exports: attestationTooltip, e2eeLockHTML, e2eeLockFootnote Window exports: none

chat-continuation.js

Response limit detection and automatic continuation wrapper for chat and discussion calls. Centralizes token-headroom constants, incomplete-response heuristics, continuation prompt construction, and usage merging. Key exports: CHAT_RESPONSE_MAX_TOKENS, callChatAPIWithContinuation, isAIResponseTruncated, responseLimitNote Window exports: none

chat-prompt-context.js

Pure prompt/message helpers shared by direct chat sends and multi-persona discussion rounds. Centralizes persona prompt additions, cross-persona API-message tagging, web-search/E2EE system hints, system-prompt assembly, and persisted lens-source serialization. Key exports: buildPersonalityPrompt, buildMultiPersonaInstruction, buildTaggedChatMessages, buildWebSearchHint, buildChatSystemPrompt, serializeLensSources, attachLensSources Window exports: none

chat-summaries.js

Conversation summary generation, saved-summary profile storage, and summary modal actions extracted from chat.js. Key exports: summarizeThread, renderSavedSummaries, viewSavedSummary, deleteSavedSummary, closeSummaryModal, copySummary, downloadSummary, printSummary Window exports: assigned by chat-window-bindings.js for existing inline handlers.

Voice subsystem

Voice is a first-use chat subsystem rather than part of the startup bundle. voice-loader.js keeps microphone capture and speech dependencies cold until the user records, listens, or enables automatic reading. It binds each pending action to the active chat thread and message so late transcription or speech work cannot update a stale conversation. Chat orchestration:
  • voice-controller.js owns microphone state, transcript insertion, per-message playback, automatic reading, cancellation, and thread/message identity checks.
  • voice-capture.js, voice-player.js, voice-audio.js, and voice-text.js own ephemeral recording, progressive audio playback, PCM/WAV handling, and safe speech-text normalization/chunking.
  • voice-service.js and voice-provider-registry.js select the configured STT/TTS provider without coupling chat controls to provider implementations.
Provider paths:
  • voice-provider-browser-local.js runs downloaded Whisper STT and Kokoro TTS through voice-local-stt-worker.js, voice-local-tts-worker.js, and the serialized voice-local-engine.js worker controller.
  • voice-provider-local-server.js calls OpenAI-compatible /v1/audio/transcriptions, /v1/audio/speech, and /v1/models endpoints directly from the browser.
  • voice-provider-xai.js and voice-provider-elevenlabs.js use voice-provider-cloud-shared.js to call the bounded same-origin /api/voice relay.
  • voice-provider-catalog.js owns capability and execution-location metadata; voice-model-catalog.js pins local models, voices, languages, download sizes, and CPU/WebGPU modes.
Settings and storage:
  • settings-voice-panel.js, settings-voice-view.js, settings-voice-model-controller.js, and settings-voice-hardware.js own the Settings → Voice UI, downloads, connection tests, voice catalogs, and hardware guidance.
  • voice-settings-schema.js is the authority for device-local, syncable, secret, and backup keys. voice-settings-storage.js validates preferences and delegates secret writes to encrypted provider storage.
  • Downloaded model assets and fetched voice catalogs are rebuildable caches. They are not sync payloads or backup data.
Server boundary: api/voice.js delegates to lib/voice-relay-handler.js; lib/voice-relay-policy.js allowlists providers/actions, bounds request and response sizes, validates identifiers and languages, and maps normalized requests to xAI or ElevenLabs. Key exports: loadVoiceModule, toggleVoiceRecording, toggleMessageSpeech, maybeAutoReadAssistantMessage, stopVoiceActivity, getVoiceSettings, setVoiceSetting, transcribeVoice, createVoiceSynthesizer Window exports: none; chat and shell actions use module callbacks.

settings.js

Settings modal shell with profile, display, AI, Voice, privacy, data, wearables, and Agent Access tabs. Delegates AI provider panels to provider-panels.js, Voice rendering and actions to settings-voice-panel.js, wearables rows to wearables-settings-panel.js, sync controls to settings-sync-panel.js, and Agent Access rendering/actions to settings-agent-access-panel.js. Key exports:
  • openSettingsModal() / closeSettingsModal()
  • initSettingsModelFetch() — fetches model lists for all providers on modal open
  • saveProfileSettings() — saves sex, DOB, location from the Profile section
  • setUnitSystem(system)'EU' | 'US'
Window exports: openSettingsModal, closeSettingsModal, saveProfileSettings, setUnitSystem, setAIProvider, startTour

settings-sync-panel.js

Cold facade for the Cross-device Sync and Agent Access settings graph. A first Settings render returns marked loading placeholders and starts settings-sync-panel-impl.js; when the import resolves, the facade replaces both placeholders in place so the real controls appear without closing and reopening Settings. Action calls use the same loader and retry boundary. Key exports:
  • renderSyncSection() — renders the Settings → Data sync panel
  • renderMessengerSection() — compatibility export that renders the Settings → Agent Access panel through settings-agent-access-panel.js
  • hydrateSettingsSyncPanel() — forwards post-paint mnemonic and relay hydration after the implementation loads
  • showSyncSetupModal() — loads the implementation and opens the setup wizard
Window exports: showSyncSetupModal, toggleSync, toggleMnemonicVisibility, copyMnemonic, saveSyncRelay, openRestoreMnemonicDialog, closeRestoreMnemonicDialog, confirmRestoreMnemonic, closeSyncSetup, syncSetupNew, syncSetupRestore, syncSetupBack, syncSetupDoRestore, syncSetupDone, toggleMessenger, toggleMessengerToken, copyMessengerToken, regenerateMessengerToken

settings-sync-panel-impl.js

Loaded implementation for the Settings → Data sync section. It owns setup/restore UI, mnemonic and relay controls, diagnostics entry points, and Agent Access delegation. Existing-mnemonic joins call the controlled restore path in sync-identity.js. Key exports: configureSettingsSyncPanelDeps, renderSyncSection, renderMessengerSection, showSyncSetupModal, closeSyncSetup, closeRestoreMnemonicDialog, hydrateSettingsSyncPanel. Window exports: none directly; the facade owns compatibility bindings.

settings-agent-access-panel.js

Settings → Agent Access renderer and action handler. It owns the enable/disable state, synced Agent Access metadata, read-only relay token display, local context-key display, wearable daily-series window, and the one-paste setup-command builder for supported MCP clients. Key exports:
  • renderMessengerSection() — renders the Agent Access settings panel, including the target-client chip group
  • buildAgentAccessSetupCommand(client) — builds the private gbsetup_v1_... bootstrap command for hermes, openclaw, claude-code, claude-desktop, cursor, cline, or codex
  • handleMessengerAction(action, el) — delegated action handler for enabling, regenerating, copying secrets, copying setup commands, and series-window changes
  • toggleMessengerToken() / copyMessengerToken() / regenerateMessengerToken() — compatibility actions for legacy window bindings

feedback.js

In-app feedback modal. Key exports:
  • openFeedbackModal() / closeFeedbackModal()
  • submitFeedback() — validates and submits feedback (bug report or feature request)
Window exports: openFeedbackModal, closeFeedbackModal, submitFeedback
Sidebar navigation, profile switcher, and mobile sidebar shell. Key exports:
  • buildSidebar(data) - renders Home, Lenses, Tools, and lab category navigation with marker counts
  • filterSidebar() - filters lab categories and keeps top-level app routes visible during search
  • toggleNavGroup(groupId) - expands/collapses sidebar category groups
  • renderProfileDropdown() / renderProfileButton() - profile switcher UI
  • openRecommendationsFromSidebar() - compatibility helper that routes to the dedicated recommendations page
Window exports: buildSidebar, filterSidebar, toggleNavGroup, renderProfileDropdown, renderProfileButton, toggleMobileSidebar, closeMobileSidebar, openRecommendationsFromSidebar

Layer 6 — Orchestration

views-router.js

Route validation, per-profile last-view persistence, mobile tab sync handoff, and element-anchor scroll preservation. views.js creates the concrete navigator by passing render handlers into createNavigate(). Key exports:
  • createNavigate({ routeHandlers, syncMobileBottomNav }) — builds the app-level navigate() function without importing page renderers
  • getInitialView() — restores the active profile’s last valid route, falling back to dashboard
  • isKnownRoute(route, data?) — validates fixed routes and data-backed lab category routes

lens-pages.js

Dedicated page renderers for Labs, Genome, Body, Insight, and Recommendations. The module receives dashboard, recommendation, and lens shell helper functions from views.js through createLensPageHandlers() so page rendering can move out of the main views module without creating new import cycles. Key exports:
  • createLensPageHandlers(deps) — returns showLabs, showGenomeLens, showBodyLens, showInsightLens, and showRecommendations

dashboard-page-view.js

Dashboard route shell and page-level dashboard orchestration. dashboard-view-composition.js creates it with createDashboardPageView() after wiring dashboard widget renderers, controls, and registry helpers, so the dashboard route can live outside the main compatibility module without importing the widget control layer directly. Key exports:
  • createDashboardPageView(deps) — returns showDashboard(data?); owns the populated dashboard shell, empty welcome/demo state, import drop-zone setup calls, mobile dashboard handoff, focus-card hydration, context-dot hydration, and first-visit tour triggers

dashboard-view-composition.js

Dashboard route, widget, mobile handoff, marker-modal, and lens-shell composition wiring. views.js creates this layer once and keeps compatibility facades, while this module wires dashboard-page-view.js, dashboard-widgets.js, dashboard-widget-controls.js, dashboard-widget-renderers.js, and mobile dashboard dependencies together. Key exports:
  • createDashboardViewComposition(deps) — returns showDashboard, dashboard widget control handlers, recommendation helpers, and dashboard render helpers needed by lens pages and recommendation actions

lens-page-shell.js

Shared lens page chrome and ordering helpers used by views.js and lens-pages.js. The module owns lens headers, reorderable page widget wrappers, per-profile lens widget order persistence, page-section move controls, dashboard add/remove toggles, and the delegated action attributes/listener used by shared lens chrome. Key exports:
  • configureLensPageShell(deps) — injects dashboard widget visibility helpers without importing dashboard modules directly
  • renderLensHeader(title, subtitle, actions?) — renders the shared lens page header
  • renderLensPageWidgets(route, widgets) / renderLensWidget(...) — render reorderable page widgets and their chrome
  • moveLensPageWidget(route, id, direction) — persists per-profile page section order and refreshes the active route
  • lensPageActionAttrs(action, attrs?) — builds escaped data-lens-page-* attributes consumed by the shared delegated click listener

dashboard-widgets.js

Dashboard widget registry and persistence helpers. dashboard-view-composition.js supplies renderer functions from dashboard-widget-renderers.js to createDashboardWidgetRegistry() so widget metadata, defaults, availability gates, per-profile widget preferences, custom marker widget IDs, and visible-entry generation can live outside the main views module. Key exports:
  • createDashboardWidgetRegistry(renderers, opts?) — returns dashboard widget definitions plus preference/order helpers
  • DASHBOARD_WIDGET_SOURCE_ORDER — Lens/source ordering for the widget picker
  • DASHBOARD_WIDGET_DEFAULT_IDS — new-profile dashboard default order
  • DASHBOARD_MANUAL_BIOMETRIC_METRICS and dashboardBiometricSelectionKey() — biometrics widget selection helpers

dashboard-widget-controls.js

Dashboard widget picker, widget chrome, layout actions, and drag/reorder controls. dashboard-view-composition.js creates the control layer with registry, marker, and biometrics dependencies; views.js re-exports the public handlers for existing window.* integrations. Key exports:
  • createDashboardWidgetControls(deps) — returns render helpers and dashboard widget action handlers

dashboard-widget-renderers.js

Dashboard widget body renderers and shared recommendation helpers. dashboard-view-composition.js creates the renderer layer with Light helper and mobile-summary dependencies, then passes the returned renderers to dashboard-widgets.js, dashboard-widget-controls.js, and lens-pages.js. Key exports:
  • createDashboardWidgetRenderers(deps) — returns dashboard body renderers, dashboard context builders, biometrics helpers, custom marker renderer support, and recommendation helper functions

category-view-renderers.js

Category chart card, table, heatmap, and fatty-acid profile renderers. category-page-view.js calls these helpers for category route content, while views.js imports and re-exports them so existing module and window.* integrations stay stable. Key exports:
  • renderChartCard(id, marker, dateLabels) — renders one category/dashboard marker card and registers it for the detail modal
  • renderTableView(cat, dateLabels, categoryKey, dates) / renderHeatmapView(cat, dateLabels, dates, categoryKey) — render category table shells with empty-value add affordances
  • renderFattyAcidsView(cat, categoryKey) / renderFattyAcidsCharts(cat) — render the single-date fatty-acid profile cards and bar chart

category-page-view.js

Category route shell and view-mode orchestration. The module owns showCategory(), switchView(), category card sorting, range-toggle order preservation, chart hydration, and chart-card recommendation loading. It depends on category-view-renderers.js for HTML fragments and keeps views.js as a thin router/compatibility facade. Key exports:
  • showCategory(categoryKey, data?) — renders the category header, view tabs, date/layer controls, chart grid, empty marker affordances, and saved table/heatmap mode
  • switchView(view, categoryKey, btn) — switches between chart, table, and heatmap modes, updates tab ARIA state, destroys stale charts, and rehydrates charts when needed

category-customization.js

Category and marker display override helpers. The module owns category rename, marker rename/revert, the emoji picker, and category icon override persistence while views.js keeps compatibility exports and injects navigation via configureCategoryCustomization(). Key exports:
  • configureCategoryCustomization(deps) — injects the app-level navigate() function without importing views.js
  • renameCategory(categoryKey) / renameMarker(id) / revertMarkerName(id) — persist display-name overrides into importedData.categoryLabels and importedData.markerLabels
  • showEmojiPicker(anchorEl, callback, opts?) — shared category/custom-marker emoji picker used by category views and the marker creation modal
  • changeCategoryIcon(categoryKey) — persists importedData.categoryIcons overrides and mirrors custom marker category icon metadata

category-order.js

Shared, DOM-independent ordering for lab navigation and category controls. getLabCategoryEntriesInSidebarOrder() keeps regular categories first and preserves schema order within specialty groups so the placement picker and sidebar agree.

marker-detail-placement.js

Marker-detail category picker and persistence controller. It lists only destinations accepted by marker-placement.js, groups categories present in the profile before other compatible categories, preserves sidebar order, serializes per-profile mutations, and provides restore-to-native behavior. Key exports: configureMarkerDetailPlacement(), getMarkerPlacementChoices(), renderMarkerPlacementSummary(), openMarkerPlacementModal(), saveMarkerPlacement(), and restoreMarkerPlacement().

views.js

Tool page routing and compatibility exports. Dashboard composition lives in dashboard-view-composition.js; dashboard route shell lives in dashboard-page-view.js; dashboard widget body renderers live in dashboard-widget-renderers.js; recommendation action handlers live in recommendation-actions.js; category route orchestration lives in category-page-view.js; category card/table/heatmap renderers live in category-view-renderers.js; category display overrides live in category-customization.js; the Light page shell lives in light-page-view.js; Light channel pills and drill-down panels live in light-channel-view.js; shared lens page chrome lives in lens-page-shell.js; public navigation and lens page functions remain exported here for compatibility, backed by views-router.js and delegated to route modules where applicable. Key exports:
  • navigate(section, params) — router facade created from views-router.js; calls the appropriate render function
  • showDashboard(data?) - compatibility facade backed by dashboard-view-composition.js and dashboard-page-view.js; renders the customizable widget dashboard whose default widget order starts with Biological Coherence, Current Focus, Current Priority, Quick Markers, Key Trends, Recommended Next Steps, Profile Context, Biometrics Overview, Biological Age, Metabolic Flexibility, and Cycle when available
  • showLabs(data?), showGenomeLens(), showBodyLens(), showInsightLens(data?), showRecommendations(data?) - compatibility facades delegated to lens-pages.js
  • showCategory(categoryKey, data?) - compatibility facade imported from category-page-view.js
  • showLight(data?), renderLightTodayStrip(), renderLightChannelsLive() - compatibility facades imported from light-page-view.js
  • showCompare(data?) / showCorrelations(data?) - focused tool pages
  • Dashboard widget controls: compatibility facades backed by dashboard-widget-controls.js, including openDashboardWidgetPicker(), toggleDashboardOrganizeMode(), resetDashboardWidgets(), clearDashboardWidgets(), addDashboardWidgetFromLens(), and removeDashboardWidgetFromLens()
  • showDetailModal(markerKey, data?) — opens the marker detail modal
Window exports: navigate, showDashboard, showLabs, showGenomeLens, showBodyLens, showInsightLens, showRecommendations, showLight, showCategory, showDetailModal, dashboard widget controls, and recommendation page helpers (openRecommendationDetail, discussRecommendation, saveRecommendation, dismissRecommendation)

recommendation-actions.js

Recommendation modal and action handlers shared by dashboard cards and the Recommendations page. It keeps option-detail rendering, chat prompts, saved/bookmarked state, and dismissed state out of the main route facade. Key exports:
  • createRecommendationActions(deps) — returns openRecommendationDetail(), discussRecommendation(), saveRecommendation(), and dismissRecommendation()

light-page-view.js

Light & Sun page shell, Light Today strip, dashboard Light channel pills, Light session log actions, page widget assembly, and async population of page-only Light workbench sections. It imports shared lens chrome from lens-page-shell.js, condition rendering from light-conditions-now.js, session history from light-sessions-view.js, and channel rows/suggestions from light-channel-view.js. Key exports:
  • showLight(data?) — renders the reorderable Light & Sun page widgets
  • renderLightTodayStrip() — legacy compact Light strip used by embedded/welcome surfaces
  • renderLightChannelsLive() — refreshes the live channel-pills slot after session updates
  • renderDashboardLightChannelPills() / renderLightSessionLogActions() — dashboard widget helper bodies shared through dashboard-widget-renderers.js
  • _expandLightToolsSection() — compatibility handler for expanding the collapsed Light tools placeholder

light-channel-view.js

Light channel pill rows, seven-day sparklines, dashboard-to-Light channel navigation, per-channel drill-down panels, citations, source mix, and channel suggestions. light-page-view.js imports the render helpers; views.js keeps the legacy window._toggleChannelDetail / window._openChannelOnLightPage wiring for inline handlers and dashboard widgets. Key exports:
  • mergeTotals(a, b) — combines sun and device channel totals
  • renderChannelPills(totals7d, totals30d) — renders the interactive Light page channel row and detail slot
  • _toggleChannelDetail(channelKey) / _openChannelOnLightPage(channelKey) — compatibility handlers for expanding channel detail panels
  • renderSuggestion(totals7d) — fallback channel-guidance copy when AI synthesis is unavailable

main.js

Thin module entry point. Imports startup feature side effects, then starts the startup orchestrator. Responsibilities:
  • Imports app-feature-modules.js for startup-loaded feature side effects and window exports
  • Calls startApp() from startup-orchestrator.js
Window exports: none (all exports come from other modules)

app-feature-modules.js

Startup-loaded feature side-effect imports extracted from main.js. This module preserves the previous feature import order while keeping main.js focused on startup orchestration. Foundation/privacy imports are grouped behind app-foundation-modules.js; the Health & Data feature cluster is grouped behind app-health-data-modules.js; the Light & Sun feature cluster is grouped behind app-light-sun-modules.js; the import/export feature cluster is grouped behind app-data-io-modules.js; the AI/chat/settings feature cluster is grouped behind app-ai-interaction-modules.js; the UI shell feature cluster is grouped behind app-ui-shell-modules.js. Key exports: none Window exports: none directly; imported feature modules attach their existing compatibility handlers.

app-foundation-modules.js

Startup-loaded foundation/privacy side-effect imports extracted from app-feature-modules.js. This module preserves the previous schema/constants/utils/pii import order while keeping the top-level feature list as named startup clusters. Key exports: none Window exports: none directly; imported foundation modules attach their existing compatibility handlers.

app-health-data-modules.js

Startup-loaded Health & Data feature side-effect imports extracted from app-feature-modules.js. This module preserves the previous charts/notes/supplements/recommendations/cycle/context/DNA/wearables import order while keeping the top-level feature list easier to scan. Key exports: none Window exports: none directly; imported Health & Data modules attach their existing compatibility handlers.

app-light-sun-modules.js

Startup-loaded Light & Sun feature side-effect imports extracted from app-feature-modules.js. This module preserves the previous Light & Sun import order while keeping the top-level feature list easier to scan. Key exports: none Window exports: none directly; imported Light & Sun modules attach their existing compatibility handlers.

app-data-io-modules.js

Startup-loaded import/export feature side-effect imports extracted from app-feature-modules.js. This module owns the compatibility startup load for data export/import handlers while keeping the top-level feature list as named startup clusters. Key exports: none Window exports: none directly; imported data I/O modules attach their existing compatibility handlers.

app-ai-interaction-modules.js

Startup-loaded AI/chat/settings feature side-effect imports extracted from app-feature-modules.js. This module preserves the previous chat/image/settings/lens/provider helper import order while keeping the top-level feature list easier to scan. Key exports: none Window exports: none directly; imported AI interaction modules attach their existing compatibility handlers.

app-ui-shell-modules.js

Startup-loaded UI shell feature side-effect imports extracted from app-feature-modules.js. This module preserves the previous feedback/tour/touch-tooltip/client-list/views import order while keeping the top-level feature list easier to scan. Key exports: none Window exports: none directly; imported UI shell modules attach their existing compatibility handlers.

startup-orchestrator.js

Startup global wiring and phase ordering. Runs once, installs app-wide startup hooks, and registers the DOMContentLoaded startup sequence. Responsibilities:
  • Sets the _getActiveProfileId startup global
  • Installs lazy EMF window handlers through emf-facade.js
  • Installs app-wide event and refresh wiring through app-event-listeners.js
  • Delegates encryption, backup, and meteo bootstrap to startup-foundation.js
  • Initializes startup profile data
  • Delegates startup service boot and post-profile maintenance to startup-maintenance.js
  • Delegates wearable/OpenRouter callback routing to startup-oauth-callbacks.js
  • Delegates first-render UI bootstrap to startup-ui.js
Key exports:
  • startApp() — idempotently installs startup globals/listeners and registers the startup sequence
Window exports: _getActiveProfileId

emf-facade.js

Lazy window facade for the EMF assessment module extracted from main.js. It installs async window.* handlers for EMF editor and assessment actions, then imports emf.js on first use and replaces the facade handlers with the real module exports. Key exports:
  • EMF_LAZY_WINDOW_FUNCTIONS — list of EMF window handlers covered by the lazy facade
  • installEMFLazyFacade() — installs lazy handlers during app startup
Window exports: EMF handler names from EMF_LAZY_WINDOW_FUNCTIONS

startup-foundation.js

Blocking startup foundation extracted from main.js: encryption unlock, decrypted meteo config cache hydration, cross-tab broadcast setup, and folder backup handle restoration. Key exports:
  • initializeStartupFoundation() — runs the blocking security/storage bootstrap before wearable services or profile data load
Window exports: none

startup-profile.js

Profile startup bootstrap extracted from main.js: legacy v1 profile migration, encrypted profile-cache warmup, active-profile imported-data load, and unit/sex/range/DOB display state. Key exports:
  • initializeProfileData() — creates the default profile for legacy users, migrates old imported data through encrypted storage, warms the profile cache, sets state.currentProfile, and loads active imported data before OAuth callbacks can persist profile-scoped data
  • applyProfileDisplayState() — applies saved units/range mode plus sex/DOB metadata to state and the startup toggle controls
Window exports: none

startup-oauth-callbacks.js

Startup OAuth callback routing extracted from main.js. Wearable callbacks run first after profile load; if they do not consume the URL code, OpenRouter OAuth handles the same ?code=/state pair. Key exports:
  • handleStartupOAuthCallbacks() — delegates wearable OAuth callback handling, exchanges OpenRouter codes with state verification, stores the OpenRouter key, switches the active AI provider, and opens chat after init
Window exports: none

startup-maintenance.js

Non-blocking startup maintenance extracted from main.js: wearable runtime config/scheduler boot, sun session self-heal, light-device preset hydration, and legacy biometrics migration. Key exports:
  • initializeStartupServices() — starts wearable runtime config loading and scheduler setup before profile data loads
  • runPostProfileStartupMaintenance() — schedules post-profile maintenance jobs without blocking OAuth callbacks or first render
Window exports: none

startup-ui.js

First-render UI bootstrap extracted from main.js: profile display state, theme, footer version, sidebar, sync indicator, initial navigation, deferred sync/catalog warmup, changelog, startup nudges, deferred settings/chat opens, header chrome, chat attachment handlers, and file-picker import binding. Key exports:
  • renderStartupUI() — runs the initial UI render and schedules non-blocking startup UI work after profile/OAuth startup completes
Window exports: none

app-event-listeners.js

App-wide browser event wiring that used to live in main.js: modal wheel guards, backdrop click handling, global role-button keyboard activation, Escape/Tab modal behavior, app shortcuts, and the registerRefreshCallback() bridge back into navigate(state.currentView || 'dashboard'). Key exports:
  • installGlobalEventListeners() — idempotently installs document-level modal, keyboard, shortcut, and click handlers
  • registerAppRefreshCallback() — registers the data refresh callback that rebuilds sidebar state and re-renders the active route

tour.js

Generic spotlight tour engine plus the app tour and cycle tour configurations. Key exports:
  • runTour(steps, storageKey, auto) — generic engine: creates #tour-overlay, #tour-spotlight, #tour-tooltip; filters steps with missing targets; navigates with Back/Next/Skip/Done
  • startTour(auto) — launches the 7-step app tour (auto=true checks completion flag first)
  • startCycleTour(auto) — launches the 8-step cycle-specific tour
  • endTour() — removes tour DOM elements, stores completion flag
  • CYCLE_TOUR_STEPS — array of 8 step configs for the cycle tour
Window exports: startTour, startCycleTour, endTour

changelog.js

What’s New modal triggered on version bump so users see what changed after each PWA update. Key exports:
  • APP_VERSION — number matching the SW cache version (e.g., 53)
  • openChangelog(showAll) — renders and shows the modal; showAll=true shows all entries, false shows latest 3
  • closeChangelog() — hides modal, marks current version as seen in localStorage
  • maybeShowChangelog() — auto-trigger: shows modal if labcharts-changelog-seen !== APP_VERSION
Window exports: openChangelog, closeChangelog, maybeShowChangelog

client-list.js

Client List modal for managing multiple profiles. Key exports:
  • openClientListModal() / closeClientListModal() — modal lifecycle
  • renderClientList(query?, sortBy?) — renders searchable, sortable profile list with inline create/edit form
  • Per-profile actions: archive, flag, pin, delete, per-client export
Window exports: openClientListModal, closeClientListModal, createClientInline, saveClientInline, toggleArchiveClient, toggleFlagClient, togglePinClient, deleteClient, exportClientJSON

recommendations.js

Supplement, lifestyle, light-device, and EMF affiliate recommendations driven by a lazy-loaded catalog. Region-aware: products + URLs + coupons are filtered by user country via a single hierarchy chain (CZ → EU → INTL etc.). The global Recommendations page is rendered by lens-pages.js, while dashboard-widgets.js registers the dashboard surface and dashboard-widget-renderers.js owns its dashboard renderer; this module owns catalog loading, slot rendering, disclosure state, product filtering, and DNA/wearable slot helpers. Key exports:
  • loadCatalog() — lazy-loads data/recommendations.json on first call
  • getUserRegion() — derives region code (CZ/SK/DE/AT/EU/US/INTL) from profile country
  • regionLookupChain(region) — returns the lookup chain (most-specific → INTL); used by both product visibility filter and per-region map resolution
  • getProductsForSlot(catalog, slotKey, region) — region-filtered products
  • _resolveCouponForRegion, _resolveHomepageForRegion, _resolveProductUrlForRegion — pick from per-region maps using the chain
  • _addUTMParams(url, content, campaign) — partner-dashboard attribution
  • renderRecommendationSection(slotKey, opts) — renders the “What can help” section in the detail modal
  • renderEMFMeterRecs(catalog, opts) / renderEMFMitigationRecs(catalog, tags, opts) — EMF panel surfaces
Window exports: none (called via imports from views.js, chat.js, context-cards.js)

crypto.js

Data encryption at rest and cross-tab sync. Key exports:
  • encryptedSetItem(key, value) / encryptedGetItem(key) — AES-256-GCM via PBKDF2 passphrase
  • getEncryptionEnabled() / setEncryptionEnabled(bool) — encryption toggle
  • validatePassphrase(p) — checks 4 strength rules (8+ chars, lowercase, uppercase, special), returns { valid, message }
  • broadcastDataChanged(profileId) — BroadcastChannel message for multi-tab sync
  • SENSITIVE_PATTERNS — array of localStorage key pattern strings that get encrypted
Window exports: setEncryptionEnabled, changePassphrase, exportBackup, importBackup

backup.js

IndexedDB auto-backup, folder backup via File System Access API, manual database backup, and restore. backup-chat-storage.js supplements profile collection with raw thread index/message envelopes so a locked or partially recovered index cannot make a full backup omit ciphertext. Unsent draft keys are intentionally excluded. Key exports:
  • scheduleAutoBackup() — debounced five-minute trigger; saves up to 5 snapshots to IndexedDB + writes to folder backup if configured
  • buildBackupSnapshot() — legacy synchronous localStorage snapshot retained for focused tests and compatibility
  • buildFullBackupSnapshot() — asynchronously captures IndexedDB-backed profile blobs, chat records, preferences, and device-local data
  • exportEncryptedBackup() / importEncryptedBackup() — manual full-database bundle export and restore
  • getAutoBackupSnapshots() — reads the retained IndexedDB snapshot list
  • restoreAutoBackup(id) — restores localStorage plus profile, wearable, and cycle IndexedDB records, then reloads
  • initFolderBackup(), pickFolderForBackup(), reauthorizeFolderBackup(), removeFolderBackup() — File System Access lifecycle for latest and daily folder snapshots
Window exports: restoreAutoBackup, pickBackupFolder, showBackupReminder

lab-context.js

Central AI context serializer. Extracted from chat.js. Key exports:
  • buildLabContext() — serializes enabled lab groups, effective dated ranges, explicit collection context, profile/context cards, cycle data, notes, and other enabled sources into tagged AI context
Window exports: none; callers import it directly or use a configured module facade.

lab-context-collection.js

Builds [section:labCollectionContext] from explicit per-draw metadata. It emits collection time, tri-state fasting when known, cycle day, and recorded phase; missing fields are omitted with an instruction not to infer them. Key export: buildLabCollectionContextSection(entries). Window exports: none.

lab-context-change-timeline.js

Builds the [section:changeHistory] profile-context timeline used by buildLabContext(). It filters the timeline by enabled Insight Context Cards and Light & Sun sources, orders snapshots by date, and renders field-level changes. Window exports: none.

lab-context-wearables.js

Builds compact wearable context and optional Agent Access series. It also detects contradictions between manually selected Sleep & Rest duration/quality and recent wearable data, returning an explicit mismatch warning instead of silently choosing one source. Key exports: getSleepContextMismatch(), buildWearableContext(), buildWearableSeriesSection(), and the in-app/Agent Access wearable-context setting helpers. Window exports: none.

markdown.js

Block-aware markdown parser for chat rendering. Extracted from chat.js. Key exports:
  • renderMarkdown(text) — block-aware parser: headings, lists, code blocks, HR, paragraphs + inline formatting
Window exports: renderMarkdown

provider-panels.js

AI provider settings behavior for the settings modal. Owns provider selection, key validation flows, provider model dropdown refresh, balances, and local-model advisor wiring. Imports provider-panel-renderers.js for provider-specific Settings → AI panel markup. Key exports:
  • renderAIProviderPanel(provider) — returns the active provider configuration panel HTML
  • switchAIProvider(provider) — persists provider choice and refreshes the settings panel
  • Provider key/model helpers for Venice, OpenRouter, Routstr, PPQ, Custom API, and local OpenAI-compatible servers
Window exports: provider panel handlers used by Settings HTML onclick attributes, including imported Routstr wallet handlers from provider-wallet-panels.js

provider-panel-renderers.js

Provider-specific Settings → AI panel markup for OpenRouter, Routstr, Venice, PPQ, Custom, and Local AI. Keeps static panel HTML and cached-model select markup separate from provider validation, balance polling, and local-model advisor behavior. Window exports: none directly. renderAIProviderPanel() is re-exported and attached to window by provider-panels.js.

provider-wallet-panels.js

Routstr/Cashu wallet UI and node funding actions used inside the Routstr provider panel. Extracted from provider-panels.js so wallet deposit, withdrawal, seed backup/restore, mint switching, and node deposit/refund behavior are isolated from general provider key/model rendering. Key exports:
  • configureRoutstrWalletPanels(callbacks) — injects provider-panel callbacks without introducing a circular module import
  • routstrWalletActionButtons(active) / buildRoutstrNodeActions(nodeUrl, hasKey, active) — render the wallet and node action controls used by the Routstr panel
  • doRoutstrWalletFund() / doRoutstrNodeDeposit() / doRoutstrNodeWithdraw() / withdraw and restore helpers — Cashu wallet and Routstr node action handlers
Window exports: exported through provider-panels.js for legacy inline handlers.

provider-qr.js

Shared QR-code loader for provider payment surfaces. Key exports:
  • ensureQRCode() — lazy-loads /vendor/qrcode-generator.js and returns the global qrcode factory

lens.js

Knowledge Base / Interpretive Lens — RAG endpoint config + multi-query rewrite + dedicated modal. Two backends under one UI: 'in-browser' (transformers.js + OPFS via lens-local.js) and 'external-server' (user-configured URL + Bearer key). Key exports:
  • hasLens() — true when a lens is configured AND has indexed content
  • queryLens(hint, opts?) — single-query retrieval; routes to in-browser worker or remote server based on backend
  • queryLensMulti(hint, opts?) — multi-query orchestrator: rewrites the query into N=3 paraphrases via the active LLM, fans out to queryLens for each, fuses results with reciprocal-rank scoring (k=60). Falls back to single-query when no AI provider, when rewrite fails, when query is <3 words, or when the toggle is off
  • getLensConfig() / saveLensConfig(partial) / getLensKey() / saveLensKey(key)
  • getLensSummary() — synchronous status object {configured, backend, displayName, docCount, chunkCount, multiQueryOn, aiAvailable} used by the dashboard KB row
  • openKnowledgeBaseModal() / closeKnowledgeBaseModal() — dedicated modal that wraps renderCustomLensSection(). Replaces the previous Settings → AI inline section
  • buildLensSnippet(chunks, sourceName) — formats retrieved chunks for AI prompt injection
  • testLensConnection() / clearLensCache()
  • renderCustomLensSection() — full settings markup (URL/key inputs, backend toggle, library picker, ingest UI, multi-query toggle); rendered inside the KB modal
  • _resetRewriteCache() / _fuseChunksRRFForTest() / _dedupeQueriesForTest() — test surface
Window exports: hasLens, queryLens, queryLensMulti, buildLensSnippet, testLensConnection, clearLensCache, openKnowledgeBaseModal, closeKnowledgeBaseModal, plus all the in-modal save/toggle/library handlers

wearable-adapters.js

Canonical wearable-metric registry + per-vendor adapter registry. Source of truth for OAuth client IDs, redirect URIs, scopes, and metric → endpoint mappings. Key exports:
  • ADAPTERS — array of {id, displayName, authType, oauth?, apiHost?, metrics, accountInfo?} for the 9 registered sources (Oura / Withings / Ultrahuman / WHOOP / legacy Fitbit / Google Health / Polar / Apple Health / manual)
  • CANONICAL_METRICS{id: {label, sub, unit, worseWhen}} for every metric the strip can render
  • DEFAULT_METRIC_ORDER — preferred order when multiple sources contribute
  • adapterById(id) / visibleAdapters(connectedIds) / adapterSupportsMetric(adapterId, metricId) / metricsForSources(sourceIds) / canonicalMetric(id)
  • applyOAuthOverrides(map) — merges a {adapterId: clientId} map into the runtime override store; called from loadWearableRuntimeConfig()
  • applyOAuthConfigured(map) / isOAuthAdapterConfigured(adapterOrId) — apply and read server-confirmed capability flags; Google Health uses this gate independently from its client-ID override
  • getOAuthClientId(adapterOrId) — returns the runtime override if set, falling back to the adapter’s hardcoded oauth.clientId. Every consumer reads through this helper so self-host overrides apply uniformly
  • _resetOAuthOverrides() — test surface
Window exports: none

wearables-connect.js

Connect/disconnect/backfill orchestration. OAuth dispatch table, scheduled stale-source sync, runtime config bootstrap. Key exports:
  • OAUTH_DISPATCH{adapterId: {begin, isCallback, complete, withFreshToken, fetchAccountInfo, fetchRange, displayName, postConnect?, commitAfterWrite?}} — generic OAuth orchestration table
  • beginConnectOAuth(adapterId) — kicks off the auth flow; reads clientId via getOAuthClientId(adapter)
  • handleOAuthCallbackOnLoad() — runs via startup-oauth-callbacks.js init; reads pending.clientId from sessionStorage (set at begin time, NOT from runtime config)
  • getConnection(adapterId) / listConnectedSources() / disconnectAdapter(adapterId)
  • syncNow(adapterId, opts?) / forceBackfill(adapterId, days)
  • initWearableScheduler() — visibility-change + 6h interval poll; awaits runtimeConfigReady() before first sync to prevent race against override fetch
  • loadWearableRuntimeConfig() — POSTs {wearable_runtime_config: true} to /api/proxy, applies returned public client-ID overrides and capability booleans, and clears failed cached requests so a later scheduler pass can retry. A 1.5s soft timeout keeps startup non-blocking
Window exports: none

Wearables vendor adapters

Each connected source ships as a pair: wearables-<vendor>.js (read API) + wearables-<vendor>-auth.js (OAuth dance). Apple Health and Manual skip the auth half — Apple is file-import only, Manual is fully local. Tokens never leave the device; sync-payload.js strips wearableConnections from the synced payload (and again on pull as defense-in-depth). OAuth2 (server-side secret): wearables-oura.js + …-oura-auth.js, …-withings.js + …-withings-auth.js, …-ultrahuman.js + …-ultrahuman-auth.js, …-polar.js + …-polar-auth.js, and …-google-health.js + …-google-health-auth.js. Secrets live in .env.local + /api/proxy. Google Health additionally requires the explicit server capability gate and encrypts its credentials and raw rows with its device-local credential vault key. OAuth2 PKCE (no secret): wearables-whoop.js + …-whoop-auth.js. The Fitbit PKCE modules remain only to sync already-connected legacy users during the migration window; the adapter is hidden for new connections. No OAuth: wearables-apple-health.js (file-import — parseAppleHealthXml reads the export.xml from a Health zip), wearables-manual.js (logManualMetric / logManualBP + MANUAL_TAGS whitelist for what users can log by hand). L1 storage + summary derivation: wearables-store.js (per-profile IndexedDB at labcharts-wearables-{profileId}; two-phase upsertDailyBatch), wearables-summary.js (L2 derivation; vendor sources read a 90-day window, while sparse manual rows read all history so older hand-entered BP/pulse/weight entries stay visible; write gate — 5% d7 shift / trend flip / 14d force-refresh / source flip / metric removal triggers). UI surface: wearables.js (dashboard strip, source picker, reorder mode, empty-card manual-log forms, and legacy window facade), wearables-detail-modal.js (metric detail modal, Chart.js series, manual-entry list/add/delete, focus trap, EMF sleep nudge), wearables-formatters.js (shared value/date formatting), wearables-manual-form-ui.js (shared manual chip/note form snippets), wearables-settings-panel.js (Settings → Wearables rows, connect/sync/backfill/disconnect actions, Apple Health file-import UI, manual-source counts/delete action, strip visibility toggle), brand-assets.js (per-vendor logo registry — iconLight/Dark for in-app rows, signInLight/Dark for landing-site Connect buttons, mono SVG fallback while a vendor logo is gated).

Knowledge Base in-browser stack

lens.js is the dispatcher; the 4 sibling lens-local-* modules are the in-browser implementation. The dispatcher routes between in-browser and external-server backends per the user’s selection.
  • lens-local.js — main-thread shell: spawns a module worker, posts ingest/query/list/activate/delete messages, exposes a Promise-based API to lens.js.
  • lens-local-worker.js — module worker. Loads transformers.js (currently from jsdelivr — see update-vendor.sh notes), runs WebGPU embedding when available with WASM fallback, owns OPFS persistence (FileSystemSyncAccessHandle), library CRUD, MMR re-rank (λ named MMR_LAMBDA), per-library model selection from a 4-model catalog.
  • lens-local-utils.js — pure helpers: chunkText, mmrSelect, hashing, vector-pack helpers. Importable from both threads.
  • lens-local-parsers.js — main-thread document parsers (PDF via pdfjs-loader.js, DOCX via mammoth, ZIP via JSZip, plus plain text/markdown/CSV).

Other recently-extracted modules

Not separately documented because their exports are best read from source — kept thin on purpose.
  • chat-images.js — image attachment lifecycle (getPendingAttachments, clearAttachments, etc.). Owns the _pendingAttachments queue. Extracted from chat.js in v1.21.9.
  • markdown.js — XSS-safe markdown rendering (applyInlineMarkdown for spans, renderMarkdown for full blocks). 34 dedicated XSS test assertions.
  • lab-context.js — lab-data → AI-prompt context assembly; memoized via fingerprint that includes wearable summary, change history, and all 9 context cards.
  • provider-panels.js — Settings → AI provider behavior, validation, balances, dropdown refresh, globals.
  • provider-panel-renderers.js — Settings → AI per-provider panel markup (Venice / OpenRouter / Routstr / PPQ / Local AI / Custom).
  • pdfjs-loader.js — cached dynamic import of vendored pdf.js ESM. Pins isEvalSupported: false defense-in-depth on every getDocument call.
  • sun-body-silhouette.js — anatomical sun-session body-region picker, stock-figure region-map hit testing, and async selection overlay. Re-exported by sun.js for compatibility.
  • sun-active-session.js — quick-log/start modal, live active-session ticker, Simpson live-dose integration, and active-session compatibility handlers. Dependency-injected from sun.js so persistence and hydration stay in the owner module.
  • sun-session-ui.js — saved sun-session row/detail rendering, detailed past-session modal, channel chips, delete, and edit-duration UI. Dependency-injected from sun.js so storage, hydration, and dose math stay in the owning module.
  • light-device-setup-modal.js — add-device preset picker, custom-device form, and URL/photo AI spec extraction. Dependency-injected from light-devices.js so device persistence and channel defaults stay in the owning module.
  • light-device-session-modal.js — log/start light therapy device session modal; dependency-injected from light-devices.js so session persistence and active timer state stay in the owning module.
  • light-env-audits.js — saved Light Environment snapshots, audit comparison renderer, and audit-specific window handlers. Dependency-injected from light-env.js so rooms/screens remain owned by the environment module.
  • light-env-evening.js — canonical room after-sunset exposure helpers; normalizes legacy boolean room rows to numeric eveningHoursAfterSunset while leaving screen eveningUseAfterSunset numeric.
  • light-tool-camera.js / light-tool-camera-modals.js — shared camera lock, row-banding, aiming guides, lux calibration, and the camera-backed Light tool modal flows. Dependency-injected from light-tools.js so measurement persistence stays in the owning module.
  • supplement-warnings.js — claim-level, primary-study mitochondrial evidence matching and bounded context; food-contaminants.js separately owns deterministic diet-source warnings.
  • emf.js — Baubiologie SBM-2015 EMF assessment as a sub-module of the Environment context card.
  • sync.js — Public sync entry/barrel; exports sync lifecycle, actions, diagnostics, relay, identity, and cutover APIs while delegating dependency wiring to sync-configure.js.
  • sync-configure.js — Sync subsystem dependency wiring; configures relay health, push/pull/subscription/tombstone/diagnostic/UI/action/recovery/reconcile modules and browser window bindings.
  • sync-push.js — outbound profile push path, missing-profile-data rejection, unchanged-payload suppression, generation-safe dirty clearing, exact source-commit tracking, relay-storage refresh scheduling, in-flight watchdog, and Evolu profileData insert/update.
  • sync-push-deltas.js — push-side per-row delta planning/application; walks DELTA_ARRAYS/MAPS/SCALARS before blob writes, advances snapshots after onComplete, and records delta telemetry.
  • sync-pull.js — inbound pull orchestration and row loop; force-publishes pending backup restores, flushes dirty local work, tracks source-tab commits, and delegates one-time cleanup, active-profile UI refresh, and rebroadcast scheduling to helper modules.
  • sync-pull-merge.js — pull row recovery/dedupe, importedData blob/per-row merge, wearable-token preservation, metadata-only genetics blob protection, and profile metadata merge helpers.
  • sync-pull-maintenance.js — pull-path one-time migrations such as stale -sync-hash localStorage cleanup.
  • sync-pull-active-refresh.js — active-profile in-memory update, migration, chat reload, sidebar rebuild, current-view refresh, origin-aware toast, and sync-applied event after a pull.
  • sync-pull-rebroadcast.js — pull-side rebroadcast gating, budget checks, push-pending guard, and delayed active-profile push scheduling.
  • data-merge.js — importedData blob merge helpers, shared record freshness comparison, tombstone state merge, and sync-aware array mutation helpers (appendImportedArrayItem, replaceImportedArrayItem, deleteImportedArrayItem, deleteImportedArrayItems, clearImportedArray) used by feature modules so identity edits/deletes record the right tombstones before the next sync push.
  • sync-cutover.js — readiness-gated Phase 2 lean-sync cutover enable/disable bridge over payload flags and delta readiness.
  • sync-delta.js — per-row CRDT delta facade; config fan-out, apply helpers, and compatibility re-exports for planners, snapshots, merge, telemetry, and readiness.
  • sync-delta-planners.js — push-side planner facade; configures shared planner dependency context and compatibility re-exports for array/map/scalar planners.
  • sync-delta-planner-context.js — shared Evolu/itemRow query dependency access for push-side delta planners.
  • sync-delta-array-planner.js — push-side array planner; diffs array items against snapshots and emits itemRow insert/update/tombstone ops with tombstone-storm protection.
  • sync-delta-map-planner.js — push-side keyed-map planner; diffs keyed objects against snapshots, preserves original raw keys in payloads, and guards genetics SNP empty-map races.
  • sync-delta-scalar-planner.js — push-side scalar planner; handles singleton fields, most-recent canonical row selection, and null-transition tombstones.
  • sync-delta-snapshot.js — delta snapshot keying, reads, plannedAt-gated writes, and snapshot clear helpers.
  • sync-delta-merge.js — pull-side itemRow grouping and merge-shape dispatch into importedData after blob merge.
  • sync-delta-merge-shapes.js — pull-side row overlay facade; compatibility re-exports for array/map/scalar merge helpers.
  • sync-delta-row-codec.js — shared itemRow payload decoder for pull-side delta merge helpers, including gzip envelope handling.
  • sync-delta-array-merge.js — pull-side array row overlay helper; owns item tombstones, nested-path writes, dedupe, composite caps, and pull delta telemetry.
  • sync-delta-map-merge.js — pull-side keyed-map row overlay helper; owns raw-key preservation, synth-id tombstones, proto guards, nested-path writes, and pull delta telemetry.
  • sync-delta-scalar-merge.js — pull-side scalar row overlay helper; owns singleton LWW selection, null tombstones, dotted-path writes, genetics SNP preservation, and pull delta telemetry.
  • sync-delta-registry.js — delta registry facade; compatibility re-exports for surfaces, per-surface config, and identity helpers.
  • sync-delta-surfaces.js — DELTA_ARRAYS/MAPS/SCALARS importedData surface lists for per-row sync.
  • sync-delta-surface-config.js — per-surface itemId/keyId overrides for array/map delta planners and pull overlays.
  • sync-delta-id.js — shared per-row identity helpers, stable hash, allowlist guard, and proto-pollution key rejection.
  • sync-delta-observability.js — delta observability facade; compatibility re-exports for telemetry, pull snapshots, readiness, and injected Evolu query access.
  • sync-delta-observability-context.js — shared Evolu/itemRow query dependency access for delta observability helpers.
  • sync-delta-pull-snapshot.js — in-memory pull-side row-count snapshots for Sync Diagnose delta replication checks.
  • sync-delta-telemetry.js — per-push delta telemetry storage, aggregation, reset, and latest pull-snapshot reporting.
  • sync-delta-readiness.js — Phase 2 cutover readiness checks across array/map/scalar delta surfaces.
  • sync-apply.js — inbound sync apply helpers for AI provider settings and display prefs, with compatibility re-exports for chat apply helpers.
  • sync-chat-apply.js — inbound chat thread/message application, thread/persona delete tombstones, per-persona timestamp merge, and local freshness locks that protect just-edited local chat from stale remote rows.
  • sync-tombstones.js — remote profile delete propagation helpers, inbound tombstone application, batched-delete quarantine, and apply/reject pending tombstone actions for Settings.
  • sync-messenger.js — Agent Access token/context-key helpers, owner-bound encrypted context writes, revoke helpers, and debounced lab-context push to the Agent Access context gateway.
  • sync-environment.js — relay URL selection, relay connectivity probing, and browser capability checks for Evolu sync.
  • sync-identity.js — BIP-39/QR lazy loaders plus mnemonic read/restore helpers; existing-identity joins suppress Evolu’s internal reload, persist enabled owner state, then perform one controlled reload.
  • sync-settings-state.js — persisted configured/active/paused state. labcharts-sync-enabled means an identity is configured; labcharts-sync-paused suppresses traffic without forgetting it.
  • sync-lifecycle.js — runtime start, identity-preserving pause/resume, explicit disconnect/reset, and backup-restore push preflight.
  • sync-backup-restore-state.js — durable restored-profile handoff; clears stale delta/cutover state, marks profiles dirty, and retains the retry list until a recovery push succeeds.
  • sync-subscriptions.js — Evolu profile/settings subscriptions and debounce timers; paused state clears and blocks inbound delivery until resume rebinds them.
  • sync-dirty-state.js — durable per-profile edit generations, captured-generation clearing, and dirty-state inspection for pull and compaction safety.
  • sync-origin-state.js — tab-local committed syncedAt tracking used to distinguish source-browser echoes from updates received elsewhere.
  • sync-profile-fields.js — deterministic shared profile metadata field list used by outbound payload collection and inbound profile merge.
  • sync-diagnostics.js — Evolu diagnostics facade; stable exports for configuration, row snapshots, and copy-text formatting.
  • sync-diagnostics-context.js — Injected Evolu/query/subscription state accessors for sync diagnostics.
  • sync-diagnostics-snapshot.js — Evolu row diagnostics snapshot assembly, including live/tombstone rows, active imported counts, delta telemetry, and lean-sync readiness.
  • sync-diagnostics-text.js — Plain-text Sync Diagnose copy formatting for support/debug handoff.
  • sync-diagnose-ui.js — Sync Diagnose modal lifecycle, copy snapshot handling, and compatibility re-exports for Diagnose action handlers.
  • sync-diagnose-render.js — Pure Sync Diagnose panel/table markup for identity, relay health, relay storage, delta telemetry, lean-sync readiness, and local Evolu rows.
  • sync-diagnose-actions.js — Sync Diagnose action facade; keeps the public imports stable while delegating to focused action modules.
  • sync-diagnose-actions-context.js — Shared injected dependencies for Diagnose actions, including sync enable/restore, push, cutover toggles, and modal refresh.
  • sync-diagnose-relay-actions.js — Sync Diagnose relay storage refresh and self-serve compaction handlers.
  • sync-diagnose-identity-actions.js — Sync Diagnose identity rotation modal, BIP-39 mnemonic generation, QR display, copy fallback, and local apply flow.
  • sync-diagnose-cutover-actions.js — Sync Diagnose telemetry reset plus lean-sync enable/backfill/disable handlers.
  • sync-actions.js — user-triggered sync actions, all-profile initial push, dirty-profile compaction preflight, fail-closed unreadable-profile guard, relay snapshot rebuild, and compatibility re-exports for save hooks and storage cleanup.
  • sync-save-hooks.js — save/chat/profile-metadata debounce hooks, durable dirty marking, AI-setting push scheduling, per-profile timer cleanup, and canonical IndexedDB-backed profile reads that return null rather than an empty default on failure.
  • sync-storage-cleanup.js — emergency sync storage compaction; clears model-list caches, trims oversized changeHistory, saves the active profile, and reports freed bytes.
  • sync-ui.js — header sync badge, popover rendering, status subscription, and activity-log copy helpers.
  • sync-payload-collectors.js — Local AI/chat/display settings collection for sync payloads, including thread messages/tombstones, custom personas, persona tombstones, and synced setting allowlists.
  • sync-payload.js — Evolu wire-payload helpers; deterministic profile-field assembly, Phase 2 cutover payload shape, gzip envelope handling, inbound payload parsing, and local-only data stripping for wearable credentials and SNP map rows.
  • sync-relay-health.js — Evolu relay helper boundary; client-side quota estimate, signed /self/owner-storage and /self/compact-owner calls, and push-landed health verdict for the silent-reject detector.
  • sync-state.js — in-memory sync status pub-sub, header badge display-state derivation, recent sync activity ring buffer, and per-profile rebroadcast budget guard.