@thisispamela/sdk 1.0.4 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,11 +1,34 @@
1
1
  {
2
2
  "name": "@thisispamela/sdk",
3
- "version": "1.0.4",
3
+ "version": "1.1.1",
4
4
  "description": "Pamela Enterprise Voice API SDK for JavaScript/TypeScript",
5
5
  "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
6
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./webhooks": {
15
+ "types": "./dist/webhooks.d.ts",
16
+ "import": "./dist/webhooks.mjs",
17
+ "require": "./dist/webhooks.js"
18
+ },
19
+ "./types": {
20
+ "types": "./dist/types.d.ts",
21
+ "import": "./dist/types.mjs",
22
+ "require": "./dist/types.js"
23
+ },
24
+ "./errors": {
25
+ "types": "./dist/errors.d.ts",
26
+ "import": "./dist/errors.mjs",
27
+ "require": "./dist/errors.js"
28
+ }
29
+ },
7
30
  "scripts": {
8
- "build": "tsc",
31
+ "build": "tsup",
9
32
  "test": "jest",
10
33
  "test:watch": "jest --watch",
11
34
  "prepublishOnly": "npm run build"
@@ -26,8 +49,9 @@
26
49
  "devDependencies": {
27
50
  "@types/node": "^20.0.0",
28
51
  "@types/jest": "^29.5.0",
29
- "typescript": "^5.0.0",
30
52
  "jest": "^29.7.0",
31
- "ts-jest": "^29.1.0"
53
+ "ts-jest": "^29.1.0",
54
+ "tsup": "^8.0.0",
55
+ "typescript": "^5.0.0"
32
56
  }
33
57
  }
package/src/index.ts CHANGED
@@ -3,7 +3,6 @@
3
3
  */
4
4
 
5
5
  import axios, { AxiosInstance, AxiosError } from 'axios';
