@plitzi/sdk-elements 0.35.10 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,60 @@
1
1
  # @plitzi/sdk-elements
2
2
 
3
+ ## 0.36.0
4
+
5
+ ### Minor Changes
6
+
7
+ - - **An `apiContainer` can keep its browser requests in a query cache, the way react-query does.** Moving between
8
+ sections or pages used to ask the API again every time a provider was shown: a provider in a hidden section is
9
+ mounted but disabled, so showing it fired a fresh request, and a page navigation remounted it and did the same.
10
+ With the new `cache: true` an answer is kept for `staleTime` seconds (30 by default) and shared by every cached
11
+ provider asking the same thing — same method, URL, credentials and headers, the token included, so two visitors
12
+ never share one. Past its time the answer is still drawn at once and a fresh one is fetched behind it; an answer
13
+ nobody shows is forgotten after `gcTime` seconds (300 by default). A refused request (`4xx`/`5xx`) is shown but
14
+ never kept. **The cache is off unless an element asks for it**: an uncached provider behaves as before, asking on
15
+ every mount and sharing nothing.
16
+
17
+ The cache is `@plitzi/sdk-shared/queries` (`queryCache`, `useQuery`, `invalidateQueries`,
18
+ `invalidateQueriesForWrite`), a nexus store written with the per-path `ttl` of `@plitzi/nexus` 1.2.0, which every
19
+ consumer now requires. It reacts to the store's own freshness events, so anything that expires a query's path
20
+ makes the providers on screen ask again.
21
+
22
+ An answer stops counting as current before its time when the element's `performQuery` runs (it always asks
23
+ again), when a flow runs the new global `invalidateQueries` step (source `queries`: `elements`, api container ids
24
+ — a container's requests are tagged with its own id — and/or a `url` prefix), and after a write. Both write steps
25
+ gained `invalidateQueries` / `invalidateElements`: a `webHook` sent with anything but `GET`/`HEAD` refreshes the
26
+ requests to its own site by default, a completed `runServerAction` refreshes all of them by default, and either
27
+ can name containers instead or refresh nothing. A `writeRecord` refreshes all. Providers on screen ask again at
28
+ once; the rest when they are next shown. A sign-in, sign-out or change of account drops everything held. Server-driven
29
+ providers and RSC are untouched.
30
+
31
+ - **A `webHook` that reads can be cached** (`cache`, `staleTime`), in the same cache and under the same key as an api
32
+ container asking the same thing. Its declaration now lives beside it (`utility/webHookSpec`) and the authoring
33
+ catalog gathers it instead of keeping a copy. A `HEAD` is no longer sent with a body, which `fetch` refused.
34
+
35
+ - **Step params can pick several elements.** A new param type, `elementIds` (with an `elementType` filter), is drawn
36
+ in the flow editor as a picker: the matching elements of the space to add, and the picked ones as chips to remove —
37
+ an id no element answers to any more is kept and flagged. The value is a list of ids, so nobody types a
38
+ comma-separated list; `invalidateQueries.elements` and the write steps' `invalidateElements` use it, and the MCP
39
+ catalog says which element type each such param takes.
40
+
41
+ - The dev-tools' Store tab lists the paths a store holds with a TTL — how long ago each was written, what is left
42
+ of it, and a button to expire one or all of them. The query cache appears there as "Queries".
43
+
44
+ - `useApi` no longer takes `params`: nothing passed them, and a GET cannot carry a body anyway. A mock now answers
45
+ synchronously, without a loading frame, and a provider whose URL has not resolved asks for nothing.
46
+
47
+ ### Patch Changes
48
+
49
+ - Updated dependencies
50
+ - @plitzi/sdk-auth@0.36.0
51
+ - @plitzi/sdk-dev-tools@0.36.0
52
+ - @plitzi/sdk-event-bridge@0.36.0
53
+ - @plitzi/sdk-interactions@0.36.0
54
+ - @plitzi/sdk-navigation@0.36.0
55
+ - @plitzi/sdk-schema@0.36.0
56
+ - @plitzi/sdk-shared@0.36.0
57
+
3
58
  ## 0.35.10
4
59
 
5
60
  ### Patch Changes
@@ -53,6 +53,9 @@ export declare const elementDeclarations: {
53
53
  readonly pagination: "none";
54
54
  readonly pageParam: "page";
55
55
  readonly renderWhileLoading: false;
56
+ readonly cache: false;
57
+ readonly staleTime: 30;
58
+ readonly gcTime: 300;
56
59
  };
57
60
  readonly definition: {
58
61
  readonly label: "Api Container";
@@ -48,8 +48,20 @@ export type ApiContainerProps = {
48
48
  pageParam?: string;
49
49
  /** Renders children while the first client-side request is still in flight, so a loading state can be bound. */
50
50
  renderWhileLoading?: boolean;
51
+ /**
52
+ * Keep a browser request's answer in the page's query cache, shared with every provider asking the same thing.
53
+ * Off by default: an author opts in knowing the page may show an answer up to `staleTime` old.
54
+ */
55
+ cache?: boolean;
56
+ /**
57
+ * With `cache`: seconds an answer is served without asking again. A stale answer is still shown while the new one
58
+ * is fetched; `0` asks on every mount. A text field in the builder, hence the string.
59
+ */
60
+ staleTime?: number | string;
61
+ /** With `cache`: seconds an answer nobody renders is kept, so coming back within it paints at once. */
62
+ gcTime?: number | string;
51
63
  };
52
- declare const ApiContainer: ({ ref, className, children, query, method, accessToken, when, headers, mockData, subType, credentials, singleRecord, pagination, pageParam, renderWhileLoading }: ApiContainerProps) => import("react").JSX.Element;
64
+ declare const ApiContainer: ({ ref, className, children, query, method, accessToken, when, headers, mockData, subType, credentials, singleRecord, pagination, pageParam, renderWhileLoading, cache, staleTime, gcTime }: ApiContainerProps) => import("react").JSX.Element;
53
65
  declare const _default: {
54
66
  (props: import('../../../Element/hocs/withElement').WithElementProps<ApiContainerProps>): import("react").JSX.Element;
55
67
  displayName: string;
@@ -7,94 +7,98 @@ import te from "./hooks/useApi.mjs";
7
7
  import ne from "./hooks/useProviderPagination.mjs";
8
8
  import re from "./hooks/useProviderWrite.mjs";
9
9
  import { use as ie, useCallback as i, useEffect as ae, useMemo as a } from "react";
10
- import o from "@plitzi/sdk-shared/hooks/usePlitziServiceContext";
11
- import { useSdkStore as oe } from "@plitzi/sdk-shared/store";
12
- import { StoreProvider as se } from "@plitzi/nexus/react";
13
- import { emptyObject as s, getPathsFromObeject as ce } from "@plitzi/sdk-shared/helpers/utils";
14
- import { jsx as c } from "react/jsx-runtime";
15
- import { currentRscLocation as le } from "@plitzi/sdk-shared/server/rsc/refreshRsc";
10
+ import oe from "@plitzi/sdk-shared/hooks/usePlitziServiceContext";
11
+ import { useSdkStore as se } from "@plitzi/sdk-shared/store";
12
+ import { StoreProvider as ce } from "@plitzi/nexus/react";
13
+ import { emptyObject as o, getPathsFromObeject as le } from "@plitzi/sdk-shared/helpers/utils";
14
+ import { jsx as s } from "react/jsx-runtime";
15
+ import { currentRscLocation as c } from "@plitzi/sdk-shared/server/rsc/refreshRsc";
16
16
  import l from "clsx";
17
17
  import u from "@plitzi/sdk-shared/dataSource/helpers/getSourceName";
18
18
  import d from "@plitzi/sdk-shared/dataSource/hooks/useRegisterSource";
19
19
  import { QueryBuilderEvaluator as ue } from "@plitzi/plitzi-ui/QueryBuilder";
20
20
  //#region src/elements/provider/ApiContainer/ApiContainer.tsx
21
- var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "get", accessToken: g = "", when: _ = s, headers: v = s, mockData: y = "{}", subType: de = "", credentials: fe = "same-origin", singleRecord: b = !1, pagination: pe = "none", pageParam: me = "page", renderWhileLoading: x = !1 }) => {
22
- let { id: S, visible: C, definition: { label: w = "Api Container", runtime: he, items: ge } } = t(), T = he === "server", { loaded: E, stale: D, location: O, elementData: k, refresh: A } = n(), j = u(ee.sourceType, S), { settings: { previewMode: M }, contexts: { InteractionsContext: N } } = o(), { interactionsManager: P } = ie(N), [[F, I, L]] = oe([
21
+ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "get", accessToken: g = "", when: _ = o, headers: v = o, mockData: y = "{}", subType: de = "", credentials: fe = "same-origin", singleRecord: b = !1, pagination: x = "none", pageParam: S = "page", renderWhileLoading: pe = !1, cache: me = !1, staleTime: he = 30, gcTime: ge = 300 }) => {
22
+ let { id: C, visible: w, definition: { label: T = "Api Container", runtime: _e, items: ve } } = t(), E = _e === "server", { loaded: D, stale: O, location: k, elementData: A, refresh: j } = n(), M = u(ee.sourceType, C), { settings: { previewMode: N }, contexts: { InteractionsContext: P } } = oe(), { interactionsManager: F } = ie(P), [[I, L, ye]] = se([
23
23
  "navigation.routeParams",
24
24
  "navigation.queryParams",
25
25
  "navigation.navigate"
26
- ]), _e = a(() => g ? {
26
+ ]), be = a(() => g ? {
27
27
  ...v,
28
28
  Authorization: `Bearer ${g}`
29
- } : v, [v, g]), ve = a(() => T || !C ? !1 : !!(M && m && (_ === s || ue(_, {
30
- ...F,
31
- ...I
32
- })) || !M && (m || y && y !== "{}" && y !== s)), [
33
- T,
34
- C,
35
- M,
29
+ } : v, [v, g]), xe = a(() => E || !w ? !1 : !!(N && m && (_ === o || ue(_, {
30
+ ...I,
31
+ ...L
32
+ })) || !N && (m || y && y !== "{}" && y !== o)), [
33
+ E,
34
+ w,
35
+ N,
36
36
  m,
37
37
  _,
38
- F,
39
38
  I,
39
+ L,
40
40
  y
41
- ]), { isLoading: ye, isFetching: be, data: R, refetch: z, isSuccess: B, isError: V } = te({
41
+ ]), Se = a(() => [C], [C]), { isLoading: Ce, isFetching: we, data: R, refetch: z, isSuccess: B, isError: V } = te({
42
42
  url: m,
43
43
  method: h,
44
44
  credentials: fe,
45
- mock: M ? void 0 : y,
46
- customHeaders: _e,
47
- enabled: ve
48
- }), H = T && !!O && O !== le(), U = T && E && !H && k === null, W = a(() => {
49
- if (!T) return R ?? s;
50
- if (k) return k;
51
- if (E) return s;
45
+ mock: N ? void 0 : y,
46
+ customHeaders: be,
47
+ enabled: xe,
48
+ cache: me,
49
+ staleTime: he,
50
+ gcTime: ge,
51
+ tags: Se
52
+ }), H = E && !!k && k !== c(), U = E && D && !H && A === null, W = a(() => {
53
+ if (!E) return R ?? o;
54
+ if (A) return A;
55
+ if (D) return o;
52
56
  if (typeof y != "string") return y;
53
57
  try {
54
58
  return JSON.parse(y || "{}");
55
59
  } catch {
56
- return s;
60
+ return o;
57
61
  }
58
62
  }, [
59
- T,
60
- R,
61
- k,
62
63
  E,
64
+ R,
65
+ A,
66
+ D,
63
67
  y
64
- ]), G = T ? H : be, xe = T ? H : ye, K = i(async () => {
65
- if (!T) {
68
+ ]), G = E ? H : we, Te = E ? H : Ce, K = i(async () => {
69
+ if (!E) {
66
70
  z();
67
71
  return;
68
72
  }
69
- await A([S]);
73
+ await j([C]);
70
74
  }, [
71
- T,
75
+ E,
72
76
  z,
73
- A,
74
- S
75
- ]), q = W, Se = a(() => Array.isArray(q.records) ? q.records : [], [q.records]), { records: J, isLoadingMore: Y, goToPage: X, loadMore: Z } = ne({
76
- elementId: S,
77
- mode: pe,
78
- pageParam: me,
79
- records: Se,
77
+ j,
78
+ C
79
+ ]), q = W, Ee = a(() => Array.isArray(q.records) ? q.records : [], [q.records]), { records: J, isLoadingMore: Y, goToPage: X, loadMore: Z } = ne({
80
+ elementId: C,
81
+ mode: x,
82
+ pageParam: S,
83
+ records: Ee,
80
84
  page: q.pageInfo?.page ?? 1,
81
- refresh: A,
82
- navigate: L
85
+ refresh: j,
86
+ navigate: ye
83
87
  });
84
88
  ae(() => {
85
- !G && S && (B ? P.interactionTrigger(S, "onApiSuccess", {
89
+ !G && C && (B ? F.interactionTrigger(C, "onApiSuccess", {
86
90
  url: m,
87
91
  method: h,
88
92
  ...W
89
- }) : V && P.interactionTrigger(S, "onApiError", {
93
+ }) : V && F.interactionTrigger(C, "onApiError", {
90
94
  url: m,
91
95
  method: h,
92
96
  ...W
93
97
  }));
94
98
  }, [
95
99
  W,
96
- S,
97
- P,
100
+ C,
101
+ F,
98
102
  V,
99
103
  G,
100
104
  B,
@@ -103,12 +107,12 @@ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "g
103
107
  ]);
104
108
  let Q = a(() => ({
105
109
  ...W,
106
- ...Array.isArray(q.records) ? { records: J } : s,
110
+ ...Array.isArray(q.records) ? { records: J } : o,
107
111
  isLoading: G || Y,
108
112
  isEmpty: b ? q.record === void 0 : J.length === 0,
109
113
  hasError: U,
110
114
  errorMessage: U ? "The data provider could not be reached" : "",
111
- isStale: T && D
115
+ isStale: E && O
112
116
  }), [
113
117
  W,
114
118
  q.records,
@@ -118,9 +122,9 @@ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "g
118
122
  Y,
119
123
  b,
120
124
  U,
121
- T,
122
- D
123
- ]), Ce = i(() => ce(Q).reduce((e, t) => {
125
+ E,
126
+ O
127
+ ]), De = i(() => le(Q).reduce((e, t) => {
124
128
  let n = t.split(".");
125
129
  return n.length > 1 ? [...e, {
126
130
  path: t,
@@ -131,20 +135,20 @@ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "g
131
135
  }];
132
136
  }, []), [Q]);
133
137
  d({
134
- id: S,
135
- source: j,
136
- name: w || `API - ${S}`,
137
- fields: Ce
138
+ id: C,
139
+ source: M,
140
+ name: T || `API - ${C}`,
141
+ fields: De
138
142
  });
139
143
  let { writeRecord: $ } = re({
140
- elementId: S,
141
- enabled: T,
144
+ elementId: C,
145
+ enabled: E,
142
146
  onDone: K
143
- }), we = a(() => {
147
+ }), Oe = a(() => {
144
148
  let e = {
145
149
  performQuery: {
146
150
  action: "performQuery",
147
- title: `Perform Query ${w}`,
151
+ title: `Perform Query ${T}`,
148
152
  type: "callback",
149
153
  callback: K,
150
154
  preview: {},
@@ -152,7 +156,7 @@ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "g
152
156
  },
153
157
  loadMore: {
154
158
  action: "loadMore",
155
- title: `Load More ${w}`,
159
+ title: `Load More ${T}`,
156
160
  type: "callback",
157
161
  callback: Z,
158
162
  preview: {},
@@ -160,7 +164,7 @@ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "g
160
164
  },
161
165
  goToPage: {
162
166
  action: "goToPage",
163
- title: `Go To Page ${w}`,
167
+ title: `Go To Page ${T}`,
164
168
  type: "callback",
165
169
  callback: ({ page: e }) => X(Number(e) || 1),
166
170
  preview: {},
@@ -171,9 +175,9 @@ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "g
171
175
  } }
172
176
  }
173
177
  };
174
- return T && (e.writeRecord = {
178
+ return E && (e.writeRecord = {
175
179
  action: "writeRecord",
176
- title: `Write Record ${w}`,
180
+ title: `Write Record ${T}`,
177
181
  type: "callback",
178
182
  callback: $,
179
183
  preview: { action: "create" },
@@ -191,13 +195,13 @@ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "g
191
195
  }
192
196
  }), e;
193
197
  }, [
194
- w,
198
+ T,
195
199
  K,
196
200
  Z,
197
201
  X,
198
- T,
202
+ E,
199
203
  $
200
- ]), Te = a(() => ({
204
+ ]), ke = a(() => ({
201
205
  onApiError: {
202
206
  action: "onApiError",
203
207
  title: "On Api Error",
@@ -222,17 +226,17 @@ var f = ({ ref: e, className: f = "", children: p, query: m = "", method: h = "g
222
226
  data: ""
223
227
  }
224
228
  }
225
- }), []), Ee = a(() => j ? { runtime: { sources: { [j]: Q } } } : s, [Q, j]);
226
- return /* @__PURE__ */ c(r, {
229
+ }), []), Ae = a(() => M ? { runtime: { sources: { [M]: Q } } } : o, [Q, M]);
230
+ return /* @__PURE__ */ s(r, {
227
231
  ref: e,
228
- tag: !M && !ge?.length ? "div" : de,
232
+ tag: !N && !ve?.length ? "div" : de,
229
233
  className: l("plitzi-component__api-container", f),
230
- interactionTriggers: Te,
231
- interactionCallbacks: we,
232
- children: (!xe || x) && /* @__PURE__ */ c(se, {
234
+ interactionTriggers: ke,
235
+ interactionCallbacks: Oe,
236
+ children: (!Te || pe) && /* @__PURE__ */ s(ce, {
233
237
  inherit: "live",
234
- name: `Api:${S}`,
235
- value: Ee,
238
+ name: `Api:${C}`,
239
+ value: Ae,
236
240
  children: p
237
241
  })
238
242
  });
@@ -21,7 +21,10 @@ type SettingsProps = {
21
21
  pagination?: 'none' | 'url' | 'append';
22
22
  pageParam?: string;
23
23
  renderWhileLoading?: boolean;
24
+ cache?: boolean;
25
+ staleTime?: number | string;
26
+ gcTime?: number | string;
24
27
  onUpdate?: (key: string, value: string | boolean | number | object, isDefinition?: boolean) => void;
25
28
  };
26
- declare const Settings: ({ query, method, accessToken, headers, when, subType, mockData, credentials, runtime, connector, action, endpoint, resource, limit, singleRecord, filters, pagination, pageParam, renderWhileLoading, onUpdate }: SettingsProps) => import("react").JSX.Element;
29
+ declare const Settings: ({ query, method, accessToken, headers, when, subType, mockData, credentials, runtime, connector, action, endpoint, resource, limit, singleRecord, filters, pagination, pageParam, renderWhileLoading, cache, staleTime, gcTime, onUpdate }: SettingsProps) => import("react").JSX.Element;
27
30
  export default Settings;
@@ -1,10 +1,10 @@
1
1
  import e from "./components/FiltersInput/index.mjs";
2
- import { useCallback as t, useMemo as n, useState as ee } from "react";
3
- import { useBuilderStore as r, useCommonStore as te, useSdkStore as i } from "@plitzi/sdk-shared/store";
4
- import { get as a } from "@plitzi/plitzi-ui/helpers";
5
- import { emptyObject as ne } from "@plitzi/sdk-shared/helpers/utils";
6
- import { Fragment as o, jsx as s, jsxs as c } from "react/jsx-runtime";
7
- import l from "@plitzi/sdk-shared/theme/useTheme";
2
+ import { useCallback as t, useMemo as n, useState as r } from "react";
3
+ import { useBuilderStore as i, useCommonStore as a, useSdkStore as o } from "@plitzi/sdk-shared/store";
4
+ import { get as ee } from "@plitzi/plitzi-ui/helpers";
5
+ import { emptyObject as te } from "@plitzi/sdk-shared/helpers/utils";
6
+ import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
7
+ import ne from "@plitzi/sdk-shared/theme/useTheme";
8
8
  import u from "@plitzi/plitzi-ui/QueryBuilder";
9
9
  import d from "@plitzi/plitzi-ui/CodeMirror";
10
10
  import f from "@plitzi/plitzi-ui/Input";
@@ -12,309 +12,335 @@ import p from "@plitzi/plitzi-ui/Select";
12
12
  import re from "@plitzi/plitzi-ui/KVInput";
13
13
  import m from "@plitzi/plitzi-ui/Switch";
14
14
  //#region src/elements/provider/ApiContainer/Settings.tsx
15
- var h = [], g = ({ query: g = "", method: _ = "get", accessToken: v = "", headers: y = ne, when: b, subType: x = "", mockData: S = "{}", credentials: C = "same-origin", runtime: w = "client", connector: T = "", action: E = "", endpoint: D = "", resource: ie = "", limit: ae = "10", singleRecord: O = !1, filters: k = h, pagination: A = "none", pageParam: j = "page", renderWhileLoading: M = !1, onUpdate: N }) => {
16
- let { resolvedTheme: P } = l(), [F] = r("pageDefinitions"), [I] = r("connectors"), [L] = te("actions.catalog"), [R] = r("hasServerRendering"), [z, B] = ee(!1), V = w === "server", H = V ? E && !T ? "action" : "connector" : "client", [[U, W, G]] = i([
15
+ var h = [], g = ({ query: g = "", method: _ = "get", accessToken: ie = "", headers: v = te, when: y, subType: b = "", mockData: x = "{}", credentials: S = "same-origin", runtime: C = "client", connector: w = "", action: T = "", endpoint: E = "", resource: D = "", limit: ae = "10", singleRecord: O = !1, filters: k = h, pagination: A = "none", pageParam: j = "page", renderWhileLoading: M = !1, cache: N = !1, staleTime: P = 30, gcTime: F = 300, onUpdate: I }) => {
16
+ let { resolvedTheme: L } = ne(), [R] = i("pageDefinitions"), [z] = i("connectors"), [B] = a("actions.catalog"), [V] = i("hasServerRendering"), [H, U] = r(!1), W = C === "server", G = W ? T && !w ? "action" : "connector" : "client", [[K, q, J]] = o([
17
17
  "navigation.routeParams",
18
18
  "navigation.queryParams",
19
19
  "navigation.currentPageId"
20
- ]), K = t((e) => (t) => N?.(e, t), [N]), q = t((e) => N?.("query", e), [N]), J = t((e) => N?.("when", e), [N]), oe = t((e) => N?.("subType", e), [N]), se = t((e) => N?.("mockData", e), [N]), ce = t((e) => B(e.target.checked), []), le = t((e, t) => N?.("headers", t), [N]), ue = t((e) => {
20
+ ]), Y = t((e) => (t) => I?.(e, t), [I]), oe = t((e) => I?.("query", e), [I]), se = t((e) => I?.("when", e), [I]), ce = t((e) => I?.("subType", e), [I]), le = t((e) => I?.("mockData", e), [I]), ue = t((e) => U(e.target.checked), []), de = t((e, t) => I?.("headers", t), [I]), fe = t((e) => {
21
21
  if (e === "client") {
22
- N?.("runtime", "client", !0);
22
+ I?.("runtime", "client", !0);
23
23
  return;
24
24
  }
25
- N?.("runtime", "server", !0), N?.(e === "action" ? "connector" : "action", "");
26
- }, [N]), Y = t((e) => N?.("singleRecord", e.target.checked), [N]), de = t((e) => N?.("renderWhileLoading", e.target.checked), [N]), fe = t((e) => N?.("filters", e), [N]), X = n(() => Object.values(I), [I]), Z = n(() => X.find((e) => e.identifier === T)?.manifest, [X, T]), pe = n(() => Object.keys(Z?.operators ?? {}), [Z]), Q = n(() => Object.keys(Z?.endpoints.read ?? {}), [Z]), $ = n(() => [...a(F, `${G}.attributes.slug`, "").matchAll(/:[a-z0-9_-]+/gim)].map((e) => e[0].slice(1)), [F, G]), me = n(() => [
27
- ...Object.keys(U),
28
- ...Object.keys(W),
25
+ I?.("runtime", "server", !0), I?.(e === "action" ? "connector" : "action", "");
26
+ }, [I]), pe = t((e) => I?.("singleRecord", e.target.checked), [I]), me = t((e) => I?.("renderWhileLoading", e.target.checked), [I]), he = t((e) => I?.("cache", e.target.checked), [I]), ge = t((e) => I?.("filters", e), [I]), X = n(() => Object.values(z), [z]), Z = n(() => X.find((e) => e.identifier === w)?.manifest, [X, w]), _e = n(() => Object.keys(Z?.operators ?? {}), [Z]), Q = n(() => Object.keys(Z?.endpoints.read ?? {}), [Z]), $ = n(() => [...ee(R, `${J}.attributes.slug`, "").matchAll(/:[a-z0-9_-]+/gim)].map((e) => e[0].slice(1)), [R, J]), ve = n(() => [
27
+ ...Object.keys(K),
28
+ ...Object.keys(q),
29
29
  ...$
30
30
  ].map((e) => ({
31
31
  type: "token",
32
32
  value: e
33
33
  })), [
34
- U,
35
- W,
34
+ K,
35
+ q,
36
36
  $
37
37
  ]);
38
- return /* @__PURE__ */ c("div", {
38
+ return /* @__PURE__ */ l("div", {
39
39
  className: "flex grow flex-col gap-4 py-2",
40
40
  children: [
41
- /* @__PURE__ */ c(p, {
42
- value: H,
41
+ /* @__PURE__ */ l(p, {
42
+ value: G,
43
43
  label: "Data Source",
44
- onChange: ue,
44
+ onChange: fe,
45
45
  size: "xs",
46
46
  children: [
47
- /* @__PURE__ */ s("option", {
47
+ /* @__PURE__ */ c("option", {
48
48
  value: "client",
49
49
  children: "Browser request"
50
50
  }),
51
- /* @__PURE__ */ s("option", {
51
+ /* @__PURE__ */ c("option", {
52
52
  value: "connector",
53
53
  children: "Connector (server-side)"
54
54
  }),
55
- /* @__PURE__ */ s("option", {
55
+ /* @__PURE__ */ c("option", {
56
56
  value: "action",
57
57
  children: "Server action (server-side)"
58
58
  })
59
59
  ]
60
60
  }),
61
- /* @__PURE__ */ c("span", {
61
+ /* @__PURE__ */ l("span", {
62
62
  className: "text-xs text-gray-500 dark:text-zinc-400",
63
63
  children: [
64
- H === "connector" && "The server calls the API and hands the page its records. The endpoint and the credential never reach the browser, and the content is in the HTML search engines see.",
65
- H === "action" && "A flow runs on the server and hands the page whatever its output step returns — for the read a connector cannot express: two calls joined, a computed field, a shape that depends on who is looking. It is fed this page’s route and query params.",
66
- H === "client" && "The browser calls the URL directly. Anything it needs to authenticate with is visible to the visitor, and the content is not in the initial HTML."
64
+ G === "connector" && "The server calls the API and hands the page its records. The endpoint and the credential never reach the browser, and the content is in the HTML search engines see.",
65
+ G === "action" && "A flow runs on the server and hands the page whatever its output step returns — for the read a connector cannot express: two calls joined, a computed field, a shape that depends on who is looking. It is fed this page’s route and query params.",
66
+ G === "client" && "The browser calls the URL directly. Anything it needs to authenticate with is visible to the visitor, and the content is not in the initial HTML."
67
67
  ]
68
68
  }),
69
- H === "action" && /* @__PURE__ */ c(o, { children: [L?.length === 0 && /* @__PURE__ */ s("div", {
69
+ G === "action" && /* @__PURE__ */ l(s, { children: [B?.length === 0 && /* @__PURE__ */ c("div", {
70
70
  className: "rounded-sm border border-gray-300 p-2 text-xs text-gray-500 dark:border-zinc-600 dark:text-zinc-400",
71
71
  children: "No actions yet. Add one in the Actions panel and give it a “While a page renders” trigger — that is the way in this element uses."
72
- }), /* @__PURE__ */ c(p, {
73
- value: E,
72
+ }), /* @__PURE__ */ l(p, {
73
+ value: T,
74
74
  label: "Action",
75
- onChange: K("action"),
75
+ onChange: Y("action"),
76
76
  size: "xs",
77
- children: [/* @__PURE__ */ s("option", {
77
+ children: [/* @__PURE__ */ c("option", {
78
78
  value: "",
79
79
  children: "Select an action…"
80
- }), (L ?? []).map((e) => /* @__PURE__ */ s("option", {
80
+ }), (B ?? []).map((e) => /* @__PURE__ */ c("option", {
81
81
  value: e.identifier,
82
82
  children: e.name
83
83
  }, e.identifier))]
84
84
  })] }),
85
- V && !R && /* @__PURE__ */ s("div", {
85
+ W && !V && /* @__PURE__ */ c("div", {
86
86
  className: "rounded-sm border border-yellow-300 bg-yellow-50 p-2 text-xs text-yellow-800 dark:border-yellow-700 dark:bg-yellow-950 dark:text-yellow-200",
87
87
  children: "This space has no server-rendered deployment. It resolves here in the builder, but a published page would have no server to resolve it — publish with a Plitzi SSR credential, or read the API from the browser instead."
88
88
  }),
89
- H === "connector" && /* @__PURE__ */ c(o, { children: [
90
- X.length === 0 && /* @__PURE__ */ s("div", {
89
+ G === "connector" && /* @__PURE__ */ l(s, { children: [
90
+ X.length === 0 && /* @__PURE__ */ c("div", {
91
91
  className: "rounded-sm border border-gray-300 p-2 text-xs text-gray-500 dark:border-zinc-600 dark:text-zinc-400",
92
92
  children: "No connectors yet. Add one in the Connectors panel — it holds the API endpoints, and the credential stays on the server."
93
93
  }),
94
- /* @__PURE__ */ c(p, {
95
- value: T,
94
+ /* @__PURE__ */ l(p, {
95
+ value: w,
96
96
  label: "Connector",
97
- onChange: K("connector"),
97
+ onChange: Y("connector"),
98
98
  size: "xs",
99
- children: [/* @__PURE__ */ s("option", {
99
+ children: [/* @__PURE__ */ c("option", {
100
100
  value: "",
101
101
  children: "Select a connector…"
102
- }), X.map((e) => /* @__PURE__ */ s("option", {
102
+ }), X.map((e) => /* @__PURE__ */ c("option", {
103
103
  value: e.identifier,
104
104
  children: e.name
105
105
  }, e.identifier))]
106
106
  }),
107
- Q.length > 1 && /* @__PURE__ */ s(p, {
108
- value: D,
107
+ Q.length > 1 && /* @__PURE__ */ c(p, {
108
+ value: E,
109
109
  label: "Endpoint",
110
- onChange: K("endpoint"),
110
+ onChange: Y("endpoint"),
111
111
  size: "xs",
112
- children: Q.map((e) => /* @__PURE__ */ s("option", {
112
+ children: Q.map((e) => /* @__PURE__ */ c("option", {
113
113
  value: e,
114
114
  children: e
115
115
  }, e))
116
116
  }),
117
- /* @__PURE__ */ s(f, {
118
- value: ie,
117
+ /* @__PURE__ */ c(f, {
118
+ value: D,
119
119
  label: "Resource",
120
120
  placeholder: "posts",
121
121
  title: "The collection read through the connector — what {{resource}} becomes in the endpoint path.",
122
- onChange: K("resource"),
122
+ onChange: Y("resource"),
123
123
  size: "xs"
124
124
  }),
125
- /* @__PURE__ */ s(e, {
125
+ /* @__PURE__ */ c(e, {
126
126
  value: k,
127
- operators: pe,
128
- onChange: fe
127
+ operators: _e,
128
+ onChange: ge
129
129
  }),
130
- /* @__PURE__ */ s(m, {
130
+ /* @__PURE__ */ c(m, {
131
131
  checked: O,
132
132
  size: "sm",
133
133
  label: "Single record (detail page)",
134
- onChange: Y
134
+ onChange: pe
135
135
  }),
136
- !O && /* @__PURE__ */ c(o, { children: [
137
- /* @__PURE__ */ s(f, {
136
+ !O && /* @__PURE__ */ l(s, { children: [
137
+ /* @__PURE__ */ c(f, {
138
138
  value: ae,
139
139
  label: "Records per page",
140
- onChange: K("limit"),
140
+ onChange: Y("limit"),
141
141
  size: "xs"
142
142
  }),
143
- /* @__PURE__ */ c(p, {
143
+ /* @__PURE__ */ l(p, {
144
144
  value: A,
145
145
  label: "Pagination",
146
- onChange: K("pagination"),
146
+ onChange: Y("pagination"),
147
147
  size: "xs",
148
148
  children: [
149
- /* @__PURE__ */ s("option", {
149
+ /* @__PURE__ */ c("option", {
150
150
  value: "none",
151
151
  children: "None"
152
152
  }),
153
- /* @__PURE__ */ s("option", {
153
+ /* @__PURE__ */ c("option", {
154
154
  value: "url",
155
155
  children: "URL (indexable)"
156
156
  }),
157
- /* @__PURE__ */ s("option", {
157
+ /* @__PURE__ */ c("option", {
158
158
  value: "append",
159
159
  children: "Load more"
160
160
  })
161
161
  ]
162
162
  }),
163
- A !== "none" && /* @__PURE__ */ s(f, {
163
+ A !== "none" && /* @__PURE__ */ c(f, {
164
164
  value: j,
165
165
  label: "Page parameter",
166
166
  title: "Query-string key this list pages on. Give each list its own so they page independently.",
167
- onChange: K("pageParam"),
167
+ onChange: Y("pageParam"),
168
168
  size: "xs"
169
169
  })
170
170
  ] })
171
171
  ] }),
172
- !V && /* @__PURE__ */ c(o, { children: [
173
- /* @__PURE__ */ c("div", {
172
+ !W && /* @__PURE__ */ l(s, { children: [
173
+ /* @__PURE__ */ l("div", {
174
174
  className: "flex flex-col",
175
- children: [/* @__PURE__ */ s("label", { children: "Query" }), /* @__PURE__ */ s(d, {
175
+ children: [/* @__PURE__ */ c("label", { children: "Query" }), /* @__PURE__ */ c(d, {
176
176
  className: "font-rubik min-h-6.5 basis-auto rounded-sm border border-gray-300 px-1 text-xs",
177
177
  value: g,
178
- theme: P,
178
+ theme: L,
179
179
  mode: "text",
180
- autoComplete: me,
180
+ autoComplete: ve,
181
181
  lineWrapping: !0,
182
182
  multiline: !1,
183
- onChange: q
183
+ onChange: oe
184
184
  })]
185
185
  }),
186
- /* @__PURE__ */ c(p, {
186
+ /* @__PURE__ */ l(p, {
187
187
  value: _,
188
188
  label: "Method",
189
- onChange: K("method"),
189
+ onChange: Y("method"),
190
190
  size: "xs",
191
- children: [/* @__PURE__ */ s("option", {
191
+ children: [/* @__PURE__ */ c("option", {
192
192
  value: "get",
193
193
  children: "Get"
194
- }), /* @__PURE__ */ s("option", {
194
+ }), /* @__PURE__ */ c("option", {
195
195
  value: "post",
196
196
  children: "Post"
197
197
  })]
198
198
  }),
199
- /* @__PURE__ */ s(f, {
200
- value: v,
199
+ /* @__PURE__ */ c(f, {
200
+ value: ie,
201
201
  label: "Access Token",
202
202
  title: "Bind this to the signed-in visitor's token. A value typed here is saved in the page and served to\n every visitor — put anything secret behind a connector instead.",
203
- onChange: K("accessToken"),
203
+ onChange: Y("accessToken"),
204
204
  size: "xs"
205
205
  }),
206
- /* @__PURE__ */ c(p, {
207
- value: C,
206
+ /* @__PURE__ */ l(p, {
207
+ value: S,
208
208
  label: "Include Credentials",
209
- onChange: K("credentials"),
209
+ onChange: Y("credentials"),
210
210
  size: "xs",
211
211
  children: [
212
- /* @__PURE__ */ s("option", {
212
+ /* @__PURE__ */ c("option", {
213
213
  value: "include",
214
214
  children: "Include"
215
215
  }),
216
- /* @__PURE__ */ s("option", {
216
+ /* @__PURE__ */ c("option", {
217
217
  value: "omit",
218
218
  children: "Omit"
219
219
  }),
220
- /* @__PURE__ */ s("option", {
220
+ /* @__PURE__ */ c("option", {
221
221
  value: "same-origin",
222
222
  children: "Same Origin"
223
223
  })
224
224
  ]
225
225
  }),
226
- /* @__PURE__ */ s(m, {
226
+ /* @__PURE__ */ c(m, {
227
+ checked: N,
228
+ size: "sm",
229
+ label: "Cache responses",
230
+ onChange: he
231
+ }),
232
+ N && /* @__PURE__ */ l(s, { children: [
233
+ /* @__PURE__ */ c(f, {
234
+ value: String(P),
235
+ label: "Fresh for (s)",
236
+ title: "How long an answer is reused without asking again — here and by every provider requesting the\n same thing. Past it, the answer stays on screen while a fresh one is fetched. 0 asks on every mount.",
237
+ onChange: Y("staleTime"),
238
+ size: "xs"
239
+ }),
240
+ /* @__PURE__ */ c(f, {
241
+ value: String(F),
242
+ label: "Keep unused for (s)",
243
+ title: "How long an answer nobody is showing is kept, so coming back to it within that time paints at once.",
244
+ onChange: Y("gcTime"),
245
+ size: "xs"
246
+ }),
247
+ /* @__PURE__ */ c("div", {
248
+ className: "rounded-sm border border-gray-300 p-2 text-xs text-gray-500 dark:border-zinc-600 dark:text-zinc-400",
249
+ children: "A completed server action refreshes every cached request, in case it changed what they read. On its step, “Refresh cached requests” can name only the containers it affects, or none for an action that only reads. A webhook step can do the same."
250
+ })
251
+ ] }),
252
+ /* @__PURE__ */ c(m, {
227
253
  checked: M,
228
254
  size: "sm",
229
255
  label: "Render children while loading",
230
- onChange: de
256
+ onChange: me
231
257
  })
232
258
  ] }),
233
- /* @__PURE__ */ s(m, {
234
- checked: z,
259
+ /* @__PURE__ */ c(m, {
260
+ checked: H,
235
261
  size: "sm",
236
262
  label: "Advanced Settings",
237
- onChange: ce
263
+ onChange: ue
238
264
  }),
239
- z && /* @__PURE__ */ c(o, { children: [
240
- /* @__PURE__ */ s(re, {
241
- value: Object.entries(y),
265
+ H && /* @__PURE__ */ l(s, { children: [
266
+ /* @__PURE__ */ c(re, {
267
+ value: Object.entries(v),
242
268
  label: "Headers",
243
- onChange: le,
269
+ onChange: de,
244
270
  size: "xs"
245
271
  }),
246
- /* @__PURE__ */ c("div", {
272
+ /* @__PURE__ */ l("div", {
247
273
  className: "flex flex-col",
248
- children: [/* @__PURE__ */ s("label", { children: "When to perform query request" }), /* @__PURE__ */ s(u, {
274
+ children: [/* @__PURE__ */ c("label", { children: "When to perform query request" }), /* @__PURE__ */ c(u, {
249
275
  direction: "vertical",
250
276
  className: "w-full",
251
277
  size: "xs",
252
- query: b,
253
- onChange: J,
278
+ query: y,
279
+ onChange: se,
254
280
  showBranches: !0
255
281
  })]
256
282
  }),
257
- /* @__PURE__ */ c(p, {
258
- value: x,
283
+ /* @__PURE__ */ l(p, {
284
+ value: b,
259
285
  label: "Container Tag",
260
- onChange: oe,
286
+ onChange: ce,
261
287
  size: "xs",
262
288
  children: [
263
- /* @__PURE__ */ s("option", {
289
+ /* @__PURE__ */ c("option", {
264
290
  value: "",
265
291
  children: "None"
266
292
  }),
267
- /* @__PURE__ */ s("option", {
293
+ /* @__PURE__ */ c("option", {
268
294
  value: "div",
269
295
  children: "Div"
270
296
  }),
271
- /* @__PURE__ */ s("option", {
297
+ /* @__PURE__ */ c("option", {
272
298
  value: "header",
273
299
  children: "Header"
274
300
  }),
275
- /* @__PURE__ */ s("option", {
301
+ /* @__PURE__ */ c("option", {
276
302
  value: "footer",
277
303
  children: "Footer"
278
304
  }),
279
- /* @__PURE__ */ s("option", {
305
+ /* @__PURE__ */ c("option", {
280
306
  value: "nav",
281
307
  children: "Nav"
282
308
  }),
283
- /* @__PURE__ */ s("option", {
309
+ /* @__PURE__ */ c("option", {
284
310
  value: "main",
285
311
  children: "Main"
286
312
  }),
287
- /* @__PURE__ */ s("option", {
313
+ /* @__PURE__ */ c("option", {
288
314
  value: "section",
289
315
  children: "Section"
290
316
  }),
291
- /* @__PURE__ */ s("option", {
317
+ /* @__PURE__ */ c("option", {
292
318
  value: "article",
293
319
  children: "Article"
294
320
  }),
295
- /* @__PURE__ */ s("option", {
321
+ /* @__PURE__ */ c("option", {
296
322
  value: "aside",
297
323
  children: "Aside"
298
324
  }),
299
- /* @__PURE__ */ s("option", {
325
+ /* @__PURE__ */ c("option", {
300
326
  value: "address",
301
327
  children: "Address"
302
328
  }),
303
- /* @__PURE__ */ s("option", {
329
+ /* @__PURE__ */ c("option", {
304
330
  value: "figure",
305
331
  children: "Figure"
306
332
  })
307
333
  ]
308
334
  }),
309
- /* @__PURE__ */ s("div", { className: "my-2 h-px w-full border border-gray-300 bg-gray-300" }),
310
- /* @__PURE__ */ c("div", {
335
+ /* @__PURE__ */ c("div", { className: "my-2 h-px w-full border border-gray-300 bg-gray-300" }),
336
+ /* @__PURE__ */ l("div", {
311
337
  className: "flex min-h-50 grow flex-col",
312
- children: [/* @__PURE__ */ s("label", { children: "Mock Data (Build Mode)" }), /* @__PURE__ */ s(d, {
313
- value: S,
314
- theme: P,
338
+ children: [/* @__PURE__ */ c("label", { children: "Mock Data (Build Mode)" }), /* @__PURE__ */ c(d, {
339
+ value: x,
340
+ theme: L,
315
341
  mode: "json",
316
342
  lineWrapping: !0,
317
- onChange: se
343
+ onChange: le
318
344
  })]
319
345
  })
320
346
  ] })
@@ -29,6 +29,9 @@ declare const declaration: {
29
29
  readonly pagination: "none";
30
30
  readonly pageParam: "page";
31
31
  readonly renderWhileLoading: false;
32
+ readonly cache: false;
33
+ readonly staleTime: 30;
34
+ readonly gcTime: 300;
32
35
  };
33
36
  readonly definition: {
34
37
  readonly label: "Api Container";
@@ -18,12 +18,15 @@ var t = e()({
18
18
  filters: [],
19
19
  pagination: "none",
20
20
  pageParam: "page",
21
- renderWhileLoading: !1
21
+ renderWhileLoading: !1,
22
+ cache: !1,
23
+ staleTime: 30,
24
+ gcTime: 300
22
25
  },
23
26
  definition: {
24
27
  label: "Api Container",
25
28
  type: "apiContainer",
26
- description: "Fetches data from a backend HTTP API (its `query`/`method`/`credentials`) and exposes the response as a data source ITS DESCENDANTS bind to (source `apiContainer_<id>.data`; only elements inside it can consume it). This is how you get backend data into the frontend. Its `mockData` prop is builder-only sample data — the published runtime fetches the real `query`, so always set a real query for production.",
29
+ description: "Fetches data from a backend HTTP API (its `query`/`method`/`credentials`) and exposes the response as a data source ITS DESCENDANTS bind to (source `apiContainer_<id>.data`; only elements inside it can consume it). This is how you get backend data into the frontend. Its `mockData` prop is builder-only sample data — the published runtime fetches the real `query`, so always set a real query for production. With `cache: true` a browser request is kept for `staleTime` seconds (default 30) and shared with every provider asking the same thing; it is off unless set. A flow refreshes it with `performQuery` or the global `invalidateQueries` step.",
27
30
  items: [],
28
31
  bindings: {},
29
32
  styleSelectors: { base: "" },
@@ -1,13 +1,31 @@
1
+ export type ApiResponse = {
2
+ status: number;
3
+ data: unknown;
4
+ };
1
5
  export type UseApiProps = {
2
6
  url?: string;
3
7
  method?: 'get' | 'post' | 'put' | 'delete' | 'patch';
8
+ /** Answers instead of the network — what the builder renders with while the page is being edited. */
4
9
  mock?: Record<string, unknown> | string;
5
- params?: Record<string, string | Blob>;
6
10
  customHeaders?: Record<string, string>;
7
11
  enabled?: boolean;
8
12
  credentials?: RequestCredentials;
13
+ /**
14
+ * Keep answers in the page's query cache and share them with every provider asking the same thing. Off, each
15
+ * provider asks for itself on every mount and forgets the answer when it unmounts — the behaviour a page gets
16
+ * unless its author opted in.
17
+ */
18
+ cache?: boolean;
19
+ /** With `cache`: how long an answer is served without asking again, in seconds. `0` asks on every mount. */
20
+ staleTime?: number | string;
21
+ /** With `cache`: how long an answer nobody renders is kept, in seconds. */
22
+ gcTime?: number | string;
23
+ /** What an invalidation can name this request by — an api container gives its own id. */
24
+ tags?: readonly string[];
9
25
  };
10
- declare const useApi: ({ url, method, mock, params, customHeaders, enabled, credentials }: UseApiProps) => {
26
+ export declare const DEFAULT_STALE_TIME = 30;
27
+ export declare const DEFAULT_GC_TIME = 300;
28
+ declare const useApi: ({ url, method, mock, customHeaders, enabled, credentials, cache, staleTime, gcTime, tags }: UseApiProps) => {
11
29
  /**
12
30
  * Nothing has been answered yet, so there is nothing truthful to render.
13
31
  *
@@ -19,12 +37,9 @@ declare const useApi: ({ url, method, mock, params, customHeaders, enabled, cred
19
37
  isLoading: boolean;
20
38
  /** A request is in flight, first or not. What a spinner binds to. */
21
39
  isFetching: boolean;
22
- data: {
23
- status: number;
24
- data: unknown;
25
- } | undefined;
40
+ data: ApiResponse | undefined;
26
41
  refetch: () => void;
27
- isSuccess: boolean | undefined;
28
- isError: boolean | undefined;
42
+ isSuccess: boolean;
43
+ isError: boolean;
29
44
  };
30
45
  export default useApi;
@@ -1,15 +1,17 @@
1
- import { useCallback as e, useEffect as t, useState as n } from "react";
1
+ import { useCallback as e, useId as t, useMemo as n } from "react";
2
2
  import { emptyObject as r } from "@plitzi/sdk-shared/helpers/utils";
3
3
  import { authFailureFromResponse as i, reportAuthFailure as a } from "@plitzi/sdk-shared/auth";
4
+ import { requestKey as o, useQuery as s } from "@plitzi/sdk-shared/queries";
4
5
  //#region src/elements/provider/ApiContainer/hooks/useApi.ts
5
- var o = async ({ url: e = "", method: t = "get", credentials: n = "same-origin", params: o = r, customHeaders: s = r, mock: c = r } = {}) => {
6
- if (c && c !== "{}" && c !== r) try {
7
- return typeof c == "string" ? {
8
- status: 200,
9
- data: JSON.parse(c)
10
- } : {
6
+ var c = 30, l = 300, u = (e) => !!e && e !== "{}" && e !== r, d = (e) => {
7
+ if (typeof e != "string") return {
8
+ status: 200,
9
+ data: e
10
+ };
11
+ try {
12
+ return {
11
13
  status: 200,
12
- data: c
14
+ data: JSON.parse(e)
13
15
  };
14
16
  } catch (e) {
15
17
  return {
@@ -17,32 +19,21 @@ var o = async ({ url: e = "", method: t = "get", credentials: n = "same-origin",
17
19
  data: e.message
18
20
  };
19
21
  }
20
- let l = new Headers();
21
- if (l.append("Content-Type", "application/json"), Object.keys(s).length > 0 && Object.keys(s).forEach((e) => {
22
- l.append(e, s[e]);
23
- }), !e) return {
22
+ }, f = async (e, t, n, r) => {
23
+ if (!e) return {
24
24
  status: 400,
25
25
  data: "URL is required"
26
26
  };
27
- Object.values(o).forEach((e) => {
28
- if (e instanceof Blob && l.get("Content-Type") !== "multipart/form-data") {
29
- l.set("Content-Type", "multipart/form-data");
30
- return;
31
- }
32
- });
33
- let u = new FormData();
34
- Object.entries(o).forEach(([e, t]) => {
35
- u.append(e, t);
36
- });
37
- let d = {
27
+ let o = new Headers(r);
28
+ o.has("Content-Type") || o.set("Content-Type", "application/json");
29
+ let s = {
38
30
  method: t,
39
31
  credentials: n,
40
- headers: l,
41
- body: u
32
+ headers: o
42
33
  };
43
- l.get("Content-Type") === "application/json" && (d.body = JSON.stringify(o)), t === "get" && delete d.body;
34
+ t !== "get" && (s.body = "{}");
44
35
  try {
45
- let t = await fetch(e, d), n = await t.json(), r = i(t.status, n);
36
+ let t = await fetch(e, s), n = await t.json(), r = i(t.status, n);
46
37
  return r && a({
47
38
  reason: r,
48
39
  url: e
@@ -56,44 +47,52 @@ var o = async ({ url: e = "", method: t = "get", credentials: n = "same-origin",
56
47
  data: e.message
57
48
  };
58
49
  }
59
- }, s = ({ url: i = "", method: a = "get", mock: s = r, params: c = r, customHeaders: l = r, enabled: u = !0, credentials: d = "same-origin" }) => {
60
- let [f, p] = n(u), [m, h] = n(), g = e(() => {
61
- u && (p(!0), o({
62
- url: i,
50
+ }, p = (e) => e.status < 400, m = (e, t) => {
51
+ let n = typeof e == "number" ? e : Number(e);
52
+ return (Number.isFinite(n) && n >= 0 ? n : t) * 1e3;
53
+ }, h = ({ url: i = "", method: a = "get", mock: c, customHeaders: l = r, enabled: h = !0, credentials: g = "same-origin", cache: _ = !1, staleTime: v = 30, gcTime: y = 300, tags: b }) => {
54
+ let x = u(c), S = t(), C = n(() => {
55
+ if (x || !i) return;
56
+ let e = o({
63
57
  method: a,
64
- credentials: d,
65
- mock: s,
66
- customHeaders: l,
67
- params: c
68
- }).then((e) => h(e)).catch((e) => h({
69
- status: 500,
70
- data: e.message
71
- })).finally(() => p(!1)));
58
+ url: i,
59
+ credentials: g,
60
+ headers: l
61
+ });
62
+ return _ ? e : `${e}#${S}`;
72
63
  }, [
73
- u,
64
+ x,
74
65
  i,
75
66
  a,
76
- d,
77
- s,
67
+ g,
78
68
  l,
79
- c
80
- ]);
81
- return t(() => {
82
- g();
83
- }, [
84
- u,
85
- c,
86
- s,
69
+ _,
70
+ S
71
+ ]), w = e(() => f(i, a, g, l), [
87
72
  i,
88
- g
89
- ]), {
90
- isLoading: f && m === void 0,
91
- isFetching: f,
92
- data: m,
93
- refetch: g,
94
- isSuccess: !f && m && m.status < 400,
95
- isError: !f && m && m.status >= 400
73
+ a,
74
+ g,
75
+ l
76
+ ]), T = s({
77
+ key: C,
78
+ meta: {
79
+ url: i,
80
+ tags: b
81
+ },
82
+ fetcher: w,
83
+ enabled: h,
84
+ staleTime: _ ? m(v, 30) : 0,
85
+ gcTime: _ ? m(y, 300) : 0,
86
+ isCacheable: p
87
+ }), E = n(() => x ? d(c) : void 0, [x, c]), D = h && E ? E : T.data, O = !E && T.isFetching;
88
+ return {
89
+ isLoading: O && D === void 0,
90
+ isFetching: O,
91
+ data: D,
92
+ refetch: T.refetch,
93
+ isSuccess: !O && !!D && D.status < 400,
94
+ isError: !O && !!D && D.status >= 400
96
95
  };
97
96
  };
98
97
  //#endregion
99
- export { s as default };
98
+ export { l as DEFAULT_GC_TIME, c as DEFAULT_STALE_TIME, h as default };
@@ -1,34 +1,35 @@
1
1
  import { useCallback as e } from "react";
2
2
  import { authFailureFromResponse as t, reportAuthFailure as n } from "@plitzi/sdk-shared/auth";
3
+ import { invalidateQueries as r } from "@plitzi/sdk-shared/queries";
3
4
  //#region src/elements/provider/ApiContainer/hooks/useProviderWrite.ts
4
- var r = ({ elementId: r, enabled: i, actionPath: a = "/_action", onDone: o }) => ({ writeRecord: e(async (e = {}) => {
5
- let { action: s, recordId: c, ...l } = e;
6
- if (!i || typeof s != "string" || !s) return;
7
- let u = await fetch(a, {
5
+ var i = ({ elementId: i, enabled: a, actionPath: o = "/_action", onDone: s }) => ({ writeRecord: e(async (e = {}) => {
6
+ let { action: c, recordId: l, ...u } = e;
7
+ if (!a || typeof c != "string" || !c) return;
8
+ let d = await fetch(o, {
8
9
  method: "POST",
9
10
  headers: { "Content-Type": "application/json" },
10
11
  credentials: "same-origin",
11
12
  body: JSON.stringify({
12
- elementId: r,
13
- action: s,
14
- recordId: c,
15
- values: l
13
+ elementId: i,
14
+ action: c,
15
+ recordId: l,
16
+ values: u
16
17
  })
17
18
  });
18
- if (!u.ok) {
19
- let e = t(u.status, await u.json().catch(() => void 0));
19
+ if (!d.ok) {
20
+ let e = t(d.status, await d.json().catch(() => void 0));
20
21
  throw e && n({
21
22
  reason: e,
22
- url: a
23
- }), Error(`Write failed with status ${u.status}`);
23
+ url: o
24
+ }), Error(`Write failed with status ${d.status}`);
24
25
  }
25
- let d = await u.json();
26
- return await o?.(), d.record;
26
+ let f = await d.json();
27
+ return r(), await s?.(), f.record;
27
28
  }, [
28
- a,
29
- r,
29
+ o,
30
30
  i,
31
- o
31
+ a,
32
+ s
32
33
  ]) });
33
34
  //#endregion
34
- export { r as default };
35
+ export { i as default };
@@ -20,6 +20,9 @@ declare const ApiContainer: {
20
20
  readonly pagination: "none";
21
21
  readonly pageParam: "page";
22
22
  readonly renderWhileLoading: false;
23
+ readonly cache: false;
24
+ readonly staleTime: 30;
25
+ readonly gcTime: 300;
23
26
  };
24
27
  readonly definition: {
25
28
  readonly label: "Api Container";
package/dist/index.d.ts CHANGED
@@ -3145,6 +3145,9 @@ export declare const defaultElements: {
3145
3145
  readonly pagination: "none";
3146
3146
  readonly pageParam: "page";
3147
3147
  readonly renderWhileLoading: false;
3148
+ readonly cache: false;
3149
+ readonly staleTime: 30;
3150
+ readonly gcTime: 300;
3148
3151
  };
3149
3152
  readonly definition: {
3150
3153
  readonly label: "Api Container";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plitzi/sdk-elements",
3
- "version": "0.35.10",
3
+ "version": "0.36.0",
4
4
  "license": "AGPL-3.0",
5
5
  "files": [
6
6
  "dist"
@@ -984,15 +984,15 @@
984
984
  "type": "module",
985
985
  "sideEffects": false,
986
986
  "dependencies": {
987
- "@plitzi/nexus": "^1.1.4",
987
+ "@plitzi/nexus": "^1.2.0",
988
988
  "@plitzi/plitzi-ui": "^1.6.21",
989
- "@plitzi/sdk-auth": "0.35.10",
990
- "@plitzi/sdk-dev-tools": "0.35.10",
991
- "@plitzi/sdk-event-bridge": "0.35.10",
992
- "@plitzi/sdk-interactions": "0.35.10",
993
- "@plitzi/sdk-navigation": "0.35.10",
994
- "@plitzi/sdk-schema": "0.35.10",
995
- "@plitzi/sdk-shared": "0.35.10",
989
+ "@plitzi/sdk-auth": "0.36.0",
990
+ "@plitzi/sdk-dev-tools": "0.36.0",
991
+ "@plitzi/sdk-event-bridge": "0.36.0",
992
+ "@plitzi/sdk-interactions": "0.36.0",
993
+ "@plitzi/sdk-navigation": "0.36.0",
994
+ "@plitzi/sdk-schema": "0.36.0",
995
+ "@plitzi/sdk-shared": "0.36.0",
996
996
  "clsx": "^2.1.1",
997
997
  "immer": "^11.1.18"
998
998
  },