@lunora/angular 1.0.0-alpha.6 → 1.0.0-alpha.8

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,13 +1,19 @@
1
+ export { agent } from './packem_shared/agent-DDKvrG4u.mjs';
2
+ export { agentChat } from './packem_shared/agentChat-C7kUEwO9.mjs';
3
+ export { agentState } from './packem_shared/agentState-C8GWf3t3.mjs';
4
+ export { agentToolEvents } from './packem_shared/agentToolEvents-sXgYggvi.mjs';
1
5
  export { auth } from './packem_shared/auth-Df9N87Z4.mjs';
2
6
  export { LUNORA_CLIENT, injectLunoraClient, provideLunora } from './packem_shared/LUNORA_CLIENT-DHUfNu9x.mjs';
3
7
  export { connectionStatus } from './packem_shared/connectionStatus-BlLodleK.mjs';
4
8
  export { flag, flags } from './packem_shared/flag-CGBo90HJ.mjs';
5
- export { hydratePreloaded } from './packem_shared/hydratePreloaded-ClRc-7rL.mjs';
6
- export { liveQuery } from './packem_shared/liveQuery-D5VQBOgf.mjs';
9
+ export { hydratePreloaded } from './packem_shared/hydratePreloaded-DIpD1cAM.mjs';
10
+ export { liveQuery } from './packem_shared/liveQuery-DVxKidjM.mjs';
7
11
  export { mutate } from './packem_shared/mutate-D3rEHwbb.mjs';
8
12
  export { mutator } from './packem_shared/mutator-BHL8bakL.mjs';
9
- export { infiniteQuery, paginatedQuery } from './packem_shared/infiniteQuery-DUV60k-n.mjs';
10
- export { presence } from './packem_shared/presence-h2xonCZM.mjs';
11
- export { rateLimit } from './packem_shared/rateLimit-CKcAig4M.mjs';
12
- export { subscription } from './packem_shared/subscription-Dd9dQiBB.mjs';
13
+ export { infiniteQuery, paginatedQuery } from './packem_shared/infiniteQuery-nboKfr5E.mjs';
14
+ export { presence } from './packem_shared/presence-BTuq19dS.mjs';
15
+ export { rateLimit } from './packem_shared/rateLimit-I4kRT9qV.mjs';
16
+ export { stream } from './packem_shared/stream-PL64AghO.mjs';
17
+ export { subscription } from './packem_shared/subscription-oZ-WTmpp.mjs';
18
+ export { voiceAgent } from './packem_shared/voiceAgent-DwbrDnB9.mjs';
13
19
  export { SKIP } from '@lunora/client/query';
