ugly-app 0.1.716 → 0.1.718

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 (35) hide show
  1. package/dist/cli/version.d.ts +1 -1
  2. package/dist/cli/version.js +1 -1
  3. package/dist/inspect/index.d.ts +1 -0
  4. package/dist/inspect/index.d.ts.map +1 -1
  5. package/dist/inspect/index.js +1 -0
  6. package/dist/inspect/index.js.map +1 -1
  7. package/dist/inspect/selfHost.d.ts +20 -0
  8. package/dist/inspect/selfHost.d.ts.map +1 -0
  9. package/dist/inspect/selfHost.js +38 -0
  10. package/dist/inspect/selfHost.js.map +1 -0
  11. package/dist/native/index.d.ts +2 -0
  12. package/dist/native/index.d.ts.map +1 -1
  13. package/dist/native/index.js +1 -0
  14. package/dist/native/index.js.map +1 -1
  15. package/dist/native/proxyHost.d.ts +19 -0
  16. package/dist/native/proxyHost.d.ts.map +1 -0
  17. package/dist/native/proxyHost.js +139 -0
  18. package/dist/native/proxyHost.js.map +1 -0
  19. package/dist/server/auth/magicLinkTemplate.d.ts +1 -1
  20. package/dist/server/auth/magicLinkTemplate.d.ts.map +1 -1
  21. package/dist/server/auth/magicLinkTemplate.js +12 -6
  22. package/dist/server/auth/magicLinkTemplate.js.map +1 -1
  23. package/dist/server/auth/workersMagicLink.d.ts.map +1 -1
  24. package/dist/server/auth/workersMagicLink.js +15 -1
  25. package/dist/server/auth/workersMagicLink.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/cli/version.ts +1 -1
  28. package/src/inspect/index.ts +6 -0
  29. package/src/inspect/selfHost.test.ts +59 -0
  30. package/src/inspect/selfHost.ts +58 -0
  31. package/src/native/index.ts +2 -0
  32. package/src/native/proxyHost.test.ts +126 -0
  33. package/src/native/proxyHost.ts +162 -0
  34. package/src/server/auth/magicLinkTemplate.ts +13 -5
  35. package/src/server/auth/workersMagicLink.ts +16 -1
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.716";
1
+ export declare const CLI_VERSION = "0.1.718";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.716";
2
+ export const CLI_VERSION = "0.1.718";
3
3
  //# sourceMappingURL=version.js.map
@@ -3,4 +3,5 @@ export type { AgentEvents, AgentMeta, InspectAgent } from './agent/types.js';
3
3
  export { createInspectAgent, installInspectAgent } from './agent/install.js';
4
4
  export { InspectClient, type InspectTransport } from './client.js';
5
5
  export { buildTarget, dispatchToAgent, HOST_ONLY_CHANNELS } from './dispatch.js';
6
+ export { createSelfInspectHost, SELF_TARGET_ID, type SelfInspectHost, type SelfInspectHostOpts, } from './selfHost.js';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAIA,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAIA,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC"}
@@ -5,4 +5,5 @@ export * from './protocol.js';
5
5
  export { createInspectAgent, installInspectAgent } from './agent/install.js';
6
6
  export { InspectClient } from './client.js';
7
7
  export { buildTarget, dispatchToAgent, HOST_ONLY_CHANNELS } from './dispatch.js';
8
+ export { createSelfInspectHost, SELF_TARGET_ID, } from './selfHost.js';
8
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAE/E,cAAc,eAAe,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAyB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAE/E,cAAc,eAAe,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAyB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,cAAc,GAGf,MAAM,eAAe,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { InspectPlatform, Screenshot, ScreenshotRequest } from './protocol.js';
2
+ /** The id this host reports for its single (self) target. */
3
+ export declare const SELF_TARGET_ID = "self";
4
+ export interface SelfInspectHostOpts {
5
+ platform: InspectPlatform;
6
+ /** Screenshot delegate — on mobile this calls native (WKWebView.takeSnapshot /
7
+ * Android PixelCopy) via the uglyNative `capture.screenshot` channel. */
8
+ screenshot?: (req: ScreenshotRequest) => Promise<Screenshot>;
9
+ /** Forward live agent events to the proxy connection. Event names are the
10
+ * per-target dynamic form (`inspect.console:self`, `inspect.network:self`,
11
+ * `inspect.picked:self`). */
12
+ onEvent?: (event: string, data: unknown) => void;
13
+ }
14
+ export interface SelfInspectHost {
15
+ /** Route one inspect.* channel (targetId is ignored — there is only `self`). */
16
+ dispatch(channel: string, payload?: Record<string, unknown>): Promise<unknown>;
17
+ stop(): void;
18
+ }
19
+ export declare function createSelfInspectHost(opts: SelfInspectHostOpts): SelfInspectHost;
20
+ //# sourceMappingURL=selfHost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selfHost.d.ts","sourceRoot":"","sources":["../../src/inspect/selfHost.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEpF,6DAA6D;AAC7D,eAAO,MAAM,cAAc,SAAS,CAAC;AAErC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B;8EAC0E;IAC1E,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7D;;kCAE8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAED,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/E,IAAI,IAAI,IAAI,CAAC;CACd;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,eAAe,CAuBhF"}
@@ -0,0 +1,38 @@
1
+ // A single-page inspect host: answers inspect.* for the CURRENT page only,
2
+ // routing to the in-page agent. This is the building block for shells that have
3
+ // no native cross-tab host — chiefly the MOBILE SPA (iOS WKWebView / Android
4
+ // WebView), where the whole proxy stack lives in the webview JS (browser
5
+ // RTCPeerConnection) and there is exactly one inspectable page: itself.
6
+ //
7
+ // The transport that connects a remote inspector to this host (the SPA acting
8
+ // as an MSK-authenticated proxy host) is shell-specific and wired separately;
9
+ // this module is just the platform-agnostic dispatch + target it answers with.
10
+ import { installInspectAgent } from './agent/install.js';
11
+ import { buildTarget, dispatchToAgent } from './dispatch.js';
12
+ /** The id this host reports for its single (self) target. */
13
+ export const SELF_TARGET_ID = 'self';
14
+ export function createSelfInspectHost(opts) {
15
+ const agent = installInspectAgent({
16
+ onConsole: (e) => opts.onEvent?.(`inspect.console:${SELF_TARGET_ID}`, e),
17
+ onNetwork: (e) => opts.onEvent?.(`inspect.network:${SELF_TARGET_ID}`, e),
18
+ onPicked: (p) => opts.onEvent?.(`inspect.picked:${SELF_TARGET_ID}`, p),
19
+ });
20
+ return {
21
+ async dispatch(channel, payload = {}) {
22
+ if (channel === 'inspect.listTargets') {
23
+ return { targets: [buildTarget(SELF_TARGET_ID, opts.platform, agent.meta())] };
24
+ }
25
+ if (channel === 'inspect.screenshot') {
26
+ if (!opts.screenshot)
27
+ throw new Error('inspect.screenshot: no native capture on this shell');
28
+ return opts.screenshot({ ...payload, targetId: SELF_TARGET_ID });
29
+ }
30
+ // Everything else is an agent method (targetId stripped — there is only self).
31
+ return dispatchToAgent(agent, channel, payload);
32
+ },
33
+ stop() {
34
+ agent.stop();
35
+ },
36
+ };
37
+ }
38
+ //# sourceMappingURL=selfHost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selfHost.js","sourceRoot":"","sources":["../../src/inspect/selfHost.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gFAAgF;AAChF,6EAA6E;AAC7E,yEAAyE;AACzE,wEAAwE;AACxE,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAE/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAG7D,6DAA6D;AAC7D,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AAmBrC,MAAM,UAAU,qBAAqB,CAAC,IAAyB;IAC7D,MAAM,KAAK,GAAG,mBAAmB,CAAC;QAChC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,mBAAmB,cAAc,EAAE,EAAE,CAAC,CAAC;QACxE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,mBAAmB,cAAc,EAAE,EAAE,CAAC,CAAC;QACxE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,kBAAkB,cAAc,EAAE,EAAE,CAAC,CAAC;KACvE,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,OAAe,EAAE,UAAmC,EAAE;YACnE,IAAI,OAAO,KAAK,qBAAqB,EAAE,CAAC;gBACtC,OAAO,EAAE,OAAO,EAAE,CAAC,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YACjF,CAAC;YACD,IAAI,OAAO,KAAK,oBAAoB,EAAE,CAAC;gBACrC,IAAI,CAAC,IAAI,CAAC,UAAU;oBAAE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;gBAC7F,OAAO,IAAI,CAAC,UAAU,CAAC,EAAE,GAAI,OAAwC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;YACrG,CAAC;YACD,+EAA+E;YAC/E,OAAO,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAClD,CAAC;QACD,IAAI;YACF,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -21,6 +21,8 @@ export { defineTask, taskContext } from './defineTask.js';
21
21
  export type { TaskDefinition, TaskContext } from './defineTask.js';
