@ateam-ai-mobile/core 0.1.0 → 0.1.2

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.d.ts CHANGED
@@ -66,16 +66,30 @@ interface AdasUser {
66
66
  actorId: string;
67
67
  name?: string;
68
68
  email?: string;
69
+ /** Roles from the host's identity (e.g. JWT claims) — forwarded to plugins
70
+ * as PluginContext.user.roles. */
71
+ roles?: string[];
69
72
  }
73
+ /** A URL that is either static or resolved on each read. Hosts with a
74
+ * runtime env switcher (dev/prod) pass a getter so the SDK always sees the
75
+ * currently-selected backend without re-calling initAdas(). */
76
+ type UrlSource = string | (() => string);
70
77
  interface AdasConfig {
71
- /** Core API base URL, e.g. https://app.ateam-ai.com */
72
- coreUrl: string;
78
+ /** Core API base URL, e.g. https://app.ateam-ai.com. Pass a getter to
79
+ * support a runtime env switch without re-initializing. */
80
+ coreUrl: UrlSource;
73
81
  /** Voice service base URL (optional — only voice features need it). */
74
- voiceUrl?: string;
82
+ voiceUrl?: UrlSource;
83
+ /** Consumer-auth base URL, e.g. https://consumer-auth.ateam-ai.com. Only
84
+ * needed for `switchTenant()` (re-scoping the session to another tenant
85
+ * the user belongs to). */
86
+ consumerAuthUrl?: UrlSource;
75
87
  tokenProvider: TokenProvider;
76
- /** Tenant slug — informational/telemetry only. The backend derives the
77
- * tenant from the JWT; the SDK never sends a tenant header. */
78
- tenant?: string;
88
+ /** Tenant slug — used for plugin URL resolution and voice, never sent as a
89
+ * header (the backend derives the tenant from the JWT). Pass a getter when
90
+ * the host resolves the tenant after startup (storage hydration, runtime
91
+ * tenant switch). */
92
+ tenant?: string | (() => string);
79
93
  /** Current end user as known to the host. actorId is used as the chat
80
94
  * reply context; without it, replies route to 'unknown'. */
81
95
  getUser?: () => AdasUser | null;
@@ -83,6 +97,24 @@ interface AdasConfig {
83
97
  * survive app restarts. No-op when omitted (previews live in memory for
84
98
  * the session only). @ateam-ai-mobile/ui ships an Expo/RN implementation. */
85
99
  attachmentCache?: AttachmentCache;
100
+ /** Called by `switchTenant()` with the freshly-minted session for the
101
+ * target tenant. The host MUST persist it here (store the new JWT so
102
+ * tokenProvider.getToken() returns it, and update the active tenant) —
103
+ * the SDK never stores credentials. Awaited before the chat reconnects. */
104
+ onSession?: (session: AdasSession) => void | Promise<void>;
105
+ }
106
+ /** A tenant-scoped session minted by the platform (e.g. via switchTenant). */
107
+ interface AdasSession {
108
+ jwt: string;
109
+ tenant: {
110
+ id: string;
111
+ name: string;
112
+ };
113
+ actor: {
114
+ id: string;
115
+ email: string | null;
116
+ roles: string[];
117
+ };
86
118
  }
87
119
  /** Register the SDK configuration. Call once at app start, before any other
88
120
  * SDK API. Calling again replaces the config (e.g. env switch) — combine
@@ -93,6 +125,7 @@ declare function getConfig(): AdasConfig;
93
125
  declare function getCoreApiUrl(): string;
94
126
  declare function getCoreWsUrl(): string;
95
127
  declare function getVoiceApiUrl(): string;
128
+ declare function getConsumerAuthApiUrl(): string;
96
129
  declare function getTenant(): string;
97
130
  declare function getUser(): AdasUser | null;
98
131
  declare function getToken(): string | null;
@@ -142,6 +175,35 @@ declare function postCommandResult(correlationId: string, result: any, error?: s
142
175
  */
143
176
  declare function unwrapMcpResult(result: any): any;
144
177
 
178
+ interface TenantMembership {
179
+ id: string;
180
+ name: string;
181
+ role: string | null;
182
+ }
183
+ /**
184
+ * List the tenants the CURRENT user belongs to (GET /api/tenants/list).
185
+ *
186
+ * The list is membership-scoped: for consumer JWTs the backend returns ONLY
187
+ * tenants where the user's login identity (google/apple oauth or embed id)
188
+ * has an active actor; builder JWTs get their user-doc memberships. It never
189
+ * leaks the full tenant list. Returns [] when signed out or unknown.
190
+ */
191
+ declare function listMyTenants(): Promise<TenantMembership[]>;
192
+ /**
193
+ * Re-scope the whole session to another tenant the user already belongs to.
194
+ *
195
+ * The backend treats the JWT tenant claim as the sole source of truth, so
196
+ * switching = minting a fresh JWT for the target tenant's actor. The SDK
197
+ * owns the call (POST consumer-auth /platform/consumer/switch-tenant, authed
198
+ * by the current token); the HOST persists the new session via
199
+ * `config.onSession` (the SDK never stores credentials). The chat stream is
200
+ * then torn down and cleared so it reconnects against the new tenant.
201
+ *
202
+ * Requires `consumerAuthUrl` and `onSession` in the initAdas() config.
203
+ * Throws on any non-OK response (e.g. not a member of the target tenant).
204
+ */
205
+ declare function switchTenant(targetTenantId: string): Promise<AdasSession>;
206
+
145
207
  interface ToolCall {
146
208
  name: string;
147
209
  args: Record<string, unknown>;
@@ -386,4 +448,310 @@ declare const borderRadius: {
386
448
  readonly full: 9999;
387
449
  };
388
450
 
389
- export { type AdasConfig, type AdasUser, type AttachmentCache, type AttachmentPreview, type BufferedCommand, type JobProgress, type Message, type MessageAttachment, type OutgoingAttachment, PluginCommandEmitter, type RefreshOutcome, TABLE_BLOCK_CLOSE, TABLE_BLOCK_OPEN, type TokenProvider, type ToolCall, type UIAction, ada, apiFetch, apiFetchRaw, blocksToText, borderRadius, closeChatStream, colors, connectorCall, fontSize, getConfig, getCoreApiUrl, getCoreWsUrl, getTenant, getToken, getUser, getVoiceApiUrl, initAdas, isAdasInitialized, mcpFetch, mcpToolCall, pluginCommandEmitter, postCommandResult, spacing, unwrapMcpResult, useChatStore };
451
+ /**
452
+ * Client for Core's /api/acs/* proxy → ACS service. Powers the "widgets"
453
+ * surface on home: AI-generated artifacts that render as carousel tiles and
454
+ * full-screen interactive panels via the bundleUrl — plus the home
455
+ * "top actions" feed.
456
+ *
457
+ * Endpoints:
458
+ * POST /api/acs/surface — list active artifacts for a surface
459
+ * POST /api/acs/event — usage tracking (clicked/dismissed/etc.)
460
+ * GET /api/acs/made-for-you — full library, all lifecycle stages
461
+ * DELETE /api/acs/artifacts/{id} — user-initiated retire (idempotent)
462
+ * PATCH /api/acs/artifacts/{id} — visibility + rename
463
+ * PUT /api/acs/order — drag-reorder
464
+ * GET /api/acs/home-actions — top-actions feed (+ PATCH/PUT order)
465
+ * WS topics acs.artifacts / acs.home-actions — cross-device sync (see ./ws)
466
+ */
467
+ interface AcsArtifact {
468
+ id: string;
469
+ name: string;
470
+ description?: string;
471
+ iconHint?: string;
472
+ manifest?: Record<string, any>;
473
+ bundleUrl: string;
474
+ version: number;
475
+ provenance?: Record<string, any>;
476
+ kind?: 'user' | 'featured';
477
+ visibility?: 'pinned' | 'hidden';
478
+ pinOrder?: number;
479
+ canDelete?: boolean;
480
+ canRename?: boolean;
481
+ canHide?: boolean;
482
+ previewMode?: 'live' | 'snapshot' | 'none';
483
+ previewUrl?: string;
484
+ }
485
+ type AcsSurface = 'home' | 'library' | (string & {});
486
+ type AcsEvent = 'clicked' | 'dismissed' | 'acted' | 'ignored';
487
+ type AcsDeleteReason = 'user_long_press_delete' | 'user_swipe_delete' | 'user_bulk_delete' | (string & {});
488
+ type AcsPatchReason = 'user_long_press_hide' | 'user_long_press_unhide' | 'user_long_press_rename' | (string & {});
489
+ /**
490
+ * List artifacts surfaced for the given surface name. Returns [] on error
491
+ * (network, auth, or empty result) — callers shouldn't have to distinguish.
492
+ * Use surface="home" for the carousel.
493
+ */
494
+ declare function listSurface(surface: AcsSurface, context?: Record<string, any>): Promise<AcsArtifact[]>;
495
+ /**
496
+ * Full library — every artifact across all lifecycle stages. Used by a
497
+ * Library screen's Yours + Hidden sections.
498
+ */
499
+ declare function listMadeForYou(): Promise<AcsArtifact[]>;
500
+ interface DeleteResult {
501
+ ok: boolean;
502
+ /** True when the server already had this artifact retired. Treat as success. */
503
+ already?: boolean;
504
+ /** True for HTTP 404 — artifact gone or never owned by caller. Treat as success
505
+ * (remove from local state) per the backend's contract: no existence leak. */
506
+ notFound?: boolean;
507
+ /** HTTP status returned by the server. */
508
+ status: number;
509
+ error?: string;
510
+ }
511
+ /**
512
+ * Retire a user widget. Per backend contract:
513
+ * 200 ok → success
514
+ * 200 ok + already:true → idempotent, treat as success
515
+ * 404 → already gone or not owned, treat as success
516
+ * 5xx / network → real failure, caller should rollback optimistic remove
517
+ */
518
+ declare function deleteArtifact(artifactId: string, reason?: AcsDeleteReason): Promise<DeleteResult>;
519
+ interface PatchResult {
520
+ ok: boolean;
521
+ /** Updated tile when the server returns the new state. */
522
+ artifact?: AcsArtifact;
523
+ already?: boolean;
524
+ notFound?: boolean;
525
+ status: number;
526
+ error?: string;
527
+ }
528
+ /**
529
+ * Update an artifact's visibility (hide/unhide) and/or name (rename). One
530
+ * call covers both because backend offers a single PATCH endpoint with
531
+ * optional fields. At least one of visibility/name must be provided.
532
+ *
533
+ * Per backend contract (mirrors DELETE semantics):
534
+ * 200 ok → success
535
+ * 200 ok + already:true → idempotent no-op, treat as success
536
+ * 404 → not found / not owned, treat as success
537
+ * 400 / 403 → real failure, surface to user
538
+ * 5xx / network → real failure, caller should rollback
539
+ */
540
+ declare function patchArtifact(artifactId: string, body: {
541
+ visibility?: 'pinned' | 'hidden';
542
+ name?: string;
543
+ }, reason: AcsPatchReason): Promise<PatchResult>;
544
+ /**
545
+ * Persist a new pin order. Body lists currently-pinned artifact IDs in the
546
+ * new visual order; server validates ownership + pinned state of each ID.
547
+ *
548
+ * Returns { ok: false, error } on failure. 400 means the array contained
549
+ * an id that's not owned or not pinned — caller should refetch /surface
550
+ * and re-render rather than fight the server.
551
+ */
552
+ declare function setOrder(pinned: string[]): Promise<{
553
+ ok: boolean;
554
+ status: number;
555
+ error?: string;
556
+ }>;
557
+ /**
558
+ * Record a usage event. Fire-and-forget — never throws, never blocks the UI.
559
+ * Use surface to tell the backend which surface the event came from
560
+ * (e.g. 'home' for the carousel).
561
+ */
562
+ declare function recordEvent(artifactId: string, event: AcsEvent, surface?: AcsSurface): Promise<void>;
563
+ type HomeActionLeaf = {
564
+ type: 'send_message';
565
+ prompt: string;
566
+ skillSlug?: string;
567
+ } | {
568
+ type: 'open_widget';
569
+ artifactId: string;
570
+ } | {
571
+ type: string;
572
+ [k: string]: any;
573
+ };
574
+ interface HomeAction {
575
+ actionId: string;
576
+ pinOrder?: number;
577
+ title: string;
578
+ subtitle?: string;
579
+ icon?: string;
580
+ action: HomeActionLeaf;
581
+ source?: 'curated' | 'pinned_by_user' | 'skill_authored' | (string & {});
582
+ canDismiss?: boolean;
583
+ canPin?: boolean;
584
+ pinned?: boolean;
585
+ }
586
+ /** List the home top-actions feed. Returns [] on any error. */
587
+ declare function listHomeActions(): Promise<HomeAction[]>;
588
+ type HomeActionReason = 'user_pin' | 'user_unpin' | 'user_dismiss' | 'user_drag_reorder' | (string & {});
589
+ /** Pin/unpin or dismiss a card. 200 already / 404 both count as success. */
590
+ declare function patchHomeAction(actionId: string, body: {
591
+ pinned?: boolean;
592
+ dismissed?: boolean;
593
+ }, reason: HomeActionReason): Promise<{
594
+ ok: boolean;
595
+ action?: HomeAction;
596
+ status: number;
597
+ error?: string;
598
+ }>;
599
+ /** Persist a new card order. Optimistic; caller rolls back on failure. */
600
+ declare function setHomeActionOrder(order: string[]): Promise<{
601
+ ok: boolean;
602
+ status: number;
603
+ error?: string;
604
+ }>;
605
+
606
+ interface WidgetsState {
607
+ /** Tiles to render in the home carousel. Order matches what /surface
608
+ * returned; sort by pinOrder when present. */
609
+ tiles: AcsArtifact[];
610
+ /** True after the first /surface fetch completes (success OR empty). */
611
+ hydrated: boolean;
612
+ /** True while a /surface request is in flight. */
613
+ loading: boolean;
614
+ /** Last error string from /surface; null on success or pre-fetch. */
615
+ error: string | null;
616
+ /** First load — idempotent; safe to call from multiple effects. */
617
+ hydrate: () => Promise<void>;
618
+ /** Force re-fetch; call on app foreground and after destructive ops. */
619
+ refresh: () => Promise<void>;
620
+ /** Reset to empty (sign-out, env switch). */
621
+ clear: () => void;
622
+ /**
623
+ * Optimistic remove. Returns { ok: false, error } only on real network /
624
+ * 5xx failures — 404 and already:true rollback to ok:true per the backend
625
+ * contract (no existence leak; the row is gone either way).
626
+ */
627
+ remove: (artifactId: string, reason?: AcsDeleteReason) => Promise<{
628
+ ok: boolean;
629
+ error?: string;
630
+ }>;
631
+ /** Optimistic hide (visibility → 'hidden'). Tile disappears from carousel. */
632
+ hide: (artifactId: string) => Promise<{
633
+ ok: boolean;
634
+ error?: string;
635
+ }>;
636
+ /** Optimistic unhide (visibility → 'pinned'). Tile reappears in carousel. */
637
+ unhide: (artifactId: string) => Promise<{
638
+ ok: boolean;
639
+ error?: string;
640
+ }>;
641
+ /** Optimistic rename. Trims input and rejects empty / overlong names locally. */
642
+ rename: (artifactId: string, name: string) => Promise<{
643
+ ok: boolean;
644
+ error?: string;
645
+ }>;
646
+ /**
647
+ * Persist a new pin order to the server. `pinnedIds` is the visible order
648
+ * of currently-pinned tiles. Optimistic — applies locally first, rolls
649
+ * back on server rejection.
650
+ */
651
+ reorder: (pinnedIds: string[]) => Promise<{
652
+ ok: boolean;
653
+ error?: string;
654
+ }>;
655
+ /** WS 'updated' event — replace the tile by id (hide/unhide/rename land here). */
656
+ applyServerUpdate: (artifact: AcsArtifact) => void;
657
+ /** WS 'retired' event — remove the tile by id. */
658
+ applyServerRetire: (artifactId: string) => void;
659
+ /** WS 'order' event — re-rank tiles to match the pinned ID array. */
660
+ applyServerOrder: (pinnedIds: string[]) => void;
661
+ /** Fire-and-forget usage event. Caller doesn't await. */
662
+ track: (artifactId: string, event: 'clicked' | 'dismissed' | 'acted' | 'ignored') => void;
663
+ }
664
+ declare const useWidgetsStore: zustand.UseBoundStore<zustand.StoreApi<WidgetsState>>;
665
+
666
+ interface HomeActionsState {
667
+ actions: HomeAction[];
668
+ hydrated: boolean;
669
+ loading: boolean;
670
+ hydrate: () => Promise<void>;
671
+ refresh: () => Promise<void>;
672
+ clear: () => void;
673
+ /** Optimistic dismiss — removes locally, rolls back on real failure. */
674
+ dismiss: (actionId: string) => Promise<{
675
+ ok: boolean;
676
+ error?: string;
677
+ }>;
678
+ /** Optimistic pin/unpin. */
679
+ setPinned: (actionId: string, pinned: boolean) => Promise<{
680
+ ok: boolean;
681
+ error?: string;
682
+ }>;
683
+ /** Optimistic reorder — `orderedIds` is the new visual order. */
684
+ reorder: (orderedIds: string[]) => Promise<{
685
+ ok: boolean;
686
+ error?: string;
687
+ }>;
688
+ applyServerUpsert: (action: HomeAction) => void;
689
+ applyServerRemove: (actionId: string) => void;
690
+ applyServerOrder: (orderedIds: string[]) => void;
691
+ }
692
+ declare const useHomeActionsStore: zustand.UseBoundStore<zustand.StoreApi<HomeActionsState>>;
693
+
694
+ /**
695
+ * Long-lived WebSocket subscription to the `acs.artifacts` and
696
+ * `acs.home-actions` topics. Protocol (backend websocket.js):
697
+ *
698
+ * client → server : { type: "subscribe", topic: "acs.artifacts" }
699
+ * server → client : { event: "subscribed", data: { topic: "acs.artifacts" } }
700
+ * server → client : { topic: "acs.artifacts", event: "updated", artifact: {...} }
701
+ * server → client : { topic: "acs.artifacts", event: "retired", artifactId: "..." }
702
+ * server → client : { topic: "acs.artifacts", event: "order", pinned: [...] }
703
+ *
704
+ * Events flow into the stores' applyServer* methods so we don't loop (those
705
+ * methods mutate local state only — no API calls).
706
+ *
707
+ * Lifecycle:
708
+ * connectAcsWs(token, tenant) starts a single connection + subscribe.
709
+ * On disconnect, exponential-backoff reconnect (capped). Call
710
+ * notifyAcsWsForeground() from the host's AppState listener to
711
+ * force-reconnect when the socket dropped while backgrounded (this module
712
+ * is host-agnostic — no react-native import — so the host owns AppState).
713
+ * On signout, disconnectAcsWs() closes the socket and stops reconnects.
714
+ *
715
+ * Backend's spec note: "WS is best-effort; the GET is the source of truth"
716
+ * — so widgetsStore.refresh() on foreground stays the safety net even when
717
+ * the WS is healthy. This file is the realtime cherry on top.
718
+ */
719
+ /**
720
+ * Call from the host's AppState listener when the app returns to the
721
+ * foreground — if the socket dropped while backgrounded, reconnect
722
+ * immediately rather than waiting out the backoff timer.
723
+ */
724
+ declare function notifyAcsWsForeground(): void;
725
+ /**
726
+ * Start the ACS WS subscription. Idempotent — calling twice with the same
727
+ * token/tenant is a no-op. Call once the host says the user is signed in
728
+ * (JWT available).
729
+ */
730
+ declare function connectAcsWs(token: string, tenant: string): void;
731
+ /**
732
+ * Stop the ACS WS subscription. Call on signout / env switch.
733
+ */
734
+ declare function disconnectAcsWs(): void;
735
+
736
+ /**
737
+ * ACS host DI seams. Both optional — the ACS layer works without them:
738
+ * no reachability reporting, and the home-actions cache lives in memory only.
739
+ */
740
+ /** Host hook fired on every ACS fetch outcome — a response (any status)
741
+ * proves the server is reachable; a thrown fetch means it isn't. The
742
+ * reference app wires this to its connectivity banner store. */
743
+ interface AcsReachabilityReporter {
744
+ up: () => void;
745
+ down: () => void;
746
+ }
747
+ declare function setAcsReachabilityReporter(r: AcsReachabilityReporter | null): void;
748
+ /** Minimal async KV used to persist the home-actions feed across cold starts
749
+ * (AsyncStorage-shaped). @ateam-ai-mobile/expo wires AsyncStorage in
750
+ * setupExpoProviders(); without a provider the cache is a no-op. */
751
+ interface AcsKvStorage {
752
+ getItem(key: string): Promise<string | null>;
753
+ setItem(key: string, value: string): Promise<void>;
754
+ }
755
+ declare function setAcsCacheStorage(kv: AcsKvStorage | null): void;
756
+
757
+ export { type AcsArtifact, type AcsDeleteReason, type AcsEvent, type AcsKvStorage, type AcsPatchReason, type AcsReachabilityReporter, type AcsSurface, type AdasConfig, type AdasSession, type AdasUser, type AttachmentCache, type AttachmentPreview, type BufferedCommand, type DeleteResult, type HomeAction, type HomeActionLeaf, type HomeActionReason, type JobProgress, type Message, type MessageAttachment, type OutgoingAttachment, type PatchResult, PluginCommandEmitter, type RefreshOutcome, TABLE_BLOCK_CLOSE, TABLE_BLOCK_OPEN, type TenantMembership, type TokenProvider, type ToolCall, type UIAction, ada, apiFetch, apiFetchRaw, blocksToText, borderRadius, closeChatStream, colors, connectAcsWs, connectorCall, deleteArtifact, disconnectAcsWs, fontSize, getConfig, getConsumerAuthApiUrl, getCoreApiUrl, getCoreWsUrl, getTenant, getToken, getUser, getVoiceApiUrl, initAdas, isAdasInitialized, listHomeActions, listMadeForYou, listMyTenants, listSurface, mcpFetch, mcpToolCall, notifyAcsWsForeground, patchArtifact, patchHomeAction, pluginCommandEmitter, postCommandResult, recordEvent, setAcsCacheStorage, setAcsReachabilityReporter, setHomeActionOrder, setOrder, spacing, switchTenant, unwrapMcpResult, useChatStore, useHomeActionsStore, useWidgetsStore };