@fusedio/widget-sdk 0.1.0 → 0.2.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/dist/bridge.js +14 -9
- package/dist/bundle.js +2 -2
- package/dist/define-catalog.d.ts +5 -3
- package/dist/define-catalog.js +4 -1
- package/dist/define-component.js +4 -1
- package/dist/form.js +18 -12
- package/dist/hooks/sql-source-overrides.d.ts +16 -0
- package/dist/hooks/sql-source-overrides.js +29 -0
- package/dist/hooks/use-allowed-sources.js +12 -9
- package/dist/hooks/use-allowed-udf-names.js +11 -8
- package/dist/hooks/use-canvas-params.js +12 -9
- package/dist/hooks/use-duckdb-sql.d.ts +1 -1
- package/dist/hooks/use-duckdb-sql.js +78 -58
- package/dist/hooks/use-fused-param-with-form.d.ts +18 -0
- package/dist/hooks/use-fused-param-with-form.js +56 -0
- package/dist/hooks/use-fused-param.js +34 -31
- package/dist/hooks/use-json-ui-edge-animation.js +6 -3
- package/dist/hooks/use-json-ui-log.js +23 -18
- package/dist/hooks/use-json-ui-udf-info.js +6 -3
- package/dist/hooks/use-param-substitution.js +25 -22
- package/dist/hooks/use-udf-output.js +33 -24
- package/dist/hooks/use-upload-access-check.js +9 -6
- package/dist/hooks/use-url-signing.js +22 -17
- package/dist/index.d.ts +3 -0
- package/dist/index.js +69 -19
- package/dist/protocol.js +8 -4
- package/dist/types.js +2 -1
- package/dist/utils/parse-style.d.ts +9 -0
- package/dist/utils/parse-style.js +27 -0
- package/dist/utils/sql-placeholders.js +36 -22
- package/package.json +2 -3
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useJsonUiUdfInfo = useJsonUiUdfInfo;
|
|
4
|
+
const bridge_1 = require("../bridge");
|
|
2
5
|
/**
|
|
3
6
|
* Returns the identity of the current canvas node.
|
|
4
7
|
*
|
|
@@ -18,6 +21,6 @@ import { useJsonUiNode } from "../bridge";
|
|
|
18
21
|
* const { udfName } = useJsonUiUdfInfo();
|
|
19
22
|
* console.log("I am node:", udfName);
|
|
20
23
|
*/
|
|
21
|
-
|
|
22
|
-
return useJsonUiNode();
|
|
24
|
+
function useJsonUiUdfInfo() {
|
|
25
|
+
return (0, bridge_1.useJsonUiNode)();
|
|
23
26
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useParamSubstitution = useParamSubstitution;
|
|
1
4
|
/**
|
|
2
5
|
* Reactively resolve `$param` and `{{udf}}` placeholders in a template.
|
|
3
6
|
*
|
|
@@ -7,10 +10,10 @@
|
|
|
7
10
|
* delegate to `bridge.template.render` so the host can use its rich UDF
|
|
8
11
|
* machinery. The SDK orchestrates state, cancellation, and re-runs.
|
|
9
12
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
const react_1 = require("react");
|
|
14
|
+
const bridge_1 = require("../bridge");
|
|
15
|
+
const form_1 = require("../form");
|
|
16
|
+
const use_canvas_params_1 = require("./use-canvas-params");
|
|
14
17
|
const PARAM_TOKEN_RE = /\$([a-zA-Z_][a-zA-Z0-9_]*)/g;
|
|
15
18
|
const UDF_PLACEHOLDER_RE = /\{\{[\s\S]*?\}\}/;
|
|
16
19
|
// Mirrors `parseInlineUdfPlaceholders` for the purpose of finding which UDF
|
|
@@ -37,17 +40,17 @@ const UDF_NAME_EXTRACT_RE = /\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\b/g;
|
|
|
37
40
|
* { preserveMissingParams: true }
|
|
38
41
|
* );
|
|
39
42
|
*/
|
|
40
|
-
|
|
43
|
+
function useParamSubstitution(template, options = {}) {
|
|
41
44
|
const safeTemplate = template ?? "";
|
|
42
45
|
const preserveMissingParams = options.preserveMissingParams ?? false;
|
|
43
|
-
const bridge = useFusedWidgetBridge();
|
|
44
|
-
const paramNames = useMemo(() => extractParamNames(safeTemplate), [safeTemplate]);
|
|
45
|
-
const canvasValues = useCanvasParams(paramNames);
|
|
46
|
-
const { inForm, values: formValues } = useFormParams(paramNames);
|
|
47
|
-
const paramValues = useMemo(() => (inForm ? { ...canvasValues, ...formValues } : canvasValues), [canvasValues, formValues, inForm]);
|
|
48
|
-
const hasUdfRefs = useMemo(() => UDF_PLACEHOLDER_RE.test(safeTemplate), [safeTemplate]);
|
|
46
|
+
const bridge = (0, bridge_1.useFusedWidgetBridge)();
|
|
47
|
+
const paramNames = (0, react_1.useMemo)(() => extractParamNames(safeTemplate), [safeTemplate]);
|
|
48
|
+
const canvasValues = (0, use_canvas_params_1.useCanvasParams)(paramNames);
|
|
49
|
+
const { inForm, values: formValues } = (0, form_1.useFormParams)(paramNames);
|
|
50
|
+
const paramValues = (0, react_1.useMemo)(() => (inForm ? { ...canvasValues, ...formValues } : canvasValues), [canvasValues, formValues, inForm]);
|
|
51
|
+
const hasUdfRefs = (0, react_1.useMemo)(() => UDF_PLACEHOLDER_RE.test(safeTemplate), [safeTemplate]);
|
|
49
52
|
// ── Fast path: no UDF refs ─────────────────────────────────────────────
|
|
50
|
-
const pureParamValue = useMemo(() => {
|
|
53
|
+
const pureParamValue = (0, react_1.useMemo)(() => {
|
|
51
54
|
if (hasUdfRefs)
|
|
52
55
|
return "";
|
|
53
56
|
return substituteParams(safeTemplate, paramValues, preserveMissingParams);
|
|
@@ -56,7 +59,7 @@ export function useParamSubstitution(template, options = {}) {
|
|
|
56
59
|
// Extract referenced UDF names so we can subscribe to their outputs.
|
|
57
60
|
// When any of them re-executes we bump a tick and the effect below
|
|
58
61
|
// re-runs `bridge.template.render` with fresh data.
|
|
59
|
-
const referencedUdfNames = useMemo(() => {
|
|
62
|
+
const referencedUdfNames = (0, react_1.useMemo)(() => {
|
|
60
63
|
if (!hasUdfRefs)
|
|
61
64
|
return [];
|
|
62
65
|
const seen = new Set();
|
|
@@ -74,10 +77,10 @@ export function useParamSubstitution(template, options = {}) {
|
|
|
74
77
|
// Subscribe to host re-render triggers (UDF outputs + topology) so that
|
|
75
78
|
// the async render re-runs when an upstream UDF re-executes or edges shift.
|
|
76
79
|
const templateChangeKey = useTemplateBridgeChangeKey(bridge, referencedUdfNames);
|
|
77
|
-
const [resolved, setResolved] = useState(() => ({ key: "", value: "" }));
|
|
78
|
-
const [loading, setLoading] = useState(false);
|
|
80
|
+
const [resolved, setResolved] = (0, react_1.useState)(() => ({ key: "", value: "" }));
|
|
81
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
79
82
|
// Render key includes template + paramValues + the host change ticker.
|
|
80
|
-
const renderKey = useMemo(() => {
|
|
83
|
+
const renderKey = (0, react_1.useMemo)(() => {
|
|
81
84
|
return JSON.stringify({
|
|
82
85
|
template: safeTemplate,
|
|
83
86
|
paramValues,
|
|
@@ -85,7 +88,7 @@ export function useParamSubstitution(template, options = {}) {
|
|
|
85
88
|
tick: templateChangeKey,
|
|
86
89
|
});
|
|
87
90
|
}, [safeTemplate, paramValues, preserveMissingParams, templateChangeKey]);
|
|
88
|
-
useEffect(() => {
|
|
91
|
+
(0, react_1.useEffect)(() => {
|
|
89
92
|
if (!hasUdfRefs) {
|
|
90
93
|
setLoading(false);
|
|
91
94
|
return;
|
|
@@ -124,7 +127,7 @@ export function useParamSubstitution(template, options = {}) {
|
|
|
124
127
|
preserveMissingParams,
|
|
125
128
|
renderKey,
|
|
126
129
|
]);
|
|
127
|
-
const value = useMemo(() => {
|
|
130
|
+
const value = (0, react_1.useMemo)(() => {
|
|
128
131
|
if (!hasUdfRefs)
|
|
129
132
|
return pureParamValue;
|
|
130
133
|
if (resolved.key === renderKey)
|
|
@@ -187,9 +190,9 @@ function stringifyParamValue(value) {
|
|
|
187
190
|
* changes whenever a re-render could produce a different result.
|
|
188
191
|
*/
|
|
189
192
|
function useTemplateBridgeChangeKey(bridge, referencedUdfNames) {
|
|
190
|
-
const tickRef = useRef(0);
|
|
193
|
+
const tickRef = (0, react_1.useRef)(0);
|
|
191
194
|
const namesKey = referencedUdfNames.slice().sort().join("|");
|
|
192
|
-
const subscribe = useCallback((cb) => {
|
|
195
|
+
const subscribe = (0, react_1.useCallback)((cb) => {
|
|
193
196
|
const fire = () => {
|
|
194
197
|
tickRef.current += 1;
|
|
195
198
|
cb();
|
|
@@ -202,6 +205,6 @@ function useTemplateBridgeChangeKey(bridge, referencedUdfNames) {
|
|
|
202
205
|
},
|
|
203
206
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
204
207
|
[bridge, namesKey]);
|
|
205
|
-
const getSnapshot = useCallback(() => tickRef.current, []);
|
|
206
|
-
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
208
|
+
const getSnapshot = (0, react_1.useCallback)(() => tickRef.current, []);
|
|
209
|
+
return (0, react_1.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
207
210
|
}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useUdfOutputByName = useUdfOutputByName;
|
|
4
|
+
exports.useRequestUdfReexecute = useRequestUdfReexecute;
|
|
5
|
+
exports.isUdfQuery = isUdfQuery;
|
|
6
|
+
exports.parseUdfColumnQuery = parseUdfColumnQuery;
|
|
7
|
+
exports.useUdfDataFrameSample = useUdfDataFrameSample;
|
|
8
|
+
exports.useUdfColumnValues = useUdfColumnValues;
|
|
9
|
+
exports.useUdfColumnValue = useUdfColumnValue;
|
|
10
|
+
const react_1 = require("react");
|
|
11
|
+
const bridge_1 = require("../bridge");
|
|
3
12
|
/**
|
|
4
13
|
* Subscribe to a UDF's output by name. Returns the current `UdfOutputSnapshot`
|
|
5
14
|
* (data + execution status + optional error + VFS filename) or `undefined`
|
|
@@ -14,15 +23,15 @@ import { useFusedWidgetBridge } from "../bridge";
|
|
|
14
23
|
* if (out.isExecutionInProgress) return <div>Loading…</div>;
|
|
15
24
|
* if (out.error) return <div>Error: {out.error}</div>;
|
|
16
25
|
*/
|
|
17
|
-
|
|
18
|
-
const bridge = useFusedWidgetBridge();
|
|
19
|
-
const subscribe = useCallback((cb) => {
|
|
26
|
+
function useUdfOutputByName(udfName) {
|
|
27
|
+
const bridge = (0, bridge_1.useFusedWidgetBridge)();
|
|
28
|
+
const subscribe = (0, react_1.useCallback)((cb) => {
|
|
20
29
|
if (!udfName)
|
|
21
30
|
return () => { };
|
|
22
31
|
return bridge.udfs.subscribeOutput(udfName, cb);
|
|
23
32
|
}, [bridge, udfName]);
|
|
24
|
-
const snapshotRef = useRef(undefined);
|
|
25
|
-
const getSnapshot = useCallback(() => {
|
|
33
|
+
const snapshotRef = (0, react_1.useRef)(undefined);
|
|
34
|
+
const getSnapshot = (0, react_1.useCallback)(() => {
|
|
26
35
|
if (!udfName)
|
|
27
36
|
return undefined;
|
|
28
37
|
const next = bridge.udfs.getOutputSnapshot(udfName);
|
|
@@ -32,15 +41,15 @@ export function useUdfOutputByName(udfName) {
|
|
|
32
41
|
snapshotRef.current = next;
|
|
33
42
|
return next;
|
|
34
43
|
}, [bridge, udfName]);
|
|
35
|
-
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
44
|
+
return (0, react_1.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
36
45
|
}
|
|
37
46
|
/**
|
|
38
47
|
* Request the workbench to re-execute a named UDF (e.g. after the user
|
|
39
48
|
* clicks a "Refresh" button). No-op in test harnesses without re-execution.
|
|
40
49
|
*/
|
|
41
|
-
|
|
42
|
-
const bridge = useFusedWidgetBridge();
|
|
43
|
-
return useCallback((udfName) => bridge.udfs.requestReexecute(udfName), [bridge]);
|
|
50
|
+
function useRequestUdfReexecute() {
|
|
51
|
+
const bridge = (0, bridge_1.useFusedWidgetBridge)();
|
|
52
|
+
return (0, react_1.useCallback)((udfName) => bridge.udfs.requestReexecute(udfName), [bridge]);
|
|
44
53
|
}
|
|
45
54
|
function snapshotsEqual(a, b) {
|
|
46
55
|
if (a === b)
|
|
@@ -64,7 +73,7 @@ const UDF_QUERY_REGEX = /^\{\{(\w+)\.(\w+)(?:\[(\d+)\])?\}\}$/;
|
|
|
64
73
|
* isUdfQuery("{{my_udf.city[0]}}") // true
|
|
65
74
|
* isUdfQuery("not a query") // false
|
|
66
75
|
*/
|
|
67
|
-
|
|
76
|
+
function isUdfQuery(query) {
|
|
68
77
|
if (!query || typeof query !== "string")
|
|
69
78
|
return false;
|
|
70
79
|
return UDF_QUERY_REGEX.test(query);
|
|
@@ -76,7 +85,7 @@ export function isUdfQuery(query) {
|
|
|
76
85
|
* parseUdfColumnQuery("{{my_udf.city}}") // { udfName: "my_udf", columnName: "city" }
|
|
77
86
|
* parseUdfColumnQuery("{{my_udf.city[0]}}") // { ..., index: 0 }
|
|
78
87
|
*/
|
|
79
|
-
|
|
88
|
+
function parseUdfColumnQuery(query) {
|
|
80
89
|
if (!isUdfQuery(query))
|
|
81
90
|
return null;
|
|
82
91
|
const match = query.match(UDF_QUERY_REGEX);
|
|
@@ -96,12 +105,12 @@ function isDataSourceLike(value) {
|
|
|
96
105
|
* column names. Used by dropdowns and galleries that populate options
|
|
97
106
|
* from UDF data.
|
|
98
107
|
*/
|
|
99
|
-
|
|
108
|
+
function useUdfDataFrameSample({ udfName, sampleSize = 200, }) {
|
|
100
109
|
const snapshot = useUdfOutputByName(udfName);
|
|
101
110
|
const reexecute = useRequestUdfReexecute();
|
|
102
|
-
const [rows, setRows] = useState([]);
|
|
103
|
-
const [columns, setColumns] = useState([]);
|
|
104
|
-
useEffect(() => {
|
|
111
|
+
const [rows, setRows] = (0, react_1.useState)([]);
|
|
112
|
+
const [columns, setColumns] = (0, react_1.useState)([]);
|
|
113
|
+
(0, react_1.useEffect)(() => {
|
|
105
114
|
let cancelled = false;
|
|
106
115
|
const data = snapshot?.data;
|
|
107
116
|
if (!data || !isDataSourceLike(data)) {
|
|
@@ -139,7 +148,7 @@ export function useUdfDataFrameSample({ udfName, sampleSize = 200, }) {
|
|
|
139
148
|
cancelled = true;
|
|
140
149
|
};
|
|
141
150
|
}, [snapshot?.data, sampleSize]);
|
|
142
|
-
const requestReexecute = useCallback(() => {
|
|
151
|
+
const requestReexecute = (0, react_1.useCallback)(() => {
|
|
143
152
|
if (udfName)
|
|
144
153
|
reexecute(udfName);
|
|
145
154
|
}, [reexecute, udfName]);
|
|
@@ -159,14 +168,14 @@ export function useUdfDataFrameSample({ udfName, sampleSize = 200, }) {
|
|
|
159
168
|
* const { values, loading } = useUdfColumnValues("{{my_udf.city}}");
|
|
160
169
|
* // values = ["NYC", "LA", "SF", ...]
|
|
161
170
|
*/
|
|
162
|
-
|
|
171
|
+
function useUdfColumnValues(query, sampleSize = 200) {
|
|
163
172
|
const isValid = isUdfQuery(query);
|
|
164
|
-
const parsed = useMemo(() => (isValid ? parseUdfColumnQuery(query) : null), [isValid, query]);
|
|
173
|
+
const parsed = (0, react_1.useMemo)(() => (isValid ? parseUdfColumnQuery(query) : null), [isValid, query]);
|
|
165
174
|
const { rows, loading } = useUdfDataFrameSample({
|
|
166
175
|
udfName: parsed?.udfName,
|
|
167
176
|
sampleSize,
|
|
168
177
|
});
|
|
169
|
-
const values = useMemo(() => {
|
|
178
|
+
const values = (0, react_1.useMemo)(() => {
|
|
170
179
|
if (!parsed || !parsed.columnName)
|
|
171
180
|
return [];
|
|
172
181
|
return rows
|
|
@@ -182,14 +191,14 @@ export function useUdfColumnValues(query, sampleSize = 200) {
|
|
|
182
191
|
* const { value, loading } = useUdfColumnValue("{{my_udf.city[0]}}");
|
|
183
192
|
* // value = "NYC"
|
|
184
193
|
*/
|
|
185
|
-
|
|
194
|
+
function useUdfColumnValue(query, sampleSize = 200) {
|
|
186
195
|
const isValid = isUdfQuery(query);
|
|
187
|
-
const parsed = useMemo(() => (isValid ? parseUdfColumnQuery(query) : null), [isValid, query]);
|
|
196
|
+
const parsed = (0, react_1.useMemo)(() => (isValid ? parseUdfColumnQuery(query) : null), [isValid, query]);
|
|
188
197
|
const { rows, loading } = useUdfDataFrameSample({
|
|
189
198
|
udfName: parsed?.udfName,
|
|
190
199
|
sampleSize,
|
|
191
200
|
});
|
|
192
|
-
const value = useMemo(() => {
|
|
201
|
+
const value = (0, react_1.useMemo)(() => {
|
|
193
202
|
if (!parsed || !parsed.columnName || parsed.index === undefined)
|
|
194
203
|
return null;
|
|
195
204
|
const row = rows[parsed.index];
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useUploadAccessCheck = useUploadAccessCheck;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const bridge_1 = require("../bridge");
|
|
3
6
|
/**
|
|
4
7
|
* Check whether the current user has write access to a destination path
|
|
5
8
|
* (S3, GCS, etc.). Used by the `file-upload` widget to surface a clear
|
|
@@ -8,10 +11,10 @@ import { useFusedWidgetBridge } from "../bridge";
|
|
|
8
11
|
* Returns a state machine value `{ status: "idle" | "checking" | "allowed" |
|
|
9
12
|
* "denied" }` that you can branch on directly in render.
|
|
10
13
|
*/
|
|
11
|
-
|
|
12
|
-
const bridge = useFusedWidgetBridge();
|
|
13
|
-
const [state, setState] = useState({ status: "idle" });
|
|
14
|
-
useEffect(() => {
|
|
14
|
+
function useUploadAccessCheck(destinationPath, enabled) {
|
|
15
|
+
const bridge = (0, bridge_1.useFusedWidgetBridge)();
|
|
16
|
+
const [state, setState] = (0, react_1.useState)({ status: "idle" });
|
|
17
|
+
(0, react_1.useEffect)(() => {
|
|
15
18
|
if (!enabled || !destinationPath?.trim()) {
|
|
16
19
|
setState({ status: "idle" });
|
|
17
20
|
return;
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SIGNED_URL_SCHEMES = void 0;
|
|
4
|
+
exports.useUrlSigning = useUrlSigning;
|
|
5
|
+
exports.useMediaSrc = useMediaSrc;
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const bridge_1 = require("../bridge");
|
|
8
|
+
const use_param_substitution_1 = require("./use-param-substitution");
|
|
4
9
|
/** URL schemes that require signing before fetch. */
|
|
5
|
-
|
|
10
|
+
exports.SIGNED_URL_SCHEMES = ["s3://", "gs://", "fd://"];
|
|
6
11
|
function needsSigning(url) {
|
|
7
|
-
return SIGNED_URL_SCHEMES.some((scheme) => url.startsWith(scheme));
|
|
12
|
+
return exports.SIGNED_URL_SCHEMES.some((scheme) => url.startsWith(scheme));
|
|
8
13
|
}
|
|
9
14
|
/**
|
|
10
15
|
* Manual URL signing — returns a stable `signUrl` callback you can call
|
|
@@ -18,9 +23,9 @@ function needsSigning(url) {
|
|
|
18
23
|
* window.location.href = signed;
|
|
19
24
|
* };
|
|
20
25
|
*/
|
|
21
|
-
|
|
22
|
-
const bridge = useFusedWidgetBridge();
|
|
23
|
-
const signUrl = useCallback((url) => bridge.signUrl(url), [bridge]);
|
|
26
|
+
function useUrlSigning() {
|
|
27
|
+
const bridge = (0, bridge_1.useFusedWidgetBridge)();
|
|
28
|
+
const signUrl = (0, react_1.useCallback)((url) => bridge.signUrl(url), [bridge]);
|
|
24
29
|
return { signUrl };
|
|
25
30
|
}
|
|
26
31
|
/**
|
|
@@ -33,14 +38,14 @@ export function useUrlSigning() {
|
|
|
33
38
|
* if (error) return <div>Failed: {error}</div>;
|
|
34
39
|
* return <img src={src ?? ""} alt="" />;
|
|
35
40
|
*/
|
|
36
|
-
|
|
37
|
-
const bridge = useFusedWidgetBridge();
|
|
38
|
-
const { value: resolvedSrc, loading: paramLoading } = useParamSubstitution(srcInput);
|
|
39
|
-
const [displaySrc, setDisplaySrc] = useState(null);
|
|
40
|
-
const [error, setError] = useState(null);
|
|
41
|
-
const [signing, setSigning] = useState(false);
|
|
42
|
-
const [refreshNonce, setRefreshNonce] = useState(0);
|
|
43
|
-
useEffect(() => {
|
|
41
|
+
function useMediaSrc(srcInput) {
|
|
42
|
+
const bridge = (0, bridge_1.useFusedWidgetBridge)();
|
|
43
|
+
const { value: resolvedSrc, loading: paramLoading } = (0, use_param_substitution_1.useParamSubstitution)(srcInput);
|
|
44
|
+
const [displaySrc, setDisplaySrc] = (0, react_1.useState)(null);
|
|
45
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
46
|
+
const [signing, setSigning] = (0, react_1.useState)(false);
|
|
47
|
+
const [refreshNonce, setRefreshNonce] = (0, react_1.useState)(0);
|
|
48
|
+
(0, react_1.useEffect)(() => {
|
|
44
49
|
if (paramLoading)
|
|
45
50
|
return;
|
|
46
51
|
if (!resolvedSrc) {
|
|
@@ -79,7 +84,7 @@ export function useMediaSrc(srcInput) {
|
|
|
79
84
|
cancelled = true;
|
|
80
85
|
};
|
|
81
86
|
}, [bridge, paramLoading, resolvedSrc, refreshNonce]);
|
|
82
|
-
const refreshSignedUrl = useCallback(async () => {
|
|
87
|
+
const refreshSignedUrl = (0, react_1.useCallback)(async () => {
|
|
83
88
|
if (!resolvedSrc || !needsSigning(resolvedSrc)) {
|
|
84
89
|
return resolvedSrc ?? null;
|
|
85
90
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -21,15 +21,18 @@ export * from "./types";
|
|
|
21
21
|
export { defineComponent, type CatalogComponentDefinition, } from "./define-component";
|
|
22
22
|
export { defineCatalog, type CatalogDefinition, type CatalogDefinitionBase, type CatalogDefinitionWithSkill, } from "./define-catalog";
|
|
23
23
|
export { useFusedParam } from "./hooks/use-fused-param";
|
|
24
|
+
export { useFusedParamWithForm } from "./hooks/use-fused-param-with-form";
|
|
24
25
|
export { useCanvasParams } from "./hooks/use-canvas-params";
|
|
25
26
|
export { useAllowedSources } from "./hooks/use-allowed-sources";
|
|
26
27
|
export { useAllowedUdfNames } from "./hooks/use-allowed-udf-names";
|
|
27
28
|
export { useParamSubstitution } from "./hooks/use-param-substitution";
|
|
28
29
|
export { useUdfOutputByName, useRequestUdfReexecute, useUdfDataFrameSample, useUdfColumnValue, useUdfColumnValues, isUdfQuery, parseUdfColumnQuery, type ParsedUdfQuery, type UseUdfDataFrameSampleOptions, type UseUdfDataFrameSampleResult, type UseUdfColumnValueResult, type UseUdfColumnValuesResult, } from "./hooks/use-udf-output";
|
|
29
30
|
export { useDuckDbSqlQuery, useDuckDbSqlQueryPreprocessing, useVfsRegistration, type UseDuckDbSqlQueryOptions, type UseDuckDbSqlQueryResult, type UseDuckDbSqlQueryPreprocessingResult, } from "./hooks/use-duckdb-sql";
|
|
31
|
+
export { SqlSourceOverrideContext, useSqlSourceOverrides, type SqlSourceOverride, type SqlSourceOverrideMap, } from "./hooks/sql-source-overrides";
|
|
30
32
|
export { useUrlSigning, useMediaSrc, SIGNED_URL_SCHEMES, type UseMediaSrcResult, } from "./hooks/use-url-signing";
|
|
31
33
|
export { useUploadAccessCheck, type UploadAccessState, } from "./hooks/use-upload-access-check";
|
|
32
34
|
export { useJsonUiLog, useJsonUiLogs, useJsonUiLogClear, } from "./hooks/use-json-ui-log";
|
|
33
35
|
export { useJsonUiUdfInfo } from "./hooks/use-json-ui-udf-info";
|
|
34
36
|
export { useJsonUiEdgeAnimation } from "./hooks/use-json-ui-edge-animation";
|
|
35
37
|
export * from "./utils/sql-placeholders";
|
|
38
|
+
export { parseStyle } from "./utils/parse-style";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* @fusedio/widget-sdk — public surface.
|
|
3
4
|
*
|
|
@@ -14,27 +15,76 @@
|
|
|
14
15
|
* Catalog components depend only on these hooks and types. They do not need
|
|
15
16
|
* to know about Jotai, BroadcastChannel internals, or the workbench source.
|
|
16
17
|
*/
|
|
18
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
21
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
22
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(o, k2, desc);
|
|
25
|
+
}) : (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
o[k2] = m[k];
|
|
28
|
+
}));
|
|
29
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
30
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
31
|
+
};
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.parseStyle = exports.useJsonUiEdgeAnimation = exports.useJsonUiUdfInfo = exports.useJsonUiLogClear = exports.useJsonUiLogs = exports.useJsonUiLog = exports.useUploadAccessCheck = exports.SIGNED_URL_SCHEMES = exports.useMediaSrc = exports.useUrlSigning = exports.useSqlSourceOverrides = exports.SqlSourceOverrideContext = exports.useVfsRegistration = exports.useDuckDbSqlQueryPreprocessing = exports.useDuckDbSqlQuery = exports.parseUdfColumnQuery = exports.isUdfQuery = exports.useUdfColumnValues = exports.useUdfColumnValue = exports.useUdfDataFrameSample = exports.useRequestUdfReexecute = exports.useUdfOutputByName = exports.useParamSubstitution = exports.useAllowedUdfNames = exports.useAllowedSources = exports.useCanvasParams = exports.useFusedParamWithForm = exports.useFusedParam = exports.defineCatalog = exports.defineComponent = void 0;
|
|
17
34
|
// ── Part 1: Provider contract ────────────────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
35
|
+
__exportStar(require("./protocol"), exports);
|
|
36
|
+
__exportStar(require("./bridge"), exports);
|
|
37
|
+
__exportStar(require("./form"), exports);
|
|
21
38
|
// ── Part 2: Hook types ───────────────────────────────────────────────────────
|
|
22
|
-
|
|
39
|
+
__exportStar(require("./types"), exports);
|
|
23
40
|
// ── Part 3: Catalog component registration ───────────────────────────────────
|
|
24
|
-
|
|
25
|
-
|
|
41
|
+
var define_component_1 = require("./define-component");
|
|
42
|
+
Object.defineProperty(exports, "defineComponent", { enumerable: true, get: function () { return define_component_1.defineComponent; } });
|
|
43
|
+
var define_catalog_1 = require("./define-catalog");
|
|
44
|
+
Object.defineProperty(exports, "defineCatalog", { enumerable: true, get: function () { return define_catalog_1.defineCatalog; } });
|
|
26
45
|
// ── Part 2: Hooks ────────────────────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
var use_fused_param_1 = require("./hooks/use-fused-param");
|
|
47
|
+
Object.defineProperty(exports, "useFusedParam", { enumerable: true, get: function () { return use_fused_param_1.useFusedParam; } });
|
|
48
|
+
var use_fused_param_with_form_1 = require("./hooks/use-fused-param-with-form");
|
|
49
|
+
Object.defineProperty(exports, "useFusedParamWithForm", { enumerable: true, get: function () { return use_fused_param_with_form_1.useFusedParamWithForm; } });
|
|
50
|
+
var use_canvas_params_1 = require("./hooks/use-canvas-params");
|
|
51
|
+
Object.defineProperty(exports, "useCanvasParams", { enumerable: true, get: function () { return use_canvas_params_1.useCanvasParams; } });
|
|
52
|
+
var use_allowed_sources_1 = require("./hooks/use-allowed-sources");
|
|
53
|
+
Object.defineProperty(exports, "useAllowedSources", { enumerable: true, get: function () { return use_allowed_sources_1.useAllowedSources; } });
|
|
54
|
+
var use_allowed_udf_names_1 = require("./hooks/use-allowed-udf-names");
|
|
55
|
+
Object.defineProperty(exports, "useAllowedUdfNames", { enumerable: true, get: function () { return use_allowed_udf_names_1.useAllowedUdfNames; } });
|
|
56
|
+
var use_param_substitution_1 = require("./hooks/use-param-substitution");
|
|
57
|
+
Object.defineProperty(exports, "useParamSubstitution", { enumerable: true, get: function () { return use_param_substitution_1.useParamSubstitution; } });
|
|
58
|
+
var use_udf_output_1 = require("./hooks/use-udf-output");
|
|
59
|
+
Object.defineProperty(exports, "useUdfOutputByName", { enumerable: true, get: function () { return use_udf_output_1.useUdfOutputByName; } });
|
|
60
|
+
Object.defineProperty(exports, "useRequestUdfReexecute", { enumerable: true, get: function () { return use_udf_output_1.useRequestUdfReexecute; } });
|
|
61
|
+
Object.defineProperty(exports, "useUdfDataFrameSample", { enumerable: true, get: function () { return use_udf_output_1.useUdfDataFrameSample; } });
|
|
62
|
+
Object.defineProperty(exports, "useUdfColumnValue", { enumerable: true, get: function () { return use_udf_output_1.useUdfColumnValue; } });
|
|
63
|
+
Object.defineProperty(exports, "useUdfColumnValues", { enumerable: true, get: function () { return use_udf_output_1.useUdfColumnValues; } });
|
|
64
|
+
Object.defineProperty(exports, "isUdfQuery", { enumerable: true, get: function () { return use_udf_output_1.isUdfQuery; } });
|
|
65
|
+
Object.defineProperty(exports, "parseUdfColumnQuery", { enumerable: true, get: function () { return use_udf_output_1.parseUdfColumnQuery; } });
|
|
66
|
+
var use_duckdb_sql_1 = require("./hooks/use-duckdb-sql");
|
|
67
|
+
Object.defineProperty(exports, "useDuckDbSqlQuery", { enumerable: true, get: function () { return use_duckdb_sql_1.useDuckDbSqlQuery; } });
|
|
68
|
+
Object.defineProperty(exports, "useDuckDbSqlQueryPreprocessing", { enumerable: true, get: function () { return use_duckdb_sql_1.useDuckDbSqlQueryPreprocessing; } });
|
|
69
|
+
Object.defineProperty(exports, "useVfsRegistration", { enumerable: true, get: function () { return use_duckdb_sql_1.useVfsRegistration; } });
|
|
70
|
+
var sql_source_overrides_1 = require("./hooks/sql-source-overrides");
|
|
71
|
+
Object.defineProperty(exports, "SqlSourceOverrideContext", { enumerable: true, get: function () { return sql_source_overrides_1.SqlSourceOverrideContext; } });
|
|
72
|
+
Object.defineProperty(exports, "useSqlSourceOverrides", { enumerable: true, get: function () { return sql_source_overrides_1.useSqlSourceOverrides; } });
|
|
73
|
+
var use_url_signing_1 = require("./hooks/use-url-signing");
|
|
74
|
+
Object.defineProperty(exports, "useUrlSigning", { enumerable: true, get: function () { return use_url_signing_1.useUrlSigning; } });
|
|
75
|
+
Object.defineProperty(exports, "useMediaSrc", { enumerable: true, get: function () { return use_url_signing_1.useMediaSrc; } });
|
|
76
|
+
Object.defineProperty(exports, "SIGNED_URL_SCHEMES", { enumerable: true, get: function () { return use_url_signing_1.SIGNED_URL_SCHEMES; } });
|
|
77
|
+
var use_upload_access_check_1 = require("./hooks/use-upload-access-check");
|
|
78
|
+
Object.defineProperty(exports, "useUploadAccessCheck", { enumerable: true, get: function () { return use_upload_access_check_1.useUploadAccessCheck; } });
|
|
79
|
+
var use_json_ui_log_1 = require("./hooks/use-json-ui-log");
|
|
80
|
+
Object.defineProperty(exports, "useJsonUiLog", { enumerable: true, get: function () { return use_json_ui_log_1.useJsonUiLog; } });
|
|
81
|
+
Object.defineProperty(exports, "useJsonUiLogs", { enumerable: true, get: function () { return use_json_ui_log_1.useJsonUiLogs; } });
|
|
82
|
+
Object.defineProperty(exports, "useJsonUiLogClear", { enumerable: true, get: function () { return use_json_ui_log_1.useJsonUiLogClear; } });
|
|
83
|
+
var use_json_ui_udf_info_1 = require("./hooks/use-json-ui-udf-info");
|
|
84
|
+
Object.defineProperty(exports, "useJsonUiUdfInfo", { enumerable: true, get: function () { return use_json_ui_udf_info_1.useJsonUiUdfInfo; } });
|
|
85
|
+
var use_json_ui_edge_animation_1 = require("./hooks/use-json-ui-edge-animation");
|
|
86
|
+
Object.defineProperty(exports, "useJsonUiEdgeAnimation", { enumerable: true, get: function () { return use_json_ui_edge_animation_1.useJsonUiEdgeAnimation; } });
|
|
39
87
|
// ── Pure utilities (re-exported for advanced workbench paths) ────────────────
|
|
40
|
-
|
|
88
|
+
__exportStar(require("./utils/sql-placeholders"), exports);
|
|
89
|
+
var parse_style_1 = require("./utils/parse-style");
|
|
90
|
+
Object.defineProperty(exports, "parseStyle", { enumerable: true, get: function () { return parse_style_1.parseStyle; } });
|
package/dist/protocol.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ParameterMessageType = exports.PARAMETER_BROADCAST_CHANNEL = void 0;
|
|
4
|
+
exports.isStandardMessage = isStandardMessage;
|
|
1
5
|
/**
|
|
2
6
|
* The Fused workbench listens on this BroadcastChannel for parameter updates
|
|
3
7
|
* from all components — both built-in and 3rd-party catalogs. The channel name
|
|
4
8
|
* is part of the public protocol; do not change it without coordinating with
|
|
5
9
|
* the workbench listener and all in-the-wild catalogs.
|
|
6
10
|
*/
|
|
7
|
-
|
|
11
|
+
exports.PARAMETER_BROADCAST_CHANNEL = "parameter-updates";
|
|
8
12
|
/**
|
|
9
13
|
* Discriminator for parameter messages on the BroadcastChannel.
|
|
10
14
|
*
|
|
@@ -13,15 +17,15 @@ export const PARAMETER_BROADCAST_CHANNEL = "parameter-updates";
|
|
|
13
17
|
* - `VIEWPORT` — map viewport bounds: `{ west, south, east, north }`
|
|
14
18
|
* - `CLEAR` — clear a parameter for this source (value will be `null`)
|
|
15
19
|
*/
|
|
16
|
-
|
|
20
|
+
var ParameterMessageType;
|
|
17
21
|
(function (ParameterMessageType) {
|
|
18
22
|
ParameterMessageType["PARAM"] = "param";
|
|
19
23
|
ParameterMessageType["RANGE"] = "range";
|
|
20
24
|
ParameterMessageType["VIEWPORT"] = "viewport";
|
|
21
25
|
ParameterMessageType["CLEAR"] = "clear";
|
|
22
|
-
})(ParameterMessageType || (ParameterMessageType = {}));
|
|
26
|
+
})(ParameterMessageType || (exports.ParameterMessageType = ParameterMessageType = {}));
|
|
23
27
|
/** Type guard that verifies an unknown object is a valid StandardMessage. */
|
|
24
|
-
|
|
28
|
+
function isStandardMessage(msg) {
|
|
25
29
|
if (typeof msg !== "object" || msg === null)
|
|
26
30
|
return false;
|
|
27
31
|
const m = msg;
|
package/dist/types.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Parses a plain CSS string into a React CSSProperties object.
|
|
4
|
+
* e.g. "color: red; font-size: 16px" → { color: "red", fontSize: "16px" }
|
|
5
|
+
*
|
|
6
|
+
* Pure — no bridge, no context. Used by every json-ui component that accepts
|
|
7
|
+
* a `style` string prop, across all hosts (workbench, MCP, test harness).
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseStyle(style: string | undefined): CSSProperties;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseStyle = parseStyle;
|
|
4
|
+
/**
|
|
5
|
+
* Parses a plain CSS string into a React CSSProperties object.
|
|
6
|
+
* e.g. "color: red; font-size: 16px" → { color: "red", fontSize: "16px" }
|
|
7
|
+
*
|
|
8
|
+
* Pure — no bridge, no context. Used by every json-ui component that accepts
|
|
9
|
+
* a `style` string prop, across all hosts (workbench, MCP, test harness).
|
|
10
|
+
*/
|
|
11
|
+
function parseStyle(style) {
|
|
12
|
+
if (!style)
|
|
13
|
+
return {};
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const declaration of style.split(";")) {
|
|
16
|
+
const colonIdx = declaration.indexOf(":");
|
|
17
|
+
if (colonIdx === -1)
|
|
18
|
+
continue;
|
|
19
|
+
const property = declaration.slice(0, colonIdx).trim();
|
|
20
|
+
const value = declaration.slice(colonIdx + 1).trim();
|
|
21
|
+
if (!property || !value)
|
|
22
|
+
continue;
|
|
23
|
+
const camelCase = property.replace(/-([a-z])/g, (_, l) => l.toUpperCase());
|
|
24
|
+
result[camelCase] = value;
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|