22
22
  export { MCP_CATALOG } from './mcp-catalog.js';
23
23
  export { createProxyClient, nativeSigner } from './proxyClient.js';
24
+ export { createProxyHost } from './proxyHost.js';
25
+ export type { ProxyHost, ProxyHostOpts } from './proxyHost.js';
24
26
  export type { ProxyClient, ProxyClientOpts, ProxySocket, HostInfo, RTCFactory, } from './proxyClient.js';
25
27
  export { isDesktopChannel, withProxy, enableUglyProxy, installProxyClient, dispatchNativeEvent, DESKTOP_NAMESPACES } from './proxy.js';
26
28
  export type { WithProxyOpts } from './proxy.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,OAAO,EACP,WAAW,EACX,SAAS,EACT,QAAQ,EACR,MAAM,EACN,SAAS,EACT,cAAc,EACd,aAAa,EACb,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,eAAe,EACf,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtF,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACtE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1D,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,QAAQ,EACR,UAAU,GACX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACvI,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnF,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,OAAO,EACP,WAAW,EACX,SAAS,EACT,QAAQ,EACR,MAAM,EACN,SAAS,EACT,cAAc,EACd,aAAa,EACb,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,eAAe,EACf,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtF,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACtE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1D,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/D,YAAY,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,QAAQ,EACR,UAAU,GACX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACvI,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnF,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
@@ -12,6 +12,7 @@ export { defineTask, taskContext } from './defineTask.js';
12
12
  export { MCP_CATALOG } from './mcp-catalog.js';
13
13
  // ── Ugly Proxy (remote UglyNative over WebRTC) ──
14
14
  export { createProxyClient, nativeSigner } from './proxyClient.js';
15
+ export { createProxyHost } from './proxyHost.js';
15
16
  export { isDesktopChannel, withProxy, enableUglyProxy, installProxyClient, dispatchNativeEvent, DESKTOP_NAMESPACES } from './proxy.js';
16
17
  export { fpTag, verifyFpTag, parseFingerprint, mskSigner } from './proxyCrypto.js';
17
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AA0CA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,0EAA0E;AAC1E,wFAAwF;AACxF,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAUtF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,gFAAgF;AAChF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,mDAAmD;AACnD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAQnE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEvI,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AA0CA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,0EAA0E;AAC1E,wFAAwF;AACxF,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAUtF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,gFAAgF;AAChF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,mDAAmD;AACnD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AASjD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEvI,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { type ProxySigner } from './proxyCrypto.js';
2
+ import type { ProxySocket, RTCFactory } from './proxyClient.js';
3
+ export interface ProxyHostOpts {
4
+ socket: ProxySocket;
5
+ /** Verify the client's offer fingerprint + sign our answer (MSK-bound). */
6
+ signer?: ProxySigner;
7
+ iceServers?: RTCIceServer[];
8
+ rtcFactory?: RTCFactory;
9
+ /** Handle a tunneled request. `origin` is the app the client declared. Throw → error frame. */
10
+ onInvoke: (channel: string, payload: unknown, origin: string) => Promise<unknown>;
11
+ }
12
+ export interface ProxyHost {
13
+ stop(): void;
14
+ /** Push an evt frame to every client subscribed to `event` (live inspect streams). */
15
+ broadcast(event: string, data: unknown): void;
16
+ peerCount(): number;
17
+ }
18
+ export declare function createProxyHost(opts: ProxyHostOpts): ProxyHost;
19
+ //# sourceMappingURL=proxyHost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxyHost.d.ts","sourceRoot":"","sources":["../../src/native/proxyHost.ts"],"names":[],"mappings":"AAaA,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,+FAA+F;IAC/F,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACnF;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,IAAI,IAAI,CAAC;IACb,sFAAsF;IACtF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9C,SAAS,IAAI,MAAM,CAAC;CACrB;AAkBD,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAgH9D"}
@@ -0,0 +1,139 @@
1
+ // Browser-side host of the Ugly Proxy: the symmetric counterpart of
2
+ // proxyClient. A shell with NO native host (chiefly the MOBILE SPA, where the
3
+ // whole proxy stack lives in the webview) registers as a proxy HOST and ANSWERS
4
+ // a remote inspector's WebRTC offer, then dispatches the tunneled inspect.*
5
+ // (or any UglyNative) calls. Signaling rides the app Socket's rtc:* messages;
6
+ // DTLS encrypts; the MSK-bound fingerprint check authenticates the client.
7
+ //
8
+ // NOTE: on the DESKTOP the host lives in the Electron main (ugly-studio
9
+ // hostHub/werift) — a desktop *renderer* host was tried + reverted. This module
10
+ // is for shells that have no main process, where the SPA is the only host there
11
+ // can be. RTCPeerConnection + Socket are injectable so it's unit-testable and
12
+ // can drive werift in node tests.
13
+ import { parseFingerprint } from './proxyCrypto.js';
14
+ function rec(d) {
15
+ return (d ?? {});
16
+ }
17
+ export function createProxyHost(opts) {
18
+ const rtcFactory = opts.rtcFactory ?? ((cfg) => new RTCPeerConnection(cfg));
19
+ const peers = new Map(); // keyed by client deviceId (`from`)
20
+ const subs = new Set();
21
+ const offs = [];
22
+ async function onOffer(d) {
23
+ const from = String(d['from'] ?? '');
24
+ if (!from)
25
+ return;
26
+ const sdp = String(d['sdp'] ?? '');
27
+ const origin = String(d['origin'] ?? '');
28
+ if (opts.signer) {
29
+ const ok = await opts.signer.verify('client', parseFingerprint(sdp) ?? '', String(d['fpTag'] ?? ''));
30
+ if (!ok) {
31
+ opts.socket.emit('rtc:error', { to: from, reason: 'fingerprint-auth-failed' });
32
+ return;
33
+ }
34
+ }
35
+ try {
36
+ peers.get(from)?.pc.close();
37
+ }
38
+ catch {
39
+ /* noop */
40
+ }
41
+ const pc = rtcFactory({ iceServers: opts.iceServers ?? [] });
42
+ const peer = { pc, dc: null, origin };
43
+ peers.set(from, peer);
44
+ pc.onicecandidate = (e) => {
45
+ if (e.candidate)
46
+ opts.socket.emit('rtc:ice', { to: from, candidate: e.candidate.toJSON() });
47
+ };
48
+ pc.ondatachannel = (e) => {
49
+ peer.dc = e.channel;
50
+ e.channel.onmessage = (m) => void onFrame(peer, e.channel, m.data);
51
+ };
52
+ await pc.setRemoteDescription({ type: 'offer', sdp });
53
+ const answer = await pc.createAnswer();
54
+ await pc.setLocalDescription(answer);
55
+ const answerSdp = pc.localDescription?.sdp ?? answer.sdp ?? '';
56
+ const tag = opts.signer ? await opts.signer.sign('host', parseFingerprint(answerSdp) ?? '') : undefined;
57
+ opts.socket.emit('rtc:answer', { to: from, sdp: answerSdp, fpTag: tag });
58
+ }
59
+ async function onIce(d) {
60
+ const peer = peers.get(String(d['from'] ?? ''));
61
+ if (!peer)
62
+ return;
63
+ try {
64
+ await peer.pc.addIceCandidate(d['candidate']);
65
+ }
66
+ catch {
67
+ /* benign — candidate races */
68
+ }
69
+ }
70
+ async function onFrame(peer, dc, raw) {
71
+ let f;
72
+ try {
73
+ f = JSON.parse(typeof raw === 'string' ? raw : new TextDecoder().decode(raw));
74
+ }
75
+ catch {
76
+ return;
77
+ }
78
+ if (f.t === 'req' && f.id !== undefined) {
79
+ try {
80
+ const result = await opts.onInvoke(String(f.channel), f.payload, peer.origin);
81
+ send(dc, { t: 'res', id: f.id, ok: true, result });
82
+ }
83
+ catch (err) {
84
+ send(dc, { t: 'res', id: f.id, ok: false, error: String(err?.message ?? err) });
85
+ }
86
+ }
87
+ else if (f.t === 'sub' && f.id !== undefined) {
88
+ // Register the live subscription; broadcast() fans matching events out.
89
+ // Snapshot is null — the client's panels also pull the current buffer via req.
90
+ subs.add({ dc, event: String(f.channel ?? ''), id: f.id });
91
+ send(dc, { t: 'res', id: f.id, ok: true, result: { snapshot: null } });
92
+ }
93
+ else if (f.t === 'unsub' && f.id !== undefined) {
94
+ for (const s of [...subs])
95
+ if (s.dc === dc && s.id === f.id)
96
+ subs.delete(s);
97
+ }
98
+ }
99
+ function send(dc, frame) {
100
+ try {
101
+ if (dc.readyState === 'open')
102
+ dc.send(JSON.stringify(frame));
103
+ }
104
+ catch {
105
+ /* channel gone */
106
+ }
107
+ }
108
+ offs.push(opts.socket.on('rtc:offer', (d) => void onOffer(rec(d))));
109
+ offs.push(opts.socket.on('rtc:ice', (d) => void onIce(rec(d))));
110
+ return {
111
+ stop() {
112
+ for (const off of offs) {
113
+ try {
114
+ off();
115
+ }
116
+ catch {
117
+ /* noop */
118
+ }
119
+ }
120
+ for (const peer of peers.values()) {
121
+ try {
122
+ peer.pc.close();
123
+ }
124
+ catch {
125
+ /* noop */
126
+ }
127
+ }
128
+ peers.clear();
129
+ subs.clear();
130
+ },
131
+ broadcast(event, data) {
132
+ for (const s of subs)
133
+ if (s.event === event)
134
+ send(s.dc, { t: 'evt', event, data });
135
+ },
136
+ peerCount: () => peers.size,
137
+ };
138
+ }
139
+ //# sourceMappingURL=proxyHost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxyHost.js","sourceRoot":"","sources":["../../src/native/proxyHost.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@
6
6
  * the same in every mail client. The button colour is black so it survives
