@foir/sdk 0.29.0 → 0.30.1
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/CHANGELOG.md +84 -0
- package/dist/ai/index.d.ts +186 -0
- package/dist/ai.js +588 -0
- package/dist/auth/auth.d.ts +15 -1
- package/dist/auth/code-flow.d.ts +1 -1
- package/dist/auth/grant-table.generated.d.ts +1 -1
- package/dist/auth/grants.d.ts +2 -1
- package/dist/auth/hosted.d.ts +3 -3
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/session-client.d.ts +1 -1
- package/dist/auth.js +13 -1
- package/dist/client/platform-client.d.ts +1 -1
- package/dist/data/agents.d.ts +104 -0
- package/dist/data/builtins.d.ts +182 -0
- package/dist/data/index.d.ts +5 -3
- package/dist/data/subjects.d.ts +45 -0
- package/dist/data/subscriptions.d.ts +38 -0
- package/dist/data.js +169 -2
- package/dist/placement.js +7 -1
- package/dist/react/FoirFeedback.d.ts +18 -1
- package/dist/react/SignIn.d.ts +2 -2
- package/dist/react/feedback-notes.d.ts +7 -0
- package/dist/react.js +261 -9
- package/dist/server/webhook-helpers.d.ts +3 -1
- package/dist/server.js +31 -4
- package/package.json +10 -1
package/dist/react.js
CHANGED
|
@@ -1242,6 +1242,12 @@ var GRANT_TABLE = [
|
|
|
1242
1242
|
["operations:write", "none", [], []],
|
|
1243
1243
|
["operations:complete", "none", [], []],
|
|
1244
1244
|
["status:write", "none", [], []],
|
|
1245
|
+
["agents:read", "none", [], []],
|
|
1246
|
+
["agents:execute", "agent", [], []],
|
|
1247
|
+
["agents:write", "none", [], []],
|
|
1248
|
+
["agenttools:execute", "agent_tool", [], []],
|
|
1249
|
+
["brief:read", "none", [], []],
|
|
1250
|
+
["brief:write", "none", [], []],
|
|
1245
1251
|
["appconfig:read", "none", [], []],
|
|
1246
1252
|
["schedules:read", "none", [], []],
|
|
1247
1253
|
["schedules:write", "none", [], []],
|
|
@@ -1291,7 +1297,7 @@ var GRANT_TABLE = [
|
|
|
1291
1297
|
["projects:read", "none", [], []],
|
|
1292
1298
|
["projects:write", "none", [], []],
|
|
1293
1299
|
["project:stand", "none", [], []],
|
|
1294
|
-
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "authclients:read", "authclients:write", "domains:read", "domains:write", "loginpages:read", "loginpages:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "orgsettings:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
1300
|
+
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "agents:read", "agents:execute", "agents:write", "agenttools:execute", "brief:read", "brief:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "authclients:read", "authclients:write", "domains:read", "domains:write", "loginpages:read", "loginpages:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "orgsettings:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
1295
1301
|
["projects:create", "none", [], []],
|
|
1296
1302
|
["projects:delete", "none", [], []],
|
|
1297
1303
|
["tenants:read", "none", [], []],
|
|
@@ -2263,7 +2269,7 @@ async function submitFeedbackNote(client, submission) {
|
|
|
2263
2269
|
await uploadFeedbackAttachment(client, submission.screenshot, submission.fetch)
|
|
2264
2270
|
);
|
|
2265
2271
|
}
|
|
2266
|
-
const args = noteArgs(submission.subject, submission.body);
|
|
2272
|
+
const args = noteArgs(submission.subject, submission.body, submission.anchorField);
|
|
2267
2273
|
if (attachmentFileIds.length > 0) args.attachmentFileIds = attachmentFileIds;
|
|
2268
2274
|
const { notes } = client.ns;
|
|
2269
2275
|
return readCreatedNote(
|
|
@@ -2277,7 +2283,11 @@ async function submitVisitorNote(client, submission) {
|
|
|
2277
2283
|
"[foir] this client has no `notes.writeNote`, which is the only create that takes a note from a visitor who is not signed in. Re-run `foir types`."
|
|
2278
2284
|
);
|
|
2279
2285
|
}
|
|
2280
|
-
const args = noteArgs(
|
|
2286
|
+
const args = noteArgs(
|
|
2287
|
+
submission.subject,
|
|
2288
|
+
submission.body,
|
|
2289
|
+
submission.anchorField
|
|
2290
|
+
);
|
|
2281
2291
|
const contactEmail = submission.contactEmail?.trim();
|
|
2282
2292
|
if (contactEmail) args.contactEmail = contactEmail;
|
|
2283
2293
|
args.pick = ["id", "createdAt"];
|
|
@@ -2292,13 +2302,15 @@ async function submitVisitorNote(client, submission) {
|
|
|
2292
2302
|
createdAt: typeof result.createdAt === "string" ? result.createdAt : ""
|
|
2293
2303
|
};
|
|
2294
2304
|
}
|
|
2295
|
-
function noteArgs(subject, body) {
|
|
2296
|
-
|
|
2305
|
+
function noteArgs(subject, body, anchorField) {
|
|
2306
|
+
const args = {
|
|
2297
2307
|
subjectType: "record",
|
|
2298
2308
|
subjectId: subject.recordId,
|
|
2299
2309
|
subjectModelKey: subject.modelKey,
|
|
2300
2310
|
body
|
|
2301
2311
|
};
|
|
2312
|
+
if (anchorField) args.anchorField = anchorField;
|
|
2313
|
+
return args;
|
|
2302
2314
|
}
|
|
2303
2315
|
async function uploadFeedbackAttachment(client, screenshot, fetchImpl = globalThis.fetch) {
|
|
2304
2316
|
const files = client.ns.files;
|
|
@@ -2422,7 +2434,11 @@ var COPY = {
|
|
|
2422
2434
|
captureFailed: "The screenshot could not be taken. You can still send your feedback.",
|
|
2423
2435
|
screenshotAlt: "The screenshot that will be sent with your feedback",
|
|
2424
2436
|
removeScreenshot: "Remove screenshot",
|
|
2425
|
-
about: "About"
|
|
2437
|
+
about: "About",
|
|
2438
|
+
point: "Point at what you mean",
|
|
2439
|
+
pointAgain: "Point at something else",
|
|
2440
|
+
pointHint: "Click the part of the page you mean, or use Tab and Enter. Escape cancels.",
|
|
2441
|
+
pointCancel: "Cancel"
|
|
2426
2442
|
};
|
|
2427
2443
|
var border = "1px solid var(--foir-feedback-border, currentColor)";
|
|
2428
2444
|
var radius = "var(--foir-feedback-radius, 8px)";
|
|
@@ -2529,6 +2545,8 @@ function FoirFeedback({
|
|
|
2529
2545
|
onSignIn,
|
|
2530
2546
|
signIn = true,
|
|
2531
2547
|
layout = "inline",
|
|
2548
|
+
launcher,
|
|
2549
|
+
pointing = false,
|
|
2532
2550
|
appearance,
|
|
2533
2551
|
onSubmitted,
|
|
2534
2552
|
onVisitorSubmitted,
|
|
@@ -2544,10 +2562,32 @@ function FoirFeedback({
|
|
|
2544
2562
|
const [busy, setBusy] = useState4(false);
|
|
2545
2563
|
const [failure, setFailure] = useState4(null);
|
|
2546
2564
|
const [sent, setSent] = useState4(false);
|
|
2565
|
+
const [pointed, setPointed] = useState4(null);
|
|
2566
|
+
const [pointingNow, setPointingNow] = useState4(false);
|
|
2567
|
+
const [canPoint, setCanPoint] = useState4(false);
|
|
2547
2568
|
const onErrorRef = useRef2(onError);
|
|
2548
2569
|
onErrorRef.current = onError;
|
|
2549
|
-
const
|
|
2570
|
+
const fetched = useResolvedSubject(subjects, subject);
|
|
2571
|
+
const offersPointing = pointing && subjects !== void 0 && subject !== null;
|
|
2572
|
+
const resolved = offersPointing && pointed ? pointed.subject : fetched;
|
|
2550
2573
|
const styled = !className;
|
|
2574
|
+
useEffect3(() => {
|
|
2575
|
+
if (!open || !offersPointing || !subjects) return;
|
|
2576
|
+
setCanPoint(markedFields(subjects).length > 0);
|
|
2577
|
+
}, [open, offersPointing, subjects]);
|
|
2578
|
+
const highlight = usePointing(pointingNow ? subjects : void 0, {
|
|
2579
|
+
onPick: (mark) => {
|
|
2580
|
+
setPointed(mark);
|
|
2581
|
+
setPointingNow(false);
|
|
2582
|
+
setSent(false);
|
|
2583
|
+
setFailure(null);
|
|
2584
|
+
setOpen(true);
|
|
2585
|
+
},
|
|
2586
|
+
onCancel: () => {
|
|
2587
|
+
setPointingNow(false);
|
|
2588
|
+
setOpen(true);
|
|
2589
|
+
}
|
|
2590
|
+
});
|
|
2551
2591
|
useNoSubjectNotice(open, resolved, subjects !== void 0, subject !== void 0);
|
|
2552
2592
|
useEffect3(() => {
|
|
2553
2593
|
if (!open) return;
|
|
@@ -2613,6 +2653,7 @@ function FoirFeedback({
|
|
|
2613
2653
|
const note = await submitFeedbackNote(client, {
|
|
2614
2654
|
subject: resolved,
|
|
2615
2655
|
body: prose,
|
|
2656
|
+
anchorField: pointed?.field,
|
|
2616
2657
|
screenshot
|
|
2617
2658
|
});
|
|
2618
2659
|
setBody("");
|
|
@@ -2623,6 +2664,7 @@ function FoirFeedback({
|
|
|
2623
2664
|
const written = await submitVisitorNote(client, {
|
|
2624
2665
|
subject: resolved,
|
|
2625
2666
|
body: prose,
|
|
2667
|
+
anchorField: pointed?.field,
|
|
2626
2668
|
contactEmail
|
|
2627
2669
|
});
|
|
2628
2670
|
setBody("");
|
|
@@ -2654,9 +2696,11 @@ function FoirFeedback({
|
|
|
2654
2696
|
}
|
|
2655
2697
|
setSent(false);
|
|
2656
2698
|
setFailure(null);
|
|
2699
|
+
setPointed(null);
|
|
2657
2700
|
setOpen(true);
|
|
2658
2701
|
};
|
|
2659
|
-
const
|
|
2702
|
+
const recordName = resolved ? pointed ? resolved.label : label ?? resolved.label : void 0;
|
|
2703
|
+
const subjectName = [recordName, pointed?.label].filter(Boolean).join(" \xB7 ") || void 0;
|
|
2660
2704
|
const dialog = layout === "dialog";
|
|
2661
2705
|
const heading = /* @__PURE__ */ jsx5("h2", { "data-foir-feedback-title": true, style: styled ? headingStyle : void 0, children: title });
|
|
2662
2706
|
const panel = open && /* @__PURE__ */ jsxs4(
|
|
@@ -2684,6 +2728,19 @@ function FoirFeedback({
|
|
|
2684
2728
|
": ",
|
|
2685
2729
|
subjectName
|
|
2686
2730
|
] }),
|
|
2731
|
+
offersPointing && canPoint && probe.status === "ready" && /* @__PURE__ */ jsx5(
|
|
2732
|
+
"button",
|
|
2733
|
+
{
|
|
2734
|
+
type: "button",
|
|
2735
|
+
"data-foir-feedback-point": true,
|
|
2736
|
+
onClick: () => {
|
|
2737
|
+
setOpen(false);
|
|
2738
|
+
setPointingNow(true);
|
|
2739
|
+
},
|
|
2740
|
+
style: styled ? buttonStyle : void 0,
|
|
2741
|
+
children: pointed ? COPY.pointAgain : COPY.point
|
|
2742
|
+
}
|
|
2743
|
+
),
|
|
2687
2744
|
probe.status === "loading" && /* @__PURE__ */ jsx5(
|
|
2688
2745
|
"p",
|
|
2689
2746
|
{
|
|
@@ -2798,12 +2855,19 @@ function FoirFeedback({
|
|
|
2798
2855
|
]
|
|
2799
2856
|
}
|
|
2800
2857
|
);
|
|
2858
|
+
const launcherPlace = launcher ? {
|
|
2859
|
+
position: "fixed",
|
|
2860
|
+
bottom: 16,
|
|
2861
|
+
[launcher === "bottom-left" ? "left" : "right"]: 16,
|
|
2862
|
+
zIndex: LAUNCHER_LAYER
|
|
2863
|
+
} : void 0;
|
|
2801
2864
|
return /* @__PURE__ */ jsxs4(
|
|
2802
2865
|
"div",
|
|
2803
2866
|
{
|
|
2804
2867
|
className,
|
|
2805
2868
|
"data-foir-feedback": true,
|
|
2806
2869
|
"data-foir-feedback-layout": layout,
|
|
2870
|
+
"data-foir-feedback-launcher": launcher,
|
|
2807
2871
|
style: styled ? wrapperStyle(appearance) : void 0,
|
|
2808
2872
|
children: [
|
|
2809
2873
|
/* @__PURE__ */ jsx5(
|
|
@@ -2814,10 +2878,25 @@ function FoirFeedback({
|
|
|
2814
2878
|
"aria-expanded": open,
|
|
2815
2879
|
"aria-haspopup": dialog ? "dialog" : void 0,
|
|
2816
2880
|
onClick: toggle,
|
|
2817
|
-
style:
|
|
2881
|
+
style: {
|
|
2882
|
+
...styled ? buttonStyle : void 0,
|
|
2883
|
+
...styled && launcher ? launcherStyle : void 0,
|
|
2884
|
+
...launcherPlace
|
|
2885
|
+
},
|
|
2818
2886
|
children: triggerLabel
|
|
2819
2887
|
}
|
|
2820
2888
|
),
|
|
2889
|
+
pointingNow && /* @__PURE__ */ jsx5(
|
|
2890
|
+
PointingChrome,
|
|
2891
|
+
{
|
|
2892
|
+
highlight,
|
|
2893
|
+
styled,
|
|
2894
|
+
onCancel: () => {
|
|
2895
|
+
setPointingNow(false);
|
|
2896
|
+
setOpen(true);
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
),
|
|
2821
2900
|
dialog ? /* @__PURE__ */ jsx5(
|
|
2822
2901
|
"dialog",
|
|
2823
2902
|
{
|
|
@@ -2831,11 +2910,184 @@ function FoirFeedback({
|
|
|
2831
2910
|
style: styled ? dialogStyle : void 0,
|
|
2832
2911
|
children: panel
|
|
2833
2912
|
}
|
|
2913
|
+
) : launcher && panel ? /* @__PURE__ */ jsx5(
|
|
2914
|
+
"div",
|
|
2915
|
+
{
|
|
2916
|
+
"data-foir-feedback-launcher-panel": true,
|
|
2917
|
+
style: {
|
|
2918
|
+
position: "fixed",
|
|
2919
|
+
bottom: 64,
|
|
2920
|
+
[launcher === "bottom-left" ? "left" : "right"]: 16,
|
|
2921
|
+
zIndex: LAUNCHER_LAYER,
|
|
2922
|
+
...styled ? { background: "var(--foir-feedback-background, Canvas)" } : void 0
|
|
2923
|
+
},
|
|
2924
|
+
children: panel
|
|
2925
|
+
}
|
|
2834
2926
|
) : panel
|
|
2835
2927
|
]
|
|
2836
2928
|
}
|
|
2837
2929
|
);
|
|
2838
2930
|
}
|
|
2931
|
+
var LAUNCHER_LAYER = 2147483e3;
|
|
2932
|
+
var POINTING_LAYER = 2147483600;
|
|
2933
|
+
var launcherStyle = {
|
|
2934
|
+
background: "var(--foir-feedback-primary, Canvas)",
|
|
2935
|
+
color: "var(--foir-feedback-primary-text, CanvasText)",
|
|
2936
|
+
boxShadow: "0 4px 16px rgb(0 0 0 / 0.18)",
|
|
2937
|
+
padding: "10px 14px",
|
|
2938
|
+
fontWeight: 600
|
|
2939
|
+
};
|
|
2940
|
+
function markedFields(subjects) {
|
|
2941
|
+
if (typeof document === "undefined") return [];
|
|
2942
|
+
return Array.from(document.querySelectorAll("[data-foir-field]")).filter(
|
|
2943
|
+
(el) => subjects.pointedAt(el.getAttribute("data-foir-field") ?? "") !== void 0 && el.getClientRects().length > 0
|
|
2944
|
+
);
|
|
2945
|
+
}
|
|
2946
|
+
function markedFieldAt(target, subjects) {
|
|
2947
|
+
if (!(target instanceof Element)) return null;
|
|
2948
|
+
const el = target.closest("[data-foir-field]");
|
|
2949
|
+
if (!el) return null;
|
|
2950
|
+
const mark = subjects.pointedAt(el.getAttribute("data-foir-field") ?? "");
|
|
2951
|
+
return mark ? { el, mark } : null;
|
|
2952
|
+
}
|
|
2953
|
+
function usePointing(subjects, handlers) {
|
|
2954
|
+
const [highlight, setHighlight] = useState4(null);
|
|
2955
|
+
const handlersRef = useRef2(handlers);
|
|
2956
|
+
handlersRef.current = handlers;
|
|
2957
|
+
useEffect3(() => {
|
|
2958
|
+
if (!subjects) return;
|
|
2959
|
+
let current = null;
|
|
2960
|
+
let index2 = -1;
|
|
2961
|
+
const show = (el) => {
|
|
2962
|
+
current = el;
|
|
2963
|
+
if (!el) {
|
|
2964
|
+
setHighlight(null);
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
const box = el.getBoundingClientRect();
|
|
2968
|
+
setHighlight({ top: box.top, left: box.left, width: box.width, height: box.height });
|
|
2969
|
+
};
|
|
2970
|
+
const ours = (target) => target instanceof Element && target.closest("[data-foir-feedback-pointing]") !== null;
|
|
2971
|
+
const onMove = (event) => {
|
|
2972
|
+
if (ours(event.target)) return;
|
|
2973
|
+
show(markedFieldAt(event.target, subjects)?.el ?? null);
|
|
2974
|
+
};
|
|
2975
|
+
const onClick = (event) => {
|
|
2976
|
+
if (ours(event.target)) return;
|
|
2977
|
+
event.preventDefault();
|
|
2978
|
+
event.stopPropagation();
|
|
2979
|
+
const hit = markedFieldAt(event.target, subjects);
|
|
2980
|
+
if (hit) handlersRef.current.onPick(hit.mark);
|
|
2981
|
+
};
|
|
2982
|
+
const onKey = (event) => {
|
|
2983
|
+
if (event.key === "Escape") {
|
|
2984
|
+
event.preventDefault();
|
|
2985
|
+
handlersRef.current.onCancel();
|
|
2986
|
+
return;
|
|
2987
|
+
}
|
|
2988
|
+
if (event.key === "Tab") {
|
|
2989
|
+
const fields = markedFields(subjects);
|
|
2990
|
+
if (fields.length === 0) return;
|
|
2991
|
+
event.preventDefault();
|
|
2992
|
+
index2 = (index2 + (event.shiftKey ? -1 : 1) + fields.length) % fields.length;
|
|
2993
|
+
const el = fields[index2];
|
|
2994
|
+
el.scrollIntoView?.({ block: "nearest" });
|
|
2995
|
+
show(el);
|
|
2996
|
+
return;
|
|
2997
|
+
}
|
|
2998
|
+
if (event.key === "Enter" && current) {
|
|
2999
|
+
const mark = subjects.pointedAt(current.getAttribute("data-foir-field") ?? "");
|
|
3000
|
+
if (!mark) return;
|
|
3001
|
+
event.preventDefault();
|
|
3002
|
+
handlersRef.current.onPick(mark);
|
|
3003
|
+
}
|
|
3004
|
+
};
|
|
3005
|
+
const onScroll = () => show(current);
|
|
3006
|
+
const root = document.documentElement;
|
|
3007
|
+
const cursor = root.style.cursor;
|
|
3008
|
+
root.style.cursor = "crosshair";
|
|
3009
|
+
document.addEventListener("pointermove", onMove, true);
|
|
3010
|
+
document.addEventListener("click", onClick, true);
|
|
3011
|
+
document.addEventListener("keydown", onKey, true);
|
|
3012
|
+
window.addEventListener("scroll", onScroll, true);
|
|
3013
|
+
return () => {
|
|
3014
|
+
root.style.cursor = cursor;
|
|
3015
|
+
document.removeEventListener("pointermove", onMove, true);
|
|
3016
|
+
document.removeEventListener("click", onClick, true);
|
|
3017
|
+
document.removeEventListener("keydown", onKey, true);
|
|
3018
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
3019
|
+
setHighlight(null);
|
|
3020
|
+
};
|
|
3021
|
+
}, [subjects]);
|
|
3022
|
+
return highlight;
|
|
3023
|
+
}
|
|
3024
|
+
function PointingChrome({
|
|
3025
|
+
highlight,
|
|
3026
|
+
styled,
|
|
3027
|
+
onCancel
|
|
3028
|
+
}) {
|
|
3029
|
+
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3030
|
+
highlight && /* @__PURE__ */ jsx5(
|
|
3031
|
+
"div",
|
|
3032
|
+
{
|
|
3033
|
+
"aria-hidden": "true",
|
|
3034
|
+
"data-foir-feedback-highlight": true,
|
|
3035
|
+
style: {
|
|
3036
|
+
position: "fixed",
|
|
3037
|
+
top: highlight.top - 4,
|
|
3038
|
+
left: highlight.left - 4,
|
|
3039
|
+
width: highlight.width + 8,
|
|
3040
|
+
height: highlight.height + 8,
|
|
3041
|
+
pointerEvents: "none",
|
|
3042
|
+
zIndex: POINTING_LAYER,
|
|
3043
|
+
...styled ? {
|
|
3044
|
+
outline: "2px solid var(--foir-feedback-primary, Highlight)",
|
|
3045
|
+
borderRadius: "var(--foir-feedback-radius, 8px)"
|
|
3046
|
+
} : void 0
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
),
|
|
3050
|
+
/* @__PURE__ */ jsxs4(
|
|
3051
|
+
"div",
|
|
3052
|
+
{
|
|
3053
|
+
role: "status",
|
|
3054
|
+
"data-foir-feedback-pointing": true,
|
|
3055
|
+
style: {
|
|
3056
|
+
position: "fixed",
|
|
3057
|
+
bottom: 16,
|
|
3058
|
+
left: "50%",
|
|
3059
|
+
transform: "translateX(-50%)",
|
|
3060
|
+
zIndex: POINTING_LAYER,
|
|
3061
|
+
cursor: "auto",
|
|
3062
|
+
...styled ? {
|
|
3063
|
+
display: "flex",
|
|
3064
|
+
alignItems: "center",
|
|
3065
|
+
gap: 12,
|
|
3066
|
+
padding: "10px 14px",
|
|
3067
|
+
borderRadius: radius,
|
|
3068
|
+
border,
|
|
3069
|
+
background: "var(--foir-feedback-background, Canvas)",
|
|
3070
|
+
color: "var(--foir-feedback-text, CanvasText)",
|
|
3071
|
+
boxShadow: "0 4px 16px rgb(0 0 0 / 0.18)"
|
|
3072
|
+
} : void 0
|
|
3073
|
+
},
|
|
3074
|
+
children: [
|
|
3075
|
+
/* @__PURE__ */ jsx5("span", { children: COPY.pointHint }),
|
|
3076
|
+
/* @__PURE__ */ jsx5(
|
|
3077
|
+
"button",
|
|
3078
|
+
{
|
|
3079
|
+
type: "button",
|
|
3080
|
+
"data-foir-feedback-point-cancel": true,
|
|
3081
|
+
onClick: onCancel,
|
|
3082
|
+
style: styled ? closeStyle : void 0,
|
|
3083
|
+
children: COPY.pointCancel
|
|
3084
|
+
}
|
|
3085
|
+
)
|
|
3086
|
+
]
|
|
3087
|
+
}
|
|
3088
|
+
)
|
|
3089
|
+
] });
|
|
3090
|
+
}
|
|
2839
3091
|
async function probeRefusal(client) {
|
|
2840
3092
|
try {
|
|
2841
3093
|
await readNoteConfig(client);
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
*
|
|
16
16
|
* The platform signs webhook payloads with HMAC-SHA256 using the
|
|
17
17
|
* extension's webhook secret. The signature is sent in the
|
|
18
|
-
* `x-foir-signature` header as a hex-encoded string.
|
|
18
|
+
* `x-foir-signature` header as a hex-encoded string. A base64 signature of
|
|
19
|
+
* the same HMAC is accepted too, so a header that carries one (Shopify's
|
|
20
|
+
* `X-Shopify-Hmac-Sha256`, for one) verifies as it arrives.
|
|
19
21
|
*
|
|
20
22
|
* @example
|
|
21
23
|
* ```ts
|
package/dist/server.js
CHANGED
|
@@ -63,14 +63,35 @@ async function verifyWebhookSignature(payload, signature, secret) {
|
|
|
63
63
|
key,
|
|
64
64
|
encoder.encode(payload)
|
|
65
65
|
);
|
|
66
|
-
const computed =
|
|
67
|
-
|
|
66
|
+
const computed = new Uint8Array(signatureBytes);
|
|
67
|
+
const presented = signatureBytesOf(signature.trim());
|
|
68
|
+
if (!presented || presented.length !== computed.length) return false;
|
|
68
69
|
let mismatch = 0;
|
|
69
70
|
for (let i = 0; i < computed.length; i++) {
|
|
70
|
-
mismatch |= computed
|
|
71
|
+
mismatch |= computed[i] ^ presented[i];
|
|
71
72
|
}
|
|
72
73
|
return mismatch === 0;
|
|
73
74
|
}
|
|
75
|
+
function signatureBytesOf(signature) {
|
|
76
|
+
if (/^[0-9a-fA-F]+$/.test(signature) && signature.length % 2 === 0) {
|
|
77
|
+
const out = new Uint8Array(signature.length / 2);
|
|
78
|
+
for (let i = 0; i < out.length; i++) {
|
|
79
|
+
out[i] = parseInt(signature.slice(i * 2, i * 2 + 2), 16);
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
if (!/^[A-Za-z0-9+/_-]+={0,2}$/.test(signature)) return null;
|
|
84
|
+
const standard = signature.replace(/-/g, "+").replace(/_/g, "/");
|
|
85
|
+
const padded = standard + "=".repeat((4 - standard.length % 4) % 4);
|
|
86
|
+
try {
|
|
87
|
+
const binary = atob(padded);
|
|
88
|
+
const out = new Uint8Array(binary.length);
|
|
89
|
+
for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
|
|
90
|
+
return out;
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
74
95
|
|
|
75
96
|
// src/auth/grant-table.generated.ts
|
|
76
97
|
var GRANT_TABLE = [
|
|
@@ -106,6 +127,12 @@ var GRANT_TABLE = [
|
|
|
106
127
|
["operations:write", "none", [], []],
|
|
107
128
|
["operations:complete", "none", [], []],
|
|
108
129
|
["status:write", "none", [], []],
|
|
130
|
+
["agents:read", "none", [], []],
|
|
131
|
+
["agents:execute", "agent", [], []],
|
|
132
|
+
["agents:write", "none", [], []],
|
|
133
|
+
["agenttools:execute", "agent_tool", [], []],
|
|
134
|
+
["brief:read", "none", [], []],
|
|
135
|
+
["brief:write", "none", [], []],
|
|
109
136
|
["appconfig:read", "none", [], []],
|
|
110
137
|
["schedules:read", "none", [], []],
|
|
111
138
|
["schedules:write", "none", [], []],
|
|
@@ -155,7 +182,7 @@ var GRANT_TABLE = [
|
|
|
155
182
|
["projects:read", "none", [], []],
|
|
156
183
|
["projects:write", "none", [], []],
|
|
157
184
|
["project:stand", "none", [], []],
|
|
158
|
-
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "authclients:read", "authclients:write", "domains:read", "domains:write", "loginpages:read", "loginpages:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "orgsettings:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
185
|
+
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "agents:read", "agents:execute", "agents:write", "agenttools:execute", "brief:read", "brief:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "authclients:read", "authclients:write", "domains:read", "domains:write", "loginpages:read", "loginpages:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "orgsettings:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
159
186
|
["projects:create", "none", [], []],
|
|
160
187
|
["projects:delete", "none", [], []],
|
|
161
188
|
["tenants:read", "none", [], []],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foir/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.1",
|
|
4
4
|
"description": "Official Foir SDK — editor iframe client + server-side platform helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"types": "./dist/data/index.d.ts",
|
|
26
26
|
"import": "./dist/data.js"
|
|
27
27
|
},
|
|
28
|
+
"./ai": {
|
|
29
|
+
"types": "./dist/ai/index.d.ts",
|
|
30
|
+
"import": "./dist/ai.js"
|
|
31
|
+
},
|
|
28
32
|
"./live": {
|
|
29
33
|
"types": "./dist/live/index.d.ts",
|
|
30
34
|
"import": "./dist/live.js"
|
|
@@ -122,6 +126,7 @@
|
|
|
122
126
|
"@bufbuild/protobuf": "^2.12.0",
|
|
123
127
|
"@graphql-codegen/cli": "^5.0.0",
|
|
124
128
|
"@graphql-codegen/client-preset": "^4.0.0",
|
|
129
|
+
"ai": "^7.0.0",
|
|
125
130
|
"blurhash": "^2.0.0",
|
|
126
131
|
"graphql": "^16.0.0",
|
|
127
132
|
"hls.js": "^1.5.0",
|
|
@@ -139,6 +144,9 @@
|
|
|
139
144
|
"@graphql-codegen/client-preset": {
|
|
140
145
|
"optional": true
|
|
141
146
|
},
|
|
147
|
+
"ai": {
|
|
148
|
+
"optional": true
|
|
149
|
+
},
|
|
142
150
|
"blurhash": {
|
|
143
151
|
"optional": true
|
|
144
152
|
},
|
|
@@ -165,6 +173,7 @@
|
|
|
165
173
|
"@types/react": "^19.2.0",
|
|
166
174
|
"@types/react-dom": "^19.2.0",
|
|
167
175
|
"@types/ws": "^8.5.13",
|
|
176
|
+
"ai": "^7.0.29",
|
|
168
177
|
"blurhash": "^2.0.5",
|
|
169
178
|
"graphql": "^16.10.0",
|
|
170
179
|
"hls.js": "^1.6.16",
|