6
- import * as crypto from 'crypto';
7
6
  import {
8
7
  PamelaError,
9
8
  AuthenticationError,
@@ -12,70 +11,13 @@ import {
12
11
  ValidationError,
13
12
  CallError,
14
13
  } from './errors';
15
-
16
- export interface PamelaClientConfig {
17
- apiKey: string;
18
- baseUrl?: string;
19
- }
20
-
21
- export interface CreateCallRequest {
22
- to: string;
23
- country?: string;
24
- locale?: string;
25
- task: string;
26
- instructions?: string;
27
- max_duration_seconds?: number;
28
- voice?: 'male' | 'female' | 'auto';
29
- agent_name?: string;
30
- caller_name?: string;
31
- end_user_id?: string;
32
- metadata?: Record<string, any>;
33
- tools?: Array<Record<string, any>>;
34
- webhooks?: {
35
- webhook_url?: string;
36
- tool_webhook_url?: string;
37
- };
38
- }
39
-
40
- export interface CallResponse {
41
- id: string;
42
- status: string;
43
- call_session_id: string;
44
- created_at: string;
45
- }
46
-
47
- export interface CallStatus {
48
- id: string;
49
- status: string;
50
- to: string;
51
- from_: string; // Backend uses from_ (Python keyword)
52
- country: string;
53
- created_at: string;
54
- started_at?: string;
55
- completed_at?: string;
56
- duration_seconds?: number;
57
- max_duration_seconds?: number;
58
- transcript?: Array<Record<string, any>>;
59
- summary?: string;
60
- metadata: Record<string, any>;
61
- end_user_id?: string; // Marketplace end-user ID for privacy isolation
62
- }
63
-
64
- export interface ToolDefinition {
65
- name: string;
66
- description: string;
67
- input_schema: Record<string, any>;
68
- output_schema?: Record<string, any>;
69
- timeout_ms?: number;
70
- }
71
-
72
- export interface WebhookPayload {
73
- event: string;
74
- call_id: string;
75
- call_session_id: string;
76
- timestamp: string;
77
- data: Record<string, any>;
78
- }
14
+ import type {
15
+ PamelaClientConfig,
16
+ CreateCallRequest,
17
+ CallResponse,
18
+ CallStatus,
19
+ ToolDefinition,
20
+ } from './types';
79
21
 
80
22
  const mapAxiosError = (error: AxiosError, endpoint?: string): PamelaError => {
81
23
  const statusCode = error.response?.status;
@@ -259,25 +201,6 @@ export class PamelaClient {
259
201
  return response.data;
260
202
  }
261
203
 
262
- /**
263
- * Verify webhook signature.
264
- */
265
- static verifyWebhookSignature(
266
- payload: string | object,
267
- signature: string,
268
- secret: string
269
- ): boolean {
270
- const payloadString = typeof payload === 'string' ? payload : JSON.stringify(payload);
271
- const expectedSignature = crypto
272
- .createHmac('sha256', secret)
273
- .update(payloadString)
274
- .digest('hex');
275
-
276
- return crypto.timingSafeEqual(
277
- Buffer.from(signature),
278
- Buffer.from(expectedSignature)
279
- );
280
- }
281
204
  }
282
205
 
283
206
  // Export as both default and named export for flexibility
@@ -291,4 +214,7 @@ export {
291
214
  ValidationError,
292
215
  CallError,
293
216
  };
217
+ export * from './types';
218
+ // Webhooks are available via @thisispamela/sdk/webhooks subpath
219
+ // (not exported here to keep main bundle browser-compatible)
294
220
 
package/src/types.ts ADDED
@@ -0,0 +1,126 @@
1
+ export interface PamelaClientConfig {
2
+ apiKey: string;
3
+ baseUrl?: string;
4
+ }
5
+
6
+ export interface CreateCallRequest {
7
+ to: string;
8
+ country?: string;
9
+ locale?: string;
10
+ task: string;
11
+ instructions?: string;
12
+ max_duration_seconds?: number;
13
+ voice?: 'male' | 'female' | 'auto';
14
+ agent_name?: string;
15
+ caller_name?: string;
16
+ end_user_id?: string;
17
+ metadata?: Record<string, any>;
18
+ tools?: Array<Record<string, any>>;
19
+ webhooks?: {
20
+ webhook_url?: string;
21
+ tool_webhook_url?: string;
22
+ };
23
+ }
24
+
25
+ export type CallStatusValue =
26
+ | 'initiating'
27
+ | 'queued'
28
+ | 'ringing'
29
+ | 'in_progress'
30
+ | 'completed'
31
+ | 'failed'
32
+ | 'cancelled'
33
+ | 'timeout_terminated'
34
+ | 'in-progress';
35
+
36
+ export interface CallResponse {
37
+ id: string;
38
+ status: CallStatusValue | string;
39
+ call_session_id: string;
40
+ created_at: string;
41
+ }
42
+
43
+ export interface CallStatus {
44
+ id: string;
45
+ status: CallStatusValue | string;
46
+ to: string;
47
+ from_: string; // Backend uses from_ (Python keyword)
48
+ country: string;
49
+ created_at: string;
50
+ started_at?: string;
51
+ completed_at?: string;
52
+ duration_seconds?: number;
53
+ max_duration_seconds?: number;
54
+ transcript?: Array<Record<string, any>>;
55
+ summary?: string;
56
+ metadata: Record<string, any>;
57
+ end_user_id?: string; // Marketplace end-user ID for privacy isolation
58
+ }
59
+
60
+ export interface ToolDefinition {
61
+ name: string;
62
+ description: string;
63
+ input_schema: Record<string, any>;
64
+ output_schema?: Record<string, any>;
65
+ timeout_ms?: number;
66
+ }
67
+
68
+ export interface WebhookPayload {
69
+ event: string;
70
+ call_id: string;
71
+ call_session_id: string;
72
+ timestamp: string;
73
+ data: Record<string, any>;
74
+ }
75
+
76
+ /** Standard error codes (aligned with backend models/errors.py) */
77
+ export const ErrorCodes = {
78
+ // Auth errors (1000-1999)
79
+ AUTH_REQUIRED: 1001,
80
+ AUTH_INVALID: 1002,
81
+ AUTH_EXPIRED: 1003,
82
+ AUTH_INSUFFICIENT_PERMISSIONS: 1004,
83
+ AUTH_FORBIDDEN: 1005,
84
+
85
+ // Validation errors (2000-2999)
86
+ VALIDATION_ERROR: 2001,
87
+ INVALID_PHONE: 2002,
88
+ INVALID_EMAIL: 2003,
89
+ INVALID_PASSWORD: 2004,
90
+ MISSING_REQUIRED_FIELD: 2005,
91
+ INVALID_JSON: 2006,
92
+ INVALID_REQUEST_BODY: 2007,
93
+
94
+ // Not found errors (3000-3999)
95
+ NOT_FOUND: 3001,
96
+ USER_NOT_FOUND: 3002,
97
+ CONVERSATION_NOT_FOUND: 3003,
98
+ CALL_SESSION_NOT_FOUND: 3004,
99
+ RESOURCE_NOT_FOUND: 3005,
100
+ MESSAGE_NOT_FOUND: 3006,
101
+
102
+ // Conflict errors (4000-4999)
103
+ RESOURCE_ALREADY_EXISTS: 4001,
104
+ EMAIL_ALREADY_REGISTERED: 4002,
105
+ ACCOUNT_LINKING_REQUIRED: 4003,
106
+
107
+ // Server errors (5000-5999)
108
+ INTERNAL_ERROR: 5001,
109
+ EXTERNAL_SERVICE_ERROR: 5002,
110
+ DATABASE_ERROR: 5003,
111
+ CONFIGURATION_ERROR: 5004,
112
+
113
+ // Rate limiting (6000-6999)
114
+ RATE_LIMIT_EXCEEDED: 6001,
115
+ QUOTA_EXCEEDED: 6002,
116
+
117
+ // B2B errors (7000-7999)
118
+ B2B_PARTNER_NOT_FOUND: 7001,
119
+ B2B_PROJECT_NOT_FOUND: 7002,
120
+ B2B_CALL_NOT_FOUND: 7003,
121
+ B2B_NO_PHONE_NUMBER: 7004,
122
+ B2B_UNSUPPORTED_COUNTRY: 7005,
123
+ B2B_TOOL_EXECUTION_FAILED: 7006,
124
+ B2B_WEBHOOK_DELIVERY_FAILED: 7007,
125
+ SUBSCRIPTION_EXPIRED: 7008,
126
+ } as const;
@@ -0,0 +1,55 @@
1
+ import * as crypto from 'crypto';
2
+
3
+ export const verifyWebhookSignature = (
4
+ payload: string | object,
5
+ signature: string | undefined | null,
6
+ secret: string
7
+ ): boolean => {
8
+ if (!signature) {
9
+ return false;
10
+ }
11
+
12
+ if (!secret) {
13
+ throw new Error('Webhook secret cannot be empty');
14
+ }
15
+
16
+ const payloadString = typeof payload === 'string' ? payload : JSON.stringify(payload);
17
+ const expectedSignature = crypto
18
+ .createHmac('sha256', secret)
19
+ .update(payloadString)
20
+ .digest('hex');
21
+
22
+ return crypto.timingSafeEqual(
23
+ Buffer.from(signature),
24
+ Buffer.from(expectedSignature)
25
+ );
26
+ };
27
+
28
+ export const parseToolWebhook = (payload: Record<string, any>): {
29
+ tool_name: string;
30
+ arguments: Record<string, any>;
31
+ call_id: string;
32
+ correlation_id: string;
33
+ call_session_id?: string;
34
+ partner_id?: string;
35
+ project_id?: string;
36
+ } => {
37
+ const requiredFields = ['tool_name', 'arguments', 'call_id', 'correlation_id'];
38
+ const missing = requiredFields.filter((field) => !(field in payload));
39
+
40
+ if (missing.length > 0) {
41
+ throw new Error(`Missing required fields: ${missing.join(', ')}`);
42
+ }
43
+
44
+ return {
45
+ tool_name: String(payload.tool_name),
46
+ arguments: typeof payload.arguments === 'object' && payload.arguments
47
+ ? payload.arguments
48
+ : {},
49
+ call_id: String(payload.call_id),
50
+ correlation_id: String(payload.correlation_id),
51
+ call_session_id: payload.call_session_id,
52
+ partner_id: payload.partner_id,
53
+ project_id: payload.project_id,
54
+ };
55
+ };
package/tsup.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts', 'src/webhooks.ts', 'src/types.ts', 'src/errors.ts'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ clean: true,
8
+ sourcemap: true,
9
+ target: 'es2020',
10
+ });