@burdenoff/microfe-subscriberbot 2026.706.3 → 2026.713.1

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 (115) hide show
  1. package/dist/generated/global-operations.d.ts +2 -0
  2. package/dist/generated/global-operations.d.ts.map +1 -0
  3. package/dist/generated/global-types.d.ts +23527 -0
  4. package/dist/generated/global-types.d.ts.map +1 -0
  5. package/dist/generated/wspace-operations.d.ts +2 -0
  6. package/dist/generated/wspace-operations.d.ts.map +1 -0
  7. package/dist/generated/wspace-types.d.ts +57851 -0
  8. package/dist/generated/wspace-types.d.ts.map +1 -0
  9. package/dist/index.d.ts +6 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +2 -1
  12. package/dist/subscriberbot/SubscriberBotRoot.d.ts +5 -0
  13. package/dist/subscriberbot/SubscriberBotRoot.d.ts.map +1 -0
  14. package/dist/subscriberbot/SubscriberBotRoot.js +56 -40
  15. package/dist/subscriberbot/SubscriberBotRoot.js.map +1 -1
  16. package/dist/subscriberbot/SubscriberBotRoutes.d.ts +4 -0
  17. package/dist/subscriberbot/SubscriberBotRoutes.d.ts.map +1 -0
  18. package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
  19. package/dist/subscriberbot/components/EmptyState.d.ts +18 -0
  20. package/dist/subscriberbot/components/EmptyState.d.ts.map +1 -0
  21. package/dist/subscriberbot/components/MetricsCard.d.ts +16 -0
  22. package/dist/subscriberbot/components/MetricsCard.d.ts.map +1 -0
  23. package/dist/subscriberbot/components/Modal.d.ts +13 -0
  24. package/dist/subscriberbot/components/Modal.d.ts.map +1 -0
  25. package/dist/subscriberbot/components/PageLayout.d.ts +23 -0
  26. package/dist/subscriberbot/components/PageLayout.d.ts.map +1 -0
  27. package/dist/subscriberbot/components/StateViews.d.ts +24 -0
  28. package/dist/subscriberbot/components/StateViews.d.ts.map +1 -0
  29. package/dist/subscriberbot/components/StatusBadge.d.ts +9 -0
  30. package/dist/subscriberbot/components/StatusBadge.d.ts.map +1 -0
  31. package/dist/subscriberbot/components/index.d.ts +13 -0
  32. package/dist/subscriberbot/components/index.d.ts.map +1 -0
  33. package/dist/subscriberbot/components/viz.d.ts +58 -0
  34. package/dist/subscriberbot/components/viz.d.ts.map +1 -0
  35. package/dist/subscriberbot/components/viz.js.map +1 -1
  36. package/dist/subscriberbot/config/assistantUsecases.d.ts +13 -0
  37. package/dist/subscriberbot/config/assistantUsecases.d.ts.map +1 -0
  38. package/dist/subscriberbot/context/SubscriberBotContext.d.ts +16 -0
  39. package/dist/subscriberbot/context/SubscriberBotContext.d.ts.map +1 -0
  40. package/dist/subscriberbot/context/index.d.ts +6 -0
  41. package/dist/subscriberbot/context/index.d.ts.map +1 -0
  42. package/dist/subscriberbot/hooks/index.d.ts +7 -0
  43. package/dist/subscriberbot/hooks/index.d.ts.map +1 -0
  44. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts +105 -0
  45. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts.map +1 -0
  46. package/dist/subscriberbot/index.d.ts +12 -0
  47. package/dist/subscriberbot/index.d.ts.map +1 -0
  48. package/dist/subscriberbot/index.js +1 -0
  49. package/dist/subscriberbot/pages/AssetVaultPage.d.ts +4 -0
  50. package/dist/subscriberbot/pages/AssetVaultPage.d.ts.map +1 -0
  51. package/dist/subscriberbot/pages/AssetVaultPage.js.map +1 -1
  52. package/dist/subscriberbot/pages/DashboardPage.d.ts +12 -0
  53. package/dist/subscriberbot/pages/DashboardPage.d.ts.map +1 -0
  54. package/dist/subscriberbot/pages/DashboardPage.js.map +1 -1
  55. package/dist/subscriberbot/pages/InboxPage.d.ts +12 -0
  56. package/dist/subscriberbot/pages/InboxPage.d.ts.map +1 -0
  57. package/dist/subscriberbot/pages/InboxPage.js.map +1 -1
  58. package/dist/subscriberbot/pages/InsightsPage.d.ts +4 -0
  59. package/dist/subscriberbot/pages/InsightsPage.d.ts.map +1 -0
  60. package/dist/subscriberbot/pages/InsightsPage.js.map +1 -1
  61. package/dist/subscriberbot/pages/InvoicesPage.d.ts +13 -0
  62. package/dist/subscriberbot/pages/InvoicesPage.d.ts.map +1 -0
  63. package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -1
  64. package/dist/subscriberbot/pages/WorkflowsPage.d.ts +15 -0
  65. package/dist/subscriberbot/pages/WorkflowsPage.d.ts.map +1 -0
  66. package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -1
  67. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts +11 -0
  68. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts.map +1 -0
  69. package/dist/subscriberbot/pages/agents/AgentNewPage.d.ts +8 -0
  70. package/dist/subscriberbot/pages/agents/AgentNewPage.d.ts.map +1 -0
  71. package/dist/subscriberbot/pages/agents/AgentsListPage.d.ts +11 -0
  72. package/dist/subscriberbot/pages/agents/AgentsListPage.d.ts.map +1 -0
  73. package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -1
  74. package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts +10 -0
  75. package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts.map +1 -0
  76. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -1
  77. package/dist/subscriberbot/pages/providers/ProviderNewPage.d.ts +10 -0
  78. package/dist/subscriberbot/pages/providers/ProviderNewPage.d.ts.map +1 -0
  79. package/dist/subscriberbot/pages/providers/ProvidersListPage.d.ts +12 -0
  80. package/dist/subscriberbot/pages/providers/ProvidersListPage.d.ts.map +1 -0
  81. package/dist/subscriberbot/pages/providers/ProvidersListPage.js.map +1 -1
  82. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts +13 -0
  83. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts.map +1 -0
  84. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  85. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.d.ts +10 -0
  86. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.d.ts.map +1 -0
  87. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -1
  88. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.d.ts +10 -0
  89. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.d.ts.map +1 -0
  90. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js.map +1 -1
  91. package/dist/subscriberbot/services/createSandboxAssistantTransport.d.ts +24 -0
  92. package/dist/subscriberbot/services/createSandboxAssistantTransport.d.ts.map +1 -0
  93. package/dist/subscriberbot/services/createSandboxAssistantTransport.js +14 -0
  94. package/dist/subscriberbot/services/createSandboxAssistantTransport.js.map +1 -0
  95. package/dist/subscriberbot/store/index.d.ts +6 -0
  96. package/dist/subscriberbot/store/index.d.ts.map +1 -0
  97. package/dist/subscriberbot/store/subscriberbotStore.d.ts +60 -0
  98. package/dist/subscriberbot/store/subscriberbotStore.d.ts.map +1 -0
  99. package/dist/subscriberbot/types/assistant.d.ts +57 -0
  100. package/dist/subscriberbot/types/assistant.d.ts.map +1 -0
  101. package/dist/subscriberbot/types/index.d.ts +465 -0
  102. package/dist/subscriberbot/types/index.d.ts.map +1 -0
  103. package/dist/subscriberbot/utils/cn.d.ts +4 -0
  104. package/dist/subscriberbot/utils/cn.d.ts.map +1 -0
  105. package/dist/subscriberbot/utils/formatters.d.ts +53 -0
  106. package/dist/subscriberbot/utils/formatters.d.ts.map +1 -0
  107. package/dist/subscriberbot/utils/index.d.ts +8 -0
  108. package/dist/subscriberbot/utils/index.d.ts.map +1 -0
  109. package/dist/subscriberbot/utils/navigation.d.ts +20 -0
  110. package/dist/subscriberbot/utils/navigation.d.ts.map +1 -0
  111. package/dist/subscriberbot/utils/pageContext.d.ts +21 -0
  112. package/dist/subscriberbot/utils/pageContext.d.ts.map +1 -0
  113. package/dist/subscriberbot/utils/pageContext.js +47 -0
  114. package/dist/subscriberbot/utils/pageContext.js.map +1 -0
  115. package/package.json +7 -3
