@lunora/angular 1.0.0-alpha.21 → 1.0.0-alpha.210

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 (48) hide show
  1. package/README.md +42 -0
  2. package/dist/index.d.mts +229 -50
  3. package/dist/index.d.ts +229 -50
  4. package/dist/index.mjs +1 -1
  5. package/dist/packem_shared/LUNORA_CLIENT-B0toApHY.mjs +1 -0
  6. package/dist/packem_shared/agent-DjMQf-yE.mjs +1 -0
  7. package/dist/packem_shared/agentChat-DyJrje49.mjs +1 -0
  8. package/dist/packem_shared/agentState-Bjqf9q2f.mjs +1 -0
  9. package/dist/packem_shared/agentToolEvents-VuBRpS6v.mjs +1 -0
  10. package/dist/packem_shared/auth-C3dB8sYS.mjs +1 -0
  11. package/dist/packem_shared/connectionStatus-UhmuwzMa.mjs +1 -0
  12. package/dist/packem_shared/flag-BDKBQGos.mjs +1 -0
  13. package/dist/packem_shared/hydratePreloaded-QPAo50Am.mjs +1 -0
  14. package/dist/packem_shared/infiniteQuery-DGYdgFHW.mjs +1 -0
  15. package/dist/packem_shared/liveQuery-eE9zMaxo.mjs +1 -0
  16. package/dist/packem_shared/mutate-BZvLQLyu.mjs +1 -0
  17. package/dist/packem_shared/mutator-DjG1yGk8.mjs +1 -0
  18. package/dist/packem_shared/platform-DGTu4Ucl.mjs +1 -0
  19. package/dist/packem_shared/presence-1T4-U8ij.mjs +1 -0
  20. package/dist/packem_shared/rateLimit-B3h9qzh-.mjs +1 -0
  21. package/dist/packem_shared/runAction-BfiPq4Xz.mjs +1 -0
  22. package/dist/packem_shared/stream-BuhiwhIH.mjs +1 -0
  23. package/dist/packem_shared/subscription-zJv48q6C.mjs +1 -0
  24. package/dist/packem_shared/voiceAgent-CH--tRWP.mjs +1 -0
  25. package/dist/server.d.mts +1 -0
  26. package/dist/server.d.ts +1 -0
  27. package/dist/server.mjs +1 -0
  28. package/dist/upload.mjs +1 -1
  29. package/package.json +9 -4
  30. package/dist/packem_shared/LUNORA_CLIENT-B0pGE0Tv.mjs +0 -1
  31. package/dist/packem_shared/agent-C-GavfBl.mjs +0 -1
  32. package/dist/packem_shared/agentChat-Bay8gA8i.mjs +0 -1
  33. package/dist/packem_shared/agentState-BAfa0QuC.mjs +0 -1
  34. package/dist/packem_shared/agentToolEvents-CBTZ_DsO.mjs +0 -1
  35. package/dist/packem_shared/auth-BTEtMnGG.mjs +0 -1
  36. package/dist/packem_shared/connectionStatus-C53UhkPi.mjs +0 -1
  37. package/dist/packem_shared/flag-BYFWoQTg.mjs +0 -1
  38. package/dist/packem_shared/hydratePreloaded-BKHgpXzQ.mjs +0 -1
  39. package/dist/packem_shared/infiniteQuery-C-T8hD7-.mjs +0 -1
  40. package/dist/packem_shared/liveQuery-DEIqmTPj.mjs +0 -1
  41. package/dist/packem_shared/mutate-DR8Uo8Hs.mjs +0 -1
  42. package/dist/packem_shared/mutator-Cw6jpG06.mjs +0 -1
  43. package/dist/packem_shared/platform-BGZypnc9.mjs +0 -1
  44. package/dist/packem_shared/presence-BMrTlOCF.mjs +0 -1
  45. package/dist/packem_shared/rateLimit-CQazDrPJ.mjs +0 -1
  46. package/dist/packem_shared/stream-CcvHiJf2.mjs +0 -1
  47. package/dist/packem_shared/subscription-DJeoGEDR.mjs +0 -1
  48. package/dist/packem_shared/voiceAgent-CwlzrEjH.mjs +0 -1
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { DestroyRef, Signal, InjectionToken, EnvironmentProviders } from '@angular/core';
2
- import { FunctionReference, LunoraClient, SubscriptionError, User, LunoraClientOptions, ConnectionStatus, Preloaded, ArgsOf, ReturnOf, MutationCallOptions, MutatorHandle } from '@lunora/client';
1
+ import { DestroyRef, Signal, InjectionToken, EnvironmentProviders, Injector } from '@angular/core';
2
+ import { FunctionReference, LunoraClient, SubscriptionErrorCallback, SubscriptionError, User, LunoraClientOptions, ConnectionStatus, Preloaded, ArgsOf, ReturnOf, MutationCallOptions, MutatorHandle, ActionCallOptions } from '@lunora/client';
3
3
  export type { ArgsOf, ConnectionStatus, FunctionReference, LunoraClient, LunoraClientOptions, MutationCallOptions, Preloaded, ReturnOf, SubscriptionError, Unsubscribe } from '@lunora/client';
4
+ import { AuthStatus } from '@lunora/client/auth';
4
5
  import { PaginationStatus } from '@lunora/client/pagination';
5
6
  import { RateLimitStatus, RateLimitConfig } from '@lunora/ratelimit';
6
7
  export { SKIP } from '@lunora/client/query';
@@ -22,8 +23,12 @@ type AgentThreadStatus = "awaiting_input" | "cancelled" | "error" | "idle" | "ru
22
23
  */
