@appstrata/dev 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -0
- package/dist/completion-notification.d.ts +22 -0
- package/dist/completion-notification.d.ts.map +1 -0
- package/dist/completion-notification.js +184 -0
- package/dist/completion-notification.js.map +1 -0
- package/dist/dev-overlay.css +450 -0
- package/dist/dev-overlay.d.ts +56 -0
- package/dist/dev-overlay.d.ts.map +1 -0
- package/dist/dev-overlay.js +371 -0
- package/dist/dev-overlay.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/intercepting-transport.d.ts +11 -0
- package/dist/intercepting-transport.d.ts.map +1 -0
- package/dist/intercepting-transport.js +31 -0
- package/dist/intercepting-transport.js.map +1 -0
- package/dist/load-config.d.ts +42 -0
- package/dist/load-config.d.ts.map +1 -0
- package/dist/load-config.js +87 -0
- package/dist/load-config.js.map +1 -0
- package/dist/logging-hmr.d.ts +20 -0
- package/dist/logging-hmr.d.ts.map +1 -0
- package/dist/logging-hmr.js +28 -0
- package/dist/logging-hmr.js.map +1 -0
- package/dist/mock-init.d.ts +9 -0
- package/dist/mock-init.d.ts.map +1 -0
- package/dist/mock-init.js +171 -0
- package/dist/mock-init.js.map +1 -0
- package/dist/mock-player.d.ts +117 -0
- package/dist/mock-player.d.ts.map +1 -0
- package/dist/mock-player.js +132 -0
- package/dist/mock-player.js.map +1 -0
- package/dist/mock-services.d.ts +32 -0
- package/dist/mock-services.d.ts.map +1 -0
- package/dist/mock-services.js +141 -0
- package/dist/mock-services.js.map +1 -0
- package/dist/player/index.html +22 -0
- package/dist/player/main.d.ts +10 -0
- package/dist/player/main.d.ts.map +1 -0
- package/dist/player/main.js +352 -0
- package/dist/player/main.js.map +1 -0
- package/dist/player/styles.css +80 -0
- package/dist/plugin.d.ts +103 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +292 -0
- package/dist/plugin.js.map +1 -0
- package/dist/types.d.ts +376 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +75 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock implementations of capability services for development.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create an in-memory mock storage service.
|
|
6
|
+
*
|
|
7
|
+
* Data is stored in a Map and persists only for the current page session.
|
|
8
|
+
* Refreshing the page clears all storage.
|
|
9
|
+
*/
|
|
10
|
+
export function createMockStorage() {
|
|
11
|
+
const storage = new Map();
|
|
12
|
+
return {
|
|
13
|
+
async get(key) {
|
|
14
|
+
return storage.get(key);
|
|
15
|
+
},
|
|
16
|
+
async set(key, value) {
|
|
17
|
+
storage.set(key, value);
|
|
18
|
+
},
|
|
19
|
+
async remove(key) {
|
|
20
|
+
storage.delete(key);
|
|
21
|
+
},
|
|
22
|
+
async list() {
|
|
23
|
+
return Array.from(storage.keys());
|
|
24
|
+
},
|
|
25
|
+
async clear() {
|
|
26
|
+
storage.clear();
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Create a passthrough mock proxy service.
|
|
32
|
+
*
|
|
33
|
+
* Uses native fetch directly. In dev mode, Vite's dev server can be configured
|
|
34
|
+
* to proxy API requests if CORS is an issue.
|
|
35
|
+
*/
|
|
36
|
+
export function createMockProxy() {
|
|
37
|
+
return {
|
|
38
|
+
async fetch(request) {
|
|
39
|
+
try {
|
|
40
|
+
const response = await globalThis.fetch(request.url, {
|
|
41
|
+
method: request.method || "GET",
|
|
42
|
+
headers: request.headers,
|
|
43
|
+
body: request.body,
|
|
44
|
+
});
|
|
45
|
+
const headers = {};
|
|
46
|
+
response.headers.forEach((value, key) => {
|
|
47
|
+
headers[key] = value;
|
|
48
|
+
});
|
|
49
|
+
// Read response body
|
|
50
|
+
const body = await response.text();
|
|
51
|
+
return {
|
|
52
|
+
ok: response.ok,
|
|
53
|
+
status: response.status,
|
|
54
|
+
statusText: response.statusText,
|
|
55
|
+
headers,
|
|
56
|
+
json: async () => JSON.parse(body),
|
|
57
|
+
text: async () => body,
|
|
58
|
+
cached: false,
|
|
59
|
+
stale: false,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error("[Dev Player] proxy.fetch failed:", error);
|
|
64
|
+
const errorMessage = error instanceof Error ? error.message : "Network Error";
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
status: 0,
|
|
68
|
+
statusText: errorMessage,
|
|
69
|
+
headers: {},
|
|
70
|
+
json: async () => Promise.reject(error),
|
|
71
|
+
text: async () => Promise.reject(error),
|
|
72
|
+
cached: false,
|
|
73
|
+
stale: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Create a mock media cache service.
|
|
81
|
+
*
|
|
82
|
+
* In dev mode, media files are not actually cached locally.
|
|
83
|
+
* This mock returns the original URLs as "local paths".
|
|
84
|
+
*/
|
|
85
|
+
export function createMockMediaCache() {
|
|
86
|
+
const cache = new Map();
|
|
87
|
+
return {
|
|
88
|
+
async download(url) {
|
|
89
|
+
// Create a mock MediaFile that just uses the original URL
|
|
90
|
+
const file = {
|
|
91
|
+
md5: btoa(url).slice(0, 32), // Fake MD5
|
|
92
|
+
localPath: url, // Use original URL in dev mode
|
|
93
|
+
fileName: url.split("/").pop() || "file",
|
|
94
|
+
size: 0,
|
|
95
|
+
status: "cached",
|
|
96
|
+
};
|
|
97
|
+
cache.set(url, file);
|
|
98
|
+
return file;
|
|
99
|
+
},
|
|
100
|
+
async get(url) {
|
|
101
|
+
return cache.get(url) || null;
|
|
102
|
+
},
|
|
103
|
+
async list() {
|
|
104
|
+
return Array.from(cache.values());
|
|
105
|
+
},
|
|
106
|
+
async delete(fileName) {
|
|
107
|
+
// Find and delete by fileName
|
|
108
|
+
for (const [url, file] of cache.entries()) {
|
|
109
|
+
if (file.fileName === fileName) {
|
|
110
|
+
cache.delete(url);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
async clear() {
|
|
116
|
+
cache.clear();
|
|
117
|
+
},
|
|
118
|
+
async getStorageInfo() {
|
|
119
|
+
return {
|
|
120
|
+
usedBytes: 0,
|
|
121
|
+
freeBytes: Number.MAX_SAFE_INTEGER,
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Create a mock static API service.
|
|
128
|
+
*
|
|
129
|
+
* In dev mode, static optimization is disabled (no screenshots taken).
|
|
130
|
+
*/
|
|
131
|
+
export function createMockStatic() {
|
|
132
|
+
return {
|
|
133
|
+
markStatic() {
|
|
134
|
+
},
|
|
135
|
+
markSemiStatic(_refreshIntervalSeconds) {
|
|
136
|
+
},
|
|
137
|
+
disableStatic() {
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=mock-services.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-services.js","sourceRoot":"","sources":["../src/mock-services.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
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.0">
|
|
6
|
+
<title>AppStrata Dev Player</title>
|
|
7
|
+
<link rel="stylesheet" href="./styles.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="player-container">
|
|
11
|
+
<div class="player-screen">
|
|
12
|
+
<div class="loading">
|
|
13
|
+
<div class="spinner"></div>
|
|
14
|
+
<p>Loading app...</p>
|
|
15
|
+
</div>
|
|
16
|
+
<iframe id="app-frame"></iframe>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<script type="module" src="./main.ts"></script>
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
|
22
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Player Page Entry Point.
|
|
3
|
+
*
|
|
4
|
+
* This is the main script for the iframe-based dev player.
|
|
5
|
+
* It loads the user's app in an iframe and provides either:
|
|
6
|
+
* - A local mock player environment (default)
|
|
7
|
+
* - A relay to a remote HTTP player (when relay config is provided)
|
|
8
|
+
*/
|
|
9
|
+
import "../dev-overlay.css";
|
|
10
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/player/main.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkBH,OAAO,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Player Page Entry Point.
|
|
3
|
+
*
|
|
4
|
+
* This is the main script for the iframe-based dev player.
|
|
5
|
+
* It loads the user's app in an iframe and provides either:
|
|
6
|
+
* - A local mock player environment (default)
|
|
7
|
+
* - A relay to a remote HTTP player (when relay config is provided)
|
|
8
|
+
*/
|
|
9
|
+
/// <reference types="vite/client" />
|
|
10
|
+
import { createMockPlayer, buildAppContext, buildCapabilityServices, resolveCapabilities, } from "../mock-player.js";
|
|
11
|
+
import { showCompletionNotification } from "../completion-notification.js";
|
|
12
|
+
import { createDevOverlay } from "../dev-overlay.js";
|
|
13
|
+
import { createInterceptingTransport } from "../intercepting-transport.js";
|
|
14
|
+
import { createPostMessageTransport } from "@appstrata/protocol";
|
|
15
|
+
import { configureLogging, createLogger } from "@appstrata/core";
|
|
16
|
+
import { buildLoggingConfig, scaleToFit, setElementResolution } from "@appstrata/utils";
|
|
17
|
+
import { CONFIG_CHANGE_EVENT } from "../types.js";
|
|
18
|
+
import "../dev-overlay.css";
|
|
19
|
+
configureLogging(buildLoggingConfig({
|
|
20
|
+
preset: { level: "debug" },
|
|
21
|
+
}));
|
|
22
|
+
const logger = createLogger("StandaloneDevPlayer");
|
|
23
|
+
logger.info("Initializing iframe dev player...");
|
|
24
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
25
|
+
// Bootstrap
|
|
26
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
27
|
+
const params = new URLSearchParams(window.location.search);
|
|
28
|
+
const appUrl = params.get("appUrl");
|
|
29
|
+
if (!appUrl) {
|
|
30
|
+
document.body.innerHTML = `
|
|
31
|
+
<div style="color: white; padding: 40px; text-align: center; font-family: system-ui;">
|
|
32
|
+
<h1>⚠️ Missing App URL</h1>
|
|
33
|
+
<p>Please provide the app URL as a query parameter:</p>
|
|
34
|
+
<code style="background: #16213e; padding: 10px; border-radius: 4px; display: inline-block; margin-top: 10px;">
|
|
35
|
+
?appUrl=http://localhost:3000
|
|
36
|
+
</code>
|
|
37
|
+
</div>
|
|
38
|
+
`;
|
|
39
|
+
throw new Error("App URL is required. Use ?appUrl=http://localhost:3000");
|
|
40
|
+
}
|
|
41
|
+
const iframe = document.getElementById("app-frame");
|
|
42
|
+
const loading = document.querySelector(".loading");
|
|
43
|
+
const playerScreen = document.querySelector(".player-screen");
|
|
44
|
+
const playerContainer = document.querySelector(".player-container");
|
|
45
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
46
|
+
// Configuration
|
|
47
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
48
|
+
const response = await fetch("/__appstrata__/context");
|
|
49
|
+
let { context: contextConfig, capabilities: capabilityConfig, lifecycle, relay, app, dev: devConfig } = (await response.json());
|
|
50
|
+
const overlay = createDevOverlay({
|
|
51
|
+
container: playerContainer,
|
|
52
|
+
measureElement: iframe,
|
|
53
|
+
context: { ...contextConfig, autoZoom: app?.autoZoom },
|
|
54
|
+
injectStyles: false,
|
|
55
|
+
...(relay && { relay: { playerUrl: relay.playerUrl } }),
|
|
56
|
+
dropLogMessages: !(devConfig?.messages?.showLogMessages ?? false),
|
|
57
|
+
});
|
|
58
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
59
|
+
// Auto-zoom
|
|
60
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
61
|
+
let zoomApply = null;
|
|
62
|
+
let zoomReset = null;
|
|
63
|
+
window.addEventListener("resize", () => {
|
|
64
|
+
zoomApply?.();
|
|
65
|
+
overlay.flashResizeToast();
|
|
66
|
+
});
|
|
67
|
+
function applyAutoZoom(mode, targetWidth, targetHeight) {
|
|
68
|
+
zoomReset?.();
|
|
69
|
+
zoomApply = null;
|
|
70
|
+
zoomReset = null;
|
|
71
|
+
if (!mode || mode === 'none')
|
|
72
|
+
return;
|
|
73
|
+
const parent = playerScreen.parentElement;
|
|
74
|
+
let apply;
|
|
75
|
+
let reset;
|
|
76
|
+
switch (mode) {
|
|
77
|
+
case 'contain':
|
|
78
|
+
case 'cover':
|
|
79
|
+
apply = () => scaleToFit(playerScreen, parent.clientWidth, parent.clientHeight, targetWidth, targetHeight, mode);
|
|
80
|
+
reset = () => scaleToFit(playerScreen);
|
|
81
|
+
break;
|
|
82
|
+
case 'auto-width': {
|
|
83
|
+
apply = () => {
|
|
84
|
+
const portrait = window.innerWidth < window.innerHeight;
|
|
85
|
+
const designPortrait = targetWidth < targetHeight;
|
|
86
|
+
const [tw, th] = (portrait !== designPortrait)
|
|
87
|
+
? [targetHeight, targetWidth]
|
|
88
|
+
: [targetWidth, targetHeight];
|
|
89
|
+
setElementResolution(playerScreen, tw, th, 'width');
|
|
90
|
+
};
|
|
91
|
+
reset = () => setElementResolution(playerScreen);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
apply = () => setElementResolution(playerScreen, targetWidth, targetHeight, mode);
|
|
96
|
+
reset = () => setElementResolution(playerScreen);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
zoomApply = apply;
|
|
100
|
+
zoomReset = reset;
|
|
101
|
+
apply();
|
|
102
|
+
}
|
|
103
|
+
applyAutoZoom(app?.autoZoom, contextConfig.viewportWidth || 1920, contextConfig.viewportHeight || 1080);
|
|
104
|
+
/**
|
|
105
|
+
* Serialise `dev.logging` into `?logLevels=` and `?logSinks=` URL params.
|
|
106
|
+
*/
|
|
107
|
+
function buildLogParams(logging) {
|
|
108
|
+
if (!logging?.level && !logging?.sinks?.length) {
|
|
109
|
+
return { levelsParam: null, sinksParam: null };
|
|
110
|
+
}
|
|
111
|
+
let levelsParam = null;
|
|
112
|
+
if (logging.level) {
|
|
113
|
+
const parts = [logging.level];
|
|
114
|
+
if (logging.namespaces) {
|
|
115
|
+
for (const [ns, lvl] of Object.entries(logging.namespaces)) {
|
|
116
|
+
parts.push(`${ns}:${lvl}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
levelsParam = parts.join(",");
|
|
120
|
+
}
|
|
121
|
+
const sinksParam = logging.sinks?.length ? logging.sinks.join(",") : null;
|
|
122
|
+
return { levelsParam, sinksParam };
|
|
123
|
+
}
|
|
124
|
+
function setIframeSrc({ levelsParam, sinksParam }) {
|
|
125
|
+
const src = new URL(appUrl);
|
|
126
|
+
if (levelsParam)
|
|
127
|
+
src.searchParams.set("logLevels", levelsParam);
|
|
128
|
+
if (sinksParam)
|
|
129
|
+
src.searchParams.set("logSinks", sinksParam);
|
|
130
|
+
iframe.src = src.href;
|
|
131
|
+
}
|
|
132
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
133
|
+
// Session management
|
|
134
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
135
|
+
let currentHost = null;
|
|
136
|
+
let currentTransport = null;
|
|
137
|
+
let currentRelay = null;
|
|
138
|
+
let droppedCountInterval = null;
|
|
139
|
+
/**
|
|
140
|
+
* Create (or recreate) a local mock player session.
|
|
141
|
+
*
|
|
142
|
+
* Normally called before setIframeSrc() so the transport listener is
|
|
143
|
+
* in place when the app sends HELLO. Also called by the load handler
|
|
144
|
+
* on unexpected reloads (manual refresh) to replace the stale session.
|
|
145
|
+
*
|
|
146
|
+
* Only applicable to non-relay mode.
|
|
147
|
+
*/
|
|
148
|
+
function createLocalSession() {
|
|
149
|
+
currentHost?.destroy();
|
|
150
|
+
currentTransport?.close();
|
|
151
|
+
logger.info("Initializing local mock player...");
|
|
152
|
+
const rawTransport = createPostMessageTransport({
|
|
153
|
+
targetWindow: iframe.contentWindow,
|
|
154
|
+
targetOrigin: new URL(appUrl).origin,
|
|
155
|
+
});
|
|
156
|
+
const transport = currentTransport = createInterceptingTransport(rawTransport, (msg, dir) => {
|
|
157
|
+
overlay.logMessage(dir, msg);
|
|
158
|
+
});
|
|
159
|
+
const host = currentHost = createMockPlayer({
|
|
160
|
+
capabilities: capabilityConfig,
|
|
161
|
+
transport,
|
|
162
|
+
notifyComplete: () => {
|
|
163
|
+
logger.info("App called notifyComplete()");
|
|
164
|
+
const hideDelay = lifecycle?.hideDelay ?? 100;
|
|
165
|
+
const stopDelay = lifecycle?.stopDelay ?? 50;
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
logger.debug("fireHide");
|
|
168
|
+
host.fireHide();
|
|
169
|
+
}, hideDelay);
|
|
170
|
+
setTimeout(() => {
|
|
171
|
+
logger.debug("fireStop");
|
|
172
|
+
host.fireStop();
|
|
173
|
+
}, hideDelay + stopDelay);
|
|
174
|
+
},
|
|
175
|
+
notifyEstimatedEnd: (expectedFinishTime) => {
|
|
176
|
+
const secsUntil = Math.round((expectedFinishTime - Date.now()) / 1000);
|
|
177
|
+
logger.info(`App called notifyEstimatedEnd() — finishes in ~${secsUntil}s (${new Date(expectedFinishTime).toISOString()})`);
|
|
178
|
+
},
|
|
179
|
+
notifyNoContent: (options) => {
|
|
180
|
+
const parts = ["App called notifyNoContent()"];
|
|
181
|
+
if (options?.reason)
|
|
182
|
+
parts.push(`reason="${options.reason}"`);
|
|
183
|
+
if (options?.retryNotBefore) {
|
|
184
|
+
const secsUntil = Math.round((options.retryNotBefore - Date.now()) / 1000);
|
|
185
|
+
parts.push(`retry in ~${secsUntil}s`);
|
|
186
|
+
}
|
|
187
|
+
logger.info(parts.join(" — "));
|
|
188
|
+
const hideDelay = lifecycle?.hideDelay ?? 100;
|
|
189
|
+
const stopDelay = lifecycle?.stopDelay ?? 50;
|
|
190
|
+
setTimeout(() => {
|
|
191
|
+
logger.debug("fireHide");
|
|
192
|
+
host.fireHide();
|
|
193
|
+
}, hideDelay);
|
|
194
|
+
setTimeout(() => {
|
|
195
|
+
logger.debug("fireStop");
|
|
196
|
+
host.fireStop();
|
|
197
|
+
}, hideDelay + stopDelay);
|
|
198
|
+
},
|
|
199
|
+
log: (level, message, data) => {
|
|
200
|
+
console[level](`[Standalone Dev Player Log Service] ${message}`, data !== undefined ? data : "");
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
host.player.onStop(() => {
|
|
204
|
+
overlay.setCompleted();
|
|
205
|
+
showCompletionNotification();
|
|
206
|
+
});
|
|
207
|
+
logger.debug("AppHost created");
|
|
208
|
+
}
|
|
209
|
+
function fireLifecycle() {
|
|
210
|
+
const capabilities = resolveCapabilities(capabilityConfig);
|
|
211
|
+
const appContext = buildAppContext(contextConfig, capabilities);
|
|
212
|
+
const initDelay = lifecycle?.initDelay ?? 0;
|
|
213
|
+
const showDelay = lifecycle?.showDelay ?? 50;
|
|
214
|
+
const startDelay = lifecycle?.startDelay ?? 50;
|
|
215
|
+
setTimeout(() => { logger.debug("fireInit"); currentHost.fireInit(appContext); }, initDelay);
|
|
216
|
+
setTimeout(() => { logger.debug("fireShow"); currentHost.fireShow(); }, initDelay + showDelay);
|
|
217
|
+
setTimeout(() => { logger.debug("fireStart"); currentHost.fireStart(); }, initDelay + showDelay + startDelay);
|
|
218
|
+
logger.info("Mock player ready");
|
|
219
|
+
logger.debug("Context", appContext);
|
|
220
|
+
logger.debug("Capabilities", capabilities);
|
|
221
|
+
}
|
|
222
|
+
async function setupRelaySession() {
|
|
223
|
+
logger.info(`Starting relay to ${relay.playerUrl} (${relay.transport})`);
|
|
224
|
+
const { createRelayTransport, createHttpSseTransport, createHttpPollingTransport, } = await import("@appstrata/protocol");
|
|
225
|
+
const sessionId = "relay-" + Date.now() + "-" + Math.random().toString(36).substr(2, 9);
|
|
226
|
+
const targetOrigin = new URL(appUrl).origin;
|
|
227
|
+
const appTransport = createPostMessageTransport({
|
|
228
|
+
targetWindow: iframe.contentWindow,
|
|
229
|
+
targetOrigin,
|
|
230
|
+
});
|
|
231
|
+
const httpTransportFactory = relay.transport === "polling"
|
|
232
|
+
? createHttpPollingTransport
|
|
233
|
+
: createHttpSseTransport;
|
|
234
|
+
const hostTransport = httpTransportFactory({
|
|
235
|
+
sendUrl: `${relay.playerUrl}/api/send`,
|
|
236
|
+
receiveUrl: `${relay.playerUrl}/api/receive`,
|
|
237
|
+
sessionId,
|
|
238
|
+
timeout: 30000,
|
|
239
|
+
});
|
|
240
|
+
// Clean up previous relay — also removes the old postMessage listener
|
|
241
|
+
// so it doesn't intercept messages from the new iframe load.
|
|
242
|
+
if (droppedCountInterval !== null)
|
|
243
|
+
clearInterval(droppedCountInterval);
|
|
244
|
+
currentRelay?.close();
|
|
245
|
+
const relayInstance = createRelayTransport({
|
|
246
|
+
appTransport,
|
|
247
|
+
hostTransport,
|
|
248
|
+
onMessage: (msg, direction) => {
|
|
249
|
+
const dir = direction;
|
|
250
|
+
overlay.logMessage(dir, msg);
|
|
251
|
+
if (msg.type === "EVENT" && msg.name === "stop") {
|
|
252
|
+
overlay.setCompleted();
|
|
253
|
+
showCompletionNotification();
|
|
254
|
+
}
|
|
255
|
+
return msg;
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
currentRelay = relayInstance;
|
|
259
|
+
// Expose relay globally for debugging
|
|
260
|
+
window.__APPSTRATA_RELAY__ = relayInstance;
|
|
261
|
+
// Periodically sync the relay's dropped count into the overlay
|
|
262
|
+
droppedCountInterval = setInterval(() => overlay.setDroppedCount(relayInstance.getStats().dropped), 1000);
|
|
263
|
+
logger.info(`Relay active (session: ${sessionId})`);
|
|
264
|
+
}
|
|
265
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
266
|
+
// Initial load
|
|
267
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
268
|
+
// Create the session before loading the iframe so the transport listener
|
|
269
|
+
// is registered on window before the app sends HELLO. This is not strictly
|
|
270
|
+
// necessary, since the protocol handles any order of initialization, but it's
|
|
271
|
+
// nice to see the HELLO in action.
|
|
272
|
+
// True when createLocalSession() is called before setIframeSrc(),
|
|
273
|
+
// which is the normal case (initial load and HMR). After the app
|
|
274
|
+
// is loaded the flag is set to false.
|
|
275
|
+
// Only applicable to non-relay mode.
|
|
276
|
+
let sessionRefreshedBeforeAppLoad = false;
|
|
277
|
+
if (!relay) {
|
|
278
|
+
createLocalSession();
|
|
279
|
+
sessionRefreshedBeforeAppLoad = true;
|
|
280
|
+
}
|
|
281
|
+
const initialLogParams = buildLogParams(devConfig?.logging);
|
|
282
|
+
setIframeSrc(initialLogParams);
|
|
283
|
+
logger.info(`Loading app from ${iframe.src}`);
|
|
284
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
285
|
+
// HMR
|
|
286
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
287
|
+
if (import.meta.hot) {
|
|
288
|
+
let currentLogKey = JSON.stringify(initialLogParams);
|
|
289
|
+
import.meta.hot.on(CONFIG_CHANGE_EVENT, (data) => {
|
|
290
|
+
logger.info("Config changed via HMR, updating player UI");
|
|
291
|
+
contextConfig = data.context;
|
|
292
|
+
overlay.updateContext({ ...data.context, autoZoom: data.app?.autoZoom });
|
|
293
|
+
overlay.setDropLogMessages(!(data.dev?.messages?.showLogMessages ?? false));
|
|
294
|
+
applyAutoZoom(data.app?.autoZoom, data.context.viewportWidth || 1920, data.context.viewportHeight || 1080);
|
|
295
|
+
const newLogParams = buildLogParams(data.dev?.logging);
|
|
296
|
+
const newLogKey = JSON.stringify(newLogParams);
|
|
297
|
+
const loggingChanged = newLogKey !== currentLogKey;
|
|
298
|
+
if (loggingChanged) {
|
|
299
|
+
currentLogKey = newLogKey;
|
|
300
|
+
// Fresh session BEFORE reload so the listener catches HELLO.
|
|
301
|
+
if (!relay) {
|
|
302
|
+
createLocalSession();
|
|
303
|
+
sessionRefreshedBeforeAppLoad = true;
|
|
304
|
+
}
|
|
305
|
+
setIframeSrc(newLogParams);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (!relay && currentHost) {
|
|
309
|
+
// Hot-swap context/capabilities in-place (no iframe reload needed).
|
|
310
|
+
const newCapabilities = resolveCapabilities(data.capabilities);
|
|
311
|
+
const newServices = buildCapabilityServices(newCapabilities);
|
|
312
|
+
currentHost.updateServices(newServices);
|
|
313
|
+
const newContext = buildAppContext(data.context, newCapabilities);
|
|
314
|
+
currentHost.updateContext(newContext);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
319
|
+
// Iframe load handler
|
|
320
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
321
|
+
iframe.addEventListener("load", async () => {
|
|
322
|
+
logger.info("App loaded...");
|
|
323
|
+
loading.classList.add("hidden");
|
|
324
|
+
requestAnimationFrame(() => overlay.updateResolution());
|
|
325
|
+
if (relay) {
|
|
326
|
+
await setupRelaySession();
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
// On unexpected reloads (manual refresh) replace the stale session.
|
|
330
|
+
if (!sessionRefreshedBeforeAppLoad) {
|
|
331
|
+
createLocalSession();
|
|
332
|
+
}
|
|
333
|
+
sessionRefreshedBeforeAppLoad = false;
|
|
334
|
+
fireLifecycle();
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
338
|
+
// Iframe error handler
|
|
339
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
340
|
+
iframe.addEventListener("error", (e) => {
|
|
341
|
+
logger.error("Failed to load app", e);
|
|
342
|
+
loading.innerHTML = `
|
|
343
|
+
<div style="color: #ff6b6b;">
|
|
344
|
+
<p>❌ Failed to load app</p>
|
|
345
|
+
<p style="font-size: 14px; margin-top: 10px;">Check that your dev server is running at:</p>
|
|
346
|
+
<code style="background: #16213e; padding: 8px; border-radius: 4px; display: inline-block; margin-top: 8px;">
|
|
347
|
+
${appUrl}
|
|
348
|
+
</code>
|
|
349
|
+
</div>
|
|
350
|
+
`;
|
|
351
|
+
});
|
|
352
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/player/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
html, body {
|
|
8
|
+
margin: 0;
|
|
9
|
+
height: 100%;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
body {
|
|
13
|
+
background: #1a1a2e;
|
|
14
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.player-container {
|
|
19
|
+
position: relative;
|
|
20
|
+
background: #0f0f1e;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
width: 100%;
|
|
23
|
+
height: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.player-screen {
|
|
27
|
+
position: relative;
|
|
28
|
+
background: black;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
iframe {
|
|
35
|
+
width: 100%;
|
|
36
|
+
height: 100%;
|
|
37
|
+
border: none;
|
|
38
|
+
display: block;
|
|
39
|
+
background: black;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.loading {
|
|
43
|
+
position: absolute;
|
|
44
|
+
top: 50%;
|
|
45
|
+
left: 50%;
|
|
46
|
+
transform: translate(-50%, -50%);
|
|
47
|
+
color: white;
|
|
48
|
+
font-size: 16px;
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 20px;
|
|
53
|
+
z-index: 10;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.spinner {
|
|
57
|
+
width: 40px;
|
|
58
|
+
height: 40px;
|
|
59
|
+
border: 3px solid rgba(255, 255, 255, 0.1);
|
|
60
|
+
border-top-color: #00d4ff;
|
|
61
|
+
border-radius: 50%;
|
|
62
|
+
animation: spin 1s linear infinite;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@keyframes spin {
|
|
66
|
+
to {
|
|
67
|
+
transform: rotate(360deg);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.loading p {
|
|
72
|
+
margin: 0;
|
|
73
|
+
opacity: 0.8;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Hide loading when iframe is ready */
|
|
77
|
+
.loading.hidden {
|
|
78
|
+
display: none;
|
|
79
|
+
}
|
|
80
|
+
|