@lunora/svelte 1.0.0-alpha.4 → 1.0.0-alpha.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,10 +1,18 @@
1
- export { auth } from './packem_shared/auth-DLPf_bK9.mjs';
2
- export { connectionStatus } from './packem_shared/connectionStatus-CRsOMeYl.mjs';
3
- export { getLunoraClient, setLunoraClient } from './packem_shared/getLunoraClient--bwSz7F6.mjs';
4
- export { hydratePreloaded } from './packem_shared/hydratePreloaded-D5rUJdXy.mjs';
5
- export { mutation } from './packem_shared/mutation-CnDkAaLH.mjs';
6
- export { infiniteQuery, paginatedQuery } from './packem_shared/infiniteQuery-jPMQw8Vz.mjs';
7
- export { presence } from './packem_shared/presence-BQWixJ2T.mjs';
8
- export { query } from './packem_shared/query-D8Pct9Qe.mjs';
1
+ export { agent } from './packem_shared/agent-KLsxO_Uw.mjs';
2
+ export { agentChat } from './packem_shared/agentChat-BlwlNfDg.mjs';
3
+ export { agentState } from './packem_shared/agentState-DBXc_3RM.mjs';
4
+ export { agentToolEvents } from './packem_shared/agentToolEvents-qYM1CdTV.mjs';
5
+ export { auth } from './packem_shared/auth-BeYqYP9S.mjs';
6
+ export { connectionStatus } from './packem_shared/connectionStatus-BrICpw9d.mjs';
7
+ export { getLunoraClient, setLunoraClient } from './packem_shared/getLunoraClient-Prczj1gU.mjs';
8
+ export { flag, flags } from './packem_shared/flag-CqMU07WH.mjs';
9
+ export { hydratePreloaded } from './packem_shared/hydratePreloaded-Djsf_C8Q.mjs';
10
+ export { mutation } from './packem_shared/mutation-BmkCZnTd.mjs';
11
+ export { mutator } from './packem_shared/mutator-B5LchgMS.mjs';
12
+ export { infiniteQuery, paginatedQuery } from './packem_shared/infiniteQuery-Bemu7Um1.mjs';
13
+ export { presence } from './packem_shared/presence-BvChXqiB.mjs';
14
+ export { query } from './packem_shared/query-B-Gu6KQw.mjs';
9
15
  export { rateLimit } from './packem_shared/rateLimit-Cdw1kp8t.mjs';
