@osdk/widget.client-react 3.4.0-beta.1 → 3.4.0-beta.10
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 +82 -0
- package/build/browser/client.js +21 -2
- package/build/browser/client.js.map +1 -1
- package/build/browser/client.test.js +348 -0
- package/build/browser/client.test.js.map +1 -0
- package/build/browser/context.js +9 -0
- package/build/browser/context.js.map +1 -1
- package/build/browser/utils/transformEmitEventPayload.js +67 -0
- package/build/browser/utils/transformEmitEventPayload.js.map +1 -0
- package/build/browser/utils/transformEmitEventPayload.test.js +210 -0
- package/build/browser/utils/transformEmitEventPayload.test.js.map +1 -0
- package/build/cjs/index.cjs +60 -1
- package/build/cjs/index.cjs.map +1 -1
- package/build/cjs/index.d.cts +35 -3
- package/build/esm/client.js +21 -2
- package/build/esm/client.js.map +1 -1
- package/build/esm/client.test.js +348 -0
- package/build/esm/client.test.js.map +1 -0
- package/build/esm/context.js +9 -0
- package/build/esm/context.js.map +1 -1
- package/build/esm/utils/transformEmitEventPayload.js +67 -0
- package/build/esm/utils/transformEmitEventPayload.js.map +1 -0
- package/build/esm/utils/transformEmitEventPayload.test.js +210 -0
- package/build/esm/utils/transformEmitEventPayload.test.js.map +1 -0
- package/build/types/client.d.ts +1 -1
- package/build/types/client.d.ts.map +1 -1
- package/build/types/client.test.d.ts +3 -0
- package/build/types/client.test.d.ts.map +1 -0
- package/build/types/context.d.ts +38 -3
- package/build/types/context.d.ts.map +1 -1
- package/build/types/utils/transformEmitEventPayload.d.ts +41 -0
- package/build/types/utils/transformEmitEventPayload.d.ts.map +1 -0
- package/build/types/utils/transformEmitEventPayload.test.d.ts +1 -0
- package/build/types/utils/transformEmitEventPayload.test.d.ts.map +1 -0
- package/package.json +6 -5
package/build/esm/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["createFoundryWidgetClient","React","useEffect","useMemo","useRef","FoundryWidgetContext","ErrorBoundary","extendParametersWithObjectSets","initializeParameters","FoundryWidget","children","config","initialValues","client","osdkClient","asyncParameterValues","setAsyncParameterValues","useState","allParameterValues","setAllParameterValues","type","objectSetCache","Map","subscribe","hostEventTarget","addEventListener","payload","processedParameters","detail","parameters","current","currentParameters","aggregatedLoadedState","firstError","newParameterValues","key","value","error","currentParameterValue","updatedValue","Error","ready","resizeObserver","ResizeObserver","entries","length","console","entry","borderBoxSize","inlineSize","width","blockSize","height","resize","observe","document","body","box","unsubscribe","disconnect","createElement","Provider","emitEvent","values","state"],"sources":["client.tsx"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Client, ObjectSet } from \"@osdk/client\";\nimport type { ObjectType } from \"@osdk/widget.api\";\nimport type {\n AsyncValue,\n ParameterConfig,\n WidgetConfig,\n} from \"@osdk/widget.client\";\nimport { createFoundryWidgetClient } from \"@osdk/widget.client\";\nimport React, { useEffect, useMemo, useRef } from \"react\";\nimport type {\n ExtendedAsyncParameterValueMap,\n ExtendedParameterValueMap,\n FoundryWidgetClientContext,\n} from \"./context.js\";\nimport { FoundryWidgetContext } from \"./context.js\";\nimport { ErrorBoundary } from \"./ErrorBoundary.js\";\nimport { extendParametersWithObjectSets } from \"./utils/extendParametersWithObjectSets.js\";\nimport { initializeParameters } from \"./utils/initializeParameters.js\";\n\ntype ExtractObjectTypes<C extends WidgetConfig<C[\"parameters\"]>> =\n C[\"parameters\"][keyof C[\"parameters\"]] extends infer Param\n ? Param extends { type: \"objectSet\"; objectType: infer OT }\n ? OT extends ObjectType ? OT\n : never\n : never\n : never;\n\ntype HasObjectSetParameters<C extends WidgetConfig<C[\"parameters\"]>> =\n ExtractObjectTypes<C> extends never ? false : true;\n\ntype ObjectSetProps<C extends WidgetConfig<C[\"parameters\"]>> = {\n /**\n * Used to hydrate object sets from their RIDs for object set parameters\n */\n client: Client;\n};\n\ntype FoundryWidgetProps<C extends WidgetConfig<C[\"parameters\"]>> =\n & {\n children: React.ReactNode;\n\n /**\n * Parameter configuration for the widget\n */\n config: C;\n\n /**\n * Customize what the initial value of each parameter should be\n *\n * @default Sets all parameters to the \"not-started\" loading state\n */\n initialValues?: ExtendedAsyncParameterValueMap<C>;\n }\n & Partial<ObjectSetProps<C>>\n & (HasObjectSetParameters<C> extends true ? ObjectSetProps<C> : {});\n\n/**\n * Handles subscribing to messages from the host Foundry UI and updating the widget's parameter values accordingly via React context\n */\nexport const FoundryWidget = <C extends WidgetConfig<C[\"parameters\"]>>({\n children,\n config,\n initialValues,\n client: osdkClient,\n}: FoundryWidgetProps<C>): React.ReactElement<FoundryWidgetProps<C>> => {\n const client = useMemo(() => createFoundryWidgetClient<C>(), []);\n const [asyncParameterValues, setAsyncParameterValues] = React.useState<\n ExtendedAsyncParameterValueMap<C>\n >(initialValues ?? initializeParameters(config, \"not-started\"));\n const [allParameterValues, setAllParameterValues] = React.useState<\n AsyncValue<ExtendedParameterValueMap<C>>\n >({\n type: \"not-started\",\n });\n\n const objectSetCache = useRef<\n Map<string, { objectSetRid: string; objectSet: ObjectSet }>\n >(new Map());\n\n useEffect(() => {\n client.subscribe();\n client.hostEventTarget.addEventListener(\n \"host.update-parameters\",\n (payload) => {\n const processedParameters = extendParametersWithObjectSets(\n osdkClient,\n config,\n payload.detail.parameters,\n objectSetCache.current,\n );\n setAsyncParameterValues((currentParameters) => ({\n ...currentParameters,\n ...processedParameters,\n }));\n setAllParameterValues((currentParameters) => {\n let aggregatedLoadedState: AsyncValue<any>[\"type\"] = \"loaded\";\n let firstError: Error | undefined;\n const newParameterValues: ExtendedParameterValueMap<\n WidgetConfig<ParameterConfig>\n > = {};\n for (const key in processedParameters) {\n const value = processedParameters[key].value;\n // If any fails, consider the whole thing failed\n if (value.type === \"failed\") {\n aggregatedLoadedState = \"failed\";\n firstError = firstError ?? value.error;\n newParameterValues[key as any] = value.value as any;\n continue;\n }\n // If any is loading, consider all of it loading unless we have failed somewhere\n if (\n value.type === \"loading\"\n && aggregatedLoadedState !== \"failed\"\n ) {\n aggregatedLoadedState = \"loading\";\n continue;\n }\n // If any is reloading, consider it loading unless something is failed or loading for the first time\n if (\n value.type === \"reloading\"\n && aggregatedLoadedState !== \"failed\"\n && aggregatedLoadedState !== \"loading\"\n ) {\n aggregatedLoadedState = \"reloading\";\n newParameterValues[key as any] = value.value as any;\n continue;\n }\n if (\n value.type === \"not-started\"\n && aggregatedLoadedState !== \"failed\"\n && aggregatedLoadedState !== \"loading\"\n && aggregatedLoadedState !== \"reloading\"\n ) {\n aggregatedLoadedState = \"not-started\";\n }\n\n if (value.type === \"loaded\") {\n newParameterValues[key as any] = value.value as any;\n }\n }\n const currentParameterValue = currentParameters.type !== \"not-started\"\n && currentParameters.type !== \"loading\"\n ? currentParameters.value\n : {};\n if (\n aggregatedLoadedState !== \"not-started\"\n && aggregatedLoadedState !== \"loading\"\n ) {\n const updatedValue = {\n ...currentParameterValue,\n ...newParameterValues,\n } as ExtendedParameterValueMap<C>;\n return aggregatedLoadedState === \"failed\"\n ? {\n type: aggregatedLoadedState,\n value: updatedValue,\n error: firstError ?? new Error(\"Failed to load parameters\"),\n }\n : {\n type: aggregatedLoadedState,\n value: updatedValue,\n };\n } else {\n return { type: aggregatedLoadedState };\n }\n });\n },\n );\n client.ready();\n\n const resizeObserver = new ResizeObserver((entries) => {\n if (entries.length !== 1) {\n // eslint-disable-next-line no-console\n console.error(\n \"Expected exactly one resize observer entry but received:\",\n entries,\n );\n return;\n }\n const entry = entries[0];\n if (entry.borderBoxSize.length !== 1) {\n // eslint-disable-next-line no-console\n console.error(\n \"Expected exactly one border box size but received:\",\n entry.borderBoxSize,\n );\n return;\n }\n const { inlineSize: width, blockSize: height } = entry.borderBoxSize[0];\n client.resize({ width, height });\n });\n resizeObserver.observe(document.body, { box: \"border-box\" });\n\n return () => {\n client.unsubscribe();\n resizeObserver.disconnect();\n };\n }, []);\n\n return (\n <FoundryWidgetContext.Provider\n value={{\n emitEvent: client.emitEvent,\n hostEventTarget: client.hostEventTarget,\n asyncParameterValues,\n parameters: {\n values: allParameterValues.value ?? {},\n state: allParameterValues.type,\n },\n // Unfortunately the context is statically defined so we can't use the generic type, hence the cast\n } as FoundryWidgetClientContext<WidgetConfig<ParameterConfig>>}\n >\n <ErrorBoundary>\n {children}\n </ErrorBoundary>\n </FoundryWidgetContext.Provider>\n );\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"client.js","names":["createFoundryWidgetClient","React","useCallback","useEffect","useMemo","useRef","FoundryWidgetContext","ErrorBoundary","extendParametersWithObjectSets","initializeParameters","transformEmitEventPayload","FoundryWidget","children","config","initialValues","client","osdkClient","asyncParameterValues","setAsyncParameterValues","useState","allParameterValues","setAllParameterValues","type","objectSetCache","Map","emitEventCallIds","emitEvent","eventId","payload","transformResult","eventKey","String","thisCallId","current","get","set","transformedPayload","subscribe","hostEventTarget","addEventListener","processedParameters","detail","parameters","currentParameters","aggregatedLoadedState","firstError","newParameterValues","key","value","error","currentParameterValue","updatedValue","Error","ready","resizeObserver","ResizeObserver","entries","length","console","entry","borderBoxSize","inlineSize","width","blockSize","height","resize","observe","document","body","box","unsubscribe","disconnect","createElement","Provider","values","state"],"sources":["client.tsx"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Client, ObjectSet } from \"@osdk/client\";\nimport type { ObjectType } from \"@osdk/widget.api\";\nimport {\n type AsyncValue,\n createFoundryWidgetClient,\n type FoundryWidgetClient,\n type ParameterConfig,\n type WidgetConfig,\n} from \"@osdk/widget.client\";\nimport React, { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport type {\n AugmentedEmitEvent,\n ExtendedAsyncParameterValueMap,\n ExtendedParameterValueMap,\n FoundryWidgetClientContext,\n} from \"./context.js\";\nimport { FoundryWidgetContext } from \"./context.js\";\nimport { ErrorBoundary } from \"./ErrorBoundary.js\";\nimport { extendParametersWithObjectSets } from \"./utils/extendParametersWithObjectSets.js\";\nimport { initializeParameters } from \"./utils/initializeParameters.js\";\nimport { transformEmitEventPayload } from \"./utils/transformEmitEventPayload.js\";\n\ntype ExtractObjectTypes<C extends WidgetConfig<C[\"parameters\"]>> =\n C[\"parameters\"][keyof C[\"parameters\"]] extends infer Param\n ? Param extends { type: \"objectSet\"; objectType: infer OT }\n ? OT extends ObjectType ? OT\n : never\n : never\n : never;\n\ntype HasObjectSetParameters<C extends WidgetConfig<C[\"parameters\"]>> =\n ExtractObjectTypes<C> extends never ? false : true;\n\ntype ObjectSetProps<C extends WidgetConfig<C[\"parameters\"]>> = {\n /**\n * Used to hydrate object sets from their RIDs for object set parameters\n */\n client: Client;\n};\n\ntype FoundryWidgetProps<C extends WidgetConfig<C[\"parameters\"]>> =\n & {\n children: React.ReactNode;\n\n /**\n * Parameter configuration for the widget\n */\n config: C;\n\n /**\n * Customize what the initial value of each parameter should be\n *\n * @default Sets all parameters to the \"not-started\" loading state\n */\n initialValues?: ExtendedAsyncParameterValueMap<C>;\n }\n & Partial<ObjectSetProps<C>>\n & (HasObjectSetParameters<C> extends true ? ObjectSetProps<C> : {});\n\n/**\n * Handles subscribing to messages from the host Foundry UI and updating the widget's parameter values accordingly via React context\n */\nexport const FoundryWidget = <C extends WidgetConfig<C[\"parameters\"]>>({\n children,\n config,\n initialValues,\n client: osdkClient,\n}: FoundryWidgetProps<C>): React.ReactElement<FoundryWidgetProps<C>> => {\n const client = useMemo(() => createFoundryWidgetClient<C>(), []);\n const [asyncParameterValues, setAsyncParameterValues] = React.useState<\n ExtendedAsyncParameterValueMap<C>\n >(initialValues ?? initializeParameters(config, \"not-started\"));\n const [allParameterValues, setAllParameterValues] = React.useState<\n AsyncValue<ExtendedParameterValueMap<C>>\n >({\n type: \"not-started\",\n });\n\n const objectSetCache = useRef<\n Map<string, { objectSetRid: string; objectSet: ObjectSet }>\n >(new Map());\n\n const emitEventCallIds = useRef<Map<string, number>>(new Map());\n\n const emitEvent: AugmentedEmitEvent<C> = useCallback(\n (eventId: Parameters<FoundryWidgetClient<C>[\"emitEvent\"]>[0], payload) => {\n const transformResult = transformEmitEventPayload(\n config,\n eventId,\n payload,\n osdkClient,\n );\n if (transformResult.type === \"passThrough\") {\n client.emitEvent(\n eventId,\n transformResult.payload as Parameters<\n FoundryWidgetClient<C>[\"emitEvent\"]\n >[1],\n );\n return;\n }\n\n async function handleAsyncEmitEvent() {\n const eventKey = String(eventId);\n const thisCallId = (emitEventCallIds.current.get(eventKey) ?? 0) + 1;\n emitEventCallIds.current.set(eventKey, thisCallId);\n\n const transformedPayload = await transformResult.payload;\n\n if (thisCallId !== emitEventCallIds.current.get(eventKey)) {\n return;\n }\n\n client.emitEvent(\n eventId,\n transformedPayload as Parameters<\n FoundryWidgetClient<C>[\"emitEvent\"]\n >[1],\n );\n }\n\n void handleAsyncEmitEvent();\n },\n [osdkClient, config, client],\n );\n\n useEffect(() => {\n client.subscribe();\n client.hostEventTarget.addEventListener(\n \"host.update-parameters\",\n (payload) => {\n const processedParameters = extendParametersWithObjectSets(\n osdkClient,\n config,\n payload.detail.parameters,\n objectSetCache.current,\n );\n setAsyncParameterValues((currentParameters) => ({\n ...currentParameters,\n ...processedParameters,\n }));\n setAllParameterValues((currentParameters) => {\n let aggregatedLoadedState: AsyncValue<any>[\"type\"] = \"loaded\";\n let firstError: Error | undefined;\n const newParameterValues: ExtendedParameterValueMap<\n WidgetConfig<ParameterConfig>\n > = {};\n for (const key in processedParameters) {\n const value = processedParameters[key].value;\n // If any fails, consider the whole thing failed\n if (value.type === \"failed\") {\n aggregatedLoadedState = \"failed\";\n firstError = firstError ?? value.error;\n newParameterValues[key as any] = value.value as any;\n continue;\n }\n // If any is loading, consider all of it loading unless we have failed somewhere\n if (\n value.type === \"loading\"\n && aggregatedLoadedState !== \"failed\"\n ) {\n aggregatedLoadedState = \"loading\";\n continue;\n }\n // If any is reloading, consider it loading unless something is failed or loading for the first time\n if (\n value.type === \"reloading\"\n && aggregatedLoadedState !== \"failed\"\n && aggregatedLoadedState !== \"loading\"\n ) {\n aggregatedLoadedState = \"reloading\";\n newParameterValues[key as any] = value.value as any;\n continue;\n }\n if (\n value.type === \"not-started\"\n && aggregatedLoadedState !== \"failed\"\n && aggregatedLoadedState !== \"loading\"\n && aggregatedLoadedState !== \"reloading\"\n ) {\n aggregatedLoadedState = \"not-started\";\n }\n\n if (value.type === \"loaded\") {\n newParameterValues[key as any] = value.value as any;\n }\n }\n const currentParameterValue = currentParameters.type !== \"not-started\"\n && currentParameters.type !== \"loading\"\n ? currentParameters.value\n : {};\n if (\n aggregatedLoadedState !== \"not-started\"\n && aggregatedLoadedState !== \"loading\"\n ) {\n const updatedValue = {\n ...currentParameterValue,\n ...newParameterValues,\n } as ExtendedParameterValueMap<C>;\n return aggregatedLoadedState === \"failed\"\n ? {\n type: aggregatedLoadedState,\n value: updatedValue,\n error: firstError ?? new Error(\"Failed to load parameters\"),\n }\n : {\n type: aggregatedLoadedState,\n value: updatedValue,\n };\n } else {\n return { type: aggregatedLoadedState };\n }\n });\n },\n );\n client.ready();\n\n const resizeObserver = new ResizeObserver((entries) => {\n if (entries.length !== 1) {\n // eslint-disable-next-line no-console\n console.error(\n \"Expected exactly one resize observer entry but received:\",\n entries,\n );\n return;\n }\n const entry = entries[0];\n if (entry.borderBoxSize.length !== 1) {\n // eslint-disable-next-line no-console\n console.error(\n \"Expected exactly one border box size but received:\",\n entry.borderBoxSize,\n );\n return;\n }\n const { inlineSize: width, blockSize: height } = entry.borderBoxSize[0];\n client.resize({ width, height });\n });\n resizeObserver.observe(document.body, { box: \"border-box\" });\n\n return () => {\n client.unsubscribe();\n resizeObserver.disconnect();\n };\n }, []);\n\n return (\n <FoundryWidgetContext.Provider\n value={{\n emitEvent,\n hostEventTarget: client.hostEventTarget,\n asyncParameterValues,\n parameters: {\n values: allParameterValues.value ?? {},\n state: allParameterValues.type,\n },\n // Unfortunately the context is statically defined so we can't use the generic type, hence the cast\n } as FoundryWidgetClientContext<WidgetConfig<ParameterConfig>>}\n >\n <ErrorBoundary>\n {children}\n </ErrorBoundary>\n </FoundryWidgetContext.Provider>\n );\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
18
|
+
import { defineConfig, FoundryHostEventTarget } from "@osdk/widget.client";
|
|
19
|
+
import { act } from "react";
|
|
20
|
+
import { createRoot } from "react-dom/client";
|
|
21
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
22
|
+
import { FoundryWidget } from "./client.js";
|
|
23
|
+
import { useFoundryWidgetContext } from "./context.js";
|
|
24
|
+
import { transformEmitEventPayload } from "./utils/transformEmitEventPayload.js";
|
|
25
|
+
|
|
26
|
+
// Mocks
|
|
27
|
+
const mockEmitEvent = vi.fn();
|
|
28
|
+
const mockWidgetClient = {
|
|
29
|
+
subscribe: vi.fn(),
|
|
30
|
+
unsubscribe: vi.fn(),
|
|
31
|
+
ready: vi.fn(),
|
|
32
|
+
resize: vi.fn(),
|
|
33
|
+
emitEvent: mockEmitEvent,
|
|
34
|
+
hostEventTarget: new FoundryHostEventTarget()
|
|
35
|
+
};
|
|
36
|
+
vi.mock("./utils/transformEmitEventPayload.js", () => ({
|
|
37
|
+
transformEmitEventPayload: vi.fn()
|
|
38
|
+
}));
|
|
39
|
+
vi.mock("@osdk/widget.client", async () => {
|
|
40
|
+
const actual = await vi.importActual("@osdk/widget.client");
|
|
41
|
+
return {
|
|
42
|
+
...actual,
|
|
43
|
+
createFoundryWidgetClient: vi.fn(() => mockWidgetClient)
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Test config
|
|
48
|
+
const config = defineConfig({
|
|
49
|
+
id: "testWidget",
|
|
50
|
+
name: "Test Widget",
|
|
51
|
+
type: "workshop",
|
|
52
|
+
parameters: {
|
|
53
|
+
myParam: {
|
|
54
|
+
displayName: "My Param",
|
|
55
|
+
type: "string"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
events: {
|
|
59
|
+
eventA: {
|
|
60
|
+
displayName: "Event A",
|
|
61
|
+
parameterUpdateIds: ["myParam"]
|
|
62
|
+
},
|
|
63
|
+
eventB: {
|
|
64
|
+
displayName: "Event B",
|
|
65
|
+
parameterUpdateIds: ["myParam"]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
describe("FoundryWidget emitEvent race condition handling", () => {
|
|
70
|
+
const client = vi.fn();
|
|
71
|
+
let container;
|
|
72
|
+
let root;
|
|
73
|
+
function EmitEventCapture({
|
|
74
|
+
emitEventRef
|
|
75
|
+
}) {
|
|
76
|
+
const context = useFoundryWidgetContext();
|
|
77
|
+
emitEventRef.current = context.emitEvent;
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const mountWidget = async () => {
|
|
81
|
+
container = document.createElement("div");
|
|
82
|
+
document.body.appendChild(container);
|
|
83
|
+
root = createRoot(container);
|
|
84
|
+
const emitEventRef = {
|
|
85
|
+
current: null
|
|
86
|
+
};
|
|
87
|
+
act(() => {
|
|
88
|
+
root.render(/*#__PURE__*/React.createElement(FoundryWidget, {
|
|
89
|
+
config: config,
|
|
90
|
+
client: client
|
|
91
|
+
}, /*#__PURE__*/React.createElement(EmitEventCapture, {
|
|
92
|
+
emitEventRef: emitEventRef
|
|
93
|
+
})));
|
|
94
|
+
});
|
|
95
|
+
await act(async () => {
|
|
96
|
+
await vi.runAllTimersAsync();
|
|
97
|
+
});
|
|
98
|
+
return emitEventRef.current;
|
|
99
|
+
};
|
|
100
|
+
const unmountWidget = () => {
|
|
101
|
+
act(() => {
|
|
102
|
+
root.unmount();
|
|
103
|
+
});
|
|
104
|
+
document.body.removeChild(container);
|
|
105
|
+
};
|
|
106
|
+
const createDeferredTransformMock = () => {
|
|
107
|
+
const pending = [];
|
|
108
|
+
vi.mocked(transformEmitEventPayload).mockImplementation((_config, _eventId, payload) => ({
|
|
109
|
+
type: "async",
|
|
110
|
+
payload: new Promise(resolve => {
|
|
111
|
+
pending.push({
|
|
112
|
+
payload: payload,
|
|
113
|
+
resolve: resolve
|
|
114
|
+
});
|
|
115
|
+
})
|
|
116
|
+
}));
|
|
117
|
+
return {
|
|
118
|
+
get pendingCount() {
|
|
119
|
+
return pending.length;
|
|
120
|
+
},
|
|
121
|
+
resolveAll() {
|
|
122
|
+
pending.forEach(({
|
|
123
|
+
payload,
|
|
124
|
+
resolve
|
|
125
|
+
}) => resolve(payload));
|
|
126
|
+
},
|
|
127
|
+
resolveNext() {
|
|
128
|
+
const next = pending.shift();
|
|
129
|
+
if (next) next.resolve(next.payload);
|
|
130
|
+
},
|
|
131
|
+
resolveAtIndex(index) {
|
|
132
|
+
const item = pending[index];
|
|
133
|
+
if (item) {
|
|
134
|
+
pending.splice(index, 1);
|
|
135
|
+
item.resolve(item.payload);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
beforeEach(() => {
|
|
141
|
+
vi.clearAllMocks();
|
|
142
|
+
vi.useFakeTimers();
|
|
143
|
+
mockWidgetClient.hostEventTarget = new FoundryHostEventTarget();
|
|
144
|
+
});
|
|
145
|
+
afterEach(() => {
|
|
146
|
+
unmountWidget();
|
|
147
|
+
vi.useRealTimers();
|
|
148
|
+
});
|
|
149
|
+
it("should emit both events when different events are called", async () => {
|
|
150
|
+
const deferred = createDeferredTransformMock();
|
|
151
|
+
const emit = await mountWidget();
|
|
152
|
+
act(() => {
|
|
153
|
+
emit("eventA", {
|
|
154
|
+
parameterUpdates: {
|
|
155
|
+
myParam: "valueA"
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
emit("eventB", {
|
|
159
|
+
parameterUpdates: {
|
|
160
|
+
myParam: "valueB"
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
expect(deferred.pendingCount).toBe(2);
|
|
165
|
+
await act(async () => {
|
|
166
|
+
deferred.resolveAll();
|
|
167
|
+
await vi.runAllTimersAsync();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Both events should be emitted
|
|
171
|
+
expect(mockEmitEvent).toHaveBeenCalledTimes(2);
|
|
172
|
+
expect(mockEmitEvent).toHaveBeenCalledWith("eventA", {
|
|
173
|
+
parameterUpdates: {
|
|
174
|
+
myParam: "valueA"
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
expect(mockEmitEvent).toHaveBeenCalledWith("eventB", {
|
|
178
|
+
parameterUpdates: {
|
|
179
|
+
myParam: "valueB"
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
it("should only emit the last call even when transforms resolve out of order", async () => {
|
|
184
|
+
const deferred = createDeferredTransformMock();
|
|
185
|
+
const emit = await mountWidget();
|
|
186
|
+
|
|
187
|
+
// Call emitEvent 3 times rapidly
|
|
188
|
+
act(() => {
|
|
189
|
+
emit("eventA", {
|
|
190
|
+
parameterUpdates: {
|
|
191
|
+
myParam: "first"
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
emit("eventA", {
|
|
195
|
+
parameterUpdates: {
|
|
196
|
+
myParam: "second"
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
emit("eventA", {
|
|
200
|
+
parameterUpdates: {
|
|
201
|
+
myParam: "third"
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
expect(deferred.pendingCount).toBe(3);
|
|
206
|
+
|
|
207
|
+
// Resolve in different order: second first, then third, then first
|
|
208
|
+
// This proves only the last *call* emits, not just the last to resolve
|
|
209
|
+
await act(async () => {
|
|
210
|
+
deferred.resolveAtIndex(1); // "second" resolves first - should not emit
|
|
211
|
+
await vi.runAllTimersAsync();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// No emit yet since "second" wasn't the last call
|
|
215
|
+
expect(mockEmitEvent).toHaveBeenCalledTimes(0);
|
|
216
|
+
await act(async () => {
|
|
217
|
+
deferred.resolveAtIndex(1); // "third" resolves second (now at index 1)
|
|
218
|
+
await vi.runAllTimersAsync();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Now "third" should emit because it was the last call
|
|
222
|
+
expect(mockEmitEvent).toHaveBeenCalledTimes(1);
|
|
223
|
+
expect(mockEmitEvent).toHaveBeenCalledWith("eventA", {
|
|
224
|
+
parameterUpdates: {
|
|
225
|
+
myParam: "third"
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
await act(async () => {
|
|
229
|
+
deferred.resolveAtIndex(0); // "first" resolves last - should not emit
|
|
230
|
+
await vi.runAllTimersAsync();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Still only one emit - all stale calls are ignored
|
|
234
|
+
expect(mockEmitEvent).toHaveBeenCalledTimes(1);
|
|
235
|
+
});
|
|
236
|
+
it("should emit all calls when they complete sequentially", async () => {
|
|
237
|
+
const deferred = createDeferredTransformMock();
|
|
238
|
+
const emit = await mountWidget();
|
|
239
|
+
|
|
240
|
+
// First call
|
|
241
|
+
act(() => {
|
|
242
|
+
emit("eventA", {
|
|
243
|
+
parameterUpdates: {
|
|
244
|
+
myParam: "first"
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Complete first call before making second
|
|
250
|
+
await act(async () => {
|
|
251
|
+
deferred.resolveNext();
|
|
252
|
+
await vi.runAllTimersAsync();
|
|
253
|
+
});
|
|
254
|
+
expect(mockEmitEvent).toHaveBeenCalledTimes(1);
|
|
255
|
+
expect(mockEmitEvent).toHaveBeenLastCalledWith("eventA", {
|
|
256
|
+
parameterUpdates: {
|
|
257
|
+
myParam: "first"
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Second call after first completed
|
|
262
|
+
act(() => {
|
|
263
|
+
emit("eventA", {
|
|
264
|
+
parameterUpdates: {
|
|
265
|
+
myParam: "second"
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
await act(async () => {
|
|
270
|
+
deferred.resolveNext();
|
|
271
|
+
await vi.runAllTimersAsync();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Both sequential calls should be emitted
|
|
275
|
+
expect(mockEmitEvent).toHaveBeenCalledTimes(2);
|
|
276
|
+
expect(mockEmitEvent).toHaveBeenLastCalledWith("eventA", {
|
|
277
|
+
parameterUpdates: {
|
|
278
|
+
myParam: "second"
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
it("should emit all rapid calls synchronously when passThrough type is returned", async () => {
|
|
283
|
+
// Mock transformEmitEventPayload to return passThrough (synchronous) results
|
|
284
|
+
vi.mocked(transformEmitEventPayload).mockImplementation((_config, _eventId, payload) => ({
|
|
285
|
+
type: "passThrough",
|
|
286
|
+
payload: payload
|
|
287
|
+
}));
|
|
288
|
+
const emit = await mountWidget();
|
|
289
|
+
|
|
290
|
+
// Emit 5 events rapidly - all should go through synchronously
|
|
291
|
+
act(() => {
|
|
292
|
+
emit("eventA", {
|
|
293
|
+
parameterUpdates: {
|
|
294
|
+
myParam: "first"
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
emit("eventA", {
|
|
298
|
+
parameterUpdates: {
|
|
299
|
+
myParam: "second"
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
emit("eventA", {
|
|
303
|
+
parameterUpdates: {
|
|
304
|
+
myParam: "third"
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
emit("eventA", {
|
|
308
|
+
parameterUpdates: {
|
|
309
|
+
myParam: "fourth"
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
emit("eventA", {
|
|
313
|
+
parameterUpdates: {
|
|
314
|
+
myParam: "fifth"
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// All 5 should be emitted immediately without waiting for any async operations
|
|
320
|
+
expect(mockEmitEvent).toHaveBeenCalledTimes(5);
|
|
321
|
+
expect(mockEmitEvent).toHaveBeenNthCalledWith(1, "eventA", {
|
|
322
|
+
parameterUpdates: {
|
|
323
|
+
myParam: "first"
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
expect(mockEmitEvent).toHaveBeenNthCalledWith(2, "eventA", {
|
|
327
|
+
parameterUpdates: {
|
|
328
|
+
myParam: "second"
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
expect(mockEmitEvent).toHaveBeenNthCalledWith(3, "eventA", {
|
|
332
|
+
parameterUpdates: {
|
|
333
|
+
myParam: "third"
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
expect(mockEmitEvent).toHaveBeenNthCalledWith(4, "eventA", {
|
|
337
|
+
parameterUpdates: {
|
|
338
|
+
myParam: "fourth"
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
expect(mockEmitEvent).toHaveBeenNthCalledWith(5, "eventA", {
|
|
342
|
+
parameterUpdates: {
|
|
343
|
+
myParam: "fifth"
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
//# sourceMappingURL=client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.js","names":["globalThis","IS_REACT_ACT_ENVIRONMENT","defineConfig","FoundryHostEventTarget","act","createRoot","afterEach","beforeEach","describe","expect","it","vi","FoundryWidget","useFoundryWidgetContext","transformEmitEventPayload","mockEmitEvent","fn","mockWidgetClient","subscribe","unsubscribe","ready","resize","emitEvent","hostEventTarget","mock","actual","importActual","createFoundryWidgetClient","config","id","name","type","parameters","myParam","displayName","events","eventA","parameterUpdateIds","eventB","client","container","root","EmitEventCapture","emitEventRef","context","current","mountWidget","document","createElement","body","appendChild","render","React","runAllTimersAsync","unmountWidget","unmount","removeChild","createDeferredTransformMock","pending","mocked","mockImplementation","_config","_eventId","payload","Promise","resolve","push","pendingCount","length","resolveAll","forEach","resolveNext","next","shift","resolveAtIndex","index","item","splice","clearAllMocks","useFakeTimers","useRealTimers","deferred","emit","parameterUpdates","toBe","toHaveBeenCalledTimes","toHaveBeenCalledWith","toHaveBeenLastCalledWith","toHaveBeenNthCalledWith"],"sources":["client.test.tsx"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ndeclare global {\n var IS_REACT_ACT_ENVIRONMENT: boolean;\n}\nglobalThis.IS_REACT_ACT_ENVIRONMENT = true;\n\nimport type { Client } from \"@osdk/client\";\nimport { defineConfig, FoundryHostEventTarget } from \"@osdk/widget.client\";\nimport { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport type { Mock } from \"vitest\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { FoundryWidget } from \"./client.js\";\nimport { useFoundryWidgetContext } from \"./context.js\";\nimport { transformEmitEventPayload } from \"./utils/transformEmitEventPayload.js\";\n\n// Mocks\nconst mockEmitEvent = vi.fn();\nconst mockWidgetClient = {\n subscribe: vi.fn(),\n unsubscribe: vi.fn(),\n ready: vi.fn(),\n resize: vi.fn(),\n emitEvent: mockEmitEvent,\n hostEventTarget: new FoundryHostEventTarget(),\n};\n\nvi.mock(\"./utils/transformEmitEventPayload.js\", () => ({\n transformEmitEventPayload: vi.fn(),\n}));\n\nvi.mock(\"@osdk/widget.client\", async () => {\n const actual = await vi.importActual(\"@osdk/widget.client\");\n return {\n ...actual,\n createFoundryWidgetClient: vi.fn(() => mockWidgetClient),\n };\n});\n\n// Test config\nconst config = defineConfig({\n id: \"testWidget\",\n name: \"Test Widget\",\n type: \"workshop\",\n parameters: {\n myParam: {\n displayName: \"My Param\",\n type: \"string\",\n },\n },\n events: {\n eventA: {\n displayName: \"Event A\",\n parameterUpdateIds: [\"myParam\"],\n },\n eventB: {\n displayName: \"Event B\",\n parameterUpdateIds: [\"myParam\"],\n },\n },\n});\n\ndescribe(\"FoundryWidget emitEvent race condition handling\", () => {\n type EmitEventFn = (eventId: string, payload: unknown) => void;\n\n const client = vi.fn() as Mock<Client> & Client;\n let container: HTMLDivElement;\n let root: Root;\n\n function EmitEventCapture(\n { emitEventRef }: { emitEventRef: { current: EmitEventFn } },\n ) {\n const context = useFoundryWidgetContext<typeof config>();\n emitEventRef.current = context.emitEvent as EmitEventFn;\n return null;\n }\n\n const mountWidget = async () => {\n container = document.createElement(\"div\");\n document.body.appendChild(container);\n root = createRoot(container);\n\n const emitEventRef = { current: null as unknown as EmitEventFn };\n\n act(() => {\n root.render(\n <FoundryWidget config={config} client={client}>\n <EmitEventCapture emitEventRef={emitEventRef} />\n </FoundryWidget>,\n );\n });\n\n await act(async () => {\n await vi.runAllTimersAsync();\n });\n\n return emitEventRef.current;\n };\n\n const unmountWidget = () => {\n act(() => {\n root.unmount();\n });\n document.body.removeChild(container);\n };\n\n const createDeferredTransformMock = () => {\n const pending: Array<{\n payload: { parameterUpdates: { myParam: string } };\n resolve: (value: { parameterUpdates: { myParam: string } }) => void;\n }> = [];\n\n vi.mocked(transformEmitEventPayload).mockImplementation(\n (_config, _eventId, payload) => ({\n type: \"async\" as const,\n payload: new Promise((resolve) => {\n pending.push({\n payload: payload as { parameterUpdates: { myParam: string } },\n resolve: resolve as (\n value: { parameterUpdates: { myParam: string } },\n ) => void,\n });\n }),\n }),\n );\n\n return {\n get pendingCount() {\n return pending.length;\n },\n resolveAll() {\n pending.forEach(({ payload, resolve }) => resolve(payload));\n },\n resolveNext() {\n const next = pending.shift();\n if (next) next.resolve(next.payload);\n },\n resolveAtIndex(index: number) {\n const item = pending[index];\n if (item) {\n pending.splice(index, 1);\n item.resolve(item.payload);\n }\n },\n };\n };\n\n beforeEach(() => {\n vi.clearAllMocks();\n vi.useFakeTimers();\n mockWidgetClient.hostEventTarget = new FoundryHostEventTarget();\n });\n\n afterEach(() => {\n unmountWidget();\n vi.useRealTimers();\n });\n\n it(\"should emit both events when different events are called\", async () => {\n const deferred = createDeferredTransformMock();\n const emit = await mountWidget();\n\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"valueA\" } });\n emit(\"eventB\", { parameterUpdates: { myParam: \"valueB\" } });\n });\n\n expect(deferred.pendingCount).toBe(2);\n\n await act(async () => {\n deferred.resolveAll();\n await vi.runAllTimersAsync();\n });\n\n // Both events should be emitted\n expect(mockEmitEvent).toHaveBeenCalledTimes(2);\n expect(mockEmitEvent).toHaveBeenCalledWith(\"eventA\", {\n parameterUpdates: { myParam: \"valueA\" },\n });\n expect(mockEmitEvent).toHaveBeenCalledWith(\"eventB\", {\n parameterUpdates: { myParam: \"valueB\" },\n });\n });\n\n it(\"should only emit the last call even when transforms resolve out of order\", async () => {\n const deferred = createDeferredTransformMock();\n const emit = await mountWidget();\n\n // Call emitEvent 3 times rapidly\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"first\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"second\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"third\" } });\n });\n\n expect(deferred.pendingCount).toBe(3);\n\n // Resolve in different order: second first, then third, then first\n // This proves only the last *call* emits, not just the last to resolve\n await act(async () => {\n deferred.resolveAtIndex(1); // \"second\" resolves first - should not emit\n await vi.runAllTimersAsync();\n });\n\n // No emit yet since \"second\" wasn't the last call\n expect(mockEmitEvent).toHaveBeenCalledTimes(0);\n\n await act(async () => {\n deferred.resolveAtIndex(1); // \"third\" resolves second (now at index 1)\n await vi.runAllTimersAsync();\n });\n\n // Now \"third\" should emit because it was the last call\n expect(mockEmitEvent).toHaveBeenCalledTimes(1);\n expect(mockEmitEvent).toHaveBeenCalledWith(\"eventA\", {\n parameterUpdates: { myParam: \"third\" },\n });\n\n await act(async () => {\n deferred.resolveAtIndex(0); // \"first\" resolves last - should not emit\n await vi.runAllTimersAsync();\n });\n\n // Still only one emit - all stale calls are ignored\n expect(mockEmitEvent).toHaveBeenCalledTimes(1);\n });\n\n it(\"should emit all calls when they complete sequentially\", async () => {\n const deferred = createDeferredTransformMock();\n const emit = await mountWidget();\n\n // First call\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"first\" } });\n });\n\n // Complete first call before making second\n await act(async () => {\n deferred.resolveNext();\n await vi.runAllTimersAsync();\n });\n\n expect(mockEmitEvent).toHaveBeenCalledTimes(1);\n expect(mockEmitEvent).toHaveBeenLastCalledWith(\"eventA\", {\n parameterUpdates: { myParam: \"first\" },\n });\n\n // Second call after first completed\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"second\" } });\n });\n\n await act(async () => {\n deferred.resolveNext();\n await vi.runAllTimersAsync();\n });\n\n // Both sequential calls should be emitted\n expect(mockEmitEvent).toHaveBeenCalledTimes(2);\n expect(mockEmitEvent).toHaveBeenLastCalledWith(\"eventA\", {\n parameterUpdates: { myParam: \"second\" },\n });\n });\n\n it(\"should emit all rapid calls synchronously when passThrough type is returned\", async () => {\n // Mock transformEmitEventPayload to return passThrough (synchronous) results\n vi.mocked(transformEmitEventPayload).mockImplementation(\n (_config, _eventId, payload) => ({\n type: \"passThrough\" as const,\n payload: payload as { parameterUpdates: { myParam: string } },\n }),\n );\n\n const emit = await mountWidget();\n\n // Emit 5 events rapidly - all should go through synchronously\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"first\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"second\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"third\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"fourth\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"fifth\" } });\n });\n\n // All 5 should be emitted immediately without waiting for any async operations\n expect(mockEmitEvent).toHaveBeenCalledTimes(5);\n expect(mockEmitEvent).toHaveBeenNthCalledWith(1, \"eventA\", {\n parameterUpdates: { myParam: \"first\" },\n });\n expect(mockEmitEvent).toHaveBeenNthCalledWith(2, \"eventA\", {\n parameterUpdates: { myParam: \"second\" },\n });\n expect(mockEmitEvent).toHaveBeenNthCalledWith(3, \"eventA\", {\n parameterUpdates: { myParam: \"third\" },\n });\n expect(mockEmitEvent).toHaveBeenNthCalledWith(4, \"eventA\", {\n parameterUpdates: { myParam: \"fourth\" },\n });\n expect(mockEmitEvent).toHaveBeenNthCalledWith(5, \"eventA\", {\n parameterUpdates: { myParam: \"fifth\" },\n });\n });\n});\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKAA,UAAU,CAACC,wBAAwB,GAAG,IAAI;AAG1C,SAASC,YAAY,EAAEC,sBAAsB,QAAQ,qBAAqB;AAC1E,SAASC,GAAG,QAAQ,OAAO;AAC3B,SAASC,UAAU,QAAmB,kBAAkB;AAExD,SAASC,SAAS,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,QAAQ;AACxE,SAASC,aAAa,QAAQ,aAAa;AAC3C,SAASC,uBAAuB,QAAQ,cAAc;AACtD,SAASC,yBAAyB,QAAQ,sCAAsC;;AAEhF;AACA,MAAMC,aAAa,GAAGJ,EAAE,CAACK,EAAE,CAAC,CAAC;AAC7B,MAAMC,gBAAgB,GAAG;EACvBC,SAAS,EAAEP,EAAE,CAACK,EAAE,CAAC,CAAC;EAClBG,WAAW,EAAER,EAAE,CAACK,EAAE,CAAC,CAAC;EACpBI,KAAK,EAAET,EAAE,CAACK,EAAE,CAAC,CAAC;EACdK,MAAM,EAAEV,EAAE,CAACK,EAAE,CAAC,CAAC;EACfM,SAAS,EAAEP,aAAa;EACxBQ,eAAe,EAAE,IAAIpB,sBAAsB,CAAC;AAC9C,CAAC;AAEDQ,EAAE,CAACa,IAAI,CAAC,sCAAsC,EAAE,OAAO;EACrDV,yBAAyB,EAAEH,EAAE,CAACK,EAAE,CAAC;AACnC,CAAC,CAAC,CAAC;AAEHL,EAAE,CAACa,IAAI,CAAC,qBAAqB,EAAE,YAAY;EACzC,MAAMC,MAAM,GAAG,MAAMd,EAAE,CAACe,YAAY,CAAC,qBAAqB,CAAC;EAC3D,OAAO;IACL,GAAGD,MAAM;IACTE,yBAAyB,EAAEhB,EAAE,CAACK,EAAE,CAAC,MAAMC,gBAAgB;EACzD,CAAC;AACH,CAAC,CAAC;;AAEF;AACA,MAAMW,MAAM,GAAG1B,YAAY,CAAC;EAC1B2B,EAAE,EAAE,YAAY;EAChBC,IAAI,EAAE,aAAa;EACnBC,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE;IACVC,OAAO,EAAE;MACPC,WAAW,EAAE,UAAU;MACvBH,IAAI,EAAE;IACR;EACF,CAAC;EACDI,MAAM,EAAE;IACNC,MAAM,EAAE;MACNF,WAAW,EAAE,SAAS;MACtBG,kBAAkB,EAAE,CAAC,SAAS;IAChC,CAAC;IACDC,MAAM,EAAE;MACNJ,WAAW,EAAE,SAAS;MACtBG,kBAAkB,EAAE,CAAC,SAAS;IAChC;EACF;AACF,CAAC,CAAC;AAEF7B,QAAQ,CAAC,iDAAiD,EAAE,MAAM;EAGhE,MAAM+B,MAAM,GAAG5B,EAAE,CAACK,EAAE,CAAC,CAA0B;EAC/C,IAAIwB,SAAyB;EAC7B,IAAIC,IAAU;EAEd,SAASC,gBAAgBA,CACvB;IAAEC;EAAyD,CAAC,EAC5D;IACA,MAAMC,OAAO,GAAG/B,uBAAuB,CAAgB,CAAC;IACxD8B,YAAY,CAACE,OAAO,GAAGD,OAAO,CAACtB,SAAwB;IACvD,OAAO,IAAI;EACb;EAEA,MAAMwB,WAAW,GAAG,MAAAA,CAAA,KAAY;IAC9BN,SAAS,GAAGO,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;IACzCD,QAAQ,CAACE,IAAI,CAACC,WAAW,CAACV,SAAS,CAAC;IACpCC,IAAI,GAAGpC,UAAU,CAACmC,SAAS,CAAC;IAE5B,MAAMG,YAAY,GAAG;MAAEE,OAAO,EAAE;IAA+B,CAAC;IAEhEzC,GAAG,CAAC,MAAM;MACRqC,IAAI,CAACU,MAAM,cACTC,KAAA,CAAAJ,aAAA,CAACpC,aAAa;QAACgB,MAAM,EAAEA,MAAO;QAACW,MAAM,EAAEA;MAAO,gBAC5Ca,KAAA,CAAAJ,aAAA,CAACN,gBAAgB;QAACC,YAAY,EAAEA;MAAa,CAAE,CAClC,CACjB,CAAC;IACH,CAAC,CAAC;IAEF,MAAMvC,GAAG,CAAC,YAAY;MACpB,MAAMO,EAAE,CAAC0C,iBAAiB,CAAC,CAAC;IAC9B,CAAC,CAAC;IAEF,OAAOV,YAAY,CAACE,OAAO;EAC7B,CAAC;EAED,MAAMS,aAAa,GAAGA,CAAA,KAAM;IAC1BlD,GAAG,CAAC,MAAM;MACRqC,IAAI,CAACc,OAAO,CAAC,CAAC;IAChB,CAAC,CAAC;IACFR,QAAQ,CAACE,IAAI,CAACO,WAAW,CAAChB,SAAS,CAAC;EACtC,CAAC;EAED,MAAMiB,2BAA2B,GAAGA,CAAA,KAAM;IACxC,MAAMC,OAGJ,GAAG,EAAE;IAEP/C,EAAE,CAACgD,MAAM,CAAC7C,yBAAyB,CAAC,CAAC8C,kBAAkB,CACrD,CAACC,OAAO,EAAEC,QAAQ,EAAEC,OAAO,MAAM;MAC/BhC,IAAI,EAAE,OAAgB;MACtBgC,OAAO,EAAE,IAAIC,OAAO,CAAEC,OAAO,IAAK;QAChCP,OAAO,CAACQ,IAAI,CAAC;UACXH,OAAO,EAAEA,OAAoD;UAC7DE,OAAO,EAAEA;QAGX,CAAC,CAAC;MACJ,CAAC;IACH,CAAC,CACH,CAAC;IAED,OAAO;MACL,IAAIE,YAAYA,CAAA,EAAG;QACjB,OAAOT,OAAO,CAACU,MAAM;MACvB,CAAC;MACDC,UAAUA,CAAA,EAAG;QACXX,OAAO,CAACY,OAAO,CAAC,CAAC;UAAEP,OAAO;UAAEE;QAAQ,CAAC,KAAKA,OAAO,CAACF,OAAO,CAAC,CAAC;MAC7D,CAAC;MACDQ,WAAWA,CAAA,EAAG;QACZ,MAAMC,IAAI,GAAGd,OAAO,CAACe,KAAK,CAAC,CAAC;QAC5B,IAAID,IAAI,EAAEA,IAAI,CAACP,OAAO,CAACO,IAAI,CAACT,OAAO,CAAC;MACtC,CAAC;MACDW,cAAcA,CAACC,KAAa,EAAE;QAC5B,MAAMC,IAAI,GAAGlB,OAAO,CAACiB,KAAK,CAAC;QAC3B,IAAIC,IAAI,EAAE;UACRlB,OAAO,CAACmB,MAAM,CAACF,KAAK,EAAE,CAAC,CAAC;UACxBC,IAAI,CAACX,OAAO,CAACW,IAAI,CAACb,OAAO,CAAC;QAC5B;MACF;IACF,CAAC;EACH,CAAC;EAEDxD,UAAU,CAAC,MAAM;IACfI,EAAE,CAACmE,aAAa,CAAC,CAAC;IAClBnE,EAAE,CAACoE,aAAa,CAAC,CAAC;IAClB9D,gBAAgB,CAACM,eAAe,GAAG,IAAIpB,sBAAsB,CAAC,CAAC;EACjE,CAAC,CAAC;EAEFG,SAAS,CAAC,MAAM;IACdgD,aAAa,CAAC,CAAC;IACf3C,EAAE,CAACqE,aAAa,CAAC,CAAC;EACpB,CAAC,CAAC;EAEFtE,EAAE,CAAC,0DAA0D,EAAE,YAAY;IACzE,MAAMuE,QAAQ,GAAGxB,2BAA2B,CAAC,CAAC;IAC9C,MAAMyB,IAAI,GAAG,MAAMpC,WAAW,CAAC,CAAC;IAEhC1C,GAAG,CAAC,MAAM;MACR8E,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAS;MAAE,CAAC,CAAC;MAC3DiD,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAS;MAAE,CAAC,CAAC;IAC7D,CAAC,CAAC;IAEFxB,MAAM,CAACwE,QAAQ,CAACd,YAAY,CAAC,CAACiB,IAAI,CAAC,CAAC,CAAC;IAErC,MAAMhF,GAAG,CAAC,YAAY;MACpB6E,QAAQ,CAACZ,UAAU,CAAC,CAAC;MACrB,MAAM1D,EAAE,CAAC0C,iBAAiB,CAAC,CAAC;IAC9B,CAAC,CAAC;;IAEF;IACA5C,MAAM,CAACM,aAAa,CAAC,CAACsE,qBAAqB,CAAC,CAAC,CAAC;IAC9C5E,MAAM,CAACM,aAAa,CAAC,CAACuE,oBAAoB,CAAC,QAAQ,EAAE;MACnDH,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAS;IACxC,CAAC,CAAC;IACFxB,MAAM,CAACM,aAAa,CAAC,CAACuE,oBAAoB,CAAC,QAAQ,EAAE;MACnDH,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAS;IACxC,CAAC,CAAC;EACJ,CAAC,CAAC;EAEFvB,EAAE,CAAC,0EAA0E,EAAE,YAAY;IACzF,MAAMuE,QAAQ,GAAGxB,2BAA2B,CAAC,CAAC;IAC9C,MAAMyB,IAAI,GAAG,MAAMpC,WAAW,CAAC,CAAC;;IAEhC;IACA1C,GAAG,CAAC,MAAM;MACR8E,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAQ;MAAE,CAAC,CAAC;MAC1DiD,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAS;MAAE,CAAC,CAAC;MAC3DiD,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAQ;MAAE,CAAC,CAAC;IAC5D,CAAC,CAAC;IAEFxB,MAAM,CAACwE,QAAQ,CAACd,YAAY,CAAC,CAACiB,IAAI,CAAC,CAAC,CAAC;;IAErC;IACA;IACA,MAAMhF,GAAG,CAAC,YAAY;MACpB6E,QAAQ,CAACP,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;MAC5B,MAAM/D,EAAE,CAAC0C,iBAAiB,CAAC,CAAC;IAC9B,CAAC,CAAC;;IAEF;IACA5C,MAAM,CAACM,aAAa,CAAC,CAACsE,qBAAqB,CAAC,CAAC,CAAC;IAE9C,MAAMjF,GAAG,CAAC,YAAY;MACpB6E,QAAQ,CAACP,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;MAC5B,MAAM/D,EAAE,CAAC0C,iBAAiB,CAAC,CAAC;IAC9B,CAAC,CAAC;;IAEF;IACA5C,MAAM,CAACM,aAAa,CAAC,CAACsE,qBAAqB,CAAC,CAAC,CAAC;IAC9C5E,MAAM,CAACM,aAAa,CAAC,CAACuE,oBAAoB,CAAC,QAAQ,EAAE;MACnDH,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAQ;IACvC,CAAC,CAAC;IAEF,MAAM7B,GAAG,CAAC,YAAY;MACpB6E,QAAQ,CAACP,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;MAC5B,MAAM/D,EAAE,CAAC0C,iBAAiB,CAAC,CAAC;IAC9B,CAAC,CAAC;;IAEF;IACA5C,MAAM,CAACM,aAAa,CAAC,CAACsE,qBAAqB,CAAC,CAAC,CAAC;EAChD,CAAC,CAAC;EAEF3E,EAAE,CAAC,uDAAuD,EAAE,YAAY;IACtE,MAAMuE,QAAQ,GAAGxB,2BAA2B,CAAC,CAAC;IAC9C,MAAMyB,IAAI,GAAG,MAAMpC,WAAW,CAAC,CAAC;;IAEhC;IACA1C,GAAG,CAAC,MAAM;MACR8E,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAQ;MAAE,CAAC,CAAC;IAC5D,CAAC,CAAC;;IAEF;IACA,MAAM7B,GAAG,CAAC,YAAY;MACpB6E,QAAQ,CAACV,WAAW,CAAC,CAAC;MACtB,MAAM5D,EAAE,CAAC0C,iBAAiB,CAAC,CAAC;IAC9B,CAAC,CAAC;IAEF5C,MAAM,CAACM,aAAa,CAAC,CAACsE,qBAAqB,CAAC,CAAC,CAAC;IAC9C5E,MAAM,CAACM,aAAa,CAAC,CAACwE,wBAAwB,CAAC,QAAQ,EAAE;MACvDJ,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAQ;IACvC,CAAC,CAAC;;IAEF;IACA7B,GAAG,CAAC,MAAM;MACR8E,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAS;MAAE,CAAC,CAAC;IAC7D,CAAC,CAAC;IAEF,MAAM7B,GAAG,CAAC,YAAY;MACpB6E,QAAQ,CAACV,WAAW,CAAC,CAAC;MACtB,MAAM5D,EAAE,CAAC0C,iBAAiB,CAAC,CAAC;IAC9B,CAAC,CAAC;;IAEF;IACA5C,MAAM,CAACM,aAAa,CAAC,CAACsE,qBAAqB,CAAC,CAAC,CAAC;IAC9C5E,MAAM,CAACM,aAAa,CAAC,CAACwE,wBAAwB,CAAC,QAAQ,EAAE;MACvDJ,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAS;IACxC,CAAC,CAAC;EACJ,CAAC,CAAC;EAEFvB,EAAE,CAAC,6EAA6E,EAAE,YAAY;IAC5F;IACAC,EAAE,CAACgD,MAAM,CAAC7C,yBAAyB,CAAC,CAAC8C,kBAAkB,CACrD,CAACC,OAAO,EAAEC,QAAQ,EAAEC,OAAO,MAAM;MAC/BhC,IAAI,EAAE,aAAsB;MAC5BgC,OAAO,EAAEA;IACX,CAAC,CACH,CAAC;IAED,MAAMmB,IAAI,GAAG,MAAMpC,WAAW,CAAC,CAAC;;IAEhC;IACA1C,GAAG,CAAC,MAAM;MACR8E,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAQ;MAAE,CAAC,CAAC;MAC1DiD,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAS;MAAE,CAAC,CAAC;MAC3DiD,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAQ;MAAE,CAAC,CAAC;MAC1DiD,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAS;MAAE,CAAC,CAAC;MAC3DiD,IAAI,CAAC,QAAQ,EAAE;QAAEC,gBAAgB,EAAE;UAAElD,OAAO,EAAE;QAAQ;MAAE,CAAC,CAAC;IAC5D,CAAC,CAAC;;IAEF;IACAxB,MAAM,CAACM,aAAa,CAAC,CAACsE,qBAAqB,CAAC,CAAC,CAAC;IAC9C5E,MAAM,CAACM,aAAa,CAAC,CAACyE,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE;MACzDL,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAQ;IACvC,CAAC,CAAC;IACFxB,MAAM,CAACM,aAAa,CAAC,CAACyE,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE;MACzDL,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAS;IACxC,CAAC,CAAC;IACFxB,MAAM,CAACM,aAAa,CAAC,CAACyE,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE;MACzDL,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAQ;IACvC,CAAC,CAAC;IACFxB,MAAM,CAACM,aAAa,CAAC,CAACyE,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE;MACzDL,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAS;IACxC,CAAC,CAAC;IACFxB,MAAM,CAACM,aAAa,CAAC,CAACyE,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE;MACzDL,gBAAgB,EAAE;QAAElD,OAAO,EAAE;MAAQ;IACvC,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
package/build/esm/context.js
CHANGED
|
@@ -16,6 +16,15 @@
|
|
|
16
16
|
|
|
17
17
|
import { FoundryHostEventTarget } from "@osdk/widget.client";
|
|
18
18
|
import React, { useContext } from "react";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Emits a widget event with parameter updates to the host Foundry UI.
|
|
22
|
+
*
|
|
23
|
+
* For object set parameters, pass `ObjectSet<T>` directly.
|
|
24
|
+
* If the same event is emitted multiple times in quick succession and involves Object Set parameters, only the last call will be sent.
|
|
25
|
+
* Errors (e.g., network failures when serializing ObjectSet parameters) are not surfaced to the caller.
|
|
26
|
+
*/
|
|
27
|
+
|
|
19
28
|
export const FoundryWidgetContext = /*#__PURE__*/React.createContext({
|
|
20
29
|
emitEvent: () => {},
|
|
21
30
|
hostEventTarget: new FoundryHostEventTarget(),
|
package/build/esm/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":["FoundryHostEventTarget","React","useContext","FoundryWidgetContext","createContext","emitEvent","hostEventTarget","asyncParameterValues","parameters","state","values","useFoundryWidgetContext","_useFoundryWidgetContext","withTypes"],"sources":["context.ts"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software=\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ObjectSet } from \"@osdk/client\";\nimport type {
|
|
1
|
+
{"version":3,"file":"context.js","names":["FoundryHostEventTarget","React","useContext","FoundryWidgetContext","createContext","emitEvent","hostEventTarget","asyncParameterValues","parameters","state","values","useFoundryWidgetContext","_useFoundryWidgetContext","withTypes"],"sources":["context.ts"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software=\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ObjectSet } from \"@osdk/client\";\nimport type {\n EventId,\n EventParameterValueMap,\n ObjectType,\n WidgetMessage,\n} from \"@osdk/widget.api\";\nimport {\n type AsyncParameterValueMap,\n type AsyncValue,\n FoundryHostEventTarget,\n type ParameterConfig,\n type ParameterValueMap,\n type WidgetConfig,\n} from \"@osdk/widget.client\";\nimport React, { useContext } from \"react\";\n\nexport type AugmentedEventParameterValueMap<\n C extends WidgetConfig<C[\"parameters\"]>,\n K extends EventId<C>,\n> = {\n [P in keyof EventParameterValueMap<C, K>]: P extends keyof C[\"parameters\"]\n ? C[\"parameters\"][P] extends { type: \"objectSet\"; objectType: infer T }\n ? T extends ObjectType ? ObjectSet<T>\n : EventParameterValueMap<C, K>[P]\n : EventParameterValueMap<C, K>[P]\n : EventParameterValueMap<C, K>[P];\n};\n\ntype AugmentedEmitEventIdMap<C extends WidgetConfig<C[\"parameters\"]>> = {\n [K in EventId<C>]: {\n eventId: K;\n parameterUpdates: AugmentedEventParameterValueMap<C, K>;\n };\n};\n\ninterface AugmentedWidgetEmitEvent<C extends WidgetConfig<C[\"parameters\"]>>\n extends Omit<WidgetMessage.EmitEvent<C>, \"payload\">\n{\n payload: AugmentedEmitEventIdMap<C>[EventId<C>];\n}\n\n/**\n * Emits a widget event with parameter updates to the host Foundry UI.\n *\n * For object set parameters, pass `ObjectSet<T>` directly.\n * If the same event is emitted multiple times in quick succession and involves Object Set parameters, only the last call will be sent.\n * Errors (e.g., network failures when serializing ObjectSet parameters) are not surfaced to the caller.\n */\nexport type AugmentedEmitEvent<C extends WidgetConfig<C[\"parameters\"]>> = <\n M extends AugmentedWidgetEmitEvent<C>,\n ID extends M[\"payload\"][\"eventId\"],\n>(\n eventId: ID,\n payload: Omit<Extract<M[\"payload\"], { eventId: ID }>, \"eventId\">,\n) => void;\n\nexport interface FoundryWidgetClientContext<\n C extends WidgetConfig<C[\"parameters\"]>,\n> {\n /**\n * Emits a widget event with parameter updates to the host Foundry UI.\n *\n * - For ObjectSet parameters, pass `ObjectSet<T>` directly\n * - If the same event is emitted multiple times rapidly and involves Object Set parameters, only the last call is sent\n * - Errors are not surfaced to the caller\n */\n emitEvent: AugmentedEmitEvent<C>;\n hostEventTarget: FoundryHostEventTarget<C>;\n\n /**\n * Object where the individual parameters have their async state represented\n */\n asyncParameterValues: ExtendedAsyncParameterValueMap<C>;\n\n /**\n * Convenience object that aggregates the value of all parameters, accounting for their loading states\n */\n parameters: {\n values: Partial<ExtendedParameterValueMap<C>>;\n state: AsyncValue<ParameterValueMap<C>>[\"type\"];\n };\n}\n\nexport type ExtendedParameterValueMap<C extends WidgetConfig<C[\"parameters\"]>> =\n {\n [K in keyof C[\"parameters\"]]: K extends keyof ParameterValueMap<C>\n ? C[\"parameters\"][K] extends { type: \"objectSet\"; objectType: infer T }\n ? T extends ObjectType\n ? ParameterValueMap<C>[K] & { objectSet: ObjectSet<T> }\n : ParameterValueMap<C>[K]\n : ParameterValueMap<C>[K]\n : never;\n };\n\nexport type ExtendedAsyncParameterValueMap<\n C extends WidgetConfig<C[\"parameters\"]>,\n> = {\n [K in keyof C[\"parameters\"]]: K extends keyof AsyncParameterValueMap<C>\n ? C[\"parameters\"][K] extends { type: \"objectSet\"; objectType: infer T }\n ? T extends ObjectType ? AsyncParameterValueMap<C>[K] & {\n value: AsyncValue<\n ParameterValueMap<C>[K] & { objectSet: ObjectSet<T> }\n >;\n }\n : AsyncParameterValueMap<C>[K]\n : AsyncParameterValueMap<C>[K]\n : never;\n};\n\nexport const FoundryWidgetContext: React.Context<\n FoundryWidgetClientContext<WidgetConfig<ParameterConfig>>\n> = React.createContext<\n FoundryWidgetClientContext<WidgetConfig<ParameterConfig>>\n>({\n emitEvent: () => {},\n hostEventTarget: new FoundryHostEventTarget<WidgetConfig<ParameterConfig>>(),\n asyncParameterValues: {},\n parameters: {\n state: \"not-started\",\n values: {},\n },\n});\n\n/**\n * @returns The current FoundryWidgetClientContext, in the context of your specific parameter configuration\n */\nexport function useFoundryWidgetContext<\n C extends WidgetConfig<C[\"parameters\"]>,\n>(): FoundryWidgetClientContext<C> {\n return useContext(FoundryWidgetContext) as FoundryWidgetClientContext<C>;\n}\n\nexport namespace useFoundryWidgetContext {\n export function withTypes<\n C extends WidgetConfig<C[\"parameters\"]>,\n >(): () => FoundryWidgetClientContext<C> {\n return () => {\n return useFoundryWidgetContext<C>();\n };\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AASA,SAGEA,sBAAsB,QAIjB,qBAAqB;AAC5B,OAAOC,KAAK,IAAIC,UAAU,QAAQ,OAAO;;AA2BzC;AACA;AACA;AACA;AACA;AACA;AACA;;AA8DA,OAAO,MAAMC,oBAEZ,gBAAGF,KAAK,CAACG,aAAa,CAErB;EACAC,SAAS,EAAEA,CAAA,KAAM,CAAC,CAAC;EACnBC,eAAe,EAAE,IAAIN,sBAAsB,CAAgC,CAAC;EAC5EO,oBAAoB,EAAE,CAAC,CAAC;EACxBC,UAAU,EAAE;IACVC,KAAK,EAAE,aAAa;IACpBC,MAAM,EAAE,CAAC;EACX;AACF,CAAC,CAAC;;AAEF;AACA;AACA;AACA,OAAO,SAASC,uBAAuBA,CAAA,EAEJ;EACjC,OAAOT,UAAU,CAACC,oBAAoB,CAAC;AACzC;AAAC,WAAAS,wBAAA;EAAAA,wBAAA,CAAAC,SAAA,GAGQ,YAEkC;IACvC,OAAO,MAAM;MACX,OAAOF,uBAAuB,CAAI,CAAC;IACrC,CAAC;EACH,CAAC;AAAA,GAPcA,uBAAuB,KAAvBA,uBAAuB","ignoreList":[]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { createAndFetchTempObjectSetRid } from "@osdk/client/internal";
|
|
18
|
+
export function transformEmitEventPayload(config, eventId, payload, osdkClient) {
|
|
19
|
+
for (const paramId of Object.keys(payload.parameterUpdates)) {
|
|
20
|
+
const paramConfig = config.parameters[paramId];
|
|
21
|
+
if (paramConfig?.type === "objectSet") {
|
|
22
|
+
return {
|
|
23
|
+
type: "async",
|
|
24
|
+
payload: transformEmitEventPayloadAsync(config, eventId, payload, osdkClient)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// No object set parameters, pass through synchronously
|
|
30
|
+
return {
|
|
31
|
+
type: "passThrough",
|
|
32
|
+
payload: {
|
|
33
|
+
parameterUpdates: payload.parameterUpdates
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Transforms an augmented emit event payload by creating temporary object sets
|
|
40
|
+
* from ObjectSet instances.
|
|
41
|
+
*
|
|
42
|
+
* Multiple ObjectSet parameters are transformed in parallel for better performance.
|
|
43
|
+
*/
|
|
44
|
+
export async function transformEmitEventPayloadAsync(config, eventId, payload, osdkClient) {
|
|
45
|
+
const event = config.events[eventId];
|
|
46
|
+
if (event == null) {
|
|
47
|
+
throw new Error(`Event with ID "${eventId.toString()}" not found in widget config`);
|
|
48
|
+
}
|
|
49
|
+
const entries = Object.entries(payload.parameterUpdates);
|
|
50
|
+
const transformedEntries = await Promise.all(entries.map(async ([paramId, paramValue]) => {
|
|
51
|
+
const paramConfig = config.parameters[paramId];
|
|
52
|
+
if (paramConfig?.type === "objectSet") {
|
|
53
|
+
if (osdkClient == null) {
|
|
54
|
+
throw new Error(`Cannot emit event "${eventId.toString()}" with ObjectSet parameter "${paramId}" without an osdk client`);
|
|
55
|
+
}
|
|
56
|
+
const objectSetRid = await createAndFetchTempObjectSetRid(osdkClient, paramValue);
|
|
57
|
+
return [paramId, {
|
|
58
|
+
objectSetRid
|
|
59
|
+
}];
|
|
60
|
+
}
|
|
61
|
+
return [paramId, paramValue];
|
|
62
|
+
}));
|
|
63
|
+
return {
|
|
64
|
+
parameterUpdates: Object.fromEntries(transformedEntries)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=transformEmitEventPayload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transformEmitEventPayload.js","names":["createAndFetchTempObjectSetRid","transformEmitEventPayload","config","eventId","payload","osdkClient","paramId","Object","keys","parameterUpdates","paramConfig","parameters","type","transformEmitEventPayloadAsync","event","events","Error","toString","entries","transformedEntries","Promise","all","map","paramValue","objectSetRid","fromEntries"],"sources":["transformEmitEventPayload.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Client, ObjectSet } from \"@osdk/client\";\nimport { createAndFetchTempObjectSetRid } from \"@osdk/client/internal\";\nimport type {\n AsyncValue,\n EventId,\n EventParameterValueMap,\n ParameterValue,\n} from \"@osdk/widget.api\";\nimport type { WidgetConfig } from \"@osdk/widget.client\";\nimport type { AugmentedEventParameterValueMap } from \"../context.js\";\n\ntype ObjectSetEmitEventPayload = ParameterValue.ObjectSet[\"value\"] extends\n AsyncValue<infer T> ? T : never;\n\ntype TransformedEmitEventPayload<\n C extends WidgetConfig<C[\"parameters\"]>,\n K extends EventId<C>,\n> = {\n parameterUpdates: EventParameterValueMap<C, K>;\n};\n\ntype TransformedEmitEventPayloadResult<\n C extends WidgetConfig<C[\"parameters\"]>,\n K extends EventId<C>,\n> = {\n type: \"async\";\n payload: Promise<TransformedEmitEventPayload<C, K>>;\n} | {\n type: \"passThrough\";\n payload: TransformedEmitEventPayload<C, K>;\n};\n\nexport function transformEmitEventPayload<\n C extends WidgetConfig<C[\"parameters\"]>,\n K extends EventId<C>,\n>(\n config: C,\n eventId: K,\n payload: { parameterUpdates: AugmentedEventParameterValueMap<C, K> },\n osdkClient?: Client,\n): TransformedEmitEventPayloadResult<C, K> {\n for (const paramId of Object.keys(payload.parameterUpdates)) {\n const paramConfig = config.parameters[paramId];\n if (paramConfig?.type === \"objectSet\") {\n return {\n type: \"async\",\n payload: transformEmitEventPayloadAsync(\n config,\n eventId,\n payload,\n osdkClient,\n ),\n };\n }\n }\n\n // No object set parameters, pass through synchronously\n return {\n type: \"passThrough\",\n payload: {\n parameterUpdates: payload.parameterUpdates as EventParameterValueMap<\n C,\n K\n >,\n },\n };\n}\n\n/**\n * Transforms an augmented emit event payload by creating temporary object sets\n * from ObjectSet instances.\n *\n * Multiple ObjectSet parameters are transformed in parallel for better performance.\n */\nexport async function transformEmitEventPayloadAsync<\n C extends WidgetConfig<C[\"parameters\"]>,\n K extends EventId<C>,\n>(\n config: C,\n eventId: K,\n payload: { parameterUpdates: AugmentedEventParameterValueMap<C, K> },\n osdkClient?: Client,\n): Promise<{ parameterUpdates: EventParameterValueMap<C, K> }> {\n const event = config.events[eventId as string];\n if (event == null) {\n throw new Error(\n `Event with ID \"${eventId.toString()}\" not found in widget config`,\n );\n }\n\n const entries = Object.entries(payload.parameterUpdates);\n\n const transformedEntries = await Promise.all(\n entries.map(async ([paramId, paramValue]): Promise<[string, unknown]> => {\n const paramConfig = config.parameters[paramId];\n if (paramConfig?.type === \"objectSet\") {\n if (osdkClient == null) {\n throw new Error(\n `Cannot emit event \"${eventId.toString()}\" with ObjectSet parameter \"${paramId}\" without an osdk client`,\n );\n }\n const objectSetRid = await createAndFetchTempObjectSetRid(\n osdkClient,\n paramValue as ObjectSet,\n );\n return [paramId, { objectSetRid } satisfies ObjectSetEmitEventPayload];\n }\n return [paramId, paramValue];\n }),\n );\n\n return {\n parameterUpdates: Object.fromEntries(\n transformedEntries,\n ) as EventParameterValueMap<C, K>,\n };\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA,SAASA,8BAA8B,QAAQ,uBAAuB;AA+BtE,OAAO,SAASC,yBAAyBA,CAIvCC,MAAS,EACTC,OAAU,EACVC,OAAoE,EACpEC,UAAmB,EACsB;EACzC,KAAK,MAAMC,OAAO,IAAIC,MAAM,CAACC,IAAI,CAACJ,OAAO,CAACK,gBAAgB,CAAC,EAAE;IAC3D,MAAMC,WAAW,GAAGR,MAAM,CAACS,UAAU,CAACL,OAAO,CAAC;IAC9C,IAAII,WAAW,EAAEE,IAAI,KAAK,WAAW,EAAE;MACrC,OAAO;QACLA,IAAI,EAAE,OAAO;QACbR,OAAO,EAAES,8BAA8B,CACrCX,MAAM,EACNC,OAAO,EACPC,OAAO,EACPC,UACF;MACF,CAAC;IACH;EACF;;EAEA;EACA,OAAO;IACLO,IAAI,EAAE,aAAa;IACnBR,OAAO,EAAE;MACPK,gBAAgB,EAAEL,OAAO,CAACK;IAI5B;EACF,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeI,8BAA8BA,CAIlDX,MAAS,EACTC,OAAU,EACVC,OAAoE,EACpEC,UAAmB,EAC0C;EAC7D,MAAMS,KAAK,GAAGZ,MAAM,CAACa,MAAM,CAACZ,OAAO,CAAW;EAC9C,IAAIW,KAAK,IAAI,IAAI,EAAE;IACjB,MAAM,IAAIE,KAAK,CACb,kBAAkBb,OAAO,CAACc,QAAQ,CAAC,CAAC,8BACtC,CAAC;EACH;EAEA,MAAMC,OAAO,GAAGX,MAAM,CAACW,OAAO,CAACd,OAAO,CAACK,gBAAgB,CAAC;EAExD,MAAMU,kBAAkB,GAAG,MAAMC,OAAO,CAACC,GAAG,CAC1CH,OAAO,CAACI,GAAG,CAAC,OAAO,CAAChB,OAAO,EAAEiB,UAAU,CAAC,KAAiC;IACvE,MAAMb,WAAW,GAAGR,MAAM,CAACS,UAAU,CAACL,OAAO,CAAC;IAC9C,IAAII,WAAW,EAAEE,IAAI,KAAK,WAAW,EAAE;MACrC,IAAIP,UAAU,IAAI,IAAI,EAAE;QACtB,MAAM,IAAIW,KAAK,CACb,sBAAsBb,OAAO,CAACc,QAAQ,CAAC,CAAC,+BAA+BX,OAAO,0BAChF,CAAC;MACH;MACA,MAAMkB,YAAY,GAAG,MAAMxB,8BAA8B,CACvDK,UAAU,EACVkB,UACF,CAAC;MACD,OAAO,CAACjB,OAAO,EAAE;QAAEkB;MAAa,CAAC,CAAqC;IACxE;IACA,OAAO,CAAClB,OAAO,EAAEiB,UAAU,CAAC;EAC9B,CAAC,CACH,CAAC;EAED,OAAO;IACLd,gBAAgB,EAAEF,MAAM,CAACkB,WAAW,CAClCN,kBACF;EACF,CAAC;AACH","ignoreList":[]}
|