@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.esm.js CHANGED
@@ -278,6 +278,70 @@ function mapRecords(callback, record1, record2, record3) {
278
278
 
279
279
  // src/serverQueries/common.ts
280
280
  import React2 from "react";
281
+
282
+ // src/serverQueries/makeQueryCacheKey.ts
283
+ function makeQueryCacheKey(id, params) {
284
+ return `${id}:${safeStableStringify(params)}`;
285
+ }
286
+ var shortPlasmicPrefix = "\u03C1";
287
+ function safeStableStringify(unstableValue) {
288
+ const stableValue = sortObjectsDeep(unstableValue, /* @__PURE__ */ new Map());
289
+ const visitedPaths = /* @__PURE__ */ new Map();
290
+ return JSON.stringify(stableValue, function(key, value) {
291
+ switch (typeof value) {
292
+ case "undefined":
293
+ return `${shortPlasmicPrefix}:UNDEFINED`;
294
+ case "function":
295
+ return `${shortPlasmicPrefix}:FUNCTION:${value.name}`;
296
+ case "symbol":
297
+ return `${shortPlasmicPrefix}:SYMBOL:${value.description}`;
298
+ case "bigint":
299
+ return value.toString();
300
+ case "object":
301
+ if (value !== null) {
302
+ const cyclePath = visitedPaths.get(value);
303
+ if (cyclePath) {
304
+ return `${shortPlasmicPrefix}:REF:${cyclePath}`;
305
+ }
306
+ const parentPath = visitedPaths.get(this);
307
+ const valuePath = parentPath === void 0 ? "$" : `${parentPath}.${key}`;
308
+ visitedPaths.set(value, valuePath);
309
+ }
310
+ return value;
311
+ default:
312
+ return value;
313
+ }
314
+ });
315
+ }
316
+ function sortObjectsDeep(value, visitedObjects) {
317
+ if (typeof value !== "object" || value === null) {
318
+ return value;
319
+ }
320
+ const visitedValue = visitedObjects.get(value);
321
+ if (visitedValue) {
322
+ return visitedValue;
323
+ }
324
+ if (typeof value.toJSON === "function") {
325
+ return sortObjectsDeep(value.toJSON(), visitedObjects);
326
+ }
327
+ if (Array.isArray(value)) {
328
+ const newArr = [];
329
+ visitedObjects.set(value, newArr);
330
+ value.forEach((item, key) => {
331
+ newArr[key] = sortObjectsDeep(item, visitedObjects);
332
+ });
333
+ return newArr;
334
+ } else {
335
+ const newObj = {};
336
+ visitedObjects.set(value, newObj);
337
+ Object.keys(value).sort().forEach((key) => {
338
+ newObj[key] = sortObjectsDeep(value[key], visitedObjects);
339
+ });
340
+ return newObj;
341
+ }
342
+ }
343
+
344
+ // src/serverQueries/common.ts
281
345
  function createDollarQueries(queryNames) {
282
346
  return Object.fromEntries(
283
347
  queryNames.map((queryName) => {
@@ -335,11 +399,6 @@ var StatefulQueryResult = class {
335
399
  (err) => this.rejectPromise(key, err)
336
400
  );
337
401
  }
338
- /**
339
- * Resolve is allowed if:
340
- * 1) no key / state is initial, which means we are resolving from cache
341
- * 2) key / state is loading, which means we need to check the keys match
342
- */
343
402
  resolvePromise(key, data) {
344
403
  if (this.current.key === null || this.current.key === key) {
345
404
  this.transitionState({
@@ -368,6 +427,9 @@ var StatefulQueryResult = class {
368
427
  untagPlasmicUndefinedDataErrorPromise(this.settable.promise);
369
428
  }
370
429
  }
430
+ toJSON() {
431
+ return this.current;
432
+ }
371
433
  get key() {
372
434
  return this.current.key;
373
435
  }
@@ -416,12 +478,17 @@ function safeExecResult(tryData) {
416
478
  function assertUnexpectedNodeType(x) {
417
479
  throw new Error(`Unexpected node type: ${x}`);
418
480
  }
419
- function resolveParams(params) {
481
+ function resolveParams(queryId, params) {
420
482
  return safeExec(
421
- () => ({
422
- status: "ready",
423
- resolvedParams: params()
424
- }),
483
+ () => {
484
+ const resolvedParams = params();
485
+ const cacheKey = makeQueryCacheKey(queryId, resolvedParams);
486
+ return {
487
+ status: "ready",
488
+ resolvedParams,
489
+ cacheKey
490
+ };
491
+ },
425
492
  (promise) => ({
426
493
  status: "blocked",
427
494
  promise
@@ -496,19 +563,6 @@ var SyncPromise = class {
496
563
  );
497
564
  }
498
565
  };
499
- function shallowEqualRecords(a, b) {
500
- if (Object.is(a, b)) {
501
- return true;
502
- }
503
- const aKeys = Object.keys(a);
504
- const bKeys = Object.keys(b);
505
- if (aKeys.length !== bKeys.length) {
506
- return false;
507
- }
508
- return aKeys.every(
509
- (key) => Object.prototype.hasOwnProperty.call(b, key) && Object.is(a[key], b[key])
510
- );
511
- }
512
566
  var SettablePromise = class {
513
567
  constructor() {
514
568
  __publicField(this, "promise");
@@ -526,181 +580,154 @@ var SettablePromise = class {
526
580
  this._reject(error);
527
581
  }
528
582
  };
529
- function useRenderEffect(effect, deps) {
530
- const ref = React2.useRef({ deps: void 0, cleanup: void 0 });
531
- const depsChanged = ref.current.deps === void 0 || deps.length !== ref.current.deps.length || deps.some((dep, i) => !Object.is(dep, ref.current.deps[i]));
532
- if (depsChanged) {
533
- if (ref.current.cleanup) {
534
- ref.current.cleanup();
583
+ function usePrevious(value) {
584
+ const ref = React2.useRef(void 0);
585
+ const prev = ref.current;
586
+ ref.current = value;
587
+ return prev;
588
+ }
589
+ function createInitial$State($ctx, $props, $q, stateSpecs) {
590
+ const root = {};
591
+ for (const stateSpec of stateSpecs) {
592
+ if (stateSpec.path.includes("[]")) {
593
+ continue;
535
594
  }
536
- const prevDeps = ref.current.deps;
537
- ref.current.cleanup = effect(prevDeps);
538
- ref.current.deps = deps;
539
- }
540
- React2.useEffect(() => {
541
- return () => {
542
- if (ref.current.cleanup) {
543
- ref.current.cleanup();
595
+ const parts = stateSpec.path.split(".");
596
+ const parentPath = parts.slice(0, parts.length - 1);
597
+ const leaf = parts[parts.length - 1];
598
+ let parent = root;
599
+ for (const part of parentPath) {
600
+ if (!(part in parent)) {
601
+ parent[part] = {};
544
602
  }
545
- };
546
- }, []);
547
- }
548
-
549
- // src/serverQueries/makeQueryCacheKey.ts
550
- function makeQueryCacheKey(id, params) {
551
- return `${id}:${safeStableStringify(params)}`;
552
- }
553
- var shortPlasmicPrefix = "\u03C1";
554
- function safeStableStringify(unstableValue) {
555
- const stableValue = sortObjectsDeep(unstableValue, /* @__PURE__ */ new Map());
556
- const visitedPaths = /* @__PURE__ */ new Map();
557
- return JSON.stringify(stableValue, function(key, value) {
558
- switch (typeof value) {
559
- case "undefined":
560
- return `${shortPlasmicPrefix}:UNDEFINED`;
561
- case "function":
562
- return `${shortPlasmicPrefix}:FUNCTION:${value.name}`;
563
- case "symbol":
564
- return `${shortPlasmicPrefix}:SYMBOL:${value.description}`;
565
- case "bigint":
566
- return value.toString();
567
- case "object":
568
- if (value !== null) {
569
- const cyclePath = visitedPaths.get(value);
570
- if (cyclePath) {
571
- return `${shortPlasmicPrefix}:REF:${cyclePath}`;
603
+ parent = parent[part];
604
+ }
605
+ if (stateSpec.valueProp) {
606
+ parent[leaf] = $props[stateSpec.valueProp];
607
+ } else if ("initVal" in stateSpec) {
608
+ parent[leaf] = stateSpec.initVal;
609
+ } else if (stateSpec.initFunc) {
610
+ const initFunc = stateSpec.initFunc;
611
+ let cached;
612
+ Object.defineProperty(parent, leaf, {
613
+ get: () => {
614
+ if (cached) {
615
+ return cached.value;
572
616
  }
573
- const parentPath = visitedPaths.get(this);
574
- const valuePath = parentPath === void 0 ? "$" : `${parentPath}.${key}`;
575
- visitedPaths.set(value, valuePath);
576
- }
577
- return value;
578
- default:
579
- return value;
617
+ const value = initFunc({
618
+ $ctx,
619
+ $props,
620
+ $q,
621
+ $state: root,
622
+ $refs: {},
623
+ $queries: {}
624
+ });
625
+ cached = { value };
626
+ return value;
627
+ },
628
+ enumerable: true,
629
+ configurable: true
630
+ });
580
631
  }
581
- });
582
- }
583
- function sortObjectsDeep(value, visitedObjects) {
584
- if (typeof value !== "object" || value === null) {
585
- return value;
586
- }
587
- const visitedValue = visitedObjects.get(value);
588
- if (visitedValue) {
589
- return visitedValue;
590
- }
591
- if (Array.isArray(value)) {
592
- const newArr = [];
593
- visitedObjects.set(value, newArr);
594
- value.forEach((item, key) => {
595
- newArr[key] = sortObjectsDeep(item, visitedObjects);
596
- });
597
- return newArr;
598
- } else {
599
- const newObj = {};
600
- visitedObjects.set(value, newObj);
601
- Object.keys(value).sort().forEach((key) => {
602
- newObj[key] = sortObjectsDeep(value[key], visitedObjects);
603
- });
604
- return newObj;
605
632
  }
633
+ return root;
606
634
  }
607
635
 
608
636
  // src/serverQueries/client.ts
609
637
  var GLOBAL_CACHE = /* @__PURE__ */ new Map();
610
- function usePlasmicQueries(tree, $props, $ctx, $state) {
611
- const stableProps = useShallowStableRecord($props);
612
- const stableCtx = useShallowStableRecord($ctx);
613
- const $stateRef = React3.useRef($state != null ? $state : {});
614
- $stateRef.current = $state != null ? $state : {};
638
+ function usePlasmicQueries(tree, $ctx, $props, $state) {
639
+ var _a;
640
+ const wrappedQueries = React3.useMemo(() => wrapQueries(tree.queries), [tree]);
615
641
  const $queries = React3.useMemo(
616
642
  () => createDollarQueries(Object.keys(tree.queries)),
617
643
  [tree]
618
644
  );
619
- const queries = React3.useMemo(() => {
620
- return mapRecords(
621
- (_name, q) => ({
622
- id: q.id,
623
- fn: q.fn,
624
- execParams: () => q.args({
625
- $q: $queries,
626
- $props: stableProps,
627
- $ctx: stableCtx,
628
- $state: $stateRef.current,
629
- $scopedItemVars: {}
630
- })
631
- }),
632
- tree.queries
633
- );
634
- }, [$queries, stableCtx, stableProps, tree]);
635
- const wrappedQueries = React3.useMemo(() => wrapQueries(queries), [queries]);
636
645
  const $queryStates = $queries;
646
+ if (!$state) {
647
+ $state = createInitial$State($ctx, $props, $queryStates, tree.stateSpecs);
648
+ }
637
649
  const { fallback: prefetchedCache, cache: swrCache } = usePlasmicDataConfig2();
638
- const [settledCount, setSettledCount] = React3.useState(0);
639
- React3.useEffect(() => {
640
- let cleanup = false;
641
- const resultListener = (next, prev) => {
642
- if (cleanup) {
650
+ const paramsResults = {};
651
+ const executionCtx = {
652
+ $ctx,
653
+ $props,
654
+ $q: $queryStates,
655
+ $state
656
+ };
657
+ const prevWrappedQueries = usePrevious(wrappedQueries);
658
+ let consistent = prevWrappedQueries === void 0 || Object.is(prevWrappedQueries, wrappedQueries);
659
+ mapRecords(
660
+ (queryName, $query, query) => {
661
+ if (!consistent || $query.current.state === "initial") {
643
662
  return;
644
663
  }
645
- if (prev.state === "done" || next.state === "done") {
646
- queueMicrotask(() => setSettledCount((v) => v + 1));
664
+ const paramsResult = resolveParams(
665
+ query.id,
666
+ () => query.args(executionCtx)
667
+ );
668
+ paramsResults[queryName] = paramsResult;
669
+ if (paramsResult.status === "blocked") {
670
+ consistent = false;
671
+ } else if (paramsResult.status === "error" && $query.current.key !== null) {
672
+ consistent = false;
673
+ } else if (paramsResult.status === "ready" && paramsResult.cacheKey !== $query.current.key) {
674
+ consistent = false;
647
675
  }
648
- };
676
+ },
677
+ $queryStates,
678
+ wrappedQueries
679
+ );
680
+ if (!consistent) {
649
681
  mapRecords((_queryName, $query) => {
650
- $query.addListener(resultListener);
682
+ $query.reset();
651
683
  }, $queryStates);
652
- return () => {
653
- cleanup = true;
654
- mapRecords((_queryName, $query) => {
655
- $query.removeListener(resultListener);
656
- }, $queryStates);
684
+ for (const k of Object.keys(paramsResults)) {
685
+ delete paramsResults[k];
686
+ }
687
+ }
688
+ const stopRef = React3.useRef();
689
+ (_a = stopRef.current) == null ? void 0 : _a.call(stopRef);
690
+ let stopped = false;
691
+ const stop = new Promise((resolve) => {
692
+ stopRef.current = () => {
693
+ stopped = true;
694
+ resolve();
657
695
  };
658
- }, [$queryStates]);
659
- useRenderEffect(
660
- (prevDeps) => {
661
- if (prevDeps) {
662
- const prevWrappedQueries = prevDeps[0];
663
- if (!Object.is(prevWrappedQueries, wrappedQueries)) {
664
- mapRecords((_queryName, $query) => {
665
- $query.reset();
666
- }, $queryStates);
696
+ });
697
+ React3.useEffect(() => () => {
698
+ var _a2;
699
+ return (_a2 = stopRef.current) == null ? void 0 : _a2.call(stopRef);
700
+ }, []);
701
+ const loop = () => __async(null, null, function* () {
702
+ while (true) {
703
+ initPlasmicQueriesSync(
704
+ $queryStates,
705
+ wrappedQueries,
706
+ paramsResults,
707
+ executionCtx,
708
+ prefetchedCache,
709
+ swrCache
710
+ );
711
+ const loadingQueries = mapRecordEntries((_queryName, $query) => {
712
+ if ($query.isLoading) {
713
+ return $query.getDoneResult();
714
+ } else {
715
+ return null;
667
716
  }
717
+ }, $queryStates).filter(notNil);
718
+ if (loadingQueries.length === 0) {
719
+ break;
668
720
  }
669
- let cleanup = false;
670
- const loop = () => __async(null, null, function* () {
671
- while (true) {
672
- initPlasmicQueriesSync(
673
- $queryStates,
674
- wrappedQueries,
675
- prefetchedCache,
676
- swrCache
677
- );
678
- const loadingQueries = mapRecordEntries((_queryName, $query) => {
679
- if ($query.isLoading) {
680
- return $query.getDoneResult();
681
- } else {
682
- return null;
683
- }
684
- }, $queryStates).filter(notNil);
685
- if (loadingQueries.length === 0) {
686
- break;
687
- }
688
- yield Promise.race(loadingQueries);
689
- if (cleanup) {
690
- break;
691
- }
692
- }
693
- });
694
- loop().catch(noopFn);
695
- return () => {
696
- cleanup = true;
697
- };
698
- },
699
- [wrappedQueries, $queryStates, settledCount]
700
- );
721
+ yield Promise.race([stop, ...loadingQueries]);
722
+ if (stopped) {
723
+ break;
724
+ }
725
+ }
726
+ });
727
+ loop().catch(noopFn);
701
728
  mapRecords(
702
- (_queryName, $query, query) => {
703
- usePlasmicQuery($query, query, settledCount);
729
+ (queryName, $query, query) => {
730
+ usePlasmicQuery($query, query, paramsResults[queryName]);
704
731
  },
705
732
  $queryStates,
706
733
  wrappedQueries
@@ -722,20 +749,24 @@ function wrapQueries(queries) {
722
749
  return {
723
750
  id: query.id,
724
751
  fn: wrappedFn,
725
- execParams: query.execParams
752
+ args: query.args
726
753
  };
727
754
  }, queries);
728
755
  }
729
- function initPlasmicQueriesSync($queries, queries, prefetchedCache, clientCache) {
756
+ function initPlasmicQueriesSync($queries, queries, paramsResults, executionCtx, prefetchedCache, clientCache) {
730
757
  let anySettled;
731
758
  do {
732
759
  anySettled = false;
733
760
  mapRecords(
734
- (_queryName, $query, query) => {
761
+ (queryName, $query, query) => {
735
762
  if ($query.current.state !== "initial") {
736
763
  return;
737
764
  }
738
- const paramsResult = resolveParams(query.execParams);
765
+ const paramsResult = resolveParams(
766
+ query.id,
767
+ () => query.args(executionCtx)
768
+ );
769
+ paramsResults[queryName] = paramsResult;
739
770
  if (paramsResult.status === "error") {
740
771
  $query.rejectPromise(null, paramsResult.error);
741
772
  anySettled = true;
@@ -778,11 +809,8 @@ function initPlasmicQueriesSync($queries, queries, prefetchedCache, clientCache)
778
809
  );
779
810
  } while (anySettled);
780
811
  }
781
- function usePlasmicQuery($query, query, settledCount) {
812
+ function usePlasmicQuery($query, query, paramsResult) {
782
813
  const $queryState = $query;
783
- const paramsResult = React3.useMemo(() => {
784
- return resolveParams(query.execParams);
785
- }, [query.execParams, settledCount]);
786
814
  const { key, fetcher } = React3.useMemo(() => {
787
815
  switch (paramsResult.status) {
788
816
  case "blocked":
@@ -802,11 +830,29 @@ function usePlasmicQuery($query, query, settledCount) {
802
830
  return {
803
831
  key: cacheKey,
804
832
  fetcher: () => {
805
- const promise = query.fn(...paramsResult.resolvedParams);
806
- $queryState.loadingPromise(cacheKey, promise);
807
- return promise.finally(() => {
808
- GLOBAL_CACHE.delete(cacheKey);
809
- });
833
+ const clientCachedPromise = GLOBAL_CACHE.get(cacheKey);
834
+ if (clientCachedPromise == null ? void 0 : clientCachedPromise.result) {
835
+ if (clientCachedPromise.result.state === "resolved") {
836
+ $queryState.resolvePromise(
837
+ cacheKey,
838
+ clientCachedPromise.result.value
839
+ );
840
+ } else {
841
+ $queryState.rejectPromise(
842
+ cacheKey,
843
+ clientCachedPromise.result.error
844
+ );
845
+ }
846
+ return clientCachedPromise.promise.finally(() => {
847
+ GLOBAL_CACHE.delete(cacheKey);
848
+ });
849
+ } else {
850
+ const promise = query.fn(...paramsResult.resolvedParams);
851
+ $queryState.loadingPromise(cacheKey, promise);
852
+ return promise.finally(() => {
853
+ GLOBAL_CACHE.delete(cacheKey);
854
+ });
855
+ }
810
856
  }
811
857
  };
812
858
  }
@@ -830,13 +876,6 @@ function usePlasmicQuery($query, query, settledCount) {
830
876
  }
831
877
  return result;
832
878
  }
833
- function useShallowStableRecord(value) {
834
- const ref = React3.useRef(value);
835
- if (!shallowEqualRecords(ref.current, value)) {
836
- ref.current = value;
837
- }
838
- return ref.current;
839
- }
840
879
 
841
880
  // src/serverQueries/server.ts
842
881
  var ROOT_COMPONENT_KEY_PATH = "root";
@@ -848,6 +887,8 @@ function executeQueryTree(rootNode, options, queriesByComponent) {
848
887
  const initialContext = {
849
888
  $props,
850
889
  $ctx,
890
+ // Placeholder; executeComponentNode replaces this with an initial
891
+ // $state derived from the component's own stateSpecs.
851
892
  $state: {},
852
893
  $q: {},
853
894
  $scopedItemVars: {}
@@ -905,10 +946,16 @@ function executeComponentNode(node, params) {
905
946
  componentQueries = {};
906
947
  queriesByComponent.set(componentKeyPath, componentQueries);
907
948
  }
949
+ const $state = node.stateSpecs.length > 0 ? createInitial$State(
950
+ parentContext.$ctx,
951
+ evaluatedProps,
952
+ componentQueries,
953
+ node.stateSpecs
954
+ ) : {};
908
955
  const componentContext = {
909
956
  $props: evaluatedProps,
910
957
  $ctx: parentContext.$ctx,
911
- $state: parentContext.$state,
958
+ $state,
912
959
  $q: componentQueries,
913
960
  $scopedItemVars: parentContext.$scopedItemVars
914
961
  };
@@ -919,14 +966,7 @@ function executeComponentNode(node, params) {
919
966
  }
920
967
  const $query = new StatefulQueryResult();
921
968
  componentQueries[queryName] = $query;
922
- const capturedContext = componentContext;
923
- const capturedArgsFn = query.args;
924
- const plasmicQuery = {
925
- id: query.id,
926
- fn: query.fn,
927
- execParams: () => capturedArgsFn(capturedContext)
928
- };
929
- discovered.push({ $query, query: plasmicQuery });
969
+ discovered.push({ $query, query, ctx: componentContext });
930
970
  }
931
971
  node.children.forEach((child, idx) => {
932
972
  discovered.push(
@@ -1053,7 +1093,7 @@ function executePlasmicQueries(rootNode, options) {
1053
1093
  discoveredQueries.push(...newQueries);
1054
1094
  yield Promise.all(
1055
1095
  newQueries.map(
1056
- (d) => executePlasmicQuery(d.$query, d.query).catch(() => {
1096
+ (d) => executePlasmicQuery(d.$query, d.query, d.ctx).catch(() => {
1057
1097
  })
1058
1098
  )
1059
1099
  );
@@ -1085,13 +1125,13 @@ function executePlasmicQueries(rootNode, options) {
1085
1125
  return { cache, queries };
1086
1126
  });
1087
1127
  }
1088
- function executePlasmicQuery($query, query) {
1128
+ function executePlasmicQuery($query, query, ctx) {
1089
1129
  return __async(this, null, function* () {
1090
1130
  if ($query.current.state === "loading" || $query.current.state === "done") {
1091
1131
  return $query.getDoneResult();
1092
1132
  }
1093
1133
  do {
1094
- const paramsResult = resolveParams(query.execParams);
1134
+ const paramsResult = resolveParams(query.id, () => query.args(ctx));
1095
1135
  switch (paramsResult.status) {
1096
1136
  case "blocked": {
1097
1137
  try {
@@ -1101,13 +1141,9 @@ function executePlasmicQuery($query, query) {
1101
1141
  continue;
1102
1142
  }
1103
1143
  case "ready": {
1104
- const cacheKey = makeQueryCacheKey(
1105
- query.id,
1106
- paramsResult.resolvedParams
1107
- );
1108
1144
  $query.loadingPromise(
1109
- cacheKey,
1110
- query.fn(...paramsResult.resolvedParams)
1145
+ paramsResult.cacheKey,
1146
+ Promise.resolve(query.fn(...paramsResult.resolvedParams))
1111
1147
  );
1112
1148
  return $query.getDoneResult();
1113
1149
  }