10
- export { subscription } from './packem_shared/subscription-twuBT_Wb.mjs';
16
+ export { stream } from './packem_shared/stream-BebZbIaD.mjs';
17
+ export { subscription } from './packem_shared/subscription-COqqiMPX.mjs';
18
+ export { voiceAgent } from './packem_shared/voiceAgent-Cxib7eCK.mjs';
@@ -0,0 +1,48 @@
1
+ import { writable } from 'svelte/store';
2
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
3
+ import { mutation } from './mutation-BmkCZnTd.mjs';
4
+
5
+ const NO_MUTATION_REF = { __lunoraRef: "" };
6
+ const isClient = (value) => typeof value === "object" && value !== null && typeof value.subscribe === "function";
7
+ const createAgentHandle = (client, options) => {
8
+ const { api, cancel: cancelReference, run: runReference, runArgs, threadKey } = options;
9
+ const runMutation = mutation(client, runReference);
10
+ const cancelMutation = mutation(client, cancelReference ?? NO_MUTATION_REF);
11
+ let latestThread;
12
+ const threadStore = writable();
13
+ const statusStore = writable();
14
+ const unsubscribe = client.subscribe(api.agents.agentThread, { key: threadKey }, (value) => {
15
+ latestThread = value;
16
+ threadStore.set(latestThread);
17
+ statusStore.set(latestThread?.status);
18
+ });
19
+ const run = async (input, arguments_) => {
20
+ await runMutation.mutate({ input, threadKey, ...runArgs, ...arguments_ });
21
+ };
22
+ const cancel = async () => {
23
+ const instanceId = latestThread?.instanceId;
24
+ if (cancelReference === void 0 || instanceId === void 0) {
25
+ return;
26
+ }
27
+ await cancelMutation.mutate({ instanceId, threadKey });
28
+ };
29
+ const teardown = () => {
30
+ unsubscribe();
31
+ };
32
+ return {
33
+ cancel,
34
+ pending: runMutation.pending,
35
+ run,
36
+ status: { subscribe: statusStore.subscribe },
37
+ teardown,
38
+ thread: { subscribe: threadStore.subscribe }
39
+ };
40
+ };
41
+ function agent(clientOrOptions, maybeOptions) {
42
+ const hasExplicitClient = isClient(clientOrOptions);
43
+ const client = hasExplicitClient ? clientOrOptions : getLunoraClient();
44
+ const options = hasExplicitClient ? maybeOptions : clientOrOptions;
45
+ return createAgentHandle(client, options);
46
+ }
47
+
48
+ export { NO_MUTATION_REF, agent, isClient };
@@ -0,0 +1,138 @@
1
+ import { writable } from 'svelte/store';
2
+ import { isClient, NO_MUTATION_REF } from './agent-KLsxO_Uw.mjs';
3
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
4
+ import { mutation } from './mutation-BmkCZnTd.mjs';
5
+ import { stream } from './stream-BebZbIaD.mjs';
6
+
7
+ const NO_STREAM_REF = { __lunoraRef: "" };
8
+ const reconcileOptimistic = (optimistic, durable) => {
9
+ const durableUserRows = durable.filter((message) => message.role === "user");
10
+ const consumed = /* @__PURE__ */ new Set();
11
+ return optimistic.filter((pending) => {
12
+ for (let index = pending.durableUserCountAtSend; index < durableUserRows.length; index += 1) {
13
+ const row = durableUserRows[index];
14
+ if (row !== void 0 && !consumed.has(index) && row.content === pending.content) {
15
+ consumed.add(index);
16
+ return false;
17
+ }
18
+ }
19
+ return true;
20
+ });
21
+ };
22
+ const createAgentChatHandle = (client, options) => {
23
+ const { api, cancel: cancelReference, limit, send: sendReference, sendArgs, stream: streamReference, threadKey } = options;
24
+ const sendMutation = mutation(client, sendReference);
25
+ const cancelMutation = mutation(client, cancelReference ?? NO_MUTATION_REF);
26
+ const approvalMutation = mutation(client, api.agents.agentResolveApproval);
27
+ let latestThread;
28
+ let durable = [];
29
+ let optimistic = [];
30
+ let liveEvents = [];
31
+ let nextId = 0;
32
+ const messagesStore = writable([]);
33
+ const statusStore = writable();
34
+ const streamingTextStore = writable("");
35
+ const recompute = () => {
36
+ const visible = reconcileOptimistic(optimistic, durable);
37
+ if (visible.length === 0) {
38
+ messagesStore.set(durable);
39
+ return;
40
+ }
41
+ let maxDurableSeq = -1;
42
+ for (const message of durable) {
43
+ if (message.seq > maxDurableSeq) {
44
+ maxDurableSeq = message.seq;
45
+ }
46
+ }
47
+ messagesStore.set([
48
+ ...durable,
49
+ ...visible.map((pending, index) => {
50
+ return {
51
+ content: pending.content,
52
+ optimistic: true,
53
+ role: "user",
54
+ seq: maxDurableSeq + 1 + index
55
+ };
56
+ })
57
+ ]);
58
+ };
59
+ const recomputeStreamingText = () => {
60
+ const assistantCount = durable.filter((message) => message.role === "assistant").length;
61
+ const text = liveEvents.filter((event) => event.kind !== "progress" && event.threadKey === threadKey && event.turn >= assistantCount).map((delta) => delta.text).join("");
62
+ streamingTextStore.set(text);
63
+ };
64
+ const streamArguments = streamReference === void 0 ? "skip" : { key: threadKey };
65
+ const streamHandle = stream(client, streamReference ?? NO_STREAM_REF, streamArguments);
66
+ const unsubscribeStream = streamHandle.chunks.subscribe((value) => {
67
+ liveEvents = value;
68
+ recomputeStreamingText();
69
+ });
70
+ const historyArgs = limit === void 0 ? { key: threadKey } : { key: threadKey, limit };
71
+ const unsubscribeHistory = client.subscribe(api.agents.agentMessages, historyArgs, (value) => {
72
+ durable = value;
73
+ recompute();
74
+ recomputeStreamingText();
75
+ });
76
+ const unsubscribeThread = client.subscribe(api.agents.agentThread, { key: threadKey }, (value) => {
77
+ latestThread = value;
78
+ statusStore.set(latestThread?.status);
79
+ });
80
+ const send = async (input, arguments_) => {
81
+ const id = nextId;
82
+ nextId += 1;
83
+ const durableUserCountAtSend = durable.filter((message) => message.role === "user").length;
84
+ optimistic = [...reconcileOptimistic(optimistic, durable), { content: input, durableUserCountAtSend, id }];
85
+ recompute();
86
+ try {
87
+ await sendMutation.mutate({ input, threadKey, ...sendArgs, ...arguments_ });
88
+ } catch (error) {
89
+ optimistic = optimistic.filter((pending) => pending.id !== id);
90
+ recompute();
91
+ throw error;
92
+ }
93
+ };
94
+ const approve = async (toolCallId, note) => {
95
+ const instanceId = latestThread?.instanceId;
96
+ if (instanceId === void 0) {
97
+ throw new Error("agentChat: cannot approve — no in-flight run (thread has no instanceId)");
98
+ }
99
+ await approvalMutation.mutate({ decision: "approve", instanceId, threadKey, toolCallId, ...note === void 0 ? {} : { note } });
100
+ };
101
+ const reject = async (toolCallId, note) => {
102
+ const instanceId = latestThread?.instanceId;
103
+ if (instanceId === void 0) {
104
+ throw new Error("agentChat: cannot reject — no in-flight run (thread has no instanceId)");
105
+ }
106
+ await approvalMutation.mutate({ decision: "reject", instanceId, threadKey, toolCallId, ...note === void 0 ? {} : { note } });
107
+ };
108
+ const cancel = async () => {
109
+ const instanceId = latestThread?.instanceId;
110
+ if (cancelReference === void 0 || instanceId === void 0) {
111
+ return;
112
+ }
113
+ await cancelMutation.mutate({ instanceId, threadKey });
114
+ };
115
+ const teardown = () => {
116
+ unsubscribeHistory();
117
+ unsubscribeThread();
118
+ unsubscribeStream();
119
+ };
120
+ return {
121
+ approve,
122
+ cancel,
123
+ messages: { subscribe: messagesStore.subscribe },
124
+ reject,
125
+ send,
126
+ status: { subscribe: statusStore.subscribe },
127
+ streamingText: { subscribe: streamingTextStore.subscribe },
128
+ teardown
129
+ };
130
+ };
131
+ function agentChat(clientOrOptions, maybeOptions) {
132
+ const hasExplicitClient = isClient(clientOrOptions);
133
+ const client = hasExplicitClient ? clientOrOptions : getLunoraClient();
134
+ const options = hasExplicitClient ? maybeOptions : clientOrOptions;
135
+ return createAgentChatHandle(client, options);
136
+ }
137
+
138
+ export { agentChat };
@@ -0,0 +1,15 @@
1
+ import { derived } from 'svelte/store';
2
+ import { isClient } from './agent-KLsxO_Uw.mjs';
3
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
4
+ import { subscription } from './subscription-COqqiMPX.mjs';
5
+
6
+ function agentState(clientOrOptions, maybeOptions) {
7
+ const hasExplicitClient = isClient(clientOrOptions);
8
+ const client = hasExplicitClient ? clientOrOptions : getLunoraClient();
9
+ const options = hasExplicitClient ? maybeOptions : clientOrOptions;
10
+ const { data, error } = subscription(client, options.api.agents.agentState, { key: options.threadKey });
11
+ const state = derived(data, (value) => value);
12
+ return { error, state };
13
+ }
14
+
15
+ export { agentState };
@@ -0,0 +1,60 @@
1
+ import { derived } from 'svelte/store';
2
+ import { isClient } from './agent-KLsxO_Uw.mjs';
3
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
4
+ import { stream } from './stream-BebZbIaD.mjs';
5
+ import { subscription } from './subscription-COqqiMPX.mjs';
6
+
7
+ const NO_STREAM_REF = { __lunoraRef: "" };
8
+ const toDurableEvent = (message) => {
9
+ if (message.role === "assistant" && message.toolCalls) {
10
+ return message.toolCalls.map((call) => {
11
+ return { input: call.input, seq: message.seq, toolCallId: call.id, toolName: call.name, type: "call" };
12
+ });
13
+ }
14
+ if (message.role !== "tool") {
15
+ return void 0;
16
+ }
17
+ if (message.status === "awaiting_approval") {
18
+ return [
19
+ {
20
+ seq: message.seq,
21
+ type: "awaiting-approval",
22
+ ...message.toolCallId === void 0 ? {} : { toolCallId: message.toolCallId },
23
+ ...message.toolName === void 0 ? {} : { toolName: message.toolName }
24
+ }
25
+ ];
26
+ }
27
+ return [
28
+ {
29
+ output: message.content,
30
+ seq: message.seq,
31
+ type: "result",
32
+ ...message.status === "approved" || message.status === "rejected" ? { status: message.status } : {},
33
+ ...message.toolCallId === void 0 ? {} : { toolCallId: message.toolCallId },
34
+ ...message.toolName === void 0 ? {} : { toolName: message.toolName }
35
+ }
36
+ ];
37
+ };
38
+ function agentToolEvents(clientOrOptions, maybeOptions) {
39
+ const hasExplicitClient = isClient(clientOrOptions);
40
+ const client = hasExplicitClient ? clientOrOptions : getLunoraClient();
41
+ const options = hasExplicitClient ? maybeOptions : clientOrOptions;
42
+ const { api, limit, stream: streamReference, threadKey } = options;
43
+ const historyArgs = limit === void 0 ? { key: threadKey } : { key: threadKey, limit };
44
+ const { data } = subscription(client, api.agents.agentMessages, historyArgs);
45
+ const streamArguments = streamReference === void 0 ? "skip" : { key: threadKey };
46
+ const streamHandle = stream(client, streamReference ?? NO_STREAM_REF, streamArguments);
47
+ const events = derived([data, streamHandle.chunks], ([history, liveEvents]) => {
48
+ const durable = history ?? [];
49
+ const collected = durable.flatMap((message) => toDurableEvent(message) ?? []);
50
+ for (const event of liveEvents) {
51
+ if (event.kind === "progress" && event.threadKey === threadKey) {
52
+ collected.push({ data: event.data, toolCallId: event.toolCallId, type: "progress" });
53
+ }
54
+ }
55
+ return collected;
56
+ });
57
+ return { events };
58
+ }
59
+
60
+ export { agentToolEvents };
@@ -1,6 +1,6 @@
1
1
  import { getIdentityStore } from '@lunora/client/auth';
