@omg-dev/sdk 0.4.28 → 0.4.30
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as VibesFeedback } from "./VibesFeedback-BF2Vf6FK.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { useId, useState } from "react";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/brand/OmgBadge.tsx
|
|
5
5
|
const BRAND = "#FF5530";
|
|
@@ -13,107 +13,17 @@ function feedbackBundled() {
|
|
|
13
13
|
return true;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
const DISMISS_KEY = "vibes-remix:dismissed";
|
|
17
|
-
const REMIX_ORIGIN = typeof import.meta !== "undefined" && import.meta.env?.VITE_REMIX_ORIGIN || "https://omg.dev";
|
|
18
|
-
const CONTROLPLANE_URL = (typeof import.meta !== "undefined" && import.meta.env?.VITE_CONTROLPLANE_URL || "https://backend.omg.dev").replace(/\/$/, "");
|
|
19
|
-
function appSlug() {
|
|
20
|
-
if (typeof import.meta === "undefined") return null;
|
|
21
|
-
const slug = import.meta.env?.VITE_APP_SLUG?.trim();
|
|
22
|
-
if (!slug || !/^[a-z0-9-]+$/.test(slug)) return null;
|
|
23
|
-
return slug;
|
|
24
|
-
}
|
|
25
|
-
function isDismissed() {
|
|
26
|
-
try {
|
|
27
|
-
return localStorage.getItem(DISMISS_KEY) === "1";
|
|
28
|
-
} catch {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function setDismissedFlag() {
|
|
33
|
-
try {
|
|
34
|
-
localStorage.setItem(DISMISS_KEY, "1");
|
|
35
|
-
} catch {}
|
|
36
|
-
}
|
|
37
|
-
/** Live check: only Explore-listed public apps may show "Make it mine". Fail closed. */
|
|
38
|
-
async function fetchRemixable(slug) {
|
|
39
|
-
try {
|
|
40
|
-
const res = await fetch(`${CONTROLPLANE_URL}/api/projects/isRemixable`, {
|
|
41
|
-
method: "POST",
|
|
42
|
-
headers: { "content-type": "application/json" },
|
|
43
|
-
body: JSON.stringify({ slug }),
|
|
44
|
-
cache: "no-store"
|
|
45
|
-
});
|
|
46
|
-
if (!res.ok) return false;
|
|
47
|
-
return (await res.json())?.remixable === true;
|
|
48
|
-
} catch {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
16
|
function OmgBadge({ href = "https://omg.dev", label = "What is omg?" }) {
|
|
53
17
|
const [open, setOpen] = useState(false);
|
|
54
|
-
const slug = appSlug();
|
|
55
|
-
const [remix, setRemix] = useState(false);
|
|
56
18
|
const titleId = useId();
|
|
57
19
|
const descriptionId = useId();
|
|
58
20
|
const markId = useId().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
if (!slug || isDismissed()) return;
|
|
61
|
-
let cancelled = false;
|
|
62
|
-
fetchRemixable(slug).then((ok) => {
|
|
63
|
-
if (!cancelled && ok && !isDismissed()) setRemix(true);
|
|
64
|
-
});
|
|
65
|
-
return () => {
|
|
66
|
-
cancelled = true;
|
|
67
|
-
};
|
|
68
|
-
}, [slug]);
|
|
69
|
-
function dismissRemix() {
|
|
70
|
-
setDismissedFlag();
|
|
71
|
-
setRemix(false);
|
|
72
|
-
}
|
|
73
21
|
function summonFeedback() {
|
|
74
22
|
setOpen(false);
|
|
75
23
|
if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent(FEEDBACK_OPEN_EVENT));
|
|
76
24
|
}
|
|
77
25
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
78
|
-
|
|
79
|
-
href: `${REMIX_ORIGIN}/remix/${slug}?ref=pwa`,
|
|
80
|
-
"aria-label": "Make this app mine",
|
|
81
|
-
"data-vibes-feedback": "",
|
|
82
|
-
style: badgeStyle,
|
|
83
|
-
children: [
|
|
84
|
-
/* @__PURE__ */ jsx(OmgMark, {
|
|
85
|
-
size: 18,
|
|
86
|
-
id: `remix-${markId}`
|
|
87
|
-
}),
|
|
88
|
-
/* @__PURE__ */ jsx("span", {
|
|
89
|
-
style: badgeTextStyle,
|
|
90
|
-
children: "Make it mine"
|
|
91
|
-
}),
|
|
92
|
-
/* @__PURE__ */ jsx("button", {
|
|
93
|
-
type: "button",
|
|
94
|
-
"aria-label": "Dismiss",
|
|
95
|
-
onClick: (event) => {
|
|
96
|
-
event.preventDefault();
|
|
97
|
-
event.stopPropagation();
|
|
98
|
-
dismissRemix();
|
|
99
|
-
},
|
|
100
|
-
style: dismissStyle,
|
|
101
|
-
children: /* @__PURE__ */ jsx("svg", {
|
|
102
|
-
"aria-hidden": "true",
|
|
103
|
-
width: "13",
|
|
104
|
-
height: "13",
|
|
105
|
-
viewBox: "0 0 24 24",
|
|
106
|
-
fill: "none",
|
|
107
|
-
children: /* @__PURE__ */ jsx("path", {
|
|
108
|
-
d: "M6 6l12 12M18 6 6 18",
|
|
109
|
-
stroke: "currentColor",
|
|
110
|
-
strokeWidth: "2.4",
|
|
111
|
-
strokeLinecap: "round"
|
|
112
|
-
})
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
]
|
|
116
|
-
}) : /* @__PURE__ */ jsxs("button", {
|
|
26
|
+
/* @__PURE__ */ jsxs("button", {
|
|
117
27
|
type: "button",
|
|
118
28
|
"aria-label": label,
|
|
119
29
|
"data-vibes-feedback": "",
|
|
@@ -262,19 +172,6 @@ const badgeTextStyle = {
|
|
|
262
172
|
letterSpacing: 0,
|
|
263
173
|
padding: "0 3px"
|
|
264
174
|
};
|
|
265
|
-
const dismissStyle = {
|
|
266
|
-
width: 22,
|
|
267
|
-
height: 22,
|
|
268
|
-
flex: "0 0 auto",
|
|
269
|
-
borderRadius: 999,
|
|
270
|
-
border: "none",
|
|
271
|
-
background: "rgba(20, 16, 12, 0.06)",
|
|
272
|
-
color: "#6b6459",
|
|
273
|
-
display: "grid",
|
|
274
|
-
placeItems: "center",
|
|
275
|
-
cursor: "pointer",
|
|
276
|
-
padding: 0
|
|
277
|
-
};
|
|
278
175
|
const backdropStyle = {
|
|
279
176
|
position: "fixed",
|
|
280
177
|
inset: 0,
|
package/dist/brand/auto.mjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as installTrace, c as requestMotionPermission, d as getAuthContext, f as notifyAuthRequired, h as subscribeAuthRequired, i as getTrace, l as useFeedbackGesture, m as subscribeAuthChange, n as captureScreenshot, o as attachGestureListeners, p as setAuthContext, r as clearTrace, s as motionPermissionState, t as VibesFeedback, u as useUpload } from "./VibesFeedback-BF2Vf6FK.mjs";
|
|
2
|
-
import { t as OmgBadge } from "./OmgBadge-
|
|
2
|
+
import { t as OmgBadge } from "./OmgBadge-DPcZZfJl.mjs";
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
4
|
import { fetchEventSource } from "@microsoft/fetch-event-source";
|
|
5
5
|
import { createAuthClient } from "better-auth/react";
|
package/package.json
CHANGED
package/src/brand/OmgBadge.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useId, useState, type CSSProperties } from "react"
|
|
2
2
|
import { VibesFeedback } from "../feedback/VibesFeedback"
|
|
3
3
|
|
|
4
4
|
export interface OmgBadgeProps {
|
|
@@ -31,97 +31,15 @@ function feedbackBundled(): boolean {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// ── Remix ("Make it mine") gating ────────────────────────────────────────────
|
|
35
|
-
// The badge's first job on a PUBLIC Explore-listed app is the recipient→creator
|
|
36
|
-
// hinge: a visitor who only has the shared link can fork the app back on
|
|
37
|
-
// omg.dev. Private (not listed) apps keep the plain branding badge only —
|
|
38
|
-
// remixBySlug rejects them, so the CTA must never appear. Once dismissed, the
|
|
39
|
-
// SAME badge collapses to branding — the omg mark never leaves, only the CTA.
|
|
40
|
-
const DISMISS_KEY = "vibes-remix:dismissed"
|
|
41
|
-
const REMIX_ORIGIN =
|
|
42
|
-
(typeof import.meta !== "undefined" &&
|
|
43
|
-
(import.meta as { env?: Record<string, string | undefined> }).env?.VITE_REMIX_ORIGIN) ||
|
|
44
|
-
"https://omg.dev"
|
|
45
|
-
// Control-plane host for the unauthenticated isRemixable probe. Overridable for
|
|
46
|
-
// self-host; defaults to production. CORS is open for this path only (Caddy).
|
|
47
|
-
const CONTROLPLANE_URL = (
|
|
48
|
-
(typeof import.meta !== "undefined" &&
|
|
49
|
-
(import.meta as { env?: Record<string, string | undefined> }).env?.VITE_CONTROLPLANE_URL) ||
|
|
50
|
-
"https://backend.omg.dev"
|
|
51
|
-
).replace(/\/$/, "")
|
|
52
|
-
|
|
53
|
-
function appSlug(): string | null {
|
|
54
|
-
if (typeof import.meta === "undefined") return null
|
|
55
|
-
const env = (import.meta as { env?: Record<string, string | undefined> }).env
|
|
56
|
-
const slug = env?.VITE_APP_SLUG?.trim()
|
|
57
|
-
if (!slug || !/^[a-z0-9-]+$/.test(slug)) return null
|
|
58
|
-
return slug
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function isDismissed(): boolean {
|
|
62
|
-
try {
|
|
63
|
-
return localStorage.getItem(DISMISS_KEY) === "1"
|
|
64
|
-
} catch {
|
|
65
|
-
return false
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function setDismissedFlag() {
|
|
70
|
-
try {
|
|
71
|
-
localStorage.setItem(DISMISS_KEY, "1")
|
|
72
|
-
} catch {
|
|
73
|
-
/* private mode */
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Live check: only Explore-listed public apps may show "Make it mine". Fail closed. */
|
|
78
|
-
async function fetchRemixable(slug: string): Promise<boolean> {
|
|
79
|
-
try {
|
|
80
|
-
const res = await fetch(`${CONTROLPLANE_URL}/api/projects/isRemixable`, {
|
|
81
|
-
method: "POST",
|
|
82
|
-
headers: { "content-type": "application/json" },
|
|
83
|
-
body: JSON.stringify({ slug }),
|
|
84
|
-
// Public boolean; no credentials. Avoid caching a stale private→public flip.
|
|
85
|
-
cache: "no-store",
|
|
86
|
-
})
|
|
87
|
-
if (!res.ok) return false
|
|
88
|
-
const data = (await res.json()) as { remixable?: unknown }
|
|
89
|
-
return data?.remixable === true
|
|
90
|
-
} catch {
|
|
91
|
-
return false
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
34
|
export function OmgBadge({
|
|
96
35
|
href = "https://omg.dev",
|
|
97
36
|
label = "What is omg?",
|
|
98
37
|
}: OmgBadgeProps) {
|
|
99
38
|
const [open, setOpen] = useState(false)
|
|
100
|
-
// Fail closed: start as branding. Promote to remix only after the public
|
|
101
|
-
// catalog confirms this slug is listed — never flash "Make it mine" on a
|
|
102
|
-
// private published app while the probe is in flight.
|
|
103
|
-
const slug = appSlug()
|
|
104
|
-
const [remix, setRemix] = useState(false)
|
|
105
39
|
const titleId = useId()
|
|
106
40
|
const descriptionId = useId()
|
|
107
41
|
const markId = useId().replace(/[^a-zA-Z0-9_-]/g, "")
|
|
108
42
|
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
if (!slug || isDismissed()) return
|
|
111
|
-
let cancelled = false
|
|
112
|
-
void fetchRemixable(slug).then((ok) => {
|
|
113
|
-
if (!cancelled && ok && !isDismissed()) setRemix(true)
|
|
114
|
-
})
|
|
115
|
-
return () => {
|
|
116
|
-
cancelled = true
|
|
117
|
-
}
|
|
118
|
-
}, [slug])
|
|
119
|
-
|
|
120
|
-
function dismissRemix() {
|
|
121
|
-
setDismissedFlag()
|
|
122
|
-
setRemix(false)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
43
|
function summonFeedback() {
|
|
126
44
|
setOpen(false)
|
|
127
45
|
if (typeof window !== "undefined") {
|
|
@@ -131,47 +49,16 @@ export function OmgBadge({
|
|
|
131
49
|
|
|
132
50
|
return (
|
|
133
51
|
<>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
<OmgMark size={18} id={`remix-${markId}`} />
|
|
145
|
-
<span style={badgeTextStyle}>Make it mine</span>
|
|
146
|
-
<button
|
|
147
|
-
type="button"
|
|
148
|
-
aria-label="Dismiss"
|
|
149
|
-
onClick={(event) => {
|
|
150
|
-
event.preventDefault()
|
|
151
|
-
event.stopPropagation()
|
|
152
|
-
dismissRemix()
|
|
153
|
-
}}
|
|
154
|
-
style={dismissStyle}
|
|
155
|
-
>
|
|
156
|
-
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none">
|
|
157
|
-
<path d="M6 6l12 12M18 6 6 18" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" />
|
|
158
|
-
</svg>
|
|
159
|
-
</button>
|
|
160
|
-
</a>
|
|
161
|
-
) : (
|
|
162
|
-
// Branding state: the omg mark + "omg". Opens the "Built with omg"
|
|
163
|
-
// dialog, which also hosts the feedback entry.
|
|
164
|
-
<button
|
|
165
|
-
type="button"
|
|
166
|
-
aria-label={label}
|
|
167
|
-
data-vibes-feedback=""
|
|
168
|
-
onClick={() => setOpen(true)}
|
|
169
|
-
style={badgeStyle}
|
|
170
|
-
>
|
|
171
|
-
<OmgMark size={18} id={`badge-${markId}`} />
|
|
172
|
-
<span style={badgeTextStyle}>omg</span>
|
|
173
|
-
</button>
|
|
174
|
-
)}
|
|
52
|
+
<button
|
|
53
|
+
type="button"
|
|
54
|
+
aria-label={label}
|
|
55
|
+
data-vibes-feedback=""
|
|
56
|
+
onClick={() => setOpen(true)}
|
|
57
|
+
style={badgeStyle}
|
|
58
|
+
>
|
|
59
|
+
<OmgMark size={18} id={`badge-${markId}`} />
|
|
60
|
+
<span style={badgeTextStyle}>omg</span>
|
|
61
|
+
</button>
|
|
175
62
|
|
|
176
63
|
{open && (
|
|
177
64
|
<div
|
|
@@ -288,20 +175,6 @@ const badgeTextStyle: CSSProperties = {
|
|
|
288
175
|
padding: "0 3px",
|
|
289
176
|
}
|
|
290
177
|
|
|
291
|
-
const dismissStyle: CSSProperties = {
|
|
292
|
-
width: 22,
|
|
293
|
-
height: 22,
|
|
294
|
-
flex: "0 0 auto",
|
|
295
|
-
borderRadius: 999,
|
|
296
|
-
border: "none",
|
|
297
|
-
background: "rgba(20, 16, 12, 0.06)",
|
|
298
|
-
color: "#6b6459",
|
|
299
|
-
display: "grid",
|
|
300
|
-
placeItems: "center",
|
|
301
|
-
cursor: "pointer",
|
|
302
|
-
padding: 0,
|
|
303
|
-
}
|
|
304
|
-
|
|
305
178
|
const backdropStyle: CSSProperties = {
|
|
306
179
|
position: "fixed",
|
|
307
180
|
inset: 0,
|
package/src/brand/auto.tsx
CHANGED
|
@@ -4,11 +4,8 @@
|
|
|
4
4
|
// app's React tree so it survives user app rewrites and does not require each
|
|
5
5
|
// generated app to carry attribution code in its source.
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// branding badge on dismiss or when the app is private, and bundles the
|
|
10
|
-
// (button-less) feedback sheet, summoned from its dialog. The vite-plugin
|
|
11
|
-
// therefore skips the standalone feedback/auto + remix-cta imports whenever
|
|
7
|
+
// The badge also bundles the button-less feedback sheet summoned from its
|
|
8
|
+
// dialog, so the vite plugin skips the standalone feedback control whenever
|
|
12
9
|
// this badge is enabled (the default).
|
|
13
10
|
|
|
14
11
|
import { createRoot } from "react-dom/client"
|