lucent-pack 0.1.0__py3-none-any.whl
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.
- lucent_pack/__init__.py +3 -0
- lucent_pack/__main__.py +3 -0
- lucent_pack/build.py +244 -0
- lucent_pack/cli.py +119 -0
- lucent_pack/serve.py +41 -0
- lucent_pack/static/lucent/dist/httpuv-sw.d.ts +2 -0
- lucent_pack/static/lucent/dist/httpuv-sw.js +1478 -0
- lucent_pack/static/lucent/dist/httpuv-sw.js.map +1 -0
- lucent_pack/static/lucent/dist/httpuv-web.d.ts +263 -0
- lucent_pack/static/lucent/dist/httpuv-web.js +794 -0
- lucent_pack/static/lucent/dist/httpuv-web.js.map +1 -0
- lucent_pack/static/lucent/dist/rWasmWorker.d.ts +2 -0
- lucent_pack/static/lucent/dist/rWasmWorker.js +1662 -0
- lucent_pack/static/lucent/dist/rWasmWorker.js.map +1 -0
- lucent_pack/static/lucent/dist/runApp.d.ts +8 -0
- lucent_pack/static/lucent/dist/runApp.js +1056 -0
- lucent_pack/static/lucent/dist/runApp.js.map +1 -0
- lucent_pack/static/lucent/dist/shiny-socket.d.ts +53 -0
- lucent_pack/static/lucent/dist/shiny-socket.js +388 -0
- lucent_pack/static/lucent/dist/shiny-socket.js.map +1 -0
- lucent_pack/templates/favicon.svg +7 -0
- lucent_pack/templates/index.html +96 -0
- lucent_pack/templates/style.css +73 -0
- lucent_pack-0.1.0.dist-info/METADATA +90 -0
- lucent_pack-0.1.0.dist-info/RECORD +28 -0
- lucent_pack-0.1.0.dist-info/WHEEL +4 -0
- lucent_pack-0.1.0.dist-info/entry_points.txt +2 -0
- lucent_pack-0.1.0.dist-info/licenses/LICENSE +28 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/httpuv/constants.ts","../src/httpuv/debug.ts","../src/httpuv/shiny-socket.ts"],"names":["payload"],"mappings":"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","file":"shiny-socket.js","sourcesContent":["/** WebSocket frame types used by httpuv (mirrors native httpuv). */\nexport const WS_FRAME = {\n SEND: \"websocket.send\",\n CLOSE: \"websocket.close\",\n} as const;\n\n/** R_HOME inside the mounted wasm prefix (VFS root is /). */\nexport const WASM_R_HOME = \"/lib/R\";\n\n/** Max time the service worker waits for the R worker to answer a request. */\nexport const REQUEST_TIMEOUT_MS = 180_000;\n\n/** Message types exchanged between the service worker and the main page. */\nexport const MSG = {\n REGISTER_HOST: \"httpuv_register_host\",\n HTTP_REQUEST: \"httpuv_http_request\",\n HTTP_RESPONSE: \"httpuv_http_response\",\n WS_PUSH: \"httpuv_ws_push\",\n /** Iframe → SW (on session port): frame delivered to Shiny.createSocket. */\n WS_PUSH_ACK: \"httpuv_ws_push_ack\",\n STOP: \"httpuv_stop\",\n /** Drop cached GET /shiny/ without tearing down the R worker (app restart). */\n CLEAR_APP_CACHE: \"httpuv_clear_app_cache\",\n /** Host -> SW: full shiny::resourcePaths() map (warmup). */\n REGISTER_RESOURCE_PATHS: \"httpuv_register_resource_paths\",\n /** Host -> SW: upsert or remove one addResourcePath prefix (empty dir removes). */\n UPDATE_RESOURCE_PATH: \"httpuv_update_resource_path\",\n /** SW -> host: Comlink to the R worker was lost (e.g. after SW update). */\n REQUEST_COMLINK: \"httpuv_request_comlink\",\n /** Iframe → SW: transfer a MessagePort for session WS push delivery. */\n REGISTER_SESSION: \"httpuv_register_session\",\n /** SW → iframe (on session port): registration accepted. */\n SESSION_ACK: \"httpuv_session_ack\",\n /** SW → iframe client: session MessagePort was lost (e.g. SW idle restart); re-REGISTER_SESSION. */\n REQUEST_SESSION_PORT: \"httpuv_request_session_port\",\n} as const;\n\n/** Bypass SW app-document cache (warmup must hit R so deps register). */\nexport const WARMUP_REQUEST_HEADER = \"X-Shiny-Forge-Warmup\";\n\n/** Message types on Module.httpuv.channel (R <-> JS bridge). */\nexport const CHANNEL = {\n HTTP_REQUEST: \"httpuv_http_request\",\n TCP_RESPONSE: \"httpuv_tcp_response\",\n WS_OPEN: \"httpuv_ws_open\",\n WS_MESSAGE: \"httpuv_ws_message\",\n WS_CLOSE: \"httpuv_ws_close\",\n WS_RESPONSE: \"httpuv_ws_response\",\n STDIN: \"stdin\",\n} as const;\n\n/** R option names registered by httpuv::startServer(). */\nexport const HTTPUV_OPTIONS = {\n ON_REQUEST: \"httpuv_onRequest\",\n ON_WS_OPEN: \"httpuv_onWSOpen\",\n ON_WS_MESSAGE: \"httpuv_onWSMessage\",\n ON_WS_CLOSE: \"httpuv_onWSClose\",\n} as const;\n\n/** Comlink MessagePort handshake between host page, service worker, and R worker. */\nexport const COMLINK = {\n PORT_HANDOFF: \"httpuv_comlink_port\",\n /**\n * SW -> host: the handoff port arrived. Sent before the Comlink round-trip so\n * the host can distinguish a dropped handoff (worker evicted mid-boot) from an\n * R worker that never finished setup.\n */\n PORT_HANDOFF_ACK: \"httpuv_comlink_port_ack\",\n} as const;\n","/**\n * Opt-in tracing for the httpuv / Shiny-Forge request pipeline.\n *\n * Enable with either:\n * - URL query: ?httpuvDebug=1\n * - localStorage: localStorage.shinyForgeDebug = \"1\"\n * - console: shinyForge.enableHttpuvDebug()\n */\nexport function isHttpuvDebug(): boolean {\n if (globalThis.__HTTPUV_DEBUG__) {\n return true;\n }\n try {\n if (typeof location !== \"undefined\") {\n const params = new URLSearchParams(location.search);\n if (params.has(\"httpuvDebug\") || params.get(\"debug\") === \"httpuv\") {\n return true;\n }\n }\n if (typeof localStorage !== \"undefined\" && localStorage.getItem(\"shinyForgeDebug\") === \"1\") {\n return true;\n }\n if (typeof self !== \"undefined\" && self.location?.href) {\n const params = new URL(self.location.href).searchParams;\n if (params.has(\"httpuvDebug\") || params.get(\"debug\") === \"httpuv\") {\n return true;\n }\n }\n } catch {\n // ignore\n }\n return false;\n}\n\nexport function httpuvDebugLog(stage: string, ...args: unknown[]): void {\n if (!isHttpuvDebug()) {\n return;\n }\n console.info(`[httpuv-debug:${stage}]`, ...args);\n}\n\nexport function enableHttpuvDebug(): void {\n globalThis.__HTTPUV_DEBUG__ = true;\n try {\n localStorage.setItem(\"shinyForgeDebug\", \"1\");\n } catch {\n // ignore\n }\n console.info(\n \"[httpuv-debug] enabled - reload or run shinyForge.enableHttpuvDebug() then re-run app\",\n );\n}\n","/**\n * Virtual WebSocket for Shiny in the browser.\n * Loaded as a module in the Shiny app iframe; overrides Shiny.createSocket.\n *\n * Server→client frames arrive on a dedicated MessagePort registered with the\n * httpuv service worker (no recv long-poll). open/send/close still use fetch.\n *\n * After the browser stops the SW while idle, the port is gone but the socket\n * stays logically open: we re-REGISTER_SESSION on send, visibilitychange, and\n * when the SW asks via REQUEST_SESSION_PORT.\n */\n\nimport { MSG, WS_FRAME } from \"./constants\";\nimport { httpuvDebugLog } from \"./debug\";\n\n/** How long to wait for SESSION_ACK after REGISTER_SESSION. */\nconst SESSION_REGISTER_TIMEOUT_MS = 5_000;\n\n/** After this gap with no SW→iframe push, the next send() force-registers. */\nconst SESSION_PORT_STALE_MS = 15_000;\n\n/** Build an absolute session URL under the Shiny app prefix. */\nfunction sessionUrl(action: string, opts: { handle?: string } = {}): string {\n const base = new URL(\"__session__/\", location.href);\n const url = new URL(action.replace(/^\\//, \"\"), base);\n if (opts.handle) {\n url.searchParams.set(\"handle\", opts.handle);\n }\n return url.href;\n}\n\ntype SessionPortMessage = {\n type?: string;\n handle?: string;\n wsType?: string;\n binary?: boolean;\n message?: unknown;\n pushId?: number;\n};\n\nconst socketsByHandle = new Map<string, VirtualShinySocket>();\n\n/** Minimal WebSocket stand-in using session fetch + MessagePort push delivery. */\nexport class VirtualShinySocket {\n static readonly CONNECTING = 0;\n static readonly OPEN = 1;\n static readonly CLOSING = 2;\n static readonly CLOSED = 3;\n\n readyState: number = VirtualShinySocket.CONNECTING;\n binaryType: BinaryType = \"arraybuffer\";\n\n private _handle: string | null = null;\n private _active = false;\n private _port: MessagePort | null = null;\n private _registering: Promise<void> | null = null;\n /** Last time a WS_PUSH arrived — used to detect orphaned ports after SW idle kill. */\n private _lastPushAt = 0;\n\n onopen: ((event: Event) => void) | null = null;\n onmessage: ((event: MessageEvent) => void) | null = null;\n onclose: ((event: CloseEvent) => void) | null = null;\n onerror: ((event: Event) => void) | null = null;\n\n constructor() {\n void this._connect();\n }\n\n private async _connect(): Promise<void> {\n try {\n const openUrl = sessionUrl(\"open\");\n httpuvDebugLog(\"socket-open\", openUrl);\n const res = await fetch(openUrl, { method: \"POST\" });\n if (!res.ok) {\n throw new Error(`session open failed: HTTP ${res.status}`);\n }\n const { handle } = (await res.json()) as { handle?: string };\n if (!handle) {\n throw new Error(\"session open response missing handle\");\n }\n this._handle = String(handle);\n this.readyState = VirtualShinySocket.OPEN;\n this._active = true;\n socketsByHandle.set(this._handle, this);\n\n await this.ensurePort();\n\n this.onopen?.(new Event(\"open\"));\n } catch (err) {\n console.error(\"[shiny-socket] connect failed\", err);\n this._teardownPort();\n this.readyState = VirtualShinySocket.CLOSED;\n this.onerror?.(new Event(\"error\"));\n this.onclose?.(new CloseEvent(\"close\", { code: 1006, wasClean: false }));\n }\n }\n\n /**\n * Ensure the SW has a live MessagePort for this session.\n * Safe to call repeatedly after idle SW restarts.\n * @param force when true, replace any existing port (recovery / stale paths).\n * Ordinary rapid send() must not force — re-registering mid-flight drops\n * SW→iframe frames on Chromium. After idle, force once so a dead port\n * (SW stopped, client still holds MessagePort) is replaced before replies.\n */\n ensurePort(force = false): Promise<void> {\n if (!this._active || !this._handle) {\n return Promise.resolve();\n }\n if (!force && this._port) {\n return Promise.resolve();\n }\n if (this._registering) {\n return this._registering;\n }\n this._registering = this._registerSessionPort(this._handle).finally(() => {\n this._registering = null;\n });\n return this._registering;\n }\n\n /** Hand a MessagePort to the SW and wait for SESSION_ACK. */\n private async _registerSessionPort(handle: string): Promise<void> {\n const controller = navigator.serviceWorker?.controller;\n if (!controller) {\n throw new Error(\"no service worker controller for session port\");\n }\n\n if (this._port) {\n try {\n this._port.close();\n } catch {\n // ignore\n }\n this._port = null;\n }\n\n const channel = new MessageChannel();\n this._port = channel.port1;\n\n const acked = new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error(\"session port registration timed out\"));\n }, SESSION_REGISTER_TIMEOUT_MS);\n\n this._port!.onmessage = (event: MessageEvent<SessionPortMessage>) => {\n const data = event.data;\n if (data?.type === MSG.SESSION_ACK) {\n clearTimeout(timer);\n this._port!.onmessage = (ev) => this._onPortMessage(ev);\n resolve();\n return;\n }\n this._onPortMessage(event);\n };\n\n this._port!.onmessageerror = () => {\n clearTimeout(timer);\n reject(new Error(\"session port messageerror\"));\n };\n });\n\n httpuvDebugLog(\"socket-register-session\", { handle });\n controller.postMessage({ type: MSG.REGISTER_SESSION, handle }, [channel.port2]);\n await acked;\n }\n\n private _ackPush(pushId: number | undefined): void {\n if (typeof pushId !== \"number\" || !this._port) {\n return;\n }\n try {\n this._port.postMessage({ type: MSG.WS_PUSH_ACK, pushId });\n } catch (err) {\n console.warn(\"[shiny-socket] WS_PUSH_ACK failed\", err);\n }\n }\n\n private _onPortMessage(event: MessageEvent<SessionPortMessage>): void {\n if (!this._active) {\n return;\n }\n const data = event.data;\n if (!data || typeof data !== \"object\") {\n return;\n }\n\n if (data.type !== MSG.WS_PUSH && data.wsType == null && data.message === undefined) {\n return;\n }\n\n const wsType = data.wsType ?? WS_FRAME.SEND;\n if (wsType === WS_FRAME.CLOSE) {\n let code = 1000;\n let reason = \"\";\n try {\n const raw = data.message;\n if (typeof raw === \"string\" && raw) {\n const payload = JSON.parse(raw) as { code?: number; reason?: string };\n code = Number(payload.code ?? code);\n reason = String(payload.reason ?? \"\");\n }\n } catch {\n // ignore malformed close payloads\n }\n this._ackPush(data.pushId);\n this._finishClose(code, reason, true);\n return;\n }\n\n const binary = Boolean(data.binary);\n let payload: string | ArrayBuffer;\n if (binary) {\n if (data.message instanceof ArrayBuffer) {\n payload = data.message;\n } else if (ArrayBuffer.isView(data.message)) {\n const view = data.message;\n payload = view.buffer.slice(\n view.byteOffset,\n view.byteOffset + view.byteLength,\n ) as ArrayBuffer;\n } else if (typeof data.message === \"string\") {\n payload = data.message;\n } else {\n payload = new ArrayBuffer(0);\n }\n } else if (typeof data.message === \"string\") {\n payload = data.message;\n } else if (data.message instanceof ArrayBuffer) {\n payload = new TextDecoder().decode(data.message);\n } else if (ArrayBuffer.isView(data.message)) {\n payload = new TextDecoder().decode(data.message);\n } else {\n payload = String(data.message ?? \"\");\n }\n\n const bytes = typeof payload === \"string\" ? payload.length : payload.byteLength;\n httpuvDebugLog(\"socket-recv\", {\n wsType,\n binary,\n bytes,\n });\n this._lastPushAt = Date.now();\n this.onmessage?.(new MessageEvent(\"message\", { data: payload }));\n this._ackPush(data.pushId);\n }\n\n private _teardownPort(): void {\n this._active = false;\n if (this._handle) {\n socketsByHandle.delete(this._handle);\n }\n if (this._port) {\n try {\n this._port.close();\n } catch {\n // ignore\n }\n this._port = null;\n }\n }\n\n send(data: string | ArrayBuffer | ArrayBufferView): void {\n if (this.readyState !== VirtualShinySocket.OPEN || !this._handle) {\n throw new Error(\"WebSocket is not open\");\n }\n\n let body: string | ArrayBuffer;\n let byteLen: number;\n let isBinary: boolean;\n if (typeof data === \"string\") {\n body = data;\n byteLen = data.length;\n isBinary = false;\n } else if (data instanceof ArrayBuffer) {\n body = data;\n byteLen = data.byteLength;\n isBinary = true;\n } else {\n body = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer;\n byteLen = data.byteLength;\n isBinary = true;\n }\n\n const handle = this._handle;\n const sendUrl = sessionUrl(\"send\", { handle });\n httpuvDebugLog(\"socket-send\", sendUrl, {\n binary: isBinary,\n bytes: byteLen,\n });\n\n // After Chromium idle-stops the SW, this._port is orphaned but non-null.\n // Force re-register once when we have been idle; keep the port stable during\n // a reply storm (recent pushes keep _lastPushAt fresh).\n const stale =\n !this._port ||\n !this._lastPushAt ||\n Date.now() - this._lastPushAt > SESSION_PORT_STALE_MS;\n void this.ensurePort(stale)\n .catch((err) => {\n console.warn(\"[shiny-socket] ensurePort before send failed\", err);\n })\n .then(() =>\n fetch(sendUrl, {\n method: \"POST\",\n headers: isBinary ? {} : { \"Content-Type\": \"text/plain; charset=UTF-8\" },\n body,\n }),\n )\n .catch((err) => {\n console.error(\"[shiny-socket] send failed\", err);\n });\n }\n\n close(code = 1000, reason = \"\"): void {\n if (\n this.readyState === VirtualShinySocket.CLOSED ||\n this.readyState === VirtualShinySocket.CLOSING\n ) {\n return;\n }\n this.readyState = VirtualShinySocket.CLOSING;\n const handle = this._handle;\n this._active = false;\n if (handle) {\n const closeUrl = sessionUrl(\"close\", { handle });\n void fetch(closeUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ code, reason }),\n }).catch((err) => {\n console.error(\"[shiny-socket] close failed\", err);\n });\n }\n this._finishClose(code, reason, true);\n }\n\n private _finishClose(code: number, reason: string, wasClean: boolean): void {\n if (this.readyState === VirtualShinySocket.CLOSED) {\n return;\n }\n this._teardownPort();\n this.readyState = VirtualShinySocket.CLOSED;\n this.onclose?.(new CloseEvent(\"close\", { code, reason, wasClean }));\n }\n}\n\nfunction reregisterAllSockets(): void {\n for (const sock of socketsByHandle.values()) {\n void sock.ensurePort(true).catch((err) => {\n console.warn(\"[shiny-socket] ensurePort failed\", err);\n });\n }\n}\n\nfunction installSessionPortRecovery(): void {\n if (typeof navigator === \"undefined\" || !navigator.serviceWorker) {\n return;\n }\n navigator.serviceWorker.addEventListener(\"message\", (event: MessageEvent) => {\n const data = event.data as { type?: string; handle?: string } | null;\n if (!data || data.type !== MSG.REQUEST_SESSION_PORT) {\n return;\n }\n const handle = data.handle ? String(data.handle) : \"\";\n const sock = handle ? socketsByHandle.get(handle) : undefined;\n if (sock) {\n void sock.ensurePort(true).catch((err) => {\n console.warn(\"[shiny-socket] REQUEST_SESSION_PORT ensurePort failed\", err);\n });\n return;\n }\n reregisterAllSockets();\n });\n\n document.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"visible\") {\n reregisterAllSockets();\n }\n });\n\n navigator.serviceWorker.addEventListener(\"controllerchange\", () => {\n reregisterAllSockets();\n });\n}\n\n/** Install VirtualShinySocket as Shiny.createSocket (call before Shiny connects). */\nexport function installVirtualShinySocket(): void {\n const factory = () => new VirtualShinySocket();\n\n const apply = () => {\n if (typeof globalThis.Shiny === \"object\" && globalThis.Shiny !== null) {\n globalThis.Shiny.createSocket = factory;\n } else {\n globalThis.Shiny = { createSocket: factory };\n }\n };\n\n apply();\n document.addEventListener(\"DOMContentLoaded\", apply, { once: true });\n installSessionPortRecovery();\n httpuvDebugLog(\"shiny-socket-installed\");\n}\n\ninstallVirtualShinySocket();\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="m16 27.2c-8.56 0-15.5-4.65-15.5-10.3 0-5.74 6.93-10.3 15.5-10.3 8.57 0 15.5 4.65 15.5 10.3 0 5.74-6.93 10.3-15.5 10.3zm2.38-16.6c-6.51 0-11.8 3.17-11.8 7.1 0 3.93 5.27 7.1 11.8 7.1 6.51 0 11.4-2.17 11.4-7.1 0-4.92-4.8-7.1-11.4-7.1z" fill="#808080" fill-opacity=".5"/>
|
|
3
|
+
<path d="m24.2 22.5s0.937 0.283 1.48 0.559c0.189 0.0957 0.516 0.286 0.752 0.537 0.231 0.245 0.344 0.494 0.344 0.494l3.7 6.22-5.97 0.0027-2.79-5.25s-0.572-0.978-0.924-1.27c-0.293-0.238-0.418-0.322-0.709-0.322h-1.43l0.0011 6.83-5.29 0.0023v-17.5h10.6s4.84 0.0871 4.84 4.69c0 4.6-4.62 4.94-4.62 4.94zm-2.29-5.84-3.19-0.0021-0.0015 2.97 3.2-1e-3s1.48-0.0045 1.48-1.51c0-1.54-1.48-1.46-1.48-1.46z" fill="#3f82d5"/>
|
|
4
|
+
<path d="m13.6 7.99-3.7-1.26-1.05-4.17c-0.0775-0.309-0.355-0.527-0.674-0.527-0.318 0-0.596 0.218-0.674 0.527l-1.05 4.17-3.7 1.26c-0.281 0.096-0.47 0.361-0.47 0.658 0 0.297 0.189 0.562 0.47 0.658l3.7 1.26 1.05 4.17c0.0775 0.309 0.355 0.527 0.674 0.527 0.318 0 0.596-0.218 0.674-0.527l1.05-4.17 3.7-1.26c0.281-0.096 0.47-0.361 0.47-0.658 0-0.297-0.189-0.562-0.47-0.658z" fill="#fdc31d"/>
|
|
5
|
+
<path d="m27.7 6.88-2.15-0.739-0.611-2.45c-0.0454-0.182-0.209-0.308-0.394-0.308s-0.35 0.127-0.394 0.308l-0.611 2.45-2.15 0.739c-0.164 0.0563-0.275 0.21-0.275 0.384s0.111 0.33 0.275 0.384l2.15 0.739 0.611 2.45c0.0454 0.182 0.209 0.308 0.394 0.308s0.35-0.127 0.394-0.308l0.611-2.45 2.15-0.739c0.164-0.0563 0.275-0.21 0.275-0.384s-0.111-0.33-0.275-0.384z" fill="#ffd639"/>
|
|
6
|
+
<path d="m9.06 25.4-1.18-0.405-0.336-1.34c-0.0248-0.0992-0.114-0.169-0.216-0.169-0.102 0-0.191 0.0696-0.216 0.169l-0.336 1.34-1.18 0.405c-0.0903 0.0309-0.15 0.116-0.15 0.212 0 0.0955 0.0607 0.18 0.15 0.212l1.18 0.405 0.336 1.34c0.0248 0.0992 0.114 0.169 0.216 0.169 0.102 0 0.191-0.0696 0.216-0.169l0.336-1.34 1.18-0.405c0.0903-0.0309 0.15-0.116 0.15-0.212 0-0.0955-0.0607-0.18-0.15-0.212z" fill="#fbaf00"/>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>{{ title }}</title>
|
|
7
|
+
<link rel="icon" href="favicon.svg" type="image/svg+xml">
|
|
8
|
+
<link rel="stylesheet" href="style.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
|
|
12
|
+
<div id="boot-overlay" class="boot-overlay" aria-live="polite">
|
|
13
|
+
<h3 id="boot-title">Starting</h3>
|
|
14
|
+
<progress id="progress" value="0" max="100"></progress>
|
|
15
|
+
<div id="status">Starting…</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<main class="app-layout">
|
|
19
|
+
<iframe
|
|
20
|
+
id="app-frame"
|
|
21
|
+
class="app-frame"
|
|
22
|
+
title="Viewer"
|
|
23
|
+
sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-downloads allow-popups-to-escape-sandbox"
|
|
24
|
+
></iframe>
|
|
25
|
+
</main>
|
|
26
|
+
<script>
|
|
27
|
+
// Resolve against the site root so project GitHub Pages mounts
|
|
28
|
+
// (username.github.io/repo/) work without absolute "/..." paths.
|
|
29
|
+
const siteRoot = new URL("./", window.location.href);
|
|
30
|
+
globalThis.__LUCENT__ = {
|
|
31
|
+
transportBaseUrl: new URL("lucent/dist/", siteRoot).href,
|
|
32
|
+
serviceWorkerUrl: new URL("httpuv-sw.js", siteRoot).href,
|
|
33
|
+
rRuntimeBaseUrl: new URL("runtime/", siteRoot).href,
|
|
34
|
+
empackMetaUrl: new URL("packages/empack_env_meta.json", siteRoot).href,
|
|
35
|
+
empackPackagesBaseUrl: new URL("packages/", siteRoot).href,
|
|
36
|
+
shinyBaseUrl: siteRoot.href,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const title = document.getElementById("boot-title");
|
|
40
|
+
const progress = document.getElementById("progress");
|
|
41
|
+
const status = document.getElementById("status");
|
|
42
|
+
const overlay = document.getElementById("boot-overlay");
|
|
43
|
+
|
|
44
|
+
const PHASE_TITLES = {
|
|
45
|
+
"load-runtime": "Loading runtime",
|
|
46
|
+
download: "Loading packages",
|
|
47
|
+
filesystem: "Preparing filesystem",
|
|
48
|
+
"init-r": "Initializing R",
|
|
49
|
+
"load-httpuv": "Loading packages",
|
|
50
|
+
"start-app": "Starting Shiny",
|
|
51
|
+
warmup: "Warming up",
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Map download % into the overall boot bar (download is ~5–60%).
|
|
55
|
+
function downloadOverallPercent(downloadPercent) {
|
|
56
|
+
if (downloadPercent == null) return null;
|
|
57
|
+
return 5 + (downloadPercent / 100) * 55;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
window.addEventListener("lucent:boot-status", (event) => {
|
|
61
|
+
const { phase, message, percent } = event.detail;
|
|
62
|
+
title.textContent = PHASE_TITLES[phase] ?? "Starting";
|
|
63
|
+
status.textContent = message;
|
|
64
|
+
if (percent != null) {
|
|
65
|
+
progress.value = percent;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
window.addEventListener("lucent:download-progress", (event) => {
|
|
70
|
+
const { percent, downloadedBytes, totalBytes } = event.detail;
|
|
71
|
+
title.textContent = PHASE_TITLES.download;
|
|
72
|
+
const overall = downloadOverallPercent(percent);
|
|
73
|
+
if (overall != null) {
|
|
74
|
+
progress.value = overall;
|
|
75
|
+
}
|
|
76
|
+
status.textContent =
|
|
77
|
+
`Loading packages… ${(downloadedBytes / 1024 / 1024).toFixed(1)} MB / ` +
|
|
78
|
+
`${(totalBytes / 1024 / 1024).toFixed(1)} MB ` +
|
|
79
|
+
`(${percent == null ? "?" : percent.toFixed(1)}%)`;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
window.addEventListener("lucent:ready", () => {
|
|
83
|
+
title.textContent = "Ready";
|
|
84
|
+
progress.value = 100;
|
|
85
|
+
status.textContent = "Ready";
|
|
86
|
+
overlay.hidden = true;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
window.addEventListener("lucent:error", (event) => {
|
|
90
|
+
status.textContent = `Error: ${event.detail?.message ?? "failed to start"}`;
|
|
91
|
+
overlay.classList.add("boot-overlay--error");
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
<script type="module" src="./lucent/dist/runApp.js"></script>
|
|
95
|
+
</body>
|
|
96
|
+
</html>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* Lucent CSS */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--background: hsl(218, 81%, 6%);
|
|
5
|
+
--text: hsl(96, 71%, 99%);
|
|
6
|
+
--text-error: hsl(351, 70%, 70%);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@media (prefers-color-scheme: light) {
|
|
10
|
+
:root {
|
|
11
|
+
--background: hsl(96, 71%, 99%);
|
|
12
|
+
--text: hsl(218, 81%, 6%);
|
|
13
|
+
--text-error:hsl(351, 50%, 40%);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
html,
|
|
18
|
+
body {
|
|
19
|
+
height: 100%;
|
|
20
|
+
margin: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
body {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
background: var(--background);
|
|
27
|
+
color: var(--text);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.boot-overlay {
|
|
31
|
+
position: fixed;
|
|
32
|
+
inset: 0;
|
|
33
|
+
z-index: 10;
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
gap: 0.75rem;
|
|
39
|
+
background: var(--background);
|
|
40
|
+
color: var(--text);
|
|
41
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.boot-overlay[hidden] {
|
|
45
|
+
display: none;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.boot-overlay h3 {
|
|
49
|
+
margin: 0;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.boot-overlay progress {
|
|
54
|
+
width: min(400px, 80vw);
|
|
55
|
+
height: 0.85rem;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.boot-overlay--error #status {
|
|
59
|
+
color: var(--text-error);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.app-layout {
|
|
63
|
+
flex: 1 1 auto;
|
|
64
|
+
display: flex;
|
|
65
|
+
min-height: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.app-frame {
|
|
69
|
+
flex: 1 1 auto;
|
|
70
|
+
width: 100%;
|
|
71
|
+
min-height: 0;
|
|
72
|
+
border: none;
|
|
73
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: lucent-pack
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pack a Shiny app and a WebAssembly R environment into a static Lucent site
|
|
5
|
+
Project-URL: Homepage, https://github.com/IsabelParedes/lucent-pack
|
|
6
|
+
Project-URL: Repository, https://github.com/IsabelParedes/lucent-pack
|
|
7
|
+
Author: Isabel Paredes
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: emscripten,lucent,r,shiny,wasm
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: empack<7,>=6
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Lucent-Pack
|
|
22
|
+
|
|
23
|
+
Pack a Shiny app and a WebAssembly R environment into a static site.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install lucent-pack
|
|
29
|
+
# OR
|
|
30
|
+
micromamba install lucent-pack
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
1. Create a wasm environment with your favorite package manager.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
micromamba create -f environment.yaml --platform=emscripten-wasm32
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
# Sample environment.yaml
|
|
43
|
+
name: shinyapp-env
|
|
44
|
+
channels:
|
|
45
|
+
- https://repo.prefix.dev/emscripten-forge-4x
|
|
46
|
+
- conda-forge
|
|
47
|
+
dependencies:
|
|
48
|
+
# Minimum requirements
|
|
49
|
+
- r-main
|
|
50
|
+
- r-shiny
|
|
51
|
+
# Any additional packages required for the app
|
|
52
|
+
- r-bslib
|
|
53
|
+
- r-plotly
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
2. Build the site.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
lucent build --prefix-dir /path/to/wasm/env/ --app /path/to/app --outdir ./_site
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
3. Check results.
|
|
63
|
+
```bash
|
|
64
|
+
lucent serve ./_site # the output directory
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Development
|
|
68
|
+
|
|
69
|
+
Requirements:
|
|
70
|
+
- python
|
|
71
|
+
- pip
|
|
72
|
+
- nodejs
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install -e .
|
|
76
|
+
|
|
77
|
+
# Browser runtime — required before `python -m build` (wheel)
|
|
78
|
+
cd js && npm ci && npm run build
|
|
79
|
+
mkdir -p ../src/lucent_pack/static/lucent/dist
|
|
80
|
+
cp -a dist/. ../src/lucent_pack/static/lucent/dist/
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The hatch wheel hook fails the build if the bundles (`src/lucent_pack/static/lucent/dist/`) are missing.
|
|
84
|
+
|
|
85
|
+
## CLI
|
|
86
|
+
|
|
87
|
+
| Command | Purpose |
|
|
88
|
+
|---------|---------|
|
|
89
|
+
| `lucent build` | Pack an existing `--prefix-dir` + `--app` into `--outdir` |
|
|
90
|
+
| `lucent serve` | Serve a built site directory (`python -m http.server` style) |
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
lucent_pack/__init__.py,sha256=8phLoMx1VLWfK0rTOHAuw3QqHjvIoAk3gu-PsPhPcLc,102
|
|
2
|
+
lucent_pack/__main__.py,sha256=Pv45l9mrwTtFGqggAhEbu0_c01HTVD8JCJ39Bv5nqvo,59
|
|
3
|
+
lucent_pack/build.py,sha256=n8kJNgOA3irBwgdLvKSeFmvgT15sATPGocZMCUaNLlA,7759
|
|
4
|
+
lucent_pack/cli.py,sha256=C2qmG8kDa338U4Z5f1Td3e-IkOu3tADv5f-BL5aQvDc,3057
|
|
5
|
+
lucent_pack/serve.py,sha256=6YXbs_Vjca69FcpK1hus1W_HPVDnUbok772GvipaEEw,1402
|
|
6
|
+
lucent_pack/templates/favicon.svg,sha256=omoxODxdOSnQW-8kg7Pmx_Xr3_g2eNu3GTCQZjV0kX0,1952
|
|
7
|
+
lucent_pack/templates/index.html,sha256=5C2_TBsL6TTvPj_OxdpbUav7kMZyjDBHsTM0R0JQLKo,3620
|
|
8
|
+
lucent_pack/templates/style.css,sha256=i8kvSdYN-_XBANFJ16dvAxaLAMxF90njYdlg9BzcnCM,1208
|
|
9
|
+
lucent_pack/static/lucent/dist/httpuv-sw.d.ts,sha256=bKoLBL3BBYKjcp2ukkTyHFvsC5_-fiqEmZwvho9d2b4,13
|
|
10
|
+
lucent_pack/static/lucent/dist/httpuv-sw.js,sha256=XLYxK5ta9T5FjszdQbg1KPUb4YmEf3M4JKJ8_pubN2w,44885
|
|
11
|
+
lucent_pack/static/lucent/dist/httpuv-sw.js.map,sha256=CM5gGw_BBeaeHxdKCC_NnNnPSWhtsbfrsnmKvAao6Yo,115207
|
|
12
|
+
lucent_pack/static/lucent/dist/httpuv-web.d.ts,sha256=NqAgf2szc0wmxjYU1Rzo7KZTEXK0GXPPmyrPUaRHeEs,12358
|
|
13
|
+
lucent_pack/static/lucent/dist/httpuv-web.js,sha256=J1qEA9Uh0r6QjigjdEdinmCuEuNHq7_WgnhsAIYaOdE,23732
|
|
14
|
+
lucent_pack/static/lucent/dist/httpuv-web.js.map,sha256=W9aEOR1T8KwqJ80uFSU_cgd1jJzRNSxL9e_X29ZXzc4,53940
|
|
15
|
+
lucent_pack/static/lucent/dist/rWasmWorker.d.ts,sha256=bKoLBL3BBYKjcp2ukkTyHFvsC5_-fiqEmZwvho9d2b4,13
|
|
16
|
+
lucent_pack/static/lucent/dist/rWasmWorker.js,sha256=pBcbMOhJjHYy2Hs6KGk01AS3QMZCwWWaYJjliw1PdqQ,49727
|
|
17
|
+
lucent_pack/static/lucent/dist/rWasmWorker.js.map,sha256=PhbZHp0YPOs2wR3-Ku2ZwcGj6urBDQ3yJ2XHQ9ld_9w,140859
|
|
18
|
+
lucent_pack/static/lucent/dist/runApp.d.ts,sha256=mn_DLDD8CaAL-SWf2Dc6XXHF0CiLPFmZ0uWMd_oHO9g,284
|
|
19
|
+
lucent_pack/static/lucent/dist/runApp.js,sha256=KuV2GoJkzONP23msEKlYMjdvAt8GYaFsujN-hvbcCcI,33332
|
|
20
|
+
lucent_pack/static/lucent/dist/runApp.js.map,sha256=XU02IRQaUXNH_AE8P4LLz2n8XvIePvJyyBokt1K3x1o,87691
|
|
21
|
+
lucent_pack/static/lucent/dist/shiny-socket.d.ts,sha256=WEha01TBvZYQzf7k4pgI9v0ttTFTAMYn14Ypep2fwRk,2264
|
|
22
|
+
lucent_pack/static/lucent/dist/shiny-socket.js,sha256=BBI4WDwDinUzIbBcgVzH1T0RkCOitz21NqkV-PCaxbw,12689
|
|
23
|
+
lucent_pack/static/lucent/dist/shiny-socket.js.map,sha256=HZGv6o8_6aqeADXp5ENTGtT-6QeoYv5h3XzkP7td6Ls,30150
|
|
24
|
+
lucent_pack-0.1.0.dist-info/METADATA,sha256=QNkt2LdMb9LP3wUIROmTLyfbqTVaPVojGIf42e_xb68,2141
|
|
25
|
+
lucent_pack-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
26
|
+
lucent_pack-0.1.0.dist-info/entry_points.txt,sha256=jYmCozPgj7CD-T2_z1KXmIk5aw47jDey71DQhdzy9TU,48
|
|
27
|
+
lucent_pack-0.1.0.dist-info/licenses/LICENSE,sha256=HMhLU8QNHc9SWGhCQeG_AtBxiNCINK0a1ShYOTa3ML8,1501
|
|
28
|
+
lucent_pack-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Isabel Paredes
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|