2
2
  import { readable } from 'svelte/store';
3
- import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
3
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
4
4
 
5
5
  const auth = (explicitClient) => {
6
6
  const client = explicitClient ?? getLunoraClient();
@@ -1,5 +1,5 @@
1
1
  import { readable } from 'svelte/store';
2
- import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
2
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
3
3
 
4
4
  const connectionStatus = (client) => {
5
5
  const resolved = client ?? getLunoraClient();
@@ -0,0 +1,56 @@
1
+ import { readable } from 'svelte/store';
2
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
3
+
4
+ const FLAGS_EVAL_PATH = "__lunora_flags__:eval";
5
+ const flagKind = (value) => {
6
+ const kind = typeof value;
7
+ if (kind === "boolean" || kind === "number" || kind === "string") {
8
+ return kind;
9
+ }
10
+ return "object";
11
+ };
12
+ const flagsReference = { __lunoraRef: FLAGS_EVAL_PATH };
13
+ const isClient = (value) => typeof value === "object" && value !== null && typeof value.subscribe === "function";
14
+ const subscribeFlag = (client, key, defaultValue, context, set) => {
15
+ try {
16
+ return client.subscribe(flagsReference, { context, default: defaultValue, key, type: flagKind(defaultValue) }, (next) => {
17
+ set(next);
18
+ });
19
+ } catch {
20
+ return () => {
21
+ };
22
+ }
23
+ };
24
+ function flag(clientOrKey, keyOrDefault, defaultOrContext, maybeContext) {
25
+ const hasExplicitClient = isClient(clientOrKey);
26
+ const client = hasExplicitClient ? clientOrKey : getLunoraClient();
27
+ const key = hasExplicitClient ? keyOrDefault : clientOrKey;
28
+ const defaultValue = hasExplicitClient ? defaultOrContext : keyOrDefault;
29
+ const context = (hasExplicitClient ? maybeContext : defaultOrContext) ?? void 0;
30
+ return readable(defaultValue, (set) => subscribeFlag(client, key, defaultValue, context, set));
31
+ }
32
+ function flags(clientOrFlags, flagsOrContext, maybeContext) {
33
+ const hasExplicitClient = isClient(clientOrFlags);
34
+ const client = hasExplicitClient ? clientOrFlags : getLunoraClient();
35
+ const flagDefaults = hasExplicitClient ? flagsOrContext : clientOrFlags;
36
+ const context = (hasExplicitClient ? maybeContext : flagsOrContext) ?? void 0;
37
+ return readable(flagDefaults, (set) => {
38
+ let current = { ...flagDefaults };
39
+ const unsubscribes = [];
40
+ for (const [key, defaultValue] of Object.entries(flagDefaults)) {
41
+ unsubscribes.push(
42
+ subscribeFlag(client, key, defaultValue, context, (next) => {
43
+ current = { ...current, [key]: next };
44
+ set(current);
45
+ })
46
+ );
47
+ }
48
+ return () => {
49
+ for (const unsubscribe of unsubscribes) {
50
+ unsubscribe();
51
+ }
52
+ };
53
+ });
54
+ }
55
+
56
+ export { flag, flags };
@@ -1,3 +1,4 @@
1
+ import { LunoraError } from '@lunora/errors';
1
2
  import { setContext, getContext } from 'svelte';
2
3
 
3
4
  const LUNORA_CONTEXT_KEY = /* @__PURE__ */ Symbol("lunora.client");
@@ -8,7 +9,7 @@ const setLunoraClient = (client) => {
8
9
  const getLunoraClient = () => {
9
10
  const client = getContext(LUNORA_CONTEXT_KEY);
10
11
  if (!client) {
11
- throw new Error("getLunoraClient(): no LunoraClient in context — call setLunoraClient(client) in an ancestor component first.");
12
+ throw new LunoraError("INTERNAL", "getLunoraClient(): no LunoraClient in context — call setLunoraClient(client) in an ancestor component first.");
12
13
  }
13
14
  return client;
14
15
  };
@@ -1,5 +1,5 @@
1
1
  import { readable } from 'svelte/store';
2
- import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
2
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
3
3
 
4
4
  const hydratePreloaded = (preloaded, client) => {
5
5
  const resolvedClient = client ?? getLunoraClient();
@@ -1,6 +1,6 @@
1
- import { initialPages, derivePaginationStatus, rebalance, applyLoadMore } from '@lunora/client/pagination';
2
- import { derived, writable, readable } from 'svelte/store';
3
- import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
1
+ import { initialPages, derivePaginationStatus, applyLoadMore, rebalance } from '@lunora/client/pagination';
2
+ import { derived, writable, readable, get } from 'svelte/store';
3
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
4
4
  import { i as isFunctionReference } from './is-function-reference-ycLAcI79.mjs';
5
5
 
6
6
  const buildPageArgs = (page, baseArgs) => {
@@ -17,23 +17,38 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
17
17
  const resultsByKey = /* @__PURE__ */ new Map();
18
18
  const activeSubs = /* @__PURE__ */ new Map();
19
19
  const pendingPageKeys = /* @__PURE__ */ new Set();
20
- let currentPages = initialPages(initialNumItems);
21
20
  const currentBaseArgs = baseArgs;
22
- pagesStore.subscribe((pages) => {
23
- currentPages = pages;
24
- });
25
21
  const rebuildPageResults = () => {
26
22
  if (currentBaseArgs === "skip") {
27
23
  pageResultsInternal.set([]);
28
24
  return;
29
25
  }
30
- const updated = currentPages.map((page) => {
26
+ const updated = get(pagesStore).map((page) => {
31
27
  const key = buildPageKey(function_["__lunoraRef"], buildPageArgs(page, currentBaseArgs));
32
28
  return resultsByKey.get(key);
33
29
  });
34
30
  pageResultsInternal.set(updated);
35
31
  };
36
- const syncSubscriptions = () => {
32
+ const migrateResultsForRebalance = (oldPages, newPages) => {
33
+ if (currentBaseArgs === "skip") {
34
+ return;
35
+ }
36
+ const keyOf = (page) => buildPageKey(function_["__lunoraRef"], buildPageArgs(page, currentBaseArgs));
37
+ for (const newPage of newPages) {
38
+ const newKey = keyOf(newPage);
39
+ if (resultsByKey.has(newKey)) {
40
+ continue;
41
+ }
42
+ const donor = oldPages.find((op) => op.lower === newPage.lower);
43
+ if (donor) {
44
+ const carried = resultsByKey.get(keyOf(donor));
45
+ if (carried) {
46
+ resultsByKey.set(newKey, carried);
47
+ }
48
+ }
49
+ }
50
+ };
51
+ const syncPass = () => {
37
52
  if (currentBaseArgs === "skip") {
38
53
  for (const unsub of activeSubs.values()) {
39
54
  unsub();
@@ -43,8 +58,9 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
43
58
  return;
44
59
  }
45
60
  const baseArgsRecord = currentBaseArgs;
61
+ const pages = get(pagesStore);
46
62
  const wantedKeys = /* @__PURE__ */ new Set();
47
- for (const page of currentPages) {
63
+ for (const page of pages) {
48
64
  wantedKeys.add(buildPageKey(function_["__lunoraRef"], buildPageArgs(page, baseArgsRecord)));
49
65
  }
50
66
  for (const [key, unsub] of activeSubs) {
@@ -52,9 +68,10 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
52
68
  unsub();
53
69
  activeSubs.delete(key);
54
70
  pendingPageKeys.delete(key);
71
+ resultsByKey.delete(key);
55
72
  }
56
73
  }
57
- for (const page of currentPages) {
74
+ for (const page of pages) {
58
75
  const pageArgs = buildPageArgs(page, baseArgsRecord);
59
76
  const key = buildPageKey(function_["__lunoraRef"], pageArgs);
60
77
  if (activeSubs.has(key)) {
@@ -69,12 +86,10 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
69
86
  pendingPageKeys.delete(key);
70
87
  rebuildPageResults();
71
88
  if (pendingPageKeys.size === 0) {
72
- let updatedResults = [];
73
- pageResultsInternal.subscribe((results) => {
74
- updatedResults = results;
75
- })();
76
- const next = rebalance(currentPages, updatedResults);
89
+ const latestPages = get(pagesStore);
90
+ const next = rebalance(latestPages, get(pageResultsInternal));
77
91
  if (next) {
92
+ migrateResultsForRebalance(latestPages, next);
78
93
  pagesStore.set(next);
79
94
  syncSubscriptions();
80
95
  rebuildPageResults();
@@ -86,6 +101,23 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
86
101
  activeSubs.set(key, unsub);
87
102
  }
88
103
  };
104
+ let syncing = false;
105
+ let resyncRequested = false;
106
+ const syncSubscriptions = () => {
107
+ if (syncing) {
108
+ resyncRequested = true;
109
+ return;
110
+ }
111
+ syncing = true;
112
+ try {
113
+ do {
114
+ resyncRequested = false;
115
+ syncPass();
116
+ } while (resyncRequested);
117
+ } finally {
118
+ syncing = false;
119
+ }
120
+ };
89
121
  const teardownAll = () => {
90
122
  for (const unsub of activeSubs.values()) {
91
123
  unsub();
@@ -115,14 +147,12 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
115
147
  if (currentBaseArgs === "skip") {
116
148
  return;
117
149
  }
118
- let currentResults = [];
119
- pageResultsInternal.subscribe((results) => {
120
- currentResults = results;
121
- })();
150
+ const currentResults = get(pageResultsInternal);
122
151
  const { nextCursor, status: currentStatus } = derivePaginationStatus(false, currentResults);
123
152
  if (currentStatus !== "CanLoadMore") {
124
153
  return;
125
154
  }
155
+ const currentPages = get(pagesStore);
126
156
  const next = applyLoadMore(currentPages, nextCursor, numberItems);
127
157
  if (!next) {
128
158
  return;
@@ -136,6 +166,7 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
136
166
  const carried = resultsByKey.get(oldKey);
137
167
  if (carried) {
138
168
  resultsByKey.set(newKey, carried);
169
+ resultsByKey.delete(oldKey);
139
170
  }
140
171
  }
141
172
  }
@@ -1,6 +1,6 @@
1
1
  import { createMutationRunner } from '@lunora/client';
2
2
  import { writable } from 'svelte/store';
3
- import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
3
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
4
4
 
5
5
  function mutation(clientOrFunction, maybeFunction) {
6
6
  const hasExplicitClient = maybeFunction !== void 0;
@@ -0,0 +1,19 @@
1
+ import { createMutatorRunner } from '@lunora/client';
2
+ import { writable, derived } from 'svelte/store';
3
+
4
+ const mutator = (handle) => {
5
+ const error = writable();
6
+ const pending = writable(false);
7
+ const isError = derived(error, ($error) => $error !== void 0);
8
+ const { mutate, reset } = createMutatorRunner(handle, {
9
+ setError: (value) => {
10
+ error.set(value);
11
+ },
12
+ setPending: (value) => {
13
+ pending.set(value);
14
+ }
15
+ });
16
+ return { error, isError, mutate, pending, reset };
17
+ };
18
+
19
+ export { mutator };
@@ -1,16 +1,24 @@
1
+ import { onDestroy } from 'svelte';
1
2
  import { readable } from 'svelte/store';
2
- import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
3
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
3
4
 
4
- const makeSessionId = () => {
5
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
6
- return crypto.randomUUID();
5
+ const randomSessionId = (prefix = "sess") => {
6
+ if (typeof crypto !== "undefined") {
7
+ if (typeof crypto.randomUUID === "function") {
8
+ return crypto.randomUUID();
9
+ }
10
+ if (typeof crypto.getRandomValues === "function") {
11
+ const bytes = crypto.getRandomValues(new Uint8Array(16));
12
+ return `${prefix}-${Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
13
+ }
7
14
  }
8
- return `sess-${Math.random().toString(36).slice(2)}-${String(Date.now())}`;
15
+ return `${prefix}-${Date.now().toString(36)}`;
9
16
  };
17
+
10
18
  const DEFAULT_INTERVAL_MS = 1e4;
11
19
  const createPresenceHandle = (client, roomId, options) => {
12
20
  const { heartbeat, intervalMs = DEFAULT_INTERVAL_MS, listPresent, shardKey } = options;
13
- const sessionId = options.sessionId ?? makeSessionId();
21
+ const sessionId = options.sessionId ?? randomSessionId();
14
22
  let latestData = options.data;
15
23
  const sendHeartbeat = () => {
16
24
  const args = {
@@ -46,13 +54,22 @@ const createPresenceHandle = (client, roomId, options) => {
46
54
  );
47
55
  return unsubscribe;
48
56
  });
57
+ let torndown = false;
49
58
  const teardown = () => {
59
+ if (torndown) {
60
+ return;
61
+ }
62
+ torndown = true;
50
63
  clearInterval(intervalHandle);
51
64
  if (typeof document !== "undefined") {
52
65
  document.removeEventListener("visibilitychange", onVisible);
53
66
  }
54
67
  releaseConnectionContext();
55
68
  };
69
+ try {
70
+ onDestroy(teardown);
71
+ } catch {
72
+ }
56
73
  return { present, sessionId, setData, teardown };
57
74
  };
58
75
  function presence(clientOrRoomId, roomIdOrOptions, maybeOptions) {
@@ -1,6 +1,6 @@
1
1
  import { createQuerySubscription } from '@lunora/client/query';
2
2
  import { readable } from 'svelte/store';
3
- import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
3
+ import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
4
4
  import { i as isFunctionReference } from './is-function-reference-ycLAcI79.mjs';
5
5
 
6
6
  function query(clientOrFunction, functionOrArguments, argumentsOrOptions, maybeOptions) {
@@ -25,7 +25,13 @@ function query(clientOrFunction, functionOrArguments, argumentsOrOptions, maybeO
25
25
  onData: (value) => {
26
26
  set(value);
27
27
  },
28
- onError: options.onError
28
+ onError: options.onError,
29
+ // `args === "skip"` short-circuits inside the shared helper and
30
+ // fires this reset — clear any prior value so a store that flips
31
+ // to `"skip"` does not retain stale data.
32
+ onReset: () => {
33
+ set(void 0);
34
+ }
29
35
  },
30
36
  { shardKey: options.shardKey }
31
37
  )