@tailorkit/client-core 0.1.0-beta.22 → 0.1.0-beta.24

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.
Files changed (35) hide show
  1. package/dist/{chunk-RNTQ3LLF.js → chunk-BLDTSDUG.js} +195 -123
  2. package/dist/{chunk-K3QITWU4.js → chunk-CWDPTXSZ.js} +22 -113
  3. package/dist/chunk-FUBKKH3Q.js +96 -0
  4. package/dist/chunk-LNGQREZV.js +79 -0
  5. package/dist/chunk-N4X53WS2.js +669 -0
  6. package/dist/chunk-QWOVC765.js +222 -0
  7. package/dist/client/config.d.ts +66 -0
  8. package/dist/client/index.d.ts +7 -0
  9. package/dist/client/primitive-css.d.ts +10 -0
  10. package/dist/client/slot-types.d.ts +61 -0
  11. package/dist/client/value-memo.d.ts +2 -0
  12. package/dist/client/views.d.ts +8 -0
  13. package/dist/client.js +24 -6
  14. package/dist/index.js +48 -16
  15. package/dist/store/fetch/apps.d.ts +1 -0
  16. package/dist/store/fetch/cache.d.ts +3 -1
  17. package/dist/store/fetch/meta.d.ts +1 -0
  18. package/dist/store/fetch/preview-manager.d.ts +1 -0
  19. package/dist/store/fetch/slot.d.ts +1 -0
  20. package/dist/store/index.d.ts +2 -0
  21. package/dist/store/local/index.d.ts +7 -2
  22. package/dist/store/local/node-store.d.ts +2 -0
  23. package/dist/store/local/remote-view.d.ts +31 -0
  24. package/dist/store/local/slot-runtime.d.ts +36 -0
  25. package/dist/store/local/view-context-diagnostics.d.ts +10 -0
  26. package/dist/store/local/view-context-types.d.ts +21 -0
  27. package/dist/store/local/{view-registry.d.ts → view-context.d.ts} +5 -2
  28. package/dist/store/query.d.ts +39 -0
  29. package/dist/store/snapshot-store.d.ts +5 -0
  30. package/dist/store/store.d.ts +4 -1
  31. package/dist/store-fetch.js +5 -4
  32. package/dist/store-local.js +11 -3
  33. package/package.json +6 -5
  34. package/dist/chunk-DPR3U4U2.js +0 -57
  35. package/dist/chunk-ED3BWTXG.js +0 -128
