create-eventus-app 0.1.1 → 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.1",
3
+ "version": "0.1.3",
4
4
  "description": "Scaffold an Eventus mini app.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,12 @@ pnpm dev
15
15
  - `pnpm build`: type-check and build the app
16
16
  - `pnpm preview`: preview the production build locally
17
17
 
18
+ ## Local Live Preview
19
+
20
+ Run `pnpm dev`, open the app in your desktop browser, and scan the QR code from
21
+ Eventus X using the `Developer` screen. Your phone and computer must be on the
22
+ same local network for the live preview URL to be reachable.
23
+
18
24
  ## Eventus Files
19
25
 
20
26
  - `eventus.manifest.json`: base Eventus manifest consumed by the Vite plugin
@@ -2,6 +2,8 @@ import { useEffect, useState } from "react";
2
2
  import manifest from "virtual:eventus-manifest";
3
3
  import {
4
4
  eventus,
5
+ getLivePreviewHtml,
6
+ isBridgeUnavailableError,
5
7
  type EventusContext,
6
8
  type EventusRuntimeSource,
7
9
  } from "@eventusgo/sdk";
@@ -9,13 +11,17 @@ import {
9
11
  type LoadState =
10
12
  | { status: "idle" | "loading" }
11
13
  | { status: "ready"; context: EventusContext }
14
+ | {
15
+ status: "bridge-unavailable";
16
+ previewHtml: string | null;
17
+ }
12
18
  | { status: "error"; message: string };
13
19
 
14
20
  export default function App() {
15
21
  const [state, setState] = useState<LoadState>({ status: "loading" });
16
- const [runtimeSource, setRuntimeSource] = useState<EventusRuntimeSource | "loading">(
17
- "loading",
18
- );
22
+ const [runtimeSource, setRuntimeSource] = useState<
23
+ EventusRuntimeSource | "bridge-unavailable" | "loading"
24
+ >("loading");
19
25
 
20
26
  useEffect(() => {
21
27
  let cancelled = false;
@@ -41,10 +47,26 @@ export default function App() {
41
47
  const context = await eventus.getContext();
42
48
 
43
49
  if (!cancelled && !receivedReadyEvent) {
44
- setRuntimeSource("mock");
50
+ setRuntimeSource(window.Eventus ? "native" : "mock");
45
51
  setState({ status: "ready", context });
46
52
  }
47
53
  } catch (error) {
54
+ if (receivedReadyEvent || cancelled) {
55
+ return;
56
+ }
57
+
58
+ if (isBridgeUnavailableError(error)) {
59
+ const previewHtml = await getLivePreviewHtml();
60
+ if (!cancelled && !receivedReadyEvent) {
61
+ setRuntimeSource("bridge-unavailable");
62
+ setState({
63
+ status: "bridge-unavailable",
64
+ previewHtml,
65
+ });
66
+ }
67
+ return;
68
+ }
69
+
48
70
  if (!cancelled) {
49
71
  setState({
50
72
  status: "error",
@@ -68,8 +90,10 @@ export default function App() {
68
90
  runtimeSource === "native"
69
91
  ? "Native bridge detected"
70
92
  : runtimeSource === "mock"
71
- ? "Browser mock mode active"
72
- : "Detecting runtime…";
93
+ ? "Explicit mock mode active"
94
+ : runtimeSource === "bridge-unavailable"
95
+ ? "Open this mini app inside Eventus X"
96
+ : "Detecting runtime…";
73
97
 
74
98
  return (
75
99
  <main className="app-shell">
@@ -77,7 +101,8 @@ export default function App() {
77
101
  <p className="eyebrow">Eventus Mini App Toolkit</p>
78
102
  <h1>{manifest.name}</h1>
79
103
  <p className="subtitle">
80
- App ID <code>{manifest.appId}</code> · Version <code>{manifest.version}</code>
104
+ App ID <code>{manifest.appId}</code> · Version{" "}
105
+ <code>{manifest.version}</code>
81
106
  </p>
82
107
 
83
108
  <div className="status-banner">{runtimeLabel}</div>
@@ -90,6 +115,25 @@ export default function App() {
90
115
  <p className="error-text">{state.message}</p>
91
116
  ) : null}
92
117
 
118
+ {state.status === "bridge-unavailable" ? (
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
+ )
135
+ ) : null}
136
+
93
137
  {state.status === "ready" ? (
94
138
  <dl className="details-grid">
95
139
  <div>
@@ -102,7 +146,11 @@ export default function App() {
102
146
  </div>
103
147
  <div>
104
148
  <dt>User</dt>
105
- <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>
106
154
  </div>
107
155
  <div>
108
156
  <dt>Manifest Permissions</dt>
@@ -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
  }
@@ -67,6 +71,12 @@ h1 {
67
71
  font-weight: 600;
68
72
  }
69
73
 
74
+ .handoff-panel {
75
+ margin: 24px 0;
76
+ display: grid;
77
+ gap: 20px;
78
+ }
79
+
70
80
  .details-grid {
71
81
  display: grid;
72
82
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
@@ -111,4 +121,8 @@ dd {
111
121
  .card {
112
122
  padding: 24px;
113
123
  }
124
+
125
+ .handoff-panel {
126
+ grid-template-columns: 1fr;
127
+ }
114
128
  }