@mentra/sdk 2.1.27 → 2.1.29-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/session/api-client.d.ts.map +1 -1
- package/dist/app/session/dashboard.d.ts +5 -8
- package/dist/app/session/dashboard.d.ts.map +1 -1
- package/dist/app/session/events.d.ts +10 -4
- package/dist/app/session/events.d.ts.map +1 -1
- package/dist/app/session/index.d.ts +64 -4
- package/dist/app/session/index.d.ts.map +1 -1
- package/dist/app/session/modules/audio.d.ts +33 -4
- package/dist/app/session/modules/audio.d.ts.map +1 -1
- package/dist/app/session/modules/camera-managed-extension.d.ts +2 -3
- package/dist/app/session/modules/camera-managed-extension.d.ts.map +1 -1
- package/dist/app/session/modules/camera.d.ts +11 -10
- package/dist/app/session/modules/camera.d.ts.map +1 -1
- package/dist/app/session/modules/led.d.ts +141 -0
- package/dist/app/session/modules/led.d.ts.map +1 -0
- package/dist/app/session/modules/location.d.ts +1 -2
- package/dist/app/session/modules/location.d.ts.map +1 -1
- package/dist/app/session/modules/simple-storage.d.ts +22 -1
- package/dist/app/session/modules/simple-storage.d.ts.map +1 -1
- package/dist/display-utils.d.ts +989 -0
- package/dist/display-utils.d.ts.map +1 -0
- package/dist/display-utils.js +1197 -0
- package/dist/display-utils.js.map +17 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5427 -112
- package/dist/index.js.map +45 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/types/capabilities.d.ts +3 -0
- package/dist/types/capabilities.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -14
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/message-types.d.ts +8 -1
- package/dist/types/message-types.d.ts.map +1 -1
- package/dist/types/messages/app-to-cloud.d.ts +49 -3
- package/dist/types/messages/app-to-cloud.d.ts.map +1 -1
- package/dist/types/messages/cloud-to-app.d.ts +18 -6
- package/dist/types/messages/cloud-to-app.d.ts.map +1 -1
- package/dist/types/messages/cloud-to-glasses.d.ts +30 -2
- package/dist/types/messages/cloud-to-glasses.d.ts.map +1 -1
- package/dist/types/messages/glasses-to-cloud.d.ts +24 -1
- package/dist/types/messages/glasses-to-cloud.d.ts.map +1 -1
- package/dist/types/rtmp-stream.d.ts +1 -1
- package/dist/types/rtmp-stream.d.ts.map +1 -1
- package/dist/types/streams.d.ts +31 -2
- package/dist/types/streams.d.ts.map +1 -1
- package/package.json +34 -11
- package/dist/app/index.js +0 -24
- package/dist/app/server/index.js +0 -658
- package/dist/app/session/api-client.js +0 -101
- package/dist/app/session/dashboard.js +0 -149
- package/dist/app/session/events.js +0 -315
- package/dist/app/session/index.js +0 -1573
- package/dist/app/session/layouts.js +0 -372
- package/dist/app/session/modules/audio.js +0 -321
- package/dist/app/session/modules/camera-managed-extension.js +0 -310
- package/dist/app/session/modules/camera.js +0 -607
- package/dist/app/session/modules/index.js +0 -19
- package/dist/app/session/modules/location.js +0 -61
- package/dist/app/session/modules/simple-storage.js +0 -232
- package/dist/app/session/settings.js +0 -358
- package/dist/app/token/index.js +0 -22
- package/dist/app/token/utils.js +0 -144
- package/dist/app/webview/index.js +0 -382
- package/dist/constants/index.js +0 -16
- package/dist/constants/log-messages/color.js +0 -14
- package/dist/constants/log-messages/logos.js +0 -48
- package/dist/constants/log-messages/updates.js +0 -55
- package/dist/constants/log-messages/warning.js +0 -89
- package/dist/examples/managed-rtmp-streaming-example.js +0 -158
- package/dist/examples/managed-rtmp-streaming-with-restream-example.js +0 -124
- package/dist/examples/rtmp-streaming-example.js +0 -102
- package/dist/logging/logger.js +0 -79
- package/dist/types/capabilities.js +0 -9
- package/dist/types/dashboard/index.js +0 -12
- package/dist/types/enums.js +0 -75
- package/dist/types/index.js +0 -101
- package/dist/types/layouts.js +0 -3
- package/dist/types/message-types.js +0 -212
- package/dist/types/messages/app-to-cloud.js +0 -95
- package/dist/types/messages/base.js +0 -3
- package/dist/types/messages/cloud-to-app.js +0 -78
- package/dist/types/messages/cloud-to-glasses.js +0 -68
- package/dist/types/messages/glasses-to-cloud.js +0 -140
- package/dist/types/models.js +0 -101
- package/dist/types/photo-data.js +0 -2
- package/dist/types/rtmp-stream.js +0 -3
- package/dist/types/streams.js +0 -306
- package/dist/types/token.js +0 -7
- package/dist/types/webhooks.js +0 -28
- package/dist/utils/animation-utils.js +0 -340
- package/dist/utils/bitmap-utils.js +0 -475
- package/dist/utils/permissions-utils.js +0 -263
- package/dist/utils/resource-tracker.js +0 -153
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../display-utils/src/profiles/g1.ts", "../../display-utils/src/measurer/script-detection.ts", "../../display-utils/src/measurer/TextMeasurer.ts", "../../display-utils/src/wrapper/types.ts", "../../display-utils/src/wrapper/TextWrapper.ts", "../../display-utils/src/helpers/DisplayHelpers.ts", "../../display-utils/src/helpers/ScrollView.ts", "../../display-utils/src/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import {DisplayProfile} from \"./types\"\n\n/**\n * Complete G1 glyph widths from G1FontLoaderKt\n * These are GLYPH widths - multiply using renderFormula to get rendered pixels.\n * Rendered width = (glyphWidth + 1) * 2\n */\nconst G1_GLYPH_WIDTHS: Record<string, number> = {\n // Punctuation & Symbols\n \" \": 2,\n \"!\": 1,\n '\"': 2,\n \"#\": 6,\n \"$\": 5,\n \"%\": 6,\n \"&\": 7,\n \"'\": 1,\n \"(\": 2,\n \")\": 2,\n \"*\": 3,\n \"+\": 4,\n \",\": 1,\n \"-\": 4, // Hyphen: 4px glyph → 10px rendered (CRITICAL for breaking!)\n \".\": 1,\n \"/\": 3,\n\n // Numbers\n \"0\": 5,\n \"1\": 3,\n \"2\": 5,\n \"3\": 5,\n \"4\": 5,\n \"5\": 5,\n \"6\": 5,\n \"7\": 5,\n \"8\": 5,\n \"9\": 5,\n\n // More punctuation\n \":\": 1,\n \";\": 1,\n \"<\": 4,\n \"=\": 4,\n \">\": 4,\n \"?\": 5,\n \"@\": 7,\n\n // Uppercase\n \"A\": 6,\n \"B\": 5,\n \"C\": 5,\n \"D\": 5,\n \"E\": 4,\n \"F\": 4,\n \"G\": 5,\n \"H\": 5,\n \"I\": 2,\n \"J\": 3,\n \"K\": 5,\n \"L\": 4,\n \"M\": 7,\n \"N\": 5,\n \"O\": 5,\n \"P\": 5,\n \"Q\": 5,\n \"R\": 5,\n \"S\": 5,\n \"T\": 5,\n \"U\": 5,\n \"V\": 6,\n \"W\": 7,\n \"X\": 6,\n \"Y\": 6,\n \"Z\": 5,\n\n // Brackets & special\n \"[\": 2,\n \"\\\\\": 3,\n \"]\": 2,\n \"^\": 4,\n \"_\": 3,\n \"`\": 2,\n\n // Lowercase\n \"a\": 5,\n \"b\": 4,\n \"c\": 4,\n \"d\": 4,\n \"e\": 4,\n \"f\": 4,\n \"g\": 4,\n \"h\": 4,\n \"i\": 1,\n \"j\": 2,\n \"k\": 4,\n \"l\": 1,\n \"m\": 7,\n \"n\": 4,\n \"o\": 4,\n \"p\": 4,\n \"q\": 4,\n \"r\": 3,\n \"s\": 4,\n \"t\": 3,\n \"u\": 5,\n \"v\": 5,\n \"w\": 7,\n \"x\": 5,\n \"y\": 5,\n \"z\": 4,\n\n // More special\n \"{\": 3,\n \"|\": 1,\n \"}\": 3,\n \"~\": 7,\n}\n\n/**\n * Even Realities G1 Smart Glasses Display Profile\n *\n * Verified through empirical testing with actual hardware.\n * See: line-width-debug-tool/line-width-spec.md\n */\nexport const G1_PROFILE: DisplayProfile = {\n id: \"even-realities-g1\",\n name: \"Even Realities G1\",\n\n // Display dimensions\n displayWidthPx: 576,\n maxLines: 5,\n\n // BLE constraints\n maxPayloadBytes: 390,\n bleChunkSize: 176,\n\n // Font metrics\n fontMetrics: {\n // Glyph widths from G1FontLoaderKt\n glyphWidths: new Map(Object.entries(G1_GLYPH_WIDTHS)),\n\n // Default glyph width for unmapped Latin characters (use max to be safe)\n defaultGlyphWidth: 7,\n\n // Rendered width = (glyphWidth + 1) * 2\n renderFormula: (glyphWidth: number) => (glyphWidth + 1) * 2,\n\n // Uniform-width scripts - ALL characters in these scripts render at this exact width\n // These are verified values in RENDERED pixels, NOT averages\n uniformScripts: {\n cjk: 18, // ALL Chinese/Japanese Kanji chars = 18px (verified)\n hiragana: 18, // ALL Hiragana chars = 18px (verified)\n katakana: 18, // ALL Katakana chars = 18px (verified)\n korean: 24, // ALL Korean Hangul chars = 24px (verified)\n cyrillic: 18, // ALL Cyrillic chars = 18px (verified)\n },\n\n // Fallback for unmapped Latin characters\n // Uses MAX width to guarantee no overflow (safe under-utilization)\n fallback: {\n latinMaxWidth: 16, // Max Latin = 'm', 'w' at (7+1)*2 = 16px\n unknownBehavior: \"useLatinMax\",\n },\n },\n\n constraints: {\n minCharsBeforeHyphen: 3,\n // Kinsoku: Characters that should not appear at start of line\n noStartChars: [\".\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"]\", \"}\", \"。\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"】\", \"」\"],\n // Kinsoku: Characters that should not appear at end of line\n noEndChars: [\"(\", \"[\", \"{\", \"(\", \"【\", \"「\"],\n },\n}\n\n/**\n * G1 Profile for LEGACY mobile clients that have their own wrapping logic.\n *\n * Old mobile clients re-wrap text received from the cloud, causing double-wrapping.\n * This profile uses a reduced display width (~522px instead of 576px) so that\n * when the mobile client re-wraps, the result still fits within 5 lines.\n *\n * Use this profile when:\n * - Mobile client version < X.X.X (has old wrapping logic)\n * - You see text getting cut off or exceeding 5 lines\n *\n * Once all clients are updated, this can be deprecated.\n */\nexport const G1_PROFILE_LEGACY: DisplayProfile = {\n id: \"even-realities-g1-legacy\",\n name: \"Even Realities G1 (Legacy Client Compatibility)\",\n\n // Reduced display width to prevent double-wrapping overflow\n // Old mobile client wraps at ~90% of true width\n displayWidthPx: 420,\n maxLines: 5,\n\n // BLE constraints (same as standard)\n maxPayloadBytes: 390,\n bleChunkSize: 176,\n\n // Font metrics (same as standard)\n fontMetrics: {\n glyphWidths: new Map(Object.entries(G1_GLYPH_WIDTHS)),\n defaultGlyphWidth: 7,\n renderFormula: (glyphWidth: number) => (glyphWidth + 1) * 2,\n uniformScripts: {\n cjk: 18,\n hiragana: 18,\n katakana: 18,\n korean: 24,\n cyrillic: 18,\n },\n fallback: {\n latinMaxWidth: 16,\n unknownBehavior: \"useLatinMax\",\n },\n },\n\n constraints: {\n minCharsBeforeHyphen: 3,\n noStartChars: [\".\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"]\", \"}\", \"。\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"】\", \"」\"],\n noEndChars: [\"(\", \"[\", \"{\", \"(\", \"【\", \"「\"],\n },\n}\n\n/**\n * Get the hyphen width for G1 in rendered pixels.\n * Hyphen glyph = 4px → rendered = (4+1)*2 = 10px\n */\nexport const G1_HYPHEN_WIDTH_PX = 10\n\n/**\n * Get the space width for G1 in rendered pixels.\n * Space glyph = 2px → rendered = (2+1)*2 = 6px\n */\nexport const G1_SPACE_WIDTH_PX = 6\n",
|
|
6
|
+
"import type {ScriptType} from \"../profiles/types\"\n\n/**\n * Unicode ranges for script detection.\n * Used to classify characters for proper width measurement.\n */\nexport const SCRIPT_RANGES = {\n // CJK Unified Ideographs\n cjk: [\n [0x4e00, 0x9fff], // Main block (common Chinese, Japanese Kanji)\n [0x3400, 0x4dbf], // Extension A\n [0x20000, 0x2a6df], // Extension B\n [0x2a700, 0x2b73f], // Extension C\n [0x2b740, 0x2b81f], // Extension D\n [0xf900, 0xfaff], // Compatibility Ideographs\n ] as const,\n\n // Japanese Hiragana\n hiragana: [[0x3040, 0x309f]] as const,\n\n // Japanese Katakana\n katakana: [\n [0x30a0, 0x30ff], // Main block\n [0x31f0, 0x31ff], // Phonetic Extensions\n ] as const,\n\n // Korean\n korean: [\n [0xac00, 0xd7af], // Hangul Syllables\n [0x1100, 0x11ff], // Hangul Jamo\n [0x3130, 0x318f], // Compatibility Jamo\n [0xa960, 0xa97f], // Jamo Extended-A\n [0xd7b0, 0xd7ff], // Jamo Extended-B\n ] as const,\n\n // Cyrillic\n cyrillic: [\n [0x0400, 0x04ff], // Main block\n [0x0500, 0x052f], // Supplement\n ] as const,\n\n // Numbers (ASCII)\n numbers: [[0x30, 0x39]] as const,\n\n // Basic punctuation (ASCII)\n punctuation: [\n [0x20, 0x2f], // Space and basic punctuation\n [0x3a, 0x40], // More punctuation\n [0x5b, 0x60], // Brackets etc.\n [0x7b, 0x7e], // Braces etc.\n ] as const,\n\n // Unsupported scripts (for filtering)\n arabic: [[0x0600, 0x06ff]] as const,\n hebrew: [[0x0590, 0x05ff]] as const,\n thai: [[0x0e00, 0x0e7f]] as const,\n emoji: [\n [0x1f600, 0x1f64f], // Emoticons\n [0x1f300, 0x1f5ff], // Misc Symbols and Pictographs\n [0x1f680, 0x1f6ff], // Transport and Map\n [0x1f1e0, 0x1f1ff], // Flags\n [0x2600, 0x26ff], // Misc Symbols\n [0x2700, 0x27bf], // Dingbats\n [0xfe00, 0xfe0f], // Variation Selectors\n [0x1f900, 0x1f9ff], // Supplemental Symbols\n ] as const,\n} as const\n\n/**\n * Check if a code point is within any of the given ranges.\n */\nfunction inRanges(codePoint: number, ranges: readonly (readonly [number, number])[]): boolean {\n for (const [start, end] of ranges) {\n if (codePoint >= start && codePoint <= end) {\n return true\n }\n }\n return false\n}\n\n/**\n * Detect the script type of a single character.\n *\n * @param char - Single character to classify\n * @returns The script type of the character\n */\nexport function detectScript(char: string): ScriptType {\n if (!char || char.length === 0) {\n return \"latin\"\n }\n\n // Get the code point (handles surrogate pairs for characters outside BMP)\n const codePoint = char.codePointAt(0)\n if (codePoint === undefined) {\n return \"latin\"\n }\n\n // Check each script in order of likelihood/importance\n\n // CJK (most common for multi-byte)\n if (inRanges(codePoint, SCRIPT_RANGES.cjk)) {\n return \"cjk\"\n }\n\n // Japanese kana\n if (inRanges(codePoint, SCRIPT_RANGES.hiragana)) {\n return \"hiragana\"\n }\n if (inRanges(codePoint, SCRIPT_RANGES.katakana)) {\n return \"katakana\"\n }\n\n // Korean\n if (inRanges(codePoint, SCRIPT_RANGES.korean)) {\n return \"korean\"\n }\n\n // Cyrillic\n if (inRanges(codePoint, SCRIPT_RANGES.cyrillic)) {\n return \"cyrillic\"\n }\n\n // Numbers\n if (inRanges(codePoint, SCRIPT_RANGES.numbers)) {\n return \"numbers\"\n }\n\n // Punctuation\n if (inRanges(codePoint, SCRIPT_RANGES.punctuation)) {\n return \"punctuation\"\n }\n\n // Unsupported scripts\n if (\n inRanges(codePoint, SCRIPT_RANGES.arabic) ||\n inRanges(codePoint, SCRIPT_RANGES.hebrew) ||\n inRanges(codePoint, SCRIPT_RANGES.thai) ||\n inRanges(codePoint, SCRIPT_RANGES.emoji)\n ) {\n return \"unsupported\"\n }\n\n // Default to Latin for ASCII letters and anything else\n return \"latin\"\n}\n\n/**\n * Check if a character is a CJK character (Chinese, Japanese Kanji).\n * CJK characters can break anywhere without needing a hyphen.\n */\nexport function isCJKCharacter(char: string): boolean {\n const script = detectScript(char)\n return script === \"cjk\" || script === \"hiragana\" || script === \"katakana\"\n}\n\n/**\n * Check if a character is Korean Hangul.\n */\nexport function isKoreanCharacter(char: string): boolean {\n return detectScript(char) === \"korean\"\n}\n\n/**\n * Check if a character is from a uniform-width script.\n * These scripts render all characters at the same width.\n */\nexport function isUniformWidthScript(char: string): boolean {\n const script = detectScript(char)\n return (\n script === \"cjk\" || script === \"hiragana\" || script === \"katakana\" || script === \"korean\" || script === \"cyrillic\"\n )\n}\n\n/**\n * Check if a character is from an unsupported script.\n * These characters may not render correctly on the glasses.\n */\nexport function isUnsupportedScript(char: string): boolean {\n return detectScript(char) === \"unsupported\"\n}\n\n/**\n * Check if breaking between two characters requires a hyphen.\n * Returns false for:\n * - Breaking after CJK characters (can break anywhere)\n * - Breaking before or after spaces\n * - Breaking after punctuation\n */\nexport function needsHyphenForBreak(charBefore: string, charAfter: string): boolean {\n // No hyphen needed after CJK (can break anywhere)\n if (isCJKCharacter(charBefore)) {\n return false\n }\n\n // No hyphen needed before CJK\n if (isCJKCharacter(charAfter)) {\n return false\n }\n\n // No hyphen needed after space\n if (charBefore === \" \" || charBefore === \"\\t\") {\n return false\n }\n\n // No hyphen needed before space (the space is a natural break point)\n if (charAfter === \" \" || charAfter === \"\\t\") {\n return false\n }\n\n // No hyphen needed after existing punctuation that serves as break\n const breakPunctuation = [\"-\", \"–\", \"—\", \"/\", \"\\\\\", \"|\"]\n if (breakPunctuation.includes(charBefore)) {\n return false\n }\n\n // Default: hyphen is needed for mid-word Latin breaks\n return true\n}\n",
|
|
7
|
+
"import type { DisplayProfile, ScriptType } from \"../profiles/types\"\nimport { detectScript, isUniformWidthScript } from \"./script-detection\"\n\n/**\n * Character measurement result with detailed breakdown.\n */\nexport interface CharMeasurement {\n /** The character measured */\n char: string\n /** Width in rendered pixels */\n widthPx: number\n /** The script type of the character */\n script: ScriptType\n /** Whether width came from glyph map (true) or fallback (false) */\n fromGlyphMap: boolean\n}\n\n/**\n * Text measurement result with detailed breakdown.\n */\nexport interface TextMeasurement {\n /** The text measured */\n text: string\n /** Total width in rendered pixels */\n totalWidthPx: number\n /** Number of characters */\n charCount: number\n /** Per-character measurements (optional, for debugging) */\n chars?: CharMeasurement[]\n}\n\n/**\n * Measures text width in pixels based on a DisplayProfile.\n * All measurements are in actual rendered pixels, not abstract units.\n *\n * Key features:\n * - Pixel-perfect measurement for mapped characters\n * - Uniform-width handling for CJK, Korean, Cyrillic\n * - Safe fallback for unmapped Latin characters\n * - Caching for performance\n */\nexport class TextMeasurer {\n private readonly profile: DisplayProfile\n private readonly charCache: Map<string, number> = new Map()\n\n constructor(profile: DisplayProfile) {\n this.profile = profile\n // Pre-populate cache with known glyphs\n this.buildCharCache()\n }\n\n /**\n * Pre-compute rendered widths for all known glyphs.\n */\n private buildCharCache(): void {\n const { glyphWidths, renderFormula } = this.profile.fontMetrics\n\n for (const [char, glyphWidth] of glyphWidths.entries()) {\n const renderedWidth = renderFormula(glyphWidth)\n this.charCache.set(char, renderedWidth)\n }\n }\n\n /**\n * Measure the total pixel width of a text string.\n *\n * @param text - The text to measure\n * @returns Width in rendered pixels\n */\n measureText(text: string): number {\n if (!text || text.length === 0) {\n return 0\n }\n\n let totalWidth = 0\n for (const char of text) {\n totalWidth += this.measureChar(char)\n }\n return totalWidth\n }\n\n /**\n * Measure text with detailed breakdown of each character.\n *\n * @param text - The text to measure\n * @returns Detailed measurement result\n */\n measureTextDetailed(text: string): TextMeasurement {\n if (!text || text.length === 0) {\n return {\n text: \"\",\n totalWidthPx: 0,\n charCount: 0,\n chars: [],\n }\n }\n\n const chars: CharMeasurement[] = []\n let totalWidth = 0\n\n for (const char of text) {\n const script = detectScript(char)\n const widthPx = this.measureChar(char)\n const fromGlyphMap = this.profile.fontMetrics.glyphWidths.has(char)\n\n chars.push({\n char,\n widthPx,\n script,\n fromGlyphMap,\n })\n\n totalWidth += widthPx\n }\n\n return {\n text,\n totalWidthPx: totalWidth,\n charCount: chars.length,\n chars,\n }\n }\n\n /**\n * Measure a single character's pixel width.\n *\n * IMPORTANT: This is PIXEL-PERFECT measurement, not averaging!\n * - Mapped characters: exact width from glyph map\n * - Uniform scripts (CJK, Korean, Cyrillic): verified uniform width\n * - Unmapped Latin: MAX width fallback (safe, never overflow)\n *\n * @param char - Single character to measure\n * @returns Width in rendered pixels\n */\n measureChar(char: string): number {\n if (!char || char.length === 0) {\n return 0\n }\n\n // Check cache first (includes pre-computed glyph map entries)\n const cached = this.charCache.get(char)\n if (cached !== undefined) {\n return cached\n }\n\n // Calculate width based on script type\n const width = this.calculateCharWidth(char)\n\n // Cache for future lookups\n this.charCache.set(char, width)\n\n return width\n }\n\n /**\n * Calculate character width (called when not in cache).\n */\n private calculateCharWidth(char: string): number {\n const { fontMetrics } = this.profile\n const { uniformScripts, fallback, renderFormula, glyphWidths } = fontMetrics\n\n // 1. Check explicit glyph map (pixel-perfect for Latin)\n const glyphWidth = glyphWidths.get(char)\n if (glyphWidth !== undefined) {\n return renderFormula(glyphWidth)\n }\n\n // 2. Uniform-width scripts (verified monospace - NOT averages!)\n const script = detectScript(char)\n\n switch (script) {\n case \"cjk\":\n return uniformScripts.cjk // ALL CJK chars are exactly this width\n case \"hiragana\":\n return uniformScripts.hiragana // ALL Hiragana chars are exactly this width\n case \"katakana\":\n return uniformScripts.katakana // ALL Katakana chars are exactly this width\n case \"korean\":\n return uniformScripts.korean // ALL Korean chars are exactly this width\n case \"cyrillic\":\n return uniformScripts.cyrillic // ALL Cyrillic chars are exactly this width\n }\n\n // 3. Unmapped Latin or unknown: use MAX width (safe fallback)\n // This guarantees we NEVER overflow - worst case is slight under-utilization\n return fallback.latinMaxWidth\n }\n\n /**\n * Get the raw glyph width (before render formula).\n * Returns undefined for unmapped characters.\n *\n * @param char - Single character\n * @returns Glyph width in pixels, or undefined if not in glyph map\n */\n getGlyphWidth(char: string): number | undefined {\n return this.profile.fontMetrics.glyphWidths.get(char)\n }\n\n /**\n * Check if text fits within a pixel width.\n *\n * @param text - Text to check\n * @param maxWidthPx - Maximum width in pixels\n * @returns true if text fits\n */\n fitsInWidth(text: string, maxWidthPx: number): boolean {\n return this.measureText(text) <= maxWidthPx\n }\n\n /**\n * Find how many characters fit within a pixel width.\n *\n * @param text - Text to measure\n * @param maxWidthPx - Maximum width in pixels\n * @param startIndex - Starting index (default: 0)\n * @returns Number of characters that fit\n */\n charsThatFit(text: string, maxWidthPx: number, startIndex: number = 0): number {\n if (!text || startIndex >= text.length) {\n return 0\n }\n\n let currentWidth = 0\n let count = 0\n\n // Use Array.from to handle surrogate pairs correctly\n const chars = Array.from(text).slice(startIndex)\n\n for (const char of chars) {\n const charWidth = this.measureChar(char)\n\n if (currentWidth + charWidth > maxWidthPx) {\n break\n }\n\n currentWidth += charWidth\n count++\n }\n\n return count\n }\n\n /**\n * Find the pixel position of a character index in text.\n *\n * @param text - Text to measure\n * @param index - Character index\n * @returns Pixel offset from start of text\n */\n getPixelOffset(text: string, index: number): number {\n if (!text || index <= 0) {\n return 0\n }\n\n const chars = Array.from(text).slice(0, index)\n let offset = 0\n\n for (const char of chars) {\n offset += this.measureChar(char)\n }\n\n return offset\n }\n\n /**\n * Detect the script type of a character.\n *\n * @param char - Single character\n * @returns Script type\n */\n detectScript(char: string): ScriptType {\n return detectScript(char)\n }\n\n /**\n * Check if a character is from a uniform-width script.\n *\n * @param char - Single character\n * @returns true if character is from CJK, Korean, or Cyrillic\n */\n isUniformWidth(char: string): boolean {\n return isUniformWidthScript(char)\n }\n\n /**\n * Get the display profile.\n */\n getProfile(): DisplayProfile {\n return this.profile\n }\n\n /**\n * Get the display width in pixels.\n */\n getDisplayWidthPx(): number {\n return this.profile.displayWidthPx\n }\n\n /**\n * Get the maximum number of lines.\n */\n getMaxLines(): number {\n return this.profile.maxLines\n }\n\n /**\n * Get the maximum payload size in bytes.\n */\n getMaxPayloadBytes(): number {\n return this.profile.maxPayloadBytes\n }\n\n /**\n * Calculate the UTF-8 byte size of text.\n *\n * @param text - Text to measure\n * @returns Byte size\n */\n getByteSize(text: string): number {\n return new TextEncoder().encode(text).length\n }\n\n /**\n * Get the width of a hyphen character in rendered pixels.\n */\n getHyphenWidth(): number {\n return this.measureChar(\"-\")\n }\n\n /**\n * Get the width of a space character in rendered pixels.\n */\n getSpaceWidth(): number {\n return this.measureChar(\" \")\n }\n\n /**\n * Clear the character cache.\n * Useful if profile metrics change at runtime.\n */\n clearCache(): void {\n this.charCache.clear()\n this.buildCharCache()\n }\n}\n",
|
|
8
|
+
"/**\n * Options for text wrapping.\n */\nexport interface WrapOptions {\n /** Maximum width in pixels (defaults to profile's displayWidthPx) */\n maxWidthPx?: number\n\n /** Maximum number of lines (defaults to profile's maxLines) */\n maxLines?: number\n\n /** Maximum total bytes (defaults to profile's maxPayloadBytes) */\n maxBytes?: number\n\n /**\n * Break mode:\n * - 'character': Break mid-word with hyphen for 100% utilization\n * - 'word': Break at word boundaries, hyphenate only if word > line\n * - 'strict-word': Break at word boundaries only, truncate long words\n */\n breakMode?: BreakMode\n\n /** Character to use for hyphenation (default: '-') */\n hyphenChar?: string\n\n /** Minimum characters before allowing hyphen break (default: 3) */\n minCharsBeforeHyphen?: number\n\n /** Whether to trim whitespace from line ends (default: true) */\n trimLines?: boolean\n\n /** Whether to preserve explicit newlines in input (default: true) */\n preserveNewlines?: boolean\n}\n\n/**\n * Break mode for text wrapping.\n */\nexport type BreakMode = \"character\" | \"word\" | \"strict-word\"\n\n/**\n * Result of wrapping operation.\n */\nexport interface WrapResult {\n /** Wrapped lines */\n lines: string[]\n\n /** Whether content was truncated to fit constraints */\n truncated: boolean\n\n /** Total pixel width of widest line */\n maxLineWidthPx: number\n\n /** Total byte size of all lines */\n totalBytes: number\n\n /** Per-line metadata */\n lineMetrics: LineMetrics[]\n\n /** Original input text */\n originalText: string\n\n /** Break mode used */\n breakMode: BreakMode\n}\n\n/**\n * Per-line metrics from wrapping.\n */\nexport interface LineMetrics {\n /** The line text */\n text: string\n\n /** Width in pixels */\n widthPx: number\n\n /** Byte size of this line */\n bytes: number\n\n /** Utilization percentage (widthPx / maxWidthPx * 100) */\n utilizationPercent: number\n\n /** Whether this line ends with a hyphen from breaking */\n endsWithHyphen: boolean\n\n /** Whether this line was created from an explicit newline */\n fromExplicitNewline: boolean\n}\n\n/**\n * Default wrap options.\n */\nexport const DEFAULT_WRAP_OPTIONS: Required<Omit<WrapOptions, \"maxWidthPx\" | \"maxLines\" | \"maxBytes\">> = {\n breakMode: \"character\",\n hyphenChar: \"-\",\n minCharsBeforeHyphen: 3,\n trimLines: true,\n preserveNewlines: true,\n}\n",
|
|
9
|
+
"import {TextMeasurer} from \"../measurer/TextMeasurer\"\nimport {isCJKCharacter, needsHyphenForBreak} from \"../measurer/script-detection\"\nimport type {WrapOptions, WrapResult, LineMetrics, BreakMode} from \"./types\"\nimport {DEFAULT_WRAP_OPTIONS} from \"./types\"\n\n/**\n * Wraps text to fit display constraints.\n *\n * Supports multiple break modes:\n * - 'character': Break mid-word with hyphen for 100% line utilization\n * - 'word': Break at word boundaries, hyphenate only if word > line width\n * - 'strict-word': Break at word boundaries only, no hyphenation\n *\n * Key features:\n * - Pixel-accurate wrapping (no abstract units)\n * - Hyphen-aware breaking (accounts for hyphen width)\n * - CJK support (breaks anywhere without hyphen)\n * - Preserves explicit newlines\n * - Respects byte limits for BLE transmission\n */\nexport class TextWrapper {\n private readonly measurer: TextMeasurer\n private readonly defaultOptions: Required<WrapOptions>\n\n constructor(measurer: TextMeasurer, defaultOptions?: WrapOptions) {\n this.measurer = measurer\n\n const profile = measurer.getProfile()\n this.defaultOptions = {\n maxWidthPx: profile.displayWidthPx,\n maxLines: profile.maxLines,\n maxBytes: profile.maxPayloadBytes,\n ...DEFAULT_WRAP_OPTIONS,\n ...defaultOptions,\n }\n }\n\n /**\n * Wrap text to fit within constraints.\n *\n * @param text - Text to wrap (may contain \\n for explicit breaks)\n * @param options - Override default options\n * @returns Wrap result with lines and metadata\n */\n wrap(text: string, options?: WrapOptions): WrapResult {\n const opts = this.mergeOptions(options)\n const {maxWidthPx, maxLines, maxBytes, breakMode, preserveNewlines} = opts\n\n if (!text || text.length === 0) {\n return this.createEmptyResult(opts)\n }\n\n // Split by explicit newlines if preserving them\n const paragraphs = preserveNewlines ? text.split(\"\\n\") : [text]\n\n const allLines: string[] = []\n const allMetrics: LineMetrics[] = []\n let totalBytes = 0\n let truncated = false\n\n for (let pIndex = 0; pIndex < paragraphs.length; pIndex++) {\n const paragraph = paragraphs[pIndex]\n const isFromNewline = pIndex > 0\n\n // Wrap this paragraph\n const paragraphLines = this.wrapParagraph(paragraph, maxWidthPx, breakMode, opts)\n\n for (let lIndex = 0; lIndex < paragraphLines.length; lIndex++) {\n const line = paragraphLines[lIndex]\n const lineBytes = this.measurer.getByteSize(line)\n\n // Check if we've exceeded limits\n if (allLines.length >= maxLines) {\n truncated = true\n break\n }\n\n if (totalBytes + lineBytes > maxBytes) {\n truncated = true\n break\n }\n\n const widthPx = this.measurer.measureText(line)\n const metrics: LineMetrics = {\n text: line,\n widthPx,\n bytes: lineBytes,\n utilizationPercent: Math.round((widthPx / maxWidthPx) * 100),\n endsWithHyphen: line.endsWith(opts.hyphenChar) && lIndex < paragraphLines.length - 1,\n fromExplicitNewline: isFromNewline && lIndex === 0,\n }\n\n allLines.push(line)\n allMetrics.push(metrics)\n totalBytes += lineBytes\n\n // Add newline byte between lines\n if (allLines.length < maxLines) {\n totalBytes += 1 // \\n is 1 byte\n }\n }\n\n if (truncated) break\n }\n\n // Find max line width\n const maxLineWidthPx = allMetrics.reduce((max, m) => Math.max(max, m.widthPx), 0)\n\n return {\n lines: allLines,\n truncated,\n maxLineWidthPx,\n totalBytes,\n lineMetrics: allMetrics,\n originalText: text,\n breakMode,\n }\n }\n\n /**\n * Simple wrap returning just lines (convenience method).\n *\n * @param text - Text to wrap\n * @param options - Override default options\n * @returns Array of wrapped lines\n */\n wrapToLines(text: string, options?: WrapOptions): string[] {\n return this.wrap(text, options).lines\n }\n\n /**\n * Check if text needs wrapping.\n *\n * @param text - Text to check\n * @param maxWidthPx - Optional width override\n * @returns true if text exceeds single line\n */\n needsWrap(text: string, maxWidthPx?: number): boolean {\n const width = maxWidthPx ?? this.defaultOptions.maxWidthPx\n return this.measurer.measureText(text) > width || text.includes(\"\\n\")\n }\n\n /**\n * Get current default options.\n */\n getOptions(): Required<WrapOptions> {\n return {...this.defaultOptions}\n }\n\n /**\n * Get the measurer instance.\n */\n getMeasurer(): TextMeasurer {\n return this.measurer\n }\n\n /**\n * Wrap a single paragraph (no newlines) according to break mode.\n */\n private wrapParagraph(\n paragraph: string,\n maxWidthPx: number,\n breakMode: BreakMode,\n opts: Required<WrapOptions>,\n ): string[] {\n const trimmed = opts.trimLines ? paragraph.trim() : paragraph\n\n if (!trimmed) {\n return [\"\"]\n }\n\n // Check if it fits on one line\n if (this.measurer.fitsInWidth(trimmed, maxWidthPx)) {\n return [trimmed]\n }\n\n switch (breakMode) {\n case \"character\":\n return this.wrapCharacterMode(trimmed, maxWidthPx, opts)\n case \"word\":\n return this.wrapWordMode(trimmed, maxWidthPx, opts)\n case \"strict-word\":\n return this.wrapStrictWordMode(trimmed, maxWidthPx, opts)\n default:\n return this.wrapCharacterMode(trimmed, maxWidthPx, opts)\n }\n }\n\n /**\n * Character break mode: Break mid-word with hyphen for 100% line utilization.\n */\n private wrapCharacterMode(text: string, maxWidthPx: number, opts: Required<WrapOptions>): string[] {\n const lines: string[] = []\n const hyphenWidth = this.measurer.measureChar(opts.hyphenChar)\n\n let currentLine = \"\"\n let currentWidth = 0\n\n const chars = Array.from(text)\n\n for (let i = 0; i < chars.length; i++) {\n const char = chars[i]\n const charWidth = this.measurer.measureChar(char)\n\n // Would this character fit?\n if (currentWidth + charWidth <= maxWidthPx) {\n currentLine += char\n currentWidth += charWidth\n } else {\n // Character doesn't fit - need to break\n\n // Determine if we need a hyphen\n const prevChar = currentLine.length > 0 ? currentLine[currentLine.length - 1] : \"\"\n const needsHyphen = currentLine.length >= opts.minCharsBeforeHyphen && needsHyphenForBreak(prevChar, char)\n\n if (needsHyphen) {\n // Back off characters until hyphen fits\n const result = this.backoffForHyphen(currentLine, currentWidth, maxWidthPx, hyphenWidth, opts)\n\n if (result.skipHyphen) {\n // Found a natural word boundary while backing off - no hyphen needed\n lines.push(result.line)\n } else {\n lines.push(result.line + opts.hyphenChar)\n }\n\n // Start new line with backed-off chars + current char\n currentLine = result.remainder + char\n currentWidth = this.measurer.measureText(currentLine)\n } else {\n // No hyphen needed (CJK, space, punctuation)\n const trimmedLine = opts.trimLines ? currentLine.trimEnd() : currentLine\n if (trimmedLine) {\n lines.push(trimmedLine)\n }\n currentLine = char === \" \" ? \"\" : char\n currentWidth = char === \" \" ? 0 : charWidth\n }\n }\n }\n\n // Add remaining text\n if (currentLine) {\n const trimmedLine = opts.trimLines ? currentLine.trim() : currentLine\n if (trimmedLine) {\n lines.push(trimmedLine)\n }\n }\n\n return lines.length > 0 ? lines : [\"\"]\n }\n\n /**\n * Word break mode: Break at word boundaries, hyphenate only if word > line width.\n */\n private wrapWordMode(text: string, maxWidthPx: number, opts: Required<WrapOptions>): string[] {\n const lines: string[] = []\n const words = this.splitIntoWords(text)\n const spaceWidth = this.measurer.getSpaceWidth()\n\n let currentLine = \"\"\n let currentWidth = 0\n\n for (const word of words) {\n const wordWidth = this.measurer.measureText(word)\n const needsSpace = currentLine.length > 0\n const totalWidth = currentWidth + (needsSpace ? spaceWidth : 0) + wordWidth\n\n if (totalWidth <= maxWidthPx) {\n // Word fits on current line\n if (needsSpace) {\n currentLine += \" \"\n currentWidth += spaceWidth\n }\n currentLine += word\n currentWidth += wordWidth\n } else {\n // Word doesn't fit\n if (currentLine.length > 0) {\n // Push current line and start new one\n lines.push(opts.trimLines ? currentLine.trim() : currentLine)\n currentLine = \"\"\n currentWidth = 0\n }\n\n // Check if word itself exceeds line width\n if (wordWidth > maxWidthPx) {\n // Word is too long - hyphenate it\n const hyphenatedLines = this.hyphenateLongWord(word, maxWidthPx, opts)\n for (let i = 0; i < hyphenatedLines.length - 1; i++) {\n lines.push(hyphenatedLines[i])\n }\n // Last piece becomes start of current line\n currentLine = hyphenatedLines[hyphenatedLines.length - 1]\n currentWidth = this.measurer.measureText(currentLine)\n } else {\n // Word fits on new line\n currentLine = word\n currentWidth = wordWidth\n }\n }\n }\n\n // Add remaining text\n if (currentLine) {\n const trimmedLine = opts.trimLines ? currentLine.trim() : currentLine\n if (trimmedLine) {\n lines.push(trimmedLine)\n }\n }\n\n return lines.length > 0 ? lines : [\"\"]\n }\n\n /**\n * Strict word break mode: Break at word boundaries only, no hyphenation.\n * Long words will overflow the line.\n */\n private wrapStrictWordMode(text: string, maxWidthPx: number, opts: Required<WrapOptions>): string[] {\n const lines: string[] = []\n const words = this.splitIntoWords(text)\n const spaceWidth = this.measurer.getSpaceWidth()\n\n let currentLine = \"\"\n let currentWidth = 0\n\n for (const word of words) {\n const wordWidth = this.measurer.measureText(word)\n const needsSpace = currentLine.length > 0\n const totalWidth = currentWidth + (needsSpace ? spaceWidth : 0) + wordWidth\n\n if (totalWidth <= maxWidthPx) {\n // Word fits on current line\n if (needsSpace) {\n currentLine += \" \"\n currentWidth += spaceWidth\n }\n currentLine += word\n currentWidth += wordWidth\n } else {\n // Word doesn't fit\n if (currentLine.length > 0) {\n // Push current line\n lines.push(opts.trimLines ? currentLine.trim() : currentLine)\n }\n // Start new line with word (even if it overflows)\n currentLine = word\n currentWidth = wordWidth\n }\n }\n\n // Add remaining text\n if (currentLine) {\n const trimmedLine = opts.trimLines ? currentLine.trim() : currentLine\n if (trimmedLine) {\n lines.push(trimmedLine)\n }\n }\n\n return lines.length > 0 ? lines : [\"\"]\n }\n\n /**\n * Split text into words, handling CJK characters specially.\n * CJK characters are treated as individual \"words\" since they can break anywhere.\n */\n private splitIntoWords(text: string): string[] {\n const words: string[] = []\n let currentWord = \"\"\n\n for (const char of text) {\n if (char === \" \" || char === \"\\t\") {\n if (currentWord) {\n words.push(currentWord)\n currentWord = \"\"\n }\n } else if (isCJKCharacter(char)) {\n // CJK characters are individual words\n if (currentWord) {\n words.push(currentWord)\n currentWord = \"\"\n }\n words.push(char)\n } else {\n currentWord += char\n }\n }\n\n if (currentWord) {\n words.push(currentWord)\n }\n\n return words\n }\n\n /**\n * Hyphenate a word that's too long to fit on a single line.\n */\n private hyphenateLongWord(word: string, maxWidthPx: number, opts: Required<WrapOptions>): string[] {\n const lines: string[] = []\n const hyphenWidth = this.measurer.measureChar(opts.hyphenChar)\n const chars = Array.from(word)\n\n let currentLine = \"\"\n let currentWidth = 0\n\n for (let i = 0; i < chars.length; i++) {\n const char = chars[i]\n const charWidth = this.measurer.measureChar(char)\n const isLastChar = i === chars.length - 1\n\n // Check if we need to break (leaving room for hyphen if not last char)\n const widthNeeded = isLastChar ? charWidth : charWidth + hyphenWidth\n\n if (currentWidth + widthNeeded <= maxWidthPx) {\n currentLine += char\n currentWidth += charWidth\n } else {\n // Need to break - back off if needed to fit hyphen\n if (currentLine.length >= opts.minCharsBeforeHyphen) {\n const result = this.backoffForHyphen(currentLine, currentWidth, maxWidthPx, hyphenWidth, opts)\n if (result.skipHyphen) {\n lines.push(result.line)\n } else {\n lines.push(result.line + opts.hyphenChar)\n }\n currentLine = result.remainder + char\n currentWidth = this.measurer.measureText(currentLine)\n } else {\n // Not enough chars for hyphen, just break\n if (currentLine) {\n lines.push(currentLine)\n }\n currentLine = char\n currentWidth = charWidth\n }\n }\n }\n\n if (currentLine) {\n lines.push(currentLine)\n }\n\n return lines.length > 0 ? lines : [word]\n }\n\n /**\n * Back off characters from line end until hyphen fits.\n * Returns null if we back off to a space (natural break point - no hyphen needed).\n */\n private backoffForHyphen(\n line: string,\n lineWidth: number,\n maxWidthPx: number,\n hyphenWidth: number,\n opts: Required<WrapOptions>,\n ): {line: string; remainder: string; skipHyphen: boolean} {\n let adjustedLine = line\n let adjustedWidth = lineWidth\n let remainder = \"\"\n\n // Remove characters until hyphen fits\n while (adjustedWidth + hyphenWidth > maxWidthPx && adjustedLine.length > opts.minCharsBeforeHyphen) {\n const lastChar = adjustedLine[adjustedLine.length - 1]\n const lastCharWidth = this.measurer.measureChar(lastChar)\n\n adjustedLine = adjustedLine.slice(0, -1)\n adjustedWidth -= lastCharWidth\n remainder = lastChar + remainder\n\n // If we've backed off to a space, we've found a natural word boundary\n // No hyphen is needed - just trim the space and break there\n if (adjustedLine.length > 0 && adjustedLine[adjustedLine.length - 1] === \" \") {\n // Trim trailing space from the line\n adjustedLine = adjustedLine.trimEnd()\n return {line: adjustedLine, remainder, skipHyphen: true}\n }\n }\n\n return {line: adjustedLine, remainder, skipHyphen: false}\n }\n\n /**\n * Merge user options with defaults.\n */\n private mergeOptions(options?: WrapOptions): Required<WrapOptions> {\n return {\n ...this.defaultOptions,\n ...options,\n }\n }\n\n /**\n * Create an empty result for empty input.\n */\n private createEmptyResult(opts: Required<WrapOptions>): WrapResult {\n return {\n lines: [\"\"],\n truncated: false,\n maxLineWidthPx: 0,\n totalBytes: 0,\n lineMetrics: [\n {\n text: \"\",\n widthPx: 0,\n bytes: 0,\n utilizationPercent: 0,\n endsWithHyphen: false,\n fromExplicitNewline: false,\n },\n ],\n originalText: \"\",\n breakMode: opts.breakMode,\n }\n }\n}\n",
|
|
10
|
+
"import type { DisplayProfile } from \"../profiles/types\"\nimport { TextMeasurer } from \"../measurer/TextMeasurer\"\nimport { TextWrapper } from \"../wrapper/TextWrapper\"\nimport type { WrapOptions, WrapResult } from \"../wrapper/types\"\n\n/**\n * Truncation result with metadata.\n */\nexport interface TruncateResult {\n /** The truncated text */\n text: string\n /** Whether text was truncated */\n wasTruncated: boolean\n /** Width in pixels of truncated text */\n widthPx: number\n /** Original text length */\n originalLength: number\n /** Truncated text length */\n truncatedLength: number\n}\n\n/**\n * Page result for pagination.\n */\nexport interface Page {\n /** Lines on this page */\n lines: string[]\n /** Page number (1-indexed) */\n pageNumber: number\n /** Total number of pages */\n totalPages: number\n /** Whether this is the first page */\n isFirst: boolean\n /** Whether this is the last page */\n isLast: boolean\n}\n\n/**\n * Chunk result for BLE transmission.\n */\nexport interface Chunk {\n /** The chunk text */\n text: string\n /** Chunk index (0-indexed) */\n index: number\n /** Total number of chunks */\n totalChunks: number\n /** Byte size of this chunk */\n bytes: number\n}\n\n/**\n * Optional helper utilities for common display operations.\n * Built on top of TextMeasurer and TextWrapper for convenience.\n */\nexport class DisplayHelpers {\n private readonly measurer: TextMeasurer\n private readonly wrapper: TextWrapper\n private readonly profile: DisplayProfile\n\n constructor(measurer: TextMeasurer, wrapper: TextWrapper) {\n this.measurer = measurer\n this.wrapper = wrapper\n this.profile = measurer.getProfile()\n }\n\n /**\n * Truncate lines array to max count.\n *\n * @param lines - Array of lines\n * @param maxLines - Maximum lines to keep\n * @param fromEnd - If true, keep last N lines; if false, keep first N (default: false)\n * @returns Truncated lines array\n */\n truncateToLines(lines: string[], maxLines: number, fromEnd: boolean = false): string[] {\n if (lines.length <= maxLines) {\n return lines\n }\n\n if (fromEnd) {\n // Keep the last N lines (most recent)\n return lines.slice(-maxLines)\n } else {\n // Keep the first N lines\n return lines.slice(0, maxLines)\n }\n }\n\n /**\n * Truncate text to fit within pixel width, adding ellipsis if needed.\n *\n * @param text - Text to truncate\n * @param maxWidthPx - Maximum width in pixels\n * @param ellipsis - Ellipsis string (default: '...')\n * @returns Truncation result\n */\n truncateWithEllipsis(\n text: string,\n maxWidthPx?: number,\n ellipsis: string = \"...\"\n ): TruncateResult {\n const width = maxWidthPx ?? this.profile.displayWidthPx\n const textWidth = this.measurer.measureText(text)\n\n if (textWidth <= width) {\n return {\n text,\n wasTruncated: false,\n widthPx: textWidth,\n originalLength: text.length,\n truncatedLength: text.length,\n }\n }\n\n const ellipsisWidth = this.measurer.measureText(ellipsis)\n const targetWidth = width - ellipsisWidth\n\n // Find how many characters fit\n let truncated = \"\"\n let currentWidth = 0\n\n for (const char of text) {\n const charWidth = this.measurer.measureChar(char)\n if (currentWidth + charWidth > targetWidth) {\n break\n }\n truncated += char\n currentWidth += charWidth\n }\n\n // Trim trailing whitespace before ellipsis\n truncated = truncated.trimEnd()\n const finalText = truncated + ellipsis\n\n return {\n text: finalText,\n wasTruncated: true,\n widthPx: this.measurer.measureText(finalText),\n originalLength: text.length,\n truncatedLength: truncated.length,\n }\n }\n\n /**\n * Estimate how many lines text will need without fully wrapping.\n * This is a quick estimate based on average character width.\n *\n * @param text - Text to estimate\n * @param maxWidthPx - Optional width override\n * @returns Estimated line count\n */\n estimateLineCount(text: string, maxWidthPx?: number): number {\n if (!text) return 1\n\n const width = maxWidthPx ?? this.profile.displayWidthPx\n const textWidth = this.measurer.measureText(text)\n\n // Account for explicit newlines\n const newlineCount = (text.match(/\\n/g) || []).length\n\n // Estimate wrapped lines\n const wrappedLines = Math.ceil(textWidth / width)\n\n return wrappedLines + newlineCount\n }\n\n /**\n * Wrap and truncate text to fit screen in one call.\n *\n * @param text - Text to fit\n * @param options - Wrap options\n * @returns Lines that fit on screen\n */\n fitToScreen(text: string, options?: WrapOptions): string[] {\n const result = this.wrapper.wrap(text, options)\n return result.lines.slice(0, this.profile.maxLines)\n }\n\n /**\n * Wrap text and paginate into screen-sized pages.\n *\n * @param text - Text to paginate\n * @param options - Wrap options (maxLines will be used as page size)\n * @returns Array of pages\n */\n paginate(text: string, options?: WrapOptions): Page[] {\n // Wrap without line limit to get all lines\n const wrapResult = this.wrapper.wrap(text, {\n ...options,\n maxLines: Infinity,\n maxBytes: Infinity,\n })\n\n const linesPerPage = options?.maxLines ?? this.profile.maxLines\n const allLines = wrapResult.lines\n const pages: Page[] = []\n\n for (let i = 0; i < allLines.length; i += linesPerPage) {\n const pageLines = allLines.slice(i, i + linesPerPage)\n const pageNumber = Math.floor(i / linesPerPage) + 1\n const totalPages = Math.ceil(allLines.length / linesPerPage)\n\n pages.push({\n lines: pageLines,\n pageNumber,\n totalPages,\n isFirst: pageNumber === 1,\n isLast: pageNumber === totalPages,\n })\n }\n\n return pages.length > 0\n ? pages\n : [\n {\n lines: [\"\"],\n pageNumber: 1,\n totalPages: 1,\n isFirst: true,\n isLast: true,\n },\n ]\n }\n\n /**\n * Calculate UTF-8 byte size of text.\n *\n * @param text - Text to measure\n * @returns Byte size\n */\n calculateByteSize(text: string): number {\n return this.measurer.getByteSize(text)\n }\n\n /**\n * Check if text exceeds byte limit.\n *\n * @param text - Text to check\n * @param maxBytes - Optional override (defaults to profile)\n * @returns true if exceeds limit\n */\n exceedsByteLimit(text: string, maxBytes?: number): boolean {\n const limit = maxBytes ?? this.profile.maxPayloadBytes\n return this.calculateByteSize(text) > limit\n }\n\n /**\n * Split text into BLE-safe chunks.\n * Tries to split at word/line boundaries when possible.\n *\n * @param text - Text to chunk\n * @param chunkSize - Optional override (defaults to profile)\n * @returns Array of chunks\n */\n splitIntoChunks(text: string, chunkSize?: number): Chunk[] {\n const size = chunkSize ?? this.profile.bleChunkSize\n const encoder = new TextEncoder()\n const bytes = encoder.encode(text)\n\n if (bytes.length <= size) {\n return [\n {\n text,\n index: 0,\n totalChunks: 1,\n bytes: bytes.length,\n },\n ]\n }\n\n const chunks: Chunk[] = []\n let offset = 0\n\n while (offset < bytes.length) {\n let endOffset = Math.min(offset + size, bytes.length)\n\n // Back off to avoid splitting a multi-byte character\n if (endOffset < bytes.length) {\n // Find a valid UTF-8 boundary\n while (endOffset > offset && (bytes[endOffset] & 0xc0) === 0x80) {\n endOffset--\n }\n\n // Try to find a good break point (space or newline)\n let breakPoint = endOffset\n for (let i = endOffset - 1; i > offset + size / 2; i--) {\n if (bytes[i] === 0x20 || bytes[i] === 0x0a) {\n // space or newline\n breakPoint = i + 1\n break\n }\n }\n if (breakPoint > offset) {\n endOffset = breakPoint\n }\n }\n\n const chunkBytes = bytes.slice(offset, endOffset)\n const chunkText = new TextDecoder().decode(chunkBytes)\n\n chunks.push({\n text: chunkText,\n index: chunks.length,\n totalChunks: 0, // Will be set after loop\n bytes: chunkBytes.length,\n })\n\n offset = endOffset\n }\n\n // Update total chunks count\n for (const chunk of chunks) {\n chunk.totalChunks = chunks.length\n }\n\n return chunks\n }\n\n /**\n * Calculate line utilization statistics.\n *\n * @param result - Wrap result to analyze\n * @returns Utilization statistics\n */\n calculateUtilization(result: WrapResult): {\n averageUtilization: number\n minUtilization: number\n maxUtilization: number\n totalWastedPx: number\n } {\n if (result.lines.length === 0 || result.lineMetrics.length === 0) {\n return {\n averageUtilization: 0,\n minUtilization: 0,\n maxUtilization: 0,\n totalWastedPx: 0,\n }\n }\n\n const maxWidthPx = this.profile.displayWidthPx\n let totalUtilization = 0\n let minUtilization = 100\n let maxUtilization = 0\n let totalWastedPx = 0\n\n for (const metric of result.lineMetrics) {\n totalUtilization += metric.utilizationPercent\n minUtilization = Math.min(minUtilization, metric.utilizationPercent)\n maxUtilization = Math.max(maxUtilization, metric.utilizationPercent)\n totalWastedPx += maxWidthPx - metric.widthPx\n }\n\n return {\n averageUtilization: Math.round(totalUtilization / result.lineMetrics.length),\n minUtilization,\n maxUtilization,\n totalWastedPx,\n }\n }\n\n /**\n * Pad lines array to exact count with empty strings.\n *\n * @param lines - Lines to pad\n * @param targetCount - Target number of lines\n * @param padAtEnd - If true, pad at end; if false, pad at start (default: true)\n * @returns Padded lines array\n */\n padToLineCount(lines: string[], targetCount: number, padAtEnd: boolean = true): string[] {\n if (lines.length >= targetCount) {\n return lines.slice(0, targetCount)\n }\n\n const padding = Array(targetCount - lines.length).fill(\"\")\n\n if (padAtEnd) {\n return [...lines, ...padding]\n } else {\n return [...padding, ...lines]\n }\n }\n\n /**\n * Join lines with newlines for display.\n *\n * @param lines - Lines to join\n * @returns Joined string\n */\n joinLines(lines: string[]): string {\n return lines.join(\"\\n\")\n }\n\n /**\n * Get the measurer instance.\n */\n getMeasurer(): TextMeasurer {\n return this.measurer\n }\n\n /**\n * Get the wrapper instance.\n */\n getWrapper(): TextWrapper {\n return this.wrapper\n }\n\n /**\n * Get the display profile.\n */\n getProfile(): DisplayProfile {\n return this.profile\n }\n}\n",
|
|
11
|
+
"import type {DisplayProfile} from \"../profiles/types\"\nimport {TextMeasurer} from \"../measurer/TextMeasurer\"\nimport {TextWrapper} from \"../wrapper/TextWrapper\"\nimport type {WrapOptions, WrapResult} from \"../wrapper/types\"\n\n/**\n * Scroll position information.\n */\nexport interface ScrollPosition {\n /** Current scroll offset (0 = top) */\n offset: number\n /** Total number of lines in content */\n totalLines: number\n /** Number of visible lines (viewport size) */\n visibleLines: number\n /** Maximum scroll offset */\n maxOffset: number\n /** Whether we're at the top */\n atTop: boolean\n /** Whether we're at the bottom */\n atBottom: boolean\n /** Scroll percentage (0-100) */\n scrollPercent: number\n}\n\n/**\n * Visible content from the scroll view.\n */\nexport interface ScrollViewport {\n /** Lines currently visible */\n lines: string[]\n /** Scroll position info */\n position: ScrollPosition\n /** Whether content was truncated during wrapping */\n contentTruncated: boolean\n}\n\n/**\n * ScrollView provides a scrollable viewport into long wrapped text.\n *\n * Unlike pagination (discrete pages), scrolling allows continuous\n * movement through content line by line.\n *\n * @example\n * ```typescript\n * const scrollView = new ScrollView(measurer, wrapper)\n * scrollView.setContent(\"Very long text that wraps to many lines...\")\n *\n * // Get initial view (top)\n * let view = scrollView.getViewport()\n * console.log(view.lines) // First 5 lines\n *\n * // Scroll down\n * scrollView.scrollDown(2) // Move down 2 lines\n * view = scrollView.getViewport()\n *\n * // Scroll to bottom\n * scrollView.scrollToBottom()\n *\n * // Scroll to specific position\n * scrollView.scrollTo(10) // Line 10 at top of viewport\n * ```\n */\nexport class ScrollView {\n private readonly measurer: TextMeasurer\n private readonly wrapper: TextWrapper\n private readonly profile: DisplayProfile\n private readonly viewportSize: number\n\n private allLines: string[] = []\n private wrapResult: WrapResult | null = null\n private scrollOffset: number = 0\n\n constructor(\n measurer: TextMeasurer,\n wrapper: TextWrapper,\n viewportSize?: number\n ) {\n this.measurer = measurer\n this.wrapper = wrapper\n this.profile = measurer.getProfile()\n this.viewportSize = viewportSize ?? this.profile.maxLines\n }\n\n /**\n * Set the content to display in the scroll view.\n * Wraps the text and resets scroll position to top.\n *\n * @param text - Text content to display\n * @param options - Optional wrap options\n */\n setContent(text: string, options?: Omit<WrapOptions, \"maxLines\">): void {\n // Wrap without line limit to get all lines\n this.wrapResult = this.wrapper.wrap(text, {\n ...options,\n maxLines: Infinity,\n maxBytes: Infinity,\n })\n this.allLines = this.wrapResult.lines\n this.scrollOffset = 0\n }\n\n /**\n * Append content to the existing scroll view.\n * Useful for streaming/live content like captions.\n *\n * @param text - Text to append\n * @param options - Optional wrap options\n * @param autoScroll - If true, scroll to show new content (default: true)\n */\n appendContent(\n text: string,\n options?: Omit<WrapOptions, \"maxLines\">,\n autoScroll: boolean = true\n ): void {\n const wasAtBottom = this.isAtBottom()\n\n // Wrap the new text\n const newResult = this.wrapper.wrap(text, {\n ...options,\n maxLines: Infinity,\n maxBytes: Infinity,\n })\n\n // Append new lines\n this.allLines = [...this.allLines, ...newResult.lines]\n\n // Auto-scroll to bottom if we were already there\n if (autoScroll && wasAtBottom) {\n this.scrollToBottom()\n }\n }\n\n /**\n * Get the current viewport (visible lines).\n */\n getViewport(): ScrollViewport {\n const visibleLines = this.allLines.slice(\n this.scrollOffset,\n this.scrollOffset + this.viewportSize\n )\n\n // Pad to viewport size if needed\n while (visibleLines.length < this.viewportSize) {\n visibleLines.push(\"\")\n }\n\n return {\n lines: visibleLines,\n position: this.getPosition(),\n contentTruncated: this.wrapResult?.truncated ?? false,\n }\n }\n\n /**\n * Get current scroll position information.\n */\n getPosition(): ScrollPosition {\n const totalLines = this.allLines.length\n const maxOffset = Math.max(0, totalLines - this.viewportSize)\n\n return {\n offset: this.scrollOffset,\n totalLines,\n visibleLines: this.viewportSize,\n maxOffset,\n atTop: this.scrollOffset === 0,\n atBottom: this.scrollOffset >= maxOffset,\n scrollPercent: maxOffset > 0 ? Math.round((this.scrollOffset / maxOffset) * 100) : 100,\n }\n }\n\n /**\n * Scroll to a specific line offset.\n *\n * @param offset - Line offset (0 = top)\n */\n scrollTo(offset: number): void {\n const maxOffset = Math.max(0, this.allLines.length - this.viewportSize)\n this.scrollOffset = Math.max(0, Math.min(offset, maxOffset))\n }\n\n /**\n * Scroll down by a number of lines.\n *\n * @param lines - Number of lines to scroll (default: 1)\n */\n scrollDown(lines: number = 1): void {\n this.scrollTo(this.scrollOffset + lines)\n }\n\n /**\n * Scroll up by a number of lines.\n *\n * @param lines - Number of lines to scroll (default: 1)\n */\n scrollUp(lines: number = 1): void {\n this.scrollTo(this.scrollOffset - lines)\n }\n\n /**\n * Scroll down by one viewport (page down).\n */\n pageDown(): void {\n this.scrollDown(this.viewportSize)\n }\n\n /**\n * Scroll up by one viewport (page up).\n */\n pageUp(): void {\n this.scrollUp(this.viewportSize)\n }\n\n /**\n * Scroll to the top.\n */\n scrollToTop(): void {\n this.scrollOffset = 0\n }\n\n /**\n * Scroll to the bottom.\n */\n scrollToBottom(): void {\n const maxOffset = Math.max(0, this.allLines.length - this.viewportSize)\n this.scrollOffset = maxOffset\n }\n\n /**\n * Scroll to show a specific line in the viewport.\n *\n * @param lineIndex - The line index to show\n * @param position - Where in viewport: 'top', 'center', 'bottom' (default: 'top')\n */\n scrollToLine(lineIndex: number, position: \"top\" | \"center\" | \"bottom\" = \"top\"): void {\n let targetOffset: number\n\n switch (position) {\n case \"top\":\n targetOffset = lineIndex\n break\n case \"center\":\n targetOffset = lineIndex - Math.floor(this.viewportSize / 2)\n break\n case \"bottom\":\n targetOffset = lineIndex - this.viewportSize + 1\n break\n }\n\n this.scrollTo(targetOffset)\n }\n\n /**\n * Scroll by a percentage of total content.\n *\n * @param percent - Percentage (0-100)\n */\n scrollToPercent(percent: number): void {\n const maxOffset = Math.max(0, this.allLines.length - this.viewportSize)\n const targetOffset = Math.round((percent / 100) * maxOffset)\n this.scrollTo(targetOffset)\n }\n\n /**\n * Check if currently at the top.\n */\n isAtTop(): boolean {\n return this.scrollOffset === 0\n }\n\n /**\n * Check if currently at the bottom.\n */\n isAtBottom(): boolean {\n const maxOffset = Math.max(0, this.allLines.length - this.viewportSize)\n return this.scrollOffset >= maxOffset\n }\n\n /**\n * Check if content is scrollable (more lines than viewport).\n */\n isScrollable(): boolean {\n return this.allLines.length > this.viewportSize\n }\n\n /**\n * Get all lines (not just visible).\n */\n getAllLines(): string[] {\n return [...this.allLines]\n }\n\n /**\n * Get total line count.\n */\n getTotalLines(): number {\n return this.allLines.length\n }\n\n /**\n * Get the viewport size.\n */\n getViewportSize(): number {\n return this.viewportSize\n }\n\n /**\n * Clear all content and reset scroll position.\n */\n clear(): void {\n this.allLines = []\n this.wrapResult = null\n this.scrollOffset = 0\n }\n\n /**\n * Get the measurer instance.\n */\n getMeasurer(): TextMeasurer {\n return this.measurer\n }\n\n /**\n * Get the wrapper instance.\n */\n getWrapper(): TextWrapper {\n return this.wrapper\n }\n\n /**\n * Get the display profile.\n */\n getProfile(): DisplayProfile {\n return this.profile\n }\n}\n",
|
|
12
|
+
"/**\n * @mentra/display-utils\n *\n * Glasses-agnostic, pixel-accurate text measurement and wrapping library\n * for smart glasses displays.\n *\n * Key features:\n * - Pixel-perfect measurement (no abstract units or averages)\n * - Multiple break modes (character, word, strict-word)\n * - Full script support (Latin, CJK, Korean, Cyrillic)\n * - Configurable display profiles for different glasses hardware\n *\n * @example\n * ```typescript\n * import {\n * TextMeasurer,\n * TextWrapper,\n * DisplayHelpers,\n * G1_PROFILE\n * } from '@mentra/display-utils'\n *\n * // Create measurer and wrapper for G1 glasses\n * const measurer = new TextMeasurer(G1_PROFILE)\n * const wrapper = new TextWrapper(measurer, { breakMode: 'character' })\n * const helpers = new DisplayHelpers(measurer, wrapper)\n *\n * // Wrap text for display\n * const result = wrapper.wrap(\"Hello, world! This is a long text.\")\n * console.log(result.lines)\n * // [\"Hello, world! This is a long text th-\", \"at needs wrapping.\"]\n * ```\n */\n\n// =============================================================================\n// Profiles - Hardware configurations for different glasses\n// =============================================================================\n\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./profiles\"\n\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Import for factory functions\nimport {G1_PROFILE_LEGACY} from \"./profiles\"\n\n// =============================================================================\n// Measurer - Pixel-accurate text measurement\n// =============================================================================\n\nexport {TextMeasurer} from \"./measurer\"\nexport type {CharMeasurement, TextMeasurement} from \"./measurer\"\n\n// Script detection utilities\nexport {\n detectScript,\n isCJKCharacter,\n isKoreanCharacter,\n isUniformWidthScript,\n isUnsupportedScript,\n needsHyphenForBreak,\n SCRIPT_RANGES,\n} from \"./measurer\"\n\n// =============================================================================\n// Wrapper - Text wrapping with multiple break modes\n// =============================================================================\n\nexport {TextWrapper} from \"./wrapper\"\nexport type {WrapOptions, WrapResult, LineMetrics, BreakMode} from \"./wrapper\"\nexport {DEFAULT_WRAP_OPTIONS} from \"./wrapper\"\n\n// =============================================================================\n// Helpers - Optional convenience utilities\n// =============================================================================\n\nexport {DisplayHelpers, ScrollView} from \"./helpers\"\nexport type {TruncateResult, Page, Chunk, ScrollPosition, ScrollViewport} from \"./helpers\"\n\n// =============================================================================\n// Convenience factory functions\n// =============================================================================\n\nimport {TextMeasurer} from \"./measurer\"\nimport {TextWrapper} from \"./wrapper\"\nimport {DisplayHelpers} from \"./helpers\"\nimport {G1_PROFILE} from \"./profiles\"\nimport type {DisplayProfile} from \"./profiles\"\nimport type {WrapOptions} from \"./wrapper\"\n\n/**\n * Create a complete display toolkit for a given profile.\n *\n * @param profile - Display profile (defaults to G1)\n * @param wrapOptions - Default wrap options\n * @returns Object with measurer, wrapper, and helpers\n *\n * @example\n * ```typescript\n * const { measurer, wrapper, helpers } = createDisplayToolkit()\n * const lines = wrapper.wrapToLines(\"Hello, world!\")\n * ```\n */\nexport function createDisplayToolkit(\n profile: DisplayProfile = G1_PROFILE,\n wrapOptions?: WrapOptions,\n): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n profile: DisplayProfile\n} {\n const measurer = new TextMeasurer(profile)\n const wrapper = new TextWrapper(measurer, wrapOptions)\n const helpers = new DisplayHelpers(measurer, wrapper)\n\n return {\n measurer,\n wrapper,\n helpers,\n profile,\n }\n}\n\n/**\n * Create a G1-configured display toolkit with character breaking.\n * This is the recommended setup for captions and similar high-utilization use cases.\n *\n * @returns Object with measurer, wrapper, and helpers configured for G1\n *\n * @example\n * ```typescript\n * const { wrapper } = createG1Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createG1Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE, {\n breakMode: \"character\",\n hyphenChar: \"-\",\n minCharsBeforeHyphen: 3,\n })\n}\n\n/**\n * Create a G1-configured display toolkit for LEGACY mobile clients.\n *\n * Use this when the mobile client has old wrapping logic that re-wraps\n * text received from the cloud. This profile uses a reduced display width\n * (~522px instead of 576px) to prevent double-wrapping overflow.\n *\n * @returns Object with measurer, wrapper, and helpers configured for legacy G1 clients\n *\n * @example\n * ```typescript\n * // For old mobile clients that double-wrap\n * const { wrapper } = createG1LegacyToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * // Lines will be shorter to account for mobile re-wrapping\n * ```\n */\nexport function createG1LegacyToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE_LEGACY, {\n breakMode: \"character\",\n hyphenChar: \"-\",\n minCharsBeforeHyphen: 3,\n })\n}\n"
|
|
13
|
+
],
|
|
14
|
+
"mappings": "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",
|
|
15
|
+
"debugId": "5DD60770487F882B64756E2164756E21",
|
|
16
|
+
"names": []
|
|
17
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export * from "./types/messages/app-to-cloud";
|
|
|
7
7
|
export * from "./utils/bitmap-utils";
|
|
8
8
|
export * from "./utils/animation-utils";
|
|
9
9
|
export { AppConnectionAck, AppConnectionError, AppStopped, SettingsUpdate as AppSettingsUpdate, // Alias to avoid conflict with cloud-to-glasses SettingsUpdate
|
|
10
|
-
CapabilitiesUpdate, DataStream, CloudToAppMessage, TranslationData, ToolCall, StandardConnectionError, CustomMessage, ManagedStreamStatus, StreamStatusCheckResponse, OutputStatus, MentraosSettingsUpdate, TranscriptionData, TranscriptionMetadata, SonioxToken, AudioChunk, PermissionError, PermissionErrorDetail, AudioPlayResponse, isAppConnectionAck, isAppConnectionError, isAppStopped, isSettingsUpdate, isCapabilitiesUpdate, isDataStream, isAudioChunk, isStreamStatusCheckResponse, isDashboardModeChanged, isDashboardAlwaysOnChanged, isManagedStreamStatus, isPhotoResponse as isPhotoResponseFromCloud, isRtmpStreamStatus as isRtmpStreamStatusFromCloud, } from "./types/messages/cloud-to-app";
|
|
10
|
+
CapabilitiesUpdate, DataStream, CloudToAppMessage, TranslationData, ToolCall, StandardConnectionError, CustomMessage, ManagedStreamStatus, StreamStatusCheckResponse, OutputStatus, MentraosSettingsUpdate, TranscriptionData, TranscriptionMetadata, SonioxToken, AudioChunk, PermissionError, PermissionErrorDetail, AudioPlayResponse, isAppConnectionAck, isAppConnectionError, isAppStopped, isSettingsUpdate, isCapabilitiesUpdate, isDataStream, isAudioChunk, isStreamStatusCheckResponse, isDashboardModeChanged, isDashboardAlwaysOnChanged, isManagedStreamStatus, isPhotoResponse as isPhotoResponseFromCloud, isRgbLedControlResponse as isRgbLedControlResponseFromCloud, isRtmpStreamStatus as isRtmpStreamStatusFromCloud, } from "./types/messages/cloud-to-app";
|
|
11
11
|
export * from "./types/streams";
|
|
12
12
|
export * from "./types/layouts";
|
|
13
13
|
export * from "./types/dashboard";
|
|
@@ -18,13 +18,13 @@ export * from "./types/webhooks";
|
|
|
18
18
|
export * from "./types/capabilities";
|
|
19
19
|
export * from "./app/index";
|
|
20
20
|
export * from "./logging/logger";
|
|
21
|
-
export { ButtonPress, HeadPosition, GlassesBatteryUpdate, PhoneBatteryUpdate, GlassesConnectionState, LocationUpdate, CalendarEvent, Vad, PhoneNotification, PhoneNotificationDismissed, StartApp, StopApp, ConnectionInit, DashboardState, OpenDashboard, GlassesToCloudMessage, PhotoResponse, PhotoErrorCode, PhotoStage, ConnectionState, PhotoErrorDetails, RtmpStreamStatus, KeepAliveAck, } from "./types/messages/glasses-to-cloud";
|
|
22
|
-
export { ConnectionAck, ConnectionError, AuthError, DisplayEvent, AppStateChange, MicrophoneStateChange, CloudToGlassesMessage, PhotoRequestToGlasses, SettingsUpdate, StartRtmpStream, StopRtmpStream, KeepRtmpStreamAlive, } from "./types/messages/cloud-to-glasses";
|
|
23
|
-
export { AppConnectionInit, AppSubscriptionUpdate, RtmpStreamRequest, RtmpStreamStopRequest, AppToCloudMessage, PhotoRequest, } from "./types/messages/app-to-cloud";
|
|
21
|
+
export { ButtonPress, HeadPosition, TouchEvent, GlassesBatteryUpdate, PhoneBatteryUpdate, GlassesConnectionState, LocationUpdate, CalendarEvent, Vad, PhoneNotification, PhoneNotificationDismissed, StartApp, StopApp, ConnectionInit, DashboardState, OpenDashboard, GlassesToCloudMessage, PhotoResponse, RgbLedControlResponse, PhotoErrorCode, PhotoStage, ConnectionState, PhotoErrorDetails, RtmpStreamStatus, KeepAliveAck, } from "./types/messages/glasses-to-cloud";
|
|
22
|
+
export { ConnectionAck, ConnectionError, AuthError, DisplayEvent, AppStateChange, MicrophoneStateChange, CloudToGlassesMessage, PhotoRequestToGlasses, RgbLedControlToGlasses, SettingsUpdate, StartRtmpStream, StopRtmpStream, KeepRtmpStreamAlive, LedColor, } from "./types/messages/cloud-to-glasses";
|
|
23
|
+
export { AppConnectionInit, AppSubscriptionUpdate, RtmpStreamRequest, RtmpStreamStopRequest, AppToCloudMessage, PhotoRequest, RgbLedControlRequest, } from "./types/messages/app-to-cloud";
|
|
24
24
|
export { TextWall, DoubleTextWall, DashboardCard, ReferenceCard, Layout, DisplayRequest, BitmapView, ClearView, } from "./types/layouts";
|
|
25
|
-
export { isButtonPress, isHeadPosition, isConnectionInit, isStartApp, isStopApp, isPhotoResponse as isPhotoResponseFromGlasses, isRtmpStreamStatus as isRtmpStreamStatusFromGlasses, isKeepAliveAck, isPhoneNotificationDismissed, } from "./types/messages/glasses-to-cloud";
|
|
26
|
-
export { isConnectionAck, isDisplayEvent, isAppStateChange, isPhotoRequest, isSettingsUpdate as isSettingsUpdateToGlasses, isStartRtmpStream, isStopRtmpStream, isKeepRtmpStreamAlive, } from "./types/messages/cloud-to-glasses";
|
|
27
|
-
export { isAppConnectionInit, isAppSubscriptionUpdate, isDisplayRequest, isRtmpStreamRequest, isRtmpStreamStopRequest, isPhotoRequest as isPhotoRequestFromApp, } from "./types/messages/app-to-cloud";
|
|
25
|
+
export { isButtonPress, isHeadPosition, isConnectionInit, isStartApp, isStopApp, isPhotoResponse as isPhotoResponseFromGlasses, isRgbLedControlResponse as isRgbLedControlResponseFromGlasses, isRtmpStreamStatus as isRtmpStreamStatusFromGlasses, isKeepAliveAck, isPhoneNotificationDismissed, } from "./types/messages/glasses-to-cloud";
|
|
26
|
+
export { isConnectionAck, isDisplayEvent, isAppStateChange, isPhotoRequest, isSettingsUpdate as isSettingsUpdateToGlasses, isStartRtmpStream, isStopRtmpStream, isKeepRtmpStreamAlive, isRgbLedControl, } from "./types/messages/cloud-to-glasses";
|
|
27
|
+
export { isAppConnectionInit, isAppSubscriptionUpdate, isDisplayRequest, isRtmpStreamRequest, isRtmpStreamStopRequest, isPhotoRequest as isPhotoRequestFromApp, isRgbLedControlRequest, } from "./types/messages/app-to-cloud";
|
|
28
28
|
export { BaseAppSetting, AppSetting, AppSettings, AppConfig, validateAppConfig, ToolSchema, ToolParameterSchema, HardwareRequirement, } from "./types/models";
|
|
29
29
|
export { VideoConfig, AudioConfig, StreamConfig, StreamStatusHandler, } from "./types/rtmp-stream";
|
|
30
30
|
export * from "./app/session/modules";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|