@mushi-mushi/core 1.29.0 → 1.31.0
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/README.md +1 -1
- package/dist/index.cjs +25 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1857
- package/dist/index.d.ts +27 -1857
- package/dist/index.js +25 -36
- package/dist/index.js.map +1 -1
- package/dist/reporter-channels.cjs +42 -0
- package/dist/reporter-channels.cjs.map +1 -0
- package/dist/reporter-channels.d.cts +1 -0
- package/dist/reporter-channels.d.ts +1 -0
- package/dist/reporter-channels.js +39 -0
- package/dist/reporter-channels.js.map +1 -0
- package/dist/reporter-ui.cjs +574 -0
- package/dist/reporter-ui.cjs.map +1 -0
- package/dist/reporter-ui.d.cts +189 -0
- package/dist/reporter-ui.d.ts +189 -0
- package/dist/reporter-ui.js +551 -0
- package/dist/reporter-ui.js.map +1 -0
- package/dist/types-0j5BJ3aC.d.cts +2100 -0
- package/dist/types-0j5BJ3aC.d.ts +2100 -0
- package/package.json +31 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/reporter-ui.ts"],"names":[],"mappings":"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","file":"reporter-ui.cjs","sourcesContent":["// SPDX-License-Identifier: MIT\n// Copyright (c) 2024–2026 Kenji Sakuramoto (kensaurus) — Mushi Mushi\n/**\n * FILE: reporter-ui.ts\n * PURPOSE: The one reporter-facing vocabulary shared by every SDK widget\n * (web, React Native, Capacitor): report categories, the end-user\n * status table, the timeline kinds and their copy in en/ja/es/th.\n *\n * OVERVIEW:\n * - `reporterStatus(report, locale)` maps all 14 internal `reports.status`\n * values (plus the `awaiting_reporter` and duplicate-group overlays and the\n * feature-request variants) onto eight end-user states. There is no branch\n * that echoes the raw status: an unknown value reads as \"Received\".\n * - `reporterTimelineText(kind, params, locale)` renders pipeline events from\n * a fixed template per kind. Stored notification payload text is never\n * shown, so internal category / severity can not leak to a reporter.\n *\n * USAGE:\n * - `import { reporterStatus } from '@mushi-mushi/core/reporter-ui'`\n * - Shipped as a subpath so the main `@mushi-mushi/core` entry stays within\n * its size budget; nothing here is re-exported from `index.ts`.\n *\n * Plan 018 (docs/execplans/reporter-loop-v2.md) §2.1 and §2.3.\n */\n\n/** Every value `reports_status_check` allows. Pinned to the server list by a test. */\nexport const REPORTER_CANONICAL_STATUSES = [\n 'new',\n 'pending',\n 'submitted',\n 'queued',\n 'classified',\n 'grouped',\n 'fixing',\n 'fixed',\n 'dismissed',\n 'triaged',\n 'in_progress',\n 'resolved',\n 'verified',\n 'reopened',\n] as const;\n\nexport type ReporterCanonicalStatus = (typeof REPORTER_CANONICAL_STATUSES)[number];\n\nexport const REPORTER_LOCALES = ['en', 'ja', 'es', 'th'] as const;\nexport type ReporterLocale = (typeof REPORTER_LOCALES)[number];\n\n/** Optional type chips on the one-screen report form, in display order. */\nexport const REPORTER_CATEGORIES = ['bug', 'slow', 'visual', 'confusing', 'idea'] as const;\nexport type ReporterCategory = (typeof REPORTER_CATEGORIES)[number];\n\n/** `closed_reason` values the `reports_closed_reason_check` constraint allows. */\nexport const REPORTER_CLOSED_REASONS = [\n 'duplicate',\n 'not_reproducible',\n 'wont_fix',\n 'working_as_intended',\n 'spam',\n] as const;\nexport type ReporterClosedReason = (typeof REPORTER_CLOSED_REASONS)[number];\n\nexport type ReporterTone =\n | 'neutral'\n | 'info'\n | 'attention'\n | 'progress'\n | 'success'\n | 'success-muted'\n | 'muted';\n\n/** The end-user state a report is shown in. */\nexport type ReporterStatusKey =\n | 'received'\n | 'reviewing'\n | 'reviewing_again'\n | 'fixing'\n | 'verified'\n | 'fixed_next'\n | 'fixed_version'\n | 'fixed'\n | 'closed'\n | 'waiting';\n\n/** Base state per internal status, before overlays. Exhaustive by type. */\nconst BASE_STATE: Record<ReporterCanonicalStatus, ReporterStatusKey> = {\n new: 'received',\n pending: 'received',\n submitted: 'received',\n queued: 'received',\n classified: 'reviewing',\n triaged: 'reviewing',\n grouped: 'reviewing',\n reopened: 'reviewing_again',\n fixing: 'fixing',\n in_progress: 'fixing',\n verified: 'verified',\n fixed: 'fixed_next',\n resolved: 'fixed',\n dismissed: 'closed',\n};\n\nconst TONE: Record<ReporterStatusKey, ReporterTone> = {\n received: 'neutral',\n reviewing: 'info',\n reviewing_again: 'info',\n fixing: 'progress',\n verified: 'success-muted',\n fixed_next: 'success',\n fixed_version: 'success',\n fixed: 'success',\n closed: 'muted',\n waiting: 'attention',\n};\n\n/** Timeline entry kinds the reporter detail view renders (§2.3). */\nexport const REPORTER_TIMELINE_KINDS = [\n 'received',\n 'reviewing',\n 'duplicate_linked',\n 'info_requested',\n 'comment',\n 'reporter_comment',\n 'fix_started',\n 'fixed',\n 'released',\n 'verified',\n 'reopened',\n 'closed',\n] as const;\nexport type ReporterTimelineKind = (typeof REPORTER_TIMELINE_KINDS)[number];\n\nexport interface ReporterCopy {\n status: Record<ReporterStatusKey, string>;\n detail: Record<ReporterStatusKey, string>;\n idea: { received: string; reviewing: string; fixing: string; shipped: string; shippedVersion: string };\n closedReason: Record<Exclude<ReporterClosedReason, 'spam'>, string> & { none: string };\n others: { few: string; many: string };\n timeline: Record<Exclude<ReporterTimelineKind, 'comment' | 'closed'>, string>;\n categories: Record<ReporterCategory, string>;\n ui: {\n yes: string;\n notYet: string;\n empty: string;\n loadError: string;\n retry: string;\n sending: string;\n sent: string;\n sendFailed: string;\n noReplies: string;\n you: string;\n developer: string;\n addWords: string;\n developerReplied: string;\n updates: string;\n /** Receipt after sending (replaces the form in place). */\n receipt: string;\n trackIt: string;\n done: string;\n /** Email opt-in on the receipt / report detail (never pre-ticked). */\n emailOptIn: string;\n emailPlaceholder: string;\n emailSubmit: string;\n emailCheckInbox: string;\n emailInvalid: string;\n emailFailed: string;\n /** Next-visit toast. */\n toastReplied: string;\n toastFixed: string;\n view: string;\n };\n}\n\nconst EN: ReporterCopy = {\n status: {\n received: 'Received',\n reviewing: 'Looking into it',\n reviewing_again: 'Looking into it again',\n fixing: 'Fix in progress',\n verified: 'Confirmed fixed',\n fixed_next: 'Fixed — coming in the next update',\n fixed_version: 'Fixed in v{version}',\n fixed: 'Fixed',\n closed: 'Closed',\n waiting: 'Waiting on you',\n },\n detail: {\n received: 'We got it.',\n reviewing: 'The developer has it on their list.',\n reviewing_again: 'Thanks — we reopened it.',\n fixing: 'A fix is being worked on.',\n verified: 'You confirmed the fix. Thank you!',\n fixed_next: 'It ships in the next release.',\n fixed_version: 'Update to v{version}. Does it work for you now?',\n fixed: 'Does it work for you now?',\n closed: 'Closed.',\n waiting: 'The developer asked a question — reply below.',\n },\n idea: {\n received: 'Thanks for the idea',\n reviewing: 'Under consideration',\n fixing: 'Being built',\n shipped: 'Shipped',\n shippedVersion: 'Shipped in v{version}',\n },\n closedReason: {\n duplicate: \"Same as an earlier report — we'll update you there.\",\n not_reproducible: \"We couldn't reproduce it. Reply if it happens again.\",\n wont_fix: 'We decided not to change this.',\n working_as_intended: 'This is expected behaviour.',\n none: 'Closed.',\n },\n others: {\n few: 'You and a few others reported this',\n many: 'Many people reported this',\n },\n timeline: {\n received: 'You reported this',\n reviewing: 'The developer is looking into it',\n duplicate_linked: \"Same as an existing report — we'll update you there\",\n info_requested: 'The developer asked: {text}',\n reporter_comment: 'You',\n fix_started: 'A fix is in progress',\n fixed: 'Fixed — coming in the next update',\n released: 'Shipped in v{version} — update to get it',\n verified: \"You confirmed it's fixed\",\n reopened: 'Reopened',\n },\n categories: {\n bug: 'Bug',\n slow: 'Slow',\n visual: 'Looks wrong',\n confusing: 'Confusing',\n idea: 'Idea',\n },\n ui: {\n yes: 'Yes',\n notYet: 'Not yet',\n empty: 'Nothing yet — your reports will show up here with updates.',\n loadError: \"Couldn't load updates\",\n retry: 'Retry',\n sending: 'Sending…',\n sent: 'Sent',\n sendFailed: 'Failed',\n noReplies: 'No developer replies yet.',\n you: 'You',\n developer: 'Developer',\n addWords: 'Add a few words',\n developerReplied: 'Developer replied: “{text}”',\n updates: '{n} updates on your reports',\n receipt: \"Sent. We'll let you know here when there's news.\",\n trackIt: 'Track it',\n done: 'Done',\n emailOptIn: 'Get updates by email',\n emailPlaceholder: 'you@example.com',\n emailSubmit: 'Email me updates',\n emailCheckInbox: 'Check your inbox and tap the link to confirm.',\n emailInvalid: 'That does not look like an email address.',\n emailFailed: \"Couldn't set up email updates. Try again later.\",\n toastReplied: 'The developer replied to your report',\n toastFixed: 'Your bug is fixed',\n view: 'View',\n },\n};\n\nconst JA: ReporterCopy = {\n status: {\n received: '受け付けました',\n reviewing: '確認中',\n reviewing_again: '再確認中',\n fixing: '修正中',\n verified: '修正を確認済み',\n fixed_next: '修正済み — 次のアップデートで反映',\n fixed_version: 'v{version} で修正済み',\n fixed: '修正済み',\n closed: '終了',\n waiting: 'あなたの返信待ち',\n },\n detail: {\n received: '報告を受け取りました。',\n reviewing: '開発者が対応リストに入れました。',\n reviewing_again: 'ありがとうございます。再度確認しています。',\n fixing: '修正に取り組んでいます。',\n verified: '修正を確認いただきありがとうございます!',\n fixed_next: '次のリリースで反映されます。',\n fixed_version: 'v{version} にアップデートしてください。解決しましたか?',\n fixed: '解決しましたか?',\n closed: '終了しました。',\n waiting: '開発者から質問があります。下から返信してください。',\n },\n idea: {\n received: 'アイデアをありがとうございます',\n reviewing: '検討中',\n fixing: '開発中',\n shipped: 'リリース済み',\n shippedVersion: 'v{version} でリリース済み',\n },\n closedReason: {\n duplicate: '以前の報告と同じ内容です。そちらで進捗をお知らせします。',\n not_reproducible: '再現できませんでした。再発したら返信してください。',\n wont_fix: 'この点は変更しないことにしました。',\n working_as_intended: 'これは想定どおりの動作です。',\n none: '終了しました。',\n },\n others: {\n few: 'あなたを含め数人が報告しています',\n many: '多くの人が報告しています',\n },\n timeline: {\n received: 'あなたが報告しました',\n reviewing: '開発者が確認しています',\n duplicate_linked: '既存の報告と同じ内容です。そちらで進捗をお知らせします',\n info_requested: '開発者からの質問: {text}',\n reporter_comment: 'あなた',\n fix_started: '修正中です',\n fixed: '修正済み — 次のアップデートで反映',\n released: 'v{version} でリリース — アップデートしてください',\n verified: '修正を確認しました',\n reopened: '再オープンしました',\n },\n categories: {\n bug: 'バグ',\n slow: '遅い',\n visual: '表示がおかしい',\n confusing: 'わかりにくい',\n idea: 'アイデア',\n },\n ui: {\n yes: 'はい',\n notYet: 'まだ',\n empty: 'まだありません。報告するとここに進捗が表示されます。',\n loadError: '更新を読み込めませんでした',\n retry: '再試行',\n sending: '送信中…',\n sent: '送信しました',\n sendFailed: '送信失敗',\n noReplies: '開発者からの返信はまだありません。',\n you: 'あなた',\n developer: '開発者',\n addWords: 'もう少し詳しく書いてください',\n developerReplied: '開発者からの返信:「{text}」',\n updates: 'あなたの報告に {n} 件の更新があります',\n receipt: '送信しました。進展があればここでお知らせします。',\n trackIt: '経過を見る',\n done: '閉じる',\n emailOptIn: 'メールで更新を受け取る',\n emailPlaceholder: 'you@example.com',\n emailSubmit: 'メールで受け取る',\n emailCheckInbox: '受信トレイのメールのリンクをタップして確認してください。',\n emailInvalid: 'メールアドレスの形式が正しくありません。',\n emailFailed: 'メール通知を設定できませんでした。後でもう一度お試しください。',\n toastReplied: '開発者があなたの報告に返信しました',\n toastFixed: 'あなたが報告した不具合が修正されました',\n view: '見る',\n },\n};\n\nconst ES: ReporterCopy = {\n status: {\n received: 'Recibido',\n reviewing: 'Lo estamos revisando',\n reviewing_again: 'Lo revisamos de nuevo',\n fixing: 'Corrección en curso',\n verified: 'Corrección confirmada',\n fixed_next: 'Corregido — llega en la próxima actualización',\n fixed_version: 'Corregido en v{version}',\n fixed: 'Corregido',\n closed: 'Cerrado',\n waiting: 'Esperando tu respuesta',\n },\n detail: {\n received: 'Lo recibimos.',\n reviewing: 'El desarrollador lo tiene en su lista.',\n reviewing_again: 'Gracias, lo reabrimos.',\n fixing: 'Se está trabajando en una corrección.',\n verified: 'Confirmaste la corrección. ¡Gracias!',\n fixed_next: 'Llega en la próxima versión.',\n fixed_version: 'Actualiza a v{version}. ¿Ya funciona?',\n fixed: '¿Ya funciona?',\n closed: 'Cerrado.',\n waiting: 'El desarrollador hizo una pregunta: responde abajo.',\n },\n idea: {\n received: 'Gracias por la idea',\n reviewing: 'En consideración',\n fixing: 'En desarrollo',\n shipped: 'Publicado',\n shippedVersion: 'Publicado en v{version}',\n },\n closedReason: {\n duplicate: 'Es igual a un reporte anterior; te avisaremos allí.',\n not_reproducible: 'No pudimos reproducirlo. Responde si vuelve a pasar.',\n wont_fix: 'Decidimos no cambiar esto.',\n working_as_intended: 'Este es el comportamiento esperado.',\n none: 'Cerrado.',\n },\n others: {\n few: 'Tú y algunas personas más reportaron esto',\n many: 'Muchas personas reportaron esto',\n },\n timeline: {\n received: 'Reportaste esto',\n reviewing: 'El desarrollador lo está revisando',\n duplicate_linked: 'Es igual a un reporte existente; te avisaremos allí',\n info_requested: 'El desarrollador preguntó: {text}',\n reporter_comment: 'Tú',\n fix_started: 'Hay una corrección en curso',\n fixed: 'Corregido — llega en la próxima actualización',\n released: 'Publicado en v{version}: actualiza para tenerlo',\n verified: 'Confirmaste que está corregido',\n reopened: 'Reabierto',\n },\n categories: {\n bug: 'Error',\n slow: 'Lento',\n visual: 'Se ve mal',\n confusing: 'Confuso',\n idea: 'Idea',\n },\n ui: {\n yes: 'Sí',\n notYet: 'Todavía no',\n empty: 'Nada todavía: tus reportes aparecerán aquí con novedades.',\n loadError: 'No se pudieron cargar las novedades',\n retry: 'Reintentar',\n sending: 'Enviando…',\n sent: 'Enviado',\n sendFailed: 'Error al enviar',\n noReplies: 'El desarrollador aún no ha respondido.',\n you: 'Tú',\n developer: 'Desarrollador',\n addWords: 'Agrega algunas palabras',\n developerReplied: 'El desarrollador respondió: “{text}”',\n updates: '{n} novedades en tus reportes',\n receipt: 'Enviado. Te avisaremos aquí cuando haya novedades.',\n trackIt: 'Seguirlo',\n done: 'Listo',\n emailOptIn: 'Recibir novedades por correo',\n emailPlaceholder: 'tu@ejemplo.com',\n emailSubmit: 'Enviarme novedades',\n emailCheckInbox: 'Revisa tu correo y toca el enlace para confirmar.',\n emailInvalid: 'Eso no parece un correo electrónico.',\n emailFailed: 'No pudimos activar las novedades por correo. Inténtalo más tarde.',\n toastReplied: 'El desarrollador respondió a tu reporte',\n toastFixed: 'Tu error está corregido',\n view: 'Ver',\n },\n};\n\nconst TH: ReporterCopy = {\n status: {\n received: 'ได้รับแล้ว',\n reviewing: 'กำลังตรวจสอบ',\n reviewing_again: 'กำลังตรวจสอบอีกครั้ง',\n fixing: 'กำลังแก้ไข',\n verified: 'ยืนยันว่าแก้แล้ว',\n fixed_next: 'แก้แล้ว — จะมาในอัปเดตถัดไป',\n fixed_version: 'แก้แล้วใน v{version}',\n fixed: 'แก้แล้ว',\n closed: 'ปิดแล้ว',\n waiting: 'รอคำตอบจากคุณ',\n },\n detail: {\n received: 'เราได้รับรายงานแล้ว',\n reviewing: 'นักพัฒนาใส่ไว้ในรายการแล้ว',\n reviewing_again: 'ขอบคุณ — เราเปิดเรื่องนี้อีกครั้งแล้ว',\n fixing: 'กำลังดำเนินการแก้ไข',\n verified: 'คุณยืนยันการแก้ไขแล้ว ขอบคุณ!',\n fixed_next: 'จะมาในรุ่นถัดไป',\n fixed_version: 'อัปเดตเป็น v{version} ตอนนี้ใช้ได้หรือยัง?',\n fixed: 'ตอนนี้ใช้ได้หรือยัง?',\n closed: 'ปิดแล้ว',\n waiting: 'นักพัฒนามีคำถาม — ตอบด้านล่าง',\n },\n idea: {\n received: 'ขอบคุณสำหรับไอเดีย',\n reviewing: 'กำลังพิจารณา',\n fixing: 'กำลังสร้าง',\n shipped: 'เปิดใช้แล้ว',\n shippedVersion: 'เปิดใช้แล้วใน v{version}',\n },\n closedReason: {\n duplicate: 'เหมือนกับรายงานก่อนหน้า — เราจะแจ้งความคืบหน้าที่นั่น',\n not_reproducible: 'เราทำให้เกิดซ้ำไม่ได้ ตอบกลับหากเกิดขึ้นอีก',\n wont_fix: 'เราตัดสินใจไม่เปลี่ยนส่วนนี้',\n working_as_intended: 'นี่เป็นการทำงานตามที่ตั้งใจไว้',\n none: 'ปิดแล้ว',\n },\n others: {\n few: 'คุณและอีกไม่กี่คนรายงานเรื่องนี้',\n many: 'มีหลายคนรายงานเรื่องนี้',\n },\n timeline: {\n received: 'คุณรายงานเรื่องนี้',\n reviewing: 'นักพัฒนากำลังตรวจสอบ',\n duplicate_linked: 'เหมือนกับรายงานที่มีอยู่ — เราจะแจ้งความคืบหน้าที่นั่น',\n info_requested: 'นักพัฒนาถามว่า: {text}',\n reporter_comment: 'คุณ',\n fix_started: 'กำลังแก้ไข',\n fixed: 'แก้แล้ว — จะมาในอัปเดตถัดไป',\n released: 'เปิดใช้ใน v{version} — อัปเดตเพื่อรับการแก้ไข',\n verified: 'คุณยืนยันว่าแก้แล้ว',\n reopened: 'เปิดอีกครั้ง',\n },\n categories: {\n bug: 'บั๊ก',\n slow: 'ช้า',\n visual: 'แสดงผลผิด',\n confusing: 'สับสน',\n idea: 'ไอเดีย',\n },\n ui: {\n yes: 'ใช่',\n notYet: 'ยังไม่',\n empty: 'ยังไม่มี — รายงานของคุณจะแสดงที่นี่พร้อมความคืบหน้า',\n loadError: 'โหลดความคืบหน้าไม่ได้',\n retry: 'ลองอีกครั้ง',\n sending: 'กำลังส่ง…',\n sent: 'ส่งแล้ว',\n sendFailed: 'ส่งไม่สำเร็จ',\n noReplies: 'ยังไม่มีคำตอบจากนักพัฒนา',\n you: 'คุณ',\n developer: 'นักพัฒนา',\n addWords: 'เพิ่มรายละเอียดอีกเล็กน้อย',\n developerReplied: 'นักพัฒนาตอบว่า: “{text}”',\n updates: 'มีความคืบหน้า {n} รายการในรายงานของคุณ',\n receipt: 'ส่งแล้ว เราจะแจ้งคุณที่นี่เมื่อมีความคืบหน้า',\n trackIt: 'ติดตาม',\n done: 'เสร็จ',\n emailOptIn: 'รับความคืบหน้าทางอีเมล',\n emailPlaceholder: 'you@example.com',\n emailSubmit: 'ส่งความคืบหน้าทางอีเมล',\n emailCheckInbox: 'ตรวจสอบกล่องจดหมายแล้วแตะลิงก์เพื่อยืนยัน',\n emailInvalid: 'ดูเหมือนจะไม่ใช่อีเมลที่ถูกต้อง',\n emailFailed: 'ตั้งค่าการแจ้งทางอีเมลไม่สำเร็จ ลองใหม่ภายหลัง',\n toastReplied: 'นักพัฒนาตอบกลับรายงานของคุณแล้ว',\n toastFixed: 'บั๊กที่คุณรายงานได้รับการแก้ไขแล้ว',\n view: 'ดู',\n },\n};\n\nconst COPY: Record<ReporterLocale, ReporterCopy> = { en: EN, ja: JA, es: ES, th: TH };\n\n/** Resolve a BCP-47 tag (`ja-JP`, `es-419`) to a supported locale; English otherwise. */\nexport function resolveReporterLocale(tag: string | null | undefined): ReporterLocale {\n const base = (tag ?? '').toLowerCase().split(/[-_]/)[0];\n return (REPORTER_LOCALES as readonly string[]).includes(base) ? (base as ReporterLocale) : 'en';\n}\n\n/** The full copy table for a locale (unknown tags fall back to English). */\nexport function reporterCopy(locale: string = 'en'): ReporterCopy {\n return COPY[resolveReporterLocale(locale)];\n}\n\n/** Replace `{name}` placeholders; a missing value leaves an empty string. */\nexport function fillReporterTemplate(\n template: string,\n params: Record<string, string | number | null | undefined> = {},\n): string {\n return template.replace(/\\{(\\w+)\\}/g, (_, key: string) => {\n const value = params[key];\n return value === null || value === undefined ? '' : String(value);\n });\n}\n\n/** Fields of a reporter-list row `reporterStatus` reads. All but `status` are optional. */\nexport interface ReporterStatusInput {\n status: string;\n /** True (or a timestamp) while the developer waits for the reporter. */\n awaiting_reporter?: boolean | null;\n awaiting_reporter_at?: string | null;\n fixed_in_version?: string | null;\n closed_reason?: string | null;\n /** Bucketed duplicate count; never a raw number. */\n group_bucket?: 'none' | 'few' | 'many' | null;\n /** `user_category`; \"Feature request\" / \"idea\" selects the idea labels. */\n user_category?: string | null;\n}\n\nexport interface ReporterStatusView {\n key: ReporterStatusKey;\n label: string;\n tone: ReporterTone;\n detail: string;\n /** Show the Yes / Not yet verification buttons. */\n canVerify: boolean;\n /** \"You and a few others reported this\", or null. */\n othersNote: string | null;\n /** `closed_reason = 'spam'`: hide the report from the reporter entirely. */\n hidden: boolean;\n}\n\nconst OPEN_KEYS: ReadonlySet<ReporterStatusKey> = new Set([\n 'received',\n 'reviewing',\n 'reviewing_again',\n 'fixing',\n]);\n\nfunction isCanonical(status: string): status is ReporterCanonicalStatus {\n return (REPORTER_CANONICAL_STATUSES as readonly string[]).includes(status);\n}\n\n/** True when the row is a feature request rather than a bug. */\nexport function isReporterIdea(input: Pick<ReporterStatusInput, 'user_category'>): boolean {\n const cat = (input.user_category ?? '').trim().toLowerCase().replace(/[\\s-]+/g, '_');\n // The web widget and the ingest path send 'feature'; older clients sent\n // 'Feature request'. The server's isFeatureRequest() accepts the same set.\n return cat === 'feature' || cat === 'feature_request' || cat === 'idea';\n}\n\n/**\n * The end-user view of a report. Overlays are checked before the base\n * status: \"Waiting on you\" wins for any open report, and the duplicate-group\n * note is added on top of whatever the base state is.\n */\nexport function reporterStatus(input: ReporterStatusInput, locale: string = 'en'): ReporterStatusView {\n const copy = reporterCopy(locale);\n const status = (input.status ?? '').trim();\n // No raw passthrough: anything the table does not know reads as Received.\n let key: ReporterStatusKey = isCanonical(status) ? BASE_STATE[status] : 'received';\n\n const version = input.fixed_in_version?.trim() || null;\n if ((status === 'fixed' || status === 'resolved') && version) key = 'fixed_version';\n\n const awaiting = Boolean(input.awaiting_reporter) || Boolean(input.awaiting_reporter_at);\n if (awaiting && OPEN_KEYS.has(key)) key = 'waiting';\n\n const idea = isReporterIdea(input);\n let label = copy.status[key];\n let detail = copy.detail[key];\n if (idea) {\n if (key === 'received') label = copy.idea.received;\n else if (key === 'reviewing' || key === 'reviewing_again') label = copy.idea.reviewing;\n else if (key === 'fixing') label = copy.idea.fixing;\n else if (key === 'fixed_version') label = copy.idea.shippedVersion;\n else if (key === 'fixed_next' || key === 'fixed') label = copy.idea.shipped;\n }\n\n const reason = input.closed_reason ?? null;\n if (key === 'closed') {\n detail =\n reason && reason !== 'spam' && reason in copy.closedReason\n ? copy.closedReason[reason as keyof ReporterCopy['closedReason']]\n : copy.closedReason.none;\n }\n\n const bucket = input.group_bucket ?? 'none';\n const othersNote =\n OPEN_KEYS.has(key) || key === 'waiting'\n ? bucket === 'few'\n ? copy.others.few\n : bucket === 'many'\n ? copy.others.many\n : null\n : null;\n\n return {\n key,\n label: fillReporterTemplate(label, { version }),\n tone: TONE[key],\n detail: fillReporterTemplate(detail, { version }),\n canVerify: key === 'fixed_next' || key === 'fixed_version' || key === 'fixed',\n othersNote,\n hidden: key === 'closed' && reason === 'spam',\n };\n}\n\n/** Parameters a timeline template may interpolate. */\nexport interface ReporterTimelineParams {\n /** Verbatim developer text for `comment` and `info_requested`; the reporter's own for `reporter_comment`. */\n text?: string | null;\n version?: string | null;\n closed_reason?: string | null;\n}\n\n/**\n * Render one timeline entry. Pipeline kinds always come from the template for\n * their kind; only the developer's own words (`comment`, `info_requested`) are\n * passed through, verbatim.\n */\nexport function reporterTimelineText(\n kind: ReporterTimelineKind,\n params: ReporterTimelineParams = {},\n locale: string = 'en',\n): string {\n const copy = reporterCopy(locale);\n if (kind === 'comment') return params.text ?? '';\n if (kind === 'closed') {\n const reason = params.closed_reason ?? '';\n return reason && reason !== 'spam' && reason in copy.closedReason\n ? copy.closedReason[reason as keyof ReporterCopy['closedReason']]\n : copy.closedReason.none;\n }\n if (kind === 'reporter_comment') return params.text ?? copy.timeline.reporter_comment;\n return fillReporterTemplate(copy.timeline[kind], { text: params.text, version: params.version });\n}\n\n/** Reporter-facing label for a category chip. */\nexport function reporterCategoryLabel(category: ReporterCategory, locale: string = 'en'): string {\n return reporterCopy(locale).categories[category];\n}\n\n// ---------------------------------------------------------------------------\n// Widget rules shared by web and React Native (Plan 018 §1.1, §2.3, §4.2)\n// ---------------------------------------------------------------------------\n\n/** A few words are enough; an attachment speaks for itself (§1.1). */\nexport const REPORTER_MIN_DESCRIPTION = 8;\n\n/** Characters Send needs: `min` (default 8), or 0 with a screenshot / element attached. */\nexport function reporterRequiredLength(min: number | undefined, hasAttachment: boolean): number {\n if (hasAttachment) return 0;\n return typeof min === 'number' && Number.isFinite(min) && min >= 0 ? Math.floor(min) : REPORTER_MIN_DESCRIPTION;\n}\n\n/** Whether Send is enabled: some text or an attachment, and enough words. */\nexport function reporterCanSend(text: string, hasAttachment: boolean, min?: number): boolean {\n const trimmed = text.trim();\n if (!trimmed && !hasAttachment) return false;\n return trimmed.length >= reporterRequiredLength(min, hasAttachment);\n}\n\n/** Wire category for an optional chip: none → `other` (triage sets the type); Idea → a feature request. */\nexport function reporterChipToReport(\n chip: ReporterCategory | null,\n): { category: 'bug' | 'slow' | 'visual' | 'confusing' | 'other'; userCategory?: string } {\n if (!chip) return { category: 'other' };\n if (chip === 'idea') return { category: 'other', userCategory: 'feature' };\n return { category: chip };\n}\n\n/** One entry of `GET /v1/reporter/reports/:id` → `timeline` (subset the widgets read). */\nexport interface ReporterTimelineEntry {\n kind: string;\n text: string;\n /** Developer- or project-written text: show `text` as is. */\n custom?: boolean;\n body?: string;\n version?: string;\n closed_reason?: string;\n}\n\n/** True for the people talking (developer / reporter), false for pipeline events. */\nexport function isReporterConversation(entry: Pick<ReporterTimelineEntry, 'kind'>): boolean {\n return entry.kind === 'comment' || entry.kind === 'reporter_comment' || entry.kind === 'info_requested';\n}\n\n/** Text for one timeline entry in the reporter's locale; custom wording is shown as is. */\nexport function reporterTimelineEntryText(entry: ReporterTimelineEntry, locale: string = 'en'): string {\n if (entry.custom || !(REPORTER_TIMELINE_KINDS as readonly string[]).includes(entry.kind)) return entry.text;\n return reporterTimelineText(\n entry.kind as ReporterTimelineKind,\n { text: entry.body ?? null, version: entry.version ?? null, closed_reason: entry.closed_reason ?? null },\n locale,\n );\n}\n\nexport const REPORTER_TOAST_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\n/** The next-visit toast: one per session and at most one a day, only with something unread (§4.2). */\nexport function reporterShouldShowToast(input: {\n enabled: boolean;\n unreadTotal: number;\n shownThisSession: boolean;\n lastShownAt: number | null;\n now: number;\n}): boolean {\n if (!input.enabled || input.unreadTotal <= 0 || input.shownThisSession) return false;\n return input.lastShownAt === null || input.now - input.lastShownAt >= REPORTER_TOAST_INTERVAL_MS;\n}\n\n/** \"The developer replied…\", \"Your bug is fixed\", or \"3 updates on your reports\". */\nexport function reporterToastMessage(\n updates: { unread_total: number; latest: Array<{ kind: string | null }> },\n locale: string = 'en',\n): string {\n const ui = reporterCopy(locale).ui;\n const kind = updates.unread_total === 1 ? updates.latest[0]?.kind : null;\n if (kind === 'comment' || kind === 'info_requested') return ui.toastReplied;\n if (kind === 'fixed' || kind === 'released') return ui.toastFixed;\n return ui.updates.replace('{n}', String(updates.unread_total));\n}\n\n/** A typo screen for the email opt-in box; the server validates the address. */\nexport function isPlausibleReporterEmail(raw: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/.test(raw.trim());\n}\n"]}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FILE: reporter-ui.ts
|
|
3
|
+
* PURPOSE: The one reporter-facing vocabulary shared by every SDK widget
|
|
4
|
+
* (web, React Native, Capacitor): report categories, the end-user
|
|
5
|
+
* status table, the timeline kinds and their copy in en/ja/es/th.
|
|
6
|
+
*
|
|
7
|
+
* OVERVIEW:
|
|
8
|
+
* - `reporterStatus(report, locale)` maps all 14 internal `reports.status`
|
|
9
|
+
* values (plus the `awaiting_reporter` and duplicate-group overlays and the
|
|
10
|
+
* feature-request variants) onto eight end-user states. There is no branch
|
|
11
|
+
* that echoes the raw status: an unknown value reads as "Received".
|
|
12
|
+
* - `reporterTimelineText(kind, params, locale)` renders pipeline events from
|
|
13
|
+
* a fixed template per kind. Stored notification payload text is never
|
|
14
|
+
* shown, so internal category / severity can not leak to a reporter.
|
|
15
|
+
*
|
|
16
|
+
* USAGE:
|
|
17
|
+
* - `import { reporterStatus } from '@mushi-mushi/core/reporter-ui'`
|
|
18
|
+
* - Shipped as a subpath so the main `@mushi-mushi/core` entry stays within
|
|
19
|
+
* its size budget; nothing here is re-exported from `index.ts`.
|
|
20
|
+
*
|
|
21
|
+
* Plan 018 (docs/execplans/reporter-loop-v2.md) §2.1 and §2.3.
|
|
22
|
+
*/
|
|
23
|
+
/** Every value `reports_status_check` allows. Pinned to the server list by a test. */
|
|
24
|
+
declare const REPORTER_CANONICAL_STATUSES: readonly ["new", "pending", "submitted", "queued", "classified", "grouped", "fixing", "fixed", "dismissed", "triaged", "in_progress", "resolved", "verified", "reopened"];
|
|
25
|
+
type ReporterCanonicalStatus = (typeof REPORTER_CANONICAL_STATUSES)[number];
|
|
26
|
+
declare const REPORTER_LOCALES: readonly ["en", "ja", "es", "th"];
|
|
27
|
+
type ReporterLocale = (typeof REPORTER_LOCALES)[number];
|
|
28
|
+
/** Optional type chips on the one-screen report form, in display order. */
|
|
29
|
+
declare const REPORTER_CATEGORIES: readonly ["bug", "slow", "visual", "confusing", "idea"];
|
|
30
|
+
type ReporterCategory = (typeof REPORTER_CATEGORIES)[number];
|
|
31
|
+
/** `closed_reason` values the `reports_closed_reason_check` constraint allows. */
|
|
32
|
+
declare const REPORTER_CLOSED_REASONS: readonly ["duplicate", "not_reproducible", "wont_fix", "working_as_intended", "spam"];
|
|
33
|
+
type ReporterClosedReason = (typeof REPORTER_CLOSED_REASONS)[number];
|
|
34
|
+
type ReporterTone = 'neutral' | 'info' | 'attention' | 'progress' | 'success' | 'success-muted' | 'muted';
|
|
35
|
+
/** The end-user state a report is shown in. */
|
|
36
|
+
type ReporterStatusKey = 'received' | 'reviewing' | 'reviewing_again' | 'fixing' | 'verified' | 'fixed_next' | 'fixed_version' | 'fixed' | 'closed' | 'waiting';
|
|
37
|
+
/** Timeline entry kinds the reporter detail view renders (§2.3). */
|
|
38
|
+
declare const REPORTER_TIMELINE_KINDS: readonly ["received", "reviewing", "duplicate_linked", "info_requested", "comment", "reporter_comment", "fix_started", "fixed", "released", "verified", "reopened", "closed"];
|
|
39
|
+
type ReporterTimelineKind = (typeof REPORTER_TIMELINE_KINDS)[number];
|
|
40
|
+
interface ReporterCopy {
|
|
41
|
+
status: Record<ReporterStatusKey, string>;
|
|
42
|
+
detail: Record<ReporterStatusKey, string>;
|
|
43
|
+
idea: {
|
|
44
|
+
received: string;
|
|
45
|
+
reviewing: string;
|
|
46
|
+
fixing: string;
|
|
47
|
+
shipped: string;
|
|
48
|
+
shippedVersion: string;
|
|
49
|
+
};
|
|
50
|
+
closedReason: Record<Exclude<ReporterClosedReason, 'spam'>, string> & {
|
|
51
|
+
none: string;
|
|
52
|
+
};
|
|
53
|
+
others: {
|
|
54
|
+
few: string;
|
|
55
|
+
many: string;
|
|
56
|
+
};
|
|
57
|
+
timeline: Record<Exclude<ReporterTimelineKind, 'comment' | 'closed'>, string>;
|
|
58
|
+
categories: Record<ReporterCategory, string>;
|
|
59
|
+
ui: {
|
|
60
|
+
yes: string;
|
|
61
|
+
notYet: string;
|
|
62
|
+
empty: string;
|
|
63
|
+
loadError: string;
|
|
64
|
+
retry: string;
|
|
65
|
+
sending: string;
|
|
66
|
+
sent: string;
|
|
67
|
+
sendFailed: string;
|
|
68
|
+
noReplies: string;
|
|
69
|
+
you: string;
|
|
70
|
+
developer: string;
|
|
71
|
+
addWords: string;
|
|
72
|
+
developerReplied: string;
|
|
73
|
+
updates: string;
|
|
74
|
+
/** Receipt after sending (replaces the form in place). */
|
|
75
|
+
receipt: string;
|
|
76
|
+
trackIt: string;
|
|
77
|
+
done: string;
|
|
78
|
+
/** Email opt-in on the receipt / report detail (never pre-ticked). */
|
|
79
|
+
emailOptIn: string;
|
|
80
|
+
emailPlaceholder: string;
|
|
81
|
+
emailSubmit: string;
|
|
82
|
+
emailCheckInbox: string;
|
|
83
|
+
emailInvalid: string;
|
|
84
|
+
emailFailed: string;
|
|
85
|
+
/** Next-visit toast. */
|
|
86
|
+
toastReplied: string;
|
|
87
|
+
toastFixed: string;
|
|
88
|
+
view: string;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Resolve a BCP-47 tag (`ja-JP`, `es-419`) to a supported locale; English otherwise. */
|
|
92
|
+
declare function resolveReporterLocale(tag: string | null | undefined): ReporterLocale;
|
|
93
|
+
/** The full copy table for a locale (unknown tags fall back to English). */
|
|
94
|
+
declare function reporterCopy(locale?: string): ReporterCopy;
|
|
95
|
+
/** Replace `{name}` placeholders; a missing value leaves an empty string. */
|
|
96
|
+
declare function fillReporterTemplate(template: string, params?: Record<string, string | number | null | undefined>): string;
|
|
97
|
+
/** Fields of a reporter-list row `reporterStatus` reads. All but `status` are optional. */
|
|
98
|
+
interface ReporterStatusInput {
|
|
99
|
+
status: string;
|
|
100
|
+
/** True (or a timestamp) while the developer waits for the reporter. */
|
|
101
|
+
awaiting_reporter?: boolean | null;
|
|
102
|
+
awaiting_reporter_at?: string | null;
|
|
103
|
+
fixed_in_version?: string | null;
|
|
104
|
+
closed_reason?: string | null;
|
|
105
|
+
/** Bucketed duplicate count; never a raw number. */
|
|
106
|
+
group_bucket?: 'none' | 'few' | 'many' | null;
|
|
107
|
+
/** `user_category`; "Feature request" / "idea" selects the idea labels. */
|
|
108
|
+
user_category?: string | null;
|
|
109
|
+
}
|
|
110
|
+
interface ReporterStatusView {
|
|
111
|
+
key: ReporterStatusKey;
|
|
112
|
+
label: string;
|
|
113
|
+
tone: ReporterTone;
|
|
114
|
+
detail: string;
|
|
115
|
+
/** Show the Yes / Not yet verification buttons. */
|
|
116
|
+
canVerify: boolean;
|
|
117
|
+
/** "You and a few others reported this", or null. */
|
|
118
|
+
othersNote: string | null;
|
|
119
|
+
/** `closed_reason = 'spam'`: hide the report from the reporter entirely. */
|
|
120
|
+
hidden: boolean;
|
|
121
|
+
}
|
|
122
|
+
/** True when the row is a feature request rather than a bug. */
|
|
123
|
+
declare function isReporterIdea(input: Pick<ReporterStatusInput, 'user_category'>): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* The end-user view of a report. Overlays are checked before the base
|
|
126
|
+
* status: "Waiting on you" wins for any open report, and the duplicate-group
|
|
127
|
+
* note is added on top of whatever the base state is.
|
|
128
|
+
*/
|
|
129
|
+
declare function reporterStatus(input: ReporterStatusInput, locale?: string): ReporterStatusView;
|
|
130
|
+
/** Parameters a timeline template may interpolate. */
|
|
131
|
+
interface ReporterTimelineParams {
|
|
132
|
+
/** Verbatim developer text for `comment` and `info_requested`; the reporter's own for `reporter_comment`. */
|
|
133
|
+
text?: string | null;
|
|
134
|
+
version?: string | null;
|
|
135
|
+
closed_reason?: string | null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Render one timeline entry. Pipeline kinds always come from the template for
|
|
139
|
+
* their kind; only the developer's own words (`comment`, `info_requested`) are
|
|
140
|
+
* passed through, verbatim.
|
|
141
|
+
*/
|
|
142
|
+
declare function reporterTimelineText(kind: ReporterTimelineKind, params?: ReporterTimelineParams, locale?: string): string;
|
|
143
|
+
/** Reporter-facing label for a category chip. */
|
|
144
|
+
declare function reporterCategoryLabel(category: ReporterCategory, locale?: string): string;
|
|
145
|
+
/** A few words are enough; an attachment speaks for itself (§1.1). */
|
|
146
|
+
declare const REPORTER_MIN_DESCRIPTION = 8;
|
|
147
|
+
/** Characters Send needs: `min` (default 8), or 0 with a screenshot / element attached. */
|
|
148
|
+
declare function reporterRequiredLength(min: number | undefined, hasAttachment: boolean): number;
|
|
149
|
+
/** Whether Send is enabled: some text or an attachment, and enough words. */
|
|
150
|
+
declare function reporterCanSend(text: string, hasAttachment: boolean, min?: number): boolean;
|
|
151
|
+
/** Wire category for an optional chip: none → `other` (triage sets the type); Idea → a feature request. */
|
|
152
|
+
declare function reporterChipToReport(chip: ReporterCategory | null): {
|
|
153
|
+
category: 'bug' | 'slow' | 'visual' | 'confusing' | 'other';
|
|
154
|
+
userCategory?: string;
|
|
155
|
+
};
|
|
156
|
+
/** One entry of `GET /v1/reporter/reports/:id` → `timeline` (subset the widgets read). */
|
|
157
|
+
interface ReporterTimelineEntry {
|
|
158
|
+
kind: string;
|
|
159
|
+
text: string;
|
|
160
|
+
/** Developer- or project-written text: show `text` as is. */
|
|
161
|
+
custom?: boolean;
|
|
162
|
+
body?: string;
|
|
163
|
+
version?: string;
|
|
164
|
+
closed_reason?: string;
|
|
165
|
+
}
|
|
166
|
+
/** True for the people talking (developer / reporter), false for pipeline events. */
|
|
167
|
+
declare function isReporterConversation(entry: Pick<ReporterTimelineEntry, 'kind'>): boolean;
|
|
168
|
+
/** Text for one timeline entry in the reporter's locale; custom wording is shown as is. */
|
|
169
|
+
declare function reporterTimelineEntryText(entry: ReporterTimelineEntry, locale?: string): string;
|
|
170
|
+
declare const REPORTER_TOAST_INTERVAL_MS: number;
|
|
171
|
+
/** The next-visit toast: one per session and at most one a day, only with something unread (§4.2). */
|
|
172
|
+
declare function reporterShouldShowToast(input: {
|
|
173
|
+
enabled: boolean;
|
|
174
|
+
unreadTotal: number;
|
|
175
|
+
shownThisSession: boolean;
|
|
176
|
+
lastShownAt: number | null;
|
|
177
|
+
now: number;
|
|
178
|
+
}): boolean;
|
|
179
|
+
/** "The developer replied…", "Your bug is fixed", or "3 updates on your reports". */
|
|
180
|
+
declare function reporterToastMessage(updates: {
|
|
181
|
+
unread_total: number;
|
|
182
|
+
latest: Array<{
|
|
183
|
+
kind: string | null;
|
|
184
|
+
}>;
|
|
185
|
+
}, locale?: string): string;
|
|
186
|
+
/** A typo screen for the email opt-in box; the server validates the address. */
|
|
187
|
+
declare function isPlausibleReporterEmail(raw: string): boolean;
|
|
188
|
+
|
|
189
|
+
export { REPORTER_CANONICAL_STATUSES, REPORTER_CATEGORIES, REPORTER_CLOSED_REASONS, REPORTER_LOCALES, REPORTER_MIN_DESCRIPTION, REPORTER_TIMELINE_KINDS, REPORTER_TOAST_INTERVAL_MS, type ReporterCanonicalStatus, type ReporterCategory, type ReporterClosedReason, type ReporterCopy, type ReporterLocale, type ReporterStatusInput, type ReporterStatusKey, type ReporterStatusView, type ReporterTimelineEntry, type ReporterTimelineKind, type ReporterTimelineParams, type ReporterTone, fillReporterTemplate, isPlausibleReporterEmail, isReporterConversation, isReporterIdea, reporterCanSend, reporterCategoryLabel, reporterChipToReport, reporterCopy, reporterRequiredLength, reporterShouldShowToast, reporterStatus, reporterTimelineEntryText, reporterTimelineText, reporterToastMessage, resolveReporterLocale };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FILE: reporter-ui.ts
|
|
3
|
+
* PURPOSE: The one reporter-facing vocabulary shared by every SDK widget
|
|
4
|
+
* (web, React Native, Capacitor): report categories, the end-user
|
|
5
|
+
* status table, the timeline kinds and their copy in en/ja/es/th.
|
|
6
|
+
*
|
|
7
|
+
* OVERVIEW:
|
|
8
|
+
* - `reporterStatus(report, locale)` maps all 14 internal `reports.status`
|
|
9
|
+
* values (plus the `awaiting_reporter` and duplicate-group overlays and the
|
|
10
|
+
* feature-request variants) onto eight end-user states. There is no branch
|
|
11
|
+
* that echoes the raw status: an unknown value reads as "Received".
|
|
12
|
+
* - `reporterTimelineText(kind, params, locale)` renders pipeline events from
|
|
13
|
+
* a fixed template per kind. Stored notification payload text is never
|
|
14
|
+
* shown, so internal category / severity can not leak to a reporter.
|
|
15
|
+
*
|
|
16
|
+
* USAGE:
|
|
17
|
+
* - `import { reporterStatus } from '@mushi-mushi/core/reporter-ui'`
|
|
18
|
+
* - Shipped as a subpath so the main `@mushi-mushi/core` entry stays within
|
|
19
|
+
* its size budget; nothing here is re-exported from `index.ts`.
|
|
20
|
+
*
|
|
21
|
+
* Plan 018 (docs/execplans/reporter-loop-v2.md) §2.1 and §2.3.
|
|
22
|
+
*/
|
|
23
|
+
/** Every value `reports_status_check` allows. Pinned to the server list by a test. */
|
|
24
|
+
declare const REPORTER_CANONICAL_STATUSES: readonly ["new", "pending", "submitted", "queued", "classified", "grouped", "fixing", "fixed", "dismissed", "triaged", "in_progress", "resolved", "verified", "reopened"];
|
|
25
|
+
type ReporterCanonicalStatus = (typeof REPORTER_CANONICAL_STATUSES)[number];
|
|
26
|
+
declare const REPORTER_LOCALES: readonly ["en", "ja", "es", "th"];
|
|
27
|
+
type ReporterLocale = (typeof REPORTER_LOCALES)[number];
|
|
28
|
+
/** Optional type chips on the one-screen report form, in display order. */
|
|
29
|
+
declare const REPORTER_CATEGORIES: readonly ["bug", "slow", "visual", "confusing", "idea"];
|
|
30
|
+
type ReporterCategory = (typeof REPORTER_CATEGORIES)[number];
|
|
31
|
+
/** `closed_reason` values the `reports_closed_reason_check` constraint allows. */
|
|
32
|
+
declare const REPORTER_CLOSED_REASONS: readonly ["duplicate", "not_reproducible", "wont_fix", "working_as_intended", "spam"];
|
|
33
|
+
type ReporterClosedReason = (typeof REPORTER_CLOSED_REASONS)[number];
|
|
34
|
+
type ReporterTone = 'neutral' | 'info' | 'attention' | 'progress' | 'success' | 'success-muted' | 'muted';
|
|
35
|
+
/** The end-user state a report is shown in. */
|
|
36
|
+
type ReporterStatusKey = 'received' | 'reviewing' | 'reviewing_again' | 'fixing' | 'verified' | 'fixed_next' | 'fixed_version' | 'fixed' | 'closed' | 'waiting';
|
|
37
|
+
/** Timeline entry kinds the reporter detail view renders (§2.3). */
|
|
38
|
+
declare const REPORTER_TIMELINE_KINDS: readonly ["received", "reviewing", "duplicate_linked", "info_requested", "comment", "reporter_comment", "fix_started", "fixed", "released", "verified", "reopened", "closed"];
|
|
39
|
+
type ReporterTimelineKind = (typeof REPORTER_TIMELINE_KINDS)[number];
|
|
40
|
+
interface ReporterCopy {
|
|
41
|
+
status: Record<ReporterStatusKey, string>;
|
|
42
|
+
detail: Record<ReporterStatusKey, string>;
|
|
43
|
+
idea: {
|
|
44
|
+
received: string;
|
|
45
|
+
reviewing: string;
|
|
46
|
+
fixing: string;
|
|
47
|
+
shipped: string;
|
|
48
|
+
shippedVersion: string;
|
|
49
|
+
};
|
|
50
|
+
closedReason: Record<Exclude<ReporterClosedReason, 'spam'>, string> & {
|
|
51
|
+
none: string;
|
|
52
|
+
};
|
|
53
|
+
others: {
|
|
54
|
+
few: string;
|
|
55
|
+
many: string;
|
|
56
|
+
};
|
|
57
|
+
timeline: Record<Exclude<ReporterTimelineKind, 'comment' | 'closed'>, string>;
|
|
58
|
+
categories: Record<ReporterCategory, string>;
|
|
59
|
+
ui: {
|
|
60
|
+
yes: string;
|
|
61
|
+
notYet: string;
|
|
62
|
+
empty: string;
|
|
63
|
+
loadError: string;
|
|
64
|
+
retry: string;
|
|
65
|
+
sending: string;
|
|
66
|
+
sent: string;
|
|
67
|
+
sendFailed: string;
|
|
68
|
+
noReplies: string;
|
|
69
|
+
you: string;
|
|
70
|
+
developer: string;
|
|
71
|
+
addWords: string;
|
|
72
|
+
developerReplied: string;
|
|
73
|
+
updates: string;
|
|
74
|
+
/** Receipt after sending (replaces the form in place). */
|
|
75
|
+
receipt: string;
|
|
76
|
+
trackIt: string;
|
|
77
|
+
done: string;
|
|
78
|
+
/** Email opt-in on the receipt / report detail (never pre-ticked). */
|
|
79
|
+
emailOptIn: string;
|
|
80
|
+
emailPlaceholder: string;
|
|
81
|
+
emailSubmit: string;
|
|
82
|
+
emailCheckInbox: string;
|
|
83
|
+
emailInvalid: string;
|
|
84
|
+
emailFailed: string;
|
|
85
|
+
/** Next-visit toast. */
|
|
86
|
+
toastReplied: string;
|
|
87
|
+
toastFixed: string;
|
|
88
|
+
view: string;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Resolve a BCP-47 tag (`ja-JP`, `es-419`) to a supported locale; English otherwise. */
|
|
92
|
+
declare function resolveReporterLocale(tag: string | null | undefined): ReporterLocale;
|
|
93
|
+
/** The full copy table for a locale (unknown tags fall back to English). */
|
|
94
|
+
declare function reporterCopy(locale?: string): ReporterCopy;
|
|
95
|
+
/** Replace `{name}` placeholders; a missing value leaves an empty string. */
|
|
96
|
+
declare function fillReporterTemplate(template: string, params?: Record<string, string | number | null | undefined>): string;
|
|
97
|
+
/** Fields of a reporter-list row `reporterStatus` reads. All but `status` are optional. */
|
|
98
|
+
interface ReporterStatusInput {
|
|
99
|
+
status: string;
|
|
100
|
+
/** True (or a timestamp) while the developer waits for the reporter. */
|
|
101
|
+
awaiting_reporter?: boolean | null;
|
|
102
|
+
awaiting_reporter_at?: string | null;
|
|
103
|
+
fixed_in_version?: string | null;
|
|
104
|
+
closed_reason?: string | null;
|
|
105
|
+
/** Bucketed duplicate count; never a raw number. */
|
|
106
|
+
group_bucket?: 'none' | 'few' | 'many' | null;
|
|
107
|
+
/** `user_category`; "Feature request" / "idea" selects the idea labels. */
|
|
108
|
+
user_category?: string | null;
|
|
109
|
+
}
|
|
110
|
+
interface ReporterStatusView {
|
|
111
|
+
key: ReporterStatusKey;
|
|
112
|
+
label: string;
|
|
113
|
+
tone: ReporterTone;
|
|
114
|
+
detail: string;
|
|
115
|
+
/** Show the Yes / Not yet verification buttons. */
|
|
116
|
+
canVerify: boolean;
|
|
117
|
+
/** "You and a few others reported this", or null. */
|
|
118
|
+
othersNote: string | null;
|
|
119
|
+
/** `closed_reason = 'spam'`: hide the report from the reporter entirely. */
|
|
120
|
+
hidden: boolean;
|
|
121
|
+
}
|
|
122
|
+
/** True when the row is a feature request rather than a bug. */
|
|
123
|
+
declare function isReporterIdea(input: Pick<ReporterStatusInput, 'user_category'>): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* The end-user view of a report. Overlays are checked before the base
|
|
126
|
+
* status: "Waiting on you" wins for any open report, and the duplicate-group
|
|
127
|
+
* note is added on top of whatever the base state is.
|
|
128
|
+
*/
|
|
129
|
+
declare function reporterStatus(input: ReporterStatusInput, locale?: string): ReporterStatusView;
|
|
130
|
+
/** Parameters a timeline template may interpolate. */
|
|
131
|
+
interface ReporterTimelineParams {
|
|
132
|
+
/** Verbatim developer text for `comment` and `info_requested`; the reporter's own for `reporter_comment`. */
|
|
133
|
+
text?: string | null;
|
|
134
|
+
version?: string | null;
|
|
135
|
+
closed_reason?: string | null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Render one timeline entry. Pipeline kinds always come from the template for
|
|
139
|
+
* their kind; only the developer's own words (`comment`, `info_requested`) are
|
|
140
|
+
* passed through, verbatim.
|
|
141
|
+
*/
|
|
142
|
+
declare function reporterTimelineText(kind: ReporterTimelineKind, params?: ReporterTimelineParams, locale?: string): string;
|
|
143
|
+
/** Reporter-facing label for a category chip. */
|
|
144
|
+
declare function reporterCategoryLabel(category: ReporterCategory, locale?: string): string;
|
|
145
|
+
/** A few words are enough; an attachment speaks for itself (§1.1). */
|
|
146
|
+
declare const REPORTER_MIN_DESCRIPTION = 8;
|
|
147
|
+
/** Characters Send needs: `min` (default 8), or 0 with a screenshot / element attached. */
|
|
148
|
+
declare function reporterRequiredLength(min: number | undefined, hasAttachment: boolean): number;
|
|
149
|
+
/** Whether Send is enabled: some text or an attachment, and enough words. */
|
|
150
|
+
declare function reporterCanSend(text: string, hasAttachment: boolean, min?: number): boolean;
|
|
151
|
+
/** Wire category for an optional chip: none → `other` (triage sets the type); Idea → a feature request. */
|
|
152
|
+
declare function reporterChipToReport(chip: ReporterCategory | null): {
|
|
153
|
+
category: 'bug' | 'slow' | 'visual' | 'confusing' | 'other';
|
|
154
|
+
userCategory?: string;
|
|
155
|
+
};
|
|
156
|
+
/** One entry of `GET /v1/reporter/reports/:id` → `timeline` (subset the widgets read). */
|
|
157
|
+
interface ReporterTimelineEntry {
|
|
158
|
+
kind: string;
|
|
159
|
+
text: string;
|
|
160
|
+
/** Developer- or project-written text: show `text` as is. */
|
|
161
|
+
custom?: boolean;
|
|
162
|
+
body?: string;
|
|
163
|
+
version?: string;
|
|
164
|
+
closed_reason?: string;
|
|
165
|
+
}
|
|
166
|
+
/** True for the people talking (developer / reporter), false for pipeline events. */
|
|
167
|
+
declare function isReporterConversation(entry: Pick<ReporterTimelineEntry, 'kind'>): boolean;
|
|
168
|
+
/** Text for one timeline entry in the reporter's locale; custom wording is shown as is. */
|
|
169
|
+
declare function reporterTimelineEntryText(entry: ReporterTimelineEntry, locale?: string): string;
|
|
170
|
+
declare const REPORTER_TOAST_INTERVAL_MS: number;
|
|
171
|
+
/** The next-visit toast: one per session and at most one a day, only with something unread (§4.2). */
|
|
172
|
+
declare function reporterShouldShowToast(input: {
|
|
173
|
+
enabled: boolean;
|
|
174
|
+
unreadTotal: number;
|
|
175
|
+
shownThisSession: boolean;
|
|
176
|
+
lastShownAt: number | null;
|
|
177
|
+
now: number;
|
|
178
|
+
}): boolean;
|
|
179
|
+
/** "The developer replied…", "Your bug is fixed", or "3 updates on your reports". */
|
|
180
|
+
declare function reporterToastMessage(updates: {
|
|
181
|
+
unread_total: number;
|
|
182
|
+
latest: Array<{
|
|
183
|
+
kind: string | null;
|
|
184
|
+
}>;
|
|
185
|
+
}, locale?: string): string;
|
|
186
|
+
/** A typo screen for the email opt-in box; the server validates the address. */
|
|
187
|
+
declare function isPlausibleReporterEmail(raw: string): boolean;
|
|
188
|
+
|
|
189
|
+
export { REPORTER_CANONICAL_STATUSES, REPORTER_CATEGORIES, REPORTER_CLOSED_REASONS, REPORTER_LOCALES, REPORTER_MIN_DESCRIPTION, REPORTER_TIMELINE_KINDS, REPORTER_TOAST_INTERVAL_MS, type ReporterCanonicalStatus, type ReporterCategory, type ReporterClosedReason, type ReporterCopy, type ReporterLocale, type ReporterStatusInput, type ReporterStatusKey, type ReporterStatusView, type ReporterTimelineEntry, type ReporterTimelineKind, type ReporterTimelineParams, type ReporterTone, fillReporterTemplate, isPlausibleReporterEmail, isReporterConversation, isReporterIdea, reporterCanSend, reporterCategoryLabel, reporterChipToReport, reporterCopy, reporterRequiredLength, reporterShouldShowToast, reporterStatus, reporterTimelineEntryText, reporterTimelineText, reporterToastMessage, resolveReporterLocale };
|