@stigmer/react 0.3.3 → 0.4.0
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/billing/AutoRechargeCard.d.ts +38 -0
- package/billing/AutoRechargeCard.d.ts.map +1 -0
- package/billing/AutoRechargeCard.js +90 -0
- package/billing/AutoRechargeCard.js.map +1 -0
- package/billing/BillingSection.d.ts +32 -0
- package/billing/BillingSection.d.ts.map +1 -0
- package/billing/BillingSection.js +81 -0
- package/billing/BillingSection.js.map +1 -0
- package/billing/CreditBalanceCard.d.ts +25 -0
- package/billing/CreditBalanceCard.d.ts.map +1 -0
- package/billing/CreditBalanceCard.js +28 -0
- package/billing/CreditBalanceCard.js.map +1 -0
- package/billing/CreditLedgerTable.d.ts +22 -0
- package/billing/CreditLedgerTable.d.ts.map +1 -0
- package/billing/CreditLedgerTable.js +75 -0
- package/billing/CreditLedgerTable.js.map +1 -0
- package/billing/CreditPackGrid.d.ts +31 -0
- package/billing/CreditPackGrid.d.ts.map +1 -0
- package/billing/CreditPackGrid.js +35 -0
- package/billing/CreditPackGrid.js.map +1 -0
- package/billing/LowBalanceBanner.d.ts +26 -0
- package/billing/LowBalanceBanner.d.ts.map +1 -0
- package/billing/LowBalanceBanner.js +33 -0
- package/billing/LowBalanceBanner.js.map +1 -0
- package/billing/PaymentMethodCard.d.ts +35 -0
- package/billing/PaymentMethodCard.d.ts.map +1 -0
- package/billing/PaymentMethodCard.js +48 -0
- package/billing/PaymentMethodCard.js.map +1 -0
- package/billing/credit-packs.d.ts +25 -0
- package/billing/credit-packs.d.ts.map +1 -0
- package/billing/credit-packs.js +39 -0
- package/billing/credit-packs.js.map +1 -0
- package/billing/format.d.ts +39 -0
- package/billing/format.d.ts.map +1 -0
- package/billing/format.js +90 -0
- package/billing/format.js.map +1 -0
- package/billing/index.d.ts +32 -0
- package/billing/index.d.ts.map +1 -0
- package/billing/index.js +21 -0
- package/billing/index.js.map +1 -0
- package/billing/useBillingAccount.d.ts +40 -0
- package/billing/useBillingAccount.d.ts.map +1 -0
- package/billing/useBillingAccount.js +35 -0
- package/billing/useBillingAccount.js.map +1 -0
- package/billing/useBillingUsageReport.d.ts +42 -0
- package/billing/useBillingUsageReport.d.ts.map +1 -0
- package/billing/useBillingUsageReport.js +43 -0
- package/billing/useBillingUsageReport.js.map +1 -0
- package/billing/useCreateBillingPortalSession.d.ts +35 -0
- package/billing/useCreateBillingPortalSession.d.ts.map +1 -0
- package/billing/useCreateBillingPortalSession.js +50 -0
- package/billing/useCreateBillingPortalSession.js.map +1 -0
- package/billing/useCreateCheckoutSession.d.ts +54 -0
- package/billing/useCreateCheckoutSession.d.ts.map +1 -0
- package/billing/useCreateCheckoutSession.js +58 -0
- package/billing/useCreateCheckoutSession.js.map +1 -0
- package/billing/useCreditLedger.d.ts +48 -0
- package/billing/useCreditLedger.d.ts.map +1 -0
- package/billing/useCreditLedger.js +39 -0
- package/billing/useCreditLedger.js.map +1 -0
- package/billing/useCustomerModelPricing.d.ts +41 -0
- package/billing/useCustomerModelPricing.d.ts.map +1 -0
- package/billing/useCustomerModelPricing.js +37 -0
- package/billing/useCustomerModelPricing.js.map +1 -0
- package/billing/useSetAutoRechargeConfig.d.ts +50 -0
- package/billing/useSetAutoRechargeConfig.d.ts.map +1 -0
- package/billing/useSetAutoRechargeConfig.js +53 -0
- package/billing/useSetAutoRechargeConfig.js.map +1 -0
- package/composer/ComposerToolbar.js +1 -1
- package/composer/ComposerToolbar.js.map +1 -1
- package/composer/SessionComposer.d.ts +1 -1
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +19 -4
- package/composer/SessionComposer.js.map +1 -1
- package/composer/__tests__/SessionComposer-memo.test.d.ts +2 -0
- package/composer/__tests__/SessionComposer-memo.test.d.ts.map +1 -0
- package/composer/__tests__/SessionComposer-memo.test.js +23 -0
- package/composer/__tests__/SessionComposer-memo.test.js.map +1 -0
- package/execution/ApprovalCard.d.ts +5 -1
- package/execution/ApprovalCard.d.ts.map +1 -1
- package/execution/ApprovalCard.js +7 -3
- package/execution/ApprovalCard.js.map +1 -1
- package/execution/ExecutionPhaseBadge.d.ts +1 -1
- package/execution/ExecutionPhaseBadge.d.ts.map +1 -1
- package/execution/ExecutionPhaseBadge.js +3 -2
- package/execution/ExecutionPhaseBadge.js.map +1 -1
- package/execution/MessageEntry.d.ts +7 -3
- package/execution/MessageEntry.d.ts.map +1 -1
- package/execution/MessageEntry.js +19 -8
- package/execution/MessageEntry.js.map +1 -1
- package/execution/MessageThread.d.ts +84 -3
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +113 -65
- package/execution/MessageThread.js.map +1 -1
- package/execution/SetupProgress.d.ts +1 -1
- package/execution/SetupProgress.d.ts.map +1 -1
- package/execution/SetupProgress.js +3 -3
- package/execution/SetupProgress.js.map +1 -1
- package/execution/SubAgentSection.d.ts +5 -1
- package/execution/SubAgentSection.d.ts.map +1 -1
- package/execution/SubAgentSection.js +13 -7
- package/execution/SubAgentSection.js.map +1 -1
- package/execution/ThreadSkeleton.d.ts +22 -0
- package/execution/ThreadSkeleton.d.ts.map +1 -0
- package/execution/ThreadSkeleton.js +26 -0
- package/execution/ThreadSkeleton.js.map +1 -0
- package/execution/ToolCallGroup.d.ts +16 -1
- package/execution/ToolCallGroup.d.ts.map +1 -1
- package/execution/ToolCallGroup.js +31 -3
- package/execution/ToolCallGroup.js.map +1 -1
- package/execution/UsageWidget.d.ts +1 -1
- package/execution/__tests__/message-entry.test.d.ts +2 -0
- package/execution/__tests__/message-entry.test.d.ts.map +1 -0
- package/execution/__tests__/message-entry.test.js +178 -0
- package/execution/__tests__/message-entry.test.js.map +1 -0
- package/execution/__tests__/thread-keys.test.d.ts +2 -0
- package/execution/__tests__/thread-keys.test.d.ts.map +1 -0
- package/execution/__tests__/thread-keys.test.js +289 -0
- package/execution/__tests__/thread-keys.test.js.map +1 -0
- package/execution/__tests__/thread-memoization.test.d.ts +2 -0
- package/execution/__tests__/thread-memoization.test.d.ts.map +1 -0
- package/execution/__tests__/thread-memoization.test.js +262 -0
- package/execution/__tests__/thread-memoization.test.js.map +1 -0
- package/execution/__tests__/thread-skeleton.test.d.ts +2 -0
- package/execution/__tests__/thread-skeleton.test.d.ts.map +1 -0
- package/execution/__tests__/thread-skeleton.test.js +35 -0
- package/execution/__tests__/thread-skeleton.test.js.map +1 -0
- package/execution/__tests__/useExecutionStream.test.js +73 -10
- package/execution/__tests__/useExecutionStream.test.js.map +1 -1
- package/execution/__tests__/useSessionVariables-stability.test.d.ts +2 -0
- package/execution/__tests__/useSessionVariables-stability.test.d.ts.map +1 -0
- package/execution/__tests__/useSessionVariables-stability.test.js +69 -0
- package/execution/__tests__/useSessionVariables-stability.test.js.map +1 -0
- package/execution/__tests__/virtualized-thread.test.d.ts +2 -0
- package/execution/__tests__/virtualized-thread.test.d.ts.map +1 -0
- package/execution/__tests__/virtualized-thread.test.js +274 -0
- package/execution/__tests__/virtualized-thread.test.js.map +1 -0
- package/execution/index.d.ts +2 -0
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +1 -0
- package/execution/index.js.map +1 -1
- package/execution/useExecutionStream.d.ts +35 -10
- package/execution/useExecutionStream.d.ts.map +1 -1
- package/execution/useExecutionStream.js +79 -40
- package/execution/useExecutionStream.js.map +1 -1
- package/execution/useSessionVariables.d.ts.map +1 -1
- package/execution/useSessionVariables.js +4 -3
- package/execution/useSessionVariables.js.map +1 -1
- package/github/useGitHubConnection.d.ts.map +1 -1
- package/github/useGitHubConnection.js +5 -4
- package/github/useGitHubConnection.js.map +1 -1
- package/identity-account/index.d.ts +2 -0
- package/identity-account/index.d.ts.map +1 -0
- package/identity-account/index.js +2 -0
- package/identity-account/index.js.map +1 -0
- package/identity-account/useIdentityAccountGate.d.ts +81 -0
- package/identity-account/useIdentityAccountGate.d.ts.map +1 -0
- package/identity-account/useIdentityAccountGate.js +100 -0
- package/identity-account/useIdentityAccountGate.js.map +1 -0
- package/index.d.ts +10 -4
- package/index.d.ts.map +1 -1
- package/index.js +8 -2
- package/index.js.map +1 -1
- package/internal/FetchCacheProvider.d.ts +44 -0
- package/internal/FetchCacheProvider.d.ts.map +1 -0
- package/internal/FetchCacheProvider.js +61 -0
- package/internal/FetchCacheProvider.js.map +1 -0
- package/internal/JumpToLatestButton.d.ts +14 -0
- package/internal/JumpToLatestButton.d.ts.map +1 -0
- package/internal/JumpToLatestButton.js +19 -0
- package/internal/JumpToLatestButton.js.map +1 -0
- package/internal/ThreadItemWrapper.d.ts +20 -0
- package/internal/ThreadItemWrapper.d.ts.map +1 -0
- package/internal/ThreadItemWrapper.js +44 -0
- package/internal/ThreadItemWrapper.js.map +1 -0
- package/internal/VirtualizedThread.d.ts +25 -0
- package/internal/VirtualizedThread.d.ts.map +1 -0
- package/internal/VirtualizedThread.js +58 -0
- package/internal/VirtualizedThread.js.map +1 -0
- package/internal/__tests__/fetch-cache.test.d.ts +2 -0
- package/internal/__tests__/fetch-cache.test.d.ts.map +1 -0
- package/internal/__tests__/fetch-cache.test.js +182 -0
- package/internal/__tests__/fetch-cache.test.js.map +1 -0
- package/internal/__tests__/stream-controller.test.d.ts +2 -0
- package/internal/__tests__/stream-controller.test.d.ts.map +1 -0
- package/internal/__tests__/stream-controller.test.js +294 -0
- package/internal/__tests__/stream-controller.test.js.map +1 -0
- package/internal/__tests__/thread-animation.test.d.ts +2 -0
- package/internal/__tests__/thread-animation.test.d.ts.map +1 -0
- package/internal/__tests__/thread-animation.test.js +79 -0
- package/internal/__tests__/thread-animation.test.js.map +1 -0
- package/internal/__tests__/useAutoScroll.test.d.ts +2 -0
- package/internal/__tests__/useAutoScroll.test.d.ts.map +1 -0
- package/internal/__tests__/useAutoScroll.test.js +188 -0
- package/internal/__tests__/useAutoScroll.test.js.map +1 -0
- package/internal/__tests__/useFetch-cache.test.d.ts +2 -0
- package/internal/__tests__/useFetch-cache.test.d.ts.map +1 -0
- package/internal/__tests__/useFetch-cache.test.js +137 -0
- package/internal/__tests__/useFetch-cache.test.js.map +1 -0
- package/internal/dev/__tests__/use-key-stability.test.d.ts +2 -0
- package/internal/dev/__tests__/use-key-stability.test.d.ts.map +1 -0
- package/internal/dev/__tests__/use-key-stability.test.js +72 -0
- package/internal/dev/__tests__/use-key-stability.test.js.map +1 -0
- package/internal/dev/__tests__/use-render-tracer.test.d.ts +2 -0
- package/internal/dev/__tests__/use-render-tracer.test.d.ts.map +1 -0
- package/internal/dev/__tests__/use-render-tracer.test.js +55 -0
- package/internal/dev/__tests__/use-render-tracer.test.js.map +1 -0
- package/internal/dev/dom-counter.d.ts +14 -0
- package/internal/dev/dom-counter.d.ts.map +1 -0
- package/internal/dev/dom-counter.js +39 -0
- package/internal/dev/dom-counter.js.map +1 -0
- package/internal/dev/index.d.ts +6 -0
- package/internal/dev/index.d.ts.map +1 -0
- package/internal/dev/index.js +6 -0
- package/internal/dev/index.js.map +1 -0
- package/internal/dev/profiler-wrapper.d.ts +16 -0
- package/internal/dev/profiler-wrapper.d.ts.map +1 -0
- package/internal/dev/profiler-wrapper.js +31 -0
- package/internal/dev/profiler-wrapper.js.map +1 -0
- package/internal/dev/use-key-stability.d.ts +22 -0
- package/internal/dev/use-key-stability.d.ts.map +1 -0
- package/internal/dev/use-key-stability.js +67 -0
- package/internal/dev/use-key-stability.js.map +1 -0
- package/internal/dev/use-render-tracer.d.ts +13 -0
- package/internal/dev/use-render-tracer.d.ts.map +1 -0
- package/internal/dev/use-render-tracer.js +57 -0
- package/internal/dev/use-render-tracer.js.map +1 -0
- package/internal/dev/use-stream-rate.d.ts +23 -0
- package/internal/dev/use-stream-rate.d.ts.map +1 -0
- package/internal/dev/use-stream-rate.js +94 -0
- package/internal/dev/use-stream-rate.js.map +1 -0
- package/internal/fetch-cache.d.ts +72 -0
- package/internal/fetch-cache.d.ts.map +1 -0
- package/internal/fetch-cache.js +118 -0
- package/internal/fetch-cache.js.map +1 -0
- package/internal/store/__tests__/conversation-store.test.d.ts +2 -0
- package/internal/store/__tests__/conversation-store.test.d.ts.map +1 -0
- package/internal/store/__tests__/conversation-store.test.js +200 -0
- package/internal/store/__tests__/conversation-store.test.js.map +1 -0
- package/internal/store/__tests__/structural-share.test.d.ts +2 -0
- package/internal/store/__tests__/structural-share.test.d.ts.map +1 -0
- package/internal/store/__tests__/structural-share.test.js +368 -0
- package/internal/store/__tests__/structural-share.test.js.map +1 -0
- package/internal/store/conversation-store.d.ts +62 -0
- package/internal/store/conversation-store.d.ts.map +1 -0
- package/internal/store/conversation-store.js +95 -0
- package/internal/store/conversation-store.js.map +1 -0
- package/internal/store/index.d.ts +31 -0
- package/internal/store/index.d.ts.map +1 -0
- package/internal/store/index.js +54 -0
- package/internal/store/index.js.map +1 -0
- package/internal/store/structural-share.d.ts +13 -0
- package/internal/store/structural-share.d.ts.map +1 -0
- package/internal/store/structural-share.js +240 -0
- package/internal/store/structural-share.js.map +1 -0
- package/internal/stream-controller.d.ts +85 -0
- package/internal/stream-controller.d.ts.map +1 -0
- package/internal/stream-controller.js +146 -0
- package/internal/stream-controller.js.map +1 -0
- package/internal/useAutoScroll.d.ts +32 -0
- package/internal/useAutoScroll.d.ts.map +1 -0
- package/internal/useAutoScroll.js +97 -0
- package/internal/useAutoScroll.js.map +1 -0
- package/internal/useFetch.d.ts +14 -0
- package/internal/useFetch.d.ts.map +1 -1
- package/internal/useFetch.js +32 -2
- package/internal/useFetch.js.map +1 -1
- package/package.json +7 -5
- package/session/__tests__/useNewSessionFlow.test.js +16 -0
- package/session/__tests__/useNewSessionFlow.test.js.map +1 -1
- package/session/__tests__/usePersistedModel.test.d.ts +2 -0
- package/session/__tests__/usePersistedModel.test.d.ts.map +1 -0
- package/session/__tests__/usePersistedModel.test.js +82 -0
- package/session/__tests__/usePersistedModel.test.js.map +1 -0
- package/session/__tests__/useSession.test.d.ts +2 -0
- package/session/__tests__/useSession.test.d.ts.map +1 -0
- package/session/__tests__/useSession.test.js +130 -0
- package/session/__tests__/useSession.test.js.map +1 -0
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +12 -6
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/usePersistedModel.d.ts +3 -0
- package/session/usePersistedModel.d.ts.map +1 -1
- package/session/usePersistedModel.js +27 -2
- package/session/usePersistedModel.js.map +1 -1
- package/session/useSession.d.ts.map +1 -1
- package/session/useSession.js +1 -1
- package/session/useSession.js.map +1 -1
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +9 -1
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionExecutions.d.ts.map +1 -1
- package/session/useSessionExecutions.js +1 -1
- package/session/useSessionExecutions.js.map +1 -1
- package/session/useSessionPageFlow.js +1 -1
- package/session/useSessionPageFlow.js.map +1 -1
- package/session/useSessionUsage.d.ts +24 -40
- package/session/useSessionUsage.d.ts.map +1 -1
- package/session/useSessionUsage.js +64 -97
- package/session/useSessionUsage.js.map +1 -1
- package/settings/BillingSection.d.ts +3 -0
- package/settings/BillingSection.d.ts.map +1 -0
- package/settings/BillingSection.js +3 -0
- package/settings/BillingSection.js.map +1 -0
- package/settings/index.d.ts +2 -0
- package/settings/index.d.ts.map +1 -1
- package/settings/index.js +1 -0
- package/settings/index.js.map +1 -1
- package/settings/settings-nav.js +1 -1
- package/settings/settings-nav.js.map +1 -1
- package/src/billing/AutoRechargeCard.tsx +274 -0
- package/src/billing/BillingSection.tsx +255 -0
- package/src/billing/CreditBalanceCard.tsx +81 -0
- package/src/billing/CreditLedgerTable.tsx +281 -0
- package/src/billing/CreditPackGrid.tsx +132 -0
- package/src/billing/LowBalanceBanner.tsx +67 -0
- package/src/billing/PaymentMethodCard.tsx +133 -0
- package/src/billing/credit-packs.ts +54 -0
- package/src/billing/format.ts +97 -0
- package/src/billing/index.ts +51 -0
- package/src/billing/useBillingAccount.ts +64 -0
- package/src/billing/useBillingUsageReport.ts +73 -0
- package/src/billing/useCreateBillingPortalSession.ts +76 -0
- package/src/billing/useCreateCheckoutSession.ts +101 -0
- package/src/billing/useCreditLedger.ts +79 -0
- package/src/billing/useCustomerModelPricing.ts +67 -0
- package/src/billing/useSetAutoRechargeConfig.ts +90 -0
- package/src/composer/ComposerToolbar.tsx +1 -1
- package/src/composer/SessionComposer.tsx +22 -4
- package/src/composer/__tests__/SessionComposer-memo.test.ts +26 -0
- package/src/execution/ApprovalCard.tsx +7 -3
- package/src/execution/ExecutionPhaseBadge.tsx +3 -2
- package/src/execution/MessageEntry.tsx +27 -16
- package/src/execution/MessageThread.tsx +308 -131
- package/src/execution/SetupProgress.tsx +3 -3
- package/src/execution/SubAgentSection.tsx +14 -6
- package/src/execution/ThreadSkeleton.tsx +73 -0
- package/src/execution/ToolCallGroup.tsx +36 -3
- package/src/execution/UsageWidget.tsx +1 -1
- package/src/execution/__tests__/message-entry.test.tsx +236 -0
- package/src/execution/__tests__/thread-keys.test.ts +409 -0
- package/src/execution/__tests__/thread-memoization.test.ts +320 -0
- package/src/execution/__tests__/thread-skeleton.test.tsx +44 -0
- package/src/execution/__tests__/useExecutionStream.test.tsx +109 -12
- package/src/execution/__tests__/useSessionVariables-stability.test.ts +95 -0
- package/src/execution/__tests__/virtualized-thread.test.tsx +401 -0
- package/src/execution/index.ts +3 -0
- package/src/execution/useExecutionStream.ts +123 -48
- package/src/execution/useSessionVariables.ts +17 -12
- package/src/github/useGitHubConnection.ts +18 -13
- package/src/identity-account/index.ts +5 -0
- package/src/identity-account/useIdentityAccountGate.ts +163 -0
- package/src/index.ts +73 -0
- package/src/internal/FetchCacheProvider.tsx +74 -0
- package/src/internal/JumpToLatestButton.tsx +61 -0
- package/src/internal/ThreadItemWrapper.tsx +65 -0
- package/src/internal/VirtualizedThread.tsx +162 -0
- package/src/internal/__tests__/fetch-cache.test.ts +230 -0
- package/src/internal/__tests__/stream-controller.test.ts +395 -0
- package/src/internal/__tests__/thread-animation.test.tsx +121 -0
- package/src/internal/__tests__/useAutoScroll.test.tsx +261 -0
- package/src/internal/__tests__/useFetch-cache.test.ts +214 -0
- package/src/internal/dev/__tests__/use-key-stability.test.ts +124 -0
- package/src/internal/dev/__tests__/use-render-tracer.test.ts +78 -0
- package/src/internal/dev/dom-counter.ts +47 -0
- package/src/internal/dev/index.ts +5 -0
- package/src/internal/dev/profiler-wrapper.tsx +52 -0
- package/src/internal/dev/use-key-stability.ts +86 -0
- package/src/internal/dev/use-render-tracer.ts +70 -0
- package/src/internal/dev/use-stream-rate.ts +138 -0
- package/src/internal/fetch-cache.ts +155 -0
- package/src/internal/store/__tests__/conversation-store.test.ts +257 -0
- package/src/internal/store/__tests__/structural-share.test.ts +454 -0
- package/src/internal/store/conversation-store.ts +128 -0
- package/src/internal/store/index.ts +68 -0
- package/src/internal/store/structural-share.ts +318 -0
- package/src/internal/stream-controller.ts +201 -0
- package/src/internal/useAutoScroll.ts +121 -0
- package/src/internal/useFetch.ts +51 -2
- package/src/session/__tests__/useNewSessionFlow.test.tsx +22 -0
- package/src/session/__tests__/usePersistedModel.test.tsx +117 -0
- package/src/session/__tests__/useSession.test.tsx +187 -0
- package/src/session/useNewSessionFlow.ts +12 -6
- package/src/session/usePersistedModel.ts +28 -2
- package/src/session/useSession.ts +1 -0
- package/src/session/useSessionConversation.ts +11 -2
- package/src/session/useSessionExecutions.ts +1 -0
- package/src/session/useSessionPageFlow.ts +1 -1
- package/src/session/useSessionUsage.ts +102 -123
- package/src/settings/BillingSection.tsx +4 -0
- package/src/settings/index.ts +2 -0
- package/src/settings/settings-nav.ts +1 -1
- package/src/styles.css +31 -0
- package/src/usage/AgentBreakdownList.tsx +147 -0
- package/src/usage/CreditRunwayIndicator.tsx +71 -0
- package/src/usage/ExportButton.tsx +115 -0
- package/src/usage/HarnessSplitCard.tsx +103 -0
- package/src/usage/OrgUsagePanel.tsx +109 -45
- package/src/usage/index.ts +15 -0
- package/src/usage/useExportCSV.ts +115 -0
- package/src/usage/useOrgUsageReport.ts +2 -1
- package/src/workspace/__tests__/useWorkspaceEntries-stability.test.ts +76 -0
- package/src/workspace/useWorkspaceEntries.ts +16 -11
- package/styles.css +1 -1
- package/usage/AgentBreakdownList.d.ts +21 -0
- package/usage/AgentBreakdownList.d.ts.map +1 -0
- package/usage/AgentBreakdownList.js +44 -0
- package/usage/AgentBreakdownList.js.map +1 -0
- package/usage/CreditRunwayIndicator.d.ts +21 -0
- package/usage/CreditRunwayIndicator.d.ts.map +1 -0
- package/usage/CreditRunwayIndicator.js +38 -0
- package/usage/CreditRunwayIndicator.js.map +1 -0
- package/usage/ExportButton.d.ts +20 -0
- package/usage/ExportButton.d.ts.map +1 -0
- package/usage/ExportButton.js +36 -0
- package/usage/ExportButton.js.map +1 -0
- package/usage/HarnessSplitCard.d.ts +17 -0
- package/usage/HarnessSplitCard.d.ts.map +1 -0
- package/usage/HarnessSplitCard.js +38 -0
- package/usage/HarnessSplitCard.js.map +1 -0
- package/usage/OrgUsagePanel.d.ts.map +1 -1
- package/usage/OrgUsagePanel.js +30 -22
- package/usage/OrgUsagePanel.js.map +1 -1
- package/usage/index.d.ts +10 -0
- package/usage/index.d.ts.map +1 -1
- package/usage/index.js +5 -0
- package/usage/index.js.map +1 -1
- package/usage/useExportCSV.d.ts +23 -0
- package/usage/useExportCSV.d.ts.map +1 -0
- package/usage/useExportCSV.js +81 -0
- package/usage/useExportCSV.js.map +1 -0
- package/usage/useOrgUsageReport.d.ts +2 -1
- package/usage/useOrgUsageReport.d.ts.map +1 -1
- package/usage/useOrgUsageReport.js +2 -1
- package/usage/useOrgUsageReport.js.map +1 -1
- package/workspace/__tests__/useWorkspaceEntries-stability.test.d.ts +2 -0
- package/workspace/__tests__/useWorkspaceEntries-stability.test.d.ts.map +1 -0
- package/workspace/__tests__/useWorkspaceEntries-stability.test.js +57 -0
- package/workspace/__tests__/useWorkspaceEntries-stability.test.js.map +1 -0
- package/workspace/useWorkspaceEntries.d.ts.map +1 -1
- package/workspace/useWorkspaceEntries.js +5 -4
- package/workspace/useWorkspaceEntries.js.map +1 -1
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { cn } from "@stigmer/theme";
|
|
5
|
+
import { getUserMessage } from "@stigmer/sdk";
|
|
6
|
+
import type { CreditLedgerEntry } from "@stigmer/protos/ai/stigmer/billing/v1/credit_pb";
|
|
7
|
+
import {
|
|
8
|
+
formatLedgerAmount,
|
|
9
|
+
formatCreditBalance,
|
|
10
|
+
formatLedgerDate,
|
|
11
|
+
ledgerEntryLabel,
|
|
12
|
+
isCredit,
|
|
13
|
+
isHold,
|
|
14
|
+
} from "./format";
|
|
15
|
+
import { useCreditLedger, type UseCreditLedgerOptions } from "./useCreditLedger";
|
|
16
|
+
|
|
17
|
+
/** Props for {@link CreditLedgerTable}. */
|
|
18
|
+
export interface CreditLedgerTableProps {
|
|
19
|
+
/** Organization ID to fetch ledger entries for. */
|
|
20
|
+
readonly orgId: string;
|
|
21
|
+
/** Additional CSS class names. */
|
|
22
|
+
readonly className?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Paginated transaction history table showing credit ledger entries.
|
|
27
|
+
*
|
|
28
|
+
* Displays entries with type badges, signed amounts, and running
|
|
29
|
+
* balance. Supports pagination with simple prev/next controls.
|
|
30
|
+
* Uses semantic colors: green for credits, red for debits, gray
|
|
31
|
+
* for holds and releases.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* <CreditLedgerTable orgId={activeOrg.metadata.id} />
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function CreditLedgerTable({
|
|
39
|
+
orgId,
|
|
40
|
+
className,
|
|
41
|
+
}: CreditLedgerTableProps) {
|
|
42
|
+
const [pageNum, setPageNum] = useState(1);
|
|
43
|
+
const options: UseCreditLedgerOptions = { pageNum, pageSize: 10 };
|
|
44
|
+
const { ledger, isLoading, error } = useCreditLedger(orgId, options);
|
|
45
|
+
|
|
46
|
+
if (isLoading) {
|
|
47
|
+
return (
|
|
48
|
+
<div className={cn("space-y-2", className)} aria-busy="true">
|
|
49
|
+
<div className="h-4 w-32 animate-pulse rounded bg-muted-subtle" />
|
|
50
|
+
{Array.from({ length: 5 }, (_, i) => (
|
|
51
|
+
<div
|
|
52
|
+
key={i}
|
|
53
|
+
className="h-10 animate-pulse rounded-lg bg-muted-subtle"
|
|
54
|
+
/>
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (error) {
|
|
61
|
+
return (
|
|
62
|
+
<p className={cn("text-destructive text-xs", className)} role="alert">
|
|
63
|
+
{getUserMessage(error)}
|
|
64
|
+
</p>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const entries = ledger?.entries ?? [];
|
|
69
|
+
const totalPages = ledger?.totalPages ?? 0;
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className={className}>
|
|
73
|
+
<h3 className="mb-2 text-xs font-semibold text-foreground">
|
|
74
|
+
Transaction History
|
|
75
|
+
</h3>
|
|
76
|
+
|
|
77
|
+
{entries.length === 0 ? (
|
|
78
|
+
<EmptyLedger />
|
|
79
|
+
) : (
|
|
80
|
+
<>
|
|
81
|
+
<div
|
|
82
|
+
className="rounded-lg border border-border bg-card"
|
|
83
|
+
role="table"
|
|
84
|
+
aria-label="Credit ledger"
|
|
85
|
+
>
|
|
86
|
+
<LedgerHeader />
|
|
87
|
+
{entries.map((entry) => (
|
|
88
|
+
<LedgerRow key={entry.entryId} entry={entry} />
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
{totalPages > 1 && (
|
|
93
|
+
<Pagination
|
|
94
|
+
pageNum={pageNum}
|
|
95
|
+
totalPages={totalPages}
|
|
96
|
+
onPageChange={setPageNum}
|
|
97
|
+
/>
|
|
98
|
+
)}
|
|
99
|
+
</>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// LedgerHeader (internal)
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
function LedgerHeader() {
|
|
110
|
+
return (
|
|
111
|
+
<div
|
|
112
|
+
role="row"
|
|
113
|
+
className="grid grid-cols-[1fr_auto_auto] gap-x-4 border-b border-border px-3.5 py-2 text-[0.65rem] font-medium uppercase tracking-wider text-muted-foreground sm:grid-cols-[auto_1fr_auto_auto]"
|
|
114
|
+
>
|
|
115
|
+
<span role="columnheader" className="hidden sm:block">
|
|
116
|
+
Date
|
|
117
|
+
</span>
|
|
118
|
+
<span role="columnheader">Type</span>
|
|
119
|
+
<span role="columnheader" className="text-right">
|
|
120
|
+
Amount
|
|
121
|
+
</span>
|
|
122
|
+
<span role="columnheader" className="text-right">
|
|
123
|
+
Balance
|
|
124
|
+
</span>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// LedgerRow (internal)
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
function LedgerRow({ entry }: { entry: CreditLedgerEntry }) {
|
|
134
|
+
const entryType = entry.type;
|
|
135
|
+
const credit = isCredit(entryType);
|
|
136
|
+
const hold = isHold(entryType);
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div
|
|
140
|
+
role="row"
|
|
141
|
+
className="grid grid-cols-[1fr_auto_auto] items-center gap-x-4 border-b border-border-muted px-3.5 py-2.5 last:border-b-0 sm:grid-cols-[auto_1fr_auto_auto]"
|
|
142
|
+
>
|
|
143
|
+
<span
|
|
144
|
+
role="cell"
|
|
145
|
+
className="hidden text-xs tabular-nums text-muted-foreground sm:block sm:w-36"
|
|
146
|
+
>
|
|
147
|
+
{entry.createdAt
|
|
148
|
+
? formatLedgerDate(entry.createdAt.seconds)
|
|
149
|
+
: "\u2014"}
|
|
150
|
+
</span>
|
|
151
|
+
|
|
152
|
+
<div role="cell" className="min-w-0">
|
|
153
|
+
<span
|
|
154
|
+
className={cn(
|
|
155
|
+
"inline-block rounded-full px-2 py-0.5 text-[0.65rem] font-medium",
|
|
156
|
+
credit
|
|
157
|
+
? "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
|
|
158
|
+
: hold
|
|
159
|
+
? "bg-muted text-muted-foreground"
|
|
160
|
+
: "bg-destructive/10 text-destructive",
|
|
161
|
+
)}
|
|
162
|
+
>
|
|
163
|
+
{ledgerEntryLabel(entryType)}
|
|
164
|
+
</span>
|
|
165
|
+
{entry.source?.description && (
|
|
166
|
+
<span className="ml-2 text-xs text-muted-foreground">
|
|
167
|
+
{entry.source.description}
|
|
168
|
+
</span>
|
|
169
|
+
)}
|
|
170
|
+
{entry.createdAt && (
|
|
171
|
+
<span className="mt-0.5 block text-[0.6rem] tabular-nums text-muted-foreground sm:hidden">
|
|
172
|
+
{formatLedgerDate(entry.createdAt.seconds)}
|
|
173
|
+
</span>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<span
|
|
178
|
+
role="cell"
|
|
179
|
+
className={cn(
|
|
180
|
+
"text-right text-xs font-medium tabular-nums",
|
|
181
|
+
credit
|
|
182
|
+
? "text-emerald-600 dark:text-emerald-400"
|
|
183
|
+
: hold
|
|
184
|
+
? "text-muted-foreground"
|
|
185
|
+
: "text-destructive",
|
|
186
|
+
)}
|
|
187
|
+
>
|
|
188
|
+
{formatLedgerAmount(entry.amountMicros)}
|
|
189
|
+
</span>
|
|
190
|
+
|
|
191
|
+
<span
|
|
192
|
+
role="cell"
|
|
193
|
+
className="text-right text-xs tabular-nums text-muted-foreground"
|
|
194
|
+
>
|
|
195
|
+
{formatCreditBalance(entry.balanceAfterMicros)}
|
|
196
|
+
</span>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// Pagination (internal)
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
function Pagination({
|
|
206
|
+
pageNum,
|
|
207
|
+
totalPages,
|
|
208
|
+
onPageChange,
|
|
209
|
+
}: {
|
|
210
|
+
pageNum: number;
|
|
211
|
+
totalPages: number;
|
|
212
|
+
onPageChange: (page: number) => void;
|
|
213
|
+
}) {
|
|
214
|
+
return (
|
|
215
|
+
<div
|
|
216
|
+
className="mt-3 flex items-center justify-between"
|
|
217
|
+
role="navigation"
|
|
218
|
+
aria-label="Ledger pagination"
|
|
219
|
+
>
|
|
220
|
+
<button
|
|
221
|
+
type="button"
|
|
222
|
+
disabled={pageNum <= 1}
|
|
223
|
+
onClick={() => onPageChange(pageNum - 1)}
|
|
224
|
+
className="rounded-md px-2.5 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-40"
|
|
225
|
+
>
|
|
226
|
+
Previous
|
|
227
|
+
</button>
|
|
228
|
+
<span className="text-xs tabular-nums text-muted-foreground">
|
|
229
|
+
Page {pageNum} of {totalPages}
|
|
230
|
+
</span>
|
|
231
|
+
<button
|
|
232
|
+
type="button"
|
|
233
|
+
disabled={pageNum >= totalPages}
|
|
234
|
+
onClick={() => onPageChange(pageNum + 1)}
|
|
235
|
+
className="rounded-md px-2.5 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-40"
|
|
236
|
+
>
|
|
237
|
+
Next
|
|
238
|
+
</button>
|
|
239
|
+
</div>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
244
|
+
// EmptyLedger (internal)
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
|
|
247
|
+
function EmptyLedger() {
|
|
248
|
+
return (
|
|
249
|
+
<div className="flex flex-col items-center justify-center rounded-lg border border-border bg-card py-10 text-center">
|
|
250
|
+
<ReceiptIcon className="text-muted-foreground mb-3 size-8" />
|
|
251
|
+
<p className="text-sm font-medium text-foreground">
|
|
252
|
+
No transactions yet
|
|
253
|
+
</p>
|
|
254
|
+
<p className="mt-1 max-w-xs text-xs text-muted-foreground">
|
|
255
|
+
Credit purchases and usage charges will appear here as your
|
|
256
|
+
organization runs agent executions.
|
|
257
|
+
</p>
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function ReceiptIcon({ className }: { className?: string }) {
|
|
263
|
+
return (
|
|
264
|
+
<svg
|
|
265
|
+
width="24"
|
|
266
|
+
height="24"
|
|
267
|
+
viewBox="0 0 24 24"
|
|
268
|
+
fill="none"
|
|
269
|
+
stroke="currentColor"
|
|
270
|
+
strokeWidth="1.5"
|
|
271
|
+
strokeLinecap="round"
|
|
272
|
+
strokeLinejoin="round"
|
|
273
|
+
className={className}
|
|
274
|
+
aria-hidden="true"
|
|
275
|
+
>
|
|
276
|
+
<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z" />
|
|
277
|
+
<path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8" />
|
|
278
|
+
<path d="M12 17.5v.5M12 6v.5" />
|
|
279
|
+
</svg>
|
|
280
|
+
);
|
|
281
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@stigmer/theme";
|
|
4
|
+
import { BillingAccountStatus } from "@stigmer/protos/ai/stigmer/billing/v1/enum_pb";
|
|
5
|
+
import {
|
|
6
|
+
CREDIT_PACKS,
|
|
7
|
+
formatPackPrice,
|
|
8
|
+
formatCreditCount,
|
|
9
|
+
type CreditPackInfo,
|
|
10
|
+
} from "./credit-packs";
|
|
11
|
+
|
|
12
|
+
/** Props for {@link CreditPackGrid}. */
|
|
13
|
+
export interface CreditPackGridProps {
|
|
14
|
+
/** Account status — purchases disabled when suspended or closed. */
|
|
15
|
+
readonly accountStatus: BillingAccountStatus;
|
|
16
|
+
/** ID of the pack currently being purchased (shows loading state). */
|
|
17
|
+
readonly purchasingPackId?: string | null;
|
|
18
|
+
/** Called when the user clicks a pack's buy button. */
|
|
19
|
+
readonly onPurchase: (packId: string) => void;
|
|
20
|
+
/** Additional CSS class names. */
|
|
21
|
+
readonly className?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Grid of credit pack cards with purchase buttons.
|
|
26
|
+
*
|
|
27
|
+
* Displays the 3 self-serve credit packs (Starter, Growth, Team)
|
|
28
|
+
* in a responsive grid. Each card shows the pack name, price,
|
|
29
|
+
* credit count, and a buy button. Buttons are disabled when the
|
|
30
|
+
* account is suspended/closed or a purchase is in progress.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* <CreditPackGrid
|
|
35
|
+
* accountStatus={account.status}
|
|
36
|
+
* purchasingPackId={isSubmitting ? activePackId : null}
|
|
37
|
+
* onPurchase={(packId) => createSession({ orgId, packId, ... })}
|
|
38
|
+
* />
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function CreditPackGrid({
|
|
42
|
+
accountStatus,
|
|
43
|
+
purchasingPackId,
|
|
44
|
+
onPurchase,
|
|
45
|
+
className,
|
|
46
|
+
}: CreditPackGridProps) {
|
|
47
|
+
const isAccountActive =
|
|
48
|
+
accountStatus === BillingAccountStatus.billing_account_active;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div>
|
|
52
|
+
<h3 className="mb-2 text-xs font-semibold text-foreground">
|
|
53
|
+
Purchase Credits
|
|
54
|
+
</h3>
|
|
55
|
+
<div
|
|
56
|
+
className={cn("grid gap-3 sm:grid-cols-3", className)}
|
|
57
|
+
role="group"
|
|
58
|
+
aria-label="Credit packs"
|
|
59
|
+
>
|
|
60
|
+
{CREDIT_PACKS.map((pack) => (
|
|
61
|
+
<PackCard
|
|
62
|
+
key={pack.packId}
|
|
63
|
+
pack={pack}
|
|
64
|
+
isPurchasing={purchasingPackId === pack.packId}
|
|
65
|
+
isDisabled={!isAccountActive || purchasingPackId != null}
|
|
66
|
+
onPurchase={onPurchase}
|
|
67
|
+
/>
|
|
68
|
+
))}
|
|
69
|
+
</div>
|
|
70
|
+
{!isAccountActive && (
|
|
71
|
+
<p className="mt-2 text-xs text-muted-foreground">
|
|
72
|
+
Credit purchases are unavailable while your billing account is{" "}
|
|
73
|
+
{accountStatus === BillingAccountStatus.billing_account_suspended
|
|
74
|
+
? "suspended"
|
|
75
|
+
: "closed"}
|
|
76
|
+
.
|
|
77
|
+
</p>
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// PackCard (internal)
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
function PackCard({
|
|
88
|
+
pack,
|
|
89
|
+
isPurchasing,
|
|
90
|
+
isDisabled,
|
|
91
|
+
onPurchase,
|
|
92
|
+
}: {
|
|
93
|
+
pack: CreditPackInfo;
|
|
94
|
+
isPurchasing: boolean;
|
|
95
|
+
isDisabled: boolean;
|
|
96
|
+
onPurchase: (packId: string) => void;
|
|
97
|
+
}) {
|
|
98
|
+
return (
|
|
99
|
+
<div className="flex flex-col rounded-lg border border-border bg-card px-4 py-4">
|
|
100
|
+
<div className="text-sm font-semibold text-foreground">
|
|
101
|
+
{pack.displayName}
|
|
102
|
+
</div>
|
|
103
|
+
<div className="mt-0.5 text-xs text-muted-foreground">
|
|
104
|
+
{pack.description}
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div className="mt-3 flex items-baseline gap-1">
|
|
108
|
+
<span className="text-xl font-bold tabular-nums text-foreground">
|
|
109
|
+
{formatPackPrice(pack.priceCents)}
|
|
110
|
+
</span>
|
|
111
|
+
</div>
|
|
112
|
+
<div className="mt-0.5 text-xs tabular-nums text-muted-foreground">
|
|
113
|
+
{formatCreditCount(pack.credits)} credits
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<button
|
|
117
|
+
type="button"
|
|
118
|
+
disabled={isDisabled}
|
|
119
|
+
onClick={() => onPurchase(pack.packId)}
|
|
120
|
+
className={cn(
|
|
121
|
+
"mt-4 w-full rounded-md px-3 py-1.5 text-xs font-medium transition-colors",
|
|
122
|
+
"bg-primary text-primary-foreground",
|
|
123
|
+
"hover:bg-primary/90",
|
|
124
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
125
|
+
)}
|
|
126
|
+
aria-busy={isPurchasing}
|
|
127
|
+
>
|
|
128
|
+
{isPurchasing ? "Redirecting\u2026" : "Buy"}
|
|
129
|
+
</button>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@stigmer/theme";
|
|
4
|
+
import { AlertTriangle } from "lucide-react";
|
|
5
|
+
import { formatCreditBalance } from "./format";
|
|
6
|
+
|
|
7
|
+
/** Props for {@link LowBalanceBanner}. */
|
|
8
|
+
export interface LowBalanceBannerProps {
|
|
9
|
+
/** Available balance in micro-USD. */
|
|
10
|
+
readonly availableMicros: bigint;
|
|
11
|
+
/** Threshold in micro-USD below which the warning is shown. */
|
|
12
|
+
readonly thresholdMicros: bigint;
|
|
13
|
+
/** Additional CSS class names. */
|
|
14
|
+
readonly className?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Conditional banner that warns when the available credit balance
|
|
19
|
+
* is below the configured threshold.
|
|
20
|
+
*
|
|
21
|
+
* Renders nothing when the balance is healthy. Not dismissible —
|
|
22
|
+
* it reflects a real account state that the user should address.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <LowBalanceBanner
|
|
27
|
+
* availableMicros={account.balance.availableMicros}
|
|
28
|
+
* thresholdMicros={account.lowBalanceThresholdMicros}
|
|
29
|
+
* />
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function LowBalanceBanner({
|
|
33
|
+
availableMicros,
|
|
34
|
+
thresholdMicros,
|
|
35
|
+
className,
|
|
36
|
+
}: LowBalanceBannerProps) {
|
|
37
|
+
if (availableMicros >= thresholdMicros) return null;
|
|
38
|
+
|
|
39
|
+
const isZeroOrNegative = availableMicros <= BigInt(0);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
role="alert"
|
|
44
|
+
className={cn(
|
|
45
|
+
"flex items-start gap-2.5 rounded-lg border px-3.5 py-3 text-xs",
|
|
46
|
+
isZeroOrNegative
|
|
47
|
+
? "border-destructive/30 bg-destructive/5 text-destructive"
|
|
48
|
+
: "border-warning/30 bg-warning/5 text-warning-foreground",
|
|
49
|
+
className,
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
<AlertTriangle className="mt-0.5 size-3.5 shrink-0" aria-hidden="true" />
|
|
53
|
+
<div>
|
|
54
|
+
<p className="font-medium">
|
|
55
|
+
{isZeroOrNegative
|
|
56
|
+
? "Credit balance exhausted"
|
|
57
|
+
: "Low credit balance"}
|
|
58
|
+
</p>
|
|
59
|
+
<p className="mt-0.5 opacity-80">
|
|
60
|
+
{isZeroOrNegative
|
|
61
|
+
? "Your credit balance is zero. Purchase credits to continue running agent executions."
|
|
62
|
+
: `Your balance (${formatCreditBalance(availableMicros)}) is below the warning threshold. Consider purchasing additional credits.`}
|
|
63
|
+
</p>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@stigmer/theme";
|
|
4
|
+
import type { PaymentMethodSummary } from "@stigmer/protos/ai/stigmer/billing/v1/billing_account_pb";
|
|
5
|
+
import { BillingAccountStatus } from "@stigmer/protos/ai/stigmer/billing/v1/enum_pb";
|
|
6
|
+
|
|
7
|
+
/** Props for {@link PaymentMethodCard}. */
|
|
8
|
+
export interface PaymentMethodCardProps {
|
|
9
|
+
/** The saved payment method, or undefined if none is on file. */
|
|
10
|
+
readonly paymentMethod?: PaymentMethodSummary;
|
|
11
|
+
/** Account status — portal button disabled when suspended or closed. */
|
|
12
|
+
readonly accountStatus: BillingAccountStatus;
|
|
13
|
+
/** `true` while the portal session is being created. */
|
|
14
|
+
readonly isPortalLoading?: boolean;
|
|
15
|
+
/** Called when the user clicks "Manage payment methods". */
|
|
16
|
+
readonly onManage: () => void;
|
|
17
|
+
/** Additional CSS class names. */
|
|
18
|
+
readonly className?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const BRAND_DISPLAY: Record<string, string> = {
|
|
22
|
+
visa: "Visa",
|
|
23
|
+
mastercard: "Mastercard",
|
|
24
|
+
amex: "American Express",
|
|
25
|
+
discover: "Discover",
|
|
26
|
+
diners: "Diners Club",
|
|
27
|
+
jcb: "JCB",
|
|
28
|
+
unionpay: "UnionPay",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function formatBrand(brand: string): string {
|
|
32
|
+
return BRAND_DISPLAY[brand.toLowerCase()] ?? brand;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function formatExpiry(month: number, year: number): string {
|
|
36
|
+
const m = String(month).padStart(2, "0");
|
|
37
|
+
const y = String(year).slice(-2);
|
|
38
|
+
return `${m}/${y}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Displays the saved payment method with a button to open the
|
|
43
|
+
* Stripe Customer Portal for management.
|
|
44
|
+
*
|
|
45
|
+
* Shows card brand, last 4 digits, and expiry when a payment method
|
|
46
|
+
* is on file. Shows an empty state prompt when none exists. The
|
|
47
|
+
* "Manage" button opens the Stripe Customer Portal where users can
|
|
48
|
+
* add, update, or remove payment methods.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* <PaymentMethodCard
|
|
53
|
+
* paymentMethod={account.defaultPaymentMethod}
|
|
54
|
+
* accountStatus={account.status}
|
|
55
|
+
* onManage={() => openPortal(orgId)}
|
|
56
|
+
* />
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function PaymentMethodCard({
|
|
60
|
+
paymentMethod,
|
|
61
|
+
accountStatus,
|
|
62
|
+
isPortalLoading,
|
|
63
|
+
onManage,
|
|
64
|
+
className,
|
|
65
|
+
}: PaymentMethodCardProps) {
|
|
66
|
+
const isAccountActive =
|
|
67
|
+
accountStatus === BillingAccountStatus.billing_account_active;
|
|
68
|
+
const hasPm =
|
|
69
|
+
paymentMethod != null && paymentMethod.paymentMethodId !== "";
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div
|
|
73
|
+
className={cn(
|
|
74
|
+
"rounded-lg border border-border bg-card px-4 py-4",
|
|
75
|
+
className,
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
<div className="flex items-center justify-between">
|
|
79
|
+
<h3 className="text-xs font-semibold text-foreground">
|
|
80
|
+
Payment Method
|
|
81
|
+
</h3>
|
|
82
|
+
{hasPm && (
|
|
83
|
+
<button
|
|
84
|
+
type="button"
|
|
85
|
+
disabled={!isAccountActive || isPortalLoading}
|
|
86
|
+
onClick={onManage}
|
|
87
|
+
className={cn(
|
|
88
|
+
"rounded-md px-2.5 py-1 text-xs font-medium transition-colors",
|
|
89
|
+
"text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
90
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
91
|
+
)}
|
|
92
|
+
aria-busy={isPortalLoading}
|
|
93
|
+
>
|
|
94
|
+
{isPortalLoading ? "Opening\u2026" : "Manage"}
|
|
95
|
+
</button>
|
|
96
|
+
)}
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
{hasPm ? (
|
|
100
|
+
<div className="mt-2 flex items-center gap-3">
|
|
101
|
+
<CardBrandIcon brand={paymentMethod.brand} />
|
|
102
|
+
<div>
|
|
103
|
+
<div className="text-sm font-medium text-foreground">
|
|
104
|
+
{formatBrand(paymentMethod.brand)} ····{" "}
|
|
105
|
+
{paymentMethod.last4}
|
|
106
|
+
</div>
|
|
107
|
+
<div className="text-xs text-muted-foreground">
|
|
108
|
+
Expires{" "}
|
|
109
|
+
{formatExpiry(paymentMethod.expMonth, paymentMethod.expYear)}
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
) : (
|
|
114
|
+
<div className="mt-2">
|
|
115
|
+
<p className="text-xs text-muted-foreground">
|
|
116
|
+
No payment method on file. A card will be saved automatically
|
|
117
|
+
when you purchase your first credit pack.
|
|
118
|
+
</p>
|
|
119
|
+
</div>
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function CardBrandIcon({ brand }: { brand: string }) {
|
|
126
|
+
return (
|
|
127
|
+
<div className="flex size-9 items-center justify-center rounded-md border border-border bg-background">
|
|
128
|
+
<span className="text-[0.6rem] font-bold uppercase text-muted-foreground">
|
|
129
|
+
{brand.slice(0, 4)}
|
|
130
|
+
</span>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Metadata for a self-serve credit pack. */
|
|
2
|
+
export interface CreditPackInfo {
|
|
3
|
+
/** Stable identifier matching the backend catalog (e.g., "starter"). */
|
|
4
|
+
readonly packId: string;
|
|
5
|
+
/** Display name shown in the UI. */
|
|
6
|
+
readonly displayName: string;
|
|
7
|
+
/** Brief description of the pack's positioning. */
|
|
8
|
+
readonly description: string;
|
|
9
|
+
/** Price in USD cents (e.g., 1000 = $10.00). */
|
|
10
|
+
readonly priceCents: number;
|
|
11
|
+
/** Number of credits granted (1 credit = $0.01 USD). */
|
|
12
|
+
readonly credits: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Static credit pack catalog matching the backend `CreditPackCatalog`.
|
|
17
|
+
*
|
|
18
|
+
* Packs are static product entries, not database-backed resources.
|
|
19
|
+
* At launch, credits equal the dollar value (no volume bonus).
|
|
20
|
+
*/
|
|
21
|
+
export const CREDIT_PACKS: readonly CreditPackInfo[] = [
|
|
22
|
+
{
|
|
23
|
+
packId: "starter",
|
|
24
|
+
displayName: "Starter",
|
|
25
|
+
description: "For trying things out",
|
|
26
|
+
priceCents: 1_000,
|
|
27
|
+
credits: 1_000,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
packId: "growth",
|
|
31
|
+
displayName: "Growth",
|
|
32
|
+
description: "For growing teams",
|
|
33
|
+
priceCents: 5_000,
|
|
34
|
+
credits: 5_000,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
packId: "team",
|
|
38
|
+
displayName: "Team",
|
|
39
|
+
description: "For production workloads",
|
|
40
|
+
priceCents: 20_000,
|
|
41
|
+
credits: 20_000,
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
/** Format a cent amount as a dollar string (e.g., 1000 -> "$10"). */
|
|
46
|
+
export function formatPackPrice(cents: number): string {
|
|
47
|
+
const dollars = cents / 100;
|
|
48
|
+
return dollars % 1 === 0 ? `$${dollars}` : `$${dollars.toFixed(2)}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Format a credit count with commas (e.g., 5000 -> "5,000"). */
|
|
52
|
+
export function formatCreditCount(credits: number): string {
|
|
53
|
+
return credits.toLocaleString("en-US");
|
|
54
|
+
}
|