vg-x07df 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/.azure-pipelines/publish-public.yml +37 -0
  2. package/.azure-pipelines/publish.yml +39 -0
  3. package/.changeset/README.md +8 -0
  4. package/.changeset/config.json +11 -0
  5. package/AUTO_JOIN_GUIDE.md +411 -0
  6. package/README.md +215 -0
  7. package/Screenshot 2025-09-24 at 14.34.48.png +0 -0
  8. package/Screenshot 2025-10-04 at 12.58.54.png +0 -0
  9. package/biome.json +48 -0
  10. package/examples/demo/.env.example +19 -0
  11. package/examples/demo/CHANGELOG.md +22 -0
  12. package/examples/demo/README.md +72 -0
  13. package/examples/demo/eslint.config.js +23 -0
  14. package/examples/demo/index.html +13 -0
  15. package/examples/demo/package.json +34 -0
  16. package/examples/demo/pnpm-lock.yaml +2098 -0
  17. package/examples/demo/pnpm-workspace.yaml +1 -0
  18. package/examples/demo/public/vite.svg +1 -0
  19. package/examples/demo/src/App.css +52 -0
  20. package/examples/demo/src/App.tsx +176 -0
  21. package/examples/demo/src/assets/react.svg +1 -0
  22. package/examples/demo/src/components/auth/LoginForm.css +144 -0
  23. package/examples/demo/src/components/auth/LoginForm.tsx +80 -0
  24. package/examples/demo/src/components/calling/AutoJoinSettings.tsx +213 -0
  25. package/examples/demo/src/components/calling/AutoJoinStatus.tsx +72 -0
  26. package/examples/demo/src/components/calling/CallInitiator.css +258 -0
  27. package/examples/demo/src/components/calling/CallInitiator.tsx +142 -0
  28. package/examples/demo/src/components/calling/CallNotifications.css +119 -0
  29. package/examples/demo/src/components/calling/CallNotifications.tsx +108 -0
  30. package/examples/demo/src/components/calling/IncomingCallModal.css +192 -0
  31. package/examples/demo/src/components/calling/IncomingCallModal.tsx +78 -0
  32. package/examples/demo/src/components/calling/MinimizedCall.css +156 -0
  33. package/examples/demo/src/components/calling/MinimizedCall.tsx +78 -0
  34. package/examples/demo/src/components/conference/ConferenceHeader.css +265 -0
  35. package/examples/demo/src/components/conference/ConferenceHeader.tsx +78 -0
  36. package/examples/demo/src/components/conference/EnhancedControlBar.css +356 -0
  37. package/examples/demo/src/components/conference/EnhancedControlBar.tsx +262 -0
  38. package/examples/demo/src/components/conference/PaginationControls.css +67 -0
  39. package/examples/demo/src/components/conference/PaginationControls.tsx +64 -0
  40. package/examples/demo/src/components/conference/ParticipantGrid.css +153 -0
  41. package/examples/demo/src/components/conference/ParticipantGrid.tsx +87 -0
  42. package/examples/demo/src/components/conference/ParticipantTile.css +210 -0
  43. package/examples/demo/src/components/conference/ParticipantTile.tsx +114 -0
  44. package/examples/demo/src/components/conference/VideoConference.css +214 -0
  45. package/examples/demo/src/components/conference/VideoConference.tsx +93 -0
  46. package/examples/demo/src/contexts/AuthContext.tsx +105 -0
  47. package/examples/demo/src/hooks/useAuth.ts +5 -0
  48. package/examples/demo/src/hooks/useCallTimer.ts +42 -0
  49. package/examples/demo/src/index.css +68 -0
  50. package/examples/demo/src/main.tsx +10 -0
  51. package/examples/demo/src/services/auth.service.ts +153 -0
  52. package/examples/demo/src/types/auth.types.ts +31 -0
  53. package/examples/demo/tsconfig.app.json +28 -0
  54. package/examples/demo/tsconfig.json +7 -0
  55. package/examples/demo/tsconfig.node.json +26 -0
  56. package/examples/demo/vite.config.ts +15 -0
  57. package/images/callpad-without-ai.png +0 -0
  58. package/package.json +28 -0
  59. package/packages/sdk/CHANGELOG.md +33 -0
  60. package/packages/sdk/LICENSE +21 -0
  61. package/packages/sdk/README.md +97 -0
  62. package/packages/sdk/documentation.md +1132 -0
  63. package/packages/sdk/openapi-ts.config.ts +7 -0
  64. package/packages/sdk/package.json +88 -0
  65. package/packages/sdk/src/core/auth.manager.ts +52 -0
  66. package/packages/sdk/src/core/events/event-bus.ts +301 -0
  67. package/packages/sdk/src/core/events/index.ts +8 -0
  68. package/packages/sdk/src/core/events/types.ts +165 -0
  69. package/packages/sdk/src/core/index.ts +3 -0
  70. package/packages/sdk/src/core/signal/api.config.ts +49 -0
  71. package/packages/sdk/src/core/signal/index.ts +16 -0
  72. package/packages/sdk/src/core/signal/signal.client.ts +101 -0
  73. package/packages/sdk/src/core/signal/types.ts +110 -0
  74. package/packages/sdk/src/core/socketio/handlers/base.handler.ts +212 -0
  75. package/packages/sdk/src/core/socketio/handlers/call-accepted.handler.ts +34 -0
  76. package/packages/sdk/src/core/socketio/handlers/call-canceled.handler.ts +34 -0
  77. package/packages/sdk/src/core/socketio/handlers/call-declined.handler.ts +29 -0
  78. package/packages/sdk/src/core/socketio/handlers/call-ended.handler.ts +40 -0
  79. package/packages/sdk/src/core/socketio/handlers/call-incoming.handler.ts +72 -0
  80. package/packages/sdk/src/core/socketio/handlers/call-join-info.handler.ts +181 -0
  81. package/packages/sdk/src/core/socketio/handlers/call-participant-joined.handler.ts +42 -0
  82. package/packages/sdk/src/core/socketio/handlers/call-participant-joining.handler.ts +42 -0
  83. package/packages/sdk/src/core/socketio/handlers/call-timeout.handler.ts +31 -0
  84. package/packages/sdk/src/core/socketio/handlers/handler.registry.ts +62 -0
  85. package/packages/sdk/src/core/socketio/handlers/index.ts +21 -0
  86. package/packages/sdk/src/core/socketio/handlers/participant-left.handler.ts +37 -0
  87. package/packages/sdk/src/core/socketio/handlers/schema.ts +130 -0
  88. package/packages/sdk/src/core/socketio/index.ts +5 -0
  89. package/packages/sdk/src/core/socketio/socket.manager.ts +187 -0
  90. package/packages/sdk/src/core/socketio/types.ts +14 -0
  91. package/packages/sdk/src/core/types.ts +23 -0
  92. package/packages/sdk/src/generated/api/core/ApiError.ts +21 -0
  93. package/packages/sdk/src/generated/api/core/ApiRequestOptions.ts +13 -0
  94. package/packages/sdk/src/generated/api/core/ApiResult.ts +7 -0
  95. package/packages/sdk/src/generated/api/core/CancelablePromise.ts +126 -0
  96. package/packages/sdk/src/generated/api/core/OpenAPI.ts +55 -0
  97. package/packages/sdk/src/generated/api/core/request.ts +339 -0
  98. package/packages/sdk/src/generated/api/index.ts +5 -0
  99. package/packages/sdk/src/generated/api/models.ts +219 -0
  100. package/packages/sdk/src/generated/api/services.ts +225 -0
  101. package/packages/sdk/src/hooks/index.ts +21 -0
  102. package/packages/sdk/src/hooks/useAutoJoin.ts +66 -0
  103. package/packages/sdk/src/hooks/useCallActions.ts +28 -0
  104. package/packages/sdk/src/hooks/useCallQuality.ts +416 -0
  105. package/packages/sdk/src/hooks/useCallState.ts +23 -0
  106. package/packages/sdk/src/hooks/useConnection.ts +15 -0
  107. package/packages/sdk/src/hooks/useDevices.ts +296 -0
  108. package/packages/sdk/src/hooks/useErrorRecovery.ts +299 -0
  109. package/packages/sdk/src/hooks/useErrors.ts +84 -0
  110. package/packages/sdk/src/hooks/useEvent.ts +188 -0
  111. package/packages/sdk/src/hooks/useMediaControls.ts +215 -0
  112. package/packages/sdk/src/hooks/useParticipantStatus.ts +318 -0
  113. package/packages/sdk/src/hooks/useParticipants.ts +111 -0
  114. package/packages/sdk/src/index.ts +66 -0
  115. package/packages/sdk/src/livekit/constants.ts +76 -0
  116. package/packages/sdk/src/livekit/device.manager.ts +172 -0
  117. package/packages/sdk/src/livekit/error-classifier.ts +155 -0
  118. package/packages/sdk/src/livekit/events/eventBridge.ts +371 -0
  119. package/packages/sdk/src/livekit/events/trackRegistry.ts +114 -0
  120. package/packages/sdk/src/livekit/index.ts +49 -0
  121. package/packages/sdk/src/livekit/livekit.service.ts +110 -0
  122. package/packages/sdk/src/livekit/media.controls.ts +315 -0
  123. package/packages/sdk/src/livekit/room.manager.ts +79 -0
  124. package/packages/sdk/src/livekit/track.utils.ts +230 -0
  125. package/packages/sdk/src/livekit/types.ts +135 -0
  126. package/packages/sdk/src/provider/RtcProvider.tsx +78 -0
  127. package/packages/sdk/src/services/call-actions.ts +260 -0
  128. package/packages/sdk/src/services/error-recovery.ts +461 -0
  129. package/packages/sdk/src/services/index.ts +2 -0
  130. package/packages/sdk/src/services/sdk-builder.ts +104 -0
  131. package/packages/sdk/src/state/errors.ts +163 -0
  132. package/packages/sdk/src/state/selectors.ts +28 -0
  133. package/packages/sdk/src/state/store.ts +36 -0
  134. package/packages/sdk/src/state/types.ts +151 -0
  135. package/packages/sdk/src/utils/logger.ts +183 -0
  136. package/packages/sdk/tsconfig.json +49 -0
  137. package/packages/sdk/tsup.config.ts +51 -0
  138. package/pnpm-workspace.yaml +4 -0
  139. package/tsconfig.base.json +19 -0
  140. package/turbo.json +34 -0
