@plasmicapp/data-sources 1.0.5 → 1.0.7

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/index.js CHANGED
@@ -320,6 +320,70 @@ function mapRecords(callback, record1, record2, record3) {
320
320
 
321
321
  // src/serverQueries/common.ts
322
322
  var import_react2 = __toESM(require("react"));
323
+
324
+ // src/serverQueries/makeQueryCacheKey.ts
325
+ function makeQueryCacheKey(id, params) {
326
+ return `${id}:${safeStableStringify(params)}`;
327
+ }
328
+ var shortPlasmicPrefix = "\u03C1";
329
+ function safeStableStringify(unstableValue) {
330
+ const stableValue = sortObjectsDeep(unstableValue, /* @__PURE__ */ new Map());
331
+ const visitedPaths = /* @__PURE__ */ new Map();
332
+ return JSON.stringify(stableValue, function(key, value) {
333
+ switch (typeof value) {
334
+ case "undefined":
335
+ return `${shortPlasmicPrefix}:UNDEFINED`;
336
+ case "function":
337
+ return `${shortPlasmicPrefix}:FUNCTION:${value.name}`;
338
+ case "symbol":
339
+ return `${shortPlasmicPrefix}:SYMBOL:${value.description}`;
340
+ case "bigint":
341
+ return value.toString();
342
+ case "object":
343
+ if (value !== null) {
344
+ const cyclePath = visitedPaths.get(value);
345
+ if (cyclePath) {
346
+ return `${shortPlasmicPrefix}:REF:${cyclePath}`;
347
+ }
348
+ const parentPath = visitedPaths.get(this);
349
+ const valuePath = parentPath === void 0 ? "$" : `${parentPath}.${key}`;
350
+ visitedPaths.set(value, valuePath);
351
+ }
352
+ return value;
353
+ default:
354
+ return value;
355
+ }
356
+ });
357
+ }
358
+ function sortObjectsDeep(value, visitedObjects) {
359
+ if (typeof value !== "object" || value === null) {
360
+ return value;
361
+ }
362
+ const visitedValue = visitedObjects.get(value);
363
+ if (visitedValue) {
364
+ return visitedValue;
365
+ }
366
+ if (typeof value.toJSON === "function") {
367
+ return sortObjectsDeep(value.toJSON(), visitedObjects);
368
+ }
369
+ if (Array.isArray(value)) {
370
+ const newArr = [];
371
+ visitedObjects.set(value, newArr);
372
+ value.forEach((item, key) => {
373
+ newArr[key] = sortObjectsDeep(item, visitedObjects);
374
+ });
375
+ return newArr;
376
+ } else {
377
+ const newObj = {};
378
+ visitedObjects.set(value, newObj);
379
+ Object.keys(value).sort().forEach((key) => {
380
+ newObj[key] = sortObjectsDeep(value[key], visitedObjects);
381
+ });
382
+ return newObj;
383
+ }
384
+ }
385
+
386
+ // src/serverQueries/common.ts
323
387
  function createDollarQueries(queryNames) {
324
388
  return Object.fromEntries(
325
389
  queryNames.map((queryName) => {
@@ -377,11 +441,6 @@ var StatefulQueryResult = class {
377
441
  (err) => this.rejectPromise(key, err)
378
442
  );
379
443
  }
380
- /**
381
- * Resolve is allowed if:
382
- * 1) no key / state is initial, which means we are resolving from cache
383
- * 2) key / state is loading, which means we need to check the keys match
384
- */
385
444
  resolvePromise(key, data) {
386
445
  if (this.current.key === null || this.current.key === key) {
387
446
  this.transitionState({
@@ -410,6 +469,9 @@ var StatefulQueryResult = class {
410
469
  untagPlasmicUndefinedDataErrorPromise(this.settable.promise);
411
470
  }
412
471
  }
472
+ toJSON() {
473
+ return this.current;
474
+ }
413
475
  get key() {
414
476
  return this.current.key;
415
477
  }
@@ -458,12 +520,17 @@ function safeExecResult(tryData) {
458
520
  function assertUnexpectedNodeType(x) {
459
521
  throw new Error(`Unexpected node type: ${x}`);
460
522
  }
461
- function resolveParams(params) {
523
+ function resolveParams(queryId, params) {
462
524
  return safeExec(
463
- () => ({
464
- status: "ready",
465
- resolvedParams: params()
466
- }),
525
+ () => {
526
+ const resolvedParams = params();
527
+ const cacheKey = makeQueryCacheKey(queryId, resolvedParams);
528
+ return {
529
+ status: "ready",
530
+ resolvedParams,
531
+ cacheKey
532
+ };
533
+ },
467
534
  (promise) => ({
468
535
  status: "blocked",
469
536
  promise
@@ -538,19 +605,6 @@ var SyncPromise = class {
538
605
  );
539
606
  }
540
607
  };
541
- function shallowEqualRecords(a, b) {
542
- if (Object.is(a, b)) {
543
- return true;
544
- }
545
- const aKeys = Object.keys(a);
546
- const bKeys = Object.keys(b);
547
- if (aKeys.length !== bKeys.length) {
548
- return false;
549
- }
550
- return aKeys.every(
551
- (key) => Object.prototype.hasOwnProperty.call(b, key) && Object.is(a[key], b[key])
552
- );
553
- }
554
608
  var SettablePromise = class {
555
609
  constructor() {
556
610
  __publicField(this, "promise");
@@ -568,181 +622,154 @@ var SettablePromise = class {
568
622
  this._reject(error);
569
623
  }
570
624
  };
571
- function useRenderEffect(effect, deps) {
572
- const ref = import_react2.default.useRef({ deps: void 0, cleanup: void 0 });
573
- const depsChanged = ref.current.deps === void 0 || deps.length !== ref.current.deps.length || deps.some((dep, i) => !Object.is(dep, ref.current.deps[i]));
574
- if (depsChanged) {
575
- if (ref.current.cleanup) {
576
- ref.current.cleanup();
625
+ function usePrevious(value) {
626
+ const ref = import_react2.default.useRef(void 0);
627
+ const prev = ref.current;
628
+ ref.current = value;
629
+ return prev;
630
+ }
631
+ function createInitial$State($ctx, $props, $q, stateSpecs) {
632
+ const root = {};
633
+ for (const stateSpec of stateSpecs) {
634
+ if (stateSpec.path.includes("[]")) {
635
+ continue;
577
636
  }
578
- const prevDeps = ref.current.deps;
579
- ref.current.cleanup = effect(prevDeps);
580
- ref.current.deps = deps;
581
- }
582
- import_react2.default.useEffect(() => {
583
- return () => {
584
- if (ref.current.cleanup) {
585
- ref.current.cleanup();
637
+ const parts = stateSpec.path.split(".");
638
+ const parentPath = parts.slice(0, parts.length - 1);
639
+ const leaf = parts[parts.length - 1];
640
+ let parent = root;
641
+ for (const part of parentPath) {
642
+ if (!(part in parent)) {
643
+ parent[part] = {};
586
644
  }
587
- };
588
- }, []);
589
- }
590
-
591
- // src/serverQueries/makeQueryCacheKey.ts
592
- function makeQueryCacheKey(id, params) {
593
- return `${id}:${safeStableStringify(params)}`;
594
- }
595
- var shortPlasmicPrefix = "\u03C1";
596
- function safeStableStringify(unstableValue) {
597
- const stableValue = sortObjectsDeep(unstableValue, /* @__PURE__ */ new Map());
598
- const visitedPaths = /* @__PURE__ */ new Map();
599
- return JSON.stringify(stableValue, function(key, value) {
600
- switch (typeof value) {
601
- case "undefined":
602
- return `${shortPlasmicPrefix}:UNDEFINED`;
603
- case "function":
604
- return `${shortPlasmicPrefix}:FUNCTION:${value.name}`;
605
- case "symbol":
606
- return `${shortPlasmicPrefix}:SYMBOL:${value.description}`;
607
- case "bigint":
608
- return value.toString();
609
- case "object":
610
- if (value !== null) {
611
- const cyclePath = visitedPaths.get(value);
612
- if (cyclePath) {
613
- return `${shortPlasmicPrefix}:REF:${cyclePath}`;
645
+ parent = parent[part];
646
+ }
647
+ if (stateSpec.valueProp) {
648
+ parent[leaf] = $props[stateSpec.valueProp];
649
+ } else if ("initVal" in stateSpec) {
650
+ parent[leaf] = stateSpec.initVal;
651
+ } else if (stateSpec.initFunc) {
652
+ const initFunc = stateSpec.initFunc;
653
+ let cached;
654
+ Object.defineProperty(parent, leaf, {
655
+ get: () => {
656
+ if (cached) {
657
+ return cached.value;
614
658
  }
615
- const parentPath = visitedPaths.get(this);
616
- const valuePath = parentPath === void 0 ? "$" : `${parentPath}.${key}`;
617
- visitedPaths.set(value, valuePath);
618
- }
619
- return value;
620
- default:
621
- return value;
659
+ const value = initFunc({
660
+ $ctx,
661
+ $props,
662
+ $q,
663
+ $state: root,
664
+ $refs: {},
665
+ $queries: {}
666
+ });
667
+ cached = { value };
668
+ return value;
669
+ },
670
+ enumerable: true,
671
+ configurable: true
672
+ });
622
673
  }
623
- });
624
- }
625
- function sortObjectsDeep(value, visitedObjects) {
626
- if (typeof value !== "object" || value === null) {
627
- return value;
628
- }
629
- const visitedValue = visitedObjects.get(value);
630
- if (visitedValue) {
631
- return visitedValue;
632
- }
633
- if (Array.isArray(value)) {
634
- const newArr = [];
635
- visitedObjects.set(value, newArr);
636
- value.forEach((item, key) => {
637
- newArr[key] = sortObjectsDeep(item, visitedObjects);
638
- });
639
- return newArr;
640
- } else {
641
- const newObj = {};
642
- visitedObjects.set(value, newObj);
643
- Object.keys(value).sort().forEach((key) => {
644
- newObj[key] = sortObjectsDeep(value[key], visitedObjects);
645
- });
646
- return newObj;
647
674
  }
675
+ return root;
648
676
  }
649
677
 
650
678
  // src/serverQueries/client.ts
651
679
  var GLOBAL_CACHE = /* @__PURE__ */ new Map();
652
- function usePlasmicQueries(tree, $props, $ctx, $state) {
653
- const stableProps = useShallowStableRecord($props);
654
- const stableCtx = useShallowStableRecord($ctx);
655
- const $stateRef = React3.useRef($state != null ? $state : {});
656
- $stateRef.current = $state != null ? $state : {};
680
+ function usePlasmicQueries(tree, $ctx, $props, $state) {
681
+ var _a;
682
+ const wrappedQueries = React3.useMemo(() => wrapQueries(tree.queries), [tree]);
657
683
  const $queries = React3.useMemo(
658
684
  () => createDollarQueries(Object.keys(tree.queries)),
659
685
  [tree]
660
686
  );
661
- const queries = React3.useMemo(() => {
662
- return mapRecords(
663
- (_name, q) => ({
664
- id: q.id,
665
- fn: q.fn,
666
- execParams: () => q.args({
667
- $q: $queries,
668
- $props: stableProps,
669
- $ctx: stableCtx,
670
- $state: $stateRef.current,
671
- $scopedItemVars: {}
672
- })
673
- }),
674
- tree.queries
675
- );
676
- }, [$queries, stableCtx, stableProps, tree]);
677
- const wrappedQueries = React3.useMemo(() => wrapQueries(queries), [queries]);
678
687
  const $queryStates = $queries;
688
+ if (!$state) {
689
+ $state = createInitial$State($ctx, $props, $queryStates, tree.stateSpecs);
690
+ }
679
691
  const { fallback: prefetchedCache, cache: swrCache } = (0, import_query2.usePlasmicDataConfig)();
680
- const [settledCount, setSettledCount] = React3.useState(0);
681
- React3.useEffect(() => {
682
- let cleanup = false;
683
- const resultListener = (next, prev) => {
684
- if (cleanup) {
692
+ const paramsResults = {};
693
+ const executionCtx = {
694
+ $ctx,
695
+ $props,
696
+ $q: $queryStates,
697
+ $state
698
+ };
699
+ const prevWrappedQueries = usePrevious(wrappedQueries);
700
+ let consistent = prevWrappedQueries === void 0 || Object.is(prevWrappedQueries, wrappedQueries);
701
+ mapRecords(
702
+ (queryName, $query, query) => {
703
+ if (!consistent || $query.current.state === "initial") {
685
704
  return;
686
705
  }
687
- if (prev.state === "done" || next.state === "done") {
688
- queueMicrotask(() => setSettledCount((v) => v + 1));
706
+ const paramsResult = resolveParams(
707
+ query.id,
708
+ () => query.args(executionCtx)
709
+ );
710
+ paramsResults[queryName] = paramsResult;
711
+ if (paramsResult.status === "blocked") {
712
+ consistent = false;
713
+ } else if (paramsResult.status === "error" && $query.current.key !== null) {
714
+ consistent = false;
715
+ } else if (paramsResult.status === "ready" && paramsResult.cacheKey !== $query.current.key) {
716
+ consistent = false;
689
717
  }
690
- };
718
+ },
719
+ $queryStates,
720
+ wrappedQueries
721
+ );
722
+ if (!consistent) {
691
723
  mapRecords((_queryName, $query) => {
692
- $query.addListener(resultListener);
724
+ $query.reset();
693
725
  }, $queryStates);
694
- return () => {
695
- cleanup = true;
696
- mapRecords((_queryName, $query) => {
697
- $query.removeListener(resultListener);
698
- }, $queryStates);
726
+ for (const k of Object.keys(paramsResults)) {
727
+ delete paramsResults[k];
728
+ }
729
+ }
730
+ const stopRef = React3.useRef();
731
+ (_a = stopRef.current) == null ? void 0 : _a.call(stopRef);
732
+ let stopped = false;
733
+ const stop = new Promise((resolve) => {
734
+ stopRef.current = () => {
735
+ stopped = true;
736
+ resolve();
699
737
  };
700
- }, [$queryStates]);
701
- useRenderEffect(
702
- (prevDeps) => {
703
- if (prevDeps) {
704
- const prevWrappedQueries = prevDeps[0];
705
- if (!Object.is(prevWrappedQueries, wrappedQueries)) {
706
- mapRecords((_queryName, $query) => {
707
- $query.reset();
708
- }, $queryStates);
738
+ });
739
+ React3.useEffect(() => () => {
740
+ var _a2;
741
+ return (_a2 = stopRef.current) == null ? void 0 : _a2.call(stopRef);
742
+ }, []);
743
+ const loop = () => __async(null, null, function* () {
744
+ while (true) {
745
+ initPlasmicQueriesSync(
746
+ $queryStates,
747
+ wrappedQueries,
748
+ paramsResults,
749
+ executionCtx,
750
+ prefetchedCache,
751
+ swrCache
752
+ );
753
+ const loadingQueries = mapRecordEntries((_queryName, $query) => {
754
+ if ($query.isLoading) {
755
+ return $query.getDoneResult();
756
+ } else {
757
+ return null;
709
758
  }
759
+ }, $queryStates).filter(notNil);
760
+ if (loadingQueries.length === 0) {
761
+ break;
710
762
  }
711
- let cleanup = false;
712
- const loop = () => __async(null, null, function* () {
713
- while (true) {
714
- initPlasmicQueriesSync(
715
- $queryStates,
716
- wrappedQueries,
717
- prefetchedCache,
718
- swrCache
719
- );
720
- const loadingQueries = mapRecordEntries((_queryName, $query) => {
721
- if ($query.isLoading) {
722
- return $query.getDoneResult();
723
- } else {
724
- return null;
725
- }
726
- }, $queryStates).filter(notNil);
727
- if (loadingQueries.length === 0) {
728
- break;
729
- }
730
- yield Promise.race(loadingQueries);
731
- if (cleanup) {
732
- break;
733
- }
734
- }
735
- });
736
- loop().catch(noopFn);
737
- return () => {
738
- cleanup = true;
739
- };
740
- },
741
- [wrappedQueries, $queryStates, settledCount]
742
- );
763
+ yield Promise.race([stop, ...loadingQueries]);
764
+ if (stopped) {
765
+ break;
766
+ }
767
+ }
768
+ });
769
+ loop().catch(noopFn);
743
770
  mapRecords(
744
- (_queryName, $query, query) => {
745
- usePlasmicQuery($query, query, settledCount);
771
+ (queryName, $query, query) => {
772
+ usePlasmicQuery($query, query, paramsResults[queryName]);
746
773
  },
747
774
  $queryStates,
748
775
  wrappedQueries
@@ -764,20 +791,24 @@ function wrapQueries(queries) {
764
791
  return {
765
792
  id: query.id,
766
793
  fn: wrappedFn,
767
- execParams: query.execParams
794
+ args: query.args
768
795
  };
769
796
  }, queries);
770
797
  }
771
- function initPlasmicQueriesSync($queries, queries, prefetchedCache, clientCache) {
798
+ function initPlasmicQueriesSync($queries, queries, paramsResults, executionCtx, prefetchedCache, clientCache) {
772
799
  let anySettled;
773
800
  do {
774
801
  anySettled = false;
775
802
  mapRecords(
776
- (_queryName, $query, query) => {
803
+ (queryName, $query, query) => {
777
804
  if ($query.current.state !== "initial") {
778
805
  return;
779
806
  }
780
- const paramsResult = resolveParams(query.execParams);
807
+ const paramsResult = resolveParams(
808
+ query.id,
809
+ () => query.args(executionCtx)
810
+ );
811
+ paramsResults[queryName] = paramsResult;
781
812
  if (paramsResult.status === "error") {
782
813
  $query.rejectPromise(null, paramsResult.error);
783
814
  anySettled = true;
@@ -820,11 +851,8 @@ function initPlasmicQueriesSync($queries, queries, prefetchedCache, clientCache)
820
851
  );
821
852
  } while (anySettled);
822
853
  }
823
- function usePlasmicQuery($query, query, settledCount) {
854
+ function usePlasmicQuery($query, query, paramsResult) {
824
855
  const $queryState = $query;
825
- const paramsResult = React3.useMemo(() => {
826
- return resolveParams(query.execParams);
827
- }, [query.execParams, settledCount]);
828
856
  const { key, fetcher } = React3.useMemo(() => {
829
857
  switch (paramsResult.status) {
830
858
  case "blocked":
@@ -844,11 +872,29 @@ function usePlasmicQuery($query, query, settledCount) {
844
872
  return {
845
873
  key: cacheKey,
846
874
  fetcher: () => {
847
- const promise = query.fn(...paramsResult.resolvedParams);
848
- $queryState.loadingPromise(cacheKey, promise);
849
- return promise.finally(() => {
850
- GLOBAL_CACHE.delete(cacheKey);
851
- });
875
+ const clientCachedPromise = GLOBAL_CACHE.get(cacheKey);
876
+ if (clientCachedPromise == null ? void 0 : clientCachedPromise.result) {
877
+ if (clientCachedPromise.result.state === "resolved") {
878
+ $queryState.resolvePromise(
879
+ cacheKey,
880
+ clientCachedPromise.result.value
881
+ );
882
+ } else {
883
+ $queryState.rejectPromise(
884
+ cacheKey,
885
+ clientCachedPromise.result.error
886
+ );
887
+ }
888
+ return clientCachedPromise.promise.finally(() => {
889
+ GLOBAL_CACHE.delete(cacheKey);
890
+ });
891
+ } else {
892
+ const promise = query.fn(...paramsResult.resolvedParams);
893
+ $queryState.loadingPromise(cacheKey, promise);
894
+ return promise.finally(() => {
895
+ GLOBAL_CACHE.delete(cacheKey);
896
+ });
897
+ }
852
898
  }
853
899
  };
854
900
  }
@@ -872,13 +918,6 @@ function usePlasmicQuery($query, query, settledCount) {
872
918
  }
873
919
  return result;
874
920
  }
875
- function useShallowStableRecord(value) {
876
- const ref = React3.useRef(value);
877
- if (!shallowEqualRecords(ref.current, value)) {
878
- ref.current = value;
879
- }
880
- return ref.current;
881
- }
882
921
 
883
922
  // src/serverQueries/server.ts
884
923
  var ROOT_COMPONENT_KEY_PATH = "root";
@@ -890,6 +929,8 @@ function executeQueryTree(rootNode, options, queriesByComponent) {
890
929
  const initialContext = {
891
930
  $props,
892
931
  $ctx,
932
+ // Placeholder; executeComponentNode replaces this with an initial
933
+ // $state derived from the component's own stateSpecs.
893
934
  $state: {},
894
935
  $q: {},
895
936
  $scopedItemVars: {}
@@ -947,10 +988,16 @@ function executeComponentNode(node, params) {
947
988
  componentQueries = {};
948
989
  queriesByComponent.set(componentKeyPath, componentQueries);
949
990
  }
991
+ const $state = node.stateSpecs.length > 0 ? createInitial$State(
992
+ parentContext.$ctx,
993
+ evaluatedProps,
994
+ componentQueries,
995
+ node.stateSpecs
996
+ ) : {};
950
997
  const componentContext = {
951
998
  $props: evaluatedProps,
952
999
  $ctx: parentContext.$ctx,
953
- $state: parentContext.$state,
1000
+ $state,
954
1001
  $q: componentQueries,
955
1002
  $scopedItemVars: parentContext.$scopedItemVars
956
1003
  };
@@ -961,14 +1008,7 @@ function executeComponentNode(node, params) {
961
1008
  }
962
1009
  const $query = new StatefulQueryResult();
963
1010
  componentQueries[queryName] = $query;
964
- const capturedContext = componentContext;
965
- const capturedArgsFn = query.args;
966
- const plasmicQuery = {
967
- id: query.id,
968
- fn: query.fn,
969
- execParams: () => capturedArgsFn(capturedContext)
970
- };
971
- discovered.push({ $query, query: plasmicQuery });
1011
+ discovered.push({ $query, query, ctx: componentContext });
972
1012
  }
973
1013
  node.children.forEach((child, idx) => {
974
1014
  discovered.push(
@@ -1095,7 +1135,7 @@ function executePlasmicQueries(rootNode, options) {
1095
1135
  discoveredQueries.push(...newQueries);
1096
1136
  yield Promise.all(
1097
1137
  newQueries.map(
1098
- (d) => executePlasmicQuery(d.$query, d.query).catch(() => {
1138
+ (d) => executePlasmicQuery(d.$query, d.query, d.ctx).catch(() => {
1099
1139
  })
1100
1140
  )
1101
1141
  );
@@ -1127,13 +1167,13 @@ function executePlasmicQueries(rootNode, options) {
1127
1167
  return { cache, queries };
1128
1168
  });
1129
1169
  }
1130
- function executePlasmicQuery($query, query) {
1170
+ function executePlasmicQuery($query, query, ctx) {
1131
1171
  return __async(this, null, function* () {
1132
1172
  if ($query.current.state === "loading" || $query.current.state === "done") {
1133
1173
  return $query.getDoneResult();
1134
1174
  }
1135
1175
  do {
1136
- const paramsResult = resolveParams(query.execParams);
1176
+ const paramsResult = resolveParams(query.id, () => query.args(ctx));
1137
1177
  switch (paramsResult.status) {
1138
1178
  case "blocked": {
1139
1179
  try {
@@ -1143,13 +1183,9 @@ function executePlasmicQuery($query, query) {
1143
1183
  continue;
1144
1184
  }
1145
1185
  case "ready": {
1146
- const cacheKey = makeQueryCacheKey(
1147
- query.id,
1148
- paramsResult.resolvedParams
1149
- );
1150
1186
  $query.loadingPromise(
1151
- cacheKey,
1152
- query.fn(...paramsResult.resolvedParams)
1187
+ paramsResult.cacheKey,
1188
+ Promise.resolve(query.fn(...paramsResult.resolvedParams))
1153
1189
  );
1154
1190
  return $query.getDoneResult();
1155
1191
  }