@@ -0,0 +1,31 @@
1
+ import { inject, DestroyRef, computed, signal } from '@angular/core';
2
+ import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
3
+ import { subscription } from './subscription-oZ-WTmpp.mjs';
4
+
5
+ const agent = (options) => {
6
+ const { api, cancel: cancelReference, run: runReference, runArgs, threadKey } = options;
7
+ const client = resolveLunoraClient(options.client);
8
+ const destroyRef = options.destroyRef ?? inject(DestroyRef);
9
+ const { data: threadData } = subscription(api.agents.agentThread, { key: threadKey }, { client, destroyRef });
10
+ const thread = computed(() => threadData());
11
+ const status = computed(() => thread()?.status);
12
+ const pending = signal(false);
13
+ const run = async (input, arguments_) => {
14
+ pending.set(true);
15
+ try {
16
+ await client.mutation(runReference, { input, threadKey, ...runArgs, ...arguments_ });
17
+ } finally {
18
+ pending.set(false);
19
+ }
20
+ };
21
+ const cancel = async () => {
22
+ const instanceId = thread()?.instanceId;
23
+ if (cancelReference === void 0 || instanceId === void 0) {
24
+ return;
25
+ }
26
+ await client.mutation(cancelReference, { instanceId, threadKey });
27
+ };
28
+ return { cancel, pending: pending.asReadonly(), run, status, thread };
29
+ };
30
+
31
+ export { agent };
@@ -0,0 +1,96 @@
1
+ import { inject, DestroyRef, signal, computed } from '@angular/core';
2
+ import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
3
+ import { stream } from './stream-PL64AghO.mjs';
4
+ import { subscription } from './subscription-oZ-WTmpp.mjs';
5
+
6
+ const NO_STREAM_REF = { __lunoraRef: "" };
7
+ const reconcileOptimistic = (optimistic, durable) => {
8
+ const pool = durable.filter((message) => message.role === "user").map((message) => message.content);
9
+ return optimistic.filter((pending) => {
10
+ const index = pool.indexOf(pending.content);
11
+ if (index !== -1) {
12
+ pool.splice(index, 1);
13
+ return false;
14
+ }
15
+ return true;
16
+ });
17
+ };
18
+ const agentChat = (options) => {
19
+ const { api, cancel: cancelReference, limit, send: sendReference, sendArgs, stream: streamReference, threadKey } = options;
20
+ const client = resolveLunoraClient(options.client);
21
+ const destroyRef = options.destroyRef ?? inject(DestroyRef);
22
+ const messagesArguments = limit === void 0 ? { key: threadKey } : { key: threadKey, limit };
23
+ const { data: history } = subscription(api.agents.agentMessages, messagesArguments, { client, destroyRef });
24
+ const { data: threadData } = subscription(api.agents.agentThread, { key: threadKey }, { client, destroyRef });
25
+ const streamArguments = streamReference === void 0 ? "skip" : { key: threadKey };
26
+ const { chunks } = stream(streamReference ?? NO_STREAM_REF, streamArguments, { client, destroyRef });
27
+ const optimistic = signal([]);
28
+ let nextId = 0;
29
+ const thread = computed(() => threadData());
30
+ const status = computed(() => thread()?.status);
31
+ const durable = computed(() => history() ?? []);
32
+ const messages = computed(() => {
33
+ const rows = durable();
34
+ const visible = reconcileOptimistic(optimistic(), rows);
35
+ if (visible.length === 0) {
36
+ return rows;
37
+ }
38
+ return [
39
+ ...rows,
40
+ ...visible.map((pending, index) => {
41
+ return {
42
+ content: pending.content,
43
+ optimistic: true,
44
+ role: "user",
45
+ seq: rows.length + index
46
+ };
47
+ })
48
+ ];
49
+ });
50
+ const streamingText = computed(() => {
51
+ const assistantCount = durable().filter((message) => message.role === "assistant").length;
52
+ return chunks().filter((event) => event.kind !== "progress" && event.threadKey === threadKey && event.turn >= assistantCount).map((delta) => delta.text).join("");
53
+ });
54
+ const send = async (input, arguments_) => {
55
+ const id = nextId;
56
+ nextId += 1;
57
+ optimistic.set([...reconcileOptimistic(optimistic(), durable()), { content: input, id }]);
58
+ await client.mutation(sendReference, { input, threadKey, ...sendArgs, ...arguments_ });
59
+ };
60
+ const approve = async (toolCallId, note) => {
61
+ const instanceId = thread()?.instanceId;
62
+ if (instanceId === void 0) {
63
+ throw new Error("agentChat: cannot approve — no in-flight run (thread has no instanceId)");
64
+ }
65
+ await client.mutation(api.agents.agentResolveApproval, {
66
+ decision: "approve",
67
+ instanceId,
68
+ threadKey,
69
+ toolCallId,
70
+ ...note === void 0 ? {} : { note }
71
+ });
72
+ };
73
+ const reject = async (toolCallId, note) => {
74
+ const instanceId = thread()?.instanceId;
75
+ if (instanceId === void 0) {
76
+ throw new Error("agentChat: cannot reject — no in-flight run (thread has no instanceId)");
77
+ }
78
+ await client.mutation(api.agents.agentResolveApproval, {
79
+ decision: "reject",
80
+ instanceId,
81
+ threadKey,
82
+ toolCallId,
83
+ ...note === void 0 ? {} : { note }
84
+ });
85
+ };
86
+ const cancel = async () => {
87
+ const instanceId = thread()?.instanceId;
88
+ if (cancelReference === void 0 || instanceId === void 0) {
89
+ return;
90
+ }
91
+ await client.mutation(cancelReference, { instanceId, threadKey });
92
+ };
93
+ return { approve, cancel, messages, reject, send, status, streamingText };
94
+ };
95
+
96
+ export { agentChat };
@@ -0,0 +1,10 @@
1
+ import { computed } from '@angular/core';
2
+ import { subscription } from './subscription-oZ-WTmpp.mjs';
3
+
4
+ const agentState = (options) => {
5
+ const { data, error } = subscription(options.api.agents.agentState, { key: options.threadKey }, { client: options.client, destroyRef: options.destroyRef });
6
+ const state = computed(() => data());
7
+ return { error, state };
8
+ };
9
+
10
+ export { agentState };
@@ -0,0 +1,59 @@
1
+ import { inject, DestroyRef, computed } from '@angular/core';
2
+ import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
3
+ import { stream } from './stream-PL64AghO.mjs';
4
+ import { subscription } from './subscription-oZ-WTmpp.mjs';
5
+
6
+ const NO_STREAM_REF = { __lunoraRef: "" };
7
+ const EMPTY_MESSAGES = [];
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
+ const agentToolEvents = (options) => {
39
+ const { api, limit, stream: streamReference, threadKey } = options;
40
+ const client = resolveLunoraClient(options.client);
41
+ const destroyRef = options.destroyRef ?? inject(DestroyRef);
42
+ const messagesArguments = limit === void 0 ? { key: threadKey } : { key: threadKey, limit };
43
+ const { data: history } = subscription(api.agents.agentMessages, messagesArguments, { client, destroyRef });
44
+ const streamArguments = streamReference === void 0 ? "skip" : { key: threadKey };
45
+ const { chunks } = stream(streamReference ?? NO_STREAM_REF, streamArguments, { client, destroyRef });
46
+ const events = computed(() => {
47
+ const durable = history() ?? EMPTY_MESSAGES;
48
+ const derived = durable.flatMap((message) => toDurableEvent(message) ?? []);
49
+ for (const event of chunks()) {
50
+ if (event.kind === "progress" && event.threadKey === threadKey) {
51
+ derived.push({ data: event.data, toolCallId: event.toolCallId, type: "progress" });
52
+ }
53
+ }
54
+ return derived;
55
+ });
56
+ return { events };
57
+ };
58
+
59
+ export { agentToolEvents };
@@ -1,28 +1,32 @@
1
1
  import { inject, DestroyRef, signal } from '@angular/core';
