@buildbase/sdk 0.0.33 → 0.0.35
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/README.md +153 -2
- package/dist/css/styles.css +1 -1
- package/dist/index.d.ts +214 -45
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/react/index.d.ts +313 -2
- package/dist/react/index.js +6 -6
- package/dist/react/index.mjs +4 -4
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -555,6 +555,8 @@ interface IWorkspace {
|
|
|
555
555
|
* When set, subscription UI only shows/uses this currency.
|
|
556
556
|
*/
|
|
557
557
|
billingCurrency?: string | null;
|
|
558
|
+
/** Per-workspace permission overrides. Takes priority over org-level settings.permissions. */
|
|
559
|
+
permissions?: Record<string, string[]>;
|
|
558
560
|
/** Workspace onboarding config. Set on creation based on org settings. SDK shows trial CTA. */
|
|
559
561
|
pendingOnboarding?: {
|
|
560
562
|
mode: 'trial';
|
|
@@ -744,6 +746,8 @@ interface ISettings {
|
|
|
744
746
|
canCreateWorkspace: boolean | 'owner-only';
|
|
745
747
|
/** Whether members can invite others. false = disabled, 'admin-only' = restricted */
|
|
746
748
|
canInviteMembers: boolean | 'admin-only';
|
|
749
|
+
/** Custom role→permission mapping. Overrides SDK defaults when provided by backend. */
|
|
750
|
+
permissions?: Record<string, string[]>;
|
|
747
751
|
/** Show workspace switcher in the UI */
|
|
748
752
|
showSwitcher: boolean;
|
|
749
753
|
/** Max workspaces a user can own. 0 = unlimited */
|
|
@@ -992,6 +996,58 @@ declare class UserApi extends BaseApi {
|
|
|
992
996
|
getFeatures(signal?: AbortSignal): Promise<Record<string, boolean>>;
|
|
993
997
|
}
|
|
994
998
|
|
|
999
|
+
/** Data passed to a notification template for merge tag replacement. */
|
|
1000
|
+
interface NotificationData {
|
|
1001
|
+
/** Push notification title. Falls back to the event name if not provided. */
|
|
1002
|
+
title?: string;
|
|
1003
|
+
/** Primary message — used in email body and as push notification body. */
|
|
1004
|
+
message?: string;
|
|
1005
|
+
/** URL to open when the user clicks the push notification. Also available as {{url}} in email template. */
|
|
1006
|
+
url?: string;
|
|
1007
|
+
/**
|
|
1008
|
+
* Which channels to send on. Overrides the event's default channel config.
|
|
1009
|
+
* Omit to use the event's configured channels.
|
|
1010
|
+
*
|
|
1011
|
+
* @example
|
|
1012
|
+
* ```ts
|
|
1013
|
+
* // Only push, no email
|
|
1014
|
+
* { channels: { push: true } }
|
|
1015
|
+
*
|
|
1016
|
+
* // Only email, no push
|
|
1017
|
+
* { channels: { email: true } }
|
|
1018
|
+
* ```
|
|
1019
|
+
*/
|
|
1020
|
+
channels?: {
|
|
1021
|
+
email?: boolean;
|
|
1022
|
+
push?: boolean;
|
|
1023
|
+
};
|
|
1024
|
+
/** Any additional merge tags available as {{key}} in the email template. */
|
|
1025
|
+
[key: string]: any;
|
|
1026
|
+
}
|
|
1027
|
+
/** Result of sending a notification. */
|
|
1028
|
+
interface NotificationResult {
|
|
1029
|
+
sent: boolean;
|
|
1030
|
+
/** Which channels were actually used. false = blocked by settings or missing template. */
|
|
1031
|
+
channels: {
|
|
1032
|
+
email: boolean;
|
|
1033
|
+
push: boolean;
|
|
1034
|
+
};
|
|
1035
|
+
/** Number of users notified. 1 for single user, N for whole workspace. */
|
|
1036
|
+
notifiedCount?: number;
|
|
1037
|
+
/** Reason if not sent (e.g., 'event_disabled'). Only present when sent=false. */
|
|
1038
|
+
reason?: string;
|
|
1039
|
+
}
|
|
1040
|
+
/** A notification event that end-users can manage in their workspace settings. */
|
|
1041
|
+
interface NotificationEvent {
|
|
1042
|
+
slug: string;
|
|
1043
|
+
name: string;
|
|
1044
|
+
description: string;
|
|
1045
|
+
category: string;
|
|
1046
|
+
channels: {
|
|
1047
|
+
email: boolean;
|
|
1048
|
+
push: boolean;
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
995
1051
|
declare class WorkspaceApi extends BaseApi {
|
|
996
1052
|
constructor(config: IOsConfig & {
|
|
997
1053
|
sessionId?: string;
|
|
@@ -1024,6 +1080,10 @@ declare class WorkspaceApi extends BaseApi {
|
|
|
1024
1080
|
workspace: IWorkspace;
|
|
1025
1081
|
message: string;
|
|
1026
1082
|
}>;
|
|
1083
|
+
updateSettings(data: {
|
|
1084
|
+
permissions: Record<string, string[]>;
|
|
1085
|
+
}): Promise<any>;
|
|
1086
|
+
updateWorkspacePermissions(workspaceId: string, permissions: Record<string, string[]>): Promise<any>;
|
|
1027
1087
|
getFeatures(): Promise<IWorkspaceFeature[]>;
|
|
1028
1088
|
updateFeature(workspaceId: string, key: string, value: boolean): Promise<IWorkspace>;
|
|
1029
1089
|
getWorkspace(workspaceId: string): Promise<IWorkspace>;
|
|
@@ -1186,6 +1246,41 @@ declare class WorkspaceApi extends BaseApi {
|
|
|
1186
1246
|
* @returns Paginated usage log entries
|
|
1187
1247
|
*/
|
|
1188
1248
|
getUsageLogs(workspaceId: string, query?: IUsageLogsQuery): Promise<IUsageLogsResponse>;
|
|
1249
|
+
/**
|
|
1250
|
+
* Trigger a notification event for a workspace.
|
|
1251
|
+
* Respects all notification gates (org settings, event config, workspace preferences).
|
|
1252
|
+
*
|
|
1253
|
+
* @param workspaceId - The workspace context
|
|
1254
|
+
* @param event - The event slug (e.g., 'comment_added')
|
|
1255
|
+
* @param userId - The user to notify. Omit to notify all workspace members.
|
|
1256
|
+
* @param data - Template merge data. `message` is used as push body.
|
|
1257
|
+
*
|
|
1258
|
+
* @example
|
|
1259
|
+
* ```ts
|
|
1260
|
+
* // Notify a specific user
|
|
1261
|
+
* await api.sendNotification(workspaceId, 'comment_added', userId, {
|
|
1262
|
+
* message: 'Alice commented on your project',
|
|
1263
|
+
* });
|
|
1264
|
+
*
|
|
1265
|
+
* // Notify all workspace members
|
|
1266
|
+
* await api.sendNotification(workspaceId, 'new_release', undefined, {
|
|
1267
|
+
* message: 'Version 2.0 is now available!',
|
|
1268
|
+
* });
|
|
1269
|
+
* ```
|
|
1270
|
+
*/
|
|
1271
|
+
sendNotification(workspaceId: string, event: string, userId?: string, data?: NotificationData): Promise<NotificationResult>;
|
|
1272
|
+
getNotificationEvents(workspaceId: string): Promise<NotificationEvent[]>;
|
|
1273
|
+
getNotificationPreferences(workspaceId: string): Promise<Record<string, {
|
|
1274
|
+
email?: boolean;
|
|
1275
|
+
push?: boolean;
|
|
1276
|
+
}>>;
|
|
1277
|
+
updateNotificationPreferences(workspaceId: string, preferences: Record<string, {
|
|
1278
|
+
email?: boolean;
|
|
1279
|
+
push?: boolean;
|
|
1280
|
+
}>): Promise<Record<string, {
|
|
1281
|
+
email?: boolean;
|
|
1282
|
+
push?: boolean;
|
|
1283
|
+
}>>;
|
|
1189
1284
|
}
|
|
1190
1285
|
|
|
1191
1286
|
/**
|
|
@@ -1578,6 +1673,90 @@ declare function validateInvite(opts: {
|
|
|
1578
1673
|
requireSubscription?: boolean;
|
|
1579
1674
|
}): InviteValidation;
|
|
1580
1675
|
|
|
1676
|
+
/**
|
|
1677
|
+
* Role-based permission system.
|
|
1678
|
+
* Framework-agnostic — used by both React hooks and server-side BuildBase.
|
|
1679
|
+
*
|
|
1680
|
+
* Two types of permissions:
|
|
1681
|
+
*
|
|
1682
|
+
* 1. **Platform permissions** (ours) — prefixed with `workspace:`, control SDK
|
|
1683
|
+
* built-in features (settings, billing, members, usage). Defined as constants
|
|
1684
|
+
* in `Permission`. Enforced by the BuildBase backend.
|
|
1685
|
+
*
|
|
1686
|
+
* 2. **App permissions** (developer's) — any custom string (e.g. `projects:create`,
|
|
1687
|
+
* `reports:export`). Defined and enforced by the developer in their own app.
|
|
1688
|
+
* Flow through the same `usePermissions()` / `can()` / `<WhenPermission>` API.
|
|
1689
|
+
*
|
|
1690
|
+
* Both are resolved from the same role→permission map. Owner always gets all
|
|
1691
|
+
* platform permissions + any app permissions defined in the config.
|
|
1692
|
+
*/
|
|
1693
|
+
declare const Permission: {
|
|
1694
|
+
readonly WORKSPACE_SETTINGS_VIEW: "workspace:settings:view";
|
|
1695
|
+
readonly WORKSPACE_SETTINGS_EDIT: "workspace:settings:edit";
|
|
1696
|
+
readonly WORKSPACE_DELETE: "workspace:delete";
|
|
1697
|
+
readonly WORKSPACE_MEMBERS_VIEW: "workspace:members:view";
|
|
1698
|
+
readonly WORKSPACE_MEMBERS_INVITE: "workspace:members:invite";
|
|
1699
|
+
readonly WORKSPACE_MEMBERS_REMOVE: "workspace:members:remove";
|
|
1700
|
+
readonly WORKSPACE_MEMBERS_ROLE_CHANGE: "workspace:members:role-change";
|
|
1701
|
+
readonly WORKSPACE_FEATURES_VIEW: "workspace:features:view";
|
|
1702
|
+
readonly WORKSPACE_FEATURES_EDIT: "workspace:features:edit";
|
|
1703
|
+
readonly WORKSPACE_BILLING_VIEW: "workspace:billing:view";
|
|
1704
|
+
readonly WORKSPACE_BILLING_MANAGE: "workspace:billing:manage";
|
|
1705
|
+
readonly WORKSPACE_USAGE_VIEW: "workspace:usage:view";
|
|
1706
|
+
};
|
|
1707
|
+
type PermissionKey = (typeof Permission)[keyof typeof Permission];
|
|
1708
|
+
type RolePermissionMap = Record<string, string[]>;
|
|
1709
|
+
declare const DEFAULT_ROLE_PERMISSIONS: RolePermissionMap;
|
|
1710
|
+
interface WorkspaceLike {
|
|
1711
|
+
_id: string;
|
|
1712
|
+
createdBy: string | {
|
|
1713
|
+
_id: string;
|
|
1714
|
+
} | null | undefined;
|
|
1715
|
+
users?: Array<string | {
|
|
1716
|
+
_id: string;
|
|
1717
|
+
role?: string;
|
|
1718
|
+
}>;
|
|
1719
|
+
permissions?: Record<string, string[]>;
|
|
1720
|
+
}
|
|
1721
|
+
interface SettingsLike {
|
|
1722
|
+
workspace?: {
|
|
1723
|
+
defaultRole?: string;
|
|
1724
|
+
permissions?: Record<string, string[]>;
|
|
1725
|
+
canInviteMembers?: boolean | 'admin-only';
|
|
1726
|
+
canCreateWorkspace?: boolean | 'owner-only';
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
interface PermissionContext {
|
|
1730
|
+
userId: string | null;
|
|
1731
|
+
workspaceRole?: string | null;
|
|
1732
|
+
workspace: WorkspaceLike | null;
|
|
1733
|
+
settings?: SettingsLike | null;
|
|
1734
|
+
/** Developer-defined app permissions per role. Merged with platform defaults. */
|
|
1735
|
+
appPermissions?: Record<string, string[]>;
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Resolve the full set of permissions for a user in a workspace.
|
|
1739
|
+
*
|
|
1740
|
+
* Returns both platform permissions (workspace:*) and app permissions
|
|
1741
|
+
* (developer-defined custom strings) in a single Set.
|
|
1742
|
+
*
|
|
1743
|
+
* Resolution order (matches backend 3-tier):
|
|
1744
|
+
* 1. If user is workspace owner → all platform permissions + all app permissions
|
|
1745
|
+
* 2. workspace.permissions[role] (per-workspace overrides)
|
|
1746
|
+
* 3. settings.workspace.permissions[role] (org-level template)
|
|
1747
|
+
* 4. DEFAULT_ROLE_PERMISSIONS[role] (SDK built-in defaults)
|
|
1748
|
+
* 5. Merge in appPermissions (developer-defined) for the role
|
|
1749
|
+
* 6. If role not found → use defaultRole from settings, then 'member'
|
|
1750
|
+
* 7. Apply setting restrictions (canInviteMembers, canCreateWorkspace)
|
|
1751
|
+
*/
|
|
1752
|
+
declare function resolvePermissions(ctx: PermissionContext): Set<string>;
|
|
1753
|
+
/**
|
|
1754
|
+
* Check if a user has a specific permission (or all of an array).
|
|
1755
|
+
* Works with both platform permissions (Permission.WORKSPACE_*) and
|
|
1756
|
+
* app permissions (any custom string).
|
|
1757
|
+
*/
|
|
1758
|
+
declare function hasPermission(permission: string | string[], ctx: PermissionContext): boolean;
|
|
1759
|
+
|
|
1581
1760
|
/**
|
|
1582
1761
|
* Push notification service worker source code.
|
|
1583
1762
|
* Export this string and write it to a file in your app's `public/` directory.
|
|
@@ -1603,49 +1782,6 @@ interface BetaFormResponse {
|
|
|
1603
1782
|
message: string;
|
|
1604
1783
|
}
|
|
1605
1784
|
|
|
1606
|
-
/**
|
|
1607
|
-
* Server-side BuildBase SDK — Auth.js-style configuration pattern.
|
|
1608
|
-
*
|
|
1609
|
-
* Configure once, use everywhere. Session is resolved automatically.
|
|
1610
|
-
*
|
|
1611
|
-
* @example 1. Configure once (lib/buildbase.ts)
|
|
1612
|
-
* ```ts
|
|
1613
|
-
* import BuildBase from "@buildbase/sdk"
|
|
1614
|
-
* import { cookies } from "next/headers"
|
|
1615
|
-
*
|
|
1616
|
-
* export const { auth, workspace, subscription, usage } = BuildBase({
|
|
1617
|
-
* serverUrl: process.env.BUILDBASE_URL!,
|
|
1618
|
-
* orgId: process.env.BUILDBASE_ORG_ID!,
|
|
1619
|
-
* getSessionId: async () => {
|
|
1620
|
-
* const c = await cookies()
|
|
1621
|
-
* return c.get("bb-session-id")?.value ?? null
|
|
1622
|
-
* },
|
|
1623
|
-
* })
|
|
1624
|
-
* ```
|
|
1625
|
-
*
|
|
1626
|
-
* @example 2. Use in API routes — no sessionId passing needed
|
|
1627
|
-
* ```ts
|
|
1628
|
-
* import { auth, workspace, subscription } from "@/lib/buildbase"
|
|
1629
|
-
*
|
|
1630
|
-
* export async function GET() {
|
|
1631
|
-
* const session = await auth()
|
|
1632
|
-
* if (!session) return Response.json({ error: "Unauthorized" }, { status: 401 })
|
|
1633
|
-
*
|
|
1634
|
-
* const workspaces = await workspace.list()
|
|
1635
|
-
* const sub = await subscription.get(workspaceId)
|
|
1636
|
-
* return Response.json({ workspaces, sub })
|
|
1637
|
-
* }
|
|
1638
|
-
* ```
|
|
1639
|
-
*
|
|
1640
|
-
* @example 3. Background jobs — override session for service accounts
|
|
1641
|
-
* ```ts
|
|
1642
|
-
* import { client } from "@/lib/buildbase"
|
|
1643
|
-
*
|
|
1644
|
-
* const api = client.forSession(process.env.SERVICE_SESSION_ID!)
|
|
1645
|
-
* await api.workspace.recordUsage(workspaceId, { quotaSlug: "uploads", quantity: 1 })
|
|
1646
|
-
* ```
|
|
1647
|
-
*/
|
|
1648
|
-
|
|
1649
1785
|
interface BuildBaseConfig {
|
|
1650
1786
|
/** Base URL of the BuildBase API server */
|
|
1651
1787
|
serverUrl: string;
|
|
@@ -1820,6 +1956,37 @@ interface FeatureActions {
|
|
|
1820
1956
|
list(): Promise<IWorkspaceFeature[]>;
|
|
1821
1957
|
update(workspaceId: string, key: string, value: boolean): Promise<IWorkspace>;
|
|
1822
1958
|
}
|
|
1959
|
+
interface PermissionActions {
|
|
1960
|
+
/** Check if a user has a permission (or all of an array) in a workspace. Works with both platform permissions (Permission.*) and app permissions (custom strings). */
|
|
1961
|
+
check(workspaceId: string, userId: string, permission: string | string[]): Promise<boolean>;
|
|
1962
|
+
/** Resolve all permissions for a user in a workspace. Returns both platform and app permissions. */
|
|
1963
|
+
resolve(workspaceId: string, userId: string): Promise<Set<string>>;
|
|
1964
|
+
}
|
|
1965
|
+
interface NotificationActions {
|
|
1966
|
+
/**
|
|
1967
|
+
* Send a notification to a user or all workspace members.
|
|
1968
|
+
* Respects all notification gates (org settings, event config, workspace preferences).
|
|
1969
|
+
*
|
|
1970
|
+
* @param workspaceId - The workspace context
|
|
1971
|
+
* @param event - The event slug (e.g., 'comment_added')
|
|
1972
|
+
* @param userId - The user to notify. Omit to notify all workspace members.
|
|
1973
|
+
* @param data - Template merge data. `message` is used as push body.
|
|
1974
|
+
*
|
|
1975
|
+
* @example
|
|
1976
|
+
* ```ts
|
|
1977
|
+
* // Notify one user
|
|
1978
|
+
* await notification.send(workspaceId, 'comment_added', userId, {
|
|
1979
|
+
* message: 'Alice commented on your project',
|
|
1980
|
+
* })
|
|
1981
|
+
*
|
|
1982
|
+
* // Notify all workspace members
|
|
1983
|
+
* await notification.send(workspaceId, 'new_release', undefined, {
|
|
1984
|
+
* message: 'Version 2.0 is now available!',
|
|
1985
|
+
* })
|
|
1986
|
+
* ```
|
|
1987
|
+
*/
|
|
1988
|
+
send(workspaceId: string, event: string, userId?: string, data?: NotificationData): Promise<NotificationResult>;
|
|
1989
|
+
}
|
|
1823
1990
|
/** All action modules bound to a specific session. Returned by `withSession()`. */
|
|
1824
1991
|
interface ScopedActions {
|
|
1825
1992
|
workspace: WorkspaceActions;
|
|
@@ -1830,6 +1997,8 @@ interface ScopedActions {
|
|
|
1830
1997
|
usage: UsageActions;
|
|
1831
1998
|
settings: SettingsActions;
|
|
1832
1999
|
features: FeatureActions;
|
|
2000
|
+
permissions: PermissionActions;
|
|
2001
|
+
notification: NotificationActions;
|
|
1833
2002
|
}
|
|
1834
2003
|
interface BuildBaseResult extends ScopedActions {
|
|
1835
2004
|
/**
|
|
@@ -1878,5 +2047,5 @@ interface BuildBaseResult extends ScopedActions {
|
|
|
1878
2047
|
}
|
|
1879
2048
|
declare function BuildBase(config: BuildBaseConfig): BuildBaseResult;
|
|
1880
2049
|
|
|
1881
|
-
export { ApiVersion, AuthApi, AuthStatus, BB_PARAM, BaseApi, BetaForm, BillingIntervals, BuildBase, CURRENCY_DISPLAY, CURRENCY_FLAG, DunningState, EventEmitter, InvoiceStatuses, PLAN_CURRENCY_CODES, PLAN_CURRENCY_OPTIONS, PUSH_SERVICE_WORKER_SCRIPT, PushApi, SDKEvent, SettingsApi, SubscriptionItemType, SubscriptionStatus, UserApi, WorkspaceApi, calculateBillableSeats, calculateSeatOverageCents, calculateTotalSubscriptionCents, cleanBBParams, createBBUrl, createCheckoutRedirectUrls, BuildBase as default, eventEmitter, formatCents, formatOverageRate, formatOverageRateWithLabel, formatQuotaIncludedOverage, formatQuotaWithPrice, getAvailableCurrenciesFromPlans, getBasePriceCents, getBillingIntervalAndCurrencyFromPriceId, getCurrencyFlag, getCurrencySymbol, getDisplayCurrency, getPerSeatPriceCents, getPricingVariant, getQuotaDisplayValue, getQuotaDisplayWithVariant, getQuotaOverageCents, getQuotaUnitLabelFromName, getSeatPricing, getStripePriceIdForInterval, invalidateQuotaUsage, invalidateSubscription, readBBParams, resolveMaxUsers, safeRedirect, validateInvite, validateRedirectUrl };
|
|
1882
|
-
export type { BetaFormData, BetaFormResponse, BillingInterval, BuildBaseConfig, BuildBaseResult, BuildBaseSession, CheckoutResult, EventData, EventType, FeatureActions, FormatQuotaWithPriceOptions, IAllQuotaUsageResponse, IBaseApiConfig, IBasePricing, IBetaConfig, ICheckoutSessionRequest, ICheckoutSessionResponse, IEventCallbacks, IInvoice, IInvoiceListResponse, IInvoiceResponse, IOsConfig, IOsState, IPlan, IPlanGroup, IPlanGroupInfo, IPlanGroupLatestVersion, IPlanGroupResponse, IPlanGroupVersion, IPlanGroupVersionWithPlans, IPlanGroupVersionsResponse, IPlanVersion, IPlanVersionSummary, IPlanVersionWithPlan, IPricingVariant, IPublicPlanItem, IPublicPlanItemCategory, IPublicPlanVersion, IPublicPlansResponse, IQuotaByInterval, IQuotaIntervalValue, IQuotaOveragePriceIdsByInterval, IQuotaOveragesByInterval, IQuotaUsageStatus, IQuotaUsageStatusResponse, IRecordUsageRequest, IRecordUsageResponse, IStripePricesByInterval, ISubscription, ISubscriptionItem, ISubscriptionResponse, ISubscriptionUpdateRequest, ISubscriptionUpdateResponse, IUsageLogEntry, IUsageLogsQuery, IUsageLogsResponse, InviteBlockReason, InviteValidation, InvoiceActions, InvoiceStatus, MaxUsersConfig, OnWorkspaceChangeParams, PlanActions, PlanVersionWithPricingVariants, QuotaDisplayValue, QuotaDisplayWithOverage, ScopedActions, SettingsActions, SubscriptionActions, SubscriptionStatusType, UsageActions, UserActions, UserCreatedEventData, UserUpdatedEventData, WorkspaceActions, WorkspaceChangedEventData, WorkspaceCreatedEventData, WorkspaceDeletedEventData, WorkspaceUpdatedEventData, WorkspaceUserAddedEventData, WorkspaceUserRemovedEventData, WorkspaceUserRoleChangedEventData };
|
|
2050
|
+
export { ApiVersion, AuthApi, AuthStatus, BB_PARAM, BaseApi, BetaForm, BillingIntervals, BuildBase, CURRENCY_DISPLAY, CURRENCY_FLAG, DEFAULT_ROLE_PERMISSIONS, DunningState, EventEmitter, InvoiceStatuses, PLAN_CURRENCY_CODES, PLAN_CURRENCY_OPTIONS, PUSH_SERVICE_WORKER_SCRIPT, Permission, PushApi, SDKEvent, SettingsApi, SubscriptionItemType, SubscriptionStatus, UserApi, WorkspaceApi, calculateBillableSeats, calculateSeatOverageCents, calculateTotalSubscriptionCents, cleanBBParams, createBBUrl, createCheckoutRedirectUrls, BuildBase as default, eventEmitter, formatCents, formatOverageRate, formatOverageRateWithLabel, formatQuotaIncludedOverage, formatQuotaWithPrice, getAvailableCurrenciesFromPlans, getBasePriceCents, getBillingIntervalAndCurrencyFromPriceId, getCurrencyFlag, getCurrencySymbol, getDisplayCurrency, getPerSeatPriceCents, getPricingVariant, getQuotaDisplayValue, getQuotaDisplayWithVariant, getQuotaOverageCents, getQuotaUnitLabelFromName, getSeatPricing, getStripePriceIdForInterval, hasPermission, invalidateQuotaUsage, invalidateSubscription, readBBParams, resolveMaxUsers, resolvePermissions, safeRedirect, validateInvite, validateRedirectUrl };
|
|
2051
|
+
export type { BetaFormData, BetaFormResponse, BillingInterval, BuildBaseConfig, BuildBaseResult, BuildBaseSession, CheckoutResult, EventData, EventType, FeatureActions, FormatQuotaWithPriceOptions, IAllQuotaUsageResponse, IBaseApiConfig, IBasePricing, IBetaConfig, ICheckoutSessionRequest, ICheckoutSessionResponse, IEventCallbacks, IInvoice, IInvoiceListResponse, IInvoiceResponse, IOsConfig, IOsState, IPlan, IPlanGroup, IPlanGroupInfo, IPlanGroupLatestVersion, IPlanGroupResponse, IPlanGroupVersion, IPlanGroupVersionWithPlans, IPlanGroupVersionsResponse, IPlanVersion, IPlanVersionSummary, IPlanVersionWithPlan, IPricingVariant, IPublicPlanItem, IPublicPlanItemCategory, IPublicPlanVersion, IPublicPlansResponse, IQuotaByInterval, IQuotaIntervalValue, IQuotaOveragePriceIdsByInterval, IQuotaOveragesByInterval, IQuotaUsageStatus, IQuotaUsageStatusResponse, IRecordUsageRequest, IRecordUsageResponse, IStripePricesByInterval, ISubscription, ISubscriptionItem, ISubscriptionResponse, ISubscriptionUpdateRequest, ISubscriptionUpdateResponse, IUsageLogEntry, IUsageLogsQuery, IUsageLogsResponse, InviteBlockReason, InviteValidation, InvoiceActions, InvoiceStatus, MaxUsersConfig, NotificationData, NotificationEvent, NotificationResult, OnWorkspaceChangeParams, PermissionActions, PermissionContext, PermissionKey, PlanActions, PlanVersionWithPricingVariants, QuotaDisplayValue, QuotaDisplayWithOverage, RolePermissionMap, ScopedActions, SettingsActions, SubscriptionActions, SubscriptionStatusType, UsageActions, UserActions, UserCreatedEventData, UserUpdatedEventData, WorkspaceActions, WorkspaceChangedEventData, WorkspaceCreatedEventData, WorkspaceDeletedEventData, WorkspaceUpdatedEventData, WorkspaceUserAddedEventData, WorkspaceUserRemovedEventData, WorkspaceUserRoleChangedEventData };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});let e=!0;function t(t,...s){e&&function(){try{const e="undefined"!=typeof globalThis?globalThis:null;return"development"===e?.process?.env?.NODE_ENV}catch{return!1}}()&&console.error(t,...s)}async function s(e,t){try{const s=await e.json();return s?.message||s?.error||t}catch{return t}}async function r(e){const t=await e.text();if(!t)throw new Error("Empty response body");try{return JSON.parse(t)}catch(e){throw new Error(`Invalid JSON response: ${t.substring(0,100)}${t.length>100?"...":""}`)}}async function n(e,t="Request failed"){if(!e.ok){let s=t;try{const t=await r(e);s=t.message||t.error||s}catch{s=function(e,t){const s={400:"Bad Request",401:"Unauthorized - Please check your session",403:"Forbidden - You do not have permission",404:"Resource not found",500:"Internal server error",502:"Bad Gateway",503:"Service unavailable"}[e.status]||e.statusText||t;return new Error(`${t} (${e.status}: ${s})`)}(e,t).message}throw new Error(s)}try{return await r(e)}catch(e){if(e instanceof Error&&e.message.includes("Invalid JSON"))throw e;throw new Error("Failed to parse response as JSON")}}class o extends Error{constructor(e,t,s,r){super(e),this.code=t,this.context=s,this.originalError=r,this.name="SDKError","undefined"!=typeof Error&&"captureStackTrace"in Error&&Error.captureStackTrace(this,o)}}const a=new class{constructor(){this.config={enableConsoleLogging:!0,showUserNotifications:!1}}configure(t){this.config={...this.config,...t},void 0!==t.enableConsoleLogging&&function(t){void 0!==t.enableLogging&&(e=t.enableLogging)}({enableLogging:t.enableConsoleLogging})}handleError(e,s={}){if(function(e){return e instanceof Error&&("AbortError"===e.name||"ERR_CANCELED"===e.code)}(e))return;const r=e instanceof Error?e:new o("string"==typeof e?e:"An unknown error occurred","UNKNOWN_ERROR",s),n=r instanceof o?r:new o(r.message,"SDK_ERROR",s,r);if(this.config.enableConsoleLogging&&t(`[SDK Error] ${s.component||"Unknown"}:`,{message:n.message,code:n.code,context:n.context,originalError:n.originalError,stack:n.stack}),this.config.onError)try{this.config.onError(n,s)}catch(e){!function(e,...t){console.error(e,...t)}("[SDK Error Handler] Error in custom error callback:",e)}this.config.showUserNotifications&&this.notifyUser(n,s)}notifyUser(e,t){"undefined"!=typeof window&&window.dispatchEvent&&window.dispatchEvent(new CustomEvent("sdk-error",{detail:{error:e,context:t}}))}wrapAsync(e,t){return(...s)=>e(...s).catch(e=>{throw this.handleError(e,t),e})}wrapSync(e,t){return(...s)=>{try{return e(...s)}catch(e){throw this.handleError(e,t),e}}}};function i(e,t={}){a.handleError(e,t)}const c="saas-session-id";function u(){if("undefined"==typeof window)return null;try{return function(e){if("undefined"==typeof window)return null;try{return localStorage.getItem(e)}catch(t){return i(t,{component:"storage",action:"getStorageItem",metadata:{key:e}}),null}}(c)}catch(e){return i(e,{component:"auth-utils",action:"getSessionId",metadata:{key:c}}),null}}function l(){const e=u(),t={};return e&&(t["x-session-id"]=e),t}const d="SDK is not ready (missing serverUrl, version, or orgId)";class h{constructor(e){this.serverUrl=e.serverUrl,this.version=e.version,this.orgId=e.orgId,this.requireOrgId=e.requireOrgId??!1,this.basePath=e.basePath??"public",this._sessionId=e.sessionId,this._timeout=e.timeout??3e4,this._maxRetries=e.maxRetries??0,this._debug=e.debug??!1,this._customHeaders=e.headers??{},this._onError=e.onError,this._fetch=e.fetch??globalThis.fetch}ensureReady(){if(!this.serverUrl?.trim()||!this.version)throw new Error(d);if(this.requireOrgId&&!this.orgId?.trim())throw new Error(d)}get baseUrl(){return this.ensureReady(),`${this.serverUrl}/api/${this.version}/${this.basePath}`}getAuthHeaders(){return this._sessionId?{"x-session-id":this._sessionId}:l()}url(e){const t=e.startsWith("/")?e.slice(1):e;return`${this.baseUrl.endsWith("/")?this.baseUrl.slice(0,-1):this.baseUrl}/${t}`}buildHeaders(e){const t={...this._customHeaders,...this.getAuthHeaders()};return e.headers&&Object.assign(t,e.headers),null==e.body||t["Content-Type"]||(t["Content-Type"]="application/json"),t}async executeFetch(e,t){const s=this.url(e),r=(t.method??"GET").toUpperCase(),n=this.buildHeaders(t),o={...t,headers:n};let a;if(this._timeout>0){const e=new AbortController;a=setTimeout(()=>e.abort(),this._timeout),o.signal=t.signal?AbortSignal.any([t.signal,e.signal]):e.signal}const i=async t=>{try{const e=this._fetch.bind(globalThis),n=await e(s,o);if(this._debug&&console.log(`[BuildBase] ${r} ${s} → ${n.status}`),n.status>=500&&t<this._maxRetries){const e=Math.min(1e3*Math.pow(2,t),1e4);return this._debug&&console.log(`[BuildBase] Retrying in ${e}ms (attempt ${t+1}/${this._maxRetries})`),await new Promise(t=>setTimeout(t,e)),i(t+1)}return n}catch(s){if(s instanceof Error&&"AbortError"===s.name){if(void 0!==a){const t=new Error(`Request timeout after ${this._timeout}ms: ${r} ${e}`);throw this._onError?.(t,{method:r,path:e}),t}throw s}if(t<this._maxRetries){const e=Math.min(1e3*Math.pow(2,t),1e4);return this._debug&&console.log(`[BuildBase] Network error, retrying in ${e}ms (attempt ${t+1}/${this._maxRetries})`),await new Promise(t=>setTimeout(t,e)),i(t+1)}throw s instanceof Error&&this._onError?.(s,{method:r,path:e}),s}};try{return await i(0)}finally{void 0!==a&&clearTimeout(a)}}async fetchJson(e,t={},s="Request failed"){this.ensureReady();try{const r=await this.executeFetch(e,t);return await n(r,s)}catch(s){throw s instanceof Error&&this._onError?.(s,{method:(t.method??"GET").toUpperCase(),path:e}),s}}async fetchResponse(e,t={}){return this.ensureReady(),this.executeFetch(e,t)}}class p extends h{constructor(e){super({...e,basePath:"beta",requireOrgId:!0})}getAuthHeaders(){return{}}async fetchConfig(){return this.fetchJson(`config?orgId=${encodeURIComponent(this.orgId)}`,{},"Failed to fetch beta form configuration")}async submitBetaUser(e){return this.fetchJson("submit",{method:"POST",body:JSON.stringify(e)},"Failed to submit beta user request")}}class f extends h{constructor(e){super({...e,requireOrgId:!0})}async getVapidPublicKey(){return this.fetchJson("push/vapid-public-key")}async subscribe(e,t){await this.fetchJson("push/subscribe",{method:"POST",body:JSON.stringify({endpoint:e.endpoint,keys:e.keys,userAgent:t})})}async unsubscribe(e){await this.fetchJson("push/unsubscribe",{method:"DELETE",body:JSON.stringify({endpoint:e})})}}class g extends h{constructor(e){super({...e,requireOrgId:!0})}async getSettings(e){return this.fetchJson(`${this.orgId}/settings`,{signal:e},"Failed to fetch settings")}}class w extends h{constructor(e){super(e)}async getAttributes(e){const t=await this.fetchResponse("users/attributes",{signal:e});if(!t.ok)throw new Error(await s(t,"Failed to fetch user attributes"));const r=await t.json();return r&&"object"==typeof r&&!Array.isArray(r)?r:{}}async updateAttributes(e){return this.fetchJson("users/attributes",{method:"PATCH",body:JSON.stringify({attributes:e})},"Failed to update user attributes")}async updateAttribute(e,t){return this.fetchJson(`users/attributes/${e}`,{method:"PATCH",body:JSON.stringify({value:t})},"Failed to update user attribute")}async getFeatures(e){const t=await this.fetchResponse("users/features",{signal:e});if(!t.ok)throw new Error(await s(t,"Failed to fetch user features"));const r=await t.json();return"object"==typeof r&&null!==r?r:{}}}class y extends h{constructor(e){super({...e,requireOrgId:!0})}async getWorkspaces(){return this.fetchJson("workspaces",{},"Failed to fetch workspaces")}async createWorkspace(e){return this.fetchJson("workspaces",{method:"POST",body:JSON.stringify(e)},"Failed to create workspace")}async updateWorkspace(e,t){return this.fetchJson(`workspaces/${e}`,{method:"PUT",body:JSON.stringify(t)},"Failed to update workspace")}async deleteWorkspace(e){return this.fetchJson(`workspaces/${e}`,{method:"DELETE"},"Failed to delete workspace")}async getWorkspaceUsers(e){return this.fetchJson(`workspaces/${e}/users`,{},"Failed to fetch workspace users")}async addUser(e,t){return this.fetchJson(`workspaces/${e}/users/add`,{method:"POST",body:JSON.stringify(t)},"Failed to invite member")}async removeUser(e,t){return this.fetchJson(`workspaces/${e}/users/${t}`,{method:"DELETE"},"Failed to remove user")}async updateUser(e,t,s){return this.fetchJson(`workspaces/${e}/users/${t}`,{method:"PATCH",body:JSON.stringify(s)},"Failed to update user")}async getFeatures(){return this.fetchJson("workspaces/features",{},"Failed to fetch features")}async updateFeature(e,t,s){return this.fetchJson(`workspaces/${e}/features`,{method:"PATCH",body:JSON.stringify({features:{[t]:s}})},"Failed to update feature")}async getWorkspace(e){return this.fetchJson(`workspaces/${e}`,{},"Failed to fetch workspace")}async getProfile(){return this.fetchJson("profile",{},"Failed to fetch profile")}async updateUserProfile(e){return this.fetchJson("profile",{method:"PATCH",body:JSON.stringify(e)},"Failed to update user profile")}async getCurrentSubscription(e){const t=await this.fetchResponse(`workspaces/${e}/subscription`);if(!t.ok){let e="Failed to fetch subscription";try{e=(await t.json()).message||e}catch{e=404===t.status?"Workspace not found or no subscription available":401===t.status?"Unauthorized - Please check your session":`Failed to fetch subscription (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch subscription");return s.data||s}return s}async getPlanGroup(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/plan-group`);if(!t.ok){let e="Failed to fetch plan group";try{e=(await t.json()).message||e}catch{e=404===t.status?"No plan group found for this workspace":401===t.status?"Unauthorized - Please check your session":`Failed to fetch plan group (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch plan group");return s.data||s}return s}async getPlanGroupByVersion(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/plan-group?groupVersionId=${encodeURIComponent(t)}`);if(!s.ok){let e="Failed to fetch plan group version";try{e=(await s.json()).message||e}catch{e=404===s.status?"Plan group version not found":401===s.status?"Unauthorized - Please check your session":`Failed to fetch plan group version (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to fetch plan group version");return r.data||r}return r}async getPlanGroupVersions(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/plan-group/versions`);if(!t.ok){let e="Failed to fetch plan group versions";try{e=(await t.json()).message||e}catch{e=404===t.status?"No plan group versions found":401===t.status?"Unauthorized - Please check your session":`Failed to fetch plan group versions (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch plan group versions");return s.data||s}return s}async getPublicPlans(e){if(!this.orgId)throw new Error("orgId is required for getPublicPlans");const t=await this.fetchResponse(`${this.orgId}/plans/${encodeURIComponent(e)}`);if(!t.ok){let s="Failed to fetch plans";try{s=(await t.json()).message||s}catch{s=404===t.status?`Plans "${e}" not found`:`Failed to fetch plans (${t.status}: ${t.statusText})`}throw new Error(s)}const s=await t.json();if(void 0!==s.success&&!s.success)throw new Error(s.message||"Failed to fetch plans");return s.data??s}async getPlanGroupVersion(e){const t=await this.fetchResponse(`plan-group-versions/${e}`);if(!t.ok){let e="Failed to fetch plan group version";try{e=(await t.json()).message||e}catch{e=404===t.status?"Plan group version not found":401===t.status?"Unauthorized - Please check your session":`Failed to fetch plan group version (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch plan group version");return s.data||s}return s}async createCheckoutSession(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/checkout`,{method:"POST",body:JSON.stringify(t)});if(!s.ok){let e="Failed to create checkout session";try{e=(await s.json()).message||e}catch{e=`Failed to create checkout session (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to create checkout session");return r.data||r}return r}async updateSubscription(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription`,{method:"PATCH",body:JSON.stringify(t)});if(!s.ok){let e="Failed to update subscription";try{e=(await s.json()).message||e}catch{e=`Failed to update subscription (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to update subscription");return r.data?.checkoutUrl||r.checkoutUrl,r.data||r}return r.checkoutUrl,r}async createBillingPortalSession(e,t){return this.fetchJson(`workspaces/${e}/subscription/billing-portal`,{method:"POST",body:JSON.stringify(t?{returnUrl:t}:{})})}async listInvoices(e,t=10,s){const r=new URLSearchParams;r.append("limit",t.toString()),s&&r.append("starting_after",s);const n=await this.fetchResponse(`workspaces/${e}/subscription/invoices?${r.toString()}`,{});if(!n.ok){let e="Failed to fetch invoices";try{e=(await n.json()).message||e}catch{e=404===n.status?"Workspace not found or no invoices available":401===n.status?"Unauthorized - Please check your session":`Failed to fetch invoices (${n.status}: ${n.statusText})`}throw new Error(e)}const o=await n.json();if(void 0!==o.success){if(!o.success)throw new Error(o.message||"Failed to fetch invoices");return o}return o}async getInvoice(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/invoices/${t}`,{});if(!s.ok){let e="Failed to fetch invoice";try{e=(await s.json()).message||e}catch{e=404===s.status?"Invoice not found":401===s.status?"Unauthorized - Please check your session":`Failed to fetch invoice (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to fetch invoice");return r}return r}async cancelSubscriptionAtPeriodEnd(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/cancel-at-period-end`,{method:"POST"});if(!t.ok){let e="Failed to cancel subscription";try{e=(await t.json()).message||e}catch{e=404===t.status?"Subscription not found":401===t.status?"Unauthorized - Please check your session":`Failed to cancel subscription (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to cancel subscription");return s.data||s}return s}async resumeSubscription(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/resume`,{method:"POST"});if(!t.ok){let e="Failed to resume subscription";try{e=(await t.json()).message||e}catch{e=404===t.status?"Subscription not found":401===t.status?"Unauthorized - Please check your session":`Failed to resume subscription (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to resume subscription");return s.data||s}return s}async recordUsage(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/usage`,{method:"POST",body:JSON.stringify(t)});if(!s.ok){let e="Failed to record usage";try{e=(await s.json()).message||e}catch{e=`Failed to record usage (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to record usage");return r.data||r}return r}async recordUsageBatch(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/usage/batch`,{method:"POST",body:JSON.stringify(t)});if(!s.ok){let e="Failed to record batch usage";try{e=(await s.json()).message||e}catch{e=`Failed to record batch usage (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();return r.data||r}async getQuotaUsageStatus(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/usage/status?quotaSlug=${encodeURIComponent(t)}`);if(!s.ok){let e="Failed to fetch quota usage status";try{e=(await s.json()).message||e}catch{e=404===s.status?"Workspace not found or no subscription available":401===s.status?"Unauthorized - Please check your session":`Failed to fetch quota usage status (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to fetch quota usage status");return r.data||r}return r}async getAllQuotaUsage(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/usage/all`);if(!t.ok){let e="Failed to fetch all quota usage";try{e=(await t.json()).message||e}catch{e=404===t.status?"Workspace not found or no subscription available":401===t.status?"Unauthorized - Please check your session":`Failed to fetch all quota usage (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch all quota usage");return s.data||s}return s}async getUsageLogs(e,t){const s=new URLSearchParams;t?.quotaSlug&&s.append("quotaSlug",t.quotaSlug),t?.from&&s.append("from",t.from),t?.to&&s.append("to",t.to),t?.source&&s.append("source",t.source),t?.page&&s.append("page",t.page.toString()),t?.limit&&s.append("limit",t.limit.toString());const r=s.toString(),n=`workspaces/${e}/subscription/usage/logs${r?`?${r}`:""}`,o=await this.fetchResponse(n);if(!o.ok){let e="Failed to fetch usage logs";try{e=(await o.json()).message||e}catch{e=404===o.status?"Workspace not found":401===o.status?"Unauthorized - Please check your session":`Failed to fetch usage logs (${o.status}: ${o.statusText})`}throw new Error(e)}const a=await o.json();if(void 0!==a.success){if(!a.success)throw new Error(a.message||"Failed to fetch usage logs");return a.data||a}return a}}exports.ApiVersion=void 0,(exports.ApiVersion||(exports.ApiVersion={})).V1="v1";const m={UserCreated:"user:created",UserUpdated:"user:updated",WorkspaceChanged:"workspace:changed",WorkspaceUpdated:"workspace:updated",WorkspaceUserAdded:"workspace:user-added",WorkspaceUserRemoved:"workspace:user-removed",WorkspaceUserRoleChanged:"workspace:user-role-changed",WorkspaceCreated:"workspace:created",WorkspaceDeleted:"workspace:deleted"};class k{constructor(){this.callbacks=null}setCallbacks(e){this.callbacks=e}getCallbacks(){return this.callbacks}async emit(e,t){if(this.callbacks?.handleEvent)try{await this.callbacks.handleEvent(e,t)}catch(t){i(t,{component:"EventEmitter",action:"emit",metadata:{eventType:e}})}}async emitUserCreated(e){await this.emit(m.UserCreated,{user:e})}async emitUserUpdated(e,t){await this.emit(m.UserUpdated,{user:e,previousUser:t})}async emitWorkspaceChanged(e,t){await this.emit(m.WorkspaceChanged,{workspace:e,previousWorkspace:t})}async emitWorkspaceUpdated(e){await this.emit(m.WorkspaceUpdated,{workspace:e})}async emitWorkspaceUserAdded(e,t,s){await this.emit(m.WorkspaceUserAdded,{userId:e,workspace:t,role:s})}async emitWorkspaceUserRemoved(e,t,s){await this.emit(m.WorkspaceUserRemoved,{userId:e,workspace:t,role:s})}async emitWorkspaceUserRoleChanged(e,t,s,r){await this.emit(m.WorkspaceUserRoleChanged,{userId:e,workspace:t,previousRole:s,newRole:r})}async emitWorkspaceCreated(e){await this.emit(m.WorkspaceCreated,{workspace:e})}async emitWorkspaceDeleted(e){await this.emit(m.WorkspaceDeleted,{workspace:e})}}const b=new k,v=new Set;const $=new Set;const S="bb";function U(e,t){let s;try{const e=t||("undefined"!=typeof window?window.location.href:"https://localhost");s=new URL(e),s.search=""}catch{s=new URL("https://localhost")}return s.searchParams.set(S,function(e){return Object.entries(e).filter(([,e])=>null!=e&&""!==e).map(([e,t])=>`${encodeURIComponent(e)}:${encodeURIComponent(t)}`).join(",")}(e)),s.toString()}function x(e){if(!e||"string"!=typeof e)return null;try{const t=new URL(e);return"https:"===t.protocol?e:"http:"!==t.protocol||"localhost"!==t.hostname&&"127.0.0.1"!==t.hostname&&"::1"!==t.hostname?null:e}catch{return null}}const E={usd:"$",eur:"€",gbp:"£",jpy:"¥",cad:"CA$",aud:"A$",chf:"CHF",cny:"¥",hkd:"HK$",sgd:"S$",inr:"₹",mxn:"MX$",brl:"R$",nzd:"NZ$",sek:"kr",nok:"kr",dkk:"kr",pln:"zł",thb:"฿"},P={usd:"🇺🇸",eur:"🇪🇺",gbp:"🇬🇧",jpy:"🇯🇵",cad:"🇨🇦",aud:"🇦🇺",chf:"🇨🇭",cny:"🇨🇳",hkd:"🇭🇰",sgd:"🇸🇬",inr:"🇮🇳",mxn:"🇲🇽",brl:"🇧🇷",nzd:"🇳🇿",sek:"🇸🇪",nok:"🇳🇴",dkk:"🇩🇰",pln:"🇵🇱",thb:"🇹🇭"};function F(e){if(!e||!e.trim())return"";const t=e.trim().toLowerCase();return E[t]??t.toUpperCase()}const R=["usd","eur","gbp","jpy","cad","aud","chf","cny","hkd","sgd","inr","mxn","brl","nzd","sek","nok","dkk","pln","thb"],I=R.map(e=>({value:e,label:`${e.toUpperCase()} (${F(e)})`}));function C(e,t){return F(t)+(e/100).toFixed(2)}const T={unit:"unit",units:"units",included:"Included",afterThat:"after that",afterIncluded:"After included"};const O={included:"included",then:"then"};const W={Monthly:"monthly",Yearly:"yearly",Quarterly:"quarterly"};function A(e,t){const s=e.pricingVariants;if(!s?.length)return null;const r=t.toLowerCase();return s.find(e=>e.currency?.toLowerCase()===r)??null}function j(e,t,s){const r=A(e,t);if(!r?.basePricing)return null;const n=r.basePricing[s];return null!=n?n:null}function _(e,t,s,r){const n=A(e,t),o=n?.quotaOverages?.[s];if(o)return o[r]}function N(e,t){const s=A(e,t);return s?.seatPricing?.enabled?s.seatPricing:null}function L(e,t,s){const r=N(e,t);return r?.perSeat?r.perSeat[s]??null:null}function B(e,t){return Math.max(0,e-(t||0))}function J(e,t,s,r){const n=N(e,t);if(!n)return null;return B(r,n.includedSeats)*(L(e,t,s)??0)}var q;function z(e){const{serverUrl:t,orgId:s,version:r="v1",getSessionId:n,timeout:o,maxRetries:a,debug:i,headers:c,onError:u,fetch:l}=e;if(!t)throw new Error("BuildBase: serverUrl is required");if(!s)throw new Error("BuildBase: orgId is required");const d={...void 0!==o&&{timeout:o},...void 0!==a&&{maxRetries:a},...void 0!==i&&{debug:i},...c&&{headers:c},...u&&{onError:u},...l&&{fetch:l}},h=e=>{const n={serverUrl:t,version:r,orgId:s,sessionId:e,...d};return{workspace:new y(n),user:new w(n),settings:new g(n),push:new f(n)}},p=new y({serverUrl:t,version:r,orgId:s,...d}),m=e=>({workspace:{list:async()=>(await e()).workspace.getWorkspaces(),get:async t=>(await e()).workspace.getWorkspace(t),create:async t=>(await e()).workspace.createWorkspace(t),update:async(t,s)=>(await e()).workspace.updateWorkspace(t,s),delete:async t=>(await e()).workspace.deleteWorkspace(t)},users:{list:async t=>(await e()).workspace.getWorkspaceUsers(t),invite:async(t,s,r)=>(await e()).workspace.addUser(t,{email:s,role:r}),remove:async(t,s)=>(await e()).workspace.removeUser(t,s),updateRole:async(t,s,r)=>(await e()).workspace.updateUser(t,s,{role:r}),getProfile:async()=>(await e()).workspace.getProfile(),updateProfile:async t=>(await e()).workspace.updateUserProfile(t)},subscription:{get:async t=>(await e()).workspace.getCurrentSubscription(t),checkout:async(t,s)=>(await e()).workspace.createCheckoutSession(t,s),update:async(t,s)=>(await e()).workspace.updateSubscription(t,s),cancel:async t=>(await e()).workspace.cancelSubscriptionAtPeriodEnd(t),resume:async t=>(await e()).workspace.resumeSubscription(t),getBillingPortalUrl:async(t,s)=>(await e()).workspace.createBillingPortalSession(t,s)},plans:{getGroup:async t=>(await e()).workspace.getPlanGroup(t),getVersions:async t=>(await e()).workspace.getPlanGroupVersions(t),getPublic:e=>p.getPublicPlans(e),getVersion:e=>p.getPlanGroupVersion(e)},invoices:{list:async(t,s,r)=>(await e()).workspace.listInvoices(t,s,r),get:async(t,s)=>(await e()).workspace.getInvoice(t,s)},usage:{record:async(t,s)=>(await e()).workspace.recordUsage(t,s),recordBatch:async(t,s)=>(await e()).workspace.recordUsageBatch(t,s),getQuota:async(t,s)=>(await e()).workspace.getQuotaUsageStatus(t,s),getAll:async t=>(await e()).workspace.getAllQuotaUsage(t),getLogs:async(t,s)=>(await e()).workspace.getUsageLogs(t,s)},settings:{get:async()=>(await e()).settings.getSettings()},features:{list:async()=>(await e()).workspace.getFeatures(),update:async(t,s,r)=>(await e()).workspace.updateFeature(t,s,r)}}),k=m(async()=>h(await(async()=>{if(!n)throw new Error("BuildBase: getSessionId callback is required for authenticated calls. Pass it in BuildBase({ getSessionId: ... }) or use withSession(id) / client.forSession(id).");const e=await n();if(!e)throw new Error("BuildBase: Not authenticated (getSessionId returned null)");return e})()));return{auth:async()=>{if(!n)return null;const e=await n();return e?{sessionId:e}:null},withSession:e=>{const t=h(e);return m(async()=>t)},client:{forSession:h},...k}}exports.AuthStatus=void 0,(q=exports.AuthStatus||(exports.AuthStatus={})).loading="loading",q.redirecting="redirecting",q.authenticated="authenticated",q.unauthenticated="unauthenticated",q.authenticating="authenticating",exports.AuthApi=class extends h{constructor(e){super(e)}async requestAuth(e){const t=`${this.serverUrl}/api/${this.version}/auth/request`,s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!s.ok){let e="Failed to initiate authentication";try{e=(await s.json()).message||e}catch{e=`Failed to initiate authentication (${s.status}: ${s.statusText})`}throw new Error(e)}return s.json()}async getProfile(e,t){return this.fetchJson("profile",{headers:{"x-session-id":e},signal:t},"Failed to fetch user profile")}},exports.BB_PARAM=S,exports.BaseApi=h,exports.BetaForm=class{constructor(e){this.api=new p(e),this.orgId=e.orgId}async fetchConfig(){return this.api.fetchConfig()}async submitBetaUser(e){const t=e?.context??{},s=t?.country??("undefined"!=typeof navigator&&navigator.language?navigator.language.split("-")[1]:void 0),r=t?.language??("undefined"!=typeof navigator&&navigator.language?navigator.language.split("-")[0]:void 0),n=t?.timezone??("undefined"!=typeof Intl&&Intl.DateTimeFormat?Intl.DateTimeFormat().resolvedOptions().timeZone:void 0),o=t?.currency??("undefined"!=typeof Intl&&Intl.NumberFormat&&Intl.NumberFormat().resolvedOptions().currency?Intl.NumberFormat().resolvedOptions().currency:void 0);return this.api.submitBetaUser({orgId:this.orgId,formData:{...e,country:s,language:r,timezone:n,currency:o}})}},exports.BillingIntervals=W,exports.BuildBase=z,exports.CURRENCY_DISPLAY=E,exports.CURRENCY_FLAG=P,exports.DunningState={None:"none",Notified:"notified",Warning:"warning",Final:"final",Suspended:"suspended"},exports.EventEmitter=k,exports.InvoiceStatuses={Draft:"draft",Open:"open",Paid:"paid",Uncollectible:"uncollectible",Void:"void"},exports.PLAN_CURRENCY_CODES=R,exports.PLAN_CURRENCY_OPTIONS=I,exports.PUSH_SERVICE_WORKER_SCRIPT="\n// BuildBase Push Notification Service Worker\n// Place this file in your app's public directory (e.g. public/push-sw.js)\n\nself.addEventListener('push', function(event) {\n if (!event.data) return;\n\n try {\n var payload = event.data.json();\n var title = payload.title || 'Notification';\n var options = {\n body: payload.body || '',\n icon: payload.icon || undefined,\n badge: payload.icon || undefined,\n data: { url: payload.url, ...(payload.data || {}) },\n tag: 'buildbase-push-' + Date.now(),\n };\n\n event.waitUntil(\n self.registration.showNotification(title, options)\n );\n } catch (e) {\n console.error('[PushSW] Failed to show notification:', e);\n }\n});\n\nself.addEventListener('notificationclick', function(event) {\n event.notification.close();\n\n var url = event.notification.data && event.notification.data.url;\n if (url) {\n event.waitUntil(\n clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function(clientList) {\n for (var i = 0; i < clientList.length; i++) {\n var client = clientList[i];\n if (client.url === url && 'focus' in client) {\n return client.focus();\n }\n }\n if (clients.openWindow) {\n return clients.openWindow(url);\n }\n })\n );\n }\n});\n",exports.PushApi=f,exports.SDKEvent=m,exports.SettingsApi=g,exports.SubscriptionItemType={Feature:"feature",Limit:"limit",Quota:"quota"},exports.SubscriptionStatus={Active:"active",Trialing:"trialing",Canceled:"canceled",PastDue:"past_due",Paused:"paused",Incomplete:"incomplete",Unpaid:"unpaid"},exports.UserApi=w,exports.WorkspaceApi=y,exports.calculateBillableSeats=B,exports.calculateSeatOverageCents=J,exports.calculateTotalSubscriptionCents=function(e,t,s,r){const n=j(e,t,s);return null===n?null:void 0===r?n:n+(J(e,t,s,r)??0)},exports.cleanBBParams=function(){if("undefined"!=typeof window)try{const e=new URL(window.location.href);e.searchParams.has(S)&&(e.searchParams.delete(S),window.history.replaceState({},"",e.toString()))}catch{}},exports.createBBUrl=U,exports.createCheckoutRedirectUrls=function(e,t){const s=t||("undefined"!=typeof window?window.location.href:void 0);return{successUrl:U({action:"checkout",status:"success",ws:e,screen:"subscription"},s),cancelUrl:U({action:"checkout",status:"cancel",ws:e,screen:"subscription"},s)}},exports.default=z,exports.eventEmitter=b,exports.formatCents=C,exports.formatOverageRate=function(e,t,s,r){if(null==e||e<0)return null;const n={...T,...r},o=null!=t&&t>=1?t:1,a=F(s),i=(e/100).toFixed(2);return 1===o?`${a}${i}/${n.unit}`:`${a}${i}/${o.toLocaleString()} ${n.units}`},exports.formatOverageRateWithLabel=function(e,t,s,r,n,o){if(null==e||e<0)return null;const a={...T,...o},i=null!=t&&t>=1?t:1,c=F(r),u=(e/100).toFixed(2);if(s){const e=n??(s.endsWith("s")?s:`${s}s`);return i>=2?`${c}${u}/${i.toLocaleString()} ${e}`:`${c}${u}/${s}`}return 1===i?`${c}${u}/${a.unit}`:`${c}${u}/${i.toLocaleString()} ${a.units}`},exports.formatQuotaIncludedOverage=function(e,t,s,r,n,o,a){const i={...T,...a},c=o??(s.endsWith("s")?s:`${s}s`),u=null!=n&&n>=2?`${n.toLocaleString()} ${c}`:s;return null!=e&&null!=t?`${i.included}: ${e.toLocaleString()}, ${i.afterThat} ${C(t,r)}/${u}`:null!=e?`${i.included}: ${e.toLocaleString()}`:null!=t?`${i.afterIncluded}: ${C(t,r)}/${u}`:"—"},exports.formatQuotaWithPrice=function(e,t,s={}){const{overageInCents:r=!0,currency:n}=s,o=s.labels??O,a=s.currencySymbol??F(n??"");if(null==e)return"—";const{included:i,overage:c}=e,u=`${i} ${o.included}`;if(null==c)return u;const l=r?c/100:c,d="number"==typeof l&&Number.isFinite(l)?l.toFixed(2):String(c),h=t&&"unitSize"in e&&null!=e.unitSize&&e.unitSize>0?` / ${e.unitSize.toLocaleString()} ${t}`:t?` / ${t}`:"";return`${u}, ${o.then} ${a}${d}${h}`},exports.getAvailableCurrenciesFromPlans=function(e){const t=new Set;for(const s of e)s.pricingVariants?.forEach(e=>{e.currency&&t.add(e.currency.toLowerCase())});return Array.from(t).sort()},exports.getBasePriceCents=j,exports.getBillingIntervalAndCurrencyFromPriceId=function(e,t){if(!e)return null;for(const s of t){const t=s.pricingVariants;if(t?.length)for(const s of t){const t=s.stripePrices;if(t){if(t.monthlyPriceId===e||t.monthly===e)return{interval:"monthly",currency:s.currency};if(t.yearlyPriceId===e||t.yearly===e)return{interval:"yearly",currency:s.currency};if(t.quarterlyPriceId===e)return{interval:"quarterly",currency:s.currency}}}}return null},exports.getCurrencyFlag=function(e){return e&&e.trim()?P[e.trim().toLowerCase()]??"":""},exports.getCurrencySymbol=F,exports.getDisplayCurrency=function(e,t){const s=A(e,t);return s?s.currency:e.plan?.currency??""},exports.getPerSeatPriceCents=L,exports.getPricingVariant=A,exports.getQuotaDisplayValue=function(e,t){if(null==e)return null;const s=e[t??"monthly"];return s?{included:s.included,...void 0!==s.overage&&{overage:s.overage},...void 0!==s.unitSize&&{unitSize:s.unitSize}}:null},exports.getQuotaDisplayWithVariant=function(e,t,s,r){const n=e.quotas?.[s];if(null==n)return null;const o=n[r];if(!o)return null;const a=_(e,t,s,r);return{included:o.included,...void 0!==o.unitSize&&{unitSize:o.unitSize},...void 0!==a&&{overage:a}}},exports.getQuotaOverageCents=_,exports.getQuotaUnitLabelFromName=function(e,t="unit"){const s=(e||"").trim().toLowerCase();if(!s)return t;const r=s.split(/\s+/)[0]??s;return new Set(["series","species","status","analysis","basis","bus","campus","corpus","axis"]).has(r)?r:r.endsWith("ies")&&r.length>3?r.slice(0,-3)+"y":r.endsWith("ses")||r.endsWith("xes")||r.endsWith("zes")||r.endsWith("ches")||r.endsWith("shes")?r.slice(0,-2):r.endsWith("s")&&!r.endsWith("ss")&&r.length>1?r.slice(0,-1):r||t},exports.getSeatPricing=N,exports.getStripePriceIdForInterval=function(e,t,s){const r=A(e,t);if(!r?.stripePrices)return null;const n=s===W.Monthly?"monthlyPriceId":s===W.Yearly?"yearlyPriceId":"quarterlyPriceId",o=s===W.Monthly?"monthly":s===W.Yearly?"yearly":void 0;return r.stripePrices[n]??(o?r.stripePrices[o]:void 0)??null},exports.invalidateQuotaUsage=function(){$.forEach(e=>e())},exports.invalidateSubscription=function(){v.forEach(e=>e())},exports.readBBParams=function(){if("undefined"==typeof window)return null;try{const e=new URLSearchParams(window.location.search).get(S);if(!e)return null;const t=function(e){const t={};if(!e)return t;const s=e.split(",");for(const e of s){const s=e.indexOf(":");if(-1===s)continue;const r=decodeURIComponent(e.slice(0,s)),n=decodeURIComponent(e.slice(s+1));r&&(t[r]=n)}return t}(e);return Object.keys(t).length>0?t:null}catch{return null}},exports.resolveMaxUsers=function(e){const{planVersion:t,currency:s="usd",settingsMaxUsers:r}=e;if(t){const e=N(t,s);if(e)return{maxUsers:e.maxSeats??0,source:"seat_pricing",includedSeats:e.includedSeats??0,hasSeatPricing:!0}}return null!=r&&r>0?{maxUsers:r,source:"settings",includedSeats:0,hasSeatPricing:!1}:{maxUsers:0,source:"none",includedSeats:0,hasSeatPricing:!1}},exports.safeRedirect=function(e,t="/"){const s=x(e);window.location.href=s||t},exports.validateInvite=function(e){const{memberCount:t,maxUsersConfig:s,hasSubscription:r=!0,requireSubscription:n=!1}=e;if(n&&!r)return{canInvite:!1,blockReason:"no_subscription",blockMessageKey:"users.subscriptionRequired",blockMessageValues:{}};const{maxUsers:o,source:a}=s;if(o<=0)return{canInvite:!0,blockReason:null,blockMessageKey:null,blockMessageValues:null};if(t>=o){return{canInvite:!1,blockReason:{seat_pricing:"seat_limit_reached",settings:"settings_user_limit_reached"}[a]??"seat_limit_reached",blockMessageKey:{seat_pricing:"users.seatLimitMessage",settings:"users.settingsLimitMessage"}[a]??"users.memberLimitMessage",blockMessageValues:{maxUsers:o}}}return{canInvite:!0,blockReason:null,blockMessageKey:null,blockMessageValues:null}},exports.validateRedirectUrl=x;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});let e=!0;function t(t,...s){e&&function(){try{const e="undefined"!=typeof globalThis?globalThis:null;return"development"===e?.process?.env?.NODE_ENV}catch{return!1}}()&&console.error(t,...s)}async function s(e,t){try{const s=await e.json();return s?.message||s?.error||t}catch{return t}}async function r(e){const t=await e.text();if(!t)throw new Error("Empty response body");try{return JSON.parse(t)}catch(e){throw new Error(`Invalid JSON response: ${t.substring(0,100)}${t.length>100?"...":""}`)}}async function n(e,t="Request failed"){if(!e.ok){let s=t;try{const t=await r(e);s=t.message||t.error||s}catch{s=function(e,t){const s={400:"Bad Request",401:"Unauthorized - Please check your session",403:"Forbidden - You do not have permission",404:"Resource not found",500:"Internal server error",502:"Bad Gateway",503:"Service unavailable"}[e.status]||e.statusText||t;return new Error(`${t} (${e.status}: ${s})`)}(e,t).message}throw new Error(s)}try{return await r(e)}catch(e){if(e instanceof Error&&e.message.includes("Invalid JSON"))throw e;throw new Error("Failed to parse response as JSON")}}class o extends Error{constructor(e,t,s,r){super(e),this.code=t,this.context=s,this.originalError=r,this.name="SDKError","undefined"!=typeof Error&&"captureStackTrace"in Error&&Error.captureStackTrace(this,o)}}const a=new class{constructor(){this.config={enableConsoleLogging:!0,showUserNotifications:!1}}configure(t){this.config={...this.config,...t},void 0!==t.enableConsoleLogging&&function(t){void 0!==t.enableLogging&&(e=t.enableLogging)}({enableLogging:t.enableConsoleLogging})}handleError(e,s={}){if(function(e){return e instanceof Error&&("AbortError"===e.name||"ERR_CANCELED"===e.code)}(e))return;const r=e instanceof Error?e:new o("string"==typeof e?e:"An unknown error occurred","UNKNOWN_ERROR",s),n=r instanceof o?r:new o(r.message,"SDK_ERROR",s,r);if(this.config.enableConsoleLogging&&t(`[SDK Error] ${s.component||"Unknown"}:`,{message:n.message,code:n.code,context:n.context,originalError:n.originalError,stack:n.stack}),this.config.onError)try{this.config.onError(n,s)}catch(e){!function(e,...t){console.error(e,...t)}("[SDK Error Handler] Error in custom error callback:",e)}this.config.showUserNotifications&&this.notifyUser(n,s)}notifyUser(e,t){"undefined"!=typeof window&&window.dispatchEvent&&window.dispatchEvent(new CustomEvent("sdk-error",{detail:{error:e,context:t}}))}wrapAsync(e,t){return(...s)=>e(...s).catch(e=>{throw this.handleError(e,t),e})}wrapSync(e,t){return(...s)=>{try{return e(...s)}catch(e){throw this.handleError(e,t),e}}}};function i(e,t={}){a.handleError(e,t)}const c="saas-session-id";function u(){if("undefined"==typeof window)return null;try{return function(e){if("undefined"==typeof window)return null;try{return localStorage.getItem(e)}catch(t){return i(t,{component:"storage",action:"getStorageItem",metadata:{key:e}}),null}}(c)}catch(e){return i(e,{component:"auth-utils",action:"getSessionId",metadata:{key:c}}),null}}function l(){const e=u(),t={};return e&&(t["x-session-id"]=e),t}const d="SDK is not ready (missing serverUrl, version, or orgId)";class p{constructor(e){this.serverUrl=e.serverUrl,this.version=e.version,this.orgId=e.orgId,this.requireOrgId=e.requireOrgId??!1,this.basePath=e.basePath??"public",this._sessionId=e.sessionId,this._timeout=e.timeout??3e4,this._maxRetries=e.maxRetries??0,this._debug=e.debug??!1,this._customHeaders=e.headers??{},this._onError=e.onError,this._fetch=e.fetch??globalThis.fetch}ensureReady(){if(!this.serverUrl?.trim()||!this.version)throw new Error(d);if(this.requireOrgId&&!this.orgId?.trim())throw new Error(d)}get baseUrl(){return this.ensureReady(),`${this.serverUrl}/api/${this.version}/${this.basePath}`}getAuthHeaders(){return this._sessionId?{"x-session-id":this._sessionId}:l()}url(e){const t=e.startsWith("/")?e.slice(1):e;return`${this.baseUrl.endsWith("/")?this.baseUrl.slice(0,-1):this.baseUrl}/${t}`}buildHeaders(e){const t={...this._customHeaders,...this.getAuthHeaders()};return e.headers&&Object.assign(t,e.headers),null==e.body||t["Content-Type"]||(t["Content-Type"]="application/json"),t}async executeFetch(e,t){const s=this.url(e),r=(t.method??"GET").toUpperCase(),n=this.buildHeaders(t),o={...t,headers:n};let a;if(this._timeout>0){const e=new AbortController;a=setTimeout(()=>e.abort(),this._timeout),o.signal=t.signal?AbortSignal.any([t.signal,e.signal]):e.signal}const i=async t=>{try{const e=this._fetch.bind(globalThis),n=await e(s,o);if(this._debug&&console.log(`[BuildBase] ${r} ${s} → ${n.status}`),n.status>=500&&t<this._maxRetries){const e=Math.min(1e3*Math.pow(2,t),1e4);return this._debug&&console.log(`[BuildBase] Retrying in ${e}ms (attempt ${t+1}/${this._maxRetries})`),await new Promise(t=>setTimeout(t,e)),i(t+1)}return n}catch(s){if(s instanceof Error&&"AbortError"===s.name){if(void 0!==a){const t=new Error(`Request timeout after ${this._timeout}ms: ${r} ${e}`);throw this._onError?.(t,{method:r,path:e}),t}throw s}if(t<this._maxRetries){const e=Math.min(1e3*Math.pow(2,t),1e4);return this._debug&&console.log(`[BuildBase] Network error, retrying in ${e}ms (attempt ${t+1}/${this._maxRetries})`),await new Promise(t=>setTimeout(t,e)),i(t+1)}throw s instanceof Error&&this._onError?.(s,{method:r,path:e}),s}};try{return await i(0)}finally{void 0!==a&&clearTimeout(a)}}async fetchJson(e,t={},s="Request failed"){this.ensureReady();try{const r=await this.executeFetch(e,t);return await n(r,s)}catch(s){throw s instanceof Error&&this._onError?.(s,{method:(t.method??"GET").toUpperCase(),path:e}),s}}async fetchResponse(e,t={}){return this.ensureReady(),this.executeFetch(e,t)}}class h extends p{constructor(e){super({...e,basePath:"beta",requireOrgId:!0})}getAuthHeaders(){return{}}async fetchConfig(){return this.fetchJson(`config?orgId=${encodeURIComponent(this.orgId)}`,{},"Failed to fetch beta form configuration")}async submitBetaUser(e){return this.fetchJson("submit",{method:"POST",body:JSON.stringify(e)},"Failed to submit beta user request")}}class f extends p{constructor(e){super({...e,requireOrgId:!0})}async getVapidPublicKey(){return this.fetchJson("push/vapid-public-key")}async subscribe(e,t){await this.fetchJson("push/subscribe",{method:"POST",body:JSON.stringify({endpoint:e.endpoint,keys:e.keys,userAgent:t})})}async unsubscribe(e){await this.fetchJson("push/unsubscribe",{method:"DELETE",body:JSON.stringify({endpoint:e})})}}class g extends p{constructor(e){super({...e,requireOrgId:!0})}async getSettings(e){return this.fetchJson(`${this.orgId}/settings`,{signal:e},"Failed to fetch settings")}}class w extends p{constructor(e){super(e)}async getAttributes(e){const t=await this.fetchResponse("users/attributes",{signal:e});if(!t.ok)throw new Error(await s(t,"Failed to fetch user attributes"));const r=await t.json();return r&&"object"==typeof r&&!Array.isArray(r)?r:{}}async updateAttributes(e){return this.fetchJson("users/attributes",{method:"PATCH",body:JSON.stringify({attributes:e})},"Failed to update user attributes")}async updateAttribute(e,t){return this.fetchJson(`users/attributes/${e}`,{method:"PATCH",body:JSON.stringify({value:t})},"Failed to update user attribute")}async getFeatures(e){const t=await this.fetchResponse("users/features",{signal:e});if(!t.ok)throw new Error(await s(t,"Failed to fetch user features"));const r=await t.json();return"object"==typeof r&&null!==r?r:{}}}class y extends p{constructor(e){super({...e,requireOrgId:!0})}async getWorkspaces(){return this.fetchJson("workspaces",{},"Failed to fetch workspaces")}async createWorkspace(e){return this.fetchJson("workspaces",{method:"POST",body:JSON.stringify(e)},"Failed to create workspace")}async updateWorkspace(e,t){return this.fetchJson(`workspaces/${e}`,{method:"PUT",body:JSON.stringify(t)},"Failed to update workspace")}async deleteWorkspace(e){return this.fetchJson(`workspaces/${e}`,{method:"DELETE"},"Failed to delete workspace")}async getWorkspaceUsers(e){return this.fetchJson(`workspaces/${e}/users`,{},"Failed to fetch workspace users")}async addUser(e,t){return this.fetchJson(`workspaces/${e}/users/add`,{method:"POST",body:JSON.stringify(t)},"Failed to invite member")}async removeUser(e,t){return this.fetchJson(`workspaces/${e}/users/${t}`,{method:"DELETE"},"Failed to remove user")}async updateUser(e,t,s){return this.fetchJson(`workspaces/${e}/users/${t}`,{method:"PATCH",body:JSON.stringify(s)},"Failed to update user")}async updateSettings(e){return this.fetchJson("workspaces/settings",{method:"PATCH",body:JSON.stringify(e)},"Failed to update workspace settings")}async updateWorkspacePermissions(e,t){return this.fetchJson(`workspaces/${e}/permissions`,{method:"PATCH",body:JSON.stringify({permissions:t})},"Failed to update workspace permissions")}async getFeatures(){return this.fetchJson("workspaces/features",{},"Failed to fetch features")}async updateFeature(e,t,s){return this.fetchJson(`workspaces/${e}/features`,{method:"PATCH",body:JSON.stringify({features:{[t]:s}})},"Failed to update feature")}async getWorkspace(e){return this.fetchJson(`workspaces/${e}`,{},"Failed to fetch workspace")}async getProfile(){return this.fetchJson("profile",{},"Failed to fetch profile")}async updateUserProfile(e){return this.fetchJson("profile",{method:"PATCH",body:JSON.stringify(e)},"Failed to update user profile")}async getCurrentSubscription(e){const t=await this.fetchResponse(`workspaces/${e}/subscription`);if(!t.ok){let e="Failed to fetch subscription";try{e=(await t.json()).message||e}catch{e=404===t.status?"Workspace not found or no subscription available":401===t.status?"Unauthorized - Please check your session":`Failed to fetch subscription (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch subscription");return s.data||s}return s}async getPlanGroup(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/plan-group`);if(!t.ok){let e="Failed to fetch plan group";try{e=(await t.json()).message||e}catch{e=404===t.status?"No plan group found for this workspace":401===t.status?"Unauthorized - Please check your session":`Failed to fetch plan group (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch plan group");return s.data||s}return s}async getPlanGroupByVersion(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/plan-group?groupVersionId=${encodeURIComponent(t)}`);if(!s.ok){let e="Failed to fetch plan group version";try{e=(await s.json()).message||e}catch{e=404===s.status?"Plan group version not found":401===s.status?"Unauthorized - Please check your session":`Failed to fetch plan group version (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to fetch plan group version");return r.data||r}return r}async getPlanGroupVersions(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/plan-group/versions`);if(!t.ok){let e="Failed to fetch plan group versions";try{e=(await t.json()).message||e}catch{e=404===t.status?"No plan group versions found":401===t.status?"Unauthorized - Please check your session":`Failed to fetch plan group versions (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch plan group versions");return s.data||s}return s}async getPublicPlans(e){if(!this.orgId)throw new Error("orgId is required for getPublicPlans");const t=await this.fetchResponse(`${this.orgId}/plans/${encodeURIComponent(e)}`);if(!t.ok){let s="Failed to fetch plans";try{s=(await t.json()).message||s}catch{s=404===t.status?`Plans "${e}" not found`:`Failed to fetch plans (${t.status}: ${t.statusText})`}throw new Error(s)}const s=await t.json();if(void 0!==s.success&&!s.success)throw new Error(s.message||"Failed to fetch plans");return s.data??s}async getPlanGroupVersion(e){const t=await this.fetchResponse(`plan-group-versions/${e}`);if(!t.ok){let e="Failed to fetch plan group version";try{e=(await t.json()).message||e}catch{e=404===t.status?"Plan group version not found":401===t.status?"Unauthorized - Please check your session":`Failed to fetch plan group version (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch plan group version");return s.data||s}return s}async createCheckoutSession(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/checkout`,{method:"POST",body:JSON.stringify(t)});if(!s.ok){let e="Failed to create checkout session";try{e=(await s.json()).message||e}catch{e=`Failed to create checkout session (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to create checkout session");return r.data||r}return r}async updateSubscription(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription`,{method:"PATCH",body:JSON.stringify(t)});if(!s.ok){let e="Failed to update subscription";try{e=(await s.json()).message||e}catch{e=`Failed to update subscription (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to update subscription");return r.data?.checkoutUrl||r.checkoutUrl,r.data||r}return r.checkoutUrl,r}async createBillingPortalSession(e,t){return this.fetchJson(`workspaces/${e}/subscription/billing-portal`,{method:"POST",body:JSON.stringify(t?{returnUrl:t}:{})})}async listInvoices(e,t=10,s){const r=new URLSearchParams;r.append("limit",t.toString()),s&&r.append("starting_after",s);const n=await this.fetchResponse(`workspaces/${e}/subscription/invoices?${r.toString()}`,{});if(!n.ok){let e="Failed to fetch invoices";try{e=(await n.json()).message||e}catch{e=404===n.status?"Workspace not found or no invoices available":401===n.status?"Unauthorized - Please check your session":`Failed to fetch invoices (${n.status}: ${n.statusText})`}throw new Error(e)}const o=await n.json();if(void 0!==o.success){if(!o.success)throw new Error(o.message||"Failed to fetch invoices");return o}return o}async getInvoice(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/invoices/${t}`,{});if(!s.ok){let e="Failed to fetch invoice";try{e=(await s.json()).message||e}catch{e=404===s.status?"Invoice not found":401===s.status?"Unauthorized - Please check your session":`Failed to fetch invoice (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to fetch invoice");return r}return r}async cancelSubscriptionAtPeriodEnd(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/cancel-at-period-end`,{method:"POST"});if(!t.ok){let e="Failed to cancel subscription";try{e=(await t.json()).message||e}catch{e=404===t.status?"Subscription not found":401===t.status?"Unauthorized - Please check your session":`Failed to cancel subscription (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to cancel subscription");return s.data||s}return s}async resumeSubscription(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/resume`,{method:"POST"});if(!t.ok){let e="Failed to resume subscription";try{e=(await t.json()).message||e}catch{e=404===t.status?"Subscription not found":401===t.status?"Unauthorized - Please check your session":`Failed to resume subscription (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to resume subscription");return s.data||s}return s}async recordUsage(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/usage`,{method:"POST",body:JSON.stringify(t)});if(!s.ok){let e="Failed to record usage";try{e=(await s.json()).message||e}catch{e=`Failed to record usage (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to record usage");return r.data||r}return r}async recordUsageBatch(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/usage/batch`,{method:"POST",body:JSON.stringify(t)});if(!s.ok){let e="Failed to record batch usage";try{e=(await s.json()).message||e}catch{e=`Failed to record batch usage (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();return r.data||r}async getQuotaUsageStatus(e,t){const s=await this.fetchResponse(`workspaces/${e}/subscription/usage/status?quotaSlug=${encodeURIComponent(t)}`);if(!s.ok){let e="Failed to fetch quota usage status";try{e=(await s.json()).message||e}catch{e=404===s.status?"Workspace not found or no subscription available":401===s.status?"Unauthorized - Please check your session":`Failed to fetch quota usage status (${s.status}: ${s.statusText})`}throw new Error(e)}const r=await s.json();if(void 0!==r.success){if(!r.success)throw new Error(r.message||"Failed to fetch quota usage status");return r.data||r}return r}async getAllQuotaUsage(e){const t=await this.fetchResponse(`workspaces/${e}/subscription/usage/all`);if(!t.ok){let e="Failed to fetch all quota usage";try{e=(await t.json()).message||e}catch{e=404===t.status?"Workspace not found or no subscription available":401===t.status?"Unauthorized - Please check your session":`Failed to fetch all quota usage (${t.status}: ${t.statusText})`}throw new Error(e)}const s=await t.json();if(void 0!==s.success){if(!s.success)throw new Error(s.message||"Failed to fetch all quota usage");return s.data||s}return s}async getUsageLogs(e,t){const s=new URLSearchParams;t?.quotaSlug&&s.append("quotaSlug",t.quotaSlug),t?.from&&s.append("from",t.from),t?.to&&s.append("to",t.to),t?.source&&s.append("source",t.source),t?.page&&s.append("page",t.page.toString()),t?.limit&&s.append("limit",t.limit.toString());const r=s.toString(),n=`workspaces/${e}/subscription/usage/logs${r?`?${r}`:""}`,o=await this.fetchResponse(n);if(!o.ok){let e="Failed to fetch usage logs";try{e=(await o.json()).message||e}catch{e=404===o.status?"Workspace not found":401===o.status?"Unauthorized - Please check your session":`Failed to fetch usage logs (${o.status}: ${o.statusText})`}throw new Error(e)}const a=await o.json();if(void 0!==a.success){if(!a.success)throw new Error(a.message||"Failed to fetch usage logs");return a.data||a}return a}async sendNotification(e,t,s,r){const n={event:t};return s&&(n.userId=s),r&&(n.data=r),this.fetchJson(`workspaces/${e}/notifications/send`,{method:"POST",body:JSON.stringify(n)},"Failed to send notification")}async getNotificationEvents(e){return this.fetchJson(`workspaces/${e}/notification-events`,{},"Failed to fetch notification events")}async getNotificationPreferences(e){return(await this.fetchJson(`workspaces/${e}/notification-preferences`,{},"Failed to fetch notification preferences")).notificationPreferences??{}}async updateNotificationPreferences(e,t){return(await this.fetchJson(`workspaces/${e}/notification-preferences`,{method:"PATCH",body:JSON.stringify({notificationPreferences:t})},"Failed to update notification preferences")).notificationPreferences??{}}}exports.ApiVersion=void 0,(exports.ApiVersion||(exports.ApiVersion={})).V1="v1";const m={UserCreated:"user:created",UserUpdated:"user:updated",WorkspaceChanged:"workspace:changed",WorkspaceUpdated:"workspace:updated",WorkspaceUserAdded:"workspace:user-added",WorkspaceUserRemoved:"workspace:user-removed",WorkspaceUserRoleChanged:"workspace:user-role-changed",WorkspaceCreated:"workspace:created",WorkspaceDeleted:"workspace:deleted"};class k{constructor(){this.callbacks=null}setCallbacks(e){this.callbacks=e}getCallbacks(){return this.callbacks}async emit(e,t){if(this.callbacks?.handleEvent)try{await this.callbacks.handleEvent(e,t)}catch(t){i(t,{component:"EventEmitter",action:"emit",metadata:{eventType:e}})}}async emitUserCreated(e){await this.emit(m.UserCreated,{user:e})}async emitUserUpdated(e,t){await this.emit(m.UserUpdated,{user:e,previousUser:t})}async emitWorkspaceChanged(e,t){await this.emit(m.WorkspaceChanged,{workspace:e,previousWorkspace:t})}async emitWorkspaceUpdated(e){await this.emit(m.WorkspaceUpdated,{workspace:e})}async emitWorkspaceUserAdded(e,t,s){await this.emit(m.WorkspaceUserAdded,{userId:e,workspace:t,role:s})}async emitWorkspaceUserRemoved(e,t,s){await this.emit(m.WorkspaceUserRemoved,{userId:e,workspace:t,role:s})}async emitWorkspaceUserRoleChanged(e,t,s,r){await this.emit(m.WorkspaceUserRoleChanged,{userId:e,workspace:t,previousRole:s,newRole:r})}async emitWorkspaceCreated(e){await this.emit(m.WorkspaceCreated,{workspace:e})}async emitWorkspaceDeleted(e){await this.emit(m.WorkspaceDeleted,{workspace:e})}}const b=new k,S=new Set;const v=new Set;const E="bb";function $(e,t){let s;try{const e=t||("undefined"!=typeof window?window.location.href:"https://localhost");s=new URL(e),s.search=""}catch{s=new URL("https://localhost")}return s.searchParams.set(E,function(e){return Object.entries(e).filter(([,e])=>null!=e&&""!==e).map(([e,t])=>`${encodeURIComponent(e)}:${encodeURIComponent(t)}`).join(",")}(e)),s.toString()}function P(e){if(!e||"string"!=typeof e)return null;try{const t=new URL(e);return"https:"===t.protocol?e:"http:"!==t.protocol||"localhost"!==t.hostname&&"127.0.0.1"!==t.hostname&&"::1"!==t.hostname?null:e}catch{return null}}const U={usd:"$",eur:"€",gbp:"£",jpy:"¥",cad:"CA$",aud:"A$",chf:"CHF",cny:"¥",hkd:"HK$",sgd:"S$",inr:"₹",mxn:"MX$",brl:"R$",nzd:"NZ$",sek:"kr",nok:"kr",dkk:"kr",pln:"zł",thb:"฿"},R={usd:"🇺🇸",eur:"🇪🇺",gbp:"🇬🇧",jpy:"🇯🇵",cad:"🇨🇦",aud:"🇦🇺",chf:"🇨🇭",cny:"🇨🇳",hkd:"🇭🇰",sgd:"🇸🇬",inr:"🇮🇳",mxn:"🇲🇽",brl:"🇧🇷",nzd:"🇳🇿",sek:"🇸🇪",nok:"🇳🇴",dkk:"🇩🇰",pln:"🇵🇱",thb:"🇹🇭"};function x(e){if(!e||!e.trim())return"";const t=e.trim().toLowerCase();return U[t]??t.toUpperCase()}const I=["usd","eur","gbp","jpy","cad","aud","chf","cny","hkd","sgd","inr","mxn","brl","nzd","sek","nok","dkk","pln","thb"],F=I.map(e=>({value:e,label:`${e.toUpperCase()} (${x(e)})`}));function C(e,t){return x(t)+(e/100).toFixed(2)}const _={unit:"unit",units:"units",included:"Included",afterThat:"after that",afterIncluded:"After included"};const W={included:"included",then:"then"};const A={Monthly:"monthly",Yearly:"yearly",Quarterly:"quarterly"};function O(e,t){const s=e.pricingVariants;if(!s?.length)return null;const r=t.toLowerCase();return s.find(e=>e.currency?.toLowerCase()===r)??null}function T(e,t,s){const r=O(e,t);if(!r?.basePricing)return null;const n=r.basePricing[s];return null!=n?n:null}function N(e,t,s,r){const n=O(e,t),o=n?.quotaOverages?.[s];if(o)return o[r]}function L(e,t){const s=O(e,t);return s?.seatPricing?.enabled?s.seatPricing:null}function j(e,t,s){const r=L(e,t);return r?.perSeat?r.perSeat[s]??null:null}function B(e,t){return Math.max(0,e-(t||0))}function J(e,t,s,r){const n=L(e,t);if(!n)return null;return B(r,n.includedSeats)*(j(e,t,s)??0)}const M={WORKSPACE_SETTINGS_VIEW:"workspace:settings:view",WORKSPACE_SETTINGS_EDIT:"workspace:settings:edit",WORKSPACE_DELETE:"workspace:delete",WORKSPACE_MEMBERS_VIEW:"workspace:members:view",WORKSPACE_MEMBERS_INVITE:"workspace:members:invite",WORKSPACE_MEMBERS_REMOVE:"workspace:members:remove",WORKSPACE_MEMBERS_ROLE_CHANGE:"workspace:members:role-change",WORKSPACE_FEATURES_VIEW:"workspace:features:view",WORKSPACE_FEATURES_EDIT:"workspace:features:edit",WORKSPACE_BILLING_VIEW:"workspace:billing:view",WORKSPACE_BILLING_MANAGE:"workspace:billing:manage",WORKSPACE_USAGE_VIEW:"workspace:usage:view"},V=Object.values(M),q={admin:V.filter(e=>e!==M.WORKSPACE_DELETE),member:[M.WORKSPACE_SETTINGS_VIEW,M.WORKSPACE_MEMBERS_VIEW,M.WORKSPACE_FEATURES_VIEW,M.WORKSPACE_BILLING_VIEW,M.WORKSPACE_USAGE_VIEW],viewer:[M.WORKSPACE_SETTINGS_VIEW,M.WORKSPACE_MEMBERS_VIEW]};function K(e){const t=new Set;for(const s of Object.values(e))for(const e of s)t.add(e);return Array.from(t)}function D(e){const{userId:t,workspace:s,settings:r,appPermissions:n}=e;if(!s||!t)return new Set;if(function(e,t){if(!t)return!1;const s=(r=e.createdBy)?"string"==typeof r?r:"object"==typeof r&&"_id"in r&&"string"==typeof r._id?r._id:null:null;var r;return null!==s&&s===t}(s,t)){const e=new Set(V);if(n)for(const t of K(n))e.add(t);if(s.permissions)for(const t of K(s.permissions))e.add(t);if(r?.workspace?.permissions)for(const t of K(r.workspace.permissions))e.add(t);return e}const o=e.workspaceRole??function(e,t){if(!t||!e.users||!Array.isArray(e.users))return null;const s=e.users.find(e=>"string"==typeof e?e===t:"object"==typeof e&&null!==e&&"_id"in e&&e._id===t);return s&&"object"==typeof s&&"role"in s&&"string"==typeof s.role?s.role:null}(s,t);if(!o)return new Set;const a=s.permissions,i=r?.workspace?.permissions,c=e=>e.filter(e=>e.startsWith("workspace:")),u=e=>e.filter(e=>!e.startsWith("workspace:")),l=a?.[o]?c(a[o]):[],d=i?.[o]?c(i[o]):[],p=q[o]??[];let h;if(l.length>0)h=l;else if(d.length>0)h=d;else if(p.length>0)h=p;else{h=q[r?.workspace?.defaultRole??"member"]??q.member??[]}const f=new Set(h),g=a?.[o]?u(a[o]):[],w=n?.[o]?u(n[o]):[],y=g.length>0?g:w;for(const e of y)f.add(e);return function(e,t,s){if(!s?.workspace)return;const{canInviteMembers:r}=s.workspace;(!1===r||"admin-only"===r&&"admin"!==t)&&e.delete(M.WORKSPACE_MEMBERS_INVITE)}(f,o,r),f}function z(e,t){const s=D(t);return Array.isArray(e)?e.every(e=>s.has(e)):s.has(e)}var G;function H(e){const{serverUrl:t,orgId:s,version:r="v1",getSessionId:n,timeout:o,maxRetries:a,debug:i,headers:c,onError:u,fetch:l}=e;if(!t)throw new Error("BuildBase: serverUrl is required");if(!s)throw new Error("BuildBase: orgId is required");const d={...void 0!==o&&{timeout:o},...void 0!==a&&{maxRetries:a},...void 0!==i&&{debug:i},...c&&{headers:c},...u&&{onError:u},...l&&{fetch:l}},p=e=>{const n={serverUrl:t,version:r,orgId:s,sessionId:e,...d};return{workspace:new y(n),user:new w(n),settings:new g(n),push:new f(n)}},h=new y({serverUrl:t,version:r,orgId:s,...d}),m=e=>({workspace:{list:async()=>(await e()).workspace.getWorkspaces(),get:async t=>(await e()).workspace.getWorkspace(t),create:async t=>(await e()).workspace.createWorkspace(t),update:async(t,s)=>(await e()).workspace.updateWorkspace(t,s),delete:async t=>(await e()).workspace.deleteWorkspace(t)},users:{list:async t=>(await e()).workspace.getWorkspaceUsers(t),invite:async(t,s,r)=>(await e()).workspace.addUser(t,{email:s,role:r}),remove:async(t,s)=>(await e()).workspace.removeUser(t,s),updateRole:async(t,s,r)=>(await e()).workspace.updateUser(t,s,{role:r}),getProfile:async()=>(await e()).workspace.getProfile(),updateProfile:async t=>(await e()).workspace.updateUserProfile(t)},subscription:{get:async t=>(await e()).workspace.getCurrentSubscription(t),checkout:async(t,s)=>(await e()).workspace.createCheckoutSession(t,s),update:async(t,s)=>(await e()).workspace.updateSubscription(t,s),cancel:async t=>(await e()).workspace.cancelSubscriptionAtPeriodEnd(t),resume:async t=>(await e()).workspace.resumeSubscription(t),getBillingPortalUrl:async(t,s)=>(await e()).workspace.createBillingPortalSession(t,s)},plans:{getGroup:async t=>(await e()).workspace.getPlanGroup(t),getVersions:async t=>(await e()).workspace.getPlanGroupVersions(t),getPublic:e=>h.getPublicPlans(e),getVersion:e=>h.getPlanGroupVersion(e)},invoices:{list:async(t,s,r)=>(await e()).workspace.listInvoices(t,s,r),get:async(t,s)=>(await e()).workspace.getInvoice(t,s)},usage:{record:async(t,s)=>(await e()).workspace.recordUsage(t,s),recordBatch:async(t,s)=>(await e()).workspace.recordUsageBatch(t,s),getQuota:async(t,s)=>(await e()).workspace.getQuotaUsageStatus(t,s),getAll:async t=>(await e()).workspace.getAllQuotaUsage(t),getLogs:async(t,s)=>(await e()).workspace.getUsageLogs(t,s)},settings:{get:async()=>(await e()).settings.getSettings()},features:{list:async()=>(await e()).workspace.getFeatures(),update:async(t,s,r)=>(await e()).workspace.updateFeature(t,s,r)},notification:{send:async(t,s,r,n)=>(await e()).workspace.sendNotification(t,s,r,n)},permissions:{check:async(t,s,r)=>{const n=await e(),[o,a,i]=await Promise.all([n.workspace.getWorkspace(t),n.settings.getSettings(),n.workspace.getWorkspaceUsers(t)]),c=i.find(e=>("string"==typeof e.user?e.user:e.user._id)===s);return z(r,{userId:s,workspaceRole:c?.role??null,workspace:o,settings:a})},resolve:async(t,s)=>{const r=await e(),[n,o,a]=await Promise.all([r.workspace.getWorkspace(t),r.settings.getSettings(),r.workspace.getWorkspaceUsers(t)]),i=a.find(e=>("string"==typeof e.user?e.user:e.user._id)===s);return D({userId:s,workspaceRole:i?.role??null,workspace:n,settings:o})}}}),k=m(async()=>p(await(async()=>{if(!n)throw new Error("BuildBase: getSessionId callback is required for authenticated calls. Pass it in BuildBase({ getSessionId: ... }) or use withSession(id) / client.forSession(id).");const e=await n();if(!e)throw new Error("BuildBase: Not authenticated (getSessionId returned null)");return e})()));return{auth:async()=>{if(!n)return null;const e=await n();return e?{sessionId:e}:null},withSession:e=>{const t=p(e);return m(async()=>t)},client:{forSession:p},...k}}exports.AuthStatus=void 0,(G=exports.AuthStatus||(exports.AuthStatus={})).loading="loading",G.redirecting="redirecting",G.authenticated="authenticated",G.unauthenticated="unauthenticated",G.authenticating="authenticating",exports.AuthApi=class extends p{constructor(e){super(e)}async requestAuth(e){const t=`${this.serverUrl}/api/${this.version}/auth/request`,s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!s.ok){let e="Failed to initiate authentication";try{e=(await s.json()).message||e}catch{e=`Failed to initiate authentication (${s.status}: ${s.statusText})`}throw new Error(e)}return s.json()}async getProfile(e,t){return this.fetchJson("profile",{headers:{"x-session-id":e},signal:t},"Failed to fetch user profile")}},exports.BB_PARAM=E,exports.BaseApi=p,exports.BetaForm=class{constructor(e){this.api=new h(e),this.orgId=e.orgId}async fetchConfig(){return this.api.fetchConfig()}async submitBetaUser(e){const t=e?.context??{},s=t?.country??("undefined"!=typeof navigator&&navigator.language?navigator.language.split("-")[1]:void 0),r=t?.language??("undefined"!=typeof navigator&&navigator.language?navigator.language.split("-")[0]:void 0),n=t?.timezone??("undefined"!=typeof Intl&&Intl.DateTimeFormat?Intl.DateTimeFormat().resolvedOptions().timeZone:void 0),o=t?.currency??("undefined"!=typeof Intl&&Intl.NumberFormat&&Intl.NumberFormat().resolvedOptions().currency?Intl.NumberFormat().resolvedOptions().currency:void 0);return this.api.submitBetaUser({orgId:this.orgId,formData:{...e,country:s,language:r,timezone:n,currency:o}})}},exports.BillingIntervals=A,exports.BuildBase=H,exports.CURRENCY_DISPLAY=U,exports.CURRENCY_FLAG=R,exports.DEFAULT_ROLE_PERMISSIONS=q,exports.DunningState={None:"none",Notified:"notified",Warning:"warning",Final:"final",Suspended:"suspended"},exports.EventEmitter=k,exports.InvoiceStatuses={Draft:"draft",Open:"open",Paid:"paid",Uncollectible:"uncollectible",Void:"void"},exports.PLAN_CURRENCY_CODES=I,exports.PLAN_CURRENCY_OPTIONS=F,exports.PUSH_SERVICE_WORKER_SCRIPT="\n// BuildBase Push Notification Service Worker\n// Place this file in your app's public directory (e.g. public/push-sw.js)\n\nself.addEventListener('push', function(event) {\n if (!event.data) return;\n\n try {\n var payload = event.data.json();\n var title = payload.title || 'Notification';\n var options = {\n body: payload.body || '',\n icon: payload.icon || undefined,\n badge: payload.icon || undefined,\n data: { url: payload.url, ...(payload.data || {}) },\n tag: 'buildbase-push-' + Date.now(),\n };\n\n event.waitUntil(\n self.registration.showNotification(title, options)\n );\n } catch (e) {\n console.error('[PushSW] Failed to show notification:', e);\n }\n});\n\nself.addEventListener('notificationclick', function(event) {\n event.notification.close();\n\n var url = event.notification.data && event.notification.data.url;\n if (url) {\n event.waitUntil(\n clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function(clientList) {\n for (var i = 0; i < clientList.length; i++) {\n var client = clientList[i];\n if (client.url === url && 'focus' in client) {\n return client.focus();\n }\n }\n if (clients.openWindow) {\n return clients.openWindow(url);\n }\n })\n );\n }\n});\n",exports.Permission=M,exports.PushApi=f,exports.SDKEvent=m,exports.SettingsApi=g,exports.SubscriptionItemType={Feature:"feature",Limit:"limit",Quota:"quota"},exports.SubscriptionStatus={Active:"active",Trialing:"trialing",Canceled:"canceled",PastDue:"past_due",Paused:"paused",Incomplete:"incomplete",Unpaid:"unpaid"},exports.UserApi=w,exports.WorkspaceApi=y,exports.calculateBillableSeats=B,exports.calculateSeatOverageCents=J,exports.calculateTotalSubscriptionCents=function(e,t,s,r){const n=T(e,t,s);return null===n?null:void 0===r?n:n+(J(e,t,s,r)??0)},exports.cleanBBParams=function(){if("undefined"!=typeof window)try{const e=new URL(window.location.href);e.searchParams.has(E)&&(e.searchParams.delete(E),window.history.replaceState({},"",e.toString()))}catch{}},exports.createBBUrl=$,exports.createCheckoutRedirectUrls=function(e,t){const s=t||("undefined"!=typeof window?window.location.href:void 0);return{successUrl:$({action:"checkout",status:"success",ws:e,screen:"subscription"},s),cancelUrl:$({action:"checkout",status:"cancel",ws:e,screen:"subscription"},s)}},exports.default=H,exports.eventEmitter=b,exports.formatCents=C,exports.formatOverageRate=function(e,t,s,r){if(null==e||e<0)return null;const n={..._,...r},o=null!=t&&t>=1?t:1,a=x(s),i=(e/100).toFixed(2);return 1===o?`${a}${i}/${n.unit}`:`${a}${i}/${o.toLocaleString()} ${n.units}`},exports.formatOverageRateWithLabel=function(e,t,s,r,n,o){if(null==e||e<0)return null;const a={..._,...o},i=null!=t&&t>=1?t:1,c=x(r),u=(e/100).toFixed(2);if(s){const e=n??(s.endsWith("s")?s:`${s}s`);return i>=2?`${c}${u}/${i.toLocaleString()} ${e}`:`${c}${u}/${s}`}return 1===i?`${c}${u}/${a.unit}`:`${c}${u}/${i.toLocaleString()} ${a.units}`},exports.formatQuotaIncludedOverage=function(e,t,s,r,n,o,a){const i={..._,...a},c=o??(s.endsWith("s")?s:`${s}s`),u=null!=n&&n>=2?`${n.toLocaleString()} ${c}`:s;return null!=e&&null!=t?`${i.included}: ${e.toLocaleString()}, ${i.afterThat} ${C(t,r)}/${u}`:null!=e?`${i.included}: ${e.toLocaleString()}`:null!=t?`${i.afterIncluded}: ${C(t,r)}/${u}`:"—"},exports.formatQuotaWithPrice=function(e,t,s={}){const{overageInCents:r=!0,currency:n}=s,o=s.labels??W,a=s.currencySymbol??x(n??"");if(null==e)return"—";const{included:i,overage:c}=e,u=`${i} ${o.included}`;if(null==c)return u;const l=r?c/100:c,d="number"==typeof l&&Number.isFinite(l)?l.toFixed(2):String(c),p=t&&"unitSize"in e&&null!=e.unitSize&&e.unitSize>0?` / ${e.unitSize.toLocaleString()} ${t}`:t?` / ${t}`:"";return`${u}, ${o.then} ${a}${d}${p}`},exports.getAvailableCurrenciesFromPlans=function(e){const t=new Set;for(const s of e)s.pricingVariants?.forEach(e=>{e.currency&&t.add(e.currency.toLowerCase())});return Array.from(t).sort()},exports.getBasePriceCents=T,exports.getBillingIntervalAndCurrencyFromPriceId=function(e,t){if(!e)return null;for(const s of t){const t=s.pricingVariants;if(t?.length)for(const s of t){const t=s.stripePrices;if(t){if(t.monthlyPriceId===e||t.monthly===e)return{interval:"monthly",currency:s.currency};if(t.yearlyPriceId===e||t.yearly===e)return{interval:"yearly",currency:s.currency};if(t.quarterlyPriceId===e)return{interval:"quarterly",currency:s.currency}}}}return null},exports.getCurrencyFlag=function(e){return e&&e.trim()?R[e.trim().toLowerCase()]??"":""},exports.getCurrencySymbol=x,exports.getDisplayCurrency=function(e,t){const s=O(e,t);return s?s.currency:e.plan?.currency??""},exports.getPerSeatPriceCents=j,exports.getPricingVariant=O,exports.getQuotaDisplayValue=function(e,t){if(null==e)return null;const s=e[t??"monthly"];return s?{included:s.included,...void 0!==s.overage&&{overage:s.overage},...void 0!==s.unitSize&&{unitSize:s.unitSize}}:null},exports.getQuotaDisplayWithVariant=function(e,t,s,r){const n=e.quotas?.[s];if(null==n)return null;const o=n[r];if(!o)return null;const a=N(e,t,s,r);return{included:o.included,...void 0!==o.unitSize&&{unitSize:o.unitSize},...void 0!==a&&{overage:a}}},exports.getQuotaOverageCents=N,exports.getQuotaUnitLabelFromName=function(e,t="unit"){const s=(e||"").trim().toLowerCase();if(!s)return t;const r=s.split(/\s+/)[0]??s;return new Set(["series","species","status","analysis","basis","bus","campus","corpus","axis"]).has(r)?r:r.endsWith("ies")&&r.length>3?r.slice(0,-3)+"y":r.endsWith("ses")||r.endsWith("xes")||r.endsWith("zes")||r.endsWith("ches")||r.endsWith("shes")?r.slice(0,-2):r.endsWith("s")&&!r.endsWith("ss")&&r.length>1?r.slice(0,-1):r||t},exports.getSeatPricing=L,exports.getStripePriceIdForInterval=function(e,t,s){const r=O(e,t);if(!r?.stripePrices)return null;const n=s===A.Monthly?"monthlyPriceId":s===A.Yearly?"yearlyPriceId":"quarterlyPriceId",o=s===A.Monthly?"monthly":s===A.Yearly?"yearly":void 0;return r.stripePrices[n]??(o?r.stripePrices[o]:void 0)??null},exports.hasPermission=z,exports.invalidateQuotaUsage=function(){v.forEach(e=>e())},exports.invalidateSubscription=function(){S.forEach(e=>e())},exports.readBBParams=function(){if("undefined"==typeof window)return null;try{const e=new URLSearchParams(window.location.search).get(E);if(!e)return null;const t=function(e){const t={};if(!e)return t;const s=e.split(",");for(const e of s){const s=e.indexOf(":");if(-1===s)continue;const r=decodeURIComponent(e.slice(0,s)),n=decodeURIComponent(e.slice(s+1));r&&(t[r]=n)}return t}(e);return Object.keys(t).length>0?t:null}catch{return null}},exports.resolveMaxUsers=function(e){const{planVersion:t,currency:s="usd",settingsMaxUsers:r}=e;if(t){const e=L(t,s);if(e)return{maxUsers:e.maxSeats??0,source:"seat_pricing",includedSeats:e.includedSeats??0,hasSeatPricing:!0}}return null!=r&&r>0?{maxUsers:r,source:"settings",includedSeats:0,hasSeatPricing:!1}:{maxUsers:0,source:"none",includedSeats:0,hasSeatPricing:!1}},exports.resolvePermissions=D,exports.safeRedirect=function(e,t="/"){const s=P(e);window.location.href=s||t},exports.validateInvite=function(e){const{memberCount:t,maxUsersConfig:s,hasSubscription:r=!0,requireSubscription:n=!1}=e;if(n&&!r)return{canInvite:!1,blockReason:"no_subscription",blockMessageKey:"users.subscriptionRequired",blockMessageValues:{}};const{maxUsers:o,source:a}=s;if(o<=0)return{canInvite:!0,blockReason:null,blockMessageKey:null,blockMessageValues:null};if(t>=o){return{canInvite:!1,blockReason:{seat_pricing:"seat_limit_reached",settings:"settings_user_limit_reached"}[a]??"seat_limit_reached",blockMessageKey:{seat_pricing:"users.seatLimitMessage",settings:"users.settingsLimitMessage"}[a]??"users.memberLimitMessage",blockMessageValues:{maxUsers:o}}}return{canInvite:!0,blockReason:null,blockMessageKey:null,blockMessageValues:null}},exports.validateRedirectUrl=P;
|