@@ -0,0 +1,669 @@
1
+ import {
2
+ createValueMemo,
3
+ matchesApp,
4
+ normalizeScopeSelection,
5
+ refetchViews
6
+ } from "./chunk-LNGQREZV.js";
7
+ import {
8
+ createSlotStore,
9
+ createSnapshotStore,
10
+ resolveSlotView,
11
+ selectSlotView,
12
+ serializeCacheKey,
13
+ switchStore,
14
+ toBaseUrl
15
+ } from "./chunk-BLDTSDUG.js";
16
+
17
+ // src/store/local/node-store.ts
18
+ import { atom, computed } from "nanostores";
19
+ var childIds = (children) => children.map((c) => c.id).join(",");
20
+ var nodeSignature = (node) => {
21
+ if (node.kind === "text") {
22
+ return `text:${node.text}`;
23
+ }
24
+ if (node.kind === "fragment") {
25
+ return `frag:${childIds(node.children)}`;
26
+ }
27
+ const propsStr = JSON.stringify(node.props);
28
+ const callbacksStr = (node.callbacks ?? []).map((binding) => `${binding.callback}:${binding.event}:${binding.inputCount}`).join(",");
29
+ return `elem:${node.type}|${childIds(node.children)}|${propsStr}|${callbacksStr}`;
30
+ };
31
+ var flattenTree = (node, out) => {
32
+ out.set(node.id, node);
33
+ if (node.kind === "text") {
34
+ return;
35
+ }
36
+ for (const child of node.children) {
37
+ flattenTree(child, out);
38
+ }
39
+ };
40
+ var NodeStore = class {
41
+ state = atom({ nodes: /* @__PURE__ */ new Map(), rootId: null });
42
+ root = computed(this.state, (snapshot) => snapshot.rootId);
43
+ signatures = /* @__PURE__ */ new Map();
44
+ clear() {
45
+ this.signatures.clear();
46
+ this.state.set({ nodes: /* @__PURE__ */ new Map(), rootId: null });
47
+ }
48
+ setSnapshot(tree) {
49
+ const previous = this.state.get();
50
+ const next = /* @__PURE__ */ new Map();
51
+ flattenTree(tree, next);
52
+ let changed = previous.rootId !== tree.id || previous.nodes.size !== next.size;
53
+ for (const [id, node] of next) {
54
+ const signature = nodeSignature(node);
55
+ const previousNode = previous.nodes.get(id);
56
+ if (previousNode && this.signatures.get(id) === signature) {
57
+ next.set(id, previousNode);
58
+ } else {
59
+ changed = true;
60
+ this.signatures.set(id, signature);
61
+ }
62
+ }
63
+ for (const id of this.signatures.keys()) {
64
+ if (!next.has(id)) {
65
+ this.signatures.delete(id);
66
+ }
67
+ }
68
+ if (changed) {
69
+ this.state.set({ nodes: next, rootId: tree.id });
70
+ }
71
+ }
72
+ getRootId() {
73
+ return this.state.get().rootId;
74
+ }
75
+ getNode(id) {
76
+ return this.state.get().nodes.get(id) ?? null;
77
+ }
78
+ selectNode(id) {
79
+ return computed(this.state, (snapshot) => snapshot.nodes.get(id) ?? null);
80
+ }
81
+ subscribe(id, listener) {
82
+ const node = this.selectNode(id);
83
+ return node.listen(listener);
84
+ }
85
+ subscribeRoot(listener) {
86
+ return this.root.listen(listener);
87
+ }
88
+ };
89
+
90
+ // src/store/local/remote-view.ts
91
+ import { atom as atom2, batch, computed as computed2 } from "nanostores";
92
+ import { createIframeUiHost } from "@tailorkit/sandbox/host";
93
+ function createRemoteViewStore(options = {}, createHost = createIframeUiHost) {
94
+ const nodes = new NodeStore();
95
+ const components = atom2(options.components ?? {});
96
+ const state = atom2({ status: "starting", error: null, generation: 0 });
97
+ let props = options.props;
98
+ let current = null;
99
+ const stop = (run) => {
100
+ if (run.stopped) return;
101
+ run.stopped = true;
102
+ if (current === run) current = null;
103
+ run.unsubscribe?.();
104
+ run.host?.destroy();
105
+ };
106
+ const reset = () => {
107
+ batch(() => {
108
+ nodes.clear();
109
+ state.set({ status: "starting", error: null, generation: state.get().generation });
110
+ });
111
+ };
112
+ return {
113
+ nodes,
114
+ components,
115
+ state,
116
+ selectComponent: (name) => computed2(components, (registry) => registry[name]),
117
+ setComponents: (registry) => components.set(registry),
118
+ setProps(next) {
119
+ props = next;
120
+ current?.host?.setProps(next);
121
+ },
122
+ dispatch(payload) {
123
+ current?.host?.dispatch(payload);
124
+ },
125
+ mount({ appUrl, ...hostOptions }) {
126
+ if (current) stop(current);
127
+ const generation = state.get().generation + 1;
128
+ batch(() => {
129
+ nodes.clear();
130
+ state.set({ status: "starting", error: null, generation });
131
+ });
132
+ const run = { host: null, unsubscribe: null, stopped: false };
133
+ current = run;
134
+ const reportError = (error) => {
135
+ if (current !== run || run.stopped) return;
136
+ console.error("TailorKit remote app failed", error);
137
+ state.set({ status: "error", error, generation });
138
+ };
139
+ try {
140
+ const host = createHost(appUrl, { ...hostOptions, props, onError: reportError });
141
+ run.host = host;
142
+ run.unsubscribe = host.subscribe(() => {
143
+ if (current !== run || run.stopped) return;
144
+ const tree = host.getSnapshot();
145
+ if (tree !== null) {
146
+ batch(() => {
147
+ nodes.setSnapshot(tree);
148
+ const previous = state.get();
149
+ if (previous.status !== "ready") {
150
+ state.set({ status: "ready", error: null, generation });
151
+ }
152
+ });
153
+ }
154
+ });
155
+ host.mount();
156
+ } catch (error) {
157
+ reportError(error instanceof Error ? error : new Error(String(error)));
158
+ stop(run);
159
+ }
160
+ return () => {
161
+ if (current !== run) return;
162
+ stop(run);
163
+ reset();
164
+ };
165
+ },
166
+ destroy() {
167
+ if (current) stop(current);
168
+ reset();
169
+ }
170
+ };
171
+ }
172
+ function createRemoteElementProps(node, dispatch) {
173
+ const props = { ...node.props };
174
+ for (const binding of node.callbacks ?? []) {
175
+ props[binding.callback] = (...args) => {
176
+ dispatch({
177
+ type: "dispatchCallback",
178
+ data: { nodeId: node.id, event: binding.event, args: args.slice(0, binding.inputCount) }
179
+ });
180
+ };
181
+ }
182
+ return props;
183
+ }
184
+
185
+ // src/store/local/view-context.ts
186
+ import { atom as atom3 } from "nanostores";
187
+ import { getViewDepth, isViewAncestor } from "@tailorkit/core/views";
188
+
189
+ // src/store/local/view-context-diagnostics.ts
190
+ import { createViewContextValidator } from "@tailorkit/core/spec";
191
+ function createViewContextDiagnostics() {
192
+ const validators = /* @__PURE__ */ new WeakMap();
193
+ return (entry, definition) => {
194
+ if (entry.status !== "ready" || !definition) return null;
195
+ const { context, view } = entry;
196
+ if (context === void 0) {
197
+ return definition.context && !definition.contextOptional ? {
198
+ message: `TailorKit view "${view}" is ready without its required context. Supply context or set loading: true while it is unavailable.`
199
+ } : null;
200
+ }
201
+ if (context === null || typeof context !== "object" || Array.isArray(context)) {
202
+ return {
203
+ message: `TailorKit view "${view}" requires an object context that matches the view's schema.`
204
+ };
205
+ }
206
+ if (!definition.context) return null;
207
+ let validation = validators.get(definition.context);
208
+ if (!validation) {
209
+ try {
210
+ validation = { validate: createViewContextValidator(definition.context) };
211
+ } catch (error) {
212
+ validation = { error };
213
+ }
214
+ validators.set(definition.context, validation);
215
+ }
216
+ if ("error" in validation) {
217
+ return {
218
+ message: `TailorKit could not validate context for view "${view}" against its JSON Schema.`,
219
+ details: validation.error
220
+ };
221
+ }
222
+ const issues = validation.validate(context);
223
+ return issues ? {
224
+ message: `TailorKit view "${view}" received context that does not match the view's schema.`,
225
+ details: issues
226
+ } : null;
227
+ };
228
+ }
229
+
230
+ // src/store/local/view-context.ts
231
+ function createViewContextStore(client) {
232
+ const entries = /* @__PURE__ */ new Map();
233
+ const state = atom3(null);
234
+ let nextOrder = 0;
235
+ let scheduled = false;
236
+ let metadataScheduled = false;
237
+ let stopMetadata = null;
238
+ const metadata = client.meta();
239
+ const diagnose = createViewContextDiagnostics();
240
+ const keys = /* @__PURE__ */ new Map();
241
+ const diagnostics = /* @__PURE__ */ new Map();
242
+ const check = (entry) => {
243
+ const definition = metadata.getSnapshot().data?.schema?.views?.[entry.view];
244
+ const diagnostic = diagnose(entry, definition);
245
+ if (!diagnostic) {
246
+ diagnostics.delete(entry.id);
247
+ return;
248
+ }
249
+ const key = JSON.stringify([entry.view, entry.context, diagnostic.message]);
250
+ if (key !== diagnostics.get(entry.id)) {
251
+ diagnostics.set(entry.id, key);
252
+ if (diagnostic.details === void 0) {
253
+ console.error(diagnostic.message);
254
+ } else {
255
+ console.error(diagnostic.message, diagnostic.details);
256
+ }
257
+ }
258
+ };
259
+ const observeMetadata = () => {
260
+ if (!stopMetadata) {
261
+ stopMetadata = metadata.subscribe(() => {
262
+ for (const entry of entries.values()) check(entry);
263
+ });
264
+ }
265
+ if (metadataScheduled) return;
266
+ metadataScheduled = true;
267
+ queueMicrotask(() => {
268
+ metadataScheduled = false;
269
+ if (entries.size > 0 && metadata.getSnapshot().status === "idle") {
270
+ void metadata.fetch();
271
+ }
272
+ });
273
+ };
274
+ const publish = () => {
275
+ if (scheduled) {
276
+ return;
277
+ }
278
+ scheduled = true;
279
+ queueMicrotask(() => {
280
+ scheduled = false;
281
+ for (const id of diagnostics.keys()) {
282
+ if (!entries.has(id)) diagnostics.delete(id);
283
+ }
284
+ const ordered = [...entries.values()].toSorted(
285
+ (a, b) => getViewDepth(b.view) - getViewDepth(a.view) || b.order - a.order
286
+ );
287
+ const selected = ordered[0];
288
+ if (selected) {
289
+ const peers = ordered.filter(
290
+ (entry) => getViewDepth(entry.view) === getViewDepth(selected.view)
291
+ );
292
+ if (peers.length > 1) {
293
+ console.warn(
294
+ `TailorKit found multiple active views at the same hierarchy depth: ${peers.toReversed().map((entry) => `"${entry.view}"`).join(
295
+ ", "
296
+ )}. TailorKit selected "${selected.view}" by mount order. Only one route at a hierarchy depth should register a view.`
297
+ );
298
+ }
299
+ state.set({
300
+ view: selected.view,
301
+ layers: ordered.filter((entry) => isViewAncestor(entry.view, selected.view)).toReversed().map((entry) => ({ path: entry.view, context: entry.context, status: entry.status }))
302
+ });
303
+ } else {
304
+ state.set(null);
305
+ }
306
+ });
307
+ };
308
+ return {
309
+ state,
310
+ getSnapshot: () => state.get(),
311
+ subscribe: (listener) => state.listen(listener),
312
+ register(input) {
313
+ const status = input.error != null ? "error" : input.loading ? "loading" : "ready";
314
+ const context = status === "ready" ? input.context : void 0;
315
+ const key = JSON.stringify({ view: input.view, context, status });
316
+ if (keys.get(input.id) === key) return;
317
+ const entry = {
318
+ id: input.id,
319
+ view: input.view,
320
+ context,
321
+ status,
322
+ order: entries.get(input.id)?.order ?? nextOrder++
323
+ };
324
+ entries.set(input.id, entry);
325
+ keys.set(input.id, key);
326
+ observeMetadata();
327
+ check(entry);
328
+ publish();
329
+ },
330
+ unregister(id) {
331
+ if (!entries.delete(id)) return;
332
+ keys.delete(id);
333
+ if (entries.size === 0) {
334
+ stopMetadata?.();
335
+ stopMetadata = null;
336
+ }
337
+ publish();
338
+ }
339
+ };
340
+ }
341
+
342
+ // src/store/local/slot-runtime.ts
343
+ import { atom as atom4 } from "nanostores";
344
+
345
+ // src/store/query.ts
346
+ import { computed as computed3 } from "nanostores";
347
+ function appsQueryKey(options) {
348
+ return serializeCacheKey([
349
+ normalizeScopeSelection(options.scopes).key,
350
+ normalizeScopeSelection(options.appIds).key
351
+ ]);
352
+ }
353
+ function result(snapshot, refetch) {
354
+ return {
355
+ data: snapshot.data,
356
+ error: snapshot.error,
357
+ status: snapshot.status,
358
+ isFetching: snapshot.isFetching,
359
+ isError: snapshot.status === "error",
360
+ isLoading: snapshot.status === "loading",
361
+ isPending: snapshot.status === "idle" || snapshot.status === "loading",
362
+ isSuccess: snapshot.status === "ready",
363
+ refetch
364
+ };
365
+ }
366
+ function createAppsQuery(store, options = {}) {
367
+ const refetch = () => store.fetchApps({ force: true });
368
+ let previous;
369
+ let snapshot;
370
+ const state = createSnapshotStore(
371
+ () => {
372
+ const current = store.fetch.apps.state.get();
373
+ if (current !== previous) {
374
+ previous = current;
375
+ snapshot = result(
376
+ {
377
+ ...current,
378
+ data: current.status === "ready" ? current.apps.filter((app) => matchesApp(app, options.scopes, options.appIds)) : void 0
379
+ },
380
+ refetch
381
+ );
382
+ }
383
+ return snapshot;
384
+ },
385
+ (listener) => {
386
+ const stop = store.fetch.apps.state.listen(listener);
387
+ void store.fetchApps();
388
+ return stop;
389
+ }
390
+ );
391
+ return { state, refetch, fetch: store.fetchApps };
392
+ }
393
+ function createViewsQuery(store, options) {
394
+ return viewsQuery(store, options);
395
+ }
396
+ function createAppViewsQuery(store, app, slot) {
397
+ return viewsQuery(store, { slot }, app);
398
+ }
399
+ function viewsQuery(store, options, app) {
400
+ let previousKey;
401
+ let previousError;
402
+ let selected;
403
+ let query;
404
+ const refetch = () => {
405
+ selection.get();
406
+ return app ? query.fetch({ force: true }) : refetchViews(store, options);
407
+ };
408
+ const selection = computed3(
409
+ [store.fetch.apps.state, store.fetch.meta.state, store.views.state],
410
+ (discovery, metadata, active) => {
411
+ const apps = app ? [app] : discovery.status === "ready" ? discovery.apps.filter(
412
+ (candidate) => matchesApp(candidate, options.scopes, options.appIds)
413
+ ) : [];
414
+ const appsStatus = app ? "ready" : discovery.status;
415
+ const appsError = app ? null : discovery.error;
416
+ const activeView = metadata.schema === null || metadata.schema.slots[options.slot]?.multiple === true ? active : null;
417
+ const key = serializeCacheKey([apps, options.slot, activeView, appsStatus]);
418
+ if (key !== previousKey || appsError !== previousError) {
419
+ previousKey = key;
420
+ previousError = appsError;
421
+ const slot = createSlotStore(store.client, {
422
+ apps,
423
+ slot: options.slot,
424
+ activeView,
425
+ appsStatus,
426
+ appsError
427
+ });
428
+ query = slot;
429
+ let last;
430
+ let fetching;
431
+ let snapshot;
432
+ selected = createSnapshotStore(
433
+ () => {
434
+ const current = slot.state.get();
435
+ const appsFetching = !app && store.fetch.apps.state.get().isFetching;
436
+ if (current !== last || fetching !== appsFetching) {
437
+ last = current;
438
+ fetching = appsFetching;
439
+ snapshot = result(
440
+ { ...current, isFetching: appsFetching || current.isFetching },
441
+ refetch
442
+ );
443
+ }
444
+ return snapshot;
445
+ },
446
+ (listener) => {
447
+ const stopSlot = slot.state.listen(listener);
448
+ const stopApps = app ? () => {
449
+ } : store.fetch.apps.state.listen(listener);
450
+ void slot.fetch();
451
+ return () => {
452
+ stopSlot();
453
+ stopApps();
454
+ };
455
+ }
456
+ );
457
+ }
458
+ return selected;
459
+ }
460
+ );
461
+ const source = switchStore(selection);
462
+ const state = createSnapshotStore(source.get, (listener) => {
463
+ const stop = source.listen(listener);
464
+ if (!app) void store.fetchApps();
465
+ return stop;
466
+ });
467
+ return { state, refetch };
468
+ }
469
+
470
+ // src/store/local/slot-runtime.ts
471
+ var hidden = { status: "hidden" };
472
+ var loading = { status: "loading", message: "Loading view\u2026" };
473
+ var failure = (message) => ({
474
+ status: "error",
475
+ error: new Error(message)
476
+ });
477
+ function createSlotRuntime(store, initial) {
478
+ const memoInput = createValueMemo();
479
+ const input = atom4(memoInput(initial));
480
+ let queryKey;
481
+ let query = null;
482
+ let previewSession;
483
+ let preview;
484
+ let previousSnapshot;
485
+ let snapshotKey;
486
+ const getQuery = () => {
487
+ const options = input.get();
488
+ if (options.mode !== "managed" || options.instanceKey === void 0 || store.views.state.get() === null)
489
+ return null;
490
+ const key = serializeCacheKey([options.app, options.name]);
491
+ if (key !== queryKey) {
492
+ queryKey = key;
493
+ query = createAppViewsQuery(store, options.app, options.name);
494
+ }
495
+ return query;
496
+ };
497
+ const getPreview = () => {
498
+ const session = input.get().app.preview?.sessionId ?? "";
499
+ if (session !== previewSession) {
500
+ previewSession = session;
501
+ preview = store.previews.getStore(() => input.get().app);
502
+ }
503
+ return preview;
504
+ };
505
+ const resolve = () => {
506
+ const options = input.get();
507
+ const { app, name } = options;
508
+ const active = store.views.state.get();
509
+ let viewState;
510
+ if (options.mode === "managed") {
511
+ if (active === null) return hidden;
512
+ viewState = active;
513
+ if (options.instanceKey !== void 0) {
514
+ const instances = getQuery().state.get();
515
+ if (instances.isPending) return loading;
516
+ if (instances.error) return { status: "error", error: instances.error };
517
+ const schema2 = store.fetch.meta.state.get().schema;
518
+ if (schema2 && schema2.slots[name]?.multiple !== true)
519
+ return failure(`Slot "${name}" does not support instances.`);
520
+ const instance = instances.data?.find(
521
+ (item) => "key" in item && item.key === options.instanceKey
522
+ );
523
+ if (!instance) return failure(`View instance "${options.instanceKey}" is unavailable.`);
524
+ const resolved = instances.isSuccess && schema2 ? resolveSlotView(app.views ?? [], name, active, schema2) : null;
525
+ if (resolved?.status !== "ready") return hidden;
526
+ viewState = {
527
+ controlled: true,
528
+ view: resolved.view,
529
+ context: resolved.context,
530
+ status: "ready",
531
+ instance: { key: instance.key, metadata: instance.metadata, data: instance.data }
532
+ };
533
+ }
534
+ } else {
535
+ viewState = {
536
+ controlled: true,
537
+ view: options.view,
538
+ status: options.status,
539
+ context: options.status === "ready" ? options.context : void 0,
540
+ ...options.status === "ready" && options.instance ? { instance: options.instance } : {}
541
+ };
542
+ if (options.status === "ready" && !options.instance && app.views?.some(
543
+ (view) => view.slot === name && view.path === options.view && view.instances && !view.disabled
544
+ )) {
545
+ return failure("A view instance is required. Pass instance to Slot.Controlled.");
546
+ }
547
+ }
548
+ const metadata = store.fetch.meta.state.get();
549
+ const source = getPreview().get();
550
+ const appUrl = app.clientPath ? new URL(app.clientPath, store.baseUrl) : metadata.assetsBaseUrl && app.projectId && app.currentDeployment?.id ? new URL(
551
+ `projects/${app.projectId}/apps/${app.id}/deployments/${app.currentDeployment.id}/client/client.js`,
552
+ toBaseUrl(metadata.assetsBaseUrl)
553
+ ) : null;
554
+ if (metadata.schema === null || appUrl === null && source.source === null) return hidden;
555
+ const schema = metadata.schema;
556
+ const multiple = schema.slots[name]?.multiple === true;
557
+ if ("controlled" in viewState && viewState.status === "ready") {
558
+ if (multiple && !viewState.instance)
559
+ return failure("A view instance is required. Pass instance to Slot.Controlled.");
560
+ if (!multiple && viewState.instance)
561
+ return failure(`Slot "${name}" does not support instances.`);
562
+ }
563
+ if (!("controlled" in viewState)) {
564
+ const selected = selectSlotView(app.views ?? [], name, viewState.view, schema);
565
+ if (selected?.instances && !multiple)
566
+ return failure(`Slot "${name}" does not support instances.`);
567
+ if (multiple) return failure("A view instance key is required. Pass instanceKey to Slot.");
568
+ }
569
+ return {
570
+ status: "render",
571
+ appUrl: (appUrl ?? new URL(`preview/${app.preview?.sessionId ?? ""}/client.js`, store.baseUrl)).toString(),
572
+ sourceText: source.source ?? void 0,
573
+ hostKey: source.revision || appUrl?.toString() || `preview/${app.preview?.sessionId ?? ""}`,
574
+ props: {
575
+ ...viewState,
576
+ slot: name,
577
+ declaredViews: Object.keys(schema.views),
578
+ supportedViews: schema.slots[name]?.views ?? []
579
+ },
580
+ getBackendSession: store.client.endpoints.getSessionProvider(app)
581
+ };
582
+ };
583
+ const state = createSnapshotStore(
584
+ () => {
585
+ const snapshot = resolve();
586
+ const key = snapshot.status === "error" ? JSON.stringify(["error", snapshot.error.message]) : JSON.stringify(snapshot);
587
+ if (key !== snapshotKey || snapshot.status === "render" && previousSnapshot?.status === "render" && snapshot.getBackendSession !== previousSnapshot.getBackendSession) {
588
+ snapshotKey = key;
589
+ previousSnapshot = snapshot;
590
+ }
591
+ return previousSnapshot;
592
+ },
593
+ (listener) => {
594
+ let active = true;
595
+ let updating = false;
596
+ let queued = false;
597
+ let requestedMetadata = false;
598
+ let observedQuery = null;
599
+ let observedPreview = null;
600
+ let stopQuery;
601
+ let stopPreview;
602
+ const refresh = () => {
603
+ if (!active) return;
604
+ if (updating) {
605
+ queued = true;
606
+ return;
607
+ }
608
+ updating = true;
609
+ do {
610
+ queued = false;
611
+ const nextQuery = getQuery();
612
+ if (nextQuery !== observedQuery) {
613
+ const stopPrevious = stopQuery;
614
+ observedQuery = nextQuery;
615
+ stopQuery = nextQuery?.state.listen(refresh);
616
+ stopPrevious?.();
617
+ }
618
+ const hasView = input.get().mode === "controlled" || store.views.state.get() !== null;
619
+ const nextPreview = hasView ? getPreview() : null;
620
+ if (nextPreview !== observedPreview) {
621
+ const stopPrevious = stopPreview;
622
+ observedPreview = nextPreview;
623
+ stopPreview = nextPreview?.listen(refresh);
624
+ stopPrevious?.();
625
+ }
626
+ if (hasView && !requestedMetadata) {
627
+ requestedMetadata = true;
628
+ void store.fetchMeta();
629
+ } else if (!hasView) {
630
+ requestedMetadata = false;
631
+ }
632
+ listener();
633
+ } while (queued && active);
634
+ updating = false;
635
+ };
636
+ const stopInput = input.listen(refresh);
637
+ const stopView = store.views.state.listen(refresh);
638
+ const stopMeta = store.fetch.meta.state.listen(refresh);
639
+ refresh();
640
+ return () => {
641
+ active = false;
642
+ stopInput();
643
+ stopView();
644
+ stopMeta();
645
+ stopQuery?.();
646
+ stopPreview?.();
647
+ };
648
+ }
649
+ );
650
+ return {
651
+ state,
652
+ setInput(options) {
653
+ store.previews.updateApp(options.app);
654
+ input.set(memoInput(options));
655
+ }
656
+ };
657
+ }
658
+
659
+ export {
660
+ createViewContextStore,
661
+ NodeStore,
662
+ createRemoteViewStore,
663
+ createRemoteElementProps,
664
+ appsQueryKey,
665
+ createAppsQuery,
666
+ createViewsQuery,
667
+ createAppViewsQuery,
668
+ createSlotRuntime
669
+ };