@@ -0,0 +1,16 @@
1
+ import { FC, PropsWithChildren } from 'react';
2
+ import { SubscriberBotRootProps } from '../types';
3
+
4
+ interface SubscriberBotContextValue extends Omit<SubscriberBotRootProps, 'registerNavItems' | 'registerFooterItems' | 'navigate'> {
5
+ isStandalone: boolean;
6
+ /** Shell's navigate function (only available in integrated mode) */
7
+ navigate?: (path: string) => void;
8
+ /** Navigate to a path relative to basePath */
9
+ navigateTo: (relativePath: string) => void;
10
+ /** Get the full path for a relative path */
11
+ getPath: (relativePath: string) => string;
12
+ }
13
+ export declare function useSubscriberBot(): SubscriberBotContextValue;
14
+ export declare const SubscriberBotProvider: FC<PropsWithChildren<SubscriberBotRootProps>>;
15
+ export {};
16
+ //# sourceMappingURL=SubscriberBotContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubscriberBotContext.d.ts","sourceRoot":"","sources":["../../../src/subscriberbot/context/SubscriberBotContext.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAOvD,UAAU,yBAA0B,SAAQ,IAAI,CAC9C,sBAAsB,EACtB,kBAAkB,GAAG,qBAAqB,GAAG,UAAU,CACxD;IACC,YAAY,EAAE,OAAO,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,8CAA8C;IAC9C,UAAU,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,4CAA4C;IAC5C,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;CAC3C;AAQD,wBAAgB,gBAAgB,IAAI,yBAAyB,CAM5D;AA6HD,eAAO,MAAM,qBAAqB,EAAE,EAAE,CAAC,iBAAiB,CAAC,sBAAsB,CAAC,CAuB/E,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Context Index
3
+ * @module subscriberbot/context
4
+ */
5
+ export { SubscriberBotProvider, useSubscriberBot } from './SubscriberBotContext';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/subscriberbot/context/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * SubscriberBot hooks barrel
3
+ * @module subscriberbot/hooks
4
+ */
5
+ export { useRelationships, useRelationship, useCreateRelationship, useUpdateRelationship, useTransitionRelationship, useCancelRelationship, useRenewalEvents, useEntitlements, useCreateEntitlement, useAssets, useCreateAsset, useUploadFile, useFileDownloadUrl, useProviders, useProvider, useCreateProvider, useUpdateProvider, useArchiveProvider, usePlans, useCreatePlan, useInboxMessages, useMarkMessageRead, useIngestMessage, useInvoices, useMarkInvoicePaid, useCreateInvoice, usePaymentInstruments, useCreatePaymentInstrument, useRemovePaymentInstrument, useChannels, useCreateChannel, useVerifyChannel, useAgents, useAgent, useCreateAgent, useSetAgentStatus, useCreatePolicy, useWorkflows, useCreateWorkflow, useActivateWorkflow, } from './useSubscriberBotApi';
6
+ export type { RelationshipListFilters, ProviderListFilters, InboxListFilters, InvoiceListFilters, AgentListFilters, } from './useSubscriberBotApi';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/subscriberbot/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,cAAc,EACd,aAAa,EACb,kBAAkB,EAElB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,aAAa,EAEb,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAEhB,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAEhB,qBAAqB,EACrB,0BAA0B,EAC1B,0BAA0B,EAC1B,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAEhB,SAAS,EACT,QAAQ,EACR,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,105 @@
1
+ import { PaginationInput, SubAgentKind, SubAgentStatus, SubAiAgent, SubAsset, SubCommunicationChannel, SubConnection, SubCreateAgentInput, SubCreateAssetInput, SubCreateChannelInput, SubCreateEntitlementInput, SubCreateInvoiceInput, SubCreatePaymentInstrumentInput, SubCreatePlanInput, SubCreatePolicyInput, SubCreateProviderInput, SubCreateRelationshipInput, SubCreateWorkflowInput, SubEntitlement, SubInboxMessage, SubIngestMessageInput, SubInvoice, SubInvoiceStatus, SubMessageCategory, SubPaymentInstrument, SubPlan, SubPolicy, SubProvider, SubProviderCategory, SubProviderStatus, SubRelationship, SubRelationshipKind, SubRelationshipStatus, SubRenewalEvent, SubUpdateProviderInput, SubUpdateRelationshipInput, SubWorkflow, SubWorkflowStatus } from '../types';
2
+
3
+ export interface RelationshipListFilters {
4
+ kind?: SubRelationshipKind;
5
+ status?: SubRelationshipStatus;
6
+ providerId?: string;
7
+ ownerId?: string;
8
+ /** Case-insensitive substring match on the relationship label (server-side). */
9
+ search?: string;
10
+ pagination?: PaginationInput;
11
+ }
12
+ export declare const useRelationships: (filters?: RelationshipListFilters) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubConnection<SubRelationship>>, Error>;
13
+ export declare const useRelationship: (id: string | undefined) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubRelationship | null>, Error>;
14
+ export declare const useCreateRelationship: () => import('@tanstack/react-query').UseMutationResult<SubRelationship, Error, SubCreateRelationshipInput, unknown>;
15
+ export declare const useTransitionRelationship: () => import('@tanstack/react-query').UseMutationResult<SubRelationship, Error, {
16
+ id: string;
17
+ status: SubRelationshipStatus;
18
+ }, unknown>;
19
+ export declare const useCancelRelationship: () => import('@tanstack/react-query').UseMutationResult<SubRelationship, Error, string, unknown>;
20
+ export declare const useUpdateRelationship: () => import('@tanstack/react-query').UseMutationResult<SubRelationship, Error, {
21
+ id: string;
22
+ input: SubUpdateRelationshipInput;
23
+ }, unknown>;
24
+ export declare const useRenewalEvents: (args?: {
25
+ relationshipId?: string;
26
+ upcomingOnly?: boolean;
27
+ }) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubRenewalEvent[]>, Error>;
28
+ export declare const useEntitlements: (relationshipId: string | undefined) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubEntitlement[]>, Error>;
29
+ export declare const useCreateEntitlement: () => import('@tanstack/react-query').UseMutationResult<SubEntitlement, Error, SubCreateEntitlementInput, unknown>;
30
+ export declare const useAssets: (relationshipId: string | undefined) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubAsset[]>, Error>;
31
+ /** Every asset in the workspace (Digital Asset Vault) — omits relationshipId. */
32
+ export declare const useAllAssets: () => import('@tanstack/react-query').UseQueryResult<NoInfer<SubAsset[]>, Error>;
33
+ export declare const useCreateAsset: () => import('@tanstack/react-query').UseMutationResult<SubAsset, Error, SubCreateAssetInput, unknown>;
34
+ export declare const useUploadFile: () => {
35
+ uploadFile: (file: File) => Promise<{
36
+ fileId: string;
37
+ fileName: string;
38
+ }>;
39
+ progress: number;
40
+ isUploading: boolean;
41
+ };
42
+ /**
43
+ * Resolve a short-lived presigned download URL for a `wspace-files-svc` File id.
44
+ * Never select the federated arg-less `File.downloadUrl` (it mints a URL beyond
45
+ * S3's 7-day cap and 500s the response) — use the root `getFileDownloadUrl`
46
+ * query with a TTL under 604800s instead.
47
+ */
48
+ export declare const useFileDownloadUrl: () => (fileId: string) => Promise<string>;
49
+ export interface ProviderListFilters {
50
+ category?: SubProviderCategory;
51
+ status?: SubProviderStatus;
52
+ search?: string;
53
+ pagination?: PaginationInput;
54
+ }
55
+ export declare const useProviders: (filters?: ProviderListFilters) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubConnection<SubProvider>>, Error>;
56
+ export declare const useProvider: (id: string | undefined) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubProvider | null>, Error>;
57
+ export declare const useCreateProvider: () => import('@tanstack/react-query').UseMutationResult<SubProvider, Error, SubCreateProviderInput, unknown>;
58
+ export declare const useUpdateProvider: () => import('@tanstack/react-query').UseMutationResult<SubProvider, Error, {
59
+ id: string;
60
+ input: SubUpdateProviderInput;
61
+ }, unknown>;
62
+ export declare const useArchiveProvider: () => import('@tanstack/react-query').UseMutationResult<boolean, Error, string, unknown>;
63
+ export declare const usePlans: (providerId: string | undefined) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubPlan[]>, Error>;
64
+ export declare const useCreatePlan: () => import('@tanstack/react-query').UseMutationResult<SubPlan, Error, SubCreatePlanInput, unknown>;
65
+ export interface InboxListFilters {
66
+ category?: SubMessageCategory;
67
+ channelId?: string;
68
+ relationshipId?: string;
69
+ unreadOnly?: boolean;
70
+ pagination?: PaginationInput;
71
+ }
72
+ export declare const useInboxMessages: (filters?: InboxListFilters) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubConnection<SubInboxMessage>>, Error>;
73
+ export declare const useMarkMessageRead: () => import('@tanstack/react-query').UseMutationResult<SubInboxMessage, Error, string, unknown>;
74
+ export declare const useIngestMessage: () => import('@tanstack/react-query').UseMutationResult<SubInboxMessage, Error, SubIngestMessageInput, unknown>;
75
+ export interface InvoiceListFilters {
76
+ status?: SubInvoiceStatus;
77
+ relationshipId?: string;
78
+ pagination?: PaginationInput;
79
+ }
80
+ export declare const useInvoices: (filters?: InvoiceListFilters) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubConnection<SubInvoice>>, Error>;
81
+ export declare const useMarkInvoicePaid: () => import('@tanstack/react-query').UseMutationResult<SubInvoice, Error, string, unknown>;
82
+ export declare const useCreateInvoice: () => import('@tanstack/react-query').UseMutationResult<SubInvoice, Error, SubCreateInvoiceInput, unknown>;
83
+ export declare const usePaymentInstruments: (ownerId?: string) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubPaymentInstrument[]>, Error>;
84
+ export declare const useCreatePaymentInstrument: () => import('@tanstack/react-query').UseMutationResult<SubPaymentInstrument, Error, SubCreatePaymentInstrumentInput, unknown>;
85
+ export declare const useRemovePaymentInstrument: () => import('@tanstack/react-query').UseMutationResult<boolean, Error, string, unknown>;
86
+ export declare const useChannels: (ownerId?: string) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubCommunicationChannel[]>, Error>;
87
+ export declare const useCreateChannel: () => import('@tanstack/react-query').UseMutationResult<SubCommunicationChannel, Error, SubCreateChannelInput, unknown>;
88
+ export declare const useVerifyChannel: () => import('@tanstack/react-query').UseMutationResult<SubCommunicationChannel, Error, string, unknown>;
89
+ export interface AgentListFilters {
90
+ kind?: SubAgentKind;
91
+ status?: SubAgentStatus;
92
+ ownerId?: string;
93
+ }
94
+ export declare const useAgents: (filters?: AgentListFilters) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubAiAgent[]>, Error>;
95
+ export declare const useAgent: (id: string | undefined) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubAiAgent | null>, Error>;
96
+ export declare const useCreateAgent: () => import('@tanstack/react-query').UseMutationResult<SubAiAgent, Error, SubCreateAgentInput, unknown>;
97
+ export declare const useSetAgentStatus: () => import('@tanstack/react-query').UseMutationResult<SubAiAgent, Error, {
98
+ id: string;
99
+ status: SubAgentStatus;
100
+ }, unknown>;
101
+ export declare const useCreatePolicy: () => import('@tanstack/react-query').UseMutationResult<SubPolicy, Error, SubCreatePolicyInput, unknown>;
102
+ export declare const useWorkflows: (status?: SubWorkflowStatus) => import('@tanstack/react-query').UseQueryResult<NoInfer<SubWorkflow[]>, Error>;
103
+ export declare const useCreateWorkflow: () => import('@tanstack/react-query').UseMutationResult<SubWorkflow, Error, SubCreateWorkflowInput, unknown>;
104
+ export declare const useActivateWorkflow: () => import('@tanstack/react-query').UseMutationResult<SubWorkflow, Error, string, unknown>;
105
+ //# sourceMappingURL=useSubscriberBotApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSubscriberBotApi.d.ts","sourceRoot":"","sources":["../../../src/subscriberbot/hooks/useSubscriberBotApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * SubscriberBot Module Exports
3
+ * @module subscriberbot
4
+ */
5
+ export { SubscriberBotRoot } from './SubscriberBotRoot';
6
+ export type { SubscriberBotRootProps, NavItem, FooterItem, MicrofrontendRootProps, ViewMode, SubProvider, SubPlan, SubRelationship, SubEntitlement, SubAsset, SubRenewalEvent, SubInboxMessage, SubInvoice, SubPaymentInstrument, SubCommunicationChannel, SubAiAgent, SubPolicy, SubWorkflow, SubPageInfo, SubConnection, PaginationInput, } from './types';
7
+ export { SubscriberBotProvider, useSubscriberBot } from './context';
8
+ export { useSubscriberBotStore } from './store';
9
+ export { useSandboxAssistantTransport, type AssistantTransport, } from './services/createSandboxAssistantTransport';
10
+ export { cn } from './utils/cn';
11
+ export { formatCurrency, formatDate, formatDateTime, formatRelativeTime, formatNumber, formatEnumLabel, formatIntervalSuffix, } from './utils/formatters';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/subscriberbot/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,YAAY,EACV,sBAAsB,EACtB,OAAO,EACP,UAAU,EACV,sBAAsB,EACtB,QAAQ,EAER,WAAW,EACX,OAAO,EACP,eAAe,EACf,cAAc,EACd,QAAQ,EACR,eAAe,EACf,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,uBAAuB,EACvB,UAAU,EACV,SAAS,EACT,WAAW,EAEX,WAAW,EACX,aAAa,EACb,eAAe,GAChB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAGpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGhD,OAAO,EACL,4BAA4B,EAC5B,KAAK,kBAAkB,GACxB,MAAM,4CAA4C,CAAC;AAGpD,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAChC,OAAO,EACL,cAAc,EACd,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,oBAAoB,GACrB,MAAM,oBAAoB,CAAC"}
@@ -5,3 +5,4 @@ import "./context/index.js";
5
5
  import "./SubscriberBotRoot.js";
