@omg-dev/sdk 0.4.30 → 0.4.31
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/dist/{OmgBadge-DPcZZfJl.mjs → OmgBadge-C559Dp1f.mjs} +68 -114
- package/dist/brand/auto.mjs +1 -2
- package/dist/index.mjs +203 -23
- package/package.json +2 -7
- package/src/brand/OmgBadge.tsx +0 -57
- package/src/brand/auto.tsx +0 -6
- package/src/index.ts +0 -3
- package/src/sandbox.test.ts +4 -0
- package/src/sandbox.ts +1 -0
- package/dist/VibesFeedback-BF2Vf6FK.mjs +0 -808
- package/dist/feedback/auto.mjs +0 -26
- package/src/feedback/VibesFeedback.tsx +0 -360
- package/src/feedback/auto.tsx +0 -47
- package/src/feedback/gestures.ts +0 -296
- package/src/feedback/index.ts +0 -18
- package/src/feedback/screenshot.ts +0 -37
- package/src/feedback/trace.ts +0 -166
|
@@ -1,114 +1,85 @@
|
|
|
1
|
-
import { t as VibesFeedback } from "./VibesFeedback-BF2Vf6FK.mjs";
|
|
2
1
|
import { useId, useState } from "react";
|
|
3
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
3
|
//#region src/brand/OmgBadge.tsx
|
|
5
4
|
const BRAND = "#FF5530";
|
|
6
5
|
const Z_BADGE = 2147482e3;
|
|
7
6
|
const Z_DIALOG = 2147483100;
|
|
8
|
-
const FEEDBACK_OPEN_EVENT = "vibes:feedback:open";
|
|
9
|
-
function feedbackBundled() {
|
|
10
|
-
try {
|
|
11
|
-
return typeof __VIBES_BRAND_FEEDBACK__ === "undefined" ? true : __VIBES_BRAND_FEEDBACK__;
|
|
12
|
-
} catch {
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
7
|
function OmgBadge({ href = "https://omg.dev", label = "What is omg?" }) {
|
|
17
8
|
const [open, setOpen] = useState(false);
|
|
18
9
|
const titleId = useId();
|
|
19
10
|
const descriptionId = useId();
|
|
20
11
|
const markId = useId().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/* @__PURE__ */
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
height: "18",
|
|
63
|
-
viewBox: "0 0 24 24",
|
|
64
|
-
fill: "none",
|
|
65
|
-
children: /* @__PURE__ */ jsx("path", {
|
|
66
|
-
d: "M6 6l12 12M18 6 6 18",
|
|
67
|
-
stroke: "currentColor",
|
|
68
|
-
strokeWidth: "2",
|
|
69
|
-
strokeLinecap: "round"
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
}),
|
|
73
|
-
/* @__PURE__ */ jsx("div", {
|
|
74
|
-
style: markWrapStyle,
|
|
75
|
-
children: /* @__PURE__ */ jsx(OmgMark, {
|
|
76
|
-
size: 34,
|
|
77
|
-
id: `dialog-${markId}`
|
|
12
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("button", {
|
|
13
|
+
type: "button",
|
|
14
|
+
"aria-label": label,
|
|
15
|
+
onClick: () => setOpen(true),
|
|
16
|
+
style: badgeStyle,
|
|
17
|
+
children: [/* @__PURE__ */ jsx(OmgMark, {
|
|
18
|
+
size: 18,
|
|
19
|
+
id: `badge-${markId}`
|
|
20
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
21
|
+
style: badgeTextStyle,
|
|
22
|
+
children: "omg"
|
|
23
|
+
})]
|
|
24
|
+
}), open && /* @__PURE__ */ jsx("div", {
|
|
25
|
+
role: "presentation",
|
|
26
|
+
style: backdropStyle,
|
|
27
|
+
onMouseDown: (event) => {
|
|
28
|
+
if (event.target === event.currentTarget) setOpen(false);
|
|
29
|
+
},
|
|
30
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
31
|
+
role: "dialog",
|
|
32
|
+
"aria-modal": "true",
|
|
33
|
+
"aria-labelledby": titleId,
|
|
34
|
+
"aria-describedby": descriptionId,
|
|
35
|
+
style: dialogStyle,
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ jsx("button", {
|
|
38
|
+
type: "button",
|
|
39
|
+
"aria-label": "Close",
|
|
40
|
+
onClick: () => setOpen(false),
|
|
41
|
+
style: closeButtonStyle,
|
|
42
|
+
children: /* @__PURE__ */ jsx("svg", {
|
|
43
|
+
"aria-hidden": "true",
|
|
44
|
+
width: "18",
|
|
45
|
+
height: "18",
|
|
46
|
+
viewBox: "0 0 24 24",
|
|
47
|
+
fill: "none",
|
|
48
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
49
|
+
d: "M6 6l12 12M18 6 6 18",
|
|
50
|
+
stroke: "currentColor",
|
|
51
|
+
strokeWidth: "2",
|
|
52
|
+
strokeLinecap: "round"
|
|
78
53
|
})
|
|
79
|
-
}),
|
|
80
|
-
/* @__PURE__ */ jsx("h2", {
|
|
81
|
-
id: titleId,
|
|
82
|
-
style: titleStyle,
|
|
83
|
-
children: "Built with omg"
|
|
84
|
-
}),
|
|
85
|
-
/* @__PURE__ */ jsx("p", {
|
|
86
|
-
id: descriptionId,
|
|
87
|
-
style: bodyStyle,
|
|
88
|
-
children: "omg turns a plain-language idea into a real app, then hosts it with sign-in, data storage, and publishing already handled."
|
|
89
|
-
}),
|
|
90
|
-
/* @__PURE__ */ jsx("a", {
|
|
91
|
-
href,
|
|
92
|
-
target: "_blank",
|
|
93
|
-
rel: "noopener noreferrer",
|
|
94
|
-
style: ctaStyle,
|
|
95
|
-
children: "Learn about omg"
|
|
96
|
-
}),
|
|
97
|
-
feedbackBundled() && /* @__PURE__ */ jsx("button", {
|
|
98
|
-
type: "button",
|
|
99
|
-
onClick: summonFeedback,
|
|
100
|
-
style: secondaryStyle,
|
|
101
|
-
children: "Send feedback"
|
|
102
54
|
})
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
55
|
+
}),
|
|
56
|
+
/* @__PURE__ */ jsx("div", {
|
|
57
|
+
style: markWrapStyle,
|
|
58
|
+
children: /* @__PURE__ */ jsx(OmgMark, {
|
|
59
|
+
size: 34,
|
|
60
|
+
id: `dialog-${markId}`
|
|
61
|
+
})
|
|
62
|
+
}),
|
|
63
|
+
/* @__PURE__ */ jsx("h2", {
|
|
64
|
+
id: titleId,
|
|
65
|
+
style: titleStyle,
|
|
66
|
+
children: "Built with omg"
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ jsx("p", {
|
|
69
|
+
id: descriptionId,
|
|
70
|
+
style: bodyStyle,
|
|
71
|
+
children: "omg turns a plain-language idea into a real app, then hosts it with sign-in, data storage, and publishing already handled."
|
|
72
|
+
}),
|
|
73
|
+
/* @__PURE__ */ jsx("a", {
|
|
74
|
+
href,
|
|
75
|
+
target: "_blank",
|
|
76
|
+
rel: "noopener noreferrer",
|
|
77
|
+
style: ctaStyle,
|
|
78
|
+
children: "Learn about omg"
|
|
79
|
+
})
|
|
80
|
+
]
|
|
110
81
|
})
|
|
111
|
-
] });
|
|
82
|
+
})] });
|
|
112
83
|
}
|
|
113
84
|
function OmgMark({ size, id }) {
|
|
114
85
|
const maskId = `omg-mark-cut-${id}`;
|
|
@@ -247,22 +218,5 @@ const ctaStyle = {
|
|
|
247
218
|
textDecoration: "none",
|
|
248
219
|
letterSpacing: 0
|
|
249
220
|
};
|
|
250
|
-
const secondaryStyle = {
|
|
251
|
-
display: "inline-flex",
|
|
252
|
-
alignItems: "center",
|
|
253
|
-
justifyContent: "center",
|
|
254
|
-
width: "100%",
|
|
255
|
-
height: 44,
|
|
256
|
-
marginTop: 8,
|
|
257
|
-
borderRadius: 12,
|
|
258
|
-
background: "transparent",
|
|
259
|
-
border: "1px solid rgba(21, 17, 13, 0.14)",
|
|
260
|
-
color: "#15110d",
|
|
261
|
-
fontSize: 15,
|
|
262
|
-
fontWeight: 650,
|
|
263
|
-
cursor: "pointer",
|
|
264
|
-
fontFamily: font,
|
|
265
|
-
letterSpacing: 0
|
|
266
|
-
};
|
|
267
221
|
//#endregion
|
|
268
222
|
export { OmgBadge as t };
|
package/dist/brand/auto.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as OmgBadge } from "../OmgBadge-
|
|
1
|
+
import { t as OmgBadge } from "../OmgBadge-C559Dp1f.mjs";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createRoot } from "react-dom/client";
|
|
4
4
|
//#region src/brand/auto.tsx
|
|
@@ -8,7 +8,6 @@ function mount() {
|
|
|
8
8
|
if (document.getElementById(HOST_ID)) return;
|
|
9
9
|
const host = document.createElement("div");
|
|
10
10
|
host.id = HOST_ID;
|
|
11
|
-
host.setAttribute("data-vibes-feedback", "");
|
|
12
11
|
document.body.appendChild(host);
|
|
13
12
|
createRoot(host).render(/* @__PURE__ */ jsx(OmgBadge, {}));
|
|
14
13
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as OmgBadge } from "./OmgBadge-DPcZZfJl.mjs";
|
|
1
|
+
import { t as OmgBadge } from "./OmgBadge-C559Dp1f.mjs";
|
|
3
2
|
import { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
3
|
import { fetchEventSource } from "@microsoft/fetch-event-source";
|
|
5
4
|
import { createAuthClient } from "better-auth/react";
|
|
6
5
|
import { passkeyClient } from "@better-auth/passkey/client";
|
|
7
6
|
import { emailOTPClient, magicLinkClient } from "better-auth/client/plugins";
|
|
8
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
//#region src/auth/bridge.ts
|
|
9
|
+
let current = {
|
|
10
|
+
user: null,
|
|
11
|
+
token: null,
|
|
12
|
+
authReady: false
|
|
13
|
+
};
|
|
14
|
+
const authChangeListeners = /* @__PURE__ */ new Set();
|
|
15
|
+
function setAuthContext(snap) {
|
|
16
|
+
current = snap;
|
|
17
|
+
for (const cb of authChangeListeners) cb(snap);
|
|
18
|
+
}
|
|
19
|
+
function getAuthContext() {
|
|
20
|
+
return current;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Subscribe to auth snapshot changes (user / token / authReady). Returns an
|
|
24
|
+
* unsubscribe fn. Data hooks use this to re-establish a subscription when the
|
|
25
|
+
* JWT finishes loading (null→token) or on sign-out (token→null) — without it
|
|
26
|
+
* the WS connects once, often before getToken() resolves, and never retries
|
|
27
|
+
* with a bearer.
|
|
28
|
+
*/
|
|
29
|
+
function subscribeAuthChange(cb) {
|
|
30
|
+
authChangeListeners.add(cb);
|
|
31
|
+
return () => authChangeListeners.delete(cb);
|
|
32
|
+
}
|
|
33
|
+
const authRequiredListeners = /* @__PURE__ */ new Set();
|
|
34
|
+
/** Subscribe to auth-required signals. Returns an unsubscribe fn. */
|
|
35
|
+
function subscribeAuthRequired(cb) {
|
|
36
|
+
authRequiredListeners.add(cb);
|
|
37
|
+
return () => authRequiredListeners.delete(cb);
|
|
38
|
+
}
|
|
39
|
+
/** Notify all subscribers that a request hit the server's auth-required signal. */
|
|
40
|
+
function notifyAuthRequired() {
|
|
41
|
+
for (const cb of authRequiredListeners) cb();
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
9
44
|
//#region src/auth/client.ts
|
|
10
45
|
/**
|
|
11
46
|
* Recover the user carried by a slug-scoped JWT.
|
|
@@ -650,6 +685,143 @@ function VibesAuthGuard({ children, fallback, loadingFallback }) {
|
|
|
650
685
|
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
651
686
|
}
|
|
652
687
|
//#endregion
|
|
688
|
+
//#region src/storage/useUpload.ts
|
|
689
|
+
function bearerHeaders() {
|
|
690
|
+
const { token } = getAuthContext();
|
|
691
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Headless upload hook. Returns the upload function plus state.
|
|
695
|
+
*
|
|
696
|
+
* Usage:
|
|
697
|
+
* const { upload, uploading, progress, error } = useUpload()
|
|
698
|
+
* await upload(file, { key: `avatars/${user.id}.png` })
|
|
699
|
+
*/
|
|
700
|
+
function useUpload() {
|
|
701
|
+
const [state, setState] = useState({
|
|
702
|
+
uploading: false,
|
|
703
|
+
progress: 0,
|
|
704
|
+
error: null,
|
|
705
|
+
result: null
|
|
706
|
+
});
|
|
707
|
+
const reset = useCallback(() => {
|
|
708
|
+
setState({
|
|
709
|
+
uploading: false,
|
|
710
|
+
progress: 0,
|
|
711
|
+
error: null,
|
|
712
|
+
result: null
|
|
713
|
+
});
|
|
714
|
+
}, []);
|
|
715
|
+
const upload = useCallback(async (file, opts) => {
|
|
716
|
+
setState({
|
|
717
|
+
uploading: true,
|
|
718
|
+
progress: 0,
|
|
719
|
+
error: null,
|
|
720
|
+
result: null
|
|
721
|
+
});
|
|
722
|
+
const presignUrl = opts.presignUrl ?? "/api/_storage/presign";
|
|
723
|
+
const contentType = opts.contentType ?? file.type ?? "application/octet-stream";
|
|
724
|
+
try {
|
|
725
|
+
const presignRes = await fetch(presignUrl, {
|
|
726
|
+
method: "POST",
|
|
727
|
+
headers: {
|
|
728
|
+
"Content-Type": "application/json",
|
|
729
|
+
...bearerHeaders()
|
|
730
|
+
},
|
|
731
|
+
body: JSON.stringify({
|
|
732
|
+
action: "put",
|
|
733
|
+
key: opts.key,
|
|
734
|
+
contentType,
|
|
735
|
+
scope: opts.scope ?? "user"
|
|
736
|
+
})
|
|
737
|
+
});
|
|
738
|
+
if (!presignRes.ok) {
|
|
739
|
+
if (presignRes.status === 401 && getAuthContext().authReady) notifyAuthRequired();
|
|
740
|
+
const text = await presignRes.text().catch(() => "");
|
|
741
|
+
throw new Error(`presign ${presignRes.status}: ${text.slice(0, 200)}`);
|
|
742
|
+
}
|
|
743
|
+
const { url, key: storedKey, maxBytes } = await presignRes.json();
|
|
744
|
+
if (typeof maxBytes === "number" && file.size > maxBytes) throw new Error(`file too large (${file.size} > ${maxBytes} bytes)`);
|
|
745
|
+
await new Promise((resolve, reject) => {
|
|
746
|
+
const xhr = new XMLHttpRequest();
|
|
747
|
+
xhr.open("PUT", url);
|
|
748
|
+
xhr.setRequestHeader("Content-Type", contentType);
|
|
749
|
+
xhr.upload.onprogress = (e) => {
|
|
750
|
+
if (e.lengthComputable) {
|
|
751
|
+
const frac = e.loaded / e.total;
|
|
752
|
+
setState((s) => ({
|
|
753
|
+
...s,
|
|
754
|
+
progress: frac
|
|
755
|
+
}));
|
|
756
|
+
opts.onProgress?.(frac);
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
xhr.onload = () => {
|
|
760
|
+
if (xhr.status >= 200 && xhr.status < 300) resolve();
|
|
761
|
+
else reject(/* @__PURE__ */ new Error(`PUT ${xhr.status}: ${xhr.responseText.slice(0, 200)}`));
|
|
762
|
+
};
|
|
763
|
+
xhr.onerror = () => reject(/* @__PURE__ */ new Error("network error during upload"));
|
|
764
|
+
xhr.send(file);
|
|
765
|
+
});
|
|
766
|
+
const dlRes = await fetch(presignUrl, {
|
|
767
|
+
method: "POST",
|
|
768
|
+
headers: {
|
|
769
|
+
"Content-Type": "application/json",
|
|
770
|
+
...bearerHeaders()
|
|
771
|
+
},
|
|
772
|
+
body: JSON.stringify({
|
|
773
|
+
action: "get",
|
|
774
|
+
key: opts.key,
|
|
775
|
+
scope: opts.scope ?? "user"
|
|
776
|
+
})
|
|
777
|
+
});
|
|
778
|
+
let downloadUrl = "";
|
|
779
|
+
if (dlRes.ok) downloadUrl = (await dlRes.json()).url ?? "";
|
|
780
|
+
fetch(presignUrl.replace(/\/presign$/, "/notify"), {
|
|
781
|
+
method: "POST",
|
|
782
|
+
headers: {
|
|
783
|
+
"Content-Type": "application/json",
|
|
784
|
+
...bearerHeaders()
|
|
785
|
+
},
|
|
786
|
+
body: JSON.stringify({
|
|
787
|
+
action: "upload",
|
|
788
|
+
key: opts.key,
|
|
789
|
+
size: file.size,
|
|
790
|
+
contentType,
|
|
791
|
+
scope: opts.scope ?? "user"
|
|
792
|
+
})
|
|
793
|
+
}).catch(() => {});
|
|
794
|
+
const result = {
|
|
795
|
+
key: storedKey,
|
|
796
|
+
downloadUrl,
|
|
797
|
+
size: file.size,
|
|
798
|
+
contentType
|
|
799
|
+
};
|
|
800
|
+
setState({
|
|
801
|
+
uploading: false,
|
|
802
|
+
progress: 1,
|
|
803
|
+
error: null,
|
|
804
|
+
result
|
|
805
|
+
});
|
|
806
|
+
return result;
|
|
807
|
+
} catch (err) {
|
|
808
|
+
const msg = err.message ?? String(err);
|
|
809
|
+
setState({
|
|
810
|
+
uploading: false,
|
|
811
|
+
progress: 0,
|
|
812
|
+
error: msg,
|
|
813
|
+
result: null
|
|
814
|
+
});
|
|
815
|
+
throw err;
|
|
816
|
+
}
|
|
817
|
+
}, []);
|
|
818
|
+
return {
|
|
819
|
+
...state,
|
|
820
|
+
upload,
|
|
821
|
+
reset
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
//#endregion
|
|
653
825
|
//#region src/storage/VibesUpload.tsx
|
|
654
826
|
function defaultKeyFor(file) {
|
|
655
827
|
const safe = file.name.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
@@ -889,6 +1061,7 @@ async function createNotification(input) {
|
|
|
889
1061
|
const runtimeClaims = {
|
|
890
1062
|
llmInvoke: "llm.invoke",
|
|
891
1063
|
mediaInvoke: "media.invoke",
|
|
1064
|
+
speechTranscribe: "speech.transcribe",
|
|
892
1065
|
browserUse: "browser.use",
|
|
893
1066
|
sandboxCreate: "sandbox.create",
|
|
894
1067
|
sandboxDelegate: "sandbox.delegate"
|
|
@@ -1185,17 +1358,19 @@ function orderedRows(rows) {
|
|
|
1185
1358
|
return Array.from(rows).sort((a, b) => compareRows(a, b));
|
|
1186
1359
|
}
|
|
1187
1360
|
var SharedCollectionSocket = class {
|
|
1361
|
+
url;
|
|
1362
|
+
token;
|
|
1363
|
+
ws = null;
|
|
1364
|
+
connecting = false;
|
|
1365
|
+
closedByManager = false;
|
|
1366
|
+
consecutiveErrors = 0;
|
|
1367
|
+
reconnectTimer = null;
|
|
1368
|
+
flushQueued = false;
|
|
1369
|
+
subs = /* @__PURE__ */ new Map();
|
|
1370
|
+
pendingSubIds = /* @__PURE__ */ new Set();
|
|
1188
1371
|
constructor(url, token) {
|
|
1189
1372
|
this.url = url;
|
|
1190
1373
|
this.token = token;
|
|
1191
|
-
this.ws = null;
|
|
1192
|
-
this.connecting = false;
|
|
1193
|
-
this.closedByManager = false;
|
|
1194
|
-
this.consecutiveErrors = 0;
|
|
1195
|
-
this.reconnectTimer = null;
|
|
1196
|
-
this.flushQueued = false;
|
|
1197
|
-
this.subs = /* @__PURE__ */ new Map();
|
|
1198
|
-
this.pendingSubIds = /* @__PURE__ */ new Set();
|
|
1199
1374
|
}
|
|
1200
1375
|
add(sub) {
|
|
1201
1376
|
this.subs.set(sub.subId, sub);
|
|
@@ -1421,24 +1596,29 @@ function makeInitialQuerySnapshot() {
|
|
|
1421
1596
|
};
|
|
1422
1597
|
}
|
|
1423
1598
|
var CollectionQueryStore = class {
|
|
1599
|
+
key;
|
|
1600
|
+
url;
|
|
1601
|
+
collection;
|
|
1602
|
+
where;
|
|
1603
|
+
onIdle;
|
|
1604
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1605
|
+
rowSubscribers = /* @__PURE__ */ new Set();
|
|
1606
|
+
socketHandle = null;
|
|
1607
|
+
fallbackHandle = null;
|
|
1608
|
+
authUnsub = null;
|
|
1609
|
+
authToken = getAuthContext().token;
|
|
1610
|
+
authReady = getAuthContext().authReady;
|
|
1611
|
+
lastSeq = null;
|
|
1612
|
+
pendingAuthRequired = null;
|
|
1613
|
+
notifyQueued = false;
|
|
1614
|
+
rowsDirty = false;
|
|
1615
|
+
snapshot = makeInitialQuerySnapshot();
|
|
1424
1616
|
constructor(key, url, collection, where, onIdle) {
|
|
1425
1617
|
this.key = key;
|
|
1426
1618
|
this.url = url;
|
|
1427
1619
|
this.collection = collection;
|
|
1428
1620
|
this.where = where;
|
|
1429
1621
|
this.onIdle = onIdle;
|
|
1430
|
-
this.listeners = /* @__PURE__ */ new Set();
|
|
1431
|
-
this.rowSubscribers = /* @__PURE__ */ new Set();
|
|
1432
|
-
this.socketHandle = null;
|
|
1433
|
-
this.fallbackHandle = null;
|
|
1434
|
-
this.authUnsub = null;
|
|
1435
|
-
this.authToken = getAuthContext().token;
|
|
1436
|
-
this.authReady = getAuthContext().authReady;
|
|
1437
|
-
this.lastSeq = null;
|
|
1438
|
-
this.pendingAuthRequired = null;
|
|
1439
|
-
this.notifyQueued = false;
|
|
1440
|
-
this.rowsDirty = false;
|
|
1441
|
-
this.snapshot = makeInitialQuerySnapshot();
|
|
1442
1622
|
}
|
|
1443
1623
|
subscribe(listener) {
|
|
1444
1624
|
this.listeners.add(listener);
|
|
@@ -1637,4 +1817,4 @@ function _canonicalPredicateForTests(predicate) {
|
|
|
1637
1817
|
return canonicalPredicateString(predicate);
|
|
1638
1818
|
}
|
|
1639
1819
|
//#endregion
|
|
1640
|
-
export { OmgBadge, VibesAuthAutoPrompt, VibesAuthGuard, VibesAuthProvider, VibesAuthRequiredError,
|
|
1820
|
+
export { OmgBadge, VibesAuthAutoPrompt, VibesAuthGuard, VibesAuthProvider, VibesAuthRequiredError, VibesLogin, VibesUpload, _canonicalPredicateForTests, _resetSharedCollectionSocketsForTests, createNotification, createSandbox, createVibesAuth, deriveAppId, deriveTokenUrl, forkSandbox, getAuthContext, mailAppForEmail, notificationSupport, notifyAuthRequired, runtimeClaims, subscribeAuthRequired, subscribeCollection, useAuth, useCollection, useNotificationPermission, useNotifications, useQuery, useUpload, useUser, useVibesAuth, useVibesToken, vibesFetch };
|
package/package.json
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omg-dev/sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./src/index.ts",
|
|
8
8
|
"default": "./dist/index.mjs"
|
|
9
9
|
},
|
|
10
|
-
"./feedback/auto": {
|
|
11
|
-
"types": "./src/feedback/auto.tsx",
|
|
12
|
-
"default": "./dist/feedback/auto.mjs"
|
|
13
|
-
},
|
|
14
10
|
"./brand/auto": {
|
|
15
11
|
"types": "./src/brand/auto.tsx",
|
|
16
12
|
"default": "./dist/brand/auto.mjs"
|
|
@@ -19,8 +15,7 @@
|
|
|
19
15
|
"dependencies": {
|
|
20
16
|
"better-auth": "^1.2.0",
|
|
21
17
|
"@better-auth/passkey": "^1.2.0",
|
|
22
|
-
"@microsoft/fetch-event-source": "^2.0.1"
|
|
23
|
-
"modern-screenshot": "^4.0.0"
|
|
18
|
+
"@microsoft/fetch-event-source": "^2.0.1"
|
|
24
19
|
},
|
|
25
20
|
"peerDependencies": {
|
|
26
21
|
"react": ">=18",
|
package/src/brand/OmgBadge.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useId, useState, type CSSProperties } from "react"
|
|
2
|
-
import { VibesFeedback } from "../feedback/VibesFeedback"
|
|
3
2
|
|
|
4
3
|
export interface OmgBadgeProps {
|
|
5
4
|
/** Link used by the dialog CTA. Default: https://omg.dev */
|
|
@@ -13,24 +12,6 @@ const BRAND = "#FF5530"
|
|
|
13
12
|
const Z_BADGE = 2147482000
|
|
14
13
|
const Z_DIALOG = 2147483100
|
|
15
14
|
|
|
16
|
-
// Cross-process signal the brand badge dispatches to summon the (button-less)
|
|
17
|
-
// feedback sheet it mounts. Bundling feedback INTO this badge is deliberate:
|
|
18
|
-
// one floating control in the corner, not three.
|
|
19
|
-
export const FEEDBACK_OPEN_EVENT = "vibes:feedback:open"
|
|
20
|
-
|
|
21
|
-
// Build-time gate (set by @omg-dev/vite-plugin via `define`). True when the app
|
|
22
|
-
// has feedback enabled AND the brand badge owns it. Falls back to true when the
|
|
23
|
-
// badge is used outside the plugin (it's only auto-injected by the plugin, so
|
|
24
|
-
// in practice the define is always present in published bundles).
|
|
25
|
-
declare const __VIBES_BRAND_FEEDBACK__: boolean | undefined
|
|
26
|
-
function feedbackBundled(): boolean {
|
|
27
|
-
try {
|
|
28
|
-
return typeof __VIBES_BRAND_FEEDBACK__ === "undefined" ? true : __VIBES_BRAND_FEEDBACK__
|
|
29
|
-
} catch {
|
|
30
|
-
return true
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
15
|
export function OmgBadge({
|
|
35
16
|
href = "https://omg.dev",
|
|
36
17
|
label = "What is omg?",
|
|
@@ -40,19 +21,11 @@ export function OmgBadge({
|
|
|
40
21
|
const descriptionId = useId()
|
|
41
22
|
const markId = useId().replace(/[^a-zA-Z0-9_-]/g, "")
|
|
42
23
|
|
|
43
|
-
function summonFeedback() {
|
|
44
|
-
setOpen(false)
|
|
45
|
-
if (typeof window !== "undefined") {
|
|
46
|
-
window.dispatchEvent(new CustomEvent(FEEDBACK_OPEN_EVENT))
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
24
|
return (
|
|
51
25
|
<>
|
|
52
26
|
<button
|
|
53
27
|
type="button"
|
|
54
28
|
aria-label={label}
|
|
55
|
-
data-vibes-feedback=""
|
|
56
29
|
onClick={() => setOpen(true)}
|
|
57
30
|
style={badgeStyle}
|
|
58
31
|
>
|
|
@@ -62,7 +35,6 @@ export function OmgBadge({
|
|
|
62
35
|
|
|
63
36
|
{open && (
|
|
64
37
|
<div
|
|
65
|
-
data-vibes-feedback=""
|
|
66
38
|
role="presentation"
|
|
67
39
|
style={backdropStyle}
|
|
68
40
|
onMouseDown={(event) => {
|
|
@@ -100,20 +72,9 @@ export function OmgBadge({
|
|
|
100
72
|
<a href={href} target="_blank" rel="noopener noreferrer" style={ctaStyle}>
|
|
101
73
|
Learn about omg
|
|
102
74
|
</a>
|
|
103
|
-
{feedbackBundled() && (
|
|
104
|
-
<button type="button" onClick={summonFeedback} style={secondaryStyle}>
|
|
105
|
-
Send feedback
|
|
106
|
-
</button>
|
|
107
|
-
)}
|
|
108
75
|
</div>
|
|
109
76
|
</div>
|
|
110
77
|
)}
|
|
111
|
-
|
|
112
|
-
{/* Feedback is bundled into the badge — a button-less sheet summoned from
|
|
113
|
-
the dialog (or by gesture), so there's no second floating control. */}
|
|
114
|
-
{feedbackBundled() && (
|
|
115
|
-
<VibesFeedback showButton={false} accent={BRAND} title="Send feedback" />
|
|
116
|
-
)}
|
|
117
78
|
</>
|
|
118
79
|
)
|
|
119
80
|
}
|
|
@@ -256,21 +217,3 @@ const ctaStyle: CSSProperties = {
|
|
|
256
217
|
textDecoration: "none",
|
|
257
218
|
letterSpacing: 0,
|
|
258
219
|
}
|
|
259
|
-
|
|
260
|
-
const secondaryStyle: CSSProperties = {
|
|
261
|
-
display: "inline-flex",
|
|
262
|
-
alignItems: "center",
|
|
263
|
-
justifyContent: "center",
|
|
264
|
-
width: "100%",
|
|
265
|
-
height: 44,
|
|
266
|
-
marginTop: 8,
|
|
267
|
-
borderRadius: 12,
|
|
268
|
-
background: "transparent",
|
|
269
|
-
border: "1px solid rgba(21, 17, 13, 0.14)",
|
|
270
|
-
color: "#15110d",
|
|
271
|
-
fontSize: 15,
|
|
272
|
-
fontWeight: 650,
|
|
273
|
-
cursor: "pointer",
|
|
274
|
-
fontFamily: font,
|
|
275
|
-
letterSpacing: 0,
|
|
276
|
-
}
|
package/src/brand/auto.tsx
CHANGED
|
@@ -4,10 +4,6 @@
|
|
|
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
|
-
// The badge also bundles the button-less feedback sheet summoned from its
|
|
8
|
-
// dialog, so the vite plugin skips the standalone feedback control whenever
|
|
9
|
-
// this badge is enabled (the default).
|
|
10
|
-
|
|
11
7
|
import { createRoot } from "react-dom/client"
|
|
12
8
|
import { OmgBadge } from "./OmgBadge"
|
|
13
9
|
|
|
@@ -18,8 +14,6 @@ function mount() {
|
|
|
18
14
|
if (document.getElementById(HOST_ID)) return
|
|
19
15
|
const host = document.createElement("div")
|
|
20
16
|
host.id = HOST_ID
|
|
21
|
-
// Feedback screenshots should capture the app, not platform chrome.
|
|
22
|
-
host.setAttribute("data-vibes-feedback", "")
|
|
23
17
|
document.body.appendChild(host)
|
|
24
18
|
createRoot(host).render(<OmgBadge />)
|
|
25
19
|
}
|
package/src/index.ts
CHANGED
|
@@ -14,9 +14,6 @@ export * from "./auth/index"
|
|
|
14
14
|
// Storage surface — useUpload() + <VibesUpload />. Re-exported here for
|
|
15
15
|
// the same publish-workflow reason as auth (only "." subpath survives).
|
|
16
16
|
export * from "./storage/index"
|
|
17
|
-
// Feedback surface — <VibesFeedback /> gesture widget + trace capture.
|
|
18
|
-
// Re-exported here for the same publish-workflow reason (only "." survives).
|
|
19
|
-
export * from "./feedback/index"
|
|
20
17
|
// Brand surface — <OmgBadge /> platform attribution badge.
|
|
21
18
|
export * from "./brand/index"
|
|
22
19
|
// Notifications surface — durable in-app inbox + Web Push registration.
|
package/src/sandbox.test.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { createSandbox, forkSandbox, runtimeClaims } from "./sandbox";
|
|
3
3
|
|
|
4
|
+
it("exports the funded transcription capability", () => {
|
|
5
|
+
expect(runtimeClaims.speechTranscribe).toBe("speech.transcribe");
|
|
6
|
+
});
|
|
7
|
+
|
|
4
8
|
describe("sandbox SDK", () => {
|
|
5
9
|
it("posts create requests to the sandbox router", async () => {
|
|
6
10
|
const calls: Array<{ url: string; body: unknown }> = [];
|