2
2
  import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
3
+ import { s as shouldOpenSubscription } from './platform-Dg8Bppgq.mjs';
3
4
 
4
5
  const hydratePreloaded = (preloaded, options = {}) => {
5
6
  const client = resolveLunoraClient(options.client);
7
+ const fromInjectionContext = options.destroyRef === void 0;
6
8
  const destroyRef = options.destroyRef ?? inject(DestroyRef);
7
9
  const { args, functionPath, shardKey, value } = preloaded;
8
10
  const data = signal(value);
9
11
  const error = signal(void 0);
10
12
  const functionReference = { __lunoraRef: functionPath };
11
- const unsubscribe = client.subscribe(
12
- functionReference,
13
- args,
14
- (next) => {
15
- data.set(next);
16
- error.set(void 0);
17
- },
18
- {
19
- onError: (error_) => {
20
- error.set(error_);
13
+ if (shouldOpenSubscription(fromInjectionContext)) {
14
+ const unsubscribe = client.subscribe(
15
+ functionReference,
16
+ args,
17
+ (next) => {
18
+ data.set(next);
19
+ error.set(void 0);
21
20
  },
22
- shardKey
23
- }
24
- );
25
- destroyRef.onDestroy(unsubscribe);
21
+ {
22
+ onError: (error_) => {
23
+ error.set(error_);
24
+ },
25
+ shardKey
26
+ }
27
+ );
28
+ destroyRef.onDestroy(unsubscribe);
29
+ }
26
30
  return { data: data.asReadonly(), error: error.asReadonly() };
27
31
  };
28
32
 
@@ -1,6 +1,7 @@
1
1
  import { computed, inject, DestroyRef, signal } from '@angular/core';
2
- import { initialPages, rebalance, derivePaginationStatus, applyLoadMore } from '@lunora/client/pagination';
2
+ import { initialPages, derivePaginationStatus, applyLoadMore, rebalance } from '@lunora/client/pagination';
3
3
  import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
4
+ import { s as shouldOpenSubscription } from './platform-Dg8Bppgq.mjs';
4
5
 
5
6
  const buildPageKey = (functionPath, pageArgs) => `${functionPath}::${JSON.stringify(pageArgs)}`;
6
7
  const buildPageArgs = (page, baseArgs) => {
@@ -11,6 +12,7 @@ const buildPageArgs = (page, baseArgs) => {
11
12
  };
12
13
  const usePaginatedCore = (reference, baseArgs, options) => {
13
14
  const client = resolveLunoraClient(options.client);
15
+ const fromInjectionContext = options.destroyRef === void 0;
14
16
  const destroyRef = options.destroyRef ?? inject(DestroyRef);
15
17
  const { initialNumItems, shardKey } = options;
16
18
  const functionPath = reference["__lunoraRef"];
@@ -47,7 +49,7 @@ const usePaginatedCore = (reference, baseArgs, options) => {
47
49
  }
48
50
  }
49
51
  };
50
- const syncSubscriptions = (currentPages) => {
52
+ const syncPass = (currentPages) => {
51
53
  const wantedKeys = /* @__PURE__ */ new Set();
52
54
  for (const page of currentPages) {
53
55
  wantedKeys.add(buildPageKey(functionPath, buildPageArgs(page, narrowedArgs)));
@@ -102,7 +104,26 @@ const usePaginatedCore = (reference, baseArgs, options) => {
102
104
  coveredKeys.add(key);
103
105
  }
104
106
  };
105
- if (baseArgs !== "skip") {
107
+ let syncing = false;
108
+ let resyncRequested = false;
109
+ const syncSubscriptions = (currentPages) => {
110
+ if (syncing) {
111
+ resyncRequested = true;
112
+ return;
113
+ }
114
+ syncing = true;
115
+ try {
116
+ let pagesToSync = currentPages;
117
+ do {
118
+ resyncRequested = false;
119
+ syncPass(pagesToSync);
120
+ pagesToSync = pages();
121
+ } while (resyncRequested);
122
+ } finally {
123
+ syncing = false;
124
+ }
125
+ };
126
+ if (baseArgs !== "skip" && shouldOpenSubscription(fromInjectionContext)) {
106
127
  syncSubscriptions(pages());
107
128
  }
108
129
  doRebuildPageResults();
@@ -0,0 +1,32 @@
1
+ import { inject, DestroyRef, signal } from '@angular/core';
2
+ import { createQuerySubscription } from '@lunora/client/query';
3
+ import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
4
+ import { s as shouldOpenSubscription } from './platform-Dg8Bppgq.mjs';
5
+
6
+ const liveQuery = (reference, args, options = {}) => {
7
+ const client = resolveLunoraClient(options.client);
8
+ const fromInjectionContext = options.destroyRef === void 0;
9
+ const destroyRef = options.destroyRef ?? inject(DestroyRef);
10
+ const value = signal(void 0);
11
+ if (shouldOpenSubscription(fromInjectionContext)) {
12
+ const unsubscribe = createQuerySubscription(
13
+ client,
14
+ reference,
15
+ args,
16
+ {
17
+ onData: (next) => {
18
+ value.set(next);
19
+ },
20
+ onError: options.onError,
21
+ onReset: () => {
22
+ value.set(void 0);
23
+ }
24
+ },
25
+ { shardKey: options.shardKey }
26
+ );
27
+ destroyRef.onDestroy(unsubscribe);
28
+ }
29
+ return value.asReadonly();
30
+ };
31
+
32
+ export { liveQuery };
@@ -0,0 +1,14 @@
1
+ import { inject, PLATFORM_ID, NgZone } from '@angular/core';
2
+
3
+ const shouldOpenSubscription = (fromInjectionContext) => {
4
+ if (!fromInjectionContext) {
5
+ return true;
6
+ }
7
+ return inject(PLATFORM_ID, { optional: true }) !== "server";
8
+ };
9
+ const runOutsideAngular = (fromInjectionContext, register) => {
10
+ const zone = fromInjectionContext ? inject(NgZone, { optional: true }) : void 0;
11
+ return zone ? zone.runOutsideAngular(register) : register();
12
+ };
13
+
14
+ export { runOutsideAngular as r, shouldOpenSubscription as s };
@@ -0,0 +1,77 @@
1
+ import { inject, DestroyRef, signal } from '@angular/core';
2
+ import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
3
+ import { s as shouldOpenSubscription, r as runOutsideAngular } from './platform-Dg8Bppgq.mjs';
4
+
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
+ }
14
+ }
15
+ return `${prefix}-${Date.now().toString(36)}`;
16
+ };
17
+
18
+ const DEFAULT_INTERVAL_MS = 1e4;
19
+ const presence = (roomId, options) => {
20
+ const client = resolveLunoraClient(options.client);
21
+ const fromInjectionContext = options.destroyRef === void 0;
22
+ const destroyRef = options.destroyRef ?? inject(DestroyRef);
23
+ const { heartbeat, listPresent, shardKey } = options;
24
+ const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
25
+ const sessionId = options.sessionId ?? randomSessionId();
26
+ const present = signal(void 0);
27
+ if (!Number.isFinite(intervalMs) || intervalMs <= 0) {
28
+ throw new RangeError(`presence intervalMs must be a positive number, got ${String(intervalMs)}`);
29
+ }
30
+ let latestData = options.data;
31
+ const sendHeartbeat = () => {
32
+ const args = { roomId, sessionId };
33
+ if (latestData !== void 0) {
34
+ args.data = latestData;
35
+ }
36
+ client.mutation(heartbeat, args, { shardKey }).catch(() => void 0);
37
+ };
38
+ const setData = (next) => {
39
+ latestData = next;
40
+ sendHeartbeat();
41
+ };
42
+ if (shouldOpenSubscription(fromInjectionContext)) {
43
+ const releaseConnectionContext = client.acquireConnectionContext({ roomId, sessionId }, { shardKey });
44
+ sendHeartbeat();
45
+ const onVisible = () => {
46
+ if (typeof document !== "undefined" && document.visibilityState === "visible") {
47
+ sendHeartbeat();
48
+ }
49
+ };
50
+ const intervalHandle = runOutsideAngular(fromInjectionContext, () => {
51
+ if (typeof document !== "undefined") {
52
+ document.addEventListener("visibilitychange", onVisible);
53
+ }
54
+ return setInterval(sendHeartbeat, intervalMs);
55
+ });
56
+ const listArgs = { roomId };
57
+ const unsubscribe = client.subscribe(
58
+ listPresent,
59
+ listArgs,
60
+ (value) => {
61
+ present.set(value);
62
+ },
63
+ { shardKey }
64
+ );
65
+ destroyRef.onDestroy(() => {
66
+ clearInterval(intervalHandle);
67
+ if (typeof document !== "undefined") {
68
+ document.removeEventListener("visibilitychange", onVisible);
69
+ }
70
+ releaseConnectionContext();
71
+ unsubscribe();
72
+ });
73
+ }
74
+ return { present: present.asReadonly(), sessionId, setData };
75
+ };
76
+
77
+ export { presence };
@@ -6,11 +6,9 @@ const rateLimit = (config, options = {}) => {
6
6
  const now = options.now ?? Date.now;
7
7
  const tickMs = options.tickMs ?? 1e3;
8
8
  let value;
9
- const epoch = signal(0);
10
9
  const computeStatus = () => evaluate(config, value, { consume: false, count: 1, now: now(), reserve: false }).status;
11
10
  const status = signal(computeStatus());
12
11
  const bump = () => {
13
- epoch.update((v) => v + 1);
14
12
  status.set(computeStatus());
15
13
  };
16
14
  let intervalHandle;
@@ -0,0 +1,47 @@
1
+ import { inject, DestroyRef, signal } from '@angular/core';
2
+ import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
3
+
4
+ const stream = (reference, args, options = {}) => {
5
+ const client = resolveLunoraClient(options.client);
6
+ const destroyRef = options.destroyRef ?? inject(DestroyRef);
7
+ const chunks = signal([]);
8
+ const error = signal(void 0);
9
+ const status = signal("idle");
10
+ let active = true;
11
+ let cancelIterable;
12
+ const cancel = () => {
13
+ active = false;
14
+ cancelIterable?.();
15
+ };
16
+ if (args !== "skip") {
17
+ status.set("streaming");
18
+ const iterable = client.stream(reference, args, { maxBuffer: options.maxBuffer, shardKey: options.shardKey });
19
+ cancelIterable = () => {
20
+ iterable.cancel();
21
+ };
22
+ (async () => {
23
+ try {
24
+ for await (const chunk of iterable) {
25
+ if (!active) {
26
+ return;
27
+ }
28
+ chunks.update((current) => [...current, chunk]);
29
+ }
30
+ if (active) {
31
+ status.set("complete");
32
+ }
33
+ } catch (streamError) {
34
+ if (!active) {
35
+ return;
36
+ }
37
+ error.set(streamError instanceof Error ? streamError : new Error(String(streamError)));
38
+ status.set("error");
39
+ }
40
+ })().catch(() => {
41
+ });
42
+ }
43
+ destroyRef.onDestroy(cancel);
44
+ return { cancel, chunks: chunks.asReadonly(), error: error.asReadonly(), status: status.asReadonly() };
45
+ };
46
+
47
+ export { stream };
@@ -1,13 +1,15 @@
1
1
  import { inject, DestroyRef, signal } from '@angular/core';
2
2
  import { createQuerySubscription } from '@lunora/client/query';
3
3
  import { resolveLunoraClient } from './LUNORA_CLIENT-DHUfNu9x.mjs';
4
+ import { s as shouldOpenSubscription } from './platform-Dg8Bppgq.mjs';
4
5
 
5
6
  const subscription = (reference, args, options = {}) => {
6
7
  const client = resolveLunoraClient(options.client);
8
+ const fromInjectionContext = options.destroyRef === void 0;
7
9
  const destroyRef = options.destroyRef ?? inject(DestroyRef);
8
10
  const data = signal(void 0);
9
11
  const error = signal(void 0);
10
- if (args !== "skip") {
12
+ if (args !== "skip" && shouldOpenSubscription(fromInjectionContext)) {
11
13
  const userOnError = options.onError;
12
14
  const unsubscribe = createQuerySubscription(
13
15
  client,