6
6
  import "./store/subscriberbotStore.js";
7
7
  import "./store/index.js";
8
+ import "./services/createSandboxAssistantTransport.js";
@@ -0,0 +1,4 @@
1
+ import { FC } from 'react';
2
+
3
+ export declare const AssetVaultPage: FC;
4
+ //# sourceMappingURL=AssetVaultPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetVaultPage.d.ts","sourceRoot":"","sources":["../../../src/subscriberbot/pages/AssetVaultPage.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AA4GnD,eAAO,MAAM,cAAc,EAAE,EAgI5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetVaultPage.js","names":[],"sources":["../../../src/subscriberbot/pages/AssetVaultPage.tsx"],"sourcesContent":["/**\n * Digital Asset Vault — every document attached to any subscription in the\n * workspace (contracts, receipts, license keys, warranties). Real data only:\n * `useAllAssets` (workspace-wide) joined to `useRelationships` for the owning\n * subscription label; downloads resolve a presigned URL via files-svc.\n * @module subscriberbot/pages\n */\nimport { useMemo, useState, type FC } from 'react';\nimport {\n FileText,\n FileKey,\n Receipt,\n ShieldCheck,\n File as FileIcon,\n Globe,\n Award,\n Search,\n Download,\n Vault,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, MetricsCard, EmptyState, LoadingView, ErrorView, Section } from '../components';\nimport { useAllAssets, useRelationships, useFileDownloadUrl } from '../hooks/useSubscriberBotApi';\nimport { formatDate, formatEnumLabel } from '../utils/formatters';\nimport type { SubAsset, SubAssetType } from '../types';\nimport { cn } from '../utils/cn';\n\nconst TYPE_ICON: Record<SubAssetType, typeof FileText> = {\n CONTRACT: FileText,\n LICENSE_KEY: FileKey,\n CREDENTIAL: FileKey,\n CERTIFICATE: Award,\n INVOICE: Receipt,\n RECEIPT: Receipt,\n WARRANTY: ShieldCheck,\n DOMAIN: Globe,\n};\n\nconst TYPE_ORDER: SubAssetType[] = [\n 'CONTRACT',\n 'LICENSE_KEY',\n 'CREDENTIAL',\n 'CERTIFICATE',\n 'INVOICE',\n 'RECEIPT',\n 'WARRANTY',\n 'DOMAIN',\n];\n\nconst isExpiringSoon = (expiresAt: string | null): boolean => {\n if (!expiresAt) return false;\n const t = new Date(expiresAt).getTime();\n if (Number.isNaN(t)) return false;\n const days = (t - Date.now()) / 86_400_000;\n return days >= 0 && days <= 30;\n};\n\nfunction AssetCard({ asset, subscription }: { asset: SubAsset; subscription: string }) {\n const getDownloadUrl = useFileDownloadUrl();\n const [busy, setBusy] = useState(false);\n const Icon = TYPE_ICON[asset.type] ?? FileIcon;\n const soon = isExpiringSoon(asset.expiresAt);\n\n const download = async () => {\n if (!asset.file?.id || busy) return;\n setBusy(true);\n try {\n const url = await getDownloadUrl(asset.file.id);\n window.open(url, '_blank', 'noopener,noreferrer');\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <GlassCard treatment=\"metric\" className=\"flex items-start gap-3 p-4\">\n <span className=\"grid h-10 w-10 shrink-0 place-items-center rounded-lg bg-accent-wash text-text-link\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-medium text-text-primary\">{asset.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">{subscription}</p>\n <div className=\"mt-1 flex flex-wrap items-center gap-2 text-xs\">\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-text-secondary\">\n {formatEnumLabel(asset.type)}\n </span>\n {asset.expiresAt && (\n <span className={cn(soon ? 'text-status-warning-text' : 'text-text-secondary')}>\n Expires {formatDate(asset.expiresAt)}\n </span>\n )}\n </div>\n </div>\n {asset.file?.id && (\n <button\n type=\"button\"\n onClick={download}\n disabled={busy}\n aria-label={`Download ${asset.name}`}\n className=\"shrink-0 rounded-lg border border-border-subtle p-2 text-text-secondary hover:text-text-primary disabled:opacity-50\"\n >\n <Download className=\"h-4 w-4\" />\n </button>\n )}\n </GlassCard>\n );\n}\n\nexport const AssetVaultPage: FC = () => {\n const assetsQuery = useAllAssets();\n const relQuery = useRelationships({ pagination: { limit: 100 } });\n const [search, setSearch] = useState('');\n const [typeFilter, setTypeFilter] = useState<SubAssetType | 'ALL'>('ALL');\n\n const relLabels = useMemo(() => {\n const map = new Map<string, string>();\n for (const r of relQuery.data?.items ?? []) map.set(r.id, r.label);\n return map;\n }, [relQuery.data]);\n\n const assets = useMemo(() => assetsQuery.data ?? [], [assetsQuery.data]);\n const filtered = useMemo(\n () =>\n assets.filter(\n (a) =>\n (typeFilter === 'ALL' || a.type === typeFilter) &&\n (!search || a.name.toLowerCase().includes(search.toLowerCase()))\n ),\n [assets, typeFilter, search]\n );\n\n const grouped = useMemo(() => {\n const g = new Map<SubAssetType, SubAsset[]>();\n for (const a of filtered) g.set(a.type, [...(g.get(a.type) ?? []), a]);\n return TYPE_ORDER.filter((t) => g.has(t)).map((t) => [t, g.get(t)!] as const);\n }, [filtered]);\n\n const expiringSoon = useMemo(() => assets.filter((a) => isExpiringSoon(a.expiresAt)), [assets]);\n\n if (assetsQuery.isLoading) return <LoadingView label=\"Loading your asset vault…\" />;\n if (assetsQuery.isError)\n return <ErrorView message=\"Could not load the asset vault.\" onRetry={() => void assetsQuery.refetch()} />;\n\n return (\n <PageLayout\n title=\"Asset vault\"\n description=\"Every contract, receipt, license key and document attached to your subscriptions — in one secure place.\"\n >\n <PagePurpose className=\"mb-2\">\n Your subscription documents, together — contracts, receipts, license keys and more. Assets are\n stored in the shared files service and linked to the subscription they belong to. Attach new\n documents from any relationship’s detail page.\n </PagePurpose>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard icon={<FileIcon className=\"h-5 w-5\" />} value={assets.length} label=\"Documents stored\" />\n <MetricsCard\n icon={<FileText className=\"h-5 w-5\" />}\n value={grouped.length}\n label=\"Document types\"\n />\n <MetricsCard\n icon={<ShieldCheck className=\"h-5 w-5\" />}\n value={expiringSoon.length}\n label=\"Expiring within 30 days\"\n trend={expiringSoon.length > 0 ? 'down' : undefined}\n />\n </div>\n\n <GlassCard treatment=\"plain\" className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search documents…\"\n aria-label=\"Search documents\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary\"\n />\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {(['ALL', ...TYPE_ORDER] as const).map((t) => (\n <button\n key={t}\n type=\"button\"\n onClick={() => setTypeFilter(t)}\n aria-pressed={typeFilter === t}\n className={cn(\n 'rounded-full px-3 py-1 text-xs font-medium transition-colors',\n typeFilter === t\n ? 'bg-accent-primary text-accent-foreground'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {t === 'ALL' ? 'All' : formatEnumLabel(t)}\n </button>\n ))}\n </div>\n </GlassCard>\n\n {filtered.length === 0 ? (\n <EmptyState\n icon={<Vault className=\"h-8 w-8\" />}\n title={assets.length === 0 ? 'No documents yet' : 'No matching documents'}\n description={\n assets.length === 0\n ? 'Attach a contract, receipt or license key from any subscription’s detail page and it will appear here.'\n : 'Try a different search or type filter.'\n }\n />\n ) : (\n grouped.map(([type, items]) => (\n <Section key={type} title={`${formatEnumLabel(type)} · ${items.length}`}>\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {items.map((a) => (\n <AssetCard key={a.id} asset={a} subscription={relLabels.get(a.relationshipId) ?? 'Subscription'} />\n ))}\n </div>\n </Section>\n ))\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AssetVaultPage.js","names":[],"sources":["../../../src/subscriberbot/pages/AssetVaultPage.tsx"],"sourcesContent":["/**\n * Digital Asset Vault — every document attached to any subscription in the\n * workspace (contracts, receipts, license keys, warranties). Real data only:\n * `useAllAssets` (workspace-wide) joined to `useRelationships` for the owning\n * subscription label; downloads resolve a presigned URL via files-svc.\n * @module subscriberbot/pages\n */\nimport { useMemo, useState, type FC } from 'react';\nimport {\n FileText,\n FileKey,\n Receipt,\n ShieldCheck,\n File as FileIcon,\n Globe,\n Award,\n Search,\n Download,\n Vault,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n EmptyState,\n LoadingView,\n ErrorView,\n Section,\n} from '../components';\nimport { useAllAssets, useRelationships, useFileDownloadUrl } from '../hooks/useSubscriberBotApi';\nimport { formatDate, formatEnumLabel } from '../utils/formatters';\nimport type { SubAsset, SubAssetType } from '../types';\nimport { cn } from '../utils/cn';\n\nconst TYPE_ICON: Record<SubAssetType, typeof FileText> = {\n CONTRACT: FileText,\n LICENSE_KEY: FileKey,\n CREDENTIAL: FileKey,\n CERTIFICATE: Award,\n INVOICE: Receipt,\n RECEIPT: Receipt,\n WARRANTY: ShieldCheck,\n DOMAIN: Globe,\n};\n\nconst TYPE_ORDER: SubAssetType[] = [\n 'CONTRACT',\n 'LICENSE_KEY',\n 'CREDENTIAL',\n 'CERTIFICATE',\n 'INVOICE',\n 'RECEIPT',\n 'WARRANTY',\n 'DOMAIN',\n];\n\nconst isExpiringSoon = (expiresAt: string | null): boolean => {\n if (!expiresAt) return false;\n const t = new Date(expiresAt).getTime();\n if (Number.isNaN(t)) return false;\n const days = (t - Date.now()) / 86_400_000;\n return days >= 0 && days <= 30;\n};\n\nfunction AssetCard({ asset, subscription }: { asset: SubAsset; subscription: string }) {\n const getDownloadUrl = useFileDownloadUrl();\n const [busy, setBusy] = useState(false);\n const Icon = TYPE_ICON[asset.type] ?? FileIcon;\n const soon = isExpiringSoon(asset.expiresAt);\n\n const download = async () => {\n if (!asset.file?.id || busy) return;\n setBusy(true);\n try {\n const url = await getDownloadUrl(asset.file.id);\n window.open(url, '_blank', 'noopener,noreferrer');\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <GlassCard treatment=\"metric\" className=\"flex items-start gap-3 p-4\">\n <span className=\"grid h-10 w-10 shrink-0 place-items-center rounded-lg bg-accent-wash text-text-link\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-medium text-text-primary\">{asset.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">{subscription}</p>\n <div className=\"mt-1 flex flex-wrap items-center gap-2 text-xs\">\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-text-secondary\">\n {formatEnumLabel(asset.type)}\n </span>\n {asset.expiresAt && (\n <span className={cn(soon ? 'text-status-warning-text' : 'text-text-secondary')}>\n Expires {formatDate(asset.expiresAt)}\n </span>\n )}\n </div>\n </div>\n {asset.file?.id && (\n <button\n type=\"button\"\n onClick={download}\n disabled={busy}\n aria-label={`Download ${asset.name}`}\n className=\"shrink-0 rounded-lg border border-border-subtle p-2 text-text-secondary hover:text-text-primary disabled:opacity-50\"\n >\n <Download className=\"h-4 w-4\" />\n </button>\n )}\n </GlassCard>\n );\n}\n\nexport const AssetVaultPage: FC = () => {\n const assetsQuery = useAllAssets();\n const relQuery = useRelationships({ pagination: { limit: 100 } });\n const [search, setSearch] = useState('');\n const [typeFilter, setTypeFilter] = useState<SubAssetType | 'ALL'>('ALL');\n\n const relLabels = useMemo(() => {\n const map = new Map<string, string>();\n for (const r of relQuery.data?.items ?? []) map.set(r.id, r.label);\n return map;\n }, [relQuery.data]);\n\n const assets = useMemo(() => assetsQuery.data ?? [], [assetsQuery.data]);\n const filtered = useMemo(\n () =>\n assets.filter(\n (a) =>\n (typeFilter === 'ALL' || a.type === typeFilter) &&\n (!search || a.name.toLowerCase().includes(search.toLowerCase()))\n ),\n [assets, typeFilter, search]\n );\n\n const grouped = useMemo(() => {\n const g = new Map<SubAssetType, SubAsset[]>();\n for (const a of filtered) g.set(a.type, [...(g.get(a.type) ?? []), a]);\n return TYPE_ORDER.filter((t) => g.has(t)).map((t) => [t, g.get(t)!] as const);\n }, [filtered]);\n\n const expiringSoon = useMemo(() => assets.filter((a) => isExpiringSoon(a.expiresAt)), [assets]);\n\n if (assetsQuery.isLoading) return <LoadingView label=\"Loading your asset vault…\" />;\n if (assetsQuery.isError)\n return (\n <ErrorView\n message=\"Could not load the asset vault.\"\n onRetry={() => void assetsQuery.refetch()}\n />\n );\n\n return (\n <PageLayout\n title=\"Asset vault\"\n description=\"Every contract, receipt, license key and document attached to your subscriptions — in one secure place.\"\n >\n <PagePurpose className=\"mb-2\">\n Your subscription documents, together — contracts, receipts, license keys and more. Assets\n are stored in the shared files service and linked to the subscription they belong to. Attach\n new documents from any relationship’s detail page.\n </PagePurpose>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<FileIcon className=\"h-5 w-5\" />}\n value={assets.length}\n label=\"Documents stored\"\n />\n <MetricsCard\n icon={<FileText className=\"h-5 w-5\" />}\n value={grouped.length}\n label=\"Document types\"\n />\n <MetricsCard\n icon={<ShieldCheck className=\"h-5 w-5\" />}\n value={expiringSoon.length}\n label=\"Expiring within 30 days\"\n trend={expiringSoon.length > 0 ? 'down' : undefined}\n />\n </div>\n\n <GlassCard treatment=\"plain\" className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search documents…\"\n aria-label=\"Search documents\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary\"\n />\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {(['ALL', ...TYPE_ORDER] as const).map((t) => (\n <button\n key={t}\n type=\"button\"\n onClick={() => setTypeFilter(t)}\n aria-pressed={typeFilter === t}\n className={cn(\n 'rounded-full px-3 py-1 text-xs font-medium transition-colors',\n typeFilter === t\n ? 'bg-accent-primary text-accent-foreground'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {t === 'ALL' ? 'All' : formatEnumLabel(t)}\n </button>\n ))}\n </div>\n </GlassCard>\n\n {filtered.length === 0 ? (\n <EmptyState\n icon={<Vault className=\"h-8 w-8\" />}\n title={assets.length === 0 ? 'No documents yet' : 'No matching documents'}\n description={\n assets.length === 0\n ? 'Attach a contract, receipt or license key from any subscription’s detail page and it will appear here.'\n : 'Try a different search or type filter.'\n }\n />\n ) : (\n grouped.map(([type, items]) => (\n <Section key={type} title={`${formatEnumLabel(type)} · ${items.length}`}>\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {items.map((a) => (\n <AssetCard\n key={a.id}\n asset={a}\n subscription={relLabels.get(a.relationshipId) ?? 'Subscription'}\n />\n ))}\n </div>\n </Section>\n ))\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Dashboard / Overview
3
+ * @module subscriberbot/pages
4
+ *
5
+ * The Subscriber Bot landing page: a premium fintech console over every
6
+ * recurring digital relationship — total recurring spend, portfolio-by-status,
7
+ * upcoming renewals, the action-required inbox, and outstanding invoices. Every
8
+ * number and chart is COMPUTED from real data returned by
9
+ * `wspace-subscriberbot-svc` — nothing is mocked.
10
+ */
11
+ export declare function DashboardPage(): import("react").JSX.Element;
12
+ //# sourceMappingURL=DashboardPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../src/subscriberbot/pages/DashboardPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmEH,wBAAgB,aAAa,gCA4X5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/subscriberbot/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard / Overview\n * @module subscriberbot/pages\n *\n * The Subscriber Bot landing page: a premium fintech console over every\n * recurring digital relationship — total recurring spend, portfolio-by-status,\n * upcoming renewals, the action-required inbox, and outstanding invoices. Every\n * number and chart is COMPUTED from real data returned by\n * `wspace-subscriberbot-svc` — nothing is mocked.\n */\n\nimport { useMemo } from 'react';\nimport {\n Repeat2,\n Wallet,\n CalendarClock,\n Inbox,\n AlertTriangle,\n ArrowRight,\n ArrowUpRight,\n Sparkles,\n Bot,\n ShieldCheck,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n StatusBadge,\n EmptyState,\n LoadingView,\n ErrorView,\n Section,\n Donut,\n Legend,\n Timeline,\n type Segment,\n type TimelineItem,\n} from '../components';\nimport { useSubscriberBot } from '../context/SubscriberBotContext';\nimport {\n useRelationships,\n useInvoices,\n useInboxMessages,\n useRenewalEvents,\n} from '../hooks/useSubscriberBotApi';\nimport { formatCurrency, formatRelativeTime, formatEnumLabel } from '../utils/formatters';\nimport type { SubBillingInterval, SubRelationship, SubRenewalEvent } from '../types';\n\n// Normalize any billing interval to an approximate monthly multiplier so we can\n// express total recurring spend as one comparable \"per month\" number.\nconst MONTHLY_FACTOR: Record<SubBillingInterval, number> = {\n DAILY: 30,\n WEEKLY: 4.345,\n MONTHLY: 1,\n QUARTERLY: 1 / 3,\n YEARLY: 1 / 12,\n LIFETIME: 0,\n FREE: 0,\n USAGE_BASED: 1,\n};\n\n// A single normalized \"what charges next\" row, sourced from real renewal events\n// when present, otherwise derived from each relationship's own `renewsAt`.\ninterface UpcomingRenewal {\n id: string;\n relationshipId: string;\n title: string;\n when: string;\n amount: number | null;\n currency: string | null;\n soon: boolean;\n}\n\nconst MS_PER_DAY = 1000 * 60 * 60 * 24;\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useSubscriberBot();\n\n const relationshipsQ = useRelationships({ pagination: { limit: 100, offset: 0 } });\n const invoicesQ = useInvoices({ pagination: { limit: 50, offset: 0 } });\n const inboxQ = useInboxMessages({ pagination: { limit: 50, offset: 0 } });\n const renewalsQ = useRenewalEvents({ upcomingOnly: true });\n\n const relationships = useMemo(() => relationshipsQ.data?.items ?? [], [relationshipsQ.data]);\n const invoices = useMemo(() => invoicesQ.data?.items ?? [], [invoicesQ.data]);\n const messages = useMemo(() => inboxQ.data?.items ?? [], [inboxQ.data]);\n const renewals = useMemo(() => renewalsQ.data ?? [], [renewalsQ.data]);\n\n // Fast label lookup so renewal rows can name the relationship they belong to.\n const relationshipById = useMemo(() => {\n const map = new Map<string, SubRelationship>();\n relationships.forEach((r) => map.set(r.id, r));\n return map;\n }, [relationships]);\n\n const stats = useMemo(() => {\n const active = relationships.filter((r) => r.status === 'ACTIVE' || r.status === 'TRIAL');\n const monthlySpend = active.reduce(\n (sum, r) => sum + r.amount * (MONTHLY_FACTOR[r.interval] ?? 1),\n 0\n );\n const primaryCurrency = active[0]?.currency ?? relationships[0]?.currency ?? 'USD';\n const unreadActionRequired = messages.filter((m) => m.actionRequired && !m.isRead).length;\n const openInvoices = invoices.filter(\n (i) => i.status === 'ISSUED' || i.status === 'OVERDUE' || i.status === 'FAILED'\n );\n const openInvoiceTotal = openInvoices.reduce((sum, i) => sum + i.total, 0);\n const atRisk = relationships.filter(\n (r) => r.status === 'PAST_DUE' || r.status === 'LAPSED'\n ).length;\n\n return {\n activeCount: active.length,\n totalCount: relationships.length,\n monthlySpend,\n primaryCurrency,\n unreadActionRequired,\n openInvoiceCount: openInvoices.length,\n openInvoiceTotal,\n atRisk,\n };\n }, [relationships, messages, invoices]);\n\n // Portfolio-by-status → donut segments (grouped from real relationships).\n const statusSegments = useMemo<Segment[]>(() => {\n const counts = new Map<string, number>();\n relationships.forEach((r) => counts.set(r.status, (counts.get(r.status) ?? 0) + 1));\n return Array.from(counts.entries())\n .sort((a, b) => b[1] - a[1])\n .map(([status, value]) => ({ label: formatEnumLabel(status), value }));\n }, [relationships]);\n\n // Normalize upcoming renewals: prefer real renewal events, fall back to\n // relationship `renewsAt` when the event stream is empty. Sorted soonest-first.\n const upcoming = useMemo<UpcomingRenewal[]>(() => {\n const now = Date.now();\n const fromEvents: UpcomingRenewal[] = renewals.map((e: SubRenewalEvent) => {\n const rel = relationshipById.get(e.relationshipId);\n const t = new Date(e.occursAt).getTime();\n return {\n id: e.id,\n relationshipId: e.relationshipId,\n title: rel?.label ?? formatEnumLabel(e.eventType),\n when: e.occursAt,\n amount: e.amount ?? rel?.amount ?? null,\n currency: e.currency ?? rel?.currency ?? null,\n soon: !Number.isNaN(t) && t - now <= 7 * MS_PER_DAY,\n };\n });\n\n if (fromEvents.length > 0) {\n return fromEvents\n .filter((u) => !Number.isNaN(new Date(u.when).getTime()))\n .sort((a, b) => new Date(a.when).getTime() - new Date(b.when).getTime());\n }\n\n // Derive from relationships that carry a future renewal date.\n return relationships\n .filter((r) => {\n if (!r.renewsAt) return false;\n const t = new Date(r.renewsAt).getTime();\n return !Number.isNaN(t) && t >= now;\n })\n .map((r) => {\n const t = new Date(r.renewsAt as string).getTime();\n return {\n id: r.id,\n relationshipId: r.id,\n title: r.label,\n when: r.renewsAt as string,\n amount: r.amount,\n currency: r.currency,\n soon: t - now <= 7 * MS_PER_DAY,\n };\n })\n .sort((a, b) => new Date(a.when).getTime() - new Date(b.when).getTime());\n }, [renewals, relationships, relationshipById]);\n\n const timelineItems = useMemo<TimelineItem[]>(\n () =>\n upcoming.slice(0, 6).map((u) => ({\n title: u.title,\n sub: formatRelativeTime(u.when),\n tone: u.soon ? 'warning' : 'default',\n meta:\n u.amount != null\n ? formatCurrency(u.amount, u.currency ?? stats.primaryCurrency, {\n maximumFractionDigits: 0,\n })\n : undefined,\n })),\n [upcoming, stats.primaryCurrency]\n );\n\n const actionMessages = useMemo(\n () => messages.filter((m) => m.actionRequired),\n [messages]\n );\n\n const isLoading =\n relationshipsQ.isLoading || invoicesQ.isLoading || inboxQ.isLoading || renewalsQ.isLoading;\n const isError =\n relationshipsQ.isError && invoicesQ.isError && inboxQ.isError && renewalsQ.isError;\n\n if (isLoading) {\n return (\n <PageLayout title=\"Overview\" description=\"Your recurring digital relationships at a glance\">\n <LoadingView label=\"Loading your subscription portfolio…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Overview\" description=\"Your recurring digital relationships at a glance\">\n <ErrorView\n message=\"We couldn't reach the Subscriber Bot service. Please try again.\"\n onRetry={() => {\n void relationshipsQ.refetch();\n void invoicesQ.refetch();\n void inboxQ.refetch();\n void renewalsQ.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n const greetingName = currentUser?.firstName || currentUser?.name?.split(' ')[0];\n\n const quickActions = [\n {\n label: 'Add a relationship',\n description: 'Track a new subscription',\n icon: <Repeat2 className=\"h-5 w-5\" />,\n path: '/relationships/new',\n },\n {\n label: 'Discover providers',\n description: 'Browse the registry',\n icon: <Sparkles className=\"h-5 w-5\" />,\n path: '/providers',\n },\n {\n label: 'Open inbox',\n description: 'Merged communications',\n icon: <Inbox className=\"h-5 w-5\" />,\n path: '/inbox',\n },\n {\n label: 'Configure agents',\n description: 'Automate your portfolio',\n icon: <Bot className=\"h-5 w-5\" />,\n path: '/agents',\n },\n ];\n\n return (\n <PageLayout\n title={greetingName ? `Welcome back, ${greetingName}` : 'Overview'}\n description=\"Everything you pay for on repeat — in one intelligent console.\"\n >\n <PagePurpose className=\"mb-6\">\n Subscriber Bot is your system of record for every recurring digital relationship. See total\n recurring spend, what renews next, what needs action, and what to optimize — all from real\n data across your providers.\n </PagePurpose>\n\n {/* KPI tiles */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n featured\n icon={<Wallet />}\n value={formatCurrency(stats.monthlySpend, stats.primaryCurrency, {\n maximumFractionDigits: 0,\n })}\n label=\"Recurring spend / month\"\n />\n <MetricsCard icon={<Repeat2 />} value={stats.activeCount} label=\"Active relationships\" />\n <MetricsCard icon={<CalendarClock />} value={upcoming.length} label=\"Upcoming renewals\" />\n <MetricsCard\n icon={<AlertTriangle />}\n value={stats.unreadActionRequired}\n label=\"Need your action\"\n trend={stats.unreadActionRequired > 0 ? 'down' : undefined}\n />\n </div>\n\n {/* Main console: renewals (left) + portfolio donut & needs-attention (right) */}\n <div className=\"mt-8 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Upcoming renewals timeline — spans two columns on desktop */}\n <div className=\"lg:col-span-2\">\n <Section\n title=\"Upcoming renewals\"\n description=\"What's charging next across your portfolio\"\n className=\"mt-0\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-text-link hover:underline\"\n >\n View all <ArrowUpRight className=\"h-3.5 w-3.5\" />\n </button>\n }\n >\n <GlassCard treatment=\"plain\" className=\"p-5\">\n {timelineItems.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n title=\"No upcoming renewals\"\n description=\"Renewals you track will appear here ahead of time.\"\n />\n ) : (\n <Timeline items={timelineItems} />\n )}\n </GlassCard>\n </Section>\n </div>\n\n {/* Right rail: portfolio-by-status donut + needs-attention panel */}\n <div className=\"flex flex-col gap-6\">\n <Section title=\"Portfolio by status\" description=\"Where your relationships stand\" className=\"mt-0\">\n <GlassCard treatment=\"glass\" className=\"p-5\">\n {statusSegments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No relationships yet\"\n description=\"Add your first subscription to see the breakdown.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Add relationship\n </button>\n }\n />\n ) : (\n <div className=\"flex flex-col items-center gap-5 sm:flex-row sm:items-center lg:flex-col xl:flex-row\">\n <Donut\n data={statusSegments}\n size={148}\n thickness={20}\n centerLabel={String(stats.totalCount)}\n centerSub={stats.totalCount === 1 ? 'relationship' : 'relationships'}\n className=\"shrink-0\"\n />\n <Legend data={statusSegments} className=\"w-full min-w-0 flex-1\" />\n </div>\n )}\n </GlassCard>\n </Section>\n\n <Section\n title=\"Needs attention\"\n description=\"Required actions from the Universal Inbox\"\n className=\"mt-0\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/inbox')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n Open inbox\n </button>\n }\n >\n <GlassCard treatment=\"plain\" className=\"p-3\">\n {actionMessages.length === 0 ? (\n <div className=\"flex items-center gap-3 px-2 py-4\">\n <span className=\"flex size-10 shrink-0 items-center justify-center rounded-lg bg-status-success-bg-subtle text-status-success-text\">\n <ShieldCheck className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary\">You're all caught up</p>\n <p className=\"text-xs text-text-secondary\">\n Required actions across your channels will surface here.\n </p>\n </div>\n </div>\n ) : (\n <ul className=\"space-y-1\">\n {actionMessages.slice(0, 5).map((message) => (\n <li key={message.id}>\n <button\n type=\"button\"\n onClick={() => navigateTo('/inbox')}\n className=\"flex w-full items-center gap-3 rounded-lg border-l-2 border-status-warning-text/60 bg-status-warning-bg-subtle/50 p-3 text-left transition-colors hover:bg-status-warning-bg-subtle\"\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {message.subject || '(no subject)'}\n </p>\n {message.preview && (\n <p className=\"truncate text-xs text-text-secondary\">{message.preview}</p>\n )}\n </div>\n <StatusBadge status={message.category} className=\"shrink-0\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n </Section>\n </div>\n </div>\n\n {/* Open-invoice call-out (only when there is real outstanding balance) */}\n {stats.openInvoiceCount > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/invoices')}\n className=\"mt-6 flex w-full items-center justify-between gap-3 rounded-xl border border-status-warning-text/30 bg-status-warning-bg-subtle px-5 py-4 text-left transition-shadow hover:shadow-md\"\n >\n <div className=\"flex items-center gap-3\">\n <AlertTriangle className=\"h-5 w-5 shrink-0 text-status-warning-text\" />\n <span className=\"text-sm font-medium text-status-warning-text\">\n {stats.openInvoiceCount} open invoice{stats.openInvoiceCount !== 1 ? 's' : ''} ·{' '}\n {formatCurrency(stats.openInvoiceTotal, stats.primaryCurrency)} outstanding\n </span>\n </div>\n <ArrowRight className=\"h-4 w-4 shrink-0 text-status-warning-text\" />\n </button>\n )}\n\n {/* Quick actions */}\n <Section title=\"Quick actions\" description=\"Jump straight into your workflow\">\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n {quickActions.map((qa) => (\n <button\n key={qa.path}\n type=\"button\"\n onClick={() => navigateTo(qa.path)}\n className=\"group flex items-center gap-3 rounded-xl border border-border-subtle bg-bg-surface p-4 text-left transition-all hover:-translate-y-0.5 hover:border-border-seam hover:shadow-md\"\n >\n <span className=\"flex size-10 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n {qa.icon}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-sm font-medium text-text-primary\">{qa.label}</span>\n <span className=\"block text-xs text-text-secondary\">{qa.description}</span>\n </span>\n <ArrowRight className=\"h-4 w-4 shrink-0 text-text-secondary transition-transform group-hover:translate-x-0.5\" />\n </button>\n ))}\n </div>\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/subscriberbot/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard / Overview\n * @module subscriberbot/pages\n *\n * The Subscriber Bot landing page: a premium fintech console over every\n * recurring digital relationship — total recurring spend, portfolio-by-status,\n * upcoming renewals, the action-required inbox, and outstanding invoices. Every\n * number and chart is COMPUTED from real data returned by\n * `wspace-subscriberbot-svc` — nothing is mocked.\n */\n\nimport { useMemo } from 'react';\nimport {\n Repeat2,\n Wallet,\n CalendarClock,\n Inbox,\n AlertTriangle,\n ArrowRight,\n ArrowUpRight,\n Sparkles,\n Bot,\n ShieldCheck,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n StatusBadge,\n EmptyState,\n LoadingView,\n ErrorView,\n Section,\n Donut,\n Legend,\n Timeline,\n type Segment,\n type TimelineItem,\n} from '../components';\nimport { useSubscriberBot } from '../context/SubscriberBotContext';\nimport {\n useRelationships,\n useInvoices,\n useInboxMessages,\n useRenewalEvents,\n} from '../hooks/useSubscriberBotApi';\nimport { formatCurrency, formatRelativeTime, formatEnumLabel } from '../utils/formatters';\nimport type { SubBillingInterval, SubRelationship, SubRenewalEvent } from '../types';\n\n// Normalize any billing interval to an approximate monthly multiplier so we can\n// express total recurring spend as one comparable \"per month\" number.\nconst MONTHLY_FACTOR: Record<SubBillingInterval, number> = {\n DAILY: 30,\n WEEKLY: 4.345,\n MONTHLY: 1,\n QUARTERLY: 1 / 3,\n YEARLY: 1 / 12,\n LIFETIME: 0,\n FREE: 0,\n USAGE_BASED: 1,\n};\n\n// A single normalized \"what charges next\" row, sourced from real renewal events\n// when present, otherwise derived from each relationship's own `renewsAt`.\ninterface UpcomingRenewal {\n id: string;\n relationshipId: string;\n title: string;\n when: string;\n amount: number | null;\n currency: string | null;\n soon: boolean;\n}\n\nconst MS_PER_DAY = 1000 * 60 * 60 * 24;\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useSubscriberBot();\n\n const relationshipsQ = useRelationships({ pagination: { limit: 100, offset: 0 } });\n const invoicesQ = useInvoices({ pagination: { limit: 50, offset: 0 } });\n const inboxQ = useInboxMessages({ pagination: { limit: 50, offset: 0 } });\n const renewalsQ = useRenewalEvents({ upcomingOnly: true });\n\n const relationships = useMemo(() => relationshipsQ.data?.items ?? [], [relationshipsQ.data]);\n const invoices = useMemo(() => invoicesQ.data?.items ?? [], [invoicesQ.data]);\n const messages = useMemo(() => inboxQ.data?.items ?? [], [inboxQ.data]);\n const renewals = useMemo(() => renewalsQ.data ?? [], [renewalsQ.data]);\n\n // Fast label lookup so renewal rows can name the relationship they belong to.\n const relationshipById = useMemo(() => {\n const map = new Map<string, SubRelationship>();\n relationships.forEach((r) => map.set(r.id, r));\n return map;\n }, [relationships]);\n\n const stats = useMemo(() => {\n const active = relationships.filter((r) => r.status === 'ACTIVE' || r.status === 'TRIAL');\n const monthlySpend = active.reduce(\n (sum, r) => sum + r.amount * (MONTHLY_FACTOR[r.interval] ?? 1),\n 0\n );\n const primaryCurrency = active[0]?.currency ?? relationships[0]?.currency ?? 'USD';\n const unreadActionRequired = messages.filter((m) => m.actionRequired && !m.isRead).length;\n const openInvoices = invoices.filter(\n (i) => i.status === 'ISSUED' || i.status === 'OVERDUE' || i.status === 'FAILED'\n );\n const openInvoiceTotal = openInvoices.reduce((sum, i) => sum + i.total, 0);\n const atRisk = relationships.filter(\n (r) => r.status === 'PAST_DUE' || r.status === 'LAPSED'\n ).length;\n\n return {\n activeCount: active.length,\n totalCount: relationships.length,\n monthlySpend,\n primaryCurrency,\n unreadActionRequired,\n openInvoiceCount: openInvoices.length,\n openInvoiceTotal,\n atRisk,\n };\n }, [relationships, messages, invoices]);\n\n // Portfolio-by-status → donut segments (grouped from real relationships).\n const statusSegments = useMemo<Segment[]>(() => {\n const counts = new Map<string, number>();\n relationships.forEach((r) => counts.set(r.status, (counts.get(r.status) ?? 0) + 1));\n return Array.from(counts.entries())\n .sort((a, b) => b[1] - a[1])\n .map(([status, value]) => ({ label: formatEnumLabel(status), value }));\n }, [relationships]);\n\n // Normalize upcoming renewals: prefer real renewal events, fall back to\n // relationship `renewsAt` when the event stream is empty. Sorted soonest-first.\n const upcoming = useMemo<UpcomingRenewal[]>(() => {\n const now = Date.now();\n const fromEvents: UpcomingRenewal[] = renewals.map((e: SubRenewalEvent) => {\n const rel = relationshipById.get(e.relationshipId);\n const t = new Date(e.occursAt).getTime();\n return {\n id: e.id,\n relationshipId: e.relationshipId,\n title: rel?.label ?? formatEnumLabel(e.eventType),\n when: e.occursAt,\n amount: e.amount ?? rel?.amount ?? null,\n currency: e.currency ?? rel?.currency ?? null,\n soon: !Number.isNaN(t) && t - now <= 7 * MS_PER_DAY,\n };\n });\n\n if (fromEvents.length > 0) {\n return fromEvents\n .filter((u) => !Number.isNaN(new Date(u.when).getTime()))\n .sort((a, b) => new Date(a.when).getTime() - new Date(b.when).getTime());\n }\n\n // Derive from relationships that carry a future renewal date.\n return relationships\n .filter((r) => {\n if (!r.renewsAt) return false;\n const t = new Date(r.renewsAt).getTime();\n return !Number.isNaN(t) && t >= now;\n })\n .map((r) => {\n const t = new Date(r.renewsAt as string).getTime();\n return {\n id: r.id,\n relationshipId: r.id,\n title: r.label,\n when: r.renewsAt as string,\n amount: r.amount,\n currency: r.currency,\n soon: t - now <= 7 * MS_PER_DAY,\n };\n })\n .sort((a, b) => new Date(a.when).getTime() - new Date(b.when).getTime());\n }, [renewals, relationships, relationshipById]);\n\n const timelineItems = useMemo<TimelineItem[]>(\n () =>\n upcoming.slice(0, 6).map((u) => ({\n title: u.title,\n sub: formatRelativeTime(u.when),\n tone: u.soon ? 'warning' : 'default',\n meta:\n u.amount != null\n ? formatCurrency(u.amount, u.currency ?? stats.primaryCurrency, {\n maximumFractionDigits: 0,\n })\n : undefined,\n })),\n [upcoming, stats.primaryCurrency]\n );\n\n const actionMessages = useMemo(() => messages.filter((m) => m.actionRequired), [messages]);\n\n const isLoading =\n relationshipsQ.isLoading || invoicesQ.isLoading || inboxQ.isLoading || renewalsQ.isLoading;\n const isError =\n relationshipsQ.isError && invoicesQ.isError && inboxQ.isError && renewalsQ.isError;\n\n if (isLoading) {\n return (\n <PageLayout title=\"Overview\" description=\"Your recurring digital relationships at a glance\">\n <LoadingView label=\"Loading your subscription portfolio…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Overview\" description=\"Your recurring digital relationships at a glance\">\n <ErrorView\n message=\"We couldn't reach the Subscriber Bot service. Please try again.\"\n onRetry={() => {\n void relationshipsQ.refetch();\n void invoicesQ.refetch();\n void inboxQ.refetch();\n void renewalsQ.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n const greetingName = currentUser?.firstName || currentUser?.name?.split(' ')[0];\n\n const quickActions = [\n {\n label: 'Add a relationship',\n description: 'Track a new subscription',\n icon: <Repeat2 className=\"h-5 w-5\" />,\n path: '/relationships/new',\n },\n {\n label: 'Discover providers',\n description: 'Browse the registry',\n icon: <Sparkles className=\"h-5 w-5\" />,\n path: '/providers',\n },\n {\n label: 'Open inbox',\n description: 'Merged communications',\n icon: <Inbox className=\"h-5 w-5\" />,\n path: '/inbox',\n },\n {\n label: 'Configure agents',\n description: 'Automate your portfolio',\n icon: <Bot className=\"h-5 w-5\" />,\n path: '/agents',\n },\n ];\n\n return (\n <PageLayout\n title={greetingName ? `Welcome back, ${greetingName}` : 'Overview'}\n description=\"Everything you pay for on repeat — in one intelligent console.\"\n >\n <PagePurpose className=\"mb-6\">\n Subscriber Bot is your system of record for every recurring digital relationship. See total\n recurring spend, what renews next, what needs action, and what to optimize — all from real\n data across your providers.\n </PagePurpose>\n\n {/* KPI tiles */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n featured\n icon={<Wallet />}\n value={formatCurrency(stats.monthlySpend, stats.primaryCurrency, {\n maximumFractionDigits: 0,\n })}\n label=\"Recurring spend / month\"\n />\n <MetricsCard icon={<Repeat2 />} value={stats.activeCount} label=\"Active relationships\" />\n <MetricsCard icon={<CalendarClock />} value={upcoming.length} label=\"Upcoming renewals\" />\n <MetricsCard\n icon={<AlertTriangle />}\n value={stats.unreadActionRequired}\n label=\"Need your action\"\n trend={stats.unreadActionRequired > 0 ? 'down' : undefined}\n />\n </div>\n\n {/* Main console: renewals (left) + portfolio donut & needs-attention (right) */}\n <div className=\"mt-8 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Upcoming renewals timeline — spans two columns on desktop */}\n <div className=\"lg:col-span-2\">\n <Section\n title=\"Upcoming renewals\"\n description=\"What's charging next across your portfolio\"\n className=\"mt-0\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-text-link hover:underline\"\n >\n View all <ArrowUpRight className=\"h-3.5 w-3.5\" />\n </button>\n }\n >\n <GlassCard treatment=\"plain\" className=\"p-5\">\n {timelineItems.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n title=\"No upcoming renewals\"\n description=\"Renewals you track will appear here ahead of time.\"\n />\n ) : (\n <Timeline items={timelineItems} />\n )}\n </GlassCard>\n </Section>\n </div>\n\n {/* Right rail: portfolio-by-status donut + needs-attention panel */}\n <div className=\"flex flex-col gap-6\">\n <Section\n title=\"Portfolio by status\"\n description=\"Where your relationships stand\"\n className=\"mt-0\"\n >\n <GlassCard treatment=\"glass\" className=\"p-5\">\n {statusSegments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No relationships yet\"\n description=\"Add your first subscription to see the breakdown.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Add relationship\n </button>\n }\n />\n ) : (\n <div className=\"flex flex-col items-center gap-5 sm:flex-row sm:items-center lg:flex-col xl:flex-row\">\n <Donut\n data={statusSegments}\n size={148}\n thickness={20}\n centerLabel={String(stats.totalCount)}\n centerSub={stats.totalCount === 1 ? 'relationship' : 'relationships'}\n className=\"shrink-0\"\n />\n <Legend data={statusSegments} className=\"w-full min-w-0 flex-1\" />\n </div>\n )}\n </GlassCard>\n </Section>\n\n <Section\n title=\"Needs attention\"\n description=\"Required actions from the Universal Inbox\"\n className=\"mt-0\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/inbox')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n Open inbox\n </button>\n }\n >\n <GlassCard treatment=\"plain\" className=\"p-3\">\n {actionMessages.length === 0 ? (\n <div className=\"flex items-center gap-3 px-2 py-4\">\n <span className=\"flex size-10 shrink-0 items-center justify-center rounded-lg bg-status-success-bg-subtle text-status-success-text\">\n <ShieldCheck className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary\">You're all caught up</p>\n <p className=\"text-xs text-text-secondary\">\n Required actions across your channels will surface here.\n </p>\n </div>\n </div>\n ) : (\n <ul className=\"space-y-1\">\n {actionMessages.slice(0, 5).map((message) => (\n <li key={message.id}>\n <button\n type=\"button\"\n onClick={() => navigateTo('/inbox')}\n className=\"flex w-full items-center gap-3 rounded-lg border-l-2 border-status-warning-text/60 bg-status-warning-bg-subtle/50 p-3 text-left transition-colors hover:bg-status-warning-bg-subtle\"\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {message.subject || '(no subject)'}\n </p>\n {message.preview && (\n <p className=\"truncate text-xs text-text-secondary\">\n {message.preview}\n </p>\n )}\n </div>\n <StatusBadge status={message.category} className=\"shrink-0\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n </Section>\n </div>\n </div>\n\n {/* Open-invoice call-out (only when there is real outstanding balance) */}\n {stats.openInvoiceCount > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/invoices')}\n className=\"mt-6 flex w-full items-center justify-between gap-3 rounded-xl border border-status-warning-text/30 bg-status-warning-bg-subtle px-5 py-4 text-left transition-shadow hover:shadow-md\"\n >\n <div className=\"flex items-center gap-3\">\n <AlertTriangle className=\"h-5 w-5 shrink-0 text-status-warning-text\" />\n <span className=\"text-sm font-medium text-status-warning-text\">\n {stats.openInvoiceCount} open invoice{stats.openInvoiceCount !== 1 ? 's' : ''} ·{' '}\n {formatCurrency(stats.openInvoiceTotal, stats.primaryCurrency)} outstanding\n </span>\n </div>\n <ArrowRight className=\"h-4 w-4 shrink-0 text-status-warning-text\" />\n </button>\n )}\n\n {/* Quick actions */}\n <Section title=\"Quick actions\" description=\"Jump straight into your workflow\">\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n {quickActions.map((qa) => (\n <button\n key={qa.path}\n type=\"button\"\n onClick={() => navigateTo(qa.path)}\n className=\"group flex items-center gap-3 rounded-xl border border-border-subtle bg-bg-surface p-4 text-left transition-all hover:-translate-y-0.5 hover:border-border-seam hover:shadow-md\"\n >\n <span className=\"flex size-10 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n {qa.icon}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-sm font-medium text-text-primary\">{qa.label}</span>\n <span className=\"block text-xs text-text-secondary\">{qa.description}</span>\n </span>\n <ArrowRight className=\"h-4 w-4 shrink-0 text-text-secondary transition-transform group-hover:translate-x-0.5\" />\n </button>\n ))}\n </div>\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Universal Inbox
3
+ * @module subscriberbot/pages
4
+ *
5
+ * Every merged subscription communication in one timeline, AI-categorized,
6
+ * plus management of the ingest channels that feed it. Filter by category /
7
+ * unread, mark messages read, add & verify channels, and log a test message.
8
+ * Reads `subListInboxMessages` / `subListChannels`; writes `subMarkMessageRead`,
9
+ * `subCreateChannel`, `subVerifyChannel`, `subIngestMessage`.
10
+ */
11
+ export declare function InboxPage(): import("react").JSX.Element;
12
+ //# sourceMappingURL=InboxPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InboxPage.d.ts","sourceRoot":"","sources":["../../../src/subscriberbot/pages/InboxPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAwwBH,wBAAgB,SAAS,gCAkNxB"}