@shubh90/app-runtime 0.4.1 → 0.5.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.
Files changed (46) hide show
  1. package/dist/auth/core.d.ts +12 -7
  2. package/dist/auth/core.js +9 -11
  3. package/dist/auth/db.js +10 -0
  4. package/dist/auth/index.d.ts +4 -4
  5. package/dist/auth/index.js +6 -6
  6. package/dist/auth/lookup.d.ts +23 -12
  7. package/dist/auth/lookup.js +85 -24
  8. package/dist/auth/plaza.d.ts +30 -10
  9. package/dist/auth/plaza.js +65 -21
  10. package/dist/auth/routes.js +1 -1
  11. package/dist/auth/session.d.ts +3 -2
  12. package/dist/auth/session.js +5 -6
  13. package/dist/chat/index.d.ts +8 -0
  14. package/dist/chat/index.js +107 -0
  15. package/dist/chat/paths.d.ts +2 -0
  16. package/dist/chat/paths.js +2 -0
  17. package/dist/chat/server.d.ts +16 -0
  18. package/dist/chat/server.js +167 -0
  19. package/dist/chat/thread.d.ts +27 -0
  20. package/dist/chat/thread.js +59 -0
  21. package/dist/chat/ui/activity.d.ts +12 -0
  22. package/dist/chat/ui/activity.js +57 -0
  23. package/dist/chat/ui/attachments.d.ts +9 -0
  24. package/dist/chat/ui/attachments.js +50 -0
  25. package/dist/chat/ui/index.d.ts +5 -0
  26. package/dist/chat/ui/index.js +6 -0
  27. package/dist/chat/ui/message-body.d.ts +8 -0
  28. package/dist/chat/ui/message-body.js +57 -0
  29. package/dist/chat/ui/styles.css +109 -0
  30. package/dist/chat/ui/styles.d.ts +16 -0
  31. package/dist/chat/ui/styles.js +126 -0
  32. package/dist/chat/ui/types.d.ts +47 -0
  33. package/dist/chat/ui/types.js +1 -0
  34. package/dist/chat/widget/api.d.ts +34 -0
  35. package/dist/chat/widget/api.js +112 -0
  36. package/dist/chat/widget/app.d.ts +11 -0
  37. package/dist/chat/widget/app.js +304 -0
  38. package/dist/chat/widget/hooks.d.ts +86 -0
  39. package/dist/chat/widget/hooks.js +312 -0
  40. package/dist/chat/widget/icons.d.ts +13 -0
  41. package/dist/chat/widget/icons.js +13 -0
  42. package/dist/chat/widget/styles.d.ts +1 -0
  43. package/dist/chat/widget/styles.js +233 -0
  44. package/dist/chat/widget/thread.d.ts +33 -0
  45. package/dist/chat/widget/thread.js +27 -0
  46. package/package.json +50 -11
