@colixsystems/widget-sdk 0.67.0 → 0.67.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks.js +35 -0
- package/package.json +2 -2
package/dist/hooks.js
CHANGED
|
@@ -593,6 +593,12 @@ function toDatastoreError(err) {
|
|
|
593
593
|
});
|
|
594
594
|
}
|
|
595
595
|
|
|
596
|
+
// sc-1579 — consecutive renders with a different serialized query before
|
|
597
|
+
// `useDatastoreQuery` calls the loop out. High enough that no real interaction
|
|
598
|
+
// reaches it (a settled fetch resets the count), low enough to fire instantly
|
|
599
|
+
// on a genuine loop.
|
|
600
|
+
const VOLATILE_QUERY_RENDER_LIMIT = 10;
|
|
601
|
+
|
|
596
602
|
/**
|
|
597
603
|
* Stateful datastore query hook. Returns { data, loading, error, refetch }.
|
|
598
604
|
*
|
|
@@ -682,6 +688,35 @@ export function useDatastoreQuery(table, query) {
|
|
|
682
688
|
return null;
|
|
683
689
|
}
|
|
684
690
|
})();
|
|
691
|
+
|
|
692
|
+
// sc-1579 — a query argument built from a volatile value (`Date.now()`,
|
|
693
|
+
// `new Date()`, `Math.random()`) serialises differently every render, so the
|
|
694
|
+
// effect below re-fetches forever and the widget never settles. A genuine
|
|
695
|
+
// edit (a typed filter) settles within one render because the re-render the
|
|
696
|
+
// fetch triggers reuses the same argument; a volatile one never does. That
|
|
697
|
+
// gap is the signal — no timers, no heuristics. Warned once per instance,
|
|
698
|
+
// and in production too: the Studio canvas and the widget agent's render
|
|
699
|
+
// smoke check both run production builds, which is where this must surface.
|
|
700
|
+
const volatileKeyRef = useRef({ key: queryKey, changes: 0, warned: false });
|
|
701
|
+
const keyWatch = volatileKeyRef.current;
|
|
702
|
+
if (keyWatch.key === queryKey) {
|
|
703
|
+
keyWatch.changes = 0;
|
|
704
|
+
} else {
|
|
705
|
+
keyWatch.key = queryKey;
|
|
706
|
+
keyWatch.changes += 1;
|
|
707
|
+
if (keyWatch.changes >= VOLATILE_QUERY_RENDER_LIMIT && !keyWatch.warned) {
|
|
708
|
+
keyWatch.warned = true;
|
|
709
|
+
// eslint-disable-next-line no-console
|
|
710
|
+
console.warn(
|
|
711
|
+
`useDatastoreQuery(${JSON.stringify(table)}): the query argument changed on ` +
|
|
712
|
+
`${keyWatch.changes} consecutive renders, so this widget is re-fetching in a ` +
|
|
713
|
+
"loop. Something in the query is regenerated every render — usually a date " +
|
|
714
|
+
"or random value. Compute it once outside render (or with useMemo) and pass " +
|
|
715
|
+
"the stable value in.",
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
685
720
|
useEffect(() => {
|
|
686
721
|
doFetch();
|
|
687
722
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.67.
|
|
3
|
+
"version": "0.67.1",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
],
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "node scripts/build.js",
|
|
51
|
-
"test": "node --test src/__tests__/contract.test.js src/__tests__/hooks-users.test.js src/__tests__/hooks-groups.test.js src/__tests__/hooks-schema.test.js src/__tests__/hooks-assets-by-tag.test.js src/__tests__/hooks-filestore-upload.test.js src/__tests__/hooks-filestore-file.test.js src/__tests__/hooks-mutation.test.js src/__tests__/hooks-record-permissions.test.js src/__tests__/hooks-geolocation.test.js src/__tests__/hooks-subscription.test.js src/__tests__/linter-users-scope.test.js src/__tests__/linter-comments.test.js src/__tests__/linter-image-height.test.js src/__tests__/linter-platform.test.js src/__tests__/linter-react-import.test.js src/__tests__/lucide-icon-names.test.js src/__tests__/lucideIconName.test.js src/__tests__/manifest-actions.test.js src/__tests__/widget-translations.test.js src/__tests__/devserver.test.js src/__tests__/host-externals.test.js src/__tests__/datetimepicker.test.js src/__tests__/property-schema-resolve.test.js src/__tests__/theme-components-parity.test.js"
|
|
51
|
+
"test": "node --test src/__tests__/contract.test.js src/__tests__/hooks-users.test.js src/__tests__/hooks-groups.test.js src/__tests__/hooks-schema.test.js src/__tests__/hooks-assets-by-tag.test.js src/__tests__/hooks-filestore-upload.test.js src/__tests__/hooks-filestore-file.test.js src/__tests__/hooks-mutation.test.js src/__tests__/hooks-record-permissions.test.js src/__tests__/hooks-geolocation.test.js src/__tests__/hooks-subscription.test.js src/__tests__/hooks-volatile-query-key.test.js src/__tests__/linter-users-scope.test.js src/__tests__/linter-comments.test.js src/__tests__/linter-image-height.test.js src/__tests__/linter-platform.test.js src/__tests__/linter-react-import.test.js src/__tests__/lucide-icon-names.test.js src/__tests__/lucideIconName.test.js src/__tests__/manifest-actions.test.js src/__tests__/widget-translations.test.js src/__tests__/devserver.test.js src/__tests__/host-externals.test.js src/__tests__/datetimepicker.test.js src/__tests__/property-schema-resolve.test.js src/__tests__/theme-components-parity.test.js"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=18"
|