@tailorkit/client-core 0.1.0-beta.20 → 0.1.0-beta.22
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/README.md +2 -51
- package/dist/{chunk-VMCRLQ7V.js → chunk-DPR3U4U2.js} +7 -1
- package/dist/{chunk-NBBSQCLW.js → chunk-ED3BWTXG.js} +18 -18
- package/dist/{chunk-RDNN64NX.js → chunk-K3QITWU4.js} +35 -33
- package/dist/{chunk-HMNBZ5PO.js → chunk-RNTQ3LLF.js} +20 -36
- package/dist/client/apps.d.ts +1 -2
- package/dist/client/fetch-client.d.ts +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client.js +3 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -9
- package/dist/store/fetch/apps.d.ts +1 -2
- package/dist/store/fetch/cache.d.ts +1 -1
- package/dist/store/fetch/index.d.ts +2 -2
- package/dist/store/fetch/{slot-instances.d.ts → slot.d.ts} +10 -6
- package/dist/store/local/node-store.d.ts +1 -1
- package/dist/store/local/view-registry.d.ts +1 -1
- package/dist/store/store.d.ts +1 -1
- package/dist/store-fetch.js +4 -4
- package/dist/store-local.js +1 -1
- package/dist/types.d.ts +0 -7
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,52 +1,3 @@
|
|
|
1
|
-
#
|
|
1
|
+
# TailorKit Client Core
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
All stores live under `src/store` and are exported from `src/index.ts`. Separate entry points keep fetch state independent of local state:
|
|
6
|
-
|
|
7
|
-
- `@tailorkit/client-core/client`: endpoint transport, shared client cache, and app/view resolution helpers.
|
|
8
|
-
- `@tailorkit/client-core/store/fetch`: app discovery, metadata, slot instances, preview sessions, and the response cache.
|
|
9
|
-
- `@tailorkit/client-core/store/local`: `NodeStore` and `createViewRegistry` for remote UI nodes and active view context.
|
|
10
|
-
|
|
11
|
-
`createEndpointClient` exposes uncached endpoint calls independently of stores. Fetch stores expose snapshot getters, subscriptions, fetch, and invalidation methods without requiring a framework adapter to access TanStack Store. This separation allows a future adapter to use its own fetch layer, such as TanStack Query, while retaining the local stores and endpoint transport. The built-in cache currently uses TanStack Store.
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { createTailorKitFetchClient, createTailorKitStore } from "@tailorkit/client-core";
|
|
15
|
-
|
|
16
|
-
const client = createTailorKitFetchClient({
|
|
17
|
-
baseUrl: "https://example.com/api/tailorkit",
|
|
18
|
-
cache: {
|
|
19
|
-
staleTime: 30_000,
|
|
20
|
-
gcTime: 300_000,
|
|
21
|
-
apps: { staleTime: 60_000 },
|
|
22
|
-
meta: { staleTime: Infinity },
|
|
23
|
-
slotInstances: { staleTime: 10_000 },
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Share a client across roots to share responses and in-flight requests.
|
|
28
|
-
// Each root retains its own active view registry and supplied app overrides.
|
|
29
|
-
const root = createTailorKitStore(client.baseUrl, undefined, client);
|
|
30
|
-
const stop = root.subscribeApps(() => {
|
|
31
|
-
const snapshot = root.getAppsSnapshot();
|
|
32
|
-
// Update the framework adapter with apps, status, error, and isFetching.
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
await root.fetchApps();
|
|
36
|
-
await root.fetchApps({ force: true });
|
|
37
|
-
|
|
38
|
-
stop();
|
|
39
|
-
root.previews.dispose();
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Successful responses are fresh for 30 seconds by default. Mounting a consumer or calling `fetch()` reuses fresh data and refreshes stale data; stale times do not start polling. `staleTime: 0` always refreshes, while `Infinity` keeps successful data fresh until invalidated or explicitly refetched. Background requests retain successful data and set `isFetching`.
|
|
43
|
-
|
|
44
|
-
Unused responses are retained for five minutes by default. `gcTime` controls eviction after the last subscriber leaves or an unobserved request finishes. Concurrent consumers share a request; slot requests are cancelled when their last subscriber leaves, and superseded responses cannot overwrite newer data. Slot cache keys include the app, deployment, preview session, slot, and active view context.
|
|
45
|
-
|
|
46
|
-
Caches belong to a client instance. Create a new client when the authenticated identity changes; `client.clear()` discards responses and session providers. User-supplied apps remain authoritative for their root and do not seed the shared endpoint cache. Views derive from the same cached apps response.
|
|
47
|
-
|
|
48
|
-
React's `createTailorKitClient` accepts the same `cache` configuration and an optional `fetch` implementation. `useApps` and `useViews` accept a `staleTime` override; `useSlotInstances` also accepts `gcTime`. Their `refetch()` methods force a new request.
|
|
49
|
-
|
|
50
|
-
`useSlotInstances({ slot })` resolves instances across discovered apps in discovery order, with the originating `app` attached to each result. Managed `Slot` components resolve only their explicitly supplied app. Instance resolution requires a slot declared with `multiple: true`.
|
|
51
|
-
|
|
52
|
-
`TailorKitApp` and `TailorKitView` are shared types; the React package re-exports them for compatibility.
|
|
3
|
+
Shared client functionality for TailorKit integrations.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createEndpointClient,
|
|
3
3
|
createFetchCache
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RNTQ3LLF.js";
|
|
5
5
|
|
|
6
6
|
// src/client/fetch-client.ts
|
|
7
7
|
function createTailorKitFetchClient(options) {
|
|
@@ -23,6 +23,11 @@ function createTailorKitFetchClient(options) {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// src/client/apps.ts
|
|
27
|
+
function matchesApp(app, scopes, appIds) {
|
|
28
|
+
return (scopes === void 0 || app.scope !== void 0 && scopes.includes(app.scope.name)) && (appIds === void 0 || appIds.includes(app.id));
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
// src/client/scope-query.ts
|
|
27
32
|
function appendScopeSelection(url, scopes) {
|
|
28
33
|
if (scopes === void 0) {
|
|
@@ -46,6 +51,7 @@ function normalizeScopeSelection(scopes) {
|
|
|
46
51
|
|
|
47
52
|
export {
|
|
48
53
|
createTailorKitFetchClient,
|
|
54
|
+
matchesApp,
|
|
49
55
|
appendScopeSelection,
|
|
50
56
|
normalizeScopeSelection
|
|
51
57
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/store/local/node-store.ts
|
|
2
|
-
import {
|
|
2
|
+
import { atom, computed } from "nanostores";
|
|
3
3
|
var childIds = (children) => children.map((c) => c.id).join(",");
|
|
4
4
|
var nodeSignature = (node) => {
|
|
5
5
|
if (node.kind === "text") {
|
|
@@ -22,14 +22,14 @@ var flattenTree = (node, out) => {
|
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
var NodeStore = class {
|
|
25
|
-
state =
|
|
25
|
+
state = atom({ nodes: /* @__PURE__ */ new Map(), rootId: null });
|
|
26
26
|
signatures = /* @__PURE__ */ new Map();
|
|
27
27
|
clear() {
|
|
28
28
|
this.signatures.clear();
|
|
29
|
-
this.state.
|
|
29
|
+
this.state.set({ nodes: /* @__PURE__ */ new Map(), rootId: null });
|
|
30
30
|
}
|
|
31
31
|
setSnapshot(tree) {
|
|
32
|
-
const previous = this.state.
|
|
32
|
+
const previous = this.state.get();
|
|
33
33
|
const next = /* @__PURE__ */ new Map();
|
|
34
34
|
flattenTree(tree, next);
|
|
35
35
|
let changed = previous.rootId !== tree.id || previous.nodes.size !== next.size;
|
|
@@ -49,31 +49,31 @@ var NodeStore = class {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
if (changed) {
|
|
52
|
-
this.state.
|
|
52
|
+
this.state.set({ nodes: next, rootId: tree.id });
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
getRootId() {
|
|
56
|
-
return this.state.
|
|
56
|
+
return this.state.get().rootId;
|
|
57
57
|
}
|
|
58
58
|
getNode(id) {
|
|
59
|
-
return this.state.
|
|
59
|
+
return this.state.get().nodes.get(id) ?? null;
|
|
60
60
|
}
|
|
61
61
|
subscribe(id, listener) {
|
|
62
|
-
const node =
|
|
63
|
-
return node.
|
|
62
|
+
const node = computed(this.state, (snapshot) => snapshot.nodes.get(id) ?? null);
|
|
63
|
+
return node.listen(listener);
|
|
64
64
|
}
|
|
65
65
|
subscribeRoot(listener) {
|
|
66
|
-
const root =
|
|
67
|
-
return root.
|
|
66
|
+
const root = computed(this.state, (snapshot) => snapshot.rootId);
|
|
67
|
+
return root.listen(listener);
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
// src/store/local/view-registry.ts
|
|
72
|
-
import {
|
|
72
|
+
import { atom as atom2 } from "nanostores";
|
|
73
73
|
import { getViewDepth, isViewAncestor } from "@tailorkit/core/views";
|
|
74
74
|
function createViewRegistry() {
|
|
75
75
|
const entries = /* @__PURE__ */ new Map();
|
|
76
|
-
const state =
|
|
76
|
+
const state = atom2(null);
|
|
77
77
|
let nextOrder = 0;
|
|
78
78
|
let scheduled = false;
|
|
79
79
|
const publish = () => {
|
|
@@ -98,19 +98,19 @@ function createViewRegistry() {
|
|
|
98
98
|
)}. TailorKit selected "${selected.view}" by mount order. Only one route at a hierarchy depth should register a view.`
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
|
-
state.
|
|
101
|
+
state.set({
|
|
102
102
|
view: selected.view,
|
|
103
103
|
layers: ordered.filter((entry) => isViewAncestor(entry.view, selected.view)).toReversed().map((entry) => ({ path: entry.view, context: entry.context, status: entry.status }))
|
|
104
|
-
})
|
|
104
|
+
});
|
|
105
105
|
} else {
|
|
106
|
-
state.
|
|
106
|
+
state.set(null);
|
|
107
107
|
}
|
|
108
108
|
});
|
|
109
109
|
};
|
|
110
110
|
return {
|
|
111
111
|
state,
|
|
112
|
-
getSnapshot: () => state.
|
|
113
|
-
subscribe: (listener) => state.
|
|
112
|
+
getSnapshot: () => state.get(),
|
|
113
|
+
subscribe: (listener) => state.listen(listener),
|
|
114
114
|
register(entry) {
|
|
115
115
|
entries.set(entry.id, { ...entry, order: entries.get(entry.id)?.order ?? nextOrder++ });
|
|
116
116
|
publish();
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createEndpointClient,
|
|
3
|
-
listViews,
|
|
4
3
|
resolveSlotView
|
|
5
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RNTQ3LLF.js";
|
|
6
5
|
|
|
7
6
|
// src/store/fetch/apps.ts
|
|
8
|
-
import {
|
|
7
|
+
import { atom } from "nanostores";
|
|
9
8
|
function createAppsStore(client, initialApps) {
|
|
10
9
|
const query = client.apps();
|
|
11
|
-
const provided =
|
|
10
|
+
const provided = atom(initialApps);
|
|
12
11
|
const suppliedSnapshot = (apps) => ({
|
|
13
12
|
apps,
|
|
14
|
-
views: listViews(apps),
|
|
15
13
|
error: null,
|
|
16
14
|
status: "ready",
|
|
17
15
|
isFetching: false
|
|
@@ -21,8 +19,6 @@ function createAppsStore(client, initialApps) {
|
|
|
21
19
|
let snapshot;
|
|
22
20
|
let requested = false;
|
|
23
21
|
let subscribers = 0;
|
|
24
|
-
let lastApps;
|
|
25
|
-
let views = [];
|
|
26
22
|
const empty2 = [];
|
|
27
23
|
const store = {
|
|
28
24
|
getSnapshot() {
|
|
@@ -30,13 +26,8 @@ function createAppsStore(client, initialApps) {
|
|
|
30
26
|
const current = query.getSnapshot();
|
|
31
27
|
if (current !== last) {
|
|
32
28
|
const apps = current.data ?? empty2;
|
|
33
|
-
if (apps !== lastApps) {
|
|
34
|
-
views = listViews(apps);
|
|
35
|
-
lastApps = apps;
|
|
36
|
-
}
|
|
37
29
|
snapshot = {
|
|
38
30
|
apps,
|
|
39
|
-
views,
|
|
40
31
|
error: current.error,
|
|
41
32
|
status: current.status,
|
|
42
33
|
isFetching: current.isFetching
|
|
@@ -47,7 +38,7 @@ function createAppsStore(client, initialApps) {
|
|
|
47
38
|
},
|
|
48
39
|
subscribe(listener) {
|
|
49
40
|
subscribers += 1;
|
|
50
|
-
const stopProvided = provided.
|
|
41
|
+
const stopProvided = provided.listen(listener);
|
|
51
42
|
const stopQuery = query.subscribe(() => {
|
|
52
43
|
if (!supplied) listener();
|
|
53
44
|
});
|
|
@@ -68,9 +59,9 @@ function createAppsStore(client, initialApps) {
|
|
|
68
59
|
return requested ? store.fetch({ force: true }) : Promise.resolve();
|
|
69
60
|
},
|
|
70
61
|
setProvidedApps(apps) {
|
|
71
|
-
if (provided.
|
|
62
|
+
if (provided.get() === apps) return;
|
|
72
63
|
supplied = apps === void 0 ? null : suppliedSnapshot(apps);
|
|
73
|
-
provided.
|
|
64
|
+
provided.set(apps);
|
|
74
65
|
if (!supplied && requested && subscribers) void store.fetch({ force: true });
|
|
75
66
|
},
|
|
76
67
|
updateViews(appId, appViews) {
|
|
@@ -116,7 +107,7 @@ function createMetadataStore(client) {
|
|
|
116
107
|
}
|
|
117
108
|
|
|
118
109
|
// src/store/fetch/preview-manager.ts
|
|
119
|
-
import {
|
|
110
|
+
import { atom as atom2, batch } from "nanostores";
|
|
120
111
|
import { createPreviewWebSocketClient } from "@tailorkit/client-platform/preview";
|
|
121
112
|
var empty = { revision: 0, source: null };
|
|
122
113
|
function viewerTokenExpiresAt(metadata) {
|
|
@@ -176,7 +167,7 @@ function createPreviewManager(baseUrl, onEnded, onViews, refreshMetadata = creat
|
|
|
176
167
|
const end = (entry) => {
|
|
177
168
|
close(entry);
|
|
178
169
|
entry.metadata = null;
|
|
179
|
-
entry.state.
|
|
170
|
+
entry.state.set(empty);
|
|
180
171
|
onEnded();
|
|
181
172
|
};
|
|
182
173
|
const handleEvent = async (entry, event) => {
|
|
@@ -184,7 +175,7 @@ function createPreviewManager(baseUrl, onEnded, onViews, refreshMetadata = creat
|
|
|
184
175
|
end(entry);
|
|
185
176
|
return;
|
|
186
177
|
}
|
|
187
|
-
if (event.revision <= entry.state.
|
|
178
|
+
if (event.revision <= entry.state.get().revision) {
|
|
188
179
|
return;
|
|
189
180
|
}
|
|
190
181
|
if (event.type === "begin") {
|
|
@@ -216,9 +207,9 @@ function createPreviewManager(baseUrl, onEnded, onViews, refreshMetadata = creat
|
|
|
216
207
|
}
|
|
217
208
|
if (event.type === "complete") {
|
|
218
209
|
const source = await verify(candidate);
|
|
219
|
-
if (source !== null && entry.candidate === candidate && candidate.revision > entry.state.
|
|
210
|
+
if (source !== null && entry.candidate === candidate && candidate.revision > entry.state.get().revision) {
|
|
220
211
|
batch(() => {
|
|
221
|
-
entry.state.
|
|
212
|
+
entry.state.set({ revision: candidate.revision, source });
|
|
222
213
|
if (candidate.manifest.views !== void 0)
|
|
223
214
|
onViews?.(entry.app.id, candidate.manifest.views);
|
|
224
215
|
});
|
|
@@ -285,7 +276,7 @@ function createPreviewManager(baseUrl, onEnded, onViews, refreshMetadata = creat
|
|
|
285
276
|
});
|
|
286
277
|
};
|
|
287
278
|
return {
|
|
288
|
-
getSnapshot: (sessionId) => entries.get(sessionId)?.state.
|
|
279
|
+
getSnapshot: (sessionId) => entries.get(sessionId)?.state.get() ?? empty,
|
|
289
280
|
updateApp: (app) => {
|
|
290
281
|
const sessionId = app.preview?.sessionId;
|
|
291
282
|
const entry = sessionId && entries.get(sessionId);
|
|
@@ -306,7 +297,7 @@ function createPreviewManager(baseUrl, onEnded, onViews, refreshMetadata = creat
|
|
|
306
297
|
metadata: null,
|
|
307
298
|
candidate: null,
|
|
308
299
|
subscribers: 0,
|
|
309
|
-
state:
|
|
300
|
+
state: atom2(empty),
|
|
310
301
|
socket: null,
|
|
311
302
|
connecting: false,
|
|
312
303
|
reconnect: null,
|
|
@@ -317,7 +308,7 @@ function createPreviewManager(baseUrl, onEnded, onViews, refreshMetadata = creat
|
|
|
317
308
|
entry.app = app;
|
|
318
309
|
entry.subscribers += 1;
|
|
319
310
|
const current = entry;
|
|
320
|
-
const
|
|
311
|
+
const unsubscribe = current.state.listen(listener);
|
|
321
312
|
void connect(entry);
|
|
322
313
|
let active = true;
|
|
323
314
|
return () => {
|
|
@@ -341,8 +332,8 @@ function createPreviewManager(baseUrl, onEnded, onViews, refreshMetadata = creat
|
|
|
341
332
|
};
|
|
342
333
|
}
|
|
343
334
|
|
|
344
|
-
// src/store/fetch/slot
|
|
345
|
-
function
|
|
335
|
+
// src/store/fetch/slot.ts
|
|
336
|
+
function createSlotStore(client, options) {
|
|
346
337
|
const {
|
|
347
338
|
apps,
|
|
348
339
|
slot,
|
|
@@ -352,7 +343,7 @@ function createSlotInstancesStore(client, options) {
|
|
|
352
343
|
appsStatus = "ready",
|
|
353
344
|
appsError = null
|
|
354
345
|
} = options;
|
|
355
|
-
const enabled = appsStatus === "ready"
|
|
346
|
+
const enabled = appsStatus === "ready";
|
|
356
347
|
const settings = {
|
|
357
348
|
...staleTime === void 0 ? {} : { staleTime },
|
|
358
349
|
...gcTime === void 0 ? {} : { gcTime }
|
|
@@ -360,14 +351,14 @@ function createSlotInstancesStore(client, options) {
|
|
|
360
351
|
const waiting = {
|
|
361
352
|
data: void 0,
|
|
362
353
|
error: appsStatus === "error" ? appsError : null,
|
|
363
|
-
status: appsStatus
|
|
354
|
+
status: appsStatus,
|
|
364
355
|
isFetching: false
|
|
365
356
|
};
|
|
366
357
|
const query = client.cache.getStore(
|
|
367
|
-
["tailorkit", client.baseUrl.toString(), "
|
|
358
|
+
["tailorkit", client.baseUrl.toString(), "slot", apps, slot, activeView],
|
|
368
359
|
async (signal) => {
|
|
369
360
|
const candidates = apps.filter(
|
|
370
|
-
(app) => app.views?.some((view) => view.slot === slot &&
|
|
361
|
+
(app) => app.views?.some((view) => view.slot === slot && !view.disabled)
|
|
371
362
|
);
|
|
372
363
|
if (!candidates.length) return { status: "ready", data: [] };
|
|
373
364
|
const meta = client.meta();
|
|
@@ -377,8 +368,19 @@ function createSlotInstancesStore(client, options) {
|
|
|
377
368
|
if (snapshot2.error) throw snapshot2.error;
|
|
378
369
|
if (!snapshot2.data) throw new Error("TailorKit metadata is unavailable.");
|
|
379
370
|
const schema = snapshot2.data.schema;
|
|
380
|
-
|
|
381
|
-
|
|
371
|
+
const definition = schema.slots[slot];
|
|
372
|
+
if (!definition) return { status: "ready", data: [] };
|
|
373
|
+
if (definition.multiple !== true) {
|
|
374
|
+
return {
|
|
375
|
+
status: "ready",
|
|
376
|
+
data: candidates.filter(
|
|
377
|
+
(app) => app.views?.some(
|
|
378
|
+
(view) => view.slot === slot && !view.disabled && !view.instances && definition.views.includes(view.path)
|
|
379
|
+
)
|
|
380
|
+
).map((app) => ({ app }))
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
if (activeView === null) return { status: "idle" };
|
|
382
384
|
const matches = candidates.flatMap((app) => {
|
|
383
385
|
const resolved = resolveSlotView(app.views ?? [], slot, activeView, schema);
|
|
384
386
|
return resolved?.instances ? [{ app, resolved }] : [];
|
|
@@ -411,7 +413,7 @@ function createSlotInstancesStore(client, options) {
|
|
|
411
413
|
signal.removeEventListener("abort", abort);
|
|
412
414
|
}
|
|
413
415
|
},
|
|
414
|
-
{ ...client.cacheOptions?.
|
|
416
|
+
{ ...client.cacheOptions?.slot, ...settings, abortOnUnsubscribe: true }
|
|
415
417
|
);
|
|
416
418
|
let last;
|
|
417
419
|
let snapshot;
|
|
@@ -441,5 +443,5 @@ export {
|
|
|
441
443
|
createAppsStore,
|
|
442
444
|
createMetadataStore,
|
|
443
445
|
createPreviewManager,
|
|
444
|
-
|
|
446
|
+
createSlotStore
|
|
445
447
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/store/fetch/cache.ts
|
|
2
|
-
import {
|
|
2
|
+
import { atom } from "nanostores";
|
|
3
3
|
var idle = () => ({
|
|
4
4
|
data: void 0,
|
|
5
5
|
error: null,
|
|
@@ -30,7 +30,7 @@ function createFetchCache(defaults = {}) {
|
|
|
30
30
|
entry.invalidated = false;
|
|
31
31
|
if (entry.timer) clearTimeout(entry.timer);
|
|
32
32
|
entry.timer = null;
|
|
33
|
-
entry.state.
|
|
33
|
+
entry.state.set(idle());
|
|
34
34
|
};
|
|
35
35
|
const scheduleGc = (key, entry) => {
|
|
36
36
|
if (entry.timer) clearTimeout(entry.timer);
|
|
@@ -63,7 +63,7 @@ function createFetchCache(defaults = {}) {
|
|
|
63
63
|
let entry = entries.get(key);
|
|
64
64
|
if (!entry) {
|
|
65
65
|
entry = {
|
|
66
|
-
state:
|
|
66
|
+
state: atom(idle()),
|
|
67
67
|
controller: null,
|
|
68
68
|
pending: null,
|
|
69
69
|
observers: 0,
|
|
@@ -82,13 +82,13 @@ function createFetchCache(defaults = {}) {
|
|
|
82
82
|
return entry;
|
|
83
83
|
};
|
|
84
84
|
const store = {
|
|
85
|
-
getSnapshot: () => getEntry().state.
|
|
85
|
+
getSnapshot: () => getEntry().state.get(),
|
|
86
86
|
subscribe(listener) {
|
|
87
87
|
const entry = getEntry();
|
|
88
88
|
if (entry.timer) clearTimeout(entry.timer);
|
|
89
89
|
entry.timer = null;
|
|
90
90
|
entry.observers += 1;
|
|
91
|
-
const
|
|
91
|
+
const unsubscribe = entry.state.listen(listener);
|
|
92
92
|
let active = true;
|
|
93
93
|
return () => {
|
|
94
94
|
if (!active) return;
|
|
@@ -100,11 +100,12 @@ function createFetchCache(defaults = {}) {
|
|
|
100
100
|
entry.controller?.abort();
|
|
101
101
|
entry.controller = null;
|
|
102
102
|
entry.pending = null;
|
|
103
|
-
entry.state.
|
|
103
|
+
const previous = entry.state.get();
|
|
104
|
+
entry.state.set({
|
|
104
105
|
...previous,
|
|
105
106
|
status: previous.data === void 0 ? "idle" : "ready",
|
|
106
107
|
isFetching: false
|
|
107
|
-
})
|
|
108
|
+
});
|
|
108
109
|
}
|
|
109
110
|
scheduleGc(key, entry);
|
|
110
111
|
};
|
|
@@ -112,7 +113,7 @@ function createFetchCache(defaults = {}) {
|
|
|
112
113
|
fetch(settings = {}) {
|
|
113
114
|
const entry = getEntry();
|
|
114
115
|
if (entry.pending && !settings.force) return entry.pending;
|
|
115
|
-
const snapshot = entry.state.
|
|
116
|
+
const snapshot = entry.state.get();
|
|
116
117
|
const age = Date.now() - snapshot.updatedAt;
|
|
117
118
|
if (!settings.force && !entry.invalidated && snapshot.status === "ready" && age < duration(settings.staleTime, freshness))
|
|
118
119
|
return Promise.resolve();
|
|
@@ -127,21 +128,21 @@ function createFetchCache(defaults = {}) {
|
|
|
127
128
|
const data = await fetcher(controller.signal);
|
|
128
129
|
if (entry.generation !== generation) return;
|
|
129
130
|
entry.invalidated = false;
|
|
130
|
-
entry.state.
|
|
131
|
+
entry.state.set({
|
|
131
132
|
data,
|
|
132
133
|
error: null,
|
|
133
134
|
status: "ready",
|
|
134
135
|
isFetching: false,
|
|
135
136
|
updatedAt: Date.now()
|
|
136
|
-
})
|
|
137
|
+
});
|
|
137
138
|
} catch (error) {
|
|
138
139
|
if (entry.generation !== generation) return;
|
|
139
|
-
entry.state.
|
|
140
|
-
...
|
|
140
|
+
entry.state.set({
|
|
141
|
+
...entry.state.get(),
|
|
141
142
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
142
143
|
status: "error",
|
|
143
144
|
isFetching: false
|
|
144
|
-
})
|
|
145
|
+
});
|
|
145
146
|
} finally {
|
|
146
147
|
if (entry.generation === generation) {
|
|
147
148
|
entry.controller = null;
|
|
@@ -157,12 +158,13 @@ function createFetchCache(defaults = {}) {
|
|
|
157
158
|
};
|
|
158
159
|
});
|
|
159
160
|
entry.pending = pending;
|
|
160
|
-
entry.state.
|
|
161
|
+
const previous = entry.state.get();
|
|
162
|
+
entry.state.set({
|
|
161
163
|
...previous,
|
|
162
164
|
error: null,
|
|
163
165
|
status: previous.data === void 0 ? "loading" : "ready",
|
|
164
166
|
isFetching: true
|
|
165
|
-
})
|
|
167
|
+
});
|
|
166
168
|
start();
|
|
167
169
|
return pending;
|
|
168
170
|
},
|
|
@@ -173,13 +175,13 @@ function createFetchCache(defaults = {}) {
|
|
|
173
175
|
entry.controller = null;
|
|
174
176
|
entry.pending = null;
|
|
175
177
|
entry.invalidated = false;
|
|
176
|
-
entry.state.
|
|
177
|
-
data: updater(
|
|
178
|
+
entry.state.set({
|
|
179
|
+
data: updater(entry.state.get().data),
|
|
178
180
|
error: null,
|
|
179
181
|
status: "ready",
|
|
180
182
|
isFetching: false,
|
|
181
183
|
updatedAt: Date.now()
|
|
182
|
-
})
|
|
184
|
+
});
|
|
183
185
|
scheduleGc(key, entry);
|
|
184
186
|
},
|
|
185
187
|
invalidate() {
|
|
@@ -295,22 +297,6 @@ function createEndpointClient(options) {
|
|
|
295
297
|
};
|
|
296
298
|
}
|
|
297
299
|
|
|
298
|
-
// src/client/apps.ts
|
|
299
|
-
function matchesApp(app, scopes, appIds) {
|
|
300
|
-
return (scopes === void 0 || app.scope !== void 0 && scopes.includes(app.scope.name)) && (appIds === void 0 || appIds.includes(app.id));
|
|
301
|
-
}
|
|
302
|
-
function listViews(apps) {
|
|
303
|
-
return apps.flatMap(
|
|
304
|
-
(app) => (app.views ?? []).filter((view) => !view.disabled).map(({ slot, path, instances }) => ({
|
|
305
|
-
id: JSON.stringify([app.id, slot, path]),
|
|
306
|
-
...instances ? { instances } : {},
|
|
307
|
-
app,
|
|
308
|
-
slot,
|
|
309
|
-
path
|
|
310
|
-
}))
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
300
|
// src/client/slot-view.ts
|
|
315
301
|
import { composeViewContext, getViewHierarchy } from "@tailorkit/core/views";
|
|
316
302
|
function selectSlotView(views, slot, activePath, schema) {
|
|
@@ -337,8 +323,6 @@ export {
|
|
|
337
323
|
createFetchCache,
|
|
338
324
|
toBaseUrl,
|
|
339
325
|
createEndpointClient,
|
|
340
|
-
matchesApp,
|
|
341
|
-
listViews,
|
|
342
326
|
selectSlotView,
|
|
343
327
|
resolveSlotView
|
|
344
328
|
};
|
package/dist/client/apps.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import type { TailorKitApp
|
|
1
|
+
import type { TailorKitApp } from "../types";
|
|
2
2
|
export declare function matchesApp(app: TailorKitApp, scopes?: readonly string[], appIds?: readonly string[]): boolean;
|
|
3
|
-
export declare function listViews(apps: TailorKitApp[]): TailorKitView[];
|
|
@@ -2,7 +2,7 @@ import type { FetchCacheOptions } from "../store/fetch/cache";
|
|
|
2
2
|
export interface TailorKitCacheOptions extends FetchCacheOptions {
|
|
3
3
|
apps?: FetchCacheOptions;
|
|
4
4
|
meta?: FetchCacheOptions;
|
|
5
|
-
|
|
5
|
+
slot?: FetchCacheOptions;
|
|
6
6
|
}
|
|
7
7
|
export interface TailorKitFetchClientOptions {
|
|
8
8
|
baseUrl: string | URL;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -3,6 +3,6 @@ export type { EndpointClient, SlotInstancesInput, TailorKitMetadata } from "./en
|
|
|
3
3
|
export { createTailorKitFetchClient } from "./fetch-client";
|
|
4
4
|
export type { TailorKitFetchClient, TailorKitFetchClientOptions, TailorKitCacheOptions, } from "./fetch-client";
|
|
5
5
|
export { toBaseUrl } from "./url";
|
|
6
|
-
export {
|
|
6
|
+
export { matchesApp } from "./apps";
|
|
7
7
|
export { normalizeScopeSelection, appendScopeSelection } from "./scope-query";
|
|
8
8
|
export { resolveSlotView, selectSlotView } from "./slot-view";
|
package/dist/client.js
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appendScopeSelection,
|
|
3
3
|
createTailorKitFetchClient,
|
|
4
|
+
matchesApp,
|
|
4
5
|
normalizeScopeSelection
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-DPR3U4U2.js";
|
|
6
7
|
import {
|
|
7
8
|
createEndpointClient,
|
|
8
|
-
listViews,
|
|
9
|
-
matchesApp,
|
|
10
9
|
resolveSlotView,
|
|
11
10
|
selectSlotView,
|
|
12
11
|
toBaseUrl
|
|
13
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-RNTQ3LLF.js";
|
|
14
13
|
export {
|
|
15
14
|
appendScopeSelection,
|
|
16
15
|
createEndpointClient,
|
|
17
16
|
createTailorKitFetchClient,
|
|
18
|
-
listViews,
|
|
19
17
|
matchesApp,
|
|
20
18
|
normalizeScopeSelection,
|
|
21
19
|
resolveSlotView,
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appendScopeSelection,
|
|
3
3
|
createTailorKitFetchClient,
|
|
4
|
+
matchesApp,
|
|
4
5
|
normalizeScopeSelection
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-DPR3U4U2.js";
|
|
6
7
|
import {
|
|
7
8
|
createAppsStore,
|
|
8
9
|
createMetadataStore,
|
|
9
10
|
createPreviewManager,
|
|
10
|
-
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
createSlotStore
|
|
12
|
+
} from "./chunk-K3QITWU4.js";
|
|
12
13
|
import {
|
|
13
14
|
createEndpointClient,
|
|
14
15
|
createFetchCache,
|
|
15
|
-
listViews,
|
|
16
|
-
matchesApp,
|
|
17
16
|
resolveSlotView,
|
|
18
17
|
selectSlotView,
|
|
19
18
|
serializeCacheKey,
|
|
20
19
|
toBaseUrl
|
|
21
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-RNTQ3LLF.js";
|
|
22
21
|
import {
|
|
23
22
|
NodeStore,
|
|
24
23
|
createViewRegistry
|
|
25
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-ED3BWTXG.js";
|
|
26
25
|
|
|
27
26
|
// src/store/store.ts
|
|
28
27
|
function createTailorKitStore(baseUrl, initialApps, client = createTailorKitFetchClient({ baseUrl })) {
|
|
@@ -61,11 +60,10 @@ export {
|
|
|
61
60
|
createFetchCache,
|
|
62
61
|
createMetadataStore,
|
|
63
62
|
createPreviewManager,
|
|
64
|
-
|
|
63
|
+
createSlotStore,
|
|
65
64
|
createTailorKitFetchClient,
|
|
66
65
|
createTailorKitStore,
|
|
67
66
|
createViewRegistry,
|
|
68
|
-
listViews,
|
|
69
67
|
matchesApp,
|
|
70
68
|
normalizeScopeSelection,
|
|
71
69
|
resolveSlotView,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { TailorKitFetchClient } from "../../client/fetch-client";
|
|
2
|
-
import type { TailorKitApp
|
|
2
|
+
import type { TailorKitApp } from "../../types";
|
|
3
3
|
import type { FetchOptions, FetchSnapshot } from "./cache";
|
|
4
4
|
export interface TailorKitAppsSnapshot {
|
|
5
5
|
apps: TailorKitApp[];
|
|
6
|
-
views: TailorKitView[];
|
|
7
6
|
error: Error | null;
|
|
8
7
|
status: FetchSnapshot<unknown>["status"];
|
|
9
8
|
isFetching: boolean;
|
|
@@ -14,7 +14,7 @@ export interface FetchSnapshot<T> {
|
|
|
14
14
|
export interface FetchOptions extends Pick<FetchCacheOptions, "staleTime"> {
|
|
15
15
|
force?: boolean;
|
|
16
16
|
}
|
|
17
|
-
/** Framework-neutral contract; adapters need not depend on
|
|
17
|
+
/** Framework-neutral contract; adapters need not depend on the state library. */
|
|
18
18
|
export interface FetchStore<T> {
|
|
19
19
|
getSnapshot: () => FetchSnapshot<T>;
|
|
20
20
|
subscribe: (listener: () => void) => () => void;
|
|
@@ -6,5 +6,5 @@ export { createMetadataStore } from "./meta";
|
|
|
6
6
|
export type { TailorKitMetaSnapshot } from "./meta";
|
|
7
7
|
export { createPreviewManager } from "./preview-manager";
|
|
8
8
|
export type { PreviewSnapshot } from "./preview-manager";
|
|
9
|
-
export {
|
|
10
|
-
export type {
|
|
9
|
+
export { createSlotStore } from "./slot";
|
|
10
|
+
export type { SlotItem, SlotSnapshot, SlotStoreOptions } from "./slot";
|
|
@@ -3,26 +3,30 @@ import type { ActiveView } from "@tailorkit/core/views";
|
|
|
3
3
|
import type { TailorKitFetchClient } from "../../client/fetch-client";
|
|
4
4
|
import type { TailorKitApp } from "../../types";
|
|
5
5
|
import type { FetchCacheOptions, FetchOptions, FetchSnapshot } from "./cache";
|
|
6
|
-
|
|
6
|
+
interface SingleSlotItem {
|
|
7
7
|
app: TailorKitApp;
|
|
8
8
|
}
|
|
9
|
-
export
|
|
9
|
+
export type SlotItem<TMultiple extends boolean = boolean> = TMultiple extends true ? ViewInstance & {
|
|
10
|
+
app: TailorKitApp;
|
|
11
|
+
} : SingleSlotItem;
|
|
12
|
+
export interface SlotStoreOptions extends FetchCacheOptions {
|
|
10
13
|
apps: TailorKitApp[];
|
|
11
14
|
slot: string;
|
|
12
15
|
activeView: ActiveView | null;
|
|
13
16
|
appsStatus?: FetchSnapshot<unknown>["status"];
|
|
14
17
|
appsError?: Error | null;
|
|
15
18
|
}
|
|
16
|
-
export interface
|
|
17
|
-
data:
|
|
19
|
+
export interface SlotSnapshot {
|
|
20
|
+
data: SlotItem[] | undefined;
|
|
18
21
|
error: Error | null;
|
|
19
22
|
status: FetchSnapshot<unknown>["status"];
|
|
20
23
|
isFetching: boolean;
|
|
21
24
|
}
|
|
22
25
|
/** Match all app contexts before authorizing any app or sending instance requests. */
|
|
23
|
-
export declare function
|
|
24
|
-
getSnapshot():
|
|
26
|
+
export declare function createSlotStore(client: TailorKitFetchClient, options: SlotStoreOptions): {
|
|
27
|
+
getSnapshot(): SlotSnapshot;
|
|
25
28
|
subscribe: (listener: () => void) => () => void;
|
|
26
29
|
fetch: (fetchOptions?: FetchOptions) => Promise<void>;
|
|
27
30
|
invalidate: () => Promise<void>;
|
|
28
31
|
};
|
|
32
|
+
export {};
|
|
@@ -5,7 +5,7 @@ export interface NodeSnapshot {
|
|
|
5
5
|
rootId: string | null;
|
|
6
6
|
}
|
|
7
7
|
export declare class NodeStore {
|
|
8
|
-
readonly state: import("
|
|
8
|
+
readonly state: import("nanostores").PreinitializedWritableAtom<NodeSnapshot> & object;
|
|
9
9
|
private signatures;
|
|
10
10
|
clear(): void;
|
|
11
11
|
setSnapshot(tree: RemoteNode): void;
|
|
@@ -7,7 +7,7 @@ export interface ViewEntry {
|
|
|
7
7
|
order: number;
|
|
8
8
|
}
|
|
9
9
|
export declare function createViewRegistry(): {
|
|
10
|
-
state: import("
|
|
10
|
+
state: import("nanostores").PreinitializedWritableAtom<ActiveView | null> & object;
|
|
11
11
|
getSnapshot: () => ActiveView | null;
|
|
12
12
|
subscribe: (listener: () => void) => (() => void);
|
|
13
13
|
register(entry: Omit<ViewEntry, "order">): void;
|
package/dist/store/store.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export declare function createTailorKitStore(baseUrl: string | URL, initialApps?
|
|
|
46
46
|
};
|
|
47
47
|
};
|
|
48
48
|
views: {
|
|
49
|
-
state: import("
|
|
49
|
+
state: import("nanostores").PreinitializedWritableAtom<import("@tailorkit/core/views").ActiveView | null> & object;
|
|
50
50
|
getSnapshot: () => import("@tailorkit/core/views").ActiveView | null;
|
|
51
51
|
subscribe: (listener: () => void) => (() => void);
|
|
52
52
|
register(entry: Omit<import("./local").ViewEntry, "order">): void;
|
package/dist/store-fetch.js
CHANGED
|
@@ -2,17 +2,17 @@ import {
|
|
|
2
2
|
createAppsStore,
|
|
3
3
|
createMetadataStore,
|
|
4
4
|
createPreviewManager,
|
|
5
|
-
|
|
6
|
-
} from "./chunk-
|
|
5
|
+
createSlotStore
|
|
6
|
+
} from "./chunk-K3QITWU4.js";
|
|
7
7
|
import {
|
|
8
8
|
createFetchCache,
|
|
9
9
|
serializeCacheKey
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-RNTQ3LLF.js";
|
|
11
11
|
export {
|
|
12
12
|
createAppsStore,
|
|
13
13
|
createFetchCache,
|
|
14
14
|
createMetadataStore,
|
|
15
15
|
createPreviewManager,
|
|
16
|
-
|
|
16
|
+
createSlotStore,
|
|
17
17
|
serializeCacheKey
|
|
18
18
|
};
|
package/dist/store-local.js
CHANGED
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailorkit/client-core",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.22",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@tailorkit/app": "0.1.0-beta.
|
|
38
|
-
"@tailorkit/client-platform": "0.1.0-beta.
|
|
39
|
-
"@tailorkit/core": "0.1.0-beta.
|
|
40
|
-
"@tailorkit/sandbox": "0.1.0-beta.
|
|
41
|
-
"
|
|
37
|
+
"@tailorkit/app": "0.1.0-beta.22",
|
|
38
|
+
"@tailorkit/client-platform": "0.1.0-beta.22",
|
|
39
|
+
"@tailorkit/core": "0.1.0-beta.22",
|
|
40
|
+
"@tailorkit/sandbox": "0.1.0-beta.22",
|
|
41
|
+
"nanostores": "1.5.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@tailorkit/config": "0.0.0",
|