@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 { useEffect, useId, useState } from "react";
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
- remix && slug ? /* @__PURE__ */ jsxs("a", {
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,
@@ -1,4 +1,4 @@
1
- import { t as OmgBadge } from "../OmgBadge-CDnTIlnn.mjs";
1
+ import { t as OmgBadge } from "../OmgBadge-DPcZZfJl.mjs";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { createRoot } from "react-dom/client";
4
4
  //#region src/brand/auto.tsx
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-CDnTIlnn.mjs";
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omg-dev/sdk",
3
- "version": "0.4.28",
3
+ "version": "0.4.30",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,4 +1,4 @@
1
- import { useEffect, useId, useState, type CSSProperties } from "react"
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
- {remix && slug ? (
135
- // Remix state: the omg mark + "Make it mine" CTA. Tapping the pill body
136
- // navigates to the dashboard to fork the app; the ✕ collapses to the
137
- // branding badge. ?ref=pwa attributes the click on /remix.
138
- <a
139
- href={`${REMIX_ORIGIN}/remix/${slug}?ref=pwa`}
140
- aria-label="Make this app mine"
141
- data-vibes-feedback=""
142
- style={badgeStyle}
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,
@@ -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
- // One control, not three: this badge is the "Make it mine" remix CTA on a fresh
8
- // visit to a PUBLIC (Explore-listed) app (same omg mark), collapses to the plain
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"