23
24
  interface AgentThreadRecord {
24
25
  createdAt?: number;
25
- /** The failure message when `status === "error"`. */
26
- error?: string;
26
+ /**
27
+ * The failure message when `status === "error"`, `null` once a later run
28
+ * cleared it, absent on a thread that has never failed. Read it for
29
+ * truthiness — `null` and absent both mean "no error".
30
+ */
31
+ error?: null | string;
27
32
  /** The workflow instance id of the in-flight run — the handle `cancel` targets. */
28
33
  instanceId?: string;
29
34
  messageCount?: number;
@@ -125,7 +130,7 @@ interface AgentOptions {
125
130
  api: AgentApi;
126
131
  /**
127
132
  * Optional app mutation over the agent's cancel path
128
- * (`ctx.agents.<name>.cancel(id)`). Called with `{ instanceId, threadKey }`.
133
+ * (`ctx.agents.<name>.cancel(id)`). Called with `{ instanceId, threadKey }`.
129
134
  * When omitted (or no run is in flight) {@link AgentResult.cancel} is a no-op.
130
135
  */
131
136
  cancel?: FunctionReference<"mutation">;
@@ -136,9 +141,15 @@ interface AgentOptions {
136
141
  * `inject(DestroyRef)` — the calling component/service.
137
142
  */
138
143
  destroyRef?: DestroyRef;
144
+ /**
145
+ * Called when the live thread subscription reports an error (a session
146
+ * expiry, an RLS denial). Without it — and without reading `error` — such a
147
+ * failure is invisible and `thread` / `status` are cleared until a later frame arrives.
148
+ */
149
+ onError?: SubscriptionErrorCallback;
139
150
  /**
140
151
  * The app mutation that starts (or continues) a run — a thin wrapper over
141
- * `ctx.agents.&lt;name>.run(...)`. Called with `{ threadKey, input }` merged with
152
+ * `ctx.agents.<name>.run(...)`. Called with `{ threadKey, input }` merged with
142
153
  * {@link AgentOptions.runArgs} and the per-call args.
143
154
  */
144
155
  run: FunctionReference<"mutation">;
@@ -157,6 +168,8 @@ interface AgentResult {
157
168
  * no-op when no `cancel` mutation was supplied or no run is in flight.
158
169
  */
159
170
  cancel: () => Promise<void>;
171
+ /** The live thread subscription's last error, or `undefined`. */
172
+ error: Signal<SubscriptionError | undefined>;
160
173
  /** `true` while a `run` invocation is in flight. */
161
174
  pending: Signal<boolean>;
162
175
  /** Start (or continue) a run with a user message; extra args merge over `runArgs`. */
@@ -174,7 +187,7 @@ interface AgentResult {
174
187
  * conversation surface (durable history + streaming + approvals) use `agentChat`.
175
188
  *
176
189
  * `run` and `cancel` stay generic over the app-defined mutations that wrap
177
- * `ctx.agents.&lt;name>.run` / `.cancel`, so the primitive hard-codes no function
190
+ * `ctx.agents.<name>.run` / `.cancel`, so the primitive hard-codes no function
178
191
  * names beyond the `agents:*` surface.
179
192
  *
180
193
  * Call from an injection context (component/service field or constructor); pass an
@@ -232,7 +245,7 @@ interface AgentChatOptions {
232
245
  api: AgentChatApi;
233
246
  /**
234
247
  * Optional app mutation over the agent's cancel path
235
- * (`ctx.agents.&lt;name>.cancel(id)`). Called with `{ instanceId, threadKey }`.
248
+ * (`ctx.agents.<name>.cancel(id)`). Called with `{ instanceId, threadKey }`.
236
249
  * When omitted (or no run is in flight) {@link AgentChatResult.cancel} is a
237
250
  * no-op.
238
251
  */
@@ -246,9 +259,15 @@ interface AgentChatOptions {
246
259
  destroyRef?: DestroyRef;
247
260
  /** History depth forwarded to `agents:agentMessages`. */
248
261
  limit?: number;
262
+ /**
263
+ * Called when the live history or thread subscription reports an error (a
264
+ * session expiry, an RLS denial). Without it — and without reading `error` —
265
+ * such a failure is invisible and `messages` / `status` are cleared until a later frame arrives.
266
+ */
267
+ onError?: SubscriptionErrorCallback;
249
268
  /**
250
269
  * The app mutation that starts (or continues) a run — a thin wrapper over
251
- * `ctx.agents.&lt;name>.run(...)`. Called with `{ threadKey, input }` merged with
270
+ * `ctx.agents.<name>.run(...)`. Called with `{ threadKey, input }` merged with
252
271
  * {@link AgentChatOptions.sendArgs} and the per-call args.
253
272
  */
254
273
  send: FunctionReference<"mutation">;
@@ -275,6 +294,8 @@ interface AgentChatResult {
275
294
  * no-op when no `cancel` mutation was supplied or no run is in flight.
276
295
  */
277
296
  cancel: () => Promise<void>;
297
+ /** The history or thread subscription's last error, or `undefined`. */
298
+ error: Signal<SubscriptionError | undefined>;
278
299
  /** Durable thread history (oldest first) plus any un-acknowledged optimistic user turns. */
279
300
  messages: Signal<ReadonlyArray<AgentChatMessage>>;
280
301
  /** Reject a paused human-in-the-loop tool call (optionally with a reason). */
@@ -363,7 +384,7 @@ interface AgentStateResult<T> {
363
384
  * only on a real `setState`. The Angular counterpart to React's `useAgentState`,
364
385
  * re-expressed with signals.
365
386
  *
366
- * Generic over the app's state shape (`agentState&lt;SupportState>(...)`, itself a
387
+ * Generic over the app's state shape (`agentState<SupportState>(...)`, itself a
367
388
  * record) — the reference is typed as an optional record because codegen cannot see
368
389
  * the per-agent state type; the generic casts to `T`. The `extends` bound (not a
369
390
  * bare unbounded type parameter) is required: this `.ts` file is parsed JSX-aware by
@@ -502,6 +523,12 @@ interface AuthOptions {
502
523
  interface AuthResult {
503
524
  /** Set the auth token (sign-in / sign-out). */
504
525
  setToken: (token: string | null) => void;
526
+ /**
527
+ * The resolved auth state. Branch on this, not on `user() === null` — see the
528
+ * contract in `@lunora/client/auth`; `user` is `null` both when signed out
529
+ * and when a held credential's identity could not be resolved.
530
+ */
531
+ status: Signal<AuthStatus>;
505
532
  /** The current auth token, or `null`. */
506
533
  token: Signal<string | null>;
507
534
  /** The resolved user from `store.getUser()`, or `null`. */
@@ -529,18 +556,20 @@ declare const auth: (options?: AuthOptions) => AuthResult;
529
556
  * @experimental
530
557
  */
531
558
  interface AuthGateResult {
532
- /** `true` once a token is set and the user has resolved. */
559
+ /** `true` once a credential is held and nothing has contradicted it. */
533
560
  isAuthenticated: Signal<boolean>;
534
- /** `true` while a token is set but the user hasn't resolved yet. */
561
+ /** `true` while a credential's first identity resolve is in flight. */
535
562
  isLoading: Signal<boolean>;
536
563
  }
537
564
  /**
538
565
  * Derived auth-gate signals for template gating (Angular's `\@if` control
539
566
  * flow), built on {@link auth}. Angular has no JSX-style `Authenticated` slot
540
567
  * component the way React/Vue/Solid do, so this exposes the same three-state
541
- * logic as two booleans instead: a token with no resolved user yet is
542
- * `isLoading`; a token with a resolved user is `isAuthenticated`; no token is
543
- * neither (the signed-out state a template checks for with a plain `\@else`).
568
+ * logic as two booleans instead, mapped from the shared `AuthStatus` contract in
569
+ * `@lunora/client/auth`: a credential whose first identity resolve is in flight
570
+ * is `isLoading`; a credential nothing has contradicted — including one whose
571
+ * identity endpoint is unreachable — is `isAuthenticated`; no session is neither
572
+ * (the signed-out state a template checks for with a plain `\@else`).
544
573
  *
545
574
  * Call from an injection context (component/service field or constructor):
546
575
  * ```ts
@@ -625,16 +654,15 @@ interface ConnectionStatusOptions {
625
654
  * @experimental
626
655
  */
627
656
  declare const connectionStatus: (options?: ConnectionStatusOptions) => Signal<ConnectionStatus>;
657
+ /** The value kinds a flag resolves to — OpenFeature's boolean / number / string / structured (JSON) flags. */
658
+ type FlagValue$1 = boolean | number | string | {
659
+ [key: string]: unknown;
660
+ } | unknown[] | null;
628
661
  /**
629
662
  * The value kinds a flag resolves to — OpenFeature's boolean / number / string / structured (JSON) flags.
630
663
  * @experimental
631
664
  */
632
- type FlagValue = boolean | number | string | Record<string, unknown> | unknown[] | null;
633
- /**
634
- * Targeting context bag forwarded to the OpenFeature provider.
635
- * @experimental
636
- */
637
- type FlagContext = Record<string, unknown>;
665
+ type FlagValue = FlagValue$1;
638
666
  /**
639
667
  * `FlagOptions` is part of the experimental `@lunora/angular` API and may change without a major version bump.
640
668
  * @experimental
@@ -642,11 +670,6 @@ type FlagContext = Record<string, unknown>;
642
670
  interface FlagOptions {
643
671
  /** Client to bind to. Defaults to the injected `LUNORA_CLIENT`. */
644
672
  client?: LunoraClient;
645
- /**
646
- * Per-call targeting context merged on top of the app's default `identify`
647
- * targeting key.
648
- */
649
- context?: FlagContext;
650
673
  /** `DestroyRef` whose `onDestroy` tears down the subscription. Defaults to `inject(DestroyRef)`. */
651
674
  destroyRef?: DestroyRef;
652
675
  }
@@ -658,9 +681,16 @@ interface FlagOptions {
658
681
  * The flag's kind is inferred from `defaultValue`'s runtime type, so
659
682
  * `flag("dark", false)` reads a boolean and `flag("hero", "control")` a string.
660
683
  *
684
+ * The reactive channel is public, so the server evaluates every flag under the
685
+ * socket's own verified identity — the targeting key your `defineFlags({
686
+ * identify })` derives — and accepts no client-supplied targeting context. For
687
+ * evaluation under a context you compute, call `ctx.flags.*` inside a query,
688
+ * mutation, or action and return the resolved value.
689
+ *
661
690
  * Evaluation runs through whatever OpenFeature provider the app wired in
662
691
  * `lunora/flags.ts`; the read never throws — a provider error resolves the
663
- * default (the same fail-open contract as server-side `ctx.flags`).
692
+ * default (the same fail-open contract as server-side `ctx.flags`). No
693
+ * subscription opens during SSR; the signal stays at `defaultValue`.
664
694
  *
665
695
  * Call from an injection context:
666
696
  * ```ts
@@ -676,11 +706,6 @@ declare const flag: <T extends FlagValue>(key: string, defaultValue: T, options?
676
706
  interface FlagsOptions {
677
707
  /** Client to bind to. Defaults to the injected `LUNORA_CLIENT`. */
678
708
  client?: LunoraClient;
679
- /**
680
- * Targeting context shared by every flag in the set, merged on top of the
681
- * app's default `identify` targeting key.
682
- */
683
- context?: FlagContext;
684
709
  /** `DestroyRef` whose `onDestroy` tears down the subscriptions. Defaults to `inject(DestroyRef)`. */
685
710
  destroyRef?: DestroyRef;
686
711
  }
@@ -689,7 +714,8 @@ interface FlagsOptions {
689
714
  *
690
715
  * Pass a record of `key → defaultValue`; each flag's kind is inferred from its
691
716
  * default, and the returned signal holds the same-shaped record with resolved
692
- * values (the defaults until each evaluation lands).
717
+ * values (the defaults until each evaluation lands). Like {@link flag} it
718
+ * evaluates under the socket's server-verified identity only.
693
719
  *
694
720
  * Call from an injection context:
695
721
  * ```ts
@@ -713,7 +739,7 @@ interface HydratePreloadedOptions {
713
739
  * @experimental
714
740
  */
715
741
  interface HydratePreloadedResult<T> {
716
- /** The latest value pushed by the server. Seeded synchronously from the preloaded value. */
742
+ /** The latest value pushed by the server. Seeded synchronously from the preloaded value until an identity is retired. */
717
743
  data: Signal<T | undefined>;
718
744
  /** The latest subscription error, or `undefined`. */
719
745
  error: Signal<SubscriptionError | undefined>;
@@ -731,6 +757,12 @@ interface HydratePreloadedResult<T> {
731
757
  *
732
758
  * The subscription tears down when the owning `DestroyRef` fires.
733
759
  *
760
+ * The preloaded value was read for whoever was signed in when the page loaded.
761
+ * After a sign-out or user switch retires that identity
762
+ * (`client.identityEpoch() > 0`), every `hydratePreloaded` on the client (created
763
+ * then or later) stops using it and `data` holds `undefined` until the live value
764
+ * arrives — matching `@lunora/react`'s `usePreloadedQuery`.
765
+ *
734
766
  * Call from an injection context:
735
767
  * ```ts
736
768
  * readonly { data, error } = hydratePreloaded(preloadedMessages);
@@ -754,6 +786,16 @@ interface LiveQueryOptions {
754
786
  * component is destroyed. Pass one explicitly to control the lifetime yourself.
755
787
  */
756
788
  destroyRef?: DestroyRef;
789
+ /**
790
+ * `Injector` to create the reactive-args `effect()` from. Only needed when
791
+ * `args` is a function/`Signal` AND `liveQuery` is called outside an injection
792
+ * context (an explicit `destroyRef` is also being passed — e.g. from
793
+ * `ngOnInit`, or from a test with no `TestBed`) — `effect()` cannot resolve an
794
+ * injector on its own there. Defaults to the ambient injection context, the
795
+ * same source `inject(DestroyRef)` already relies on. Unused for the static
796
+ * `args` form, which never creates an `effect()`.
797
+ */
798
+ injector?: Injector;
757
799
  /**
758
800
  * Called when the subscription errors after the initial attach — the async
759
801
  * error channel `createQuerySubscription` only wires when a sink is present.
@@ -787,9 +829,17 @@ interface LiveQueryOptions {
787
829
  * short-circuit — no network call, no socket; the signal stays `undefined`. To
788
830
  * call outside an injection context (e.g. lazily in `ngOnInit`), supply `client`
789
831
  * and `destroyRef` via {@link LiveQueryOptions}.
832
+ *
833
+ * `args` also accepts a function/`Signal` — `() => ({ channelId: channelId() })`
834
+ * — to make the subscription reactive: an args change tears the old
835
+ * subscription down, resets the signal to `undefined`, and opens a fresh one
836
+ * for the new args, mirroring
837
+ * `@lunora/solid`'s `createQuery`/`@lunora/vue`'s `useQuery`. A static (plain
838
+ * object) `args` resolves once and never re-runs — no `effect()` is created for
839
+ * it, so it carries none of the reactive form's DI requirement.
790
840
  * @experimental
791
841
  */
792
- declare const liveQuery: <F extends FunctionReference>(reference: F, args: ArgsOf<F> | "skip", options?: LiveQueryOptions) => Signal<ReturnOf<F> | undefined>;
842
+ declare const liveQuery: <F extends FunctionReference>(reference: F, args: ArgsOf<F> | "skip" | (() => ArgsOf<F> | "skip"), options?: LiveQueryOptions) => Signal<ReturnOf<F> | undefined>;
793
843
  /**
794
844
  * `MutateOptions` is part of the experimental `@lunora/angular` API and may change without a major version bump.
795
845
  * @experimental
@@ -877,6 +927,15 @@ interface PaginatedQueryOptions {
877
927
  destroyRef?: DestroyRef;
878
928
  /** Page size for the first page (and the default for `loadMore`). */
879
929
  initialNumItems: number;
930
+ /**
931
+ * `Injector` to create the reactive-args `effect()` from. Only needed when
932
+ * `args` is a function/`Signal` AND the call is outside an injection context
933
+ * (an explicit `destroyRef` is also being passed). Defaults to the ambient
934
+ * injection context. Unused for the static `args` form.
935
+ */
936
+ injector?: Injector;
937
+ /** Called when a page subscription reports an error (also surfaced on the `error` signal). */
938
+ onError?: SubscriptionErrorCallback;
880
939
  /** Route to a specific shard when the target function is `.shardBy(...)`-partitioned. */
881
940
  shardKey?: string;
882
941
  }
@@ -885,6 +944,13 @@ interface PaginatedQueryOptions {
885
944
  * @experimental
886
945
  */
887
946
  interface PaginatedQueryResult<T> {
947
+ /**
948
+ * The last page subscription error, or `undefined`. A tail page that fails
949
+ * before its first frame is dropped so `status` returns to `"CanLoadMore"`
950
+ * and `loadMore` can retry it; cleared by the next successful frame,
951
+ * `loadMore`, or an args change.
952
+ */
953
+ error: Signal<SubscriptionError | undefined>;
888
954
  /** `true` while the first page or a `loadMore` page is in flight. */
889
955
  isLoading: Signal<boolean>;
890
956
  /** Request the next page. A no-op unless `status === "CanLoadMore"`. */
@@ -899,6 +965,8 @@ interface PaginatedQueryResult<T> {
899
965
  * @experimental
900
966
  */
901
967
  interface InfiniteQueryResult<T> {
968
+ /** The last page subscription error, or `undefined` — see `PaginatedQueryResult.error`. */
969
+ error: Signal<SubscriptionError | undefined>;
902
970
  /** Request the next page. A no-op unless `status === "CanLoadMore"`. */
903
971
  fetchNextPage: (numberItems?: number) => void;
904
972
  /** `true` when the loaded tail reports it can load another page. */
@@ -927,9 +995,13 @@ interface InfiniteQueryResult<T> {
927
995
  * ```ts
928
996
  * readonly messages = paginatedQuery(api.messages.list, {}, { initialNumItems: 20 });
929
997
  * ```
998
+ *
999
+ * `args` also accepts a function/`Signal` to make the query reactive — an args
1000
+ * change disposes the current pagination engine and builds a fresh one for the
1001
+ * new args. A static (plain object) `args` resolves once and never re-runs.
930
1002
  * @experimental
931
1003
  */
932
- declare const paginatedQuery: <F extends FunctionReference>(reference: F, args: PaginatedArgs<F> | "skip", options: PaginatedQueryOptions) => PaginatedQueryResult<PageItemOf<F>>;
1004
+ declare const paginatedQuery: <F extends FunctionReference>(reference: F, args: PaginatedArgs<F> | "skip" | (() => PaginatedArgs<F> | "skip"), options: PaginatedQueryOptions) => PaginatedQueryResult<PageItemOf<F>>;
933
1005
  /**
934
1006
  * Subscribe to a reactively-paginated query and expose its pages discretely.
935
1007
  *
@@ -941,9 +1013,12 @@ declare const paginatedQuery: <F extends FunctionReference>(reference: F, args:
941
1013
  * ```ts
942
1014
  * readonly feed = infiniteQuery(api.messages.list, {}, { initialNumItems: 20 });
943
1015
  * ```
1016
+ *
1017
+ * `args` also accepts a function/`Signal` to make the query reactive — see
1018
+ * `paginatedQuery`'s equivalent note.
944
1019
  * @experimental
945
1020
  */
946
- declare const infiniteQuery: <F extends FunctionReference>(reference: F, args: PaginatedArgs<F> | "skip", options: PaginatedQueryOptions) => InfiniteQueryResult<PageItemOf<F>>;
1021
+ declare const infiniteQuery: <F extends FunctionReference>(reference: F, args: PaginatedArgs<F> | "skip" | (() => PaginatedArgs<F> | "skip"), options: PaginatedQueryOptions) => InfiniteQueryResult<PageItemOf<F>>;
947
1022
  /**
948
1023
  * `HeartbeatReference` is part of the experimental `@lunora/angular` API and may change without a major version bump.
949
1024
  * @experimental
@@ -977,6 +1052,12 @@ interface PresenceOptions<H extends HeartbeatReference, L extends ListPresentRef
977
1052
  intervalMs?: number;
978
1053
  /** The `api.*` reference for the presence listPresent query. */
979
1054
  listPresent: L;
1055
+ /**
1056
+ * Called when the `listPresent` subscription reports an error (a session
1057
+ * expiry, an RLS denial). Without it — and without reading `error` — such a
1058
+ * failure is invisible and `present` is cleared until a later frame arrives.
1059
+ */
1060
+ onError?: SubscriptionErrorCallback;
980
1061
  /**
981
1062
  * Stable id for this presence row. Defaults to a fresh per-call id.
982
1063
  * Pass a user/connection id to control deduping across tabs.
@@ -990,6 +1071,8 @@ interface PresenceOptions<H extends HeartbeatReference, L extends ListPresentRef
990
1071
  * @experimental
991
1072
  */
992
1073
  interface PresenceResult<L extends ListPresentReference> {
1074
+ /** The `listPresent` subscription's last error, or `undefined`. */
1075
+ error: Signal<SubscriptionError | undefined>;
993
1076
  /** The present members for the room. `undefined` until the first push. */
994
1077
  present: Signal<ReturnOf<L> | undefined>;
995
1078
  /** This mount's session id (generated when not supplied). */
@@ -1065,6 +1148,43 @@ interface RateLimitResult {
1065
1148
  * @experimental
1066
1149
  */
1067
1150
  declare const rateLimit: (config: RateLimitConfig, options?: RateLimitOptions) => RateLimitResult;
1151
+ /**
1152
+ * `RunActionOptions` is part of the experimental `@lunora/angular` API and may change without a major version bump.
1153
+ * @experimental
1154
+ */
1155
+ interface RunActionOptions extends ActionCallOptions {
1156
+ /**
1157
+ * Client to run the action on. Defaults to the injected `LUNORA_CLIENT`.
1158
+ * Because actions usually fire from event handlers — which run *outside* an
1159
+ * injection context — capture the client once (`injectLunoraClient()` in a
1160
+ * field) and pass it here, or call `client.action(...)` directly.
1161
+ */
1162
+ client?: LunoraClient;
1163
+ }
1164
+ /**
1165
+ * Run a Lunora action and resolve with the server result (rejects on failure).
1166
+ *
1167
+ * The sibling of `mutate`, and a plain function for the same reason: Angular's
1168
+ * adapter models writes as calls rather than reactive handles, because they fire
1169
+ * from event handlers where a signal-returning primitive has nothing to bind to.
1170
+ * The other adapters return a reactive `{ call, pending, … }` handle because
1171
+ * their idioms make that natural; this one does not.
1172
+ *
1173
+ * Unlike `mutate` there are no `optimistic` / `optimisticUpdate` options. An
1174
+ * optimistic update patches the subscription cache on the assumption a write
1175
+ * will land; an action is not a write — it runs in the Worker, may call a third
1176
+ * party, and has no declared effect on any query.
1177
+ *
1178
+ * ```ts
1179
+ * private readonly client = injectLunoraClient();
1180
+ * verify = () => runAction(api.commands.run, { command: "lunora", args: ["verify"] }, { client: this.client });
1181
+ * ```
1182
+ *
1183
+ * When called from within an injection context you may omit `client` and let it
1184
+ * resolve from the injector.
1185
+ * @experimental
1186
+ */
1187
+ declare const runAction: <F extends FunctionReference>(reference: F, args: ArgsOf<F>, options?: RunActionOptions) => Promise<ReturnOf<F>>;
1068
1188
  /**
1069
1189
  * The lifecycle of a stream the primitive is observing.
1070
1190
  * @experimental
@@ -1082,6 +1202,13 @@ interface StreamOptions {
1082
1202
  * `inject(DestroyRef)` — the calling component/service.
1083
1203
  */
1084
1204
  destroyRef?: DestroyRef;
1205
+ /**
1206
+ * Opt into resume-on-reconnect for a stream the server declared `durable`.
1207
+ * The chunks already received are kept and the socket re-attaches to the same
1208
+ * run, so a dropped connection mid-generation continues instead of surfacing
1209
+ * `STREAM_DISCONNECTED`. Has no effect on an ephemeral stream.
1210
+ */
1211
+ durable?: boolean;
1085
1212
  /** Forwarded to `client.stream()` — caps the in-flight chunk buffer. */
1086
1213
  maxBuffer?: number;
1087
1214
  /** Route to a specific shard when the target function is `.shardBy(...)`-partitioned. */
@@ -1109,8 +1236,8 @@ interface StreamResult<T> {
1109
1236
  * chunk the server pushes — use it for token-by-token deltas and other append-only
1110
1237
  * feeds. Pass `"skip"` as `args` to keep the primitive mounted without opening a
1111
1238
  * stream (mirrors `subscription`); the stream tears down when the owning
1112
- * `DestroyRef` fires. The Angular counterpart to React's `useStream`, re-expressed
1113
- * with signals.
1239
+ * `DestroyRef` fires. Nothing opens on the Angular server platform (SSR). The
1240
+ * Angular counterpart to React's `useStream`, re-expressed with signals.
1114
1241
  *
1115
1242
  * Call from an injection context (component/service field or constructor):
1116
1243
  * ```ts
@@ -1131,6 +1258,14 @@ interface SubscriptionOptions {
1131
1258
  * `inject(DestroyRef)` — the calling component/service.
1132
1259
  */
1133
1260
  destroyRef?: DestroyRef;
1261
+ /**
1262
+ * `Injector` to create the reactive-args `effect()` from. Only needed when
1263
+ * `args` is a function/`Signal` AND `subscription` is called outside an
1264
+ * injection context (an explicit `destroyRef` is also being passed).
1265
+ * Defaults to the ambient injection context. Unused for the static `args`
1266
+ * form, which never creates an `effect()`.
1267
+ */
1268
+ injector?: Injector;
1134
1269
  /**
1135
1270
  * Called when the subscription errors after the initial attach. Without it,
1136
1271
  * a post-attach failure is dropped silently.
@@ -1164,9 +1299,13 @@ interface SubscriptionResult<T> {
1164
1299
  * ```ts
1165
1300
  * readonly stream = subscription(api.events.stream, { roomId: "general" });
1166
1301
  * ```
1302
+ *
1303
+ * `args` also accepts a function/`Signal` to make the subscription reactive —
1304
+ * an args change tears the old subscription down and opens a fresh one for the
1305
+ * new args. A static (plain object) `args` resolves once and never re-runs.
1167
1306
  * @experimental
1168
1307
  */
1169
- declare const subscription: <F extends FunctionReference>(reference: F, args: ArgsOf<F> | "skip", options?: SubscriptionOptions) => SubscriptionResult<ReturnOf<F>>;
1308
+ declare const subscription: <F extends FunctionReference>(reference: F, args: ArgsOf<F> | "skip" | (() => ArgsOf<F> | "skip"), options?: SubscriptionOptions) => SubscriptionResult<ReturnOf<F>>;
1170
1309
  /**
1171
1310
  * Browser Web Audio subsystems for `voiceAgent` — the default microphone capture
1172
1311
  * and speaker playback implementations injected into the primitive via its
@@ -1205,8 +1344,24 @@ interface MicrophoneConfig {
1205
1344
  interruptChunks: number;
1206
1345
  /** RMS above which the user is considered to be barging in while the agent speaks. */
1207
1346
  interruptThreshold: number;
1208
- /** `true` while `status === "speaking"` — gates barge-in detection. */
1209
- isSpeaking: () => boolean;
1347
+ /**
1348
+ * `true` from the moment a turn is committed until it completes — the whole
1349
+ * `thinking` + `speaking` window, not just the audible half.
1350
+ *
1351
+ * It gates BOTH branches below, and the wider span is the point. Gated only
1352
+ * on "audibly speaking", turn detection kept running through the entire
1353
+ * STT+LLM window after a `commit`: room noise at the (deliberately low)
1354
+ * `silenceThreshold` re-armed `sawSpeech`, another quiet gap fired a SECOND
1355
+ * `commit`, and the DO refused it with "a turn is already in progress" —
1356
+ * a refusal that returns before draining the audio buffer, so the PCM
1357
+ * captured since the first commit leaked into the next utterance.
1358
+ *
1359
+ * A genuine barge-in still works in that window: it routes through the
1360
+ * `onInterrupt` branch, which needs `interruptChunks` consecutive chunks at
1361
+ * `interruptThreshold` — an order of magnitude above `silenceThreshold` —
1362
+ * and `interrupt` is exactly what the DO tells the client to send.
1363
+ */
1364
+ isTurnActive: () => boolean;
1210
1365
  /** One 16 kHz mono 16-bit little-endian PCM frame captured from the mic. */
1211
1366
  onAudio: (pcm: Uint8Array) => void;
1212
1367
  /** A barge-in was detected (RMS spike while the agent is speaking). */
@@ -1225,9 +1380,9 @@ type CreateSpeaker = (config: {
1225
1380
  audioFormat: VoiceAudioFormat;
1226
1381
  }) => VoiceSpeaker;
1227
1382
  /**
1228
- * The `agents.&lt;name>Voice` reference codegen emits for a voice-enabled agent — a
1383
+ * The `agents.<name>Voice` reference codegen emits for a voice-enabled agent — a
1229
1384
  * live, WS-backed session keyed by `threadKey`. A structural subset of the
1230
- * generated member, so passing `api.agents.&lt;name>Voice` type-checks.
1385
+ * generated member, so passing `api.agents.<name>Voice` type-checks.
1231
1386
  * @experimental
1232
1387
  */
1233
1388
  type VoiceReference = FunctionReference<"stream", {
@@ -1265,7 +1420,11 @@ interface VoiceAgentOptions {
1265
1420
  * Audio graph stays isolated (and mockable in a non-browser test env).
1266
1421
  */
1267
1422
  createMicrophone?: CreateMicrophone;
1268
- /** Advanced/test seam: open the transport. Defaults to `new WebSocket(url)`. */
1423
+ /**
1424
+ * Advanced/test seam: open the transport. Defaults to the WebSocket
1425
+ * implementation the client was built with (`client.getWebSocketImpl()`),
1426
+ * NOT a raw `globalThis.WebSocket`.
1427
+ */
1269
1428
  createSocket?: CreateSocket;
1270
1429
  /** Advanced/test seam: build the audio playback subsystem. Defaults to a Web Audio implementation. */
1271
1430
  createSpeaker?: CreateSpeaker;
@@ -1282,9 +1441,13 @@ interface VoiceAgentOptions {
1282
1441
  silenceDurationMs?: number;
1283
1442
  /** Input RMS below which audio counts as silence. Default `0.01`. */
1284
1443
  silenceThreshold?: number;
1285
- /** The thread to converse on — shared with the agent's text turns. Resolved when the call opens. */
1286
- threadKey: string;
1287
- /** The generated `api.agents.&lt;name>Voice` reference — identifies the voice DO endpoint. */
1444
+ /**
1445
+ * The thread to converse on — shared with the agent's text turns. A plain
1446
+ * value, or a `Signal`/getter resolved afresh every time a call opens — the
1447
+ * reactive-args form the package's other primitives take.
1448
+ */
1449
+ threadKey: (() => string) | string;
1450
+ /** The generated `api.agents.<name>Voice` reference — identifies the voice DO endpoint. */
1288
1451
  voice: VoiceReference;
1289
1452
  }
1290
1453
  /**
@@ -1320,7 +1483,7 @@ interface VoiceAgentResult {
1320
1483
  * WebSocket to the agent's `VoiceSessionDO`, captures mic audio as 16 kHz PCM,
1321
1484
  * streams the agent's synthesized speech back through the browser's audio output,
1322
1485
  * and mirrors the call lifecycle (`status`, `transcript`, `interimTranscript`,
1323
- * `audioLevel`) to Angular signals. Pass the generated `api.agents.&lt;name>Voice`
1486
+ * `audioLevel`) to Angular signals. Pass the generated `api.agents.<name>Voice`
1324
1487
  * reference (never a string), matching `agentChat`'s reference-passing style. The
1325
1488
  * Angular counterpart to React's `useVoiceAgent`, re-expressed with signals; the
1326
1489
  * per-call connection lives in a closure variable (the primitive runs once per
@@ -1336,4 +1499,20 @@ interface VoiceAgentResult {
1336
1499
  * @experimental
1337
1500
  */
1338
1501
  declare const voiceAgent: (options: VoiceAgentOptions) => VoiceAgentResult;
1339
- export { type AgentApi, type AgentChatApi, type AgentChatMessage, type AgentChatOptions, type AgentChatResult, type AgentLiveEvent, type AgentOptions, type AgentProgressEvent, type AgentResult, type AgentStateApi, type AgentStateOptions, type AgentStateResult, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentTokenStreamReference, type AgentToolEvent, type AgentToolEventsApi, type AgentToolEventsOptions, type AgentToolEventsResult, type AuthGateResult, type AuthOptions, type AuthResult, type ConnectionStatusOptions, type FlagContext, type FlagOptions, type FlagValue, type FlagsOptions, type HeartbeatReference, type HydratePreloadedOptions, type HydratePreloadedResult, type InfiniteQueryResult, LUNORA_CLIENT, type ListPresentReference, type LiveQueryOptions, type MutateOptions, type MutatorResult, type PaginatedQueryOptions, type PaginatedQueryResult, type PresenceOptions, type PresenceResult, type ProvideLunoraOptions, type RateLimitOptions, type RateLimitResult, type StreamOptions, type StreamResult, type StreamStatus, type SubscriptionOptions, type SubscriptionResult, type VoiceAgentOptions, type VoiceAgentResult, type VoiceAudioFormat, type VoiceReference, type VoiceStatus, agent, agentChat, agentState, agentToolEvents, auth, authGate, connectionStatus, flag, flags, hydratePreloaded, infiniteQuery, injectLunoraClient, liveQuery, mutate, mutator, paginatedQuery, presence, provideLunora, rateLimit, stream, subscription, voiceAgent };
1502
+ export { type AgentApi, type AgentChatApi, type AgentChatMessage, type AgentChatOptions, type AgentChatResult, type AgentLiveEvent, type AgentOptions, type AgentProgressEvent, type AgentResult, type AgentStateApi, type AgentStateOptions, type AgentStateResult, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentTokenStreamReference, type AgentToolEvent, type AgentToolEventsApi, type AgentToolEventsOptions, type AgentToolEventsResult, type AuthGateResult, type AuthOptions, type AuthResult, type ConnectionStatusOptions, type FlagOptions, type FlagValue, type FlagsOptions, type HeartbeatReference, type HydratePreloadedOptions, type HydratePreloadedResult, type InfiniteQueryResult, LUNORA_CLIENT, type ListPresentReference, type LiveQueryOptions, type MutateOptions, type MutatorResult, type PaginatedQueryOptions, type PaginatedQueryResult, type PresenceOptions, type PresenceResult,
1503
+ /**
1504
+ * The Angular adapter for Lunora.
1505
+ *
1506
+ * Thin, idiomatic glue over the framework-neutral `@lunora/client`. Angular
1507
+ * signals map directly onto Lunora's per-subscription deltas, so a live query is
1508
+ * just a `signal` the WebSocket writes to.
1509
+ *
1510
+ * `provideLunora` / `LUNORA_CLIENT` / `injectLunoraClient` are the injectable
1511
+ * provider carrying one `LunoraClient` (opens its socket lazily), wired once in the
1512
+ * application config. `liveQuery` is a live-query `signal` that opens a
1513
+ * subscription and updates on every delta, torn down automatically on
1514
+ * `DestroyRef.onDestroy`. `mutate` runs a mutation (optimistic updates + offline
1515
+ * queue pass through to the client). `connectionStatus` is a `signal` of the
1516
+ * aggregate live-socket status.
1517
+ */
1518
+ type ProvideLunoraOptions, type RateLimitOptions, type RateLimitResult, type RunActionOptions, type StreamOptions, type StreamResult, type StreamStatus, type SubscriptionOptions, type SubscriptionResult, type VoiceAgentOptions, type VoiceAgentResult, type VoiceAudioFormat, type VoiceReference, type VoiceStatus, agent, agentChat, agentState, agentToolEvents, auth, authGate, connectionStatus, flag, flags, hydratePreloaded, infiniteQuery, injectLunoraClient, liveQuery, mutate, mutator, paginatedQuery, presence, provideLunora, rateLimit, runAction, stream, subscription, voiceAgent };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{agent as e}from"./packem_shared/agent-C-GavfBl.mjs";import{agentChat as m}from"./packem_shared/agentChat-Bay8gA8i.mjs";import{agentState as a}from"./packem_shared/agentState-BAfa0QuC.mjs";import{agentToolEvents as x}from"./packem_shared/agentToolEvents-CBTZ_DsO.mjs";import{auth as i,authGate as u}from"./packem_shared/auth-BTEtMnGG.mjs";import{LUNORA_CLIENT as s,injectLunoraClient as c,provideLunora as l}from"./packem_shared/LUNORA_CLIENT-B0pGE0Tv.mjs";import{connectionStatus as L}from"./packem_shared/connectionStatus-C53UhkPi.mjs";import{flag as v,flags as y}from"./packem_shared/flag-BYFWoQTg.mjs";import{hydratePreloaded as Q}from"./packem_shared/hydratePreloaded-BKHgpXzQ.mjs";import{liveQuery as A}from"./packem_shared/liveQuery-DEIqmTPj.mjs";import{mutate as I}from"./packem_shared/mutate-DR8Uo8Hs.mjs";import{mutator as P}from"./packem_shared/mutator-Cw6jpG06.mjs";import{infiniteQuery as b,paginatedQuery as j}from"./packem_shared/infiniteQuery-C-T8hD7-.mjs";import{presence as K}from"./packem_shared/presence-BMrTlOCF.mjs";import{rateLimit as R}from"./packem_shared/rateLimit-CQazDrPJ.mjs";import{stream as _}from"./packem_shared/stream-CcvHiJf2.mjs";import{subscription as q}from"./packem_shared/subscription-DJeoGEDR.mjs";import{voiceAgent as z}from"./packem_shared/voiceAgent-CwlzrEjH.mjs";import{SKIP as D}from"@lunora/client/query";export{s as LUNORA_CLIENT,D as SKIP,e as agent,m as agentChat,a as agentState,x as agentToolEvents,i as auth,u as authGate,L as connectionStatus,v as flag,y as flags,Q as hydratePreloaded,b as infiniteQuery,c as injectLunoraClient,A as liveQuery,I as mutate,P as mutator,j as paginatedQuery,K as presence,l as provideLunora,R as rateLimit,_ as stream,q as subscription,z as voiceAgent};
1
+ import{agent as t}from"./packem_shared/agent-DjMQf-yE.mjs";import{agentChat as m}from"./packem_shared/agentChat-DyJrje49.mjs";import{agentState as f}from"./packem_shared/agentState-Bjqf9q2f.mjs";import{agentToolEvents as n}from"./packem_shared/agentToolEvents-VuBRpS6v.mjs";import{auth as i,authGate as u}from"./packem_shared/auth-C3dB8sYS.mjs";import{LUNORA_CLIENT as c,injectLunoraClient as s,provideLunora as l}from"./packem_shared/LUNORA_CLIENT-B0toApHY.mjs";import{connectionStatus as L}from"./packem_shared/connectionStatus-UhmuwzMa.mjs";import{flag as v,flags as y}from"./packem_shared/flag-BDKBQGos.mjs";import{hydratePreloaded as C}from"./packem_shared/hydratePreloaded-QPAo50Am.mjs";import{liveQuery as S}from"./packem_shared/liveQuery-eE9zMaxo.mjs";import{mutate as I}from"./packem_shared/mutate-BZvLQLyu.mjs";import{mutator as P}from"./packem_shared/mutator-DjG1yGk8.mjs";import{infiniteQuery as b,paginatedQuery as j}from"./packem_shared/infiniteQuery-DGYdgFHW.mjs";import{presence as K}from"./packem_shared/presence-1T4-U8ij.mjs";import{rateLimit as R}from"./packem_shared/rateLimit-B3h9qzh-.mjs";import{runAction as _}from"./packem_shared/runAction-BfiPq4Xz.mjs";import{stream as q}from"./packem_shared/stream-BuhiwhIH.mjs";import{subscription as z}from"./packem_shared/subscription-zJv48q6C.mjs";import{voiceAgent as D}from"./packem_shared/voiceAgent-CH--tRWP.mjs";import{SKIP as H}from"@lunora/client/query";export{c as LUNORA_CLIENT,H as SKIP,t as agent,m as agentChat,f as agentState,n as agentToolEvents,i as auth,u as authGate,L as connectionStatus,v as flag,y as flags,C as hydratePreloaded,b as infiniteQuery,s as injectLunoraClient,S as liveQuery,I as mutate,P as mutator,j as paginatedQuery,K as presence,l as provideLunora,R as rateLimit,_ as runAction,q as stream,z as subscription,D as voiceAgent};
@@ -0,0 +1 @@
1
+ import{InjectionToken as t,makeEnvironmentProviders as i,inject as c}from"@angular/core";import{LunoraClient as r}from"@lunora/client";const o=()=>globalThis.location?.origin??"",e=new t("lunora.client",{factory:()=>new r({url:o()}),providedIn:"root"}),s=(n={})=>i([{provide:e,useFactory:()=>n instanceof r?n:new r({...n,url:n.url??o()})}]),a=()=>c(e),m=n=>n??a();export{e as LUNORA_CLIENT,a as injectLunoraClient,s as provideLunora,m as resolveLunoraClient};
@@ -0,0 +1 @@
1
+ import{computed as o,signal as R}from"@angular/core";import{resolveLunoraClient as h}from"./LUNORA_CLIENT-B0toApHY.mjs";import{subscription as v}from"./subscription-zJv48q6C.mjs";const x=t=>{const{api:i,cancel:c,onError:d,run:l,runArgs:u,threadKey:n}=t,a=h(t.client),{data:f,error:m}=v(i.agents.agentThread,{key:n},{client:a,destroyRef:t.destroyRef,onError:d}),r=o(()=>f()),y=o(()=>r()?.status),s=R(!1),g=async(e,p)=>{s.set(!0);try{await a.mutation(l,{input:e,threadKey:n,...u,...p})}finally{s.set(!1)}};return{cancel:async()=>{const e=r()?.instanceId;c===void 0||e===void 0||await a.mutation(c,{instanceId:e,threadKey:n})},error:m,pending:s.asReadonly(),run:g,status:y,thread:r}};export{x as agent};
@@ -0,0 +1 @@
1
+ import{computed as a,signal as L}from"@angular/core";import{reconcileOptimistic as k,maxSeq as w}from"@lunora/client";import{resolveLunoraClient as N}from"./LUNORA_CLIENT-B0toApHY.mjs";import{stream as $}from"./stream-BuhiwhIH.mjs";import{subscription as x}from"./subscription-zJv48q6C.mjs";const z={__lunoraRef:""},W=m=>{const{api:d,cancel:g,limit:h,onError:f,send:A,sendArgs:E,stream:y,threadKey:r}=m,s=N(m.client),{destroyRef:l}=m,b=h===void 0?{key:r}:{key:r,limit:h},{data:I,error:S}=x(d.agents.agentMessages,b,{client:s,destroyRef:l,onError:f}),{data:j,error:q}=x(d.agents.agentThread,{key:r},{client:s,destroyRef:l,onError:f}),C=a(()=>S()??q()),_=y===void 0?"skip":{key:r},{chunks:D}=$(y??z,_,{client:s,destroyRef:l}),c=L([]);let v=0;const u=a(()=>j()),T=a(()=>u()?.status),i=a(()=>I()??[]),K=a(()=>{const t=i(),e=k(c(),t);if(e.length===0)return t;const n=w(t);return[...t,...e.map((o,p)=>({content:o.content,optimistic:!0,role:"user",seq:n+1+p}))]}),M=a(()=>{const t=i().filter(e=>e.role==="assistant").length;return D().filter(e=>e.kind!=="progress"&&e.threadKey===r&&e.turn>=t).map(e=>e.text).join("")}),O=async(t,e)=>{const n=v;v+=1;const o=w(i());c.set([...k(c(),i()),{content:t,id:n,maxDurableSeqAtSend:o}]);try{await s.mutation(A,{input:t,threadKey:r,...E,...e})}catch(p){throw c.set(c().filter(F=>F.id!==n)),p}},R=async(t,e,n)=>{const o=u()?.instanceId;if(o===void 0)throw new Error(`agentChat: cannot ${t} — no in-flight run (thread has no instanceId)`);await s.mutation(d.agents.agentResolveApproval,{decision:t,instanceId:o,threadKey:r,toolCallId:e,...n===void 0?{}:{note:n}})};return{approve:async(t,e)=>R("approve",t,e),cancel:async()=>{const t=u()?.instanceId;g===void 0||t===void 0||await s.mutation(g,{instanceId:t,threadKey:r})},error:C,messages:K,reject:async(t,e)=>R("reject",t,e),send:O,status:T,streamingText:M}};export{W as agentChat};
@@ -0,0 +1 @@
1
+ import{computed as c}from"@angular/core";import{subscription as n}from"./subscription-zJv48q6C.mjs";const d=t=>{const{data:e,error:r}=n(t.api.agents.agentState,{key:t.threadKey},{client:t.client,destroyRef:t.destroyRef}),a=c(()=>e());return{error:r,state:a}};export{d as agentState};
@@ -0,0 +1 @@
1
+ import{computed as v}from"@angular/core";import{resolveLunoraClient as f}from"./LUNORA_CLIENT-B0toApHY.mjs";import{stream as C}from"./stream-BuhiwhIH.mjs";import{subscription as y}from"./subscription-zJv48q6C.mjs";const I={__lunoraRef:""},N=[],m=t=>{if(t.role==="assistant"&&t.toolCalls)return t.toolCalls.map(l=>({input:l.input,seq:t.seq,toolCallId:l.id,toolName:l.name,type:"call"}));if(t.role==="tool")return t.status==="awaiting_approval"?[{seq:t.seq,type:"awaiting-approval",...t.toolCallId===void 0?{}:{toolCallId:t.toolCallId},...t.toolName===void 0?{}:{toolName:t.toolName}}]:[{output:t.content,seq:t.seq,type:"result",...t.status==="approved"||t.status==="rejected"?{status:t.status}:{},...t.toolCallId===void 0?{}:{toolCallId:t.toolCallId},...t.toolName===void 0?{}:{toolName:t.toolName}}]},R=t=>{const{api:l,limit:n,stream:e,threadKey:r}=t,a=f(t.client),{destroyRef:i}=t,u=n===void 0?{key:r}:{key:r,limit:n},{data:p}=y(l.agents.agentMessages,u,{client:a,destroyRef:i}),s=e===void 0?"skip":{key:r},{chunks:c}=C(e??I,s,{client:a,destroyRef:i});return{events:v(()=>{const d=(p()??N).flatMap(o=>m(o)??[]);for(const o of c())o.kind==="progress"&&o.threadKey===r&&d.push({data:o.data,toolCallId:o.toolCallId,type:"progress"});return d})}};export{R as agentToolEvents};
@@ -0,0 +1 @@
1
+ import{inject as h,DestroyRef as k,signal as o,computed as c}from"@angular/core";import{getIdentityStore as l,isLoadingStatus as y,isAuthenticatedStatus as m}from"@lunora/client/auth";import{resolveLunoraClient as A}from"./LUNORA_CLIENT-B0toApHY.mjs";const T=(s={})=>{const t=A(s.client),n=s.destroyRef??h(k),e=l(t),u=o(t.getAuthToken()),r=o(e.getUser()),a=o(e.getStatus()),i=t.onAuthTokenChange(()=>{u.set(t.getAuthToken())}),d=e.subscribe(()=>{r.set(e.getUser()),a.set(e.getStatus())});return n.onDestroy(()=>{i(),d()}),{setToken:g=>{t.setAuthToken(g)},status:a.asReadonly(),token:u.asReadonly(),user:r.asReadonly()}},p=(s={})=>{const{status:t}=T(s),n=c(()=>y(t()));return{isAuthenticated:c(()=>m(t())),isLoading:n}};export{T as auth,p as authGate};
@@ -0,0 +1 @@
1
+ import{inject as r,DestroyRef as i,signal as a}from"@angular/core";import{resolveLunoraClient as u}from"./LUNORA_CLIENT-B0toApHY.mjs";const y=(t={})=>{const n=u(t.client),e=t.destroyRef??r(i),o=a(n.connectionStatus()),s=n.onConnectionStatus(c=>{o.set(c)});return e.onDestroy(s),o.asReadonly()};export{y as connectionStatus};
@@ -0,0 +1 @@
1
+ import{inject as l,DestroyRef as u,signal as a}from"@angular/core";import{resolveLunoraClient as i}from"./LUNORA_CLIENT-B0toApHY.mjs";import{s as d}from"./platform-DGTu4Ucl.mjs";const m="__lunora_flags__:eval",_=t=>{const e=typeof t;return e==="boolean"||e==="number"||e==="string"?e:"object"},v={__lunoraRef:m},y=(t,e,n)=>{try{return t.subscribe(v,{default:e.default,key:e.key,type:_(e.default)},c=>{n(c)},{onError:()=>{n(e.default)}})}catch{return()=>{}}},k=(t,e,n={})=>{const c=i(n.client),f=n.destroyRef===void 0,o=n.destroyRef??l(u),r=a(e);return d(f)&&o.onDestroy(y(c,{default:e,key:t},s=>{r.set(s)})),r.asReadonly()},h=(t,e={})=>{const n=i(e.client),c=e.destroyRef===void 0,f=e.destroyRef??l(u),o=a({...t});if(!d(c))return o.asReadonly();const r=[];for(const[s,b]of Object.entries(t))r.push(y(n,{default:b,key:s},R=>{o.set({...o(),[s]:R})}));return f.onDestroy(()=>{for(const s of r)s()}),o.asReadonly()};export{k as flag,h as flags};
@@ -0,0 +1 @@
1
+ import{inject as v,DestroyRef as h,signal as s}from"@angular/core";import{resolveLunoraClient as b}from"./LUNORA_CLIENT-B0toApHY.mjs";import{s as p}from"./platform-DGTu4Ucl.mjs";const j=(i,e={})=>{const o=b(e.client),c=e.destroyRef===void 0,d=e.destroyRef??v(h),{args:a,functionPath:f,shardKey:y,value:l}=i,t=s(o.identityEpoch()===0?l:void 0),n=s(void 0),u={__lunoraRef:f};if(p(c)){const R=o.subscribe(u,a,r=>{t.set(r),n.set(void 0)},{onError:r=>{n.set(r)},shardKey:y}),m=o.onIdentityChange(()=>{t.set(void 0)});d.onDestroy(()=>{m(),R()})}return{data:t.asReadonly(),error:n.asReadonly()}};export{j as hydratePreloaded};
@@ -0,0 +1 @@
1
+ import{computed as m,inject as q,DestroyRef as z,signal as x}from"@angular/core";import{initialPages as H,derivePaginationStatus as _,applyLoadMore as J,rebalance as T}from"@lunora/client/pagination";import{stableWireKey as U}from"@lunora/wire";import{resolveLunoraClient as B}from"./LUNORA_CLIENT-B0toApHY.mjs";import{s as E,a as X}from"./platform-DGTu4Ucl.mjs";const h=(o,t)=>`${o}::${U(t)}`,L=(o,t)=>({...t,paginationOpts:{cursor:o.lower,endCursor:o.upper,numItems:o.numItems}}),$=(o,t,n,i)=>{const r=B(n.client),K=n.destroyRef===void 0&&i===void 0,{initialNumItems:a,shardKey:w}=n,g=o.__lunoraRef,l=t==="skip"?{}:t,e=x(H(a)),C=x([]),D=x("LoadingFirstPage"),b=x(void 0),R=new Map,p=new Map,F=new Set,S=()=>{const f=e().map(s=>{const u=h(g,L(s,l));return p.get(u)});C.set(f);const{status:P}=_(t==="skip",f);D.set(P)},W=(y,f)=>{const P=s=>h(g,L(s,l));for(const s of f){const u=P(s);if(p.has(u))continue;const d=y.find(c=>c.lower===s.lower);if(d){const c=p.get(P(d));c&&p.set(u,c)}}},G=y=>{const f=new Set;for(const s of y)f.add(h(g,L(s,l)));for(const[s,u]of R)f.has(u.currentKey)||(u.unsub(),R.delete(s),p.delete(u.currentKey));const P=new Set([...R.values()].map(s=>s.currentKey));for(const s of y){const u=L(s,l),d=h(g,u);if(P.has(d))continue;const c={currentKey:d,unsub:void 0};F.add(d);const j=r.subscribe(o,u,M=>{if(p.set(c.currentKey,M),F.delete(c.currentKey),b.set(void 0),S(),F.size===0){const v=e(),k=T(v,C());k&&(W(v,k),e.set(k),I(k),S())}},{onError:M=>{F.delete(d),b.set(M);const v=e(),k=v.at(-1);v.length>1&&k&&!p.has(d)&&h(g,L(k,l))===d&&(e.set(v.slice(0,-1)),I(e())),S(),n.onError?.(M)},shardKey:w});c.unsub=j,R.set(d,c),P.add(d)}};let N=!1,O=!1;const I=y=>{if(N){O=!0;return}N=!0;try{let f=y;do O=!1,G(f),f=e();while(O)}finally{N=!1}};t!=="skip"&&E(K)&&I(e()),S();const Q=()=>{for(const y of R.values())y.unsub();R.clear(),p.clear()};return i===void 0?(n.destroyRef??q(z)).onDestroy(Q):i(Q),{error:b,loadMore:y=>{if(t==="skip")return;const{nextCursor:f,status:P}=_(!1,C());if(P!=="CanLoadMore")return;const s=J(e(),f,y);if(!s)return;const u=e().at(-1),d=s.at(-2);if(u&&d){const c=h(g,L(u,l)),j=h(g,L(d,l)),M=R.get(c);if(M&&c!==j){const v=p.get(c);v&&p.set(j,v),M.unsub(),R.delete(c),p.delete(c)}}b.set(void 0),e.set(s),I(e()),S()},pageResults:C,skipped:m(()=>t==="skip"),status:D}},V=(o,t,n)=>{if(typeof t!="function")return $(o,t,n);const i=B(n.client),r=n.destroyRef===void 0,K=n.destroyRef??q(z),a=x(void 0);return E(r)&&X(t,{destroyRef:K,injector:n.injector},(w,g)=>{const l=[];a.set($(o,w,{...n,client:i},e=>l.push(e))),g(()=>{for(const e of l)e()})}),{error:m(()=>a()?.error()),loadMore:w=>{a()?.loadMore(w)},pageResults:m(()=>a()?.pageResults()??[]),skipped:m(()=>a()?.skipped()??t()==="skip"),status:m(()=>a()?.status()??"LoadingFirstPage")}},ne=(o,t,n)=>{const i=V(o,t,n),r=m(()=>i.pageResults().flatMap(a=>a?.page??[])),K=m(()=>{const a=i.status();return!i.skipped()&&(a==="LoadingFirstPage"||a==="LoadingMore")});return{error:i.error,isLoading:K,loadMore:i.loadMore,results:r,status:i.status}},oe=(o,t,n)=>{const{initialNumItems:i}=n,r=V(o,t,n),K=m(()=>r.pageResults().flatMap(e=>e?[e.page]:[])),a=m(()=>!r.skipped()&&r.status()==="LoadingFirstPage"),w=m(()=>r.status()==="CanLoadMore"),g=m(()=>!r.skipped()&&r.status()==="LoadingMore"),l=e=>{r.loadMore(e??i)};return{error:r.error,fetchNextPage:l,hasNextPage:w,isFetchingNextPage:g,isLoading:a,pages:K,status:r.status}};export{oe as infiniteQuery,ne as paginatedQuery};
@@ -0,0 +1 @@
1
+ import{inject as u,DestroyRef as y,signal as v}from"@angular/core";import{createQuerySubscription as m}from"@lunora/client/query";import{resolveLunoraClient as R}from"./LUNORA_CLIENT-B0toApHY.mjs";import{s as p,a as b}from"./platform-DGTu4Ucl.mjs";const g=(c,t,e={})=>{const i=R(e.client),a=e.destroyRef===void 0,s=e.destroyRef??u(y),o=v(void 0),n=(r,f)=>{o.set(void 0);const l=m(i,c,r,{onData:d=>{o.set(d)},onError:e.onError,onReset:()=>{o.set(void 0)}},{shardKey:e.shardKey});f(l)};return p(a)&&(typeof t=="function"?b(t,{destroyRef:s,injector:e.injector},n):n(t,r=>s.onDestroy(r))),o.asReadonly()};export{g as liveQuery};
@@ -0,0 +1 @@
1
+ import{resolveLunoraClient as i}from"./LUNORA_CLIENT-B0toApHY.mjs";const a=(t,o,n={})=>{const{client:e,...r}=n;return i(e).mutation(t,o,r)};export{a as mutate};
@@ -0,0 +1 @@
1
+ import{signal as o,computed as d}from"@angular/core";import{createMutatorRunner as c}from"@lunora/client";const u=n=>{const r=o(void 0),e=o(!1),s=d(()=>r()!==void 0),{mutate:a,reset:i}=c(n,{setError:t=>{r.set(t)},setPending:t=>{e.set(t)}});return{error:r.asReadonly(),isError:s,mutate:a,pending:e.asReadonly(),reset:i}};export{u as mutator};