@manyrows/appkit-react 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 ADDED
@@ -0,0 +1,59 @@
1
+ Customer usage
2
+ import { AppKit, AppKitAuthed, useAppKit } from "@manyrows/appkit-react";
3
+
4
+ function CustomerApp() {
5
+ const { snapshot, logout } = useAppKit();
6
+
7
+ return (
8
+ <div>
9
+ <button onClick={() => logout()}>Logout</button>
10
+ <pre>{JSON.stringify(snapshot?.appData, null, 2)}</pre>
11
+ </div>
12
+ );
13
+ }
14
+
15
+ export default function Page() {
16
+ return (
17
+ <div>
18
+ <AppKit
19
+ src={`${baseURL}/appkit/assets/appkit.js`}
20
+ workspace="acme"
21
+ project="drums"
22
+ />
23
+
24
+ <AppKitAuthed fallback={null}>
25
+ <CustomerApp />
26
+ </AppKitAuthed>
27
+ </div>
28
+ );
29
+ }
30
+
31
+ Option A (recommended): AppKitAuthed gate component
32
+
33
+ Pros
34
+
35
+ Dead simple for customers.
36
+
37
+ Doesn’t require them to understand snapshot shape.
38
+
39
+ Lets you change snapshot internals later without breaking them.
40
+
41
+ Customer code
42
+
43
+ <AppKit ... />
44
+ <AppKitAuthed fallback={null}>
45
+ <CustomerApp />
46
+ </AppKitAuthed>
47
+
48
+ Option B: only useAppKit() and customers gate themselves
49
+
50
+ Pros
51
+
52
+ Fewer exports.
53
+
54
+ Very explicit.
55
+
56
+ Customer code
57
+
58
+ <AppKit ... />
59
+ {useAppKit().isAuthenticated ? <CustomerApp /> : null}
package/dist/index.cjs ADDED
@@ -0,0 +1,439 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var React__default = /*#__PURE__*/_interopDefault(React);
9
+
10
+ // src/AppKit.tsx
11
+
12
+ // src/runtime.ts
13
+ function getManyRowsAppKitRuntime() {
14
+ const w = window;
15
+ if (w.ManyRows?.AppKit?.init) return w.ManyRows.AppKit;
16
+ if (w.initManyRowsAppKit) {
17
+ return {
18
+ init: w.initManyRowsAppKit,
19
+ destroy: w.destroyManyRowsAppKit,
20
+ info: w.getManyRowsAppKitInfo
21
+ };
22
+ }
23
+ return null;
24
+ }
25
+ function ensureScriptLoaded(src, timeoutMs) {
26
+ return new Promise((resolve, reject) => {
27
+ if (typeof window === "undefined" || typeof document === "undefined") {
28
+ resolve();
29
+ return;
30
+ }
31
+ if (document.querySelector(`script[data-manyrows-appkit="true"][src="${src}"]`)) {
32
+ resolve();
33
+ return;
34
+ }
35
+ if (getManyRowsAppKitRuntime()) {
36
+ resolve();
37
+ return;
38
+ }
39
+ const s = document.createElement("script");
40
+ s.src = src;
41
+ s.async = true;
42
+ s.crossOrigin = "anonymous";
43
+ s.setAttribute("data-manyrows-appkit", "true");
44
+ const timer = window.setTimeout(() => {
45
+ cleanup();
46
+ reject(new Error(`Timed out loading AppKit script after ${timeoutMs}ms: ${src}`));
47
+ }, timeoutMs);
48
+ function cleanup() {
49
+ window.clearTimeout(timer);
50
+ s.onload = null;
51
+ s.onerror = null;
52
+ }
53
+ s.onload = () => {
54
+ cleanup();
55
+ resolve();
56
+ };
57
+ s.onerror = (e) => {
58
+ cleanup();
59
+ reject(e);
60
+ };
61
+ document.head.appendChild(s);
62
+ });
63
+ }
64
+ function parseSemver(v) {
65
+ if (typeof v !== "string") return null;
66
+ const s = v.trim();
67
+ const m = /^v?(\d+)\.(\d+)\.(\d+)/.exec(s);
68
+ if (!m) return null;
69
+ const major = Number(m[1]);
70
+ const minor = Number(m[2]);
71
+ const patch = Number(m[3]);
72
+ if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) return null;
73
+ return { major, minor, patch };
74
+ }
75
+ function cmpSemver(a, b) {
76
+ if (a.major !== b.major) return a.major - b.major;
77
+ if (a.minor !== b.minor) return a.minor - b.minor;
78
+ return a.patch - b.patch;
79
+ }
80
+ function semverGte(runtimeVersion, minVersion) {
81
+ const r = parseSemver(runtimeVersion);
82
+ const m = parseSemver(minVersion);
83
+ if (!r || !m) return false;
84
+ return cmpSemver(r, m) >= 0;
85
+ }
86
+ function isProbablyProdBuild() {
87
+ const p = globalThis?.process;
88
+ const env = p?.env?.NODE_ENV;
89
+ return env === "production";
90
+ }
91
+ function looksLikeLocalhost(url) {
92
+ const s = (url || "").trim().toLowerCase();
93
+ return s.startsWith("http://localhost") || s.startsWith("https://localhost") || s.startsWith("http://127.0.0.1") || s.startsWith("https://127.0.0.1") || s.startsWith("http://0.0.0.0") || s.startsWith("https://0.0.0.0");
94
+ }
95
+ function isAuthedSnapshot(s) {
96
+ if (!s || typeof s !== "object") return false;
97
+ const status = s.status;
98
+ if (status !== "authenticated") return false;
99
+ const appData = s.appData;
100
+ if (!appData || typeof appData !== "object") return false;
101
+ return true;
102
+ }
103
+ var Ctx = React.createContext(null);
104
+ function useAppKit() {
105
+ const v = React.useContext(Ctx);
106
+ if (!v) throw new Error("useAppKit() must be used under <AppKit />");
107
+ return v;
108
+ }
109
+ function AppKitAuthed(props) {
110
+ const { isAuthenticated } = useAppKit();
111
+ if (!isAuthenticated) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: props.fallback ?? null });
112
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: props.children });
113
+ }
114
+ function mkErr(code, message, details) {
115
+ return { code, message, details };
116
+ }
117
+ function DefaultSkeleton() {
118
+ return /* @__PURE__ */ jsxRuntime.jsxs(
119
+ "div",
120
+ {
121
+ "aria-busy": "true",
122
+ "aria-live": "polite",
123
+ style: {
124
+ width: "100%",
125
+ borderRadius: 10,
126
+ border: "1px solid rgba(0,0,0,0.08)",
127
+ padding: 12
128
+ },
129
+ children: [
130
+ /* @__PURE__ */ jsxRuntime.jsx(
131
+ "div",
132
+ {
133
+ style: {
134
+ height: 12,
135
+ width: 140,
136
+ borderRadius: 6,
137
+ background: "rgba(0,0,0,0.06)",
138
+ marginBottom: 10
139
+ }
140
+ }
141
+ ),
142
+ /* @__PURE__ */ jsxRuntime.jsx(
143
+ "div",
144
+ {
145
+ style: {
146
+ height: 10,
147
+ width: "65%",
148
+ borderRadius: 6,
149
+ background: "rgba(0,0,0,0.06)",
150
+ marginBottom: 8
151
+ }
152
+ }
153
+ ),
154
+ /* @__PURE__ */ jsxRuntime.jsx(
155
+ "div",
156
+ {
157
+ style: {
158
+ height: 10,
159
+ width: "40%",
160
+ borderRadius: 6,
161
+ background: "rgba(0,0,0,0.06)"
162
+ }
163
+ }
164
+ )
165
+ ]
166
+ }
167
+ );
168
+ }
169
+ function DefaultError({ err }) {
170
+ return /* @__PURE__ */ jsxRuntime.jsxs(
171
+ "div",
172
+ {
173
+ role: "alert",
174
+ style: {
175
+ width: "100%",
176
+ borderRadius: 10,
177
+ border: "1px solid rgba(220, 38, 38, 0.35)",
178
+ background: "rgba(220, 38, 38, 0.06)",
179
+ padding: 12,
180
+ fontFamily: 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"'
181
+ },
182
+ children: [
183
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 700, marginBottom: 6 }, children: "ManyRows AppKit failed to load" }),
184
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 13, marginBottom: 8 }, children: [
185
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600 }, children: err.code }),
186
+ ": ",
187
+ err.message
188
+ ] }),
189
+ err.details !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
190
+ "pre",
191
+ {
192
+ style: {
193
+ fontSize: 12,
194
+ margin: 0,
195
+ whiteSpace: "pre-wrap",
196
+ wordBreak: "break-word",
197
+ opacity: 0.8
198
+ },
199
+ children: typeof err.details === "string" ? err.details : JSON.stringify(err.details, null, 2)
200
+ }
201
+ ) : null
202
+ ]
203
+ }
204
+ );
205
+ }
206
+ function AppKit(props) {
207
+ const autoId = React.useId();
208
+ const containerId = props.containerId ?? `manyrows-appkit-${autoId.replace(/[:]/g, "")}`;
209
+ const hasChildren = React__default.default.Children.count(props.children) > 0;
210
+ const initKey = React.useMemo(
211
+ () => [
212
+ containerId,
213
+ props.workspace,
214
+ props.appId,
215
+ props.baseURL ?? "",
216
+ props.src ?? "",
217
+ props.runtimeMinVersion ?? "",
218
+ props.runtimeExactVersion ?? "",
219
+ props.allowDevEnvInProd ? "1" : "0",
220
+ props.blockLocalhostBaseURLInProd === false ? "0" : "1",
221
+ hasChildren ? "children:1" : "children:0"
222
+ ].join("|"),
223
+ [
224
+ containerId,
225
+ props.workspace,
226
+ props.appId,
227
+ props.baseURL,
228
+ props.src,
229
+ props.runtimeMinVersion,
230
+ props.runtimeExactVersion,
231
+ props.allowDevEnvInProd,
232
+ props.blockLocalhostBaseURLInProd,
233
+ hasChildren
234
+ ]
235
+ );
236
+ const handleRef = React.useRef(null);
237
+ const [status, setStatus] = React.useState("idle");
238
+ const [lastError, setLastError] = React.useState(null);
239
+ const [readyInfo, setReadyInfo] = React.useState(null);
240
+ const [snapshot, setSnapshot] = React.useState(null);
241
+ React.useEffect(() => {
242
+ let cancelled = false;
243
+ setStatus("loading");
244
+ setLastError(null);
245
+ setReadyInfo(null);
246
+ setSnapshot(null);
247
+ handleRef.current = null;
248
+ const report = (err) => {
249
+ setLastError(err);
250
+ setStatus("error");
251
+ if (!props.silent) {
252
+ console.warn("[@manyrows/appkit-react]", err.code, err.message, err.details ?? "");
253
+ }
254
+ props.onError?.(err);
255
+ };
256
+ const init = async () => {
257
+ if (!props.workspace?.trim() || !props.appId?.trim()) {
258
+ report(
259
+ mkErr("INVALID_PROPS", "workspace and appId are required.", {
260
+ workspace: props.workspace,
261
+ appId: props.appId
262
+ })
263
+ );
264
+ return;
265
+ }
266
+ const prod = isProbablyProdBuild();
267
+ if (prod && props.blockLocalhostBaseURLInProd !== false && props.baseURL && looksLikeLocalhost(props.baseURL)) {
268
+ report(
269
+ mkErr(
270
+ "BASE_URL_NOT_ALLOWED_IN_PROD",
271
+ "localhost baseURL is not allowed in production builds.",
272
+ { baseURL: props.baseURL }
273
+ )
274
+ );
275
+ return;
276
+ }
277
+ try {
278
+ const timeoutMs = props.timeoutMs ?? (props.src ? 4e3 : 2500);
279
+ if (props.src) {
280
+ await ensureScriptLoaded(props.src, timeoutMs);
281
+ }
282
+ const start = Date.now();
283
+ while (!getManyRowsAppKitRuntime() && Date.now() - start < timeoutMs) {
284
+ if (cancelled) return;
285
+ await new Promise((r) => setTimeout(r, 25));
286
+ }
287
+ const api = getManyRowsAppKitRuntime();
288
+ if (!api) {
289
+ report(
290
+ mkErr(
291
+ props.src ? "SCRIPT_TIMEOUT" : "RUNTIME_NOT_FOUND",
292
+ props.src ? `AppKit runtime not found after loading script: ${props.src}` : "AppKit runtime not found.",
293
+ { src: props.src }
294
+ )
295
+ );
296
+ return;
297
+ }
298
+ const runtimeVersion = api?.version;
299
+ if (props.runtimeExactVersion) {
300
+ const expected = props.runtimeExactVersion.trim();
301
+ if (!expected) {
302
+ report(mkErr("INVALID_PROPS", "runtimeExactVersion must be a non-empty string."));
303
+ return;
304
+ }
305
+ const found = typeof runtimeVersion === "string" ? runtimeVersion.trim() : "";
306
+ if (found !== expected) {
307
+ report(
308
+ mkErr("RUNTIME_VERSION_MISMATCH", "AppKit runtime version mismatch.", {
309
+ expected,
310
+ found: runtimeVersion
311
+ })
312
+ );
313
+ return;
314
+ }
315
+ } else if (props.runtimeMinVersion) {
316
+ const min = props.runtimeMinVersion.trim();
317
+ if (!min) {
318
+ report(mkErr("INVALID_PROPS", "runtimeMinVersion must be a non-empty string."));
319
+ return;
320
+ }
321
+ const ok = semverGte(runtimeVersion, min);
322
+ if (!ok) {
323
+ report(
324
+ mkErr("RUNTIME_VERSION_TOO_OLD", "AppKit runtime is too old.", {
325
+ requiredMin: min,
326
+ found: runtimeVersion,
327
+ parsedFound: parseSemver(runtimeVersion)
328
+ })
329
+ );
330
+ return;
331
+ }
332
+ }
333
+ const handle = api.init({
334
+ containerId,
335
+ workspace: props.workspace.trim(),
336
+ appId: props.appId.trim(),
337
+ baseURL: props.baseURL,
338
+ silent: props.silent,
339
+ throwOnError: props.throwOnError,
340
+ // ✅ If host provides children, hide runtime default authed UI.
341
+ // Runtime will still render login / errors / forbidden screens as normal.
342
+ renderAuthed: hasChildren ? (() => null) : void 0,
343
+ onReady: (info) => {
344
+ if (cancelled) return;
345
+ setStatus("mounted");
346
+ setLastError(null);
347
+ setReadyInfo(info);
348
+ props.onReady?.(info);
349
+ },
350
+ onState: (s) => {
351
+ if (cancelled) return;
352
+ setSnapshot(s);
353
+ props.onState?.(s);
354
+ },
355
+ onReadyState: (s) => {
356
+ if (cancelled) return;
357
+ props.onReadyState?.(s);
358
+ },
359
+ onError: (e) => {
360
+ report(mkErr("RUNTIME_ERROR", "AppKit runtime error.", e));
361
+ }
362
+ });
363
+ handleRef.current = handle ?? null;
364
+ } catch (e) {
365
+ report(mkErr("SCRIPT_LOAD_FAILED", "Failed to load AppKit script.", { error: e }));
366
+ }
367
+ };
368
+ void init();
369
+ return () => {
370
+ cancelled = true;
371
+ try {
372
+ handleRef.current?.destroy?.();
373
+ } catch {
374
+ }
375
+ try {
376
+ const api = getManyRowsAppKitRuntime();
377
+ api?.destroy?.(containerId);
378
+ } catch {
379
+ }
380
+ handleRef.current = null;
381
+ };
382
+ }, [initKey]);
383
+ const showLoading = status === "loading" && !props.hideLoadingUI;
384
+ const showError = status === "error" && !!lastError && !props.hideErrorUI;
385
+ const ctx = React.useMemo(() => {
386
+ const h = handleRef.current;
387
+ return {
388
+ status,
389
+ error: lastError,
390
+ readyInfo,
391
+ snapshot,
392
+ isAuthenticated: isAuthedSnapshot(snapshot),
393
+ handle: h,
394
+ refresh: () => {
395
+ try {
396
+ h?.refresh?.();
397
+ } catch {
398
+ }
399
+ },
400
+ logout: async () => {
401
+ try {
402
+ await h?.logout?.();
403
+ } catch {
404
+ }
405
+ },
406
+ setToken: (tok) => {
407
+ try {
408
+ h?.setToken?.(tok);
409
+ } catch {
410
+ }
411
+ },
412
+ destroy: () => {
413
+ try {
414
+ h?.destroy?.();
415
+ } catch {
416
+ }
417
+ },
418
+ info: () => {
419
+ try {
420
+ return h?.info?.() ?? null;
421
+ } catch {
422
+ return null;
423
+ }
424
+ }
425
+ };
426
+ }, [status, lastError, readyInfo, snapshot]);
427
+ return /* @__PURE__ */ jsxRuntime.jsx(Ctx.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: props.className, style: props.style, children: [
428
+ showLoading ? props.loading ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultSkeleton, {}) : null,
429
+ showError && lastError ? props.errorUI ? props.errorUI(lastError) : /* @__PURE__ */ jsxRuntime.jsx(DefaultError, { err: lastError }) : null,
430
+ props.children,
431
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: containerId })
432
+ ] }) });
433
+ }
434
+
435
+ exports.AppKit = AppKit;
436
+ exports.AppKitAuthed = AppKitAuthed;
437
+ exports.useAppKit = useAppKit;
438
+ //# sourceMappingURL=index.cjs.map
439
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime.ts","../src/AppKit.tsx"],"names":["createContext","useContext","jsx","Fragment","jsxs","useId","React","useMemo","useRef","useState","useEffect"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AppKitRuntime } from \"./types\";\n\nexport function getManyRowsAppKitRuntime(): AppKitRuntime | null {\n const w = window as any;\n\n // Preferred: namespaced\n if (w.ManyRows?.AppKit?.init) return w.ManyRows.AppKit;\n\n // Back-compat: function globals\n if (w.initManyRowsAppKit) {\n return {\n init: w.initManyRowsAppKit,\n destroy: w.destroyManyRowsAppKit,\n info: w.getManyRowsAppKitInfo,\n };\n }\n\n return null;\n}\n\nexport function ensureScriptLoaded(src: string, timeoutMs: number): Promise<void> {\n return new Promise((resolve, reject) => {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n resolve(); // SSR: noop\n return;\n }\n\n // Already present?\n if (document.querySelector(`script[data-manyrows-appkit=\"true\"][src=\"${src}\"]`)) {\n resolve();\n return;\n }\n\n // If runtime already exists, we’re good.\n if (getManyRowsAppKitRuntime()) {\n resolve();\n return;\n }\n\n const s = document.createElement(\"script\");\n s.src = src;\n s.async = true;\n s.crossOrigin = \"anonymous\";\n s.setAttribute(\"data-manyrows-appkit\", \"true\");\n\n const timer = window.setTimeout(() => {\n cleanup();\n reject(new Error(`Timed out loading AppKit script after ${timeoutMs}ms: ${src}`));\n }, timeoutMs);\n\n function cleanup() {\n window.clearTimeout(timer);\n s.onload = null;\n s.onerror = null;\n }\n\n s.onload = () => {\n cleanup();\n resolve();\n };\n\n s.onerror = (e) => {\n cleanup();\n reject(e);\n };\n\n document.head.appendChild(s);\n });\n}\n","// appkit-react/AppKit.tsx\nimport React, {\n createContext,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n ManyRowsAppKitError,\n ManyRowsAppKitReady,\n ManyRowsAppKitHandle,\n ManyRowsAppKitSnapshot,\n} from \"./types\";\nimport { ensureScriptLoaded, getManyRowsAppKitRuntime } from \"./runtime\";\n\n// -----------------------------\n// Tiny semver helpers (no deps)\n// -----------------------------\n\ntype Semver = { major: number; minor: number; patch: number };\n\nfunction parseSemver(v: unknown): Semver | null {\n if (typeof v !== \"string\") return null;\n const s = v.trim();\n const m = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(s);\n if (!m) return null;\n const major = Number(m[1]);\n const minor = Number(m[2]);\n const patch = Number(m[3]);\n if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) return null;\n return { major, minor, patch };\n}\n\nfunction cmpSemver(a: Semver, b: Semver): number {\n if (a.major !== b.major) return a.major - b.major;\n if (a.minor !== b.minor) return a.minor - b.minor;\n return a.patch - b.patch;\n}\n\nfunction semverGte(runtimeVersion: unknown, minVersion: string): boolean {\n const r = parseSemver(runtimeVersion);\n const m = parseSemver(minVersion);\n if (!r || !m) return false;\n return cmpSemver(r, m) >= 0;\n}\n\n// -----------------------------\n// Prod/dev safety helpers\n// -----------------------------\n\nfunction isProbablyProdBuild(): boolean {\n const p = (globalThis as any)?.process;\n const env = p?.env?.NODE_ENV;\n return env === \"production\";\n}\n\nfunction looksLikeLocalhost(url: string): boolean {\n const s = (url || \"\").trim().toLowerCase();\n return (\n s.startsWith(\"http://localhost\") ||\n s.startsWith(\"https://localhost\") ||\n s.startsWith(\"http://127.0.0.1\") ||\n s.startsWith(\"https://127.0.0.1\") ||\n s.startsWith(\"http://0.0.0.0\") ||\n s.startsWith(\"https://0.0.0.0\")\n );\n}\n\n// -----------------------------\n// Auth predicate (snapshot is loose)\n// -----------------------------\n\nfunction isAuthedSnapshot(s: ManyRowsAppKitSnapshot | null | undefined): boolean {\n if (!s || typeof s !== \"object\") return false;\n const status = (s as any).status;\n if (status !== \"authenticated\") return false;\n\n const appData = (s as any).appData;\n if (!appData || typeof appData !== \"object\") return false;\n\n // don’t over-constrain v0\n return true;\n}\n\n// -----------------------------\n// AppKit context + hook\n// -----------------------------\n\nexport type AppKitContextValue = {\n status: \"idle\" | \"loading\" | \"mounted\" | \"error\";\n error: ManyRowsAppKitError | null;\n\n readyInfo: ManyRowsAppKitReady | null;\n snapshot: ManyRowsAppKitSnapshot | null;\n\n // convenience derived flag\n isAuthenticated: boolean;\n\n // present when runtime supports handle API\n handle: ManyRowsAppKitHandle | null;\n\n // convenience methods (safe no-ops if handle missing)\n refresh: () => void;\n logout: () => Promise<void>;\n setToken: (tok: string | null) => void;\n destroy: () => void;\n info: () => ManyRowsAppKitReady | null;\n};\n\nconst Ctx = createContext<AppKitContextValue | null>(null);\n\nexport function useAppKit(): AppKitContextValue {\n const v = useContext(Ctx);\n if (!v) throw new Error(\"useAppKit() must be used under <AppKit />\");\n return v;\n}\n\n/**\n * Render children only when the AppKit runtime is authenticated and appData exists.\n * Use this to mount your customer app \"behind\" the AppKit login screen.\n */\nexport function AppKitAuthed(props: {\n children: React.ReactNode;\n /**\n * Optional: shown when not authenticated (or still checking).\n * Default: null (render nothing).\n */\n fallback?: React.ReactNode;\n}) {\n const { isAuthenticated } = useAppKit();\n if (!isAuthenticated) return <>{props.fallback ?? null}</>;\n return <>{props.children}</>;\n}\n\n// -----------------------------\n// Props\n// -----------------------------\n\nexport type AppKitProps = {\n workspace: string;\n\n // ✅ replaces project+env\n appId: string;\n\n baseURL?: string;\n\n src?: string;\n timeoutMs?: number;\n\n silent?: boolean;\n throwOnError?: boolean;\n\n onReady?: (info: ManyRowsAppKitReady) => void;\n onError?: (err: ManyRowsAppKitError) => void;\n\n /**\n * Fired for every snapshot update from the runtime (checking/unauth/authed/etc).\n */\n onState?: (snapshot: ManyRowsAppKitSnapshot | null) => void;\n\n /**\n * Fired when AppKit is authenticated and appData is available.\n * This is the correct place to render the customer app (imperative style).\n */\n onReadyState?: (snapshot: ManyRowsAppKitSnapshot) => void;\n\n className?: string;\n style?: React.CSSProperties;\n containerId?: string;\n\n runtimeMinVersion?: string;\n runtimeExactVersion?: string;\n\n loading?: React.ReactNode;\n errorUI?: (err: ManyRowsAppKitError) => React.ReactNode;\n hideLoadingUI?: boolean;\n hideErrorUI?: boolean;\n\n // kept for future (no longer used now that env is arbitrary)\n allowDevEnvInProd?: boolean;\n blockLocalhostBaseURLInProd?: boolean;\n\n // ✅ allow <AppKit>children</AppKit>\n children?: React.ReactNode;\n};\n\n// -----------------------------\n// Errors / UI\n// -----------------------------\n\nfunction mkErr(\n code: ManyRowsAppKitError[\"code\"],\n message: string,\n details?: unknown\n): ManyRowsAppKitError {\n return { code, message, details };\n}\n\nfunction DefaultSkeleton() {\n return (\n <div\n aria-busy=\"true\"\n aria-live=\"polite\"\n style={{\n width: \"100%\",\n borderRadius: 10,\n border: \"1px solid rgba(0,0,0,0.08)\",\n padding: 12,\n }}\n >\n <div\n style={{\n height: 12,\n width: 140,\n borderRadius: 6,\n background: \"rgba(0,0,0,0.06)\",\n marginBottom: 10,\n }}\n />\n <div\n style={{\n height: 10,\n width: \"65%\",\n borderRadius: 6,\n background: \"rgba(0,0,0,0.06)\",\n marginBottom: 8,\n }}\n />\n <div\n style={{\n height: 10,\n width: \"40%\",\n borderRadius: 6,\n background: \"rgba(0,0,0,0.06)\",\n }}\n />\n </div>\n );\n}\n\nfunction DefaultError({ err }: { err: ManyRowsAppKitError }) {\n return (\n <div\n role=\"alert\"\n style={{\n width: \"100%\",\n borderRadius: 10,\n border: \"1px solid rgba(220, 38, 38, 0.35)\",\n background: \"rgba(220, 38, 38, 0.06)\",\n padding: 12,\n fontFamily:\n 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n }}\n >\n <div style={{ fontWeight: 700, marginBottom: 6 }}>ManyRows AppKit failed to load</div>\n <div style={{ fontSize: 13, marginBottom: 8 }}>\n <span style={{ fontWeight: 600 }}>{err.code}</span>: {err.message}\n </div>\n {err.details !== undefined ? (\n <pre\n style={{\n fontSize: 12,\n margin: 0,\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n opacity: 0.8,\n }}\n >\n {typeof err.details === \"string\" ? err.details : JSON.stringify(err.details, null, 2)}\n </pre>\n ) : null}\n </div>\n );\n}\n\n// -----------------------------\n// Component\n// -----------------------------\n\nexport function AppKit(props: AppKitProps) {\n const autoId = useId();\n const containerId = props.containerId ?? `manyrows-appkit-${autoId.replace(/[:]/g, \"\")}`;\n\n // If host supplies children, we assume host wants to own the authed UI.\n // In that case, suppress the runtime's *default* authed screen by passing renderAuthed={() => null}.\n const hasChildren = React.Children.count(props.children) > 0;\n\n const initKey = useMemo(\n () =>\n [\n containerId,\n props.workspace,\n props.appId,\n props.baseURL ?? \"\",\n props.src ?? \"\",\n props.runtimeMinVersion ?? \"\",\n props.runtimeExactVersion ?? \"\",\n props.allowDevEnvInProd ? \"1\" : \"0\",\n props.blockLocalhostBaseURLInProd === false ? \"0\" : \"1\",\n hasChildren ? \"children:1\" : \"children:0\",\n ].join(\"|\"),\n [\n containerId,\n props.workspace,\n props.appId,\n props.baseURL,\n props.src,\n props.runtimeMinVersion,\n props.runtimeExactVersion,\n props.allowDevEnvInProd,\n props.blockLocalhostBaseURLInProd,\n hasChildren,\n ]\n );\n\n const handleRef = useRef<ManyRowsAppKitHandle | null>(null);\n\n const [status, setStatus] = useState<\"idle\" | \"loading\" | \"mounted\" | \"error\">(\"idle\");\n const [lastError, setLastError] = useState<ManyRowsAppKitError | null>(null);\n\n const [readyInfo, setReadyInfo] = useState<ManyRowsAppKitReady | null>(null);\n const [snapshot, setSnapshot] = useState<ManyRowsAppKitSnapshot | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n\n setStatus(\"loading\");\n setLastError(null);\n setReadyInfo(null);\n setSnapshot(null);\n handleRef.current = null;\n\n const report = (err: ManyRowsAppKitError) => {\n setLastError(err);\n setStatus(\"error\");\n\n if (!props.silent) {\n // eslint-disable-next-line no-console\n console.warn(\"[@manyrows/appkit-react]\", err.code, err.message, err.details ?? \"\");\n }\n props.onError?.(err);\n };\n\n const init = async () => {\n if (!props.workspace?.trim() || !props.appId?.trim()) {\n report(\n mkErr(\"INVALID_PROPS\", \"workspace and appId are required.\", {\n workspace: props.workspace,\n appId: props.appId,\n })\n );\n return;\n }\n\n const prod = isProbablyProdBuild();\n\n if (\n prod &&\n props.blockLocalhostBaseURLInProd !== false &&\n props.baseURL &&\n looksLikeLocalhost(props.baseURL)\n ) {\n report(\n mkErr(\n \"BASE_URL_NOT_ALLOWED_IN_PROD\",\n \"localhost baseURL is not allowed in production builds.\",\n { baseURL: props.baseURL }\n )\n );\n return;\n }\n\n try {\n const timeoutMs = props.timeoutMs ?? (props.src ? 4000 : 2500);\n\n if (props.src) {\n await ensureScriptLoaded(props.src, timeoutMs);\n }\n\n const start = Date.now();\n while (!getManyRowsAppKitRuntime() && Date.now() - start < timeoutMs) {\n if (cancelled) return;\n await new Promise((r) => setTimeout(r, 25));\n }\n\n const api = getManyRowsAppKitRuntime();\n if (!api) {\n report(\n mkErr(\n props.src ? \"SCRIPT_TIMEOUT\" : \"RUNTIME_NOT_FOUND\",\n props.src\n ? `AppKit runtime not found after loading script: ${props.src}`\n : \"AppKit runtime not found.\",\n { src: props.src }\n )\n );\n return;\n }\n\n const runtimeVersion: unknown = (api as any)?.version;\n\n if (props.runtimeExactVersion) {\n const expected = props.runtimeExactVersion.trim();\n if (!expected) {\n report(mkErr(\"INVALID_PROPS\", \"runtimeExactVersion must be a non-empty string.\"));\n return;\n }\n const found = typeof runtimeVersion === \"string\" ? runtimeVersion.trim() : \"\";\n if (found !== expected) {\n report(\n mkErr(\"RUNTIME_VERSION_MISMATCH\", \"AppKit runtime version mismatch.\", {\n expected,\n found: runtimeVersion,\n })\n );\n return;\n }\n } else if (props.runtimeMinVersion) {\n const min = props.runtimeMinVersion.trim();\n if (!min) {\n report(mkErr(\"INVALID_PROPS\", \"runtimeMinVersion must be a non-empty string.\"));\n return;\n }\n const ok = semverGte(runtimeVersion, min);\n if (!ok) {\n report(\n mkErr(\"RUNTIME_VERSION_TOO_OLD\", \"AppKit runtime is too old.\", {\n requiredMin: min,\n found: runtimeVersion,\n parsedFound: parseSemver(runtimeVersion),\n })\n );\n return;\n }\n }\n\n const handle = (api as any).init({\n containerId,\n workspace: props.workspace.trim(),\n appId: props.appId.trim(),\n baseURL: props.baseURL,\n silent: props.silent,\n throwOnError: props.throwOnError,\n\n // ✅ If host provides children, hide runtime default authed UI.\n // Runtime will still render login / errors / forbidden screens as normal.\n renderAuthed: hasChildren ? (() => null) : undefined,\n\n onReady: (info: ManyRowsAppKitReady) => {\n if (cancelled) return;\n setStatus(\"mounted\");\n setLastError(null);\n setReadyInfo(info);\n props.onReady?.(info);\n },\n\n onState: (s: ManyRowsAppKitSnapshot | null) => {\n if (cancelled) return;\n setSnapshot(s);\n props.onState?.(s);\n },\n\n onReadyState: (s: ManyRowsAppKitSnapshot) => {\n if (cancelled) return;\n props.onReadyState?.(s);\n },\n\n onError: (e: any) => {\n report(mkErr(\"RUNTIME_ERROR\", \"AppKit runtime error.\", e));\n },\n });\n\n handleRef.current = handle ?? null;\n } catch (e) {\n report(mkErr(\"SCRIPT_LOAD_FAILED\", \"Failed to load AppKit script.\", { error: e }));\n }\n };\n\n void init();\n\n return () => {\n cancelled = true;\n\n try {\n handleRef.current?.destroy?.();\n } catch {\n // ignore\n }\n\n try {\n const api = getManyRowsAppKitRuntime();\n api?.destroy?.(containerId);\n } catch {\n // ignore\n }\n\n handleRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initKey]);\n\n const showLoading = status === \"loading\" && !props.hideLoadingUI;\n const showError = status === \"error\" && !!lastError && !props.hideErrorUI;\n\n const ctx: AppKitContextValue = useMemo(() => {\n const h = handleRef.current;\n\n return {\n status,\n error: lastError,\n readyInfo,\n snapshot,\n isAuthenticated: isAuthedSnapshot(snapshot),\n handle: h,\n\n refresh: () => {\n try {\n h?.refresh?.();\n } catch {\n // ignore\n }\n },\n logout: async () => {\n try {\n await h?.logout?.();\n } catch {\n // ignore\n }\n },\n setToken: (tok: string | null) => {\n try {\n h?.setToken?.(tok);\n } catch {\n // ignore\n }\n },\n destroy: () => {\n try {\n h?.destroy?.();\n } catch {\n // ignore\n }\n },\n info: () => {\n try {\n return h?.info?.() ?? null;\n } catch {\n return null;\n }\n },\n };\n }, [status, lastError, readyInfo, snapshot]);\n\n return (\n <Ctx.Provider value={ctx}>\n <div className={props.className} style={props.style}>\n {showLoading ? props.loading ?? <DefaultSkeleton /> : null}\n {showError && lastError\n ? props.errorUI\n ? props.errorUI(lastError)\n : <DefaultError err={lastError} />\n : null}\n\n {/* Host-side children (can use AppKitAuthed/useAppKit) */}\n {props.children}\n\n {/* Runtime owns all UI inside this container */}\n <div id={containerId} />\n </div>\n </Ctx.Provider>\n );\n}\n"]}
@@ -0,0 +1,92 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ type ManyRowsAppKitErrorCode = "RUNTIME_NOT_FOUND" | "SCRIPT_LOAD_FAILED" | "SCRIPT_TIMEOUT" | "RUNTIME_ERROR" | "RUNTIME_VERSION_MISMATCH" | "RUNTIME_VERSION_TOO_OLD" | "ENV_NOT_ALLOWED_IN_PROD" | "BASE_URL_NOT_ALLOWED_IN_PROD" | "INVALID_PROPS";
5
+ type ManyRowsAppKitError = {
6
+ code: ManyRowsAppKitErrorCode;
7
+ message: string;
8
+ details?: unknown;
9
+ };
10
+ type ManyRowsAppKitReady = {
11
+ container: HTMLElement;
12
+ containerId?: string;
13
+ workspace: string;
14
+ appId: string;
15
+ project: string;
16
+ env: string;
17
+ baseURL: string;
18
+ version: string;
19
+ };
20
+ type ManyRowsAppKitSnapshot = any;
21
+ type ManyRowsAppKitHandle = {
22
+ version: string;
23
+ info(): ManyRowsAppKitReady | null;
24
+ getState(): ManyRowsAppKitSnapshot | null;
25
+ subscribe(fn: (s: ManyRowsAppKitSnapshot | null) => void): () => void;
26
+ refresh(): void;
27
+ logout(): Promise<void>;
28
+ setToken(tok: string | null): void;
29
+ destroy(): void;
30
+ };
31
+
32
+ type AppKitContextValue = {
33
+ status: "idle" | "loading" | "mounted" | "error";
34
+ error: ManyRowsAppKitError | null;
35
+ readyInfo: ManyRowsAppKitReady | null;
36
+ snapshot: ManyRowsAppKitSnapshot | null;
37
+ isAuthenticated: boolean;
38
+ handle: ManyRowsAppKitHandle | null;
39
+ refresh: () => void;
40
+ logout: () => Promise<void>;
41
+ setToken: (tok: string | null) => void;
42
+ destroy: () => void;
43
+ info: () => ManyRowsAppKitReady | null;
44
+ };
45
+ declare function useAppKit(): AppKitContextValue;
46
+ /**
47
+ * Render children only when the AppKit runtime is authenticated and appData exists.
48
+ * Use this to mount your customer app "behind" the AppKit login screen.
49
+ */
50
+ declare function AppKitAuthed(props: {
51
+ children: React.ReactNode;
52
+ /**
53
+ * Optional: shown when not authenticated (or still checking).
54
+ * Default: null (render nothing).
55
+ */
56
+ fallback?: React.ReactNode;
57
+ }): react_jsx_runtime.JSX.Element;
58
+ type AppKitProps = {
59
+ workspace: string;
60
+ appId: string;
61
+ baseURL?: string;
62
+ src?: string;
63
+ timeoutMs?: number;
64
+ silent?: boolean;
65
+ throwOnError?: boolean;
66
+ onReady?: (info: ManyRowsAppKitReady) => void;
67
+ onError?: (err: ManyRowsAppKitError) => void;
68
+ /**
69
+ * Fired for every snapshot update from the runtime (checking/unauth/authed/etc).
70
+ */
71
+ onState?: (snapshot: ManyRowsAppKitSnapshot | null) => void;
72
+ /**
73
+ * Fired when AppKit is authenticated and appData is available.
74
+ * This is the correct place to render the customer app (imperative style).
75
+ */
76
+ onReadyState?: (snapshot: ManyRowsAppKitSnapshot) => void;
77
+ className?: string;
78
+ style?: React.CSSProperties;
79
+ containerId?: string;
80
+ runtimeMinVersion?: string;
81
+ runtimeExactVersion?: string;
82
+ loading?: React.ReactNode;
83
+ errorUI?: (err: ManyRowsAppKitError) => React.ReactNode;
84
+ hideLoadingUI?: boolean;
85
+ hideErrorUI?: boolean;
86
+ allowDevEnvInProd?: boolean;
87
+ blockLocalhostBaseURLInProd?: boolean;
88
+ children?: React.ReactNode;
89
+ };
90
+ declare function AppKit(props: AppKitProps): react_jsx_runtime.JSX.Element;
91
+
92
+ export { AppKit, AppKitAuthed, type ManyRowsAppKitError, type ManyRowsAppKitErrorCode, type ManyRowsAppKitHandle, type ManyRowsAppKitReady, type ManyRowsAppKitSnapshot, useAppKit };
@@ -0,0 +1,92 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ type ManyRowsAppKitErrorCode = "RUNTIME_NOT_FOUND" | "SCRIPT_LOAD_FAILED" | "SCRIPT_TIMEOUT" | "RUNTIME_ERROR" | "RUNTIME_VERSION_MISMATCH" | "RUNTIME_VERSION_TOO_OLD" | "ENV_NOT_ALLOWED_IN_PROD" | "BASE_URL_NOT_ALLOWED_IN_PROD" | "INVALID_PROPS";
5
+ type ManyRowsAppKitError = {
6
+ code: ManyRowsAppKitErrorCode;
7
+ message: string;
8
+ details?: unknown;
9
+ };
10
+ type ManyRowsAppKitReady = {
11
+ container: HTMLElement;
12
+ containerId?: string;
13
+ workspace: string;
14
+ appId: string;
15
+ project: string;
16
+ env: string;
17
+ baseURL: string;
18
+ version: string;
19
+ };
20
+ type ManyRowsAppKitSnapshot = any;
21
+ type ManyRowsAppKitHandle = {
22
+ version: string;
23
+ info(): ManyRowsAppKitReady | null;
24
+ getState(): ManyRowsAppKitSnapshot | null;
25
+ subscribe(fn: (s: ManyRowsAppKitSnapshot | null) => void): () => void;
26
+ refresh(): void;
27
+ logout(): Promise<void>;
28
+ setToken(tok: string | null): void;
29
+ destroy(): void;
30
+ };
31
+
32
+ type AppKitContextValue = {
33
+ status: "idle" | "loading" | "mounted" | "error";
34
+ error: ManyRowsAppKitError | null;
35
+ readyInfo: ManyRowsAppKitReady | null;
36
+ snapshot: ManyRowsAppKitSnapshot | null;
37
+ isAuthenticated: boolean;
38
+ handle: ManyRowsAppKitHandle | null;
39
+ refresh: () => void;
40
+ logout: () => Promise<void>;
41
+ setToken: (tok: string | null) => void;
42
+ destroy: () => void;
43
+ info: () => ManyRowsAppKitReady | null;
44
+ };
45
+ declare function useAppKit(): AppKitContextValue;
46
+ /**
47
+ * Render children only when the AppKit runtime is authenticated and appData exists.
48
+ * Use this to mount your customer app "behind" the AppKit login screen.
49
+ */
50
+ declare function AppKitAuthed(props: {
51
+ children: React.ReactNode;
52
+ /**
53
+ * Optional: shown when not authenticated (or still checking).
54
+ * Default: null (render nothing).
55
+ */
56
+ fallback?: React.ReactNode;
57
+ }): react_jsx_runtime.JSX.Element;
58
+ type AppKitProps = {
59
+ workspace: string;
60
+ appId: string;
61
+ baseURL?: string;
62
+ src?: string;
63
+ timeoutMs?: number;
64
+ silent?: boolean;
65
+ throwOnError?: boolean;
66
+ onReady?: (info: ManyRowsAppKitReady) => void;
67
+ onError?: (err: ManyRowsAppKitError) => void;
68
+ /**
69
+ * Fired for every snapshot update from the runtime (checking/unauth/authed/etc).
70
+ */
71
+ onState?: (snapshot: ManyRowsAppKitSnapshot | null) => void;
72
+ /**
73
+ * Fired when AppKit is authenticated and appData is available.
74
+ * This is the correct place to render the customer app (imperative style).
75
+ */
76
+ onReadyState?: (snapshot: ManyRowsAppKitSnapshot) => void;
77
+ className?: string;
78
+ style?: React.CSSProperties;
79
+ containerId?: string;
80
+ runtimeMinVersion?: string;
81
+ runtimeExactVersion?: string;
82
+ loading?: React.ReactNode;
83
+ errorUI?: (err: ManyRowsAppKitError) => React.ReactNode;
84
+ hideLoadingUI?: boolean;
85
+ hideErrorUI?: boolean;
86
+ allowDevEnvInProd?: boolean;
87
+ blockLocalhostBaseURLInProd?: boolean;
88
+ children?: React.ReactNode;
89
+ };
90
+ declare function AppKit(props: AppKitProps): react_jsx_runtime.JSX.Element;
91
+
92
+ export { AppKit, AppKitAuthed, type ManyRowsAppKitError, type ManyRowsAppKitErrorCode, type ManyRowsAppKitHandle, type ManyRowsAppKitReady, type ManyRowsAppKitSnapshot, useAppKit };
package/dist/index.js ADDED
@@ -0,0 +1,431 @@
1
+ import React, { createContext, useContext, useId, useMemo, useRef, useState, useEffect } from 'react';
2
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
3
+
4
+ // src/AppKit.tsx
5
+
6
+ // src/runtime.ts
7
+ function getManyRowsAppKitRuntime() {
8
+ const w = window;
9
+ if (w.ManyRows?.AppKit?.init) return w.ManyRows.AppKit;
10
+ if (w.initManyRowsAppKit) {
11
+ return {
12
+ init: w.initManyRowsAppKit,
13
+ destroy: w.destroyManyRowsAppKit,
14
+ info: w.getManyRowsAppKitInfo
15
+ };
16
+ }
17
+ return null;
18
+ }
19
+ function ensureScriptLoaded(src, timeoutMs) {
20
+ return new Promise((resolve, reject) => {
21
+ if (typeof window === "undefined" || typeof document === "undefined") {
22
+ resolve();
23
+ return;
24
+ }
25
+ if (document.querySelector(`script[data-manyrows-appkit="true"][src="${src}"]`)) {
26
+ resolve();
27
+ return;
28
+ }
29
+ if (getManyRowsAppKitRuntime()) {
30
+ resolve();
31
+ return;
32
+ }
33
+ const s = document.createElement("script");
34
+ s.src = src;
35
+ s.async = true;
36
+ s.crossOrigin = "anonymous";
37
+ s.setAttribute("data-manyrows-appkit", "true");
38
+ const timer = window.setTimeout(() => {
39
+ cleanup();
40
+ reject(new Error(`Timed out loading AppKit script after ${timeoutMs}ms: ${src}`));
41
+ }, timeoutMs);
42
+ function cleanup() {
43
+ window.clearTimeout(timer);
44
+ s.onload = null;
45
+ s.onerror = null;
46
+ }
47
+ s.onload = () => {
48
+ cleanup();
49
+ resolve();
50
+ };
51
+ s.onerror = (e) => {
52
+ cleanup();
53
+ reject(e);
54
+ };
55
+ document.head.appendChild(s);
56
+ });
57
+ }
58
+ function parseSemver(v) {
59
+ if (typeof v !== "string") return null;
60
+ const s = v.trim();
61
+ const m = /^v?(\d+)\.(\d+)\.(\d+)/.exec(s);
62
+ if (!m) return null;
63
+ const major = Number(m[1]);
64
+ const minor = Number(m[2]);
65
+ const patch = Number(m[3]);
66
+ if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) return null;
67
+ return { major, minor, patch };
68
+ }
69
+ function cmpSemver(a, b) {
70
+ if (a.major !== b.major) return a.major - b.major;
71
+ if (a.minor !== b.minor) return a.minor - b.minor;
72
+ return a.patch - b.patch;
73
+ }
74
+ function semverGte(runtimeVersion, minVersion) {
75
+ const r = parseSemver(runtimeVersion);
76
+ const m = parseSemver(minVersion);
77
+ if (!r || !m) return false;
78
+ return cmpSemver(r, m) >= 0;
79
+ }
80
+ function isProbablyProdBuild() {
81
+ const p = globalThis?.process;
82
+ const env = p?.env?.NODE_ENV;
83
+ return env === "production";
84
+ }
85
+ function looksLikeLocalhost(url) {
86
+ const s = (url || "").trim().toLowerCase();
87
+ return s.startsWith("http://localhost") || s.startsWith("https://localhost") || s.startsWith("http://127.0.0.1") || s.startsWith("https://127.0.0.1") || s.startsWith("http://0.0.0.0") || s.startsWith("https://0.0.0.0");
88
+ }
89
+ function isAuthedSnapshot(s) {
90
+ if (!s || typeof s !== "object") return false;
91
+ const status = s.status;
92
+ if (status !== "authenticated") return false;
93
+ const appData = s.appData;
94
+ if (!appData || typeof appData !== "object") return false;
95
+ return true;
96
+ }
97
+ var Ctx = createContext(null);
98
+ function useAppKit() {
99
+ const v = useContext(Ctx);
100
+ if (!v) throw new Error("useAppKit() must be used under <AppKit />");
101
+ return v;
102
+ }
103
+ function AppKitAuthed(props) {
104
+ const { isAuthenticated } = useAppKit();
105
+ if (!isAuthenticated) return /* @__PURE__ */ jsx(Fragment, { children: props.fallback ?? null });
106
+ return /* @__PURE__ */ jsx(Fragment, { children: props.children });
107
+ }
108
+ function mkErr(code, message, details) {
109
+ return { code, message, details };
110
+ }
111
+ function DefaultSkeleton() {
112
+ return /* @__PURE__ */ jsxs(
113
+ "div",
114
+ {
115
+ "aria-busy": "true",
116
+ "aria-live": "polite",
117
+ style: {
118
+ width: "100%",
119
+ borderRadius: 10,
120
+ border: "1px solid rgba(0,0,0,0.08)",
121
+ padding: 12
122
+ },
123
+ children: [
124
+ /* @__PURE__ */ jsx(
125
+ "div",
126
+ {
127
+ style: {
128
+ height: 12,
129
+ width: 140,
130
+ borderRadius: 6,
131
+ background: "rgba(0,0,0,0.06)",
132
+ marginBottom: 10
133
+ }
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsx(
137
+ "div",
138
+ {
139
+ style: {
140
+ height: 10,
141
+ width: "65%",
142
+ borderRadius: 6,
143
+ background: "rgba(0,0,0,0.06)",
144
+ marginBottom: 8
145
+ }
146
+ }
147
+ ),
148
+ /* @__PURE__ */ jsx(
149
+ "div",
150
+ {
151
+ style: {
152
+ height: 10,
153
+ width: "40%",
154
+ borderRadius: 6,
155
+ background: "rgba(0,0,0,0.06)"
156
+ }
157
+ }
158
+ )
159
+ ]
160
+ }
161
+ );
162
+ }
163
+ function DefaultError({ err }) {
164
+ return /* @__PURE__ */ jsxs(
165
+ "div",
166
+ {
167
+ role: "alert",
168
+ style: {
169
+ width: "100%",
170
+ borderRadius: 10,
171
+ border: "1px solid rgba(220, 38, 38, 0.35)",
172
+ background: "rgba(220, 38, 38, 0.06)",
173
+ padding: 12,
174
+ fontFamily: 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"'
175
+ },
176
+ children: [
177
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 700, marginBottom: 6 }, children: "ManyRows AppKit failed to load" }),
178
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 13, marginBottom: 8 }, children: [
179
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600 }, children: err.code }),
180
+ ": ",
181
+ err.message
182
+ ] }),
183
+ err.details !== void 0 ? /* @__PURE__ */ jsx(
184
+ "pre",
185
+ {
186
+ style: {
187
+ fontSize: 12,
188
+ margin: 0,
189
+ whiteSpace: "pre-wrap",
190
+ wordBreak: "break-word",
191
+ opacity: 0.8
192
+ },
193
+ children: typeof err.details === "string" ? err.details : JSON.stringify(err.details, null, 2)
194
+ }
195
+ ) : null
196
+ ]
197
+ }
198
+ );
199
+ }
200
+ function AppKit(props) {
201
+ const autoId = useId();
202
+ const containerId = props.containerId ?? `manyrows-appkit-${autoId.replace(/[:]/g, "")}`;
203
+ const hasChildren = React.Children.count(props.children) > 0;
204
+ const initKey = useMemo(
205
+ () => [
206
+ containerId,
207
+ props.workspace,
208
+ props.appId,
209
+ props.baseURL ?? "",
210
+ props.src ?? "",
211
+ props.runtimeMinVersion ?? "",
212
+ props.runtimeExactVersion ?? "",
213
+ props.allowDevEnvInProd ? "1" : "0",
214
+ props.blockLocalhostBaseURLInProd === false ? "0" : "1",
215
+ hasChildren ? "children:1" : "children:0"
216
+ ].join("|"),
217
+ [
218
+ containerId,
219
+ props.workspace,
220
+ props.appId,
221
+ props.baseURL,
222
+ props.src,
223
+ props.runtimeMinVersion,
224
+ props.runtimeExactVersion,
225
+ props.allowDevEnvInProd,
226
+ props.blockLocalhostBaseURLInProd,
227
+ hasChildren
228
+ ]
229
+ );
230
+ const handleRef = useRef(null);
231
+ const [status, setStatus] = useState("idle");
232
+ const [lastError, setLastError] = useState(null);
233
+ const [readyInfo, setReadyInfo] = useState(null);
234
+ const [snapshot, setSnapshot] = useState(null);
235
+ useEffect(() => {
236
+ let cancelled = false;
237
+ setStatus("loading");
238
+ setLastError(null);
239
+ setReadyInfo(null);
240
+ setSnapshot(null);
241
+ handleRef.current = null;
242
+ const report = (err) => {
243
+ setLastError(err);
244
+ setStatus("error");
245
+ if (!props.silent) {
246
+ console.warn("[@manyrows/appkit-react]", err.code, err.message, err.details ?? "");
247
+ }
248
+ props.onError?.(err);
249
+ };
250
+ const init = async () => {
251
+ if (!props.workspace?.trim() || !props.appId?.trim()) {
252
+ report(
253
+ mkErr("INVALID_PROPS", "workspace and appId are required.", {
254
+ workspace: props.workspace,
255
+ appId: props.appId
256
+ })
257
+ );
258
+ return;
259
+ }
260
+ const prod = isProbablyProdBuild();
261
+ if (prod && props.blockLocalhostBaseURLInProd !== false && props.baseURL && looksLikeLocalhost(props.baseURL)) {
262
+ report(
263
+ mkErr(
264
+ "BASE_URL_NOT_ALLOWED_IN_PROD",
265
+ "localhost baseURL is not allowed in production builds.",
266
+ { baseURL: props.baseURL }
267
+ )
268
+ );
269
+ return;
270
+ }
271
+ try {
272
+ const timeoutMs = props.timeoutMs ?? (props.src ? 4e3 : 2500);
273
+ if (props.src) {
274
+ await ensureScriptLoaded(props.src, timeoutMs);
275
+ }
276
+ const start = Date.now();
277
+ while (!getManyRowsAppKitRuntime() && Date.now() - start < timeoutMs) {
278
+ if (cancelled) return;
279
+ await new Promise((r) => setTimeout(r, 25));
280
+ }
281
+ const api = getManyRowsAppKitRuntime();
282
+ if (!api) {
283
+ report(
284
+ mkErr(
285
+ props.src ? "SCRIPT_TIMEOUT" : "RUNTIME_NOT_FOUND",
286
+ props.src ? `AppKit runtime not found after loading script: ${props.src}` : "AppKit runtime not found.",
287
+ { src: props.src }
288
+ )
289
+ );
290
+ return;
291
+ }
292
+ const runtimeVersion = api?.version;
293
+ if (props.runtimeExactVersion) {
294
+ const expected = props.runtimeExactVersion.trim();
295
+ if (!expected) {
296
+ report(mkErr("INVALID_PROPS", "runtimeExactVersion must be a non-empty string."));
297
+ return;
298
+ }
299
+ const found = typeof runtimeVersion === "string" ? runtimeVersion.trim() : "";
300
+ if (found !== expected) {
301
+ report(
302
+ mkErr("RUNTIME_VERSION_MISMATCH", "AppKit runtime version mismatch.", {
303
+ expected,
304
+ found: runtimeVersion
305
+ })
306
+ );
307
+ return;
308
+ }
309
+ } else if (props.runtimeMinVersion) {
310
+ const min = props.runtimeMinVersion.trim();
311
+ if (!min) {
312
+ report(mkErr("INVALID_PROPS", "runtimeMinVersion must be a non-empty string."));
313
+ return;
314
+ }
315
+ const ok = semverGte(runtimeVersion, min);
316
+ if (!ok) {
317
+ report(
318
+ mkErr("RUNTIME_VERSION_TOO_OLD", "AppKit runtime is too old.", {
319
+ requiredMin: min,
320
+ found: runtimeVersion,
321
+ parsedFound: parseSemver(runtimeVersion)
322
+ })
323
+ );
324
+ return;
325
+ }
326
+ }
327
+ const handle = api.init({
328
+ containerId,
329
+ workspace: props.workspace.trim(),
330
+ appId: props.appId.trim(),
331
+ baseURL: props.baseURL,
332
+ silent: props.silent,
333
+ throwOnError: props.throwOnError,
334
+ // ✅ If host provides children, hide runtime default authed UI.
335
+ // Runtime will still render login / errors / forbidden screens as normal.
336
+ renderAuthed: hasChildren ? (() => null) : void 0,
337
+ onReady: (info) => {
338
+ if (cancelled) return;
339
+ setStatus("mounted");
340
+ setLastError(null);
341
+ setReadyInfo(info);
342
+ props.onReady?.(info);
343
+ },
344
+ onState: (s) => {
345
+ if (cancelled) return;
346
+ setSnapshot(s);
347
+ props.onState?.(s);
348
+ },
349
+ onReadyState: (s) => {
350
+ if (cancelled) return;
351
+ props.onReadyState?.(s);
352
+ },
353
+ onError: (e) => {
354
+ report(mkErr("RUNTIME_ERROR", "AppKit runtime error.", e));
355
+ }
356
+ });
357
+ handleRef.current = handle ?? null;
358
+ } catch (e) {
359
+ report(mkErr("SCRIPT_LOAD_FAILED", "Failed to load AppKit script.", { error: e }));
360
+ }
361
+ };
362
+ void init();
363
+ return () => {
364
+ cancelled = true;
365
+ try {
366
+ handleRef.current?.destroy?.();
367
+ } catch {
368
+ }
369
+ try {
370
+ const api = getManyRowsAppKitRuntime();
371
+ api?.destroy?.(containerId);
372
+ } catch {
373
+ }
374
+ handleRef.current = null;
375
+ };
376
+ }, [initKey]);
377
+ const showLoading = status === "loading" && !props.hideLoadingUI;
378
+ const showError = status === "error" && !!lastError && !props.hideErrorUI;
379
+ const ctx = useMemo(() => {
380
+ const h = handleRef.current;
381
+ return {
382
+ status,
383
+ error: lastError,
384
+ readyInfo,
385
+ snapshot,
386
+ isAuthenticated: isAuthedSnapshot(snapshot),
387
+ handle: h,
388
+ refresh: () => {
389
+ try {
390
+ h?.refresh?.();
391
+ } catch {
392
+ }
393
+ },
394
+ logout: async () => {
395
+ try {
396
+ await h?.logout?.();
397
+ } catch {
398
+ }
399
+ },
400
+ setToken: (tok) => {
401
+ try {
402
+ h?.setToken?.(tok);
403
+ } catch {
404
+ }
405
+ },
406
+ destroy: () => {
407
+ try {
408
+ h?.destroy?.();
409
+ } catch {
410
+ }
411
+ },
412
+ info: () => {
413
+ try {
414
+ return h?.info?.() ?? null;
415
+ } catch {
416
+ return null;
417
+ }
418
+ }
419
+ };
420
+ }, [status, lastError, readyInfo, snapshot]);
421
+ return /* @__PURE__ */ jsx(Ctx.Provider, { value: ctx, children: /* @__PURE__ */ jsxs("div", { className: props.className, style: props.style, children: [
422
+ showLoading ? props.loading ?? /* @__PURE__ */ jsx(DefaultSkeleton, {}) : null,
423
+ showError && lastError ? props.errorUI ? props.errorUI(lastError) : /* @__PURE__ */ jsx(DefaultError, { err: lastError }) : null,
424
+ props.children,
425
+ /* @__PURE__ */ jsx("div", { id: containerId })
426
+ ] }) });
427
+ }
428
+
429
+ export { AppKit, AppKitAuthed, useAppKit };
430
+ //# sourceMappingURL=index.js.map
431
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime.ts","../src/AppKit.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { AppKitRuntime } from \"./types\";\n\nexport function getManyRowsAppKitRuntime(): AppKitRuntime | null {\n const w = window as any;\n\n // Preferred: namespaced\n if (w.ManyRows?.AppKit?.init) return w.ManyRows.AppKit;\n\n // Back-compat: function globals\n if (w.initManyRowsAppKit) {\n return {\n init: w.initManyRowsAppKit,\n destroy: w.destroyManyRowsAppKit,\n info: w.getManyRowsAppKitInfo,\n };\n }\n\n return null;\n}\n\nexport function ensureScriptLoaded(src: string, timeoutMs: number): Promise<void> {\n return new Promise((resolve, reject) => {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n resolve(); // SSR: noop\n return;\n }\n\n // Already present?\n if (document.querySelector(`script[data-manyrows-appkit=\"true\"][src=\"${src}\"]`)) {\n resolve();\n return;\n }\n\n // If runtime already exists, we’re good.\n if (getManyRowsAppKitRuntime()) {\n resolve();\n return;\n }\n\n const s = document.createElement(\"script\");\n s.src = src;\n s.async = true;\n s.crossOrigin = \"anonymous\";\n s.setAttribute(\"data-manyrows-appkit\", \"true\");\n\n const timer = window.setTimeout(() => {\n cleanup();\n reject(new Error(`Timed out loading AppKit script after ${timeoutMs}ms: ${src}`));\n }, timeoutMs);\n\n function cleanup() {\n window.clearTimeout(timer);\n s.onload = null;\n s.onerror = null;\n }\n\n s.onload = () => {\n cleanup();\n resolve();\n };\n\n s.onerror = (e) => {\n cleanup();\n reject(e);\n };\n\n document.head.appendChild(s);\n });\n}\n","// appkit-react/AppKit.tsx\nimport React, {\n createContext,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n ManyRowsAppKitError,\n ManyRowsAppKitReady,\n ManyRowsAppKitHandle,\n ManyRowsAppKitSnapshot,\n} from \"./types\";\nimport { ensureScriptLoaded, getManyRowsAppKitRuntime } from \"./runtime\";\n\n// -----------------------------\n// Tiny semver helpers (no deps)\n// -----------------------------\n\ntype Semver = { major: number; minor: number; patch: number };\n\nfunction parseSemver(v: unknown): Semver | null {\n if (typeof v !== \"string\") return null;\n const s = v.trim();\n const m = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(s);\n if (!m) return null;\n const major = Number(m[1]);\n const minor = Number(m[2]);\n const patch = Number(m[3]);\n if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) return null;\n return { major, minor, patch };\n}\n\nfunction cmpSemver(a: Semver, b: Semver): number {\n if (a.major !== b.major) return a.major - b.major;\n if (a.minor !== b.minor) return a.minor - b.minor;\n return a.patch - b.patch;\n}\n\nfunction semverGte(runtimeVersion: unknown, minVersion: string): boolean {\n const r = parseSemver(runtimeVersion);\n const m = parseSemver(minVersion);\n if (!r || !m) return false;\n return cmpSemver(r, m) >= 0;\n}\n\n// -----------------------------\n// Prod/dev safety helpers\n// -----------------------------\n\nfunction isProbablyProdBuild(): boolean {\n const p = (globalThis as any)?.process;\n const env = p?.env?.NODE_ENV;\n return env === \"production\";\n}\n\nfunction looksLikeLocalhost(url: string): boolean {\n const s = (url || \"\").trim().toLowerCase();\n return (\n s.startsWith(\"http://localhost\") ||\n s.startsWith(\"https://localhost\") ||\n s.startsWith(\"http://127.0.0.1\") ||\n s.startsWith(\"https://127.0.0.1\") ||\n s.startsWith(\"http://0.0.0.0\") ||\n s.startsWith(\"https://0.0.0.0\")\n );\n}\n\n// -----------------------------\n// Auth predicate (snapshot is loose)\n// -----------------------------\n\nfunction isAuthedSnapshot(s: ManyRowsAppKitSnapshot | null | undefined): boolean {\n if (!s || typeof s !== \"object\") return false;\n const status = (s as any).status;\n if (status !== \"authenticated\") return false;\n\n const appData = (s as any).appData;\n if (!appData || typeof appData !== \"object\") return false;\n\n // don’t over-constrain v0\n return true;\n}\n\n// -----------------------------\n// AppKit context + hook\n// -----------------------------\n\nexport type AppKitContextValue = {\n status: \"idle\" | \"loading\" | \"mounted\" | \"error\";\n error: ManyRowsAppKitError | null;\n\n readyInfo: ManyRowsAppKitReady | null;\n snapshot: ManyRowsAppKitSnapshot | null;\n\n // convenience derived flag\n isAuthenticated: boolean;\n\n // present when runtime supports handle API\n handle: ManyRowsAppKitHandle | null;\n\n // convenience methods (safe no-ops if handle missing)\n refresh: () => void;\n logout: () => Promise<void>;\n setToken: (tok: string | null) => void;\n destroy: () => void;\n info: () => ManyRowsAppKitReady | null;\n};\n\nconst Ctx = createContext<AppKitContextValue | null>(null);\n\nexport function useAppKit(): AppKitContextValue {\n const v = useContext(Ctx);\n if (!v) throw new Error(\"useAppKit() must be used under <AppKit />\");\n return v;\n}\n\n/**\n * Render children only when the AppKit runtime is authenticated and appData exists.\n * Use this to mount your customer app \"behind\" the AppKit login screen.\n */\nexport function AppKitAuthed(props: {\n children: React.ReactNode;\n /**\n * Optional: shown when not authenticated (or still checking).\n * Default: null (render nothing).\n */\n fallback?: React.ReactNode;\n}) {\n const { isAuthenticated } = useAppKit();\n if (!isAuthenticated) return <>{props.fallback ?? null}</>;\n return <>{props.children}</>;\n}\n\n// -----------------------------\n// Props\n// -----------------------------\n\nexport type AppKitProps = {\n workspace: string;\n\n // ✅ replaces project+env\n appId: string;\n\n baseURL?: string;\n\n src?: string;\n timeoutMs?: number;\n\n silent?: boolean;\n throwOnError?: boolean;\n\n onReady?: (info: ManyRowsAppKitReady) => void;\n onError?: (err: ManyRowsAppKitError) => void;\n\n /**\n * Fired for every snapshot update from the runtime (checking/unauth/authed/etc).\n */\n onState?: (snapshot: ManyRowsAppKitSnapshot | null) => void;\n\n /**\n * Fired when AppKit is authenticated and appData is available.\n * This is the correct place to render the customer app (imperative style).\n */\n onReadyState?: (snapshot: ManyRowsAppKitSnapshot) => void;\n\n className?: string;\n style?: React.CSSProperties;\n containerId?: string;\n\n runtimeMinVersion?: string;\n runtimeExactVersion?: string;\n\n loading?: React.ReactNode;\n errorUI?: (err: ManyRowsAppKitError) => React.ReactNode;\n hideLoadingUI?: boolean;\n hideErrorUI?: boolean;\n\n // kept for future (no longer used now that env is arbitrary)\n allowDevEnvInProd?: boolean;\n blockLocalhostBaseURLInProd?: boolean;\n\n // ✅ allow <AppKit>children</AppKit>\n children?: React.ReactNode;\n};\n\n// -----------------------------\n// Errors / UI\n// -----------------------------\n\nfunction mkErr(\n code: ManyRowsAppKitError[\"code\"],\n message: string,\n details?: unknown\n): ManyRowsAppKitError {\n return { code, message, details };\n}\n\nfunction DefaultSkeleton() {\n return (\n <div\n aria-busy=\"true\"\n aria-live=\"polite\"\n style={{\n width: \"100%\",\n borderRadius: 10,\n border: \"1px solid rgba(0,0,0,0.08)\",\n padding: 12,\n }}\n >\n <div\n style={{\n height: 12,\n width: 140,\n borderRadius: 6,\n background: \"rgba(0,0,0,0.06)\",\n marginBottom: 10,\n }}\n />\n <div\n style={{\n height: 10,\n width: \"65%\",\n borderRadius: 6,\n background: \"rgba(0,0,0,0.06)\",\n marginBottom: 8,\n }}\n />\n <div\n style={{\n height: 10,\n width: \"40%\",\n borderRadius: 6,\n background: \"rgba(0,0,0,0.06)\",\n }}\n />\n </div>\n );\n}\n\nfunction DefaultError({ err }: { err: ManyRowsAppKitError }) {\n return (\n <div\n role=\"alert\"\n style={{\n width: \"100%\",\n borderRadius: 10,\n border: \"1px solid rgba(220, 38, 38, 0.35)\",\n background: \"rgba(220, 38, 38, 0.06)\",\n padding: 12,\n fontFamily:\n 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n }}\n >\n <div style={{ fontWeight: 700, marginBottom: 6 }}>ManyRows AppKit failed to load</div>\n <div style={{ fontSize: 13, marginBottom: 8 }}>\n <span style={{ fontWeight: 600 }}>{err.code}</span>: {err.message}\n </div>\n {err.details !== undefined ? (\n <pre\n style={{\n fontSize: 12,\n margin: 0,\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n opacity: 0.8,\n }}\n >\n {typeof err.details === \"string\" ? err.details : JSON.stringify(err.details, null, 2)}\n </pre>\n ) : null}\n </div>\n );\n}\n\n// -----------------------------\n// Component\n// -----------------------------\n\nexport function AppKit(props: AppKitProps) {\n const autoId = useId();\n const containerId = props.containerId ?? `manyrows-appkit-${autoId.replace(/[:]/g, \"\")}`;\n\n // If host supplies children, we assume host wants to own the authed UI.\n // In that case, suppress the runtime's *default* authed screen by passing renderAuthed={() => null}.\n const hasChildren = React.Children.count(props.children) > 0;\n\n const initKey = useMemo(\n () =>\n [\n containerId,\n props.workspace,\n props.appId,\n props.baseURL ?? \"\",\n props.src ?? \"\",\n props.runtimeMinVersion ?? \"\",\n props.runtimeExactVersion ?? \"\",\n props.allowDevEnvInProd ? \"1\" : \"0\",\n props.blockLocalhostBaseURLInProd === false ? \"0\" : \"1\",\n hasChildren ? \"children:1\" : \"children:0\",\n ].join(\"|\"),\n [\n containerId,\n props.workspace,\n props.appId,\n props.baseURL,\n props.src,\n props.runtimeMinVersion,\n props.runtimeExactVersion,\n props.allowDevEnvInProd,\n props.blockLocalhostBaseURLInProd,\n hasChildren,\n ]\n );\n\n const handleRef = useRef<ManyRowsAppKitHandle | null>(null);\n\n const [status, setStatus] = useState<\"idle\" | \"loading\" | \"mounted\" | \"error\">(\"idle\");\n const [lastError, setLastError] = useState<ManyRowsAppKitError | null>(null);\n\n const [readyInfo, setReadyInfo] = useState<ManyRowsAppKitReady | null>(null);\n const [snapshot, setSnapshot] = useState<ManyRowsAppKitSnapshot | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n\n setStatus(\"loading\");\n setLastError(null);\n setReadyInfo(null);\n setSnapshot(null);\n handleRef.current = null;\n\n const report = (err: ManyRowsAppKitError) => {\n setLastError(err);\n setStatus(\"error\");\n\n if (!props.silent) {\n // eslint-disable-next-line no-console\n console.warn(\"[@manyrows/appkit-react]\", err.code, err.message, err.details ?? \"\");\n }\n props.onError?.(err);\n };\n\n const init = async () => {\n if (!props.workspace?.trim() || !props.appId?.trim()) {\n report(\n mkErr(\"INVALID_PROPS\", \"workspace and appId are required.\", {\n workspace: props.workspace,\n appId: props.appId,\n })\n );\n return;\n }\n\n const prod = isProbablyProdBuild();\n\n if (\n prod &&\n props.blockLocalhostBaseURLInProd !== false &&\n props.baseURL &&\n looksLikeLocalhost(props.baseURL)\n ) {\n report(\n mkErr(\n \"BASE_URL_NOT_ALLOWED_IN_PROD\",\n \"localhost baseURL is not allowed in production builds.\",\n { baseURL: props.baseURL }\n )\n );\n return;\n }\n\n try {\n const timeoutMs = props.timeoutMs ?? (props.src ? 4000 : 2500);\n\n if (props.src) {\n await ensureScriptLoaded(props.src, timeoutMs);\n }\n\n const start = Date.now();\n while (!getManyRowsAppKitRuntime() && Date.now() - start < timeoutMs) {\n if (cancelled) return;\n await new Promise((r) => setTimeout(r, 25));\n }\n\n const api = getManyRowsAppKitRuntime();\n if (!api) {\n report(\n mkErr(\n props.src ? \"SCRIPT_TIMEOUT\" : \"RUNTIME_NOT_FOUND\",\n props.src\n ? `AppKit runtime not found after loading script: ${props.src}`\n : \"AppKit runtime not found.\",\n { src: props.src }\n )\n );\n return;\n }\n\n const runtimeVersion: unknown = (api as any)?.version;\n\n if (props.runtimeExactVersion) {\n const expected = props.runtimeExactVersion.trim();\n if (!expected) {\n report(mkErr(\"INVALID_PROPS\", \"runtimeExactVersion must be a non-empty string.\"));\n return;\n }\n const found = typeof runtimeVersion === \"string\" ? runtimeVersion.trim() : \"\";\n if (found !== expected) {\n report(\n mkErr(\"RUNTIME_VERSION_MISMATCH\", \"AppKit runtime version mismatch.\", {\n expected,\n found: runtimeVersion,\n })\n );\n return;\n }\n } else if (props.runtimeMinVersion) {\n const min = props.runtimeMinVersion.trim();\n if (!min) {\n report(mkErr(\"INVALID_PROPS\", \"runtimeMinVersion must be a non-empty string.\"));\n return;\n }\n const ok = semverGte(runtimeVersion, min);\n if (!ok) {\n report(\n mkErr(\"RUNTIME_VERSION_TOO_OLD\", \"AppKit runtime is too old.\", {\n requiredMin: min,\n found: runtimeVersion,\n parsedFound: parseSemver(runtimeVersion),\n })\n );\n return;\n }\n }\n\n const handle = (api as any).init({\n containerId,\n workspace: props.workspace.trim(),\n appId: props.appId.trim(),\n baseURL: props.baseURL,\n silent: props.silent,\n throwOnError: props.throwOnError,\n\n // ✅ If host provides children, hide runtime default authed UI.\n // Runtime will still render login / errors / forbidden screens as normal.\n renderAuthed: hasChildren ? (() => null) : undefined,\n\n onReady: (info: ManyRowsAppKitReady) => {\n if (cancelled) return;\n setStatus(\"mounted\");\n setLastError(null);\n setReadyInfo(info);\n props.onReady?.(info);\n },\n\n onState: (s: ManyRowsAppKitSnapshot | null) => {\n if (cancelled) return;\n setSnapshot(s);\n props.onState?.(s);\n },\n\n onReadyState: (s: ManyRowsAppKitSnapshot) => {\n if (cancelled) return;\n props.onReadyState?.(s);\n },\n\n onError: (e: any) => {\n report(mkErr(\"RUNTIME_ERROR\", \"AppKit runtime error.\", e));\n },\n });\n\n handleRef.current = handle ?? null;\n } catch (e) {\n report(mkErr(\"SCRIPT_LOAD_FAILED\", \"Failed to load AppKit script.\", { error: e }));\n }\n };\n\n void init();\n\n return () => {\n cancelled = true;\n\n try {\n handleRef.current?.destroy?.();\n } catch {\n // ignore\n }\n\n try {\n const api = getManyRowsAppKitRuntime();\n api?.destroy?.(containerId);\n } catch {\n // ignore\n }\n\n handleRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initKey]);\n\n const showLoading = status === \"loading\" && !props.hideLoadingUI;\n const showError = status === \"error\" && !!lastError && !props.hideErrorUI;\n\n const ctx: AppKitContextValue = useMemo(() => {\n const h = handleRef.current;\n\n return {\n status,\n error: lastError,\n readyInfo,\n snapshot,\n isAuthenticated: isAuthedSnapshot(snapshot),\n handle: h,\n\n refresh: () => {\n try {\n h?.refresh?.();\n } catch {\n // ignore\n }\n },\n logout: async () => {\n try {\n await h?.logout?.();\n } catch {\n // ignore\n }\n },\n setToken: (tok: string | null) => {\n try {\n h?.setToken?.(tok);\n } catch {\n // ignore\n }\n },\n destroy: () => {\n try {\n h?.destroy?.();\n } catch {\n // ignore\n }\n },\n info: () => {\n try {\n return h?.info?.() ?? null;\n } catch {\n return null;\n }\n },\n };\n }, [status, lastError, readyInfo, snapshot]);\n\n return (\n <Ctx.Provider value={ctx}>\n <div className={props.className} style={props.style}>\n {showLoading ? props.loading ?? <DefaultSkeleton /> : null}\n {showError && lastError\n ? props.errorUI\n ? props.errorUI(lastError)\n : <DefaultError err={lastError} />\n : null}\n\n {/* Host-side children (can use AppKitAuthed/useAppKit) */}\n {props.children}\n\n {/* Runtime owns all UI inside this container */}\n <div id={containerId} />\n </div>\n </Ctx.Provider>\n );\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@manyrows/appkit-react",
3
+ "version": "0.1.0",
4
+ "sideEffects": false,
5
+ "private": false,
6
+ "type": "module",
7
+ "files": ["dist"],
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "peerDependencies": {
19
+ "react": ">=18",
20
+ "react-dom": ">=18"
21
+ },
22
+ "devDependencies": {
23
+ "@types/react": "^19.2.9",
24
+ "@types/react-dom": "^19.2.3",
25
+ "tsup": "^8.5.1",
26
+ "typescript": "^5.9.3"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "dev": "tsup --watch",
34
+ "prepublishOnly": "npm run build"
35
+ }
36
+ }