create-eventus-app 0.1.2 → 0.1.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-eventus-app",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Scaffold an Eventus mini app.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,12 +10,10 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@eventusgo/sdk": "__EVENTUS_SDK_VERSION__",
13
- "qrcode": "1.5.4",
14
13
  "react": "18.3.1",
15
14
  "react-dom": "18.3.1"
16
15
  },
17
16
  "devDependencies": {
18
- "@types/qrcode": "1.5.5",
19
17
  "@eventusgo/vite-plugin": "__EVENTUS_VITE_PLUGIN_VERSION__",
20
18
  "@types/react": "18.3.28",
21
19
  "@types/react-dom": "18.3.7",
@@ -1,23 +1,19 @@
1
1
  import { useEffect, useState } from "react";
2
2
  import manifest from "virtual:eventus-manifest";
3
- import QRCode from "qrcode";
4
3
  import {
5
4
  eventus,
5
+ getLivePreviewHtml,
6
+ isBridgeUnavailableError,
6
7
  type EventusContext,
7
8
  type EventusRuntimeSource,
8
9
  } from "@eventusgo/sdk";
9
- import {
10
- fetchDevPreviewDescriptor,
11
- isBridgeUnavailableError,
12
- type EventusDevPreviewDescriptor,
13
- } from "./dev-preview";
14
10
 
15
11
  type LoadState =
16
12
  | { status: "idle" | "loading" }
17
13
  | { status: "ready"; context: EventusContext }
18
14
  | {
19
15
  status: "bridge-unavailable";
20
- preview: EventusDevPreviewDescriptor | null;
16
+ previewHtml: string | null;
21
17
  }
22
18
  | { status: "error"; message: string };
23
19
 
@@ -60,12 +56,12 @@ export default function App() {
60
56
  }
61
57
 
62
58
  if (isBridgeUnavailableError(error)) {
63
- const preview = await fetchDevPreviewDescriptor();
59
+ const previewHtml = await getLivePreviewHtml();
64
60
  if (!cancelled && !receivedReadyEvent) {
65
61
  setRuntimeSource("bridge-unavailable");
66
62
  setState({
67
63
  status: "bridge-unavailable",
68
- preview,
64
+ previewHtml,
69
65
  });
70
66
  }
71
67
  return;
@@ -97,7 +93,7 @@ export default function App() {
97
93
  ? "Explicit mock mode active"
98
94
  : runtimeSource === "bridge-unavailable"
99
95
  ? "Open this mini app inside Eventus X"
100
- : "Detecting runtime…";
96
+ : "Detecting runtime…";
101
97
 
102
98
  return (
103
99
  <main className="app-shell">
@@ -105,7 +101,8 @@ export default function App() {
105
101
  <p className="eyebrow">Eventus Mini App Toolkit</p>
106
102
  <h1>{manifest.name}</h1>
107
103
  <p className="subtitle">
108
- App ID <code>{manifest.appId}</code> · Version <code>{manifest.version}</code>
104
+ App ID <code>{manifest.appId}</code> · Version{" "}
105
+ <code>{manifest.version}</code>
109
106
  </p>
110
107
 
111
108
  <div className="status-banner">{runtimeLabel}</div>
@@ -119,7 +116,22 @@ export default function App() {
119
116
  ) : null}
120
117
 
121
118
  {state.status === "bridge-unavailable" ? (
122
- <DeveloperHandoff preview={state.preview} />
119
+ state.previewHtml ? (
120
+ <div
121
+ dangerouslySetInnerHTML={{
122
+ __html: state.previewHtml,
123
+ }}
124
+ />
125
+ ) : (
126
+ <div className="handoff-panel">
127
+ <h2>Open inside Eventus X</h2>
128
+ <p>
129
+ This mini app needs the Eventus bridge to access the real
130
+ runtime. Open it from Eventus X to test it with production-like
131
+ behavior.
132
+ </p>
133
+ </div>
134
+ )
123
135
  ) : null}
124
136
 
125
137
  {state.status === "ready" ? (
@@ -134,7 +146,11 @@ export default function App() {
134
146
  </div>
135
147
  <div>
136
148
  <dt>User</dt>
137
- <dd>{state.context.user?.name ?? state.context.user?.id ?? "Anonymous"}</dd>
149
+ <dd>
150
+ {state.context.user?.name ??
151
+ state.context.user?.id ??
152
+ "Anonymous"}
153
+ </dd>
138
154
  </div>
139
155
  <div>
140
156
  <dt>Manifest Permissions</dt>
@@ -152,102 +168,3 @@ export default function App() {
152
168
  </main>
153
169
  );
154
170
  }
155
-
156
- function DeveloperHandoff({
157
- preview,
158
- }: {
159
- preview: EventusDevPreviewDescriptor | null;
160
- }) {
161
- if (!preview) {
162
- return (
163
- <div className="handoff-panel">
164
- <h2>Open inside Eventus X</h2>
165
- <p>
166
- This mini app needs the Eventus bridge to access the real runtime.
167
- Open it from Eventus X to test it with production-like behavior.
168
- </p>
169
- </div>
170
- );
171
- }
172
-
173
- return (
174
- <div className="handoff-panel">
175
- <div className="handoff-copy">
176
- <h2>Live preview from your phone</h2>
177
- <p>
178
- Open Eventus X, go to <strong>Developer</strong>, and scan this QR
179
- code to launch the mini app with the real Eventus bridge.
180
- </p>
181
- <dl className="preview-grid">
182
- <div>
183
- <dt>Preview URL</dt>
184
- <dd>
185
- <code>{preview.urls.preview}</code>
186
- </dd>
187
- </div>
188
- <div>
189
- <dt>Local URL</dt>
190
- <dd>
191
- <code>{preview.urls.local}</code>
192
- </dd>
193
- </div>
194
- {preview.urls.network ? (
195
- <div>
196
- <dt>Network URL</dt>
197
- <dd>
198
- <code>{preview.urls.network}</code>
199
- </dd>
200
- </div>
201
- ) : null}
202
- <div>
203
- <dt>Permissions</dt>
204
- <dd>{preview.manifest.permissions?.join(", ") ?? "None"}</dd>
205
- </div>
206
- </dl>
207
- <p className="hint-text">
208
- Your phone and computer must be on the same local network.
209
- </p>
210
- </div>
211
- <QrPanel payload={preview} />
212
- </div>
213
- );
214
- }
215
-
216
- function QrPanel({
217
- payload,
218
- }: {
219
- payload: EventusDevPreviewDescriptor;
220
- }) {
221
- const [svg, setSvg] = useState("");
222
-
223
- useEffect(() => {
224
- let cancelled = false;
225
-
226
- void (async () => {
227
- const nextSvg = await QRCode.toString(JSON.stringify(payload), {
228
- type: "svg",
229
- width: 220,
230
- margin: 1,
231
- });
232
- if (!cancelled) {
233
- setSvg(nextSvg);
234
- }
235
- })();
236
-
237
- return () => {
238
- cancelled = true;
239
- };
240
- }, [payload]);
241
-
242
- return (
243
- <div className="qr-panel">
244
- <div
245
- className="qr-code"
246
- aria-label="Eventus live preview QR code"
247
- dangerouslySetInnerHTML={{
248
- __html: svg || "<div class='qr-placeholder'>Generating QR…</div>",
249
- }}
250
- />
251
- </div>
252
- );
253
- }
@@ -1,8 +1,12 @@
1
1
  :root {
2
2
  font-family: "IBM Plex Sans", "Segoe UI", sans-serif;
3
3
  color: #102347;
4
- background:
5
- radial-gradient(circle at top, #d8f2ff 0%, #f3f9ff 35%, #eef3ff 100%);
4
+ background: radial-gradient(
5
+ circle at top,
6
+ #d8f2ff 0%,
7
+ #f3f9ff 35%,
8
+ #eef3ff 100%
9
+ );
6
10
  line-height: 1.5;
7
11
  font-weight: 400;
8
12
  }
@@ -73,70 +77,6 @@ h1 {
73
77
  gap: 20px;
74
78
  }
75
79
 
76
- .handoff-copy h2 {
77
- margin: 0 0 8px;
78
- font-size: 1.5rem;
79
- }
80
-
81
- .handoff-copy p {
82
- margin: 0;
83
- color: #465d82;
84
- }
85
-
86
- .preview-grid {
87
- margin: 20px 0 0;
88
- display: grid;
89
- gap: 12px;
90
- }
91
-
92
- .preview-grid div {
93
- padding: 14px 16px;
94
- border-radius: 16px;
95
- background: #f8fbff;
96
- border: 1px solid rgba(16, 35, 71, 0.08);
97
- }
98
-
99
- .preview-grid code {
100
- word-break: break-all;
101
- }
102
-
103
- .hint-text {
104
- margin-top: 16px;
105
- font-size: 0.95rem;
106
- }
107
-
108
- .qr-panel {
109
- display: grid;
110
- place-items: center;
111
- padding: 20px;
112
- border-radius: 24px;
113
- background: linear-gradient(180deg, #fefefe 0%, #f3f7ff 100%);
114
- border: 1px solid rgba(16, 35, 71, 0.08);
115
- }
116
-
117
- .qr-code {
118
- width: min(260px, 100%);
119
- aspect-ratio: 1;
120
- display: grid;
121
- place-items: center;
122
- }
123
-
124
- .qr-code svg {
125
- width: 100%;
126
- height: auto;
127
- }
128
-
129
- .qr-placeholder {
130
- display: grid;
131
- place-items: center;
132
- width: 100%;
133
- height: 100%;
134
- border-radius: 20px;
135
- background: #eef6ff;
136
- color: #22548d;
137
- font-weight: 600;
138
- }
139
-
140
80
  .details-grid {
141
81
  display: grid;
142
82
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
@@ -186,10 +126,3 @@ dd {
186
126
  grid-template-columns: 1fr;
187
127
  }
188
128
  }
189
-
190
- @media (min-width: 641px) {
191
- .handoff-panel {
192
- grid-template-columns: minmax(0, 1.3fr) minmax(220px, 0.7fr);
193
- align-items: start;
194
- }
195
- }
@@ -1,102 +0,0 @@
1
- export type EventusDevPreviewDescriptor = {
2
- type: "eventus-dev-preview";
3
- version: 1;
4
- manifest: {
5
- name: string;
6
- appId: string;
7
- version: string;
8
- permissions?: string[];
9
- };
10
- urls: {
11
- local: string;
12
- network: string | null;
13
- preview: string;
14
- };
15
- };
16
-
17
- export function isBridgeUnavailableError(error: unknown): boolean {
18
- return (
19
- error instanceof Error && error.name === "EventusBridgeUnavailableError"
20
- );
21
- }
22
-
23
- export async function fetchDevPreviewDescriptor(): Promise<EventusDevPreviewDescriptor | null> {
24
- if (typeof fetch !== "function") {
25
- return null;
26
- }
27
-
28
- try {
29
- const response = await fetch("/__eventus__/preview.json", {
30
- headers: {
31
- Accept: "application/json",
32
- },
33
- });
34
- if (!response.ok) {
35
- return null;
36
- }
37
-
38
- const json = (await response.json()) as unknown;
39
- return parseDevPreviewDescriptor(json);
40
- } catch {
41
- return null;
42
- }
43
- }
44
-
45
- export function parseDevPreviewDescriptor(
46
- value: unknown,
47
- ): EventusDevPreviewDescriptor | null {
48
- if (!value || typeof value !== "object" || Array.isArray(value)) {
49
- return null;
50
- }
51
-
52
- const descriptor = value as Record<string, unknown>;
53
- const manifest = descriptor.manifest;
54
- const urls = descriptor.urls;
55
-
56
- if (
57
- descriptor.type !== "eventus-dev-preview" ||
58
- descriptor.version !== 1 ||
59
- !manifest ||
60
- typeof manifest !== "object" ||
61
- Array.isArray(manifest) ||
62
- !urls ||
63
- typeof urls !== "object" ||
64
- Array.isArray(urls)
65
- ) {
66
- return null;
67
- }
68
-
69
- const nextManifest = manifest as Record<string, unknown>;
70
- const nextUrls = urls as Record<string, unknown>;
71
- const permissions = nextManifest.permissions;
72
-
73
- if (
74
- typeof nextManifest.name !== "string" ||
75
- typeof nextManifest.appId !== "string" ||
76
- typeof nextManifest.version !== "string" ||
77
- typeof nextUrls.local !== "string" ||
78
- (nextUrls.network !== null && typeof nextUrls.network !== "string") ||
79
- typeof nextUrls.preview !== "string" ||
80
- (permissions !== undefined &&
81
- (!Array.isArray(permissions) ||
82
- permissions.some((permission) => typeof permission !== "string")))
83
- ) {
84
- return null;
85
- }
86
-
87
- return {
88
- type: "eventus-dev-preview",
89
- version: 1,
90
- manifest: {
91
- name: nextManifest.name,
92
- appId: nextManifest.appId,
93
- version: nextManifest.version,
94
- ...(permissions ? { permissions: permissions as string[] } : {}),
95
- },
96
- urls: {
97
- local: nextUrls.local,
98
- network: nextUrls.network as string | null,
99
- preview: nextUrls.preview,
100
- },
101
- };
102
- }