@@ -0,0 +1,163 @@
1
+ import type { LogLevel } from "../utils/logger";
2
+ import { rtcStore } from "./store";
3
+ import type { RtcError } from "./types";
4
+
5
+ // Re-export RtcError type for external consumption
6
+ export type { RtcError } from "./types";
7
+
8
+ export type ErrorCode =
9
+ | "NETWORK"
10
+ | "SOCKET_PAYLOAD"
11
+ | "JOIN_FLOW"
12
+ | "LIVEKIT_CONNECT"
13
+ | "LIVEKIT_MEDIA"
14
+ | "MEDIA_PERMISSION"
15
+ | "DEVICE_SWITCH"
16
+ | "API_ERROR"
17
+ | "UNEXPECTED";
18
+
19
+ export function pushError(
20
+ code: ErrorCode,
21
+ message: string,
22
+ context?: any,
23
+ logger?: (level: LogLevel, message: string, meta?: any) => void
24
+ ): void {
25
+ const error: RtcError = {
26
+ code,
27
+ message,
28
+ timestamp: Date.now(),
29
+ context,
30
+ };
31
+
32
+ // Log the error if logger is provided
33
+ logger?.("error", message, { code, context });
34
+ rtcStore.getState().addError(error);
35
+ }
36
+
37
+ /**
38
+ * Clear errors from the store
39
+ * @param predicate Optional filter function - if provided, only matching errors are removed
40
+ */
41
+ export function clearErrors(predicate?: (error: RtcError) => boolean): void {
42
+ rtcStore.getState().patch((state) => {
43
+ if (predicate) {
44
+ // Remove only errors matching the predicate
45
+ state.errors = state.errors.filter((error) => !predicate(error));
46
+ } else {
47
+ // Clear all errors
48
+ state.errors = [];
49
+ }
50
+ });
51
+ }
52
+
53
+ // Convenience helpers for common error scenarios
54
+ export function pushSocketValidationError(
55
+ eventType: string,
56
+ issues: any,
57
+ payload?: any,
58
+ logger?: (level: LogLevel, message: string, meta?: any) => void
59
+ ): void {
60
+ pushError(
61
+ "SOCKET_PAYLOAD",
62
+ `Invalid ${eventType} event payload`,
63
+ { eventType, issues, payload },
64
+ logger
65
+ );
66
+ }
67
+
68
+ export function pushIdentityGuardError(
69
+ reason: string,
70
+ expected?: string,
71
+ received?: string,
72
+ logger?: (level: LogLevel, message: string, meta?: any) => void
73
+ ): void {
74
+ pushError(
75
+ "JOIN_FLOW", // Use new error code
76
+ `Identity guard failed: ${reason}`,
77
+ { expected, received },
78
+ logger
79
+ );
80
+ }
81
+
82
+ export function pushLiveKitConnectError(
83
+ message: string,
84
+ error: unknown,
85
+ logger?: (level: LogLevel, message: string, meta?: any) => void
86
+ ): void {
87
+ pushError(
88
+ "LIVEKIT_CONNECT",
89
+ `LiveKit connection failed: ${message}`,
90
+ { originalError: error },
91
+ logger
92
+ );
93
+ }
94
+
95
+ export function pushStaleEventError(
96
+ eventType: string,
97
+ reason: string,
98
+ context?: any,
99
+ logger?: (level: LogLevel, message: string, meta?: any) => void
100
+ ): void {
101
+ pushError(
102
+ "JOIN_FLOW", // Use new error code
103
+ `Ignored stale ${eventType} event: ${reason}`,
104
+ context,
105
+ logger
106
+ );
107
+ }
108
+
109
+ export function pushApiError(
110
+ operation: string,
111
+ error: unknown,
112
+ logger?: (level: LogLevel, message: string, meta?: any) => void
113
+ ): void {
114
+ const errorMessage = error instanceof Error ? error.message : String(error);
115
+ pushError(
116
+ "API_ERROR",
117
+ `API ${operation} failed: ${errorMessage}`,
118
+ { operation, originalError: error },
119
+ logger
120
+ );
121
+ }
122
+
123
+ export function pushNetworkError(
124
+ operation: string,
125
+ error: unknown,
126
+ logger?: (level: LogLevel, message: string, meta?: any) => void
127
+ ): void {
128
+ const errorMessage = error instanceof Error ? error.message : String(error);
129
+ pushError(
130
+ "NETWORK",
131
+ `Network error during ${operation}: ${errorMessage}`,
132
+ { operation, originalError: error },
133
+ logger
134
+ );
135
+ }
136
+
137
+ export function pushMediaPermissionError(
138
+ device: string,
139
+ error?: unknown,
140
+ logger?: (level: LogLevel, message: string, meta?: any) => void
141
+ ): void {
142
+ pushError(
143
+ "MEDIA_PERMISSION",
144
+ `${device} permission denied`,
145
+ { device, originalError: error },
146
+ logger
147
+ );
148
+ }
149
+
150
+ export function pushDeviceError(
151
+ operation: string,
152
+ device: string,
153
+ error: unknown,
154
+ logger?: (level: LogLevel, message: string, meta?: any) => void
155
+ ): void {
156
+ const errorMessage = error instanceof Error ? error.message : String(error);
157
+ pushError(
158
+ "DEVICE_SWITCH",
159
+ `Failed to ${operation} ${device}: ${errorMessage}`,
160
+ { operation, device, originalError: error },
161
+ logger
162
+ );
163
+ }
@@ -0,0 +1,28 @@
1
+ import { useRtcStore } from "./store";
2
+ import type { Participant } from "./types";
3
+
4
+ export function useParticipants(): Participant[] {
5
+ return useRtcStore((state) => Object.values(state.room.participants));
6
+ }
7
+
8
+ export function useParticipant(id: string): Participant | undefined {
9
+ return useRtcStore((state) => state.room.participants[id]);
10
+ }
11
+
12
+ export function useRingingParticipants(): Participant[] {
13
+ return useRtcStore((state) =>
14
+ Object.values(state.room.participants).filter(
15
+ (p) => p.callState === "RINGING"
16
+ )
17
+ );
18
+ }
19
+
20
+ export function useLocalParticipant(): Participant | undefined {
21
+ return undefined;
22
+ }
23
+
24
+ export function useSpeakingParticipants(): Participant[] {
25
+ return useRtcStore((state) =>
26
+ Object.values(state.room.participants).filter((p) => p.isSpeaking)
27
+ );
28
+ }
@@ -0,0 +1,36 @@
1
+ import { create } from "zustand";
2
+ import { immer } from "zustand/middleware/immer";
3
+ import type { RtcError, RtcState } from "./types";
4
+ import { defaultState } from "./types";
5
+
6
+ type Actions = {
7
+ patch: (fn: (draft: RtcState) => void) => void;
8
+ reset: () => void;
9
+ addError: (error: RtcError) => void;
10
+ clearErrors: () => void;
11
+ };
12
+
13
+ export const useRtcStore = create<RtcState & Actions>()(
14
+ immer((set) => ({
15
+ ...defaultState,
16
+
17
+ patch: (fn) =>
18
+ set((state) => {
19
+ fn(state);
20
+ }),
21
+
22
+ reset: () => set(() => defaultState),
23
+
24
+ addError: (error) =>
25
+ set((state) => {
26
+ state.errors.push(error);
27
+ }),
28
+
29
+ clearErrors: () =>
30
+ set((state) => {
31
+ state.errors = [];
32
+ }),
33
+ }))
34
+ );
35
+
36
+ export const rtcStore = useRtcStore;
@@ -0,0 +1,151 @@
1
+ export type SessionStatus =
2
+ | "IDLE"
3
+ | "CALLING" // Caller initiated, waiting for acceptance
4
+ | "RINGING" // Incoming call (callee perspective)
5
+ | "ACCEPTED" // Call accepted but not yet joined media
6
+ | "AWAITING_JOIN_INFO" // Waiting for join credentials
7
+ | "READY_TO_JOIN" // Has join-info but not connected to media
8
+ | "CONNECTING" // Joining LiveKit room
9
+ | "ACTIVE" // Successfully connected to media session
10
+ | "ENDED";
11
+
12
+ // Unified Participant interface - combines all participant data
13
+ export interface Participant {
14
+ id: string;
15
+ // Profile data
16
+ firstName?: string;
17
+ lastName?: string;
18
+ avatarUrl?: string;
19
+ // Call state
20
+ role: "CALLER" | "CALLEE" | "HOST" | "MEMBER";
21
+ callState: "INVITED" | "RINGING" | "JOINED" | "LEFT";
22
+ // Media state
23
+ audioEnabled: boolean;
24
+ videoEnabled: boolean;
25
+ isSpeaking: boolean;
26
+ connectionQuality?: "excellent" | "good" | "poor" | "lost" | "unknown";
27
+ // Timestamps
28
+ invitedAt?: number;
29
+ joinedAt?: number;
30
+ leftAt?: number;
31
+ }
32
+
33
+ export type PermissionStatus = "granted" | "denied" | "prompt" | "unknown";
34
+
35
+ export interface DeviceState {
36
+ mics: MediaDeviceInfo[];
37
+ cams: MediaDeviceInfo[];
38
+ speakers: MediaDeviceInfo[];
39
+ selected: {
40
+ micId: string | undefined;
41
+ camId: string | undefined;
42
+ speakerId: string | undefined;
43
+ };
44
+ permissions: {
45
+ camera: PermissionStatus;
46
+ microphone: PermissionStatus;
47
+ };
48
+ isEnumerating: boolean;
49
+ lastEnumeratedAt: number | undefined;
50
+ }
51
+
52
+ export interface IncomingCallInfo {
53
+ callId: string;
54
+ caller: {
55
+ id: string;
56
+ name: string;
57
+ avatarUrl: string | undefined;
58
+ };
59
+ type: "AUDIO" | "VIDEO";
60
+ timestamp: number;
61
+ }
62
+
63
+ export interface LiveKitJoinInfo {
64
+ token: string;
65
+ roomName: string;
66
+ callId: string;
67
+ url?: string;
68
+ }
69
+
70
+ export interface RtcError {
71
+ code: string;
72
+ message: string;
73
+ timestamp: number;
74
+ context?: any;
75
+ }
76
+
77
+ export type AutoJoinStatus = "idle" | "pending" | "retrying" | "succeeded" | "failed";
78
+
79
+ export interface AutoJoinState {
80
+ status: AutoJoinStatus;
81
+ attempt: number;
82
+ maxAttempts: number;
83
+ lastError?: string;
84
+ startedAt?: number;
85
+ completedAt?: number;
86
+ }
87
+
88
+ export interface RtcState {
89
+ session: {
90
+ id?: string;
91
+ status: SessionStatus;
92
+ mode?: "AUDIO" | "VIDEO";
93
+ livekitInfo?: LiveKitJoinInfo;
94
+ // Identity context: how did I get into this call?
95
+ myRole?: "CALLER" | "CALLEE";
96
+ initiatedByMe: boolean;
97
+ };
98
+
99
+ room: {
100
+ participants: Record<string, Participant>; // Single unified record
101
+ };
102
+
103
+ local: {
104
+ audioEnabled: boolean;
105
+ videoEnabled: boolean;
106
+ screenEnabled: boolean;
107
+ };
108
+
109
+ connection: {
110
+ connected: boolean;
111
+ reconnecting: boolean;
112
+ quality?: "excellent" | "good" | "poor" | "lost";
113
+ };
114
+
115
+ autoJoin: AutoJoinState;
116
+ devices: DeviceState;
117
+ errors: RtcError[];
118
+ incomingCall: IncomingCallInfo | undefined;
119
+ }
120
+
121
+ export const defaultState: RtcState = {
122
+ session: { status: "IDLE", initiatedByMe: false },
123
+ room: {
124
+ participants: {},
125
+ },
126
+ local: { audioEnabled: false, videoEnabled: false, screenEnabled: false },
127
+ connection: { connected: false, reconnecting: false },
128
+ autoJoin: {
129
+ status: "idle",
130
+ attempt: 0,
131
+ maxAttempts: 0,
132
+ },
133
+ devices: {
134
+ mics: [],
135
+ cams: [],
136
+ speakers: [],
137
+ selected: {
138
+ micId: undefined,
139
+ camId: undefined,
140
+ speakerId: undefined,
141
+ },
142
+ permissions: {
143
+ camera: "unknown",
144
+ microphone: "unknown",
145
+ },
146
+ isEnumerating: false,
147
+ lastEnumeratedAt: undefined,
148
+ },
149
+ errors: [],
150
+ incomingCall: undefined,
151
+ };
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Comprehensive logging system for the Callpad Web SDK
3
+ *
4
+ * Features:
5
+ * - Log level filtering (debug, info, warn, error)
6
+ * - Environment variable configuration (DEBUG, CALLPAD_LOG_LEVEL)
7
+ * - Hierarchical namespacing (callpad:socket:connection)
8
+ * - Custom logger integration
9
+ * - Zero-cost when disabled
10
+ */
11
+
12
+ export type LogLevel = "debug" | "info" | "warn" | "error";
13
+
14
+ export interface LoggerOptions {
15
+ level?: LogLevel;
16
+ enableDebug?: boolean;
17
+ customLogger?: (level: LogLevel, message: string, meta?: any) => void;
18
+ }
19
+
20
+ export interface CallpadLogger {
21
+ debug(message: string, meta?: any): void;
22
+ info(message: string, meta?: any): void;
23
+ warn(message: string, meta?: any): void;
24
+ error(message: string, meta?: any): void;
25
+ child(namespace: string): CallpadLogger;
26
+ setLevel(level: LogLevel): void;
27
+ isLevelEnabled(level: LogLevel): boolean;
28
+ }
29
+
30
+ const LOG_LEVELS: Record<LogLevel, number> = {
31
+ debug: 0,
32
+ info: 1,
33
+ warn: 2,
34
+ error: 3,
35
+ };
36
+
37
+ class CallpadLoggerImpl implements CallpadLogger {
38
+ private namespace: string;
39
+ private level: LogLevel;
40
+ private enableDebug: boolean;
41
+ private customLogger?: (level: LogLevel, message: string, meta?: any) => void;
42
+
43
+ constructor(namespace = "callpad", options: LoggerOptions = {}) {
44
+ this.namespace = namespace;
45
+ this.level = options.level ?? this.getDefaultLevel();
46
+ this.enableDebug = options.enableDebug ?? this.shouldEnableDebug();
47
+ if (options.customLogger) {
48
+ this.customLogger = options.customLogger;
49
+ }
50
+ }
51
+
52
+ private getDefaultLevel(): LogLevel {
53
+ const envLevel =
54
+ typeof window !== "undefined"
55
+ ? (window as any).__CALLPAD_LOG_LEVEL__
56
+ : typeof globalThis !== "undefined" &&
57
+ (globalThis as any).process?.env?.CALLPAD_LOG_LEVEL;
58
+
59
+ if (envLevel && this.isValidLogLevel(envLevel)) {
60
+ return envLevel as LogLevel;
61
+ }
62
+
63
+ const isProduction =
64
+ typeof globalThis !== "undefined" &&
65
+ (globalThis as any).process?.env?.NODE_ENV === "production";
66
+
67
+ return isProduction ? "warn" : "info";
68
+ }
69
+
70
+ private shouldEnableDebug(): boolean {
71
+ const debugEnv =
72
+ typeof window !== "undefined"
73
+ ? (window as any).__DEBUG__
74
+ : typeof globalThis !== "undefined" &&
75
+ (globalThis as any).process?.env?.DEBUG;
76
+
77
+ if (!debugEnv) return false;
78
+
79
+ const debugPatterns = debugEnv.split(/[\s,]+/);
80
+ return debugPatterns.some((pattern: string) => {
81
+ if (pattern === "*") return true;
82
+ if (pattern.endsWith("*")) {
83
+ const prefix = pattern.slice(0, -1);
84
+ return this.namespace.startsWith(prefix);
85
+ }
86
+ return this.namespace === pattern;
87
+ });
88
+ }
89
+
90
+ private isValidLogLevel(level: string): boolean {
91
+ return Object.keys(LOG_LEVELS).includes(level);
92
+ }
93
+
94
+ private shouldLog(level: LogLevel): boolean {
95
+ if (level === "debug" && !this.enableDebug) {
96
+ return false;
97
+ }
98
+ return LOG_LEVELS[level] >= LOG_LEVELS[this.level];
99
+ }
100
+
101
+ private formatMessage(level: LogLevel, message: string, meta?: any): void {
102
+ if (!this.shouldLog(level)) return;
103
+
104
+ const timestamp = new Date().toISOString();
105
+ const prefix = `[${timestamp}] [${this.namespace}] [${level.toUpperCase()}]`;
106
+
107
+ if (this.customLogger) {
108
+ this.customLogger(level, message, meta);
109
+ return;
110
+ }
111
+
112
+ const logMethod =
113
+ level === "error"
114
+ ? console.error
115
+ : level === "warn"
116
+ ? console.warn
117
+ : level === "info"
118
+ ? console.info
119
+ : console.log;
120
+
121
+ if (meta !== undefined) {
122
+ logMethod(`${prefix} ${message}`, meta);
123
+ } else {
124
+ logMethod(`${prefix} ${message}`);
125
+ }
126
+ }
127
+
128
+ debug(message: string, meta?: any): void {
129
+ this.formatMessage("debug", message, meta);
130
+ }
131
+
132
+ info(message: string, meta?: any): void {
133
+ this.formatMessage("info", message, meta);
134
+ }
135
+
136
+ warn(message: string, meta?: any): void {
137
+ this.formatMessage("warn", message, meta);
138
+ }
139
+
140
+ error(message: string, meta?: any): void {
141
+ this.formatMessage("error", message, meta);
142
+ }
143
+
144
+ child(namespace: string): CallpadLogger {
145
+ const childNamespace = `${this.namespace}:${namespace}`;
146
+ const childOptions: LoggerOptions = {
147
+ level: this.level,
148
+ enableDebug: this.enableDebug,
149
+ };
150
+ if (this.customLogger) {
151
+ childOptions.customLogger = this.customLogger;
152
+ }
153
+ return new CallpadLoggerImpl(childNamespace, childOptions);
154
+ }
155
+
156
+ setLevel(level: LogLevel): void {
157
+ this.level = level;
158
+ }
159
+
160
+ isLevelEnabled(level: LogLevel): boolean {
161
+ return this.shouldLog(level);
162
+ }
163
+ }
164
+
165
+ let rootLogger: CallpadLogger | null = null;
166
+
167
+ export function createLogger(
168
+ namespace?: string,
169
+ options?: LoggerOptions
170
+ ): CallpadLogger {
171
+ if (!namespace) {
172
+ if (!rootLogger) {
173
+ rootLogger = new CallpadLoggerImpl("callpad", options);
174
+ }
175
+ return rootLogger;
176
+ }
177
+
178
+ return new CallpadLoggerImpl(`callpad:${namespace}`, options);
179
+ }
180
+
181
+ export function setGlobalLoggerOptions(options: LoggerOptions): void {
182
+ rootLogger = new CallpadLoggerImpl("callpad", options);
183
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Base configuration (standalone, no dependency on monorepo)
4
+ "target": "ES2020",
5
+ "lib": ["DOM", "DOM.Iterable", "ES2020"],
6
+ "allowJs": true,
7
+ "skipLibCheck": true,
8
+ "esModuleInterop": true,
9
+ "allowSyntheticDefaultImports": true,
10
+ "strict": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "noFallthroughCasesInSwitch": true,
13
+ "module": "esnext",
14
+ "moduleResolution": "bundler",
15
+ "resolveJsonModule": true,
16
+ "isolatedModules": true,
17
+ "jsx": "react-jsx",
18
+
19
+ // Library-specific configuration
20
+ "declaration": true,
21
+ "declarationMap": true,
22
+ "sourceMap": true,
23
+ "outDir": "./dist/types",
24
+
25
+ // Additional strictness for library
26
+ "exactOptionalPropertyTypes": true,
27
+ "noImplicitReturns": true,
28
+ "noUncheckedIndexedAccess": true,
29
+ "noImplicitOverride": true,
30
+
31
+ // Library output settings
32
+ "removeComments": false,
33
+ "preserveConstEnums": true,
34
+ "inlineSources": true
35
+ },
36
+ "include": [
37
+ "src/**/*"
38
+ ],
39
+ "exclude": [
40
+ "node_modules",
41
+ "dist",
42
+ "**/*.test.ts",
43
+ "**/*.test.tsx",
44
+ "**/*.spec.ts",
45
+ "**/*.spec.tsx",
46
+ "**/*.stories.ts",
47
+ "**/*.stories.tsx"
48
+ ]
49
+ }
@@ -0,0 +1,51 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: {
5
+ index: "src/index.ts",
6
+ "livekit/index": "src/livekit/index.ts",
7
+ },
8
+ format: ["cjs", "esm"],
9
+ sourcemap: true,
10
+ clean: true,
11
+ splitting: false,
12
+ treeshake: true,
13
+ minify: false, // Keep readable for debugging
14
+ external: [
15
+ "react",
16
+ "react-dom",
17
+ "livekit-client",
18
+ "socket.io-client",
19
+ "axios",
20
+ "jwt-decode",
21
+ "zustand",
22
+ "immer",
23
+ "zod",
24
+ ],
25
+ target: "es2020",
26
+ platform: "browser",
27
+ outExtension({ format }) {
28
+ return {
29
+ js: format === "esm" ? ".mjs" : ".cjs",
30
+ };
31
+ },
32
+ // Production optimizations
33
+ bundle: true,
34
+ skipNodeModulesBundle: true,
35
+ noExternal: [],
36
+ // Library specific settings
37
+ esbuildOptions(options) {
38
+ options.banner = {
39
+ js: '"use client";', // Next.js client component support
40
+ };
41
+ options.jsx = "automatic";
42
+ options.jsxImportSource = "react";
43
+ },
44
+ // Type generation
45
+ dts: {
46
+ resolve: true,
47
+ compilerOptions: {
48
+ moduleResolution: "bundler",
49
+ },
50
+ },
51
+ });
@@ -0,0 +1,4 @@
1
+ packages:
2
+ - "apps/*"
3
+ - "packages/*"
4
+ - "examples/*"
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["DOM", "DOM.Iterable", "ES2020"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "esModuleInterop": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "strict": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "noFallthroughCasesInSwitch": true,
12
+ "module": "esnext",
13
+ "moduleResolution": "bundler",
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "noEmit": true,
17
+ "jsx": "react-jsx"
18
+ }
19
+ }