7
7
  * light/dark-mode inversion.
8
8
  */
9
- export declare function magicLinkEmail(url: string, appName: string, expiresMin: number): {
9
+ export declare function magicLinkEmail(url: string, appName: string, expiresMin: number, iconUrl?: string): {
10
10
  subject: string;
11
11
  html: string;
12
12
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"magicLinkTemplate.d.ts","sourceRoot":"","sources":["../../../src/server/auth/magicLinkTemplate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAYjD"}
1
+ {"version":3,"file":"magicLinkTemplate.d.ts","sourceRoot":"","sources":["../../../src/server/auth/magicLinkTemplate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAmBjD"}
@@ -6,15 +6,21 @@
6
6
  * the same in every mail client. The button colour is black so it survives
7
7
  * light/dark-mode inversion.
8
8
  */
9
- export function magicLinkEmail(url, appName, expiresMin) {
9
+ export function magicLinkEmail(url, appName, expiresMin, iconUrl) {
10
10
  const safeAppName = escapeHtml(appName);
11
+ // Only honour absolute https icons — mail clients won't load anything else,
12
+ // and it keeps a hostile relative/`javascript:` value out of the markup.
13
+ const iconImg = iconUrl && /^https:\/\//i.test(iconUrl)
14
+ ? `<img src="${escapeHtml(iconUrl)}" alt="" width="56" height="56" style="border-radius:12px;display:block;margin:0 auto 16px">`
15
+ : '';
11
16
  return {
12
17
  subject: `Sign in to ${appName}`,
13
- html: `<!doctype html><html><body style="font-family:system-ui,sans-serif;padding:24px;max-width:480px;margin:auto">
14
- <h2>Sign in to ${safeAppName}</h2>
15
- <p>Click the button below to sign in. This link expires in ${expiresMin} minutes and can only be used once.</p>
16
- <p><a href="${url}" style="background:#000;color:#fff;padding:12px 24px;text-decoration:none;border-radius:6px;display:inline-block">Sign in</a></p>
17
- <p style="color:#888;font-size:12px">If you didn't request this, you can safely ignore this email.</p>
18
+ html: `<!doctype html><html><body style="font-family:system-ui,sans-serif;padding:24px;max-width:480px;margin:auto;text-align:center">
19
+ ${iconImg}
20
+ <h2 style="margin:0 0 12px">Sign in to ${safeAppName}</h2>
21
+ <p style="text-align:left">Click the button below to sign in. This link expires in ${expiresMin} minutes and can only be used once.</p>
22
+ <p><a href="${url}" style="background:#000;color:#fff;padding:12px 24px;text-decoration:none;border-radius:6px;display:inline-block">Sign in to ${safeAppName}</a></p>
23
+ <p style="color:#888;font-size:12px;text-align:left">If you didn't request this, you can safely ignore this email.</p>
18
24
  </body></html>`,
19
25
  text: `Sign in to ${appName}: ${url}\n\nThis link expires in ${expiresMin} minutes.`,
20
26
  };
@@ -1 +1 @@
1
- {"version":3,"file":"magicLinkTemplate.js","sourceRoot":"","sources":["../../../src/server/auth/magicLinkTemplate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,OAAe,EACf,UAAkB;IAElB,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO;QACL,OAAO,EAAE,cAAc,OAAO,EAAE;QAChC,IAAI,EAAE;uBACa,WAAW;mEACiC,UAAU;oBACzD,GAAG;;mBAEJ;QACf,IAAI,EAAE,cAAc,OAAO,KAAK,GAAG,4BAA4B,UAAU,WAAW;KACrF,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CACd,SAAS,EACT,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAE,CACvE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"magicLinkTemplate.js","sourceRoot":"","sources":["../../../src/server/auth/magicLinkTemplate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,OAAe,EACf,UAAkB,EAClB,OAAgB;IAEhB,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACxC,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,OAAO,GACX,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC;QACrC,CAAC,CAAC,aAAa,UAAU,CAAC,OAAO,CAAC,8FAA8F;QAChI,CAAC,CAAC,EAAE,CAAC;IACT,OAAO;QACL,OAAO,EAAE,cAAc,OAAO,EAAE;QAChC,IAAI,EAAE;QACF,OAAO;+CACgC,WAAW;2FACiC,UAAU;oBACjF,GAAG,iIAAiI,WAAW;;mBAEhJ;QACf,IAAI,EAAE,cAAc,OAAO,KAAK,GAAG,4BAA4B,UAAU,WAAW;KACrF,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CACd,SAAS,EACT,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAE,CACvE,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"workersMagicLink.d.ts","sourceRoot":"","sources":["../../../src/server/auth/workersMagicLink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,MAAM,CAAC;AAK1C,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI5E,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AA0DxE,MAAM,WAAW,sBAAsB;IACrC,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IAEH,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACjB,kEAAkE;IAClE,YAAY,EAAE,YAAY,CAAC;CAC5B;AA+DD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAA+B,GACtC,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED,+EAA+E;AAC/E,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAOjB;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAE5C,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EACf,MAAM,EAAE,sBAAsB,GAC7B,IAAI,CA8MN"}
1
+ {"version":3,"file":"workersMagicLink.d.ts","sourceRoot":"","sources":["../../../src/server/auth/workersMagicLink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,MAAM,CAAC;AAK1C,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI5E,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAkExE,MAAM,WAAW,sBAAsB;IACrC,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IAEH,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACjB,kEAAkE;IAClE,YAAY,EAAE,YAAY,CAAC;CAC5B;AA+DD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAA+B,GACtC,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED,+EAA+E;AAC/E,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAOjB;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAE5C,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EACf,MAAM,EAAE,sBAAsB,GAC7B,IAAI,CAqNN"}
@@ -21,6 +21,14 @@ const requestBodySchema = z.object({
21
21
  * `window.location.href` so the user resumes wherever they were.
22
22
  */
23
23
  returnTo: z.string().max(2000).optional(),
24
+ /**
25
+ * Optional per-request branding for the email (subject/heading + icon).
26
+ * Used by a central login authority (e.g. ugly.bot) to brand the sign-in
27
+ * email with the CHILD app that triggered the login, rather than the
28
+ * authority's own name. Falls back to the registration-time `appName`.
29
+ */
30
+ appName: z.string().max(120).optional(),
31
+ iconUrl: z.string().url().max(2000).optional(),
24
32
  });
25
33
  const verifyBodySchema = z.object({
26
34
  id: z.string().min(1).max(128),
@@ -221,7 +229,13 @@ hono, config) {
221
229
  // eslint-disable-next-line no-console
222
230
  console.log(`[Auth] DEBUG magic-link for ${email}: ${url}`);
223
231
  }
224
- const tpl = magicLinkEmail(url, appName, expiresMin);
232
+ // Per-request branding (the app that triggered the login) overrides the
233
+ // registration-time default; icon is honoured only if absolute https.
234
+ const reqAppName = parsed.data.appName?.trim() || appName;
235
+ const reqIconUrl = parsed.data.iconUrl && /^https:\/\//i.test(parsed.data.iconUrl)
236
+ ? parsed.data.iconUrl
237
+ : undefined;
238
+ const tpl = magicLinkEmail(url, reqAppName, expiresMin, reqIconUrl);
225
239
  let emailError = null;
226
240
  try {
227
241
  await emailSend({
@@ -1 +1 @@
1
- {"version":3,"file":"workersMagicLink.js","sourceRoot":"","sources":["../../../src/server/auth/workersMagicLink.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workersMagicLink.js","sourceRoot":"","sources":["../../../src/server/auth/workersMagicLink.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAgB,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAqB,MAAM,iBAAiB,CAAC;AAExE,uEAAuE;AACvE,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAEjD,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC/B,MAAM,4BAA4B,GAAG,EAAE,CAAC;AACxC,MAAM,+BAA+B,GAAG,CAAC,CAAC;AAE1C,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;IACzC;;;;;OAKG;IACH,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;CAC/C,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC9B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;CAC1C,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,SAAS,gBAAgB,CACvB,QAA4B,EAC5B,WAAmB;IAEnB,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC;IACpD,+CAA+C;IAC/C,IAAI,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5B,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO;gBAAE,OAAO,GAAG,CAAC;YAClE,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE;gBAAE,OAAO,GAAG,CAAC;YACnE,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,mBAAmB,CAAC;gBAAE,OAAO,GAAG,CAAC;YAC3D,OAAO,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IACD,oEAAoE;IACpE,uDAAuD;IACvD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IACvE,IAAI,QAAQ,CAAC,UAAU,CAAC,mBAAmB,CAAC;QAAE,OAAO,GAAG,CAAC;IACzD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAqBD,SAAS,aAAa;IACpB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IACxE,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CACb,6EAA6E,CAC9E,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,eAAe,CAAC,CAAU,EAAE,QAAiB;IACpD,MAAM,QAAQ,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC3D,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAClD,oEAAoE;IACpE,mEAAmE;IACnE,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,KAAK,GAAG,QAAQ,IAAI,OAAO,CAAC;QAClC,OAAO,GAAG,KAAK,MAAM,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,WAAW,CAAC,CAAU;IAC7B,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAC5C,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACxC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC9C,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,SAAS,CAAC;AACnB,CAAC;AAOD,SAAS,iBAAiB,CAAC,YAAoB,EAAE,QAAgB;IAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,OAAO,CAAC,GAAW,EAAW,EAAE;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,WAAW,IAAI,QAAQ,EAAE,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YACjD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,CAAC,KAAK,IAAI,YAAY;YAAE,OAAO,KAAK,CAAC;QAC1C,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAc,EACd,MAAc,EACd,SAAiB,sBAAsB;IAEvC,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,OAAO,IAAI,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;SAChC,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;SACpC,WAAW,EAAE;SACb,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC;SACzD,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,MAAc;IAEd,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAChD,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC;AACrB,CAAC;AAED,SAAS,eAAe,CAAC,KAAa,EAAE,OAA4B,EAAE;IACpE,MAAM,KAAK,GAAG,CAAC,cAAc,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACxD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,EAAE,CAAC,CAAC;IACjE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,8BAA8B;AAC5C,8DAA8D;AAC9D,IAAe,EACf,MAA8B;IAE9B,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,GAAG,IAAI,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CACb,0EAA0E,UAAU,GAAG,CACxF,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GACX,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC;IAE1D,MAAM,SAAS,GAAG,iBAAiB,CAAC,4BAA4B,EAAE,OAAO,CAAC,CAAC;IAC3E,MAAM,YAAY,GAAG,iBAAiB,CACpC,+BAA+B,EAC/B,OAAO,CACR,CAAC;IAEF,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAChD,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,KAAK,MAAM,EAAE,CAAC;YACjD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAC9C,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAE1B,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAC3B,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;YAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,MAAM,CAAC;YACnD,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YAE7D,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;YACrC,MAAM,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,aAAa,EAAE;gBACjD,GAAG,EAAE,SAAS;gBACd,GAAG,UAAU,EAAE;gBACf,KAAK;gBACL,SAAS;gBACT,SAAS;gBACT,UAAU,EAAE,IAAI;gBAChB,SAAS,EAAE,EAAE;gBACb,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;aACxB,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;YACrD,6DAA6D;YAC7D,iEAAiE;YACjE,gEAAgE;YAChE,0CAA0C;YAC1C,IAAI,QAAQ,GAAG,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACxC,CAAC;YACD,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACtE,MAAM,aAAa,GACjB,YAAY,KAAK,GAAG;gBAClB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,aAAa,kBAAkB,CAAC,YAAY,CAAC,EAAE,CAAC;YACtD,MAAM,GAAG,GAAG,GAAG,IAAI,8BAA8B,kBAAkB,CAAC,OAAO,CAAC,QAAQ,kBAAkB,CAAC,GAAG,CAAC,GAAG,aAAa,EAAE,CAAC;YAE9H,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,KAAK,GAAG,CAAC;YACnE,mEAAmE;YACnE,6DAA6D;YAC7D,kEAAkE;YAClE,+CAA+C;YAC/C,IAAI,SAAS,EAAE,CAAC;gBACd,sCAAsC;gBACtC,OAAO,CAAC,GAAG,CACT,+BAA+B,KAAK,KAAK,GAAG,EAAE,CAC/C,CAAC;YACJ,CAAC;YAED,wEAAwE;YACxE,sEAAsE;YACtE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC;YAC1D,MAAM,UAAU,GACd,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;gBAC7D,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO;gBACrB,CAAC,CAAC,SAAS,CAAC;YAChB,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;YACpE,IAAI,UAAU,GAAY,IAAI,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC;oBACd,EAAE,EAAE,KAAK;oBACT,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,EAAE,EAAE,YAAY;iBACjB,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,UAAU,GAAG,GAAG,CAAC;gBACjB,sCAAsC;gBACtC,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,GAAG,CAAC,CAAC;YAC5D,CAAC;YAED,IAAI,SAAS,EAAE,CAAC;gBACd,8DAA8D;gBAC9D,8DAA8D;gBAC9D,yDAAyD;gBACzD,uDAAuD;gBACvD,oBAAoB;gBACpB,OAAO,CAAC,CAAC,IAAI,CAAC;oBACZ,EAAE,EAAE,IAAI;oBACR,KAAK,EAAE;wBACL,IAAI,EAAE,GAAG;wBACT,cAAc,EAAE,CAAC,UAAU;wBAC3B,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI;qBACnD;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,yBAAyB,EAAE,CAAC,CAAC,EAAE,EAAE;QACxC,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,KAAK,MAAM,EAAE,CAAC;YACjD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACrC,mEAAmE;QACnE,gEAAgE;QAChE,qDAAqD;QACrD,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,YAAY,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC;QACrE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG;;mBAEE,YAAY;;;;;;mCAMI,MAAM,UAAU,OAAO;;;;;;;;;;;wBAWlC,CAAC;QACrB,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC/C,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,KAAK,MAAM,EAAE,CAAC;YACjD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;QACnE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;QAEhC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;YAChC,8DAA8D;YAC9D,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,EAAE,CAAC,MAAM,CACjC,YAAY,CAAC,aAAa,EAC1B,SAAS,CACV,CAMO,CAAC;YACT,IAAI,CAAC,GAAG;gBAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;YACxD,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI;gBAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;YAChF,IAAI,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE;gBAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;YAC/E,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC;gBAChE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;YAChD,CAAC;YAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,kBAAkB,CACzC,MAAM,CAAC,EAAE,EACT,YAAY,EACZ,GAAG,CAAC,KAAK,EACT,IAAI,EACJ,MAAM,CAAC,YAAY,CACpB,CAAC;YAEF,MAAM,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,aAAa,EAAE,SAAS,EAAE;gBAClE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;aACvB,CAAC,CAAC;YAEH,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAClE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;YACtD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;QAChD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.716",
3
+ "version": "0.1.718",
4
4
  "type": "module",
5
5
  "comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
6
6
  "files": [
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.716";
2
+ export const CLI_VERSION = "0.1.718";
@@ -7,3 +7,9 @@ export type { AgentEvents, AgentMeta, InspectAgent } from './agent/types.js';
7
7
  export { createInspectAgent, installInspectAgent } from './agent/install.js';
8
8
  export { InspectClient, type InspectTransport } from './client.js';
9
9
  export { buildTarget, dispatchToAgent, HOST_ONLY_CHANNELS } from './dispatch.js';
10
+ export {
11
+ createSelfInspectHost,
12
+ SELF_TARGET_ID,
13
+ type SelfInspectHost,
14
+ type SelfInspectHostOpts,
15
+ } from './selfHost.js';
@@ -0,0 +1,59 @@
1
+ // @vitest-environment jsdom
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { createSelfInspectHost, SELF_TARGET_ID } from './selfHost.js';
4
+ import type { Screenshot } from './protocol.js';
5
+
6
+ afterEach(() => {
7
+ // Reset the singleton agent between tests.
8
+ delete (window as { __uglyInspectAgent?: unknown }).__uglyInspectAgent;
9
+ });
10
+
11
+ describe('createSelfInspectHost', () => {
12
+ it('lists exactly one target (self) with the given platform', async () => {
13
+ document.title = 'Mobile App';
14
+ const host = createSelfInspectHost({ platform: 'ios' });
15
+ const res = (await host.dispatch('inspect.listTargets')) as { targets: { id: string; platform: string }[] };
16
+ expect(res.targets).toHaveLength(1);
17
+ expect(res.targets[0].id).toBe(SELF_TARGET_ID);
18
+ expect(res.targets[0].platform).toBe('ios');
19
+ });
20
+
21
+ it('routes inspect.eval to the in-page agent', async () => {
22
+ const host = createSelfInspectHost({ platform: 'android' });
23
+ const res = (await host.dispatch('inspect.eval', { expression: '21 * 2' })) as {
24
+ ok: boolean;
25
+ value: { value: number };
26
+ };
27
+ expect(res.ok).toBe(true);
28
+ expect(res.value.value).toBe(42);
29
+ });
30
+
31
+ it('captures the DOM via the agent', async () => {
32
+ document.body.innerHTML = '<main id="x">hi</main>';
33
+ const host = createSelfInspectHost({ platform: 'ios' });
34
+ const snap = (await host.dispatch('inspect.dom.capture')) as { root: { nodeName: string } };
35
+ expect(snap.root.nodeName).toBe('HTML');
36
+ });
37
+
38
+ it('delegates inspect.screenshot to the native capture callback', async () => {
39
+ const shot: Screenshot = { base64: 'AAAA', width: 390, height: 844, dpr: 3, format: 'png' };
40
+ const capture = vi.fn(async () => shot);
41
+ const host = createSelfInspectHost({ platform: 'ios', screenshot: capture });
42
+ const res = await host.dispatch('inspect.screenshot', { fullPage: true });
43
+ expect(res).toEqual(shot);
44
+ expect(capture).toHaveBeenCalledWith(expect.objectContaining({ targetId: SELF_TARGET_ID, fullPage: true }));
45
+ });
46
+
47
+ it('errors on screenshot when no native capture is provided', async () => {
48
+ const host = createSelfInspectHost({ platform: 'web' });
49
+ await expect(host.dispatch('inspect.screenshot', {})).rejects.toThrow(/no native capture/);
50
+ });
51
+
52
+ it('forwards live console events under the self event name', async () => {
53
+ const events: { event: string; data: unknown }[] = [];
54
+ createSelfInspectHost({ platform: 'android', onEvent: (event, data) => events.push({ event, data }) });
55
+ console.log('streamed-line');
56
+ const consoleEvt = events.find((e) => e.event === `inspect.console:${SELF_TARGET_ID}`);
57
+ expect(consoleEvt).toBeTruthy();
58
+ });
59
+ });
@@ -0,0 +1,58 @@
1
+ // A single-page inspect host: answers inspect.* for the CURRENT page only,
2
+ // routing to the in-page agent. This is the building block for shells that have
3
+ // no native cross-tab host — chiefly the MOBILE SPA (iOS WKWebView / Android
4
+ // WebView), where the whole proxy stack lives in the webview JS (browser
5
+ // RTCPeerConnection) and there is exactly one inspectable page: itself.
6
+ //
7
+ // The transport that connects a remote inspector to this host (the SPA acting
8
+ // as an MSK-authenticated proxy host) is shell-specific and wired separately;
9
+ // this module is just the platform-agnostic dispatch + target it answers with.
10
+
11
+ import { installInspectAgent } from './agent/install.js';
12
+ import { buildTarget, dispatchToAgent } from './dispatch.js';
13
+ import type { InspectPlatform, Screenshot, ScreenshotRequest } from './protocol.js';
14
+
15
+ /** The id this host reports for its single (self) target. */
16
+ export const SELF_TARGET_ID = 'self';
17
+
18
+ export interface SelfInspectHostOpts {
19
+ platform: InspectPlatform;
20
+ /** Screenshot delegate — on mobile this calls native (WKWebView.takeSnapshot /
21
+ * Android PixelCopy) via the uglyNative `capture.screenshot` channel. */
22
+ screenshot?: (req: ScreenshotRequest) => Promise<Screenshot>;
23
+ /** Forward live agent events to the proxy connection. Event names are the
24
+ * per-target dynamic form (`inspect.console:self`, `inspect.network:self`,
25
+ * `inspect.picked:self`). */
26
+ onEvent?: (event: string, data: unknown) => void;
27
+ }
28
+
29
+ export interface SelfInspectHost {
30
+ /** Route one inspect.* channel (targetId is ignored — there is only `self`). */
31
+ dispatch(channel: string, payload?: Record<string, unknown>): Promise<unknown>;
32
+ stop(): void;
33
+ }
34
+
35
+ export function createSelfInspectHost(opts: SelfInspectHostOpts): SelfInspectHost {
36
+ const agent = installInspectAgent({
37
+ onConsole: (e) => opts.onEvent?.(`inspect.console:${SELF_TARGET_ID}`, e),
38
+ onNetwork: (e) => opts.onEvent?.(`inspect.network:${SELF_TARGET_ID}`, e),
39
+ onPicked: (p) => opts.onEvent?.(`inspect.picked:${SELF_TARGET_ID}`, p),
40
+ });
41
+
42
+ return {
43
+ async dispatch(channel: string, payload: Record<string, unknown> = {}): Promise<unknown> {
44
+ if (channel === 'inspect.listTargets') {
45
+ return { targets: [buildTarget(SELF_TARGET_ID, opts.platform, agent.meta())] };
46
+ }
47
+ if (channel === 'inspect.screenshot') {
48
+ if (!opts.screenshot) throw new Error('inspect.screenshot: no native capture on this shell');
49
+ return opts.screenshot({ ...(payload as unknown as ScreenshotRequest), targetId: SELF_TARGET_ID });
50
+ }
51
+ // Everything else is an agent method (targetId stripped — there is only self).
52
+ return dispatchToAgent(agent, channel, payload);
53
+ },
54
+ stop() {
55
+ agent.stop();
56
+ },
57
+ };
58
+ }
@@ -67,6 +67,8 @@ export { MCP_CATALOG } from './mcp-catalog.js';
67
67
 
68
68
  // ── Ugly Proxy (remote UglyNative over WebRTC) ──
69
69
  export { createProxyClient, nativeSigner } from './proxyClient.js';
70
+ export { createProxyHost } from './proxyHost.js';
71
+ export type { ProxyHost, ProxyHostOpts } from './proxyHost.js';
70
72
  export type {
71
73
  ProxyClient,
72
74
  ProxyClientOpts,
@@ -0,0 +1,126 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { createProxyHost } from './proxyHost.js';
3
+ import type { ProxySocket } from './proxyClient.js';
4
+ import type { ProxySigner } from './proxyCrypto.js';
5
+
6
+ // A controllable fake socket: capture emits, fire inbound rtc:* events on demand.
7
+ function fakeSocket() {
8
+ const emits: { type: string; data: Record<string, unknown> }[] = [];
9
+ const handlers = new Map<string, (d: unknown) => void>();
10
+ const socket: ProxySocket = {
11
+ emit: (type, data) => emits.push({ type, data: data as Record<string, unknown> }),
12
+ on: (event, handler) => {
13
+ handlers.set(event, handler);
14
+ return () => handlers.delete(event);
15
+ },
16
+ };
17
+ return { socket, emits, fire: (event: string, d: unknown) => handlers.get(event)?.(d) };
18
+ }
19
+
20
+ // A fake RTCDataChannel that records sent frames and lets the test push messages.
21
+ function fakeChannel() {
22
+ const sent: string[] = [];
23
+ const ch = {
24
+ readyState: 'open',
25
+ send: (s: string) => sent.push(s),
26
+ onmessage: null as null | ((e: { data: unknown }) => void),
27
+ };
28
+ return { ch, sent, push: (frame: object) => ch.onmessage?.({ data: JSON.stringify(frame) }) };
29
+ }
30
+
31
+ // rtcFactory returning a fake answerer PC the test drives.
32
+ function fakeRtc() {
33
+ const pc: Record<string, unknown> = {
34
+ onicecandidate: null,
35
+ ondatachannel: null,
36
+ setRemoteDescription: vi.fn(async () => {}),
37
+ createAnswer: vi.fn(async () => ({ type: 'answer', sdp: 'answer-sdp\na=fingerprint:sha-256 AA:BB' })),
38
+ setLocalDescription: vi.fn(async () => {}),
39
+ localDescription: { sdp: 'answer-sdp\na=fingerprint:sha-256 AA:BB' },
40
+ addIceCandidate: vi.fn(async () => {}),
41
+ close: vi.fn(),
42
+ };
43
+ return { pc, factory: () => pc as unknown as RTCPeerConnection };
44
+ }
45
+
46
+ const okSigner: ProxySigner = {
47
+ sign: vi.fn(async (role: string) => `sig-${role}`),
48
+ verify: vi.fn(async (_role, _fp, tag: string) => tag === 'good'),
49
+ };
50
+
51
+ describe('createProxyHost', () => {
52
+ it('answers a fingerprint-valid offer with a host-signed answer', async () => {
53
+ const { socket, emits, fire } = fakeSocket();
54
+ const { pc, factory } = fakeRtc();
55
+ createProxyHost({ socket, signer: okSigner, rtcFactory: factory, onInvoke: async () => ({}) });
56
+
57
+ await fire('rtc:offer', { from: 'client-1', sdp: 'offer-sdp\na=fingerprint:sha-256 CC:DD', fpTag: 'good', origin: 'https://app.x' });
58
+ await new Promise((r) => setTimeout(r, 0));
59
+
60
+ expect(okSigner.verify).toHaveBeenCalledWith('client', expect.any(String), 'good');
61
+ expect(pc.setRemoteDescription).toHaveBeenCalled();
62
+ const answer = emits.find((e) => e.type === 'rtc:answer');
63
+ expect(answer?.data).toMatchObject({ to: 'client-1', sdp: expect.stringContaining('answer-sdp'), fpTag: 'sig-host' });
64
+ });
65
+
66
+ it('rejects an offer with a bad fingerprint (no answer, emits rtc:error)', async () => {
67
+ const { socket, emits, fire } = fakeSocket();
68
+ createProxyHost({ socket, signer: okSigner, rtcFactory: fakeRtc().factory, onInvoke: async () => ({}) });
69
+
70
+ await fire('rtc:offer', { from: 'evil', sdp: 'x', fpTag: 'BAD', origin: '' });
71
+ await Promise.resolve();
72
+
73
+ expect(emits.find((e) => e.type === 'rtc:answer')).toBeUndefined();
74
+ expect(emits.find((e) => e.type === 'rtc:error')?.data).toMatchObject({ to: 'evil', reason: 'fingerprint-auth-failed' });
75
+ });
76
+
77
+ it('dispatches a req frame to onInvoke and replies with a res frame', async () => {
78
+ const { socket, fire } = fakeSocket();
79
+ const { pc, factory } = fakeRtc();
80
+ const onInvoke = vi.fn(async (channel: string) => ({ echoed: channel }));
81
+ createProxyHost({ socket, signer: okSigner, rtcFactory: factory, onInvoke });
82
+
83
+ await fire('rtc:offer', { from: 'c', sdp: 's\na=fingerprint:sha-256 CC', fpTag: 'good', origin: 'https://o' });
84
+ await Promise.resolve();
85
+
86
+ const { ch, sent, push } = fakeChannel();
87
+ (pc.ondatachannel as (e: { channel: unknown }) => void)({ channel: ch });
88
+ push({ t: 'req', id: '7', channel: 'inspect.listTargets', payload: {} });
89
+ await new Promise((r) => setTimeout(r, 0));
90
+
91
+ expect(onInvoke).toHaveBeenCalledWith('inspect.listTargets', {}, 'https://o');
92
+ expect(JSON.parse(sent[0])).toEqual({ t: 'res', id: '7', ok: true, result: { echoed: 'inspect.listTargets' } });
93
+ });
94
+
95
+ it('replies with an error frame when onInvoke throws', async () => {
96
+ const { socket, fire } = fakeSocket();
97
+ const { pc, factory } = fakeRtc();
98
+ createProxyHost({ socket, signer: okSigner, rtcFactory: factory, onInvoke: async () => { throw new Error('boom'); } });
99
+ await fire('rtc:offer', { from: 'c', sdp: 's', fpTag: 'good', origin: '' });
100
+ await Promise.resolve();
101
+ const { ch, sent, push } = fakeChannel();
102
+ (pc.ondatachannel as (e: { channel: unknown }) => void)({ channel: ch });
103
+ push({ t: 'req', id: '1', channel: 'inspect.eval', payload: {} });
104
+ await new Promise((r) => setTimeout(r, 0));
105
+ expect(JSON.parse(sent[0])).toMatchObject({ t: 'res', id: '1', ok: false, error: expect.stringContaining('boom') });
106
+ });
107
+
108
+ it('broadcasts evt frames to subscribed channels only', async () => {
109
+ const { socket, fire } = fakeSocket();
110
+ const { pc, factory } = fakeRtc();
111
+ const host = createProxyHost({ socket, signer: okSigner, rtcFactory: factory, onInvoke: async () => ({}) });
112
+ await fire('rtc:offer', { from: 'c', sdp: 's', fpTag: 'good', origin: '' });
113
+ await Promise.resolve();
114
+ const { ch, sent, push } = fakeChannel();
115
+ (pc.ondatachannel as (e: { channel: unknown }) => void)({ channel: ch });
116
+
117
+ push({ t: 'sub', id: '9', channel: 'inspect.console:self' });
118
+ await new Promise((r) => setTimeout(r, 0));
119
+ expect(JSON.parse(sent[0])).toMatchObject({ t: 'res', id: '9', ok: true });
120
+
121
+ host.broadcast('inspect.console:self', { text: 'hello' });
122
+ host.broadcast('inspect.network:self', { url: 'x' }); // not subscribed → dropped
123
+ const evts = sent.slice(1).map((s) => JSON.parse(s));
124
+ expect(evts).toEqual([{ t: 'evt', event: 'inspect.console:self', data: { text: 'hello' } }]);
125
+ });
126
+ });
@@ -0,0 +1,162 @@
1
+ // Browser-side host of the Ugly Proxy: the symmetric counterpart of
2
+ // proxyClient. A shell with NO native host (chiefly the MOBILE SPA, where the
3
+ // whole proxy stack lives in the webview) registers as a proxy HOST and ANSWERS
4
+ // a remote inspector's WebRTC offer, then dispatches the tunneled inspect.*
5
+ // (or any UglyNative) calls. Signaling rides the app Socket's rtc:* messages;
6
+ // DTLS encrypts; the MSK-bound fingerprint check authenticates the client.
7
+ //
8
+ // NOTE: on the DESKTOP the host lives in the Electron main (ugly-studio
9
+ // hostHub/werift) — a desktop *renderer* host was tried + reverted. This module
10
+ // is for shells that have no main process, where the SPA is the only host there
11
+ // can be. RTCPeerConnection + Socket are injectable so it's unit-testable and
12
+ // can drive werift in node tests.
13
+
14
+ import { parseFingerprint, type ProxySigner } from './proxyCrypto.js';
15
+ import type { ProxySocket, RTCFactory } from './proxyClient.js';
16
+
17
+ export interface ProxyHostOpts {
18
+ socket: ProxySocket;
19
+ /** Verify the client's offer fingerprint + sign our answer (MSK-bound). */
20
+ signer?: ProxySigner;
21
+ iceServers?: RTCIceServer[];
22
+ rtcFactory?: RTCFactory;
23
+ /** Handle a tunneled request. `origin` is the app the client declared. Throw → error frame. */
24
+ onInvoke: (channel: string, payload: unknown, origin: string) => Promise<unknown>;
25
+ }
26
+
27
+ export interface ProxyHost {
28
+ stop(): void;
29
+ /** Push an evt frame to every client subscribed to `event` (live inspect streams). */
30
+ broadcast(event: string, data: unknown): void;
31
+ peerCount(): number;
32
+ }
33
+
34
+ interface Peer {
35
+ pc: RTCPeerConnection;
36
+ dc: RTCDataChannel | null;
37
+ origin: string;
38
+ }
39
+
40
+ interface Sub {
41
+ dc: RTCDataChannel;
42
+ event: string;
43
+ id: string;
44
+ }
45
+
46
+ function rec(d: unknown): Record<string, unknown> {
47
+ return (d ?? {}) as Record<string, unknown>;
48
+ }
49
+
50
+ export function createProxyHost(opts: ProxyHostOpts): ProxyHost {
51
+ const rtcFactory = opts.rtcFactory ?? ((cfg: RTCConfiguration) => new RTCPeerConnection(cfg));
52
+ const peers = new Map<string, Peer>(); // keyed by client deviceId (`from`)
53
+ const subs = new Set<Sub>();
54
+ const offs: (() => void)[] = [];
55
+
56
+ async function onOffer(d: Record<string, unknown>): Promise<void> {
57
+ const from = String(d['from'] ?? '');
58
+ if (!from) return;
59
+ const sdp = String(d['sdp'] ?? '');
60
+ const origin = String(d['origin'] ?? '');
61
+ if (opts.signer) {
62
+ const ok = await opts.signer.verify('client', parseFingerprint(sdp) ?? '', String(d['fpTag'] ?? ''));
63
+ if (!ok) {
64
+ opts.socket.emit('rtc:error', { to: from, reason: 'fingerprint-auth-failed' });
65
+ return;
66
+ }
67
+ }
68
+ try {
69
+ peers.get(from)?.pc.close();
70
+ } catch {
71
+ /* noop */
72
+ }
73
+ const pc = rtcFactory({ iceServers: opts.iceServers ?? [] });
74
+ const peer: Peer = { pc, dc: null, origin };
75
+ peers.set(from, peer);
76
+
77
+ pc.onicecandidate = (e) => {
78
+ if (e.candidate) opts.socket.emit('rtc:ice', { to: from, candidate: e.candidate.toJSON() });
79
+ };
80
+ pc.ondatachannel = (e) => {
81
+ peer.dc = e.channel;
82
+ e.channel.onmessage = (m: MessageEvent) => void onFrame(peer, e.channel, m.data);
83
+ };
84
+
85
+ await pc.setRemoteDescription({ type: 'offer', sdp });
86
+ const answer = await pc.createAnswer();
87
+ await pc.setLocalDescription(answer);
88
+ const answerSdp = pc.localDescription?.sdp ?? answer.sdp ?? '';
89
+ const tag = opts.signer ? await opts.signer.sign('host', parseFingerprint(answerSdp) ?? '') : undefined;
90
+ opts.socket.emit('rtc:answer', { to: from, sdp: answerSdp, fpTag: tag });
91
+ }
92
+
93
+ async function onIce(d: Record<string, unknown>): Promise<void> {
94
+ const peer = peers.get(String(d['from'] ?? ''));
95
+ if (!peer) return;
96
+ try {
97
+ await peer.pc.addIceCandidate(d['candidate'] as RTCIceCandidateInit);
98
+ } catch {
99
+ /* benign — candidate races */
100
+ }
101
+ }
102
+
103
+ async function onFrame(peer: Peer, dc: RTCDataChannel, raw: unknown): Promise<void> {
104
+ let f: { t?: string; id?: string; channel?: string; payload?: unknown };
105
+ try {
106
+ f = JSON.parse(typeof raw === 'string' ? raw : new TextDecoder().decode(raw as ArrayBuffer));
107
+ } catch {
108
+ return;
109
+ }
110
+ if (f.t === 'req' && f.id !== undefined) {
111
+ try {
112
+ const result = await opts.onInvoke(String(f.channel), f.payload, peer.origin);
113
+ send(dc, { t: 'res', id: f.id, ok: true, result });
114
+ } catch (err) {
115
+ send(dc, { t: 'res', id: f.id, ok: false, error: String((err as Error)?.message ?? err) });
116
+ }
117
+ } else if (f.t === 'sub' && f.id !== undefined) {
118
+ // Register the live subscription; broadcast() fans matching events out.
119
+ // Snapshot is null — the client's panels also pull the current buffer via req.
120
+ subs.add({ dc, event: String(f.channel ?? ''), id: f.id });
121
+ send(dc, { t: 'res', id: f.id, ok: true, result: { snapshot: null } });
122
+ } else if (f.t === 'unsub' && f.id !== undefined) {
123
+ for (const s of [...subs]) if (s.dc === dc && s.id === f.id) subs.delete(s);
124
+ }
125
+ }
126
+
127
+ function send(dc: RTCDataChannel, frame: object): void {
128
+ try {
129
+ if (dc.readyState === 'open') dc.send(JSON.stringify(frame));
130
+ } catch {
131
+ /* channel gone */
132
+ }
133
+ }
134
+
135
+ offs.push(opts.socket.on('rtc:offer', (d) => void onOffer(rec(d))));
136
+ offs.push(opts.socket.on('rtc:ice', (d) => void onIce(rec(d))));
137
+
138
+ return {
139
+ stop(): void {
140
+ for (const off of offs) {
141
+ try {
142
+ off();
143
+ } catch {
144
+ /* noop */
145
+ }
146
+ }
147
+ for (const peer of peers.values()) {
148
+ try {
149
+ peer.pc.close();
150
+ } catch {
151
+ /* noop */
152
+ }
153
+ }
154
+ peers.clear();
155
+ subs.clear();
156
+ },
157
+ broadcast(event: string, data: unknown): void {
158
+ for (const s of subs) if (s.event === event) send(s.dc, { t: 'evt', event, data });
159
+ },
160
+ peerCount: () => peers.size,
161
+ };
162
+ }
@@ -10,15 +10,23 @@ export function magicLinkEmail(
10
10
  url: string,
11
11
  appName: string,
12
12
  expiresMin: number,
13
+ iconUrl?: string,
13
14
  ): { subject: string; html: string; text: string } {
14
15
  const safeAppName = escapeHtml(appName);
16
+ // Only honour absolute https icons — mail clients won't load anything else,
17
+ // and it keeps a hostile relative/`javascript:` value out of the markup.
18
+ const iconImg =
19
+ iconUrl && /^https:\/\//i.test(iconUrl)
20
+ ? `<img src="${escapeHtml(iconUrl)}" alt="" width="56" height="56" style="border-radius:12px;display:block;margin:0 auto 16px">`
21
+ : '';
15
22
  return {
16
23
  subject: `Sign in to ${appName}`,
17
- html: `<!doctype html><html><body style="font-family:system-ui,sans-serif;padding:24px;max-width:480px;margin:auto">
18
- <h2>Sign in to ${safeAppName}</h2>
19
- <p>Click the button below to sign in. This link expires in ${expiresMin} minutes and can only be used once.</p>
20
- <p><a href="${url}" style="background:#000;color:#fff;padding:12px 24px;text-decoration:none;border-radius:6px;display:inline-block">Sign in</a></p>
21
- <p style="color:#888;font-size:12px">If you didn't request this, you can safely ignore this email.</p>
24
+ html: `<!doctype html><html><body style="font-family:system-ui,sans-serif;padding:24px;max-width:480px;margin:auto;text-align:center">
25
+ ${iconImg}
26
+ <h2 style="margin:0 0 12px">Sign in to ${safeAppName}</h2>
27
+ <p style="text-align:left">Click the button below to sign in. This link expires in ${expiresMin} minutes and can only be used once.</p>
28
+ <p><a href="${url}" style="background:#000;color:#fff;padding:12px 24px;text-decoration:none;border-radius:6px;display:inline-block">Sign in to ${safeAppName}</a></p>
29
+ <p style="color:#888;font-size:12px;text-align:left">If you didn't request this, you can safely ignore this email.</p>
22
30
  </body></html>`,
23
31
  text: `Sign in to ${appName}: ${url}\n\nThis link expires in ${expiresMin} minutes.`,
24
32
  };
@@ -38,6 +38,14 @@ const requestBodySchema = z.object({
38
38
  * `window.location.href` so the user resumes wherever they were.
39
39
  */
40
40
  returnTo: z.string().max(2000).optional(),
41
+ /**
42
+ * Optional per-request branding for the email (subject/heading + icon).
43
+ * Used by a central login authority (e.g. ugly.bot) to brand the sign-in
44
+ * email with the CHILD app that triggered the login, rather than the
45
+ * authority's own name. Falls back to the registration-time `appName`.
46
+ */
47
+ appName: z.string().max(120).optional(),
48
+ iconUrl: z.string().url().max(2000).optional(),
41
49
  });
42
50
 
43
51
  const verifyBodySchema = z.object({
@@ -292,7 +300,14 @@ export function registerWorkersMagicLinkRoutes(
292
300
  );
293
301
  }
294
302
 
295
- const tpl = magicLinkEmail(url, appName, expiresMin);
303
+ // Per-request branding (the app that triggered the login) overrides the
304
+ // registration-time default; icon is honoured only if absolute https.
305
+ const reqAppName = parsed.data.appName?.trim() || appName;
306
+ const reqIconUrl =
307
+ parsed.data.iconUrl && /^https:\/\//i.test(parsed.data.iconUrl)
308
+ ? parsed.data.iconUrl
309
+ : undefined;
310
+ const tpl = magicLinkEmail(url, reqAppName, expiresMin, reqIconUrl);
296
311
  let emailError: unknown = null;
297
312
  try {
298
313
  await emailSend({