@shubh90/app-runtime 0.5.0 → 0.6.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/dist/chat/index.d.ts +12 -0
- package/dist/chat/index.js +25 -0
- package/dist/chat/origins.d.ts +9 -0
- package/dist/chat/origins.js +37 -0
- package/package.json +1 -1
package/dist/chat/index.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import type { Brand } from "./widget/app.js";
|
|
2
2
|
export { CHAT_BASE_PATH } from "./paths.js";
|
|
3
|
+
/**
|
|
4
|
+
* Whether the bubble belongs on this host: the app as people use it, not a
|
|
5
|
+
* draft of it. The pane itself is covered by not mounting when framed; this is
|
|
6
|
+
* for the same draft opened in a tab of its own, which the pane's toolbar does.
|
|
7
|
+
*
|
|
8
|
+
* A draft is a working copy (`wc-<12 hex>.miis.run`) or the instance an agent is
|
|
9
|
+
* editing (`<sandbox>.app.miis.run`). Anything else keeps the bubble, including
|
|
10
|
+
* localhost: guessing wrong should leave a live app with its chat, not take it
|
|
11
|
+
* away. Vercel names a branch preview two ways and only one is recognisable
|
|
12
|
+
* here, which is the acceptable side to be wrong on.
|
|
13
|
+
*/
|
|
14
|
+
export declare function chatBelongsOnHost(hostname: string): boolean;
|
|
3
15
|
export declare function MiiChat({ enabled }: {
|
|
4
16
|
readonly enabled: boolean;
|
|
5
17
|
}): null;
|
package/dist/chat/index.js
CHANGED
|
@@ -19,11 +19,36 @@ import { CHAT_CSS } from "./widget/styles.js";
|
|
|
19
19
|
// someone to talk to, not with every page of the app.
|
|
20
20
|
const ChatApp = lazy(() => import("./widget/app.js").then((module) => ({ default: module.ChatApp })));
|
|
21
21
|
export { CHAT_BASE_PATH } from "./paths.js";
|
|
22
|
+
/**
|
|
23
|
+
* Whether the bubble belongs on this host: the app as people use it, not a
|
|
24
|
+
* draft of it. The pane itself is covered by not mounting when framed; this is
|
|
25
|
+
* for the same draft opened in a tab of its own, which the pane's toolbar does.
|
|
26
|
+
*
|
|
27
|
+
* A draft is a working copy (`wc-<12 hex>.miis.run`) or the instance an agent is
|
|
28
|
+
* editing (`<sandbox>.app.miis.run`). Anything else keeps the bubble, including
|
|
29
|
+
* localhost: guessing wrong should leave a live app with its chat, not take it
|
|
30
|
+
* away. Vercel names a branch preview two ways and only one is recognisable
|
|
31
|
+
* here, which is the acceptable side to be wrong on.
|
|
32
|
+
*/
|
|
33
|
+
export function chatBelongsOnHost(hostname) {
|
|
34
|
+
const host = hostname.toLowerCase();
|
|
35
|
+
const [label = ""] = host.split(".");
|
|
36
|
+
if (/^wc-[0-9a-f]{12}$/.test(label))
|
|
37
|
+
return false;
|
|
38
|
+
if (host.endsWith(".app.miis.run"))
|
|
39
|
+
return false;
|
|
40
|
+
// Qualified, because a bare <project>.vercel.app is a live alias.
|
|
41
|
+
if (host.includes("-git-") && host.endsWith(".vercel.app"))
|
|
42
|
+
return false;
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
22
45
|
export function MiiChat({ enabled }) {
|
|
23
46
|
useEffect(() => {
|
|
24
47
|
// Inside Plaza's App pane, Plaza's own chat is already beside the app.
|
|
25
48
|
if (!enabled || window.self !== window.top)
|
|
26
49
|
return;
|
|
50
|
+
if (!chatBelongsOnHost(window.location.hostname))
|
|
51
|
+
return;
|
|
27
52
|
const host = document.createElement("div");
|
|
28
53
|
host.setAttribute("data-mii-chat", "");
|
|
29
54
|
document.body.appendChild(host);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const MII_CHAT_MEDIA_ORIGINS: readonly string[];
|
|
2
|
+
/**
|
|
3
|
+
* The policy directives chat needs, ready to join into a CSP.
|
|
4
|
+
*
|
|
5
|
+
* Apps compose their own policy; this only says what chat adds to it. Pass the
|
|
6
|
+
* app's own sources for a directive and they are kept — `img-src` in particular
|
|
7
|
+
* usually already carries `data:` and `blob:` for the app's own pictures.
|
|
8
|
+
*/
|
|
9
|
+
export declare function miiChatCspSources(directive: "img-src" | "media-src" | "connect-src", own?: readonly string[]): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// The one place outside this app's own origin that chat touches, for apps that
|
|
2
|
+
// set a Content-Security-Policy.
|
|
3
|
+
//
|
|
4
|
+
// Chat is otherwise same-origin by design: the widget talks to the app's own
|
|
5
|
+
// server, which forwards to Plaza. Files are the exception. mii hands the
|
|
6
|
+
// browser a presigned URL on its media bucket and the browser posts the
|
|
7
|
+
// attachment there itself, and the pictures and video already in a thread are
|
|
8
|
+
// served from the same place. An agent's photo is a redirect from the app's own
|
|
9
|
+
// avatar route to that bucket, which is a connect check rather than an img one
|
|
10
|
+
// because the widget fetches it and renders a blob.
|
|
11
|
+
//
|
|
12
|
+
// So an app with a policy needs the bucket named in three directives:
|
|
13
|
+
//
|
|
14
|
+
// import { MII_CHAT_MEDIA_ORIGINS } from "@shubh90/app-runtime/chat/origins";
|
|
15
|
+
// const media = MII_CHAT_MEDIA_ORIGINS.join(" ");
|
|
16
|
+
// `img-src 'self' data: blob: ${media}`
|
|
17
|
+
// `media-src 'self' ${media}`
|
|
18
|
+
// `connect-src 'self' ${media}`
|
|
19
|
+
//
|
|
20
|
+
// It lives here, versioned with the package, because the bucket has moved twice
|
|
21
|
+
// (miiplaza-media -> -2 -> -3, us-east-1 -> us-west-2) and each move would
|
|
22
|
+
// otherwise be a hunt through every app's config for a string that only fails
|
|
23
|
+
// in production, only on attachments, and only after a deploy.
|
|
24
|
+
export const MII_CHAT_MEDIA_ORIGINS = [
|
|
25
|
+
"https://miiplaza-media-3.s3.us-west-2.amazonaws.com"
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* The policy directives chat needs, ready to join into a CSP.
|
|
29
|
+
*
|
|
30
|
+
* Apps compose their own policy; this only says what chat adds to it. Pass the
|
|
31
|
+
* app's own sources for a directive and they are kept — `img-src` in particular
|
|
32
|
+
* usually already carries `data:` and `blob:` for the app's own pictures.
|
|
33
|
+
*/
|
|
34
|
+
export function miiChatCspSources(directive, own = ["'self'"]) {
|
|
35
|
+
const sources = [...own, ...MII_CHAT_MEDIA_ORIGINS];
|
|
36
|
+
return `${directive} ${sources.join(" ")}`;
|
|
37
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shubh90/app-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "The platform contract every mii org app depends on — sign-in, chat with the org's agents, and the config an app must not diverge from. A versioned package, not files copied into each repo.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|