@@ -0,0 +1,109 @@
1
+ .mii-md { min-width: 0; overflow-wrap: anywhere; font-size: var(--mii-md-font-size, inherit); line-height: var(--mii-md-line-height, inherit); }
2
+ .mii-md p { margin: .5rem 0; white-space: pre-wrap; }
3
+ .mii-md :is(p, ul, ol, h1, h2, h3, blockquote, hr, .mii-code, .mii-table):first-child { margin-top: 0; }
4
+ .mii-md :is(p, ul, ol, h1, h2, h3, blockquote, hr, .mii-code, .mii-table):last-child { margin-bottom: 0; }
5
+ .mii-md a { font-weight: 500; color: var(--mii-link); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--mii-link) 40%, transparent); text-underline-offset: 2px; }
6
+ .mii-md a:hover { text-decoration-color: var(--mii-link); }
7
+ .mii-md blockquote { margin: .75rem 0; padding-left: .75rem; border-left: 2px solid color-mix(in srgb, var(--mii-link) 40%, transparent); color: var(--mii-ink-lo); }
8
+ .mii-md code { border-radius: 4px; background: var(--mii-code-bg); padding: .125rem .375rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .85em; color: var(--mii-ink); }
9
+ .mii-md h1, .mii-md h2 { margin: 1rem 0 .5rem; font-weight: 600; line-height: 1.25; }
10
+ .mii-md h1 { font-size: 1.125rem; }
11
+ .mii-md h2 { font-size: 1rem; }
12
+ .mii-md h3 { margin: .75rem 0 .375rem; font-size: .875rem; font-weight: 600; }
13
+ .mii-md hr { margin: 1rem 0; border: 0; border-top: 1px solid var(--mii-line); }
14
+ .mii-md ul, .mii-md ol { margin: .5rem 0 .5rem 1.25rem; padding: 0; }
15
+ .mii-md ul { list-style: disc; }
16
+ .mii-md ol { list-style: decimal; }
17
+ .mii-md ul.contains-task-list { margin-left: 0; list-style: none; }
18
+ .mii-md li { margin: .25rem 0; padding-left: .125rem; }
19
+ .mii-md li::marker { color: var(--mii-ink-lo); }
20
+
21
+ .mii-code { margin: .75rem 0; overflow: hidden; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface); text-align: left; box-shadow: 0 1px 2px rgba(0,0,0,.05); }
22
+ .mii-code-head { display: flex; height: 2.25rem; align-items: center; justify-content: space-between; padding: 0 .75rem; border-bottom: 1px solid var(--mii-line); background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); }
23
+ .mii-code-language { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; font-weight: 500; letter-spacing: .025em; text-transform: uppercase; color: var(--mii-ink-lo); }
24
+ .mii-code-copy { display: inline-flex; height: 1.75rem; align-items: center; gap: .375rem; padding: 0 .5rem; border: 0; border-radius: 6px; background: transparent; font: inherit; font-size: .75rem; color: var(--mii-ink-lo); cursor: pointer; }
25
+ .mii-code-copy:hover { background: var(--mii-surface); color: var(--mii-ink); }
26
+ .mii-md .mii-code pre { margin: 0; max-width: 100%; overflow-x: auto; padding: .75rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .75rem; line-height: 1.25rem; color: var(--mii-ink); overflow-wrap: normal; white-space: pre; }
27
+ .mii-md .mii-code pre code { background: none; padding: 0; border-radius: 0; font-size: inherit; }
28
+
29
+ .mii-table { margin: .75rem 0; max-width: 100%; overflow-x: auto; border: 1px solid var(--mii-line); border-radius: 6px; }
30
+ .mii-table table { min-width: 100%; border-collapse: collapse; text-align: left; font-size: var(--mii-table-font-size, inherit); }
31
+ .mii-table tbody tr + tr { border-top: 1px solid var(--mii-line); }
32
+ .mii-table tr:hover { background: var(--mii-surface-2); }
33
+ .mii-table th, .mii-table td { min-width: 4.5rem; padding: .5rem .75rem; color: var(--mii-ink); }
34
+ .mii-table th { border-bottom: 1px solid var(--mii-line); background: color-mix(in srgb, var(--mii-surface-2) 80%, transparent); font-weight: 600; }
35
+ .mii-table td { max-width: 20rem; vertical-align: top; line-height: 1.25rem; }
36
+
37
+ .mii-md .hljs-comment, .mii-md .hljs-quote { font-style: italic; color: var(--mii-ink-lo); }
38
+ .mii-md :is(.hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-type) { color: var(--mii-code-keyword); }
39
+ .mii-md :is(.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute) { color: var(--mii-code-string); }
40
+ .mii-md :is(.hljs-number, .hljs-symbol, .hljs-bullet, .hljs-variable, .hljs-template-variable) { color: var(--mii-code-number); }
41
+ .mii-md :is(.hljs-title, .hljs-section, .hljs-name, .hljs-selector-id, .hljs-selector-class, .hljs-function) { color: var(--mii-code-title); }
42
+ .mii-md :is(.hljs-built_in, .hljs-doctag, .hljs-meta, .hljs-property) { color: var(--mii-code-builtin); }
43
+ .mii-md .hljs-deletion { color: var(--mii-danger); }
44
+ .mii-md .hljs-emphasis { font-style: italic; }
45
+ .mii-md .hljs-strong { font-weight: 600; }
46
+
47
+ .mii-attachments { display: flex; flex-direction: column; align-items: flex-start; gap: .5rem; }
48
+ .mii-attachments[data-align="end"] { align-items: flex-end; }
49
+ .mii-images { display: grid; grid-template-columns: minmax(0, 1fr); gap: .375rem; max-width: var(--mii-attachment-width, 24rem); }
50
+ .mii-images[data-count="many"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
51
+ .mii-image { display: block; padding: 0; overflow: hidden; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface-2); cursor: zoom-in; transition: opacity 110ms; }
52
+ .mii-image:hover { opacity: .9; }
53
+ .mii-image img { display: block; width: 100%; height: 100%; max-height: 15rem; object-fit: cover; }
54
+ .mii-video { display: block; max-width: var(--mii-attachment-width, 24rem); max-height: 18rem; border: 1px solid var(--mii-line); border-radius: 6px; }
55
+ .mii-file { display: flex; align-items: center; gap: .5rem; max-width: var(--mii-attachment-width, 24rem); padding: .5rem .75rem; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface-2); font-size: .875em; color: var(--mii-ink); text-decoration: none; }
56
+ .mii-file:hover { background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); }
57
+ .mii-file svg { flex-shrink: 0; color: var(--mii-ink-lo); }
58
+ .mii-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
59
+ .mii-file-size { flex-shrink: 0; margin-left: auto; padding-left: .25rem; font-size: .875em; color: var(--mii-ink-lo); }
60
+ .mii-lightbox { outline: none; position: fixed; inset: 0; z-index: 2147483647; display: flex; align-items: center; justify-content: center; padding: 1.5rem; background: rgba(0,0,0,.8); }
61
+ .mii-lightbox img { max-width: 100%; max-height: 100%; border-radius: 6px; object-fit: contain; }
62
+ .mii-lightbox-close { position: absolute; top: 1rem; right: 1rem; display: flex; width: 2.5rem; height: 2.5rem; align-items: center; justify-content: center; border: 0; border-radius: 50%; background: rgba(255,255,255,.1); color: #fff; cursor: pointer; }
63
+ .mii-lightbox-close:hover { background: rgba(255,255,255,.2); }
64
+
65
+ .mii-activity { width: 100%; max-width: 30rem; margin: 0 auto; padding: .375rem .25rem; }
66
+ .mii-activity p { margin: 0; }
67
+ .mii-activity-head { display: flex; min-height: 1.75rem; align-items: center; gap: .5rem; font-size: .75rem; }
68
+ .mii-activity-mark { display: grid; width: 1.25rem; height: 1.25rem; flex-shrink: 0; place-items: center; border-radius: 50%; background: var(--mii-surface-2); color: var(--mii-ink-lo); box-shadow: 0 0 0 1px var(--mii-line); }
69
+ .mii-activity-mark[data-status="running"] { background: color-mix(in srgb, var(--mii-running) 10%, transparent); color: var(--mii-running); box-shadow: none; }
70
+ .mii-activity-toggle, .mii-activity-title { display: flex; min-width: 0; flex: 1; align-items: center; gap: .5rem; padding: .25rem 0; color: var(--mii-ink-mid); }
71
+ .mii-activity-toggle { border: 0; border-radius: 6px; background: transparent; font: inherit; text-align: left; cursor: pointer; transition: color 110ms; }
72
+ .mii-activity-toggle:hover { color: var(--mii-ink); }
73
+ .mii-activity-agent { flex-shrink: 0; font-weight: 500; color: var(--mii-ink); }
74
+ .mii-activity-label { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
75
+ .mii-activity-details { display: flex; flex-shrink: 0; align-items: center; gap: .125rem; font-size: .6875rem; font-weight: 500; color: var(--mii-ink-lo); }
76
+ .mii-activity-toggle:hover .mii-activity-details { color: var(--mii-ink-mid); }
77
+ .mii-steps { position: relative; display: flex; flex-direction: column; gap: .125rem; margin: .125rem 0 0 .625rem; padding: .125rem 0 .125rem 1rem; border-left: 1px solid var(--mii-line); }
78
+ .mii-steps-hidden { padding-bottom: .125rem; font-size: .6875rem; color: var(--mii-ink-lo); }
79
+ .mii-step { position: relative; display: flex; min-height: 1.5rem; align-items: flex-start; gap: .5rem; padding: .125rem 0; font-size: .75rem; color: var(--mii-ink-mid); }
80
+ .mii-step-glyph { position: absolute; top: .25rem; left: -1.3125rem; display: grid; width: .75rem; height: .75rem; place-items: center; background: var(--mii-activity-ground, var(--mii-surface)); color: var(--mii-ink-lo); }
81
+ .mii-step-text { min-width: 0; flex: 1; }
82
+ .mii-step-text p { overflow-wrap: anywhere; line-height: 1.25rem; }
83
+ .mii-step[data-status="running"] .mii-step-text p { font-weight: 500; color: var(--mii-ink); }
84
+ .mii-step-paths { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .125rem; }
85
+ .mii-step-paths span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: .125rem .375rem; border-radius: 3px; background: var(--mii-surface-2); box-shadow: 0 0 0 1px var(--mii-line); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .625rem; color: var(--mii-ink-lo); }
86
+ .mii-step-pulse { width: .375rem; height: .375rem; flex-shrink: 0; margin-top: .375rem; border-radius: 50%; background: var(--mii-running); animation: mii-pulse 2s cubic-bezier(.4,0,.6,1) infinite; }
87
+ .mii-outcomes { display: flex; flex-direction: column; gap: .25rem; }
88
+ .mii-outcomes[data-spaced="true"] { margin-top: .375rem; }
89
+ .mii-outcome { padding: .5rem .625rem; border-radius: 6px; background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); box-shadow: 0 0 0 1px var(--mii-line); font-size: .75rem; }
90
+ .mii-outcome[data-status="failed"] { background: color-mix(in srgb, var(--mii-danger) 5%, transparent); }
91
+ .mii-outcome-row { display: flex; align-items: flex-start; gap: .5rem; }
92
+ .mii-outcome-mark { display: grid; width: 1.25rem; height: 1.25rem; flex-shrink: 0; place-items: center; margin-top: .125rem; border-radius: 50%; background: var(--mii-surface); box-shadow: 0 0 0 1px var(--mii-line); color: var(--mii-ink-mid); }
93
+ .mii-outcome-summary { min-width: 0; flex: 1; padding-top: .125rem; overflow-wrap: anywhere; font-weight: 500; line-height: 1rem; color: var(--mii-ink-mid); }
94
+ .mii-outcome[data-status="failed"] :is(.mii-outcome-mark, .mii-outcome-summary) { color: var(--mii-danger); }
95
+ .mii-outcome-toggle { flex-shrink: 0; padding: .125rem .25rem; border: 0; border-radius: 3px; background: transparent; font: inherit; font-weight: 500; color: var(--mii-ink-lo); cursor: pointer; }
96
+ .mii-outcome-toggle:hover { color: var(--mii-ink); }
97
+ .mii-outcome-detail { margin: .375rem 0 0 1.75rem; padding-left: .625rem; border-left: 1px solid var(--mii-line); color: var(--mii-ink); }
98
+ .mii-outcome-subject { font-weight: 500; }
99
+ .mii-activity .mii-outcome-body { margin-top: .25rem; white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.25rem; }
100
+ .mii-activity .mii-outcome-attached { margin-top: .375rem; color: var(--mii-ink-lo); }
101
+
102
+ .mii-code-copy:focus-visible, .mii-image:focus-visible, .mii-file:focus-visible, .mii-lightbox-close:focus-visible,
103
+ .mii-activity-toggle:focus-visible, .mii-outcome-toggle:focus-visible { outline: 2px solid var(--mii-link); outline-offset: 2px; }
104
+ .mii-spin { animation: mii-spin 1s linear infinite; }
105
+ @keyframes mii-spin { to { transform: rotate(360deg); } }
106
+ @keyframes mii-pulse { 50% { opacity: .5; } }
107
+ @media (prefers-reduced-motion: reduce) {
108
+ .mii-spin, .mii-step-pulse { animation: none; }
109
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The shared components' stylesheet, published as `chat/ui.css` too. It owns
3
+ * layout and type; colour comes from the host, which sets these on an
4
+ * ancestor (Plaza from its tokens, the widget from the app's theme):
5
+ *
6
+ * --mii-ink, --mii-ink-mid, --mii-ink-lo text, strong to faint
7
+ * --mii-surface, --mii-surface-2 cards, and the fill inside them
8
+ * --mii-line borders
9
+ * --mii-link, --mii-running, --mii-danger accents
10
+ * --mii-code-bg inline code
11
+ * --mii-code-keyword, -string, -number, -title, -builtin highlighting
12
+ *
13
+ * Optional: --mii-md-font-size, --mii-md-line-height, --mii-table-font-size,
14
+ * --mii-attachment-width, --mii-activity-ground (behind the step glyphs).
15
+ */
16
+ export declare const CHAT_UI_CSS = "\n.mii-md { min-width: 0; overflow-wrap: anywhere; font-size: var(--mii-md-font-size, inherit); line-height: var(--mii-md-line-height, inherit); }\n.mii-md p { margin: .5rem 0; white-space: pre-wrap; }\n.mii-md :is(p, ul, ol, h1, h2, h3, blockquote, hr, .mii-code, .mii-table):first-child { margin-top: 0; }\n.mii-md :is(p, ul, ol, h1, h2, h3, blockquote, hr, .mii-code, .mii-table):last-child { margin-bottom: 0; }\n.mii-md a { font-weight: 500; color: var(--mii-link); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--mii-link) 40%, transparent); text-underline-offset: 2px; }\n.mii-md a:hover { text-decoration-color: var(--mii-link); }\n.mii-md blockquote { margin: .75rem 0; padding-left: .75rem; border-left: 2px solid color-mix(in srgb, var(--mii-link) 40%, transparent); color: var(--mii-ink-lo); }\n.mii-md code { border-radius: 4px; background: var(--mii-code-bg); padding: .125rem .375rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .85em; color: var(--mii-ink); }\n.mii-md h1, .mii-md h2 { margin: 1rem 0 .5rem; font-weight: 600; line-height: 1.25; }\n.mii-md h1 { font-size: 1.125rem; }\n.mii-md h2 { font-size: 1rem; }\n.mii-md h3 { margin: .75rem 0 .375rem; font-size: .875rem; font-weight: 600; }\n.mii-md hr { margin: 1rem 0; border: 0; border-top: 1px solid var(--mii-line); }\n.mii-md ul, .mii-md ol { margin: .5rem 0 .5rem 1.25rem; padding: 0; }\n.mii-md ul { list-style: disc; }\n.mii-md ol { list-style: decimal; }\n.mii-md ul.contains-task-list { margin-left: 0; list-style: none; }\n.mii-md li { margin: .25rem 0; padding-left: .125rem; }\n.mii-md li::marker { color: var(--mii-ink-lo); }\n\n.mii-code { margin: .75rem 0; overflow: hidden; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface); text-align: left; box-shadow: 0 1px 2px rgba(0,0,0,.05); }\n.mii-code-head { display: flex; height: 2.25rem; align-items: center; justify-content: space-between; padding: 0 .75rem; border-bottom: 1px solid var(--mii-line); background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); }\n.mii-code-language { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; font-weight: 500; letter-spacing: .025em; text-transform: uppercase; color: var(--mii-ink-lo); }\n.mii-code-copy { display: inline-flex; height: 1.75rem; align-items: center; gap: .375rem; padding: 0 .5rem; border: 0; border-radius: 6px; background: transparent; font: inherit; font-size: .75rem; color: var(--mii-ink-lo); cursor: pointer; }\n.mii-code-copy:hover { background: var(--mii-surface); color: var(--mii-ink); }\n.mii-md .mii-code pre { margin: 0; max-width: 100%; overflow-x: auto; padding: .75rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .75rem; line-height: 1.25rem; color: var(--mii-ink); overflow-wrap: normal; white-space: pre; }\n.mii-md .mii-code pre code { background: none; padding: 0; border-radius: 0; font-size: inherit; }\n\n.mii-table { margin: .75rem 0; max-width: 100%; overflow-x: auto; border: 1px solid var(--mii-line); border-radius: 6px; }\n.mii-table table { min-width: 100%; border-collapse: collapse; text-align: left; font-size: var(--mii-table-font-size, inherit); }\n.mii-table tbody tr + tr { border-top: 1px solid var(--mii-line); }\n.mii-table tr:hover { background: var(--mii-surface-2); }\n.mii-table th, .mii-table td { min-width: 4.5rem; padding: .5rem .75rem; color: var(--mii-ink); }\n.mii-table th { border-bottom: 1px solid var(--mii-line); background: color-mix(in srgb, var(--mii-surface-2) 80%, transparent); font-weight: 600; }\n.mii-table td { max-width: 20rem; vertical-align: top; line-height: 1.25rem; }\n\n.mii-md .hljs-comment, .mii-md .hljs-quote { font-style: italic; color: var(--mii-ink-lo); }\n.mii-md :is(.hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-type) { color: var(--mii-code-keyword); }\n.mii-md :is(.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute) { color: var(--mii-code-string); }\n.mii-md :is(.hljs-number, .hljs-symbol, .hljs-bullet, .hljs-variable, .hljs-template-variable) { color: var(--mii-code-number); }\n.mii-md :is(.hljs-title, .hljs-section, .hljs-name, .hljs-selector-id, .hljs-selector-class, .hljs-function) { color: var(--mii-code-title); }\n.mii-md :is(.hljs-built_in, .hljs-doctag, .hljs-meta, .hljs-property) { color: var(--mii-code-builtin); }\n.mii-md .hljs-deletion { color: var(--mii-danger); }\n.mii-md .hljs-emphasis { font-style: italic; }\n.mii-md .hljs-strong { font-weight: 600; }\n\n.mii-attachments { display: flex; flex-direction: column; align-items: flex-start; gap: .5rem; }\n.mii-attachments[data-align=\"end\"] { align-items: flex-end; }\n.mii-images { display: grid; grid-template-columns: minmax(0, 1fr); gap: .375rem; max-width: var(--mii-attachment-width, 24rem); }\n.mii-images[data-count=\"many\"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n.mii-image { display: block; padding: 0; overflow: hidden; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface-2); cursor: zoom-in; transition: opacity 110ms; }\n.mii-image:hover { opacity: .9; }\n.mii-image img { display: block; width: 100%; height: 100%; max-height: 15rem; object-fit: cover; }\n.mii-video { display: block; max-width: var(--mii-attachment-width, 24rem); max-height: 18rem; border: 1px solid var(--mii-line); border-radius: 6px; }\n.mii-file { display: flex; align-items: center; gap: .5rem; max-width: var(--mii-attachment-width, 24rem); padding: .5rem .75rem; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface-2); font-size: .875em; color: var(--mii-ink); text-decoration: none; }\n.mii-file:hover { background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); }\n.mii-file svg { flex-shrink: 0; color: var(--mii-ink-lo); }\n.mii-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.mii-file-size { flex-shrink: 0; margin-left: auto; padding-left: .25rem; font-size: .875em; color: var(--mii-ink-lo); }\n.mii-lightbox { outline: none; position: fixed; inset: 0; z-index: 2147483647; display: flex; align-items: center; justify-content: center; padding: 1.5rem; background: rgba(0,0,0,.8); }\n.mii-lightbox img { max-width: 100%; max-height: 100%; border-radius: 6px; object-fit: contain; }\n.mii-lightbox-close { position: absolute; top: 1rem; right: 1rem; display: flex; width: 2.5rem; height: 2.5rem; align-items: center; justify-content: center; border: 0; border-radius: 50%; background: rgba(255,255,255,.1); color: #fff; cursor: pointer; }\n.mii-lightbox-close:hover { background: rgba(255,255,255,.2); }\n\n.mii-activity { width: 100%; max-width: 30rem; margin: 0 auto; padding: .375rem .25rem; }\n.mii-activity p { margin: 0; }\n.mii-activity-head { display: flex; min-height: 1.75rem; align-items: center; gap: .5rem; font-size: .75rem; }\n.mii-activity-mark { display: grid; width: 1.25rem; height: 1.25rem; flex-shrink: 0; place-items: center; border-radius: 50%; background: var(--mii-surface-2); color: var(--mii-ink-lo); box-shadow: 0 0 0 1px var(--mii-line); }\n.mii-activity-mark[data-status=\"running\"] { background: color-mix(in srgb, var(--mii-running) 10%, transparent); color: var(--mii-running); box-shadow: none; }\n.mii-activity-toggle, .mii-activity-title { display: flex; min-width: 0; flex: 1; align-items: center; gap: .5rem; padding: .25rem 0; color: var(--mii-ink-mid); }\n.mii-activity-toggle { border: 0; border-radius: 6px; background: transparent; font: inherit; text-align: left; cursor: pointer; transition: color 110ms; }\n.mii-activity-toggle:hover { color: var(--mii-ink); }\n.mii-activity-agent { flex-shrink: 0; font-weight: 500; color: var(--mii-ink); }\n.mii-activity-label { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }\n.mii-activity-details { display: flex; flex-shrink: 0; align-items: center; gap: .125rem; font-size: .6875rem; font-weight: 500; color: var(--mii-ink-lo); }\n.mii-activity-toggle:hover .mii-activity-details { color: var(--mii-ink-mid); }\n.mii-steps { position: relative; display: flex; flex-direction: column; gap: .125rem; margin: .125rem 0 0 .625rem; padding: .125rem 0 .125rem 1rem; border-left: 1px solid var(--mii-line); }\n.mii-steps-hidden { padding-bottom: .125rem; font-size: .6875rem; color: var(--mii-ink-lo); }\n.mii-step { position: relative; display: flex; min-height: 1.5rem; align-items: flex-start; gap: .5rem; padding: .125rem 0; font-size: .75rem; color: var(--mii-ink-mid); }\n.mii-step-glyph { position: absolute; top: .25rem; left: -1.3125rem; display: grid; width: .75rem; height: .75rem; place-items: center; background: var(--mii-activity-ground, var(--mii-surface)); color: var(--mii-ink-lo); }\n.mii-step-text { min-width: 0; flex: 1; }\n.mii-step-text p { overflow-wrap: anywhere; line-height: 1.25rem; }\n.mii-step[data-status=\"running\"] .mii-step-text p { font-weight: 500; color: var(--mii-ink); }\n.mii-step-paths { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .125rem; }\n.mii-step-paths span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: .125rem .375rem; border-radius: 3px; background: var(--mii-surface-2); box-shadow: 0 0 0 1px var(--mii-line); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .625rem; color: var(--mii-ink-lo); }\n.mii-step-pulse { width: .375rem; height: .375rem; flex-shrink: 0; margin-top: .375rem; border-radius: 50%; background: var(--mii-running); animation: mii-pulse 2s cubic-bezier(.4,0,.6,1) infinite; }\n.mii-outcomes { display: flex; flex-direction: column; gap: .25rem; }\n.mii-outcomes[data-spaced=\"true\"] { margin-top: .375rem; }\n.mii-outcome { padding: .5rem .625rem; border-radius: 6px; background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); box-shadow: 0 0 0 1px var(--mii-line); font-size: .75rem; }\n.mii-outcome[data-status=\"failed\"] { background: color-mix(in srgb, var(--mii-danger) 5%, transparent); }\n.mii-outcome-row { display: flex; align-items: flex-start; gap: .5rem; }\n.mii-outcome-mark { display: grid; width: 1.25rem; height: 1.25rem; flex-shrink: 0; place-items: center; margin-top: .125rem; border-radius: 50%; background: var(--mii-surface); box-shadow: 0 0 0 1px var(--mii-line); color: var(--mii-ink-mid); }\n.mii-outcome-summary { min-width: 0; flex: 1; padding-top: .125rem; overflow-wrap: anywhere; font-weight: 500; line-height: 1rem; color: var(--mii-ink-mid); }\n.mii-outcome[data-status=\"failed\"] :is(.mii-outcome-mark, .mii-outcome-summary) { color: var(--mii-danger); }\n.mii-outcome-toggle { flex-shrink: 0; padding: .125rem .25rem; border: 0; border-radius: 3px; background: transparent; font: inherit; font-weight: 500; color: var(--mii-ink-lo); cursor: pointer; }\n.mii-outcome-toggle:hover { color: var(--mii-ink); }\n.mii-outcome-detail { margin: .375rem 0 0 1.75rem; padding-left: .625rem; border-left: 1px solid var(--mii-line); color: var(--mii-ink); }\n.mii-outcome-subject { font-weight: 500; }\n.mii-activity .mii-outcome-body { margin-top: .25rem; white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.25rem; }\n.mii-activity .mii-outcome-attached { margin-top: .375rem; color: var(--mii-ink-lo); }\n\n.mii-code-copy:focus-visible, .mii-image:focus-visible, .mii-file:focus-visible, .mii-lightbox-close:focus-visible,\n.mii-activity-toggle:focus-visible, .mii-outcome-toggle:focus-visible { outline: 2px solid var(--mii-link); outline-offset: 2px; }\n.mii-spin { animation: mii-spin 1s linear infinite; }\n@keyframes mii-spin { to { transform: rotate(360deg); } }\n@keyframes mii-pulse { 50% { opacity: .5; } }\n@media (prefers-reduced-motion: reduce) {\n .mii-spin, .mii-step-pulse { animation: none; }\n}\n";
@@ -0,0 +1,126 @@
1
+ /**
2
+ * The shared components' stylesheet, published as `chat/ui.css` too. It owns
3
+ * layout and type; colour comes from the host, which sets these on an
4
+ * ancestor (Plaza from its tokens, the widget from the app's theme):
5
+ *
6
+ * --mii-ink, --mii-ink-mid, --mii-ink-lo text, strong to faint
7
+ * --mii-surface, --mii-surface-2 cards, and the fill inside them
8
+ * --mii-line borders
9
+ * --mii-link, --mii-running, --mii-danger accents
10
+ * --mii-code-bg inline code
11
+ * --mii-code-keyword, -string, -number, -title, -builtin highlighting
12
+ *
13
+ * Optional: --mii-md-font-size, --mii-md-line-height, --mii-table-font-size,
14
+ * --mii-attachment-width, --mii-activity-ground (behind the step glyphs).
15
+ */
16
+ export const CHAT_UI_CSS = `
17
+ .mii-md { min-width: 0; overflow-wrap: anywhere; font-size: var(--mii-md-font-size, inherit); line-height: var(--mii-md-line-height, inherit); }
18
+ .mii-md p { margin: .5rem 0; white-space: pre-wrap; }
19
+ .mii-md :is(p, ul, ol, h1, h2, h3, blockquote, hr, .mii-code, .mii-table):first-child { margin-top: 0; }
20
+ .mii-md :is(p, ul, ol, h1, h2, h3, blockquote, hr, .mii-code, .mii-table):last-child { margin-bottom: 0; }
21
+ .mii-md a { font-weight: 500; color: var(--mii-link); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--mii-link) 40%, transparent); text-underline-offset: 2px; }
22
+ .mii-md a:hover { text-decoration-color: var(--mii-link); }
23
+ .mii-md blockquote { margin: .75rem 0; padding-left: .75rem; border-left: 2px solid color-mix(in srgb, var(--mii-link) 40%, transparent); color: var(--mii-ink-lo); }
24
+ .mii-md code { border-radius: 4px; background: var(--mii-code-bg); padding: .125rem .375rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .85em; color: var(--mii-ink); }
25
+ .mii-md h1, .mii-md h2 { margin: 1rem 0 .5rem; font-weight: 600; line-height: 1.25; }
26
+ .mii-md h1 { font-size: 1.125rem; }
27
+ .mii-md h2 { font-size: 1rem; }
28
+ .mii-md h3 { margin: .75rem 0 .375rem; font-size: .875rem; font-weight: 600; }
29
+ .mii-md hr { margin: 1rem 0; border: 0; border-top: 1px solid var(--mii-line); }
30
+ .mii-md ul, .mii-md ol { margin: .5rem 0 .5rem 1.25rem; padding: 0; }
31
+ .mii-md ul { list-style: disc; }
32
+ .mii-md ol { list-style: decimal; }
33
+ .mii-md ul.contains-task-list { margin-left: 0; list-style: none; }
34
+ .mii-md li { margin: .25rem 0; padding-left: .125rem; }
35
+ .mii-md li::marker { color: var(--mii-ink-lo); }
36
+
37
+ .mii-code { margin: .75rem 0; overflow: hidden; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface); text-align: left; box-shadow: 0 1px 2px rgba(0,0,0,.05); }
38
+ .mii-code-head { display: flex; height: 2.25rem; align-items: center; justify-content: space-between; padding: 0 .75rem; border-bottom: 1px solid var(--mii-line); background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); }
39
+ .mii-code-language { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; font-weight: 500; letter-spacing: .025em; text-transform: uppercase; color: var(--mii-ink-lo); }
40
+ .mii-code-copy { display: inline-flex; height: 1.75rem; align-items: center; gap: .375rem; padding: 0 .5rem; border: 0; border-radius: 6px; background: transparent; font: inherit; font-size: .75rem; color: var(--mii-ink-lo); cursor: pointer; }
41
+ .mii-code-copy:hover { background: var(--mii-surface); color: var(--mii-ink); }
42
+ .mii-md .mii-code pre { margin: 0; max-width: 100%; overflow-x: auto; padding: .75rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .75rem; line-height: 1.25rem; color: var(--mii-ink); overflow-wrap: normal; white-space: pre; }
43
+ .mii-md .mii-code pre code { background: none; padding: 0; border-radius: 0; font-size: inherit; }
44
+
45
+ .mii-table { margin: .75rem 0; max-width: 100%; overflow-x: auto; border: 1px solid var(--mii-line); border-radius: 6px; }
46
+ .mii-table table { min-width: 100%; border-collapse: collapse; text-align: left; font-size: var(--mii-table-font-size, inherit); }
47
+ .mii-table tbody tr + tr { border-top: 1px solid var(--mii-line); }
48
+ .mii-table tr:hover { background: var(--mii-surface-2); }
49
+ .mii-table th, .mii-table td { min-width: 4.5rem; padding: .5rem .75rem; color: var(--mii-ink); }
50
+ .mii-table th { border-bottom: 1px solid var(--mii-line); background: color-mix(in srgb, var(--mii-surface-2) 80%, transparent); font-weight: 600; }
51
+ .mii-table td { max-width: 20rem; vertical-align: top; line-height: 1.25rem; }
52
+
53
+ .mii-md .hljs-comment, .mii-md .hljs-quote { font-style: italic; color: var(--mii-ink-lo); }
54
+ .mii-md :is(.hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-type) { color: var(--mii-code-keyword); }
55
+ .mii-md :is(.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute) { color: var(--mii-code-string); }
56
+ .mii-md :is(.hljs-number, .hljs-symbol, .hljs-bullet, .hljs-variable, .hljs-template-variable) { color: var(--mii-code-number); }
57
+ .mii-md :is(.hljs-title, .hljs-section, .hljs-name, .hljs-selector-id, .hljs-selector-class, .hljs-function) { color: var(--mii-code-title); }
58
+ .mii-md :is(.hljs-built_in, .hljs-doctag, .hljs-meta, .hljs-property) { color: var(--mii-code-builtin); }
59
+ .mii-md .hljs-deletion { color: var(--mii-danger); }
60
+ .mii-md .hljs-emphasis { font-style: italic; }
61
+ .mii-md .hljs-strong { font-weight: 600; }
62
+
63
+ .mii-attachments { display: flex; flex-direction: column; align-items: flex-start; gap: .5rem; }
64
+ .mii-attachments[data-align="end"] { align-items: flex-end; }
65
+ .mii-images { display: grid; grid-template-columns: minmax(0, 1fr); gap: .375rem; max-width: var(--mii-attachment-width, 24rem); }
66
+ .mii-images[data-count="many"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
67
+ .mii-image { display: block; padding: 0; overflow: hidden; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface-2); cursor: zoom-in; transition: opacity 110ms; }
68
+ .mii-image:hover { opacity: .9; }
69
+ .mii-image img { display: block; width: 100%; height: 100%; max-height: 15rem; object-fit: cover; }
70
+ .mii-video { display: block; max-width: var(--mii-attachment-width, 24rem); max-height: 18rem; border: 1px solid var(--mii-line); border-radius: 6px; }
71
+ .mii-file { display: flex; align-items: center; gap: .5rem; max-width: var(--mii-attachment-width, 24rem); padding: .5rem .75rem; border: 1px solid var(--mii-line); border-radius: 6px; background: var(--mii-surface-2); font-size: .875em; color: var(--mii-ink); text-decoration: none; }
72
+ .mii-file:hover { background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); }
73
+ .mii-file svg { flex-shrink: 0; color: var(--mii-ink-lo); }
74
+ .mii-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
75
+ .mii-file-size { flex-shrink: 0; margin-left: auto; padding-left: .25rem; font-size: .875em; color: var(--mii-ink-lo); }
76
+ .mii-lightbox { outline: none; position: fixed; inset: 0; z-index: 2147483647; display: flex; align-items: center; justify-content: center; padding: 1.5rem; background: rgba(0,0,0,.8); }
77
+ .mii-lightbox img { max-width: 100%; max-height: 100%; border-radius: 6px; object-fit: contain; }
78
+ .mii-lightbox-close { position: absolute; top: 1rem; right: 1rem; display: flex; width: 2.5rem; height: 2.5rem; align-items: center; justify-content: center; border: 0; border-radius: 50%; background: rgba(255,255,255,.1); color: #fff; cursor: pointer; }
79
+ .mii-lightbox-close:hover { background: rgba(255,255,255,.2); }
80
+
81
+ .mii-activity { width: 100%; max-width: 30rem; margin: 0 auto; padding: .375rem .25rem; }
82
+ .mii-activity p { margin: 0; }
83
+ .mii-activity-head { display: flex; min-height: 1.75rem; align-items: center; gap: .5rem; font-size: .75rem; }
84
+ .mii-activity-mark { display: grid; width: 1.25rem; height: 1.25rem; flex-shrink: 0; place-items: center; border-radius: 50%; background: var(--mii-surface-2); color: var(--mii-ink-lo); box-shadow: 0 0 0 1px var(--mii-line); }
85
+ .mii-activity-mark[data-status="running"] { background: color-mix(in srgb, var(--mii-running) 10%, transparent); color: var(--mii-running); box-shadow: none; }
86
+ .mii-activity-toggle, .mii-activity-title { display: flex; min-width: 0; flex: 1; align-items: center; gap: .5rem; padding: .25rem 0; color: var(--mii-ink-mid); }
87
+ .mii-activity-toggle { border: 0; border-radius: 6px; background: transparent; font: inherit; text-align: left; cursor: pointer; transition: color 110ms; }
88
+ .mii-activity-toggle:hover { color: var(--mii-ink); }
89
+ .mii-activity-agent { flex-shrink: 0; font-weight: 500; color: var(--mii-ink); }
90
+ .mii-activity-label { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
91
+ .mii-activity-details { display: flex; flex-shrink: 0; align-items: center; gap: .125rem; font-size: .6875rem; font-weight: 500; color: var(--mii-ink-lo); }
92
+ .mii-activity-toggle:hover .mii-activity-details { color: var(--mii-ink-mid); }
93
+ .mii-steps { position: relative; display: flex; flex-direction: column; gap: .125rem; margin: .125rem 0 0 .625rem; padding: .125rem 0 .125rem 1rem; border-left: 1px solid var(--mii-line); }
94
+ .mii-steps-hidden { padding-bottom: .125rem; font-size: .6875rem; color: var(--mii-ink-lo); }
95
+ .mii-step { position: relative; display: flex; min-height: 1.5rem; align-items: flex-start; gap: .5rem; padding: .125rem 0; font-size: .75rem; color: var(--mii-ink-mid); }
96
+ .mii-step-glyph { position: absolute; top: .25rem; left: -1.3125rem; display: grid; width: .75rem; height: .75rem; place-items: center; background: var(--mii-activity-ground, var(--mii-surface)); color: var(--mii-ink-lo); }
97
+ .mii-step-text { min-width: 0; flex: 1; }
98
+ .mii-step-text p { overflow-wrap: anywhere; line-height: 1.25rem; }
99
+ .mii-step[data-status="running"] .mii-step-text p { font-weight: 500; color: var(--mii-ink); }
100
+ .mii-step-paths { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .125rem; }
101
+ .mii-step-paths span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: .125rem .375rem; border-radius: 3px; background: var(--mii-surface-2); box-shadow: 0 0 0 1px var(--mii-line); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .625rem; color: var(--mii-ink-lo); }
102
+ .mii-step-pulse { width: .375rem; height: .375rem; flex-shrink: 0; margin-top: .375rem; border-radius: 50%; background: var(--mii-running); animation: mii-pulse 2s cubic-bezier(.4,0,.6,1) infinite; }
103
+ .mii-outcomes { display: flex; flex-direction: column; gap: .25rem; }
104
+ .mii-outcomes[data-spaced="true"] { margin-top: .375rem; }
105
+ .mii-outcome { padding: .5rem .625rem; border-radius: 6px; background: color-mix(in srgb, var(--mii-surface-2) 70%, transparent); box-shadow: 0 0 0 1px var(--mii-line); font-size: .75rem; }
106
+ .mii-outcome[data-status="failed"] { background: color-mix(in srgb, var(--mii-danger) 5%, transparent); }
107
+ .mii-outcome-row { display: flex; align-items: flex-start; gap: .5rem; }
108
+ .mii-outcome-mark { display: grid; width: 1.25rem; height: 1.25rem; flex-shrink: 0; place-items: center; margin-top: .125rem; border-radius: 50%; background: var(--mii-surface); box-shadow: 0 0 0 1px var(--mii-line); color: var(--mii-ink-mid); }
109
+ .mii-outcome-summary { min-width: 0; flex: 1; padding-top: .125rem; overflow-wrap: anywhere; font-weight: 500; line-height: 1rem; color: var(--mii-ink-mid); }
110
+ .mii-outcome[data-status="failed"] :is(.mii-outcome-mark, .mii-outcome-summary) { color: var(--mii-danger); }
111
+ .mii-outcome-toggle { flex-shrink: 0; padding: .125rem .25rem; border: 0; border-radius: 3px; background: transparent; font: inherit; font-weight: 500; color: var(--mii-ink-lo); cursor: pointer; }
112
+ .mii-outcome-toggle:hover { color: var(--mii-ink); }
113
+ .mii-outcome-detail { margin: .375rem 0 0 1.75rem; padding-left: .625rem; border-left: 1px solid var(--mii-line); color: var(--mii-ink); }
114
+ .mii-outcome-subject { font-weight: 500; }
115
+ .mii-activity .mii-outcome-body { margin-top: .25rem; white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.25rem; }
116
+ .mii-activity .mii-outcome-attached { margin-top: .375rem; color: var(--mii-ink-lo); }
117
+
118
+ .mii-code-copy:focus-visible, .mii-image:focus-visible, .mii-file:focus-visible, .mii-lightbox-close:focus-visible,
119
+ .mii-activity-toggle:focus-visible, .mii-outcome-toggle:focus-visible { outline: 2px solid var(--mii-link); outline-offset: 2px; }
120
+ .mii-spin { animation: mii-spin 1s linear infinite; }
121
+ @keyframes mii-spin { to { transform: rotate(360deg); } }
122
+ @keyframes mii-pulse { 50% { opacity: .5; } }
123
+ @media (prefers-reduced-motion: reduce) {
124
+ .mii-spin, .mii-step-pulse { animation: none; }
125
+ }
126
+ `;
@@ -0,0 +1,47 @@
1
+ export type ChatAttachment = {
2
+ readonly url: string;
3
+ readonly type: string;
4
+ readonly name?: string | null;
5
+ readonly sizeBytes?: number | null;
6
+ readonly width?: number | null;
7
+ readonly height?: number | null;
8
+ };
9
+ /** The parts of a step the card draws; Plaza's events carry more. */
10
+ export type ActivityDetail = {
11
+ readonly type: "communication";
12
+ readonly channel: "email" | "text" | "chat";
13
+ readonly subject?: string;
14
+ readonly body?: string;
15
+ readonly attachments: readonly string[];
16
+ } | {
17
+ readonly type: "files";
18
+ readonly paths: readonly string[];
19
+ } | {
20
+ readonly type: "browser";
21
+ readonly action: "navigate" | "inspect" | "interact" | "input" | "tabs" | "capture";
22
+ } | {
23
+ readonly type: "integration" | "task" | "schedule" | "verification" | "web";
24
+ };
25
+ export type ActivityEvent = {
26
+ readonly id: string;
27
+ readonly status: "running" | "completed" | "failed";
28
+ readonly summary: string;
29
+ readonly detail: ActivityDetail;
30
+ };
31
+ /**
32
+ * One agent's work on one message: steps as they happen, outcomes that matter.
33
+ * While it runs, only the latest few steps are shown and the rest are counted;
34
+ * once done, every step is kept behind Details.
35
+ */
36
+ export type ActivityGroup = {
37
+ readonly agentName: string;
38
+ readonly contextLabel: string;
39
+ readonly outcomes: readonly ActivityEvent[];
40
+ } & ({
41
+ readonly status: "running";
42
+ readonly visibleSteps: readonly ActivityEvent[];
43
+ readonly hiddenStepCount: number;
44
+ } | {
45
+ readonly status: "completed";
46
+ readonly steps: readonly ActivityEvent[];
47
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import type { ChatActivity, ChatAgent, ChatAttachment, ChatMessage } from "./thread.js";
2
+ import type { MessageCursor } from "../thread.js";
3
+ export declare class ChatRequestError extends Error {
4
+ readonly status: number;
5
+ readonly code: string;
6
+ constructor(status: number, code: string, message: string);
7
+ }
8
+ export type AgentsResponse = {
9
+ readonly viewerId: string;
10
+ /** In the order a chat offers them: the first is who it opens on. */
11
+ readonly agents: readonly ChatAgent[];
12
+ };
13
+ /** Someone to talk to: at least one agent. */
14
+ export type ChatAgents = {
15
+ readonly viewerId: string;
16
+ readonly agents: readonly [ChatAgent, ...ChatAgent[]];
17
+ };
18
+ export type ThreadResponse = {
19
+ readonly conversationId: string | null;
20
+ /** What the agent is doing about this thread right now, labelled by Plaza. */
21
+ readonly activity: ChatActivity | null;
22
+ readonly messages: readonly ChatMessage[];
23
+ };
24
+ export type OutgoingMessage = {
25
+ readonly body: string;
26
+ readonly attachments: readonly ChatAttachment[];
27
+ readonly pageUrl: string;
28
+ };
29
+ export declare function fetchAgents(): Promise<AgentsResponse>;
30
+ export declare function fetchThread(agentId: string, cursor: MessageCursor | undefined): Promise<ThreadResponse>;
31
+ export declare function avatarUrl(agentId: string): string;
32
+ export declare function sendMessage(agentId: string, message: OutgoingMessage): Promise<ChatMessage>;
33
+ /** Upload one file straight to storage and describe it as an attachment. */
34
+ export declare function uploadFile(file: File): Promise<ChatAttachment>;
@@ -0,0 +1,112 @@
1
+ import { CHAT_BASE_PATH } from "../paths.js";
2
+ // The widget's calls, all to this app's own origin (see ../server.ts).
3
+ export class ChatRequestError extends Error {
4
+ status;
5
+ code;
6
+ constructor(status, code, message) {
7
+ super(message);
8
+ this.status = status;
9
+ this.code = code;
10
+ }
11
+ }
12
+ export function fetchAgents() {
13
+ return call("GET", "/agents");
14
+ }
15
+ export function fetchThread(agentId, cursor) {
16
+ const query = cursor === undefined
17
+ ? ""
18
+ : `?${new URLSearchParams({ after: cursor.updatedAt, afterId: cursor.id }).toString()}`;
19
+ return call("GET", `/agents/${agentId}/messages${query}`);
20
+ }
21
+ export function avatarUrl(agentId) {
22
+ return `${CHAT_BASE_PATH}/agents/${agentId}/avatar`;
23
+ }
24
+ export function sendMessage(agentId, message) {
25
+ return call("POST", `/agents/${agentId}/messages`, message);
26
+ }
27
+ /** Upload one file straight to storage and describe it as an attachment. */
28
+ export async function uploadFile(file) {
29
+ const presigned = await call("POST", "/uploads", {
30
+ fileName: file.name,
31
+ fileType: file.type,
32
+ sizeBytes: file.size
33
+ });
34
+ const form = new FormData();
35
+ for (const [key, value] of Object.entries(presigned.fields)) {
36
+ form.append(key, value);
37
+ }
38
+ form.append("file", file);
39
+ const stored = await fetch(presigned.uploadUrl, { method: "POST", body: form });
40
+ if (!stored.ok) {
41
+ throw new ChatRequestError(stored.status, "upload_failed", "The file couldn't be stored. Try again in a moment.");
42
+ }
43
+ const dimensions = presigned.type.startsWith("image/")
44
+ ? await imageSize(file)
45
+ : null;
46
+ return {
47
+ url: presigned.publicUrl,
48
+ type: presigned.type,
49
+ name: presigned.name,
50
+ sizeBytes: presigned.sizeBytes,
51
+ width: dimensions?.width ?? null,
52
+ height: dimensions?.height ?? null
53
+ };
54
+ }
55
+ async function imageSize(file) {
56
+ try {
57
+ const bitmap = await createImageBitmap(file);
58
+ const size = { width: bitmap.width, height: bitmap.height };
59
+ bitmap.close();
60
+ return size;
61
+ }
62
+ catch {
63
+ // A format the browser cannot decode (HEIC on most) still uploads; the chat
64
+ // just shows it without reserving its shape.
65
+ return null;
66
+ }
67
+ }
68
+ async function call(method, path, body) {
69
+ const response = await fetch(`${CHAT_BASE_PATH}${path}`, {
70
+ method,
71
+ credentials: "same-origin",
72
+ headers: body === undefined ? undefined : { "Content-Type": "application/json" },
73
+ body: body === undefined ? undefined : JSON.stringify(body)
74
+ });
75
+ const text = await response.text();
76
+ if (response.ok) {
77
+ try {
78
+ return JSON.parse(text);
79
+ }
80
+ catch (error) {
81
+ // Something answered in the chat's place, like a page the app serves for
82
+ // any path: the chat's routes are not reachable.
83
+ console.error("mii-chat: the chat answered with something other than JSON", error);
84
+ throw new ChatRequestError(response.status, "not_the_chat", "Couldn't reach the chat. Try again in a moment.");
85
+ }
86
+ }
87
+ const error = errorBody(text);
88
+ throw new ChatRequestError(response.status, error.code, error.detail ?? messageFor(response.status));
89
+ }
90
+ // Plaza answers { error: <sentence>, code? }. Whatever sits in front of the app
91
+ // (a CDN, a dev server) may answer with a page of HTML instead.
92
+ function errorBody(text) {
93
+ let parsed;
94
+ try {
95
+ parsed = JSON.parse(text);
96
+ }
97
+ catch {
98
+ return { code: "error", detail: null };
99
+ }
100
+ const body = parsed;
101
+ return {
102
+ code: typeof body.code === "string" ? body.code : "error",
103
+ detail: typeof body.error === "string" ? body.error : null
104
+ };
105
+ }
106
+ function messageFor(status) {
107
+ if (status === 401)
108
+ return "Sign in again to keep chatting.";
109
+ if (status === 403)
110
+ return "Chat isn't available to you here.";
111
+ return "Couldn't reach the chat. Try again in a moment.";
112
+ }
@@ -0,0 +1,11 @@
1
+ import { type ChatAgents } from "./api.js";
2
+ /** The app's accent pair (null keeps the chat's default), and its theme. */
3
+ export type Brand = {
4
+ readonly brand: string | null;
5
+ readonly foreground: string | null;
6
+ readonly dark: boolean;
7
+ };
8
+ export declare function ChatApp({ agents, brand }: {
9
+ readonly agents: ChatAgents;
10
+ readonly brand: Brand;
11
+ }): import("react").JSX.Element;