@ecodrix/erix-api 1.2.0 → 1.2.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/dist/cli.js +5 -5
- package/dist/index.d.ts +283 -43
- package/dist/ts/browser/index.global.js +14 -14
- package/dist/ts/browser/index.global.js.map +1 -1
- package/dist/ts/cjs/index.cjs +1 -1
- package/dist/ts/cjs/index.cjs.map +1 -1
- package/dist/ts/cjs/index.d.cts +283 -43
- package/dist/ts/esm/index.d.ts +283 -43
- package/dist/ts/esm/index.js +1 -1
- package/dist/ts/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core.ts +16 -17
- package/src/index.ts +2 -0
- package/src/resources/crm/leads.ts +64 -0
- package/src/resources/crm/pipelines.ts +37 -1
- package/src/resources/email.ts +108 -26
- package/src/resources/health.ts +25 -22
- package/src/resources/logs.ts +97 -0
- package/src/resources/media.ts +6 -9
- package/src/resources/whatsapp/templates.ts +45 -0
- package/src/types/metadata.ts +71 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecodrix/erix-api",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"author": "ECODrIx Team <contact@ecodrix.com>",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Official Isomorphic SDK for the ECODrIx platform. Native support for WhatsApp, CRM, Storage, and Meetings across TS, JS, Python, and Java.",
|
package/src/core.ts
CHANGED
|
@@ -3,11 +3,12 @@ import axiosRetry from "axios-retry";
|
|
|
3
3
|
import { type Socket, io } from "socket.io-client";
|
|
4
4
|
import { APIError, AuthenticationError } from "./error";
|
|
5
5
|
import { CRM } from "./resources/crm";
|
|
6
|
-
import {
|
|
6
|
+
import { Email } from "./resources/email";
|
|
7
7
|
import { EventsResource } from "./resources/events";
|
|
8
8
|
import { Health } from "./resources/health";
|
|
9
|
+
import { Logs } from "./resources/logs";
|
|
9
10
|
import { Marketing } from "./resources/marketing";
|
|
10
|
-
import {
|
|
11
|
+
import { Media } from "./resources/media";
|
|
11
12
|
import { Meetings } from "./resources/meet";
|
|
12
13
|
import { Notifications } from "./resources/notifications";
|
|
13
14
|
import { Queue } from "./resources/queue";
|
|
@@ -90,7 +91,7 @@ export class Ecodrix {
|
|
|
90
91
|
public readonly crm: CRM;
|
|
91
92
|
|
|
92
93
|
/** Cloudflare R2-backed media storage. */
|
|
93
|
-
public readonly media:
|
|
94
|
+
public readonly media: Media;
|
|
94
95
|
|
|
95
96
|
/** Google Meet appointment scheduling. */
|
|
96
97
|
public readonly meet: Meetings;
|
|
@@ -98,8 +99,11 @@ export class Ecodrix {
|
|
|
98
99
|
/** Automation execution logs and provider webhook callbacks. */
|
|
99
100
|
public readonly notifications: Notifications;
|
|
100
101
|
|
|
101
|
-
/** Outbound email marketing engine. */
|
|
102
|
-
public readonly email:
|
|
102
|
+
/** Outbound email marketing engine and template management. */
|
|
103
|
+
public readonly email: Email;
|
|
104
|
+
|
|
105
|
+
/** Platform-wide execution logs and audit trails. */
|
|
106
|
+
public readonly logs: Logs;
|
|
103
107
|
|
|
104
108
|
/** Lead events and workflow automation triggers. */
|
|
105
109
|
public readonly events: EventsResource;
|
|
@@ -129,8 +133,7 @@ export class Ecodrix {
|
|
|
129
133
|
const baseUrl = options.baseUrl ?? ECOD_API_BASE;
|
|
130
134
|
const socketUrl = options.socketUrl || baseUrl;
|
|
131
135
|
|
|
132
|
-
const isBrowser =
|
|
133
|
-
typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
136
|
+
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
134
137
|
const runtime = isBrowser
|
|
135
138
|
? "browser"
|
|
136
139
|
: typeof process !== "undefined"
|
|
@@ -163,14 +166,11 @@ export class Ecodrix {
|
|
|
163
166
|
retryDelay: axiosRetry.exponentialDelay,
|
|
164
167
|
retryCondition: (error) => {
|
|
165
168
|
return (
|
|
166
|
-
axiosRetry.isNetworkOrIdempotentRequestError(error) ||
|
|
167
|
-
error.response?.status === 429
|
|
169
|
+
axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 429
|
|
168
170
|
);
|
|
169
171
|
},
|
|
170
172
|
onRetry: (retryCount, error, requestConfig) => {
|
|
171
|
-
const isDev =
|
|
172
|
-
typeof process !== "undefined" &&
|
|
173
|
-
process.env?.NODE_ENV === "development";
|
|
173
|
+
const isDev = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
|
|
174
174
|
if (isDev) {
|
|
175
175
|
console.warn(
|
|
176
176
|
`[ECODrIx SDK] Retrying request (${retryCount}/3): ${requestConfig.method?.toUpperCase()} ${requestConfig.url}. Reason: ${error.message}`,
|
|
@@ -182,10 +182,11 @@ export class Ecodrix {
|
|
|
182
182
|
// Initialise resources
|
|
183
183
|
this.whatsapp = new WhatsApp(this.client);
|
|
184
184
|
this.crm = new CRM(this.client);
|
|
185
|
-
this.media = new
|
|
185
|
+
this.media = new Media(this.client);
|
|
186
186
|
this.meet = new Meetings(this.client);
|
|
187
187
|
this.notifications = new Notifications(this.client);
|
|
188
|
-
this.email = new
|
|
188
|
+
this.email = new Email(this.client);
|
|
189
|
+
this.logs = new Logs(this.client);
|
|
189
190
|
this.events = new EventsResource(this.client);
|
|
190
191
|
this.webhooks = new Webhooks();
|
|
191
192
|
this.storage = new Storage(this.client);
|
|
@@ -323,9 +324,7 @@ export class Ecodrix {
|
|
|
323
324
|
} catch (error: any) {
|
|
324
325
|
if (error.response) {
|
|
325
326
|
throw new APIError(
|
|
326
|
-
error.response.data?.message ||
|
|
327
|
-
error.response.data?.error ||
|
|
328
|
-
"Raw Execution Failed",
|
|
327
|
+
error.response.data?.message || error.response.data?.error || "Raw Execution Failed",
|
|
329
328
|
error.response.status,
|
|
330
329
|
error.response.data?.code,
|
|
331
330
|
);
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { Ecodrix, type EcodrixOptions } from "./core";
|
|
2
|
+
export * from "./types/metadata";
|
|
2
3
|
export * from "./error";
|
|
3
4
|
export * from "./resources/crm/activities";
|
|
4
5
|
export * from "./resources/crm/analytics";
|
|
@@ -13,6 +14,7 @@ export * from "./resources/crm/sequences";
|
|
|
13
14
|
export * from "./resources/email";
|
|
14
15
|
export * from "./resources/events";
|
|
15
16
|
export * from "./resources/health";
|
|
17
|
+
export * from "./resources/logs";
|
|
16
18
|
export * from "./resources/marketing";
|
|
17
19
|
export * from "./resources/media";
|
|
18
20
|
export * from "./resources/meet";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { APIResource } from "../../resource";
|
|
2
|
+
import type { ResourceManifest } from "../../types/metadata";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Valid statuses for a CRM Lead.
|
|
@@ -102,6 +103,69 @@ export class Leads extends APIResource {
|
|
|
102
103
|
return this.post<T>("/api/crm/leads", params);
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Introspect the Leads resource and provide a "Blueprint" for UI generation.
|
|
108
|
+
*
|
|
109
|
+
* This method returns a list of all fields (standard + custom), their types,
|
|
110
|
+
* labels, and suggested UI controls. Erix React uses this to render SmartForms
|
|
111
|
+
* and tables dynamically.
|
|
112
|
+
*/
|
|
113
|
+
async describe(): Promise<ResourceManifest> {
|
|
114
|
+
// 1. Fetch custom fields from the tenant configuration
|
|
115
|
+
const customFieldsRes: any = await this.fields();
|
|
116
|
+
const customFields = Array.isArray(customFieldsRes.data) ? customFieldsRes.data : [];
|
|
117
|
+
|
|
118
|
+
// 2. Define the core system fields
|
|
119
|
+
const systemFields: any[] = [
|
|
120
|
+
{
|
|
121
|
+
key: "firstName",
|
|
122
|
+
label: "First Name",
|
|
123
|
+
type: "string",
|
|
124
|
+
required: true,
|
|
125
|
+
group: "Basic Info",
|
|
126
|
+
},
|
|
127
|
+
{ key: "lastName", label: "Last Name", type: "string", required: false, group: "Basic Info" },
|
|
128
|
+
{ key: "phone", label: "Phone Number", type: "phone", required: true, group: "Contact" },
|
|
129
|
+
{ key: "email", label: "Email Address", type: "email", required: false, group: "Contact" },
|
|
130
|
+
{
|
|
131
|
+
key: "status",
|
|
132
|
+
label: "Status",
|
|
133
|
+
type: "select",
|
|
134
|
+
required: true,
|
|
135
|
+
options: [
|
|
136
|
+
{ label: "New", value: "new" },
|
|
137
|
+
{ label: "Contacted", value: "contacted" },
|
|
138
|
+
{ label: "Qualified", value: "qualified" },
|
|
139
|
+
{ label: "Won", value: "won" },
|
|
140
|
+
{ label: "Lost", value: "lost" },
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
{ key: "value", label: "Lead Value", type: "currency", required: false },
|
|
144
|
+
{ key: "source", label: "Source", type: "string", required: false },
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
// 3. Map custom fields to FieldManifest shape
|
|
148
|
+
const mappedCustom = customFields.map((f: any) => ({
|
|
149
|
+
key: `metadata.extra.${f.name}`,
|
|
150
|
+
label: f.label || f.name,
|
|
151
|
+
type: f.type || "string",
|
|
152
|
+
required: !!f.required,
|
|
153
|
+
options: f.options,
|
|
154
|
+
group: "Custom Fields",
|
|
155
|
+
}));
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
name: "Lead",
|
|
159
|
+
fields: [...systemFields, ...mappedCustom],
|
|
160
|
+
uiHints: {
|
|
161
|
+
icon: "User",
|
|
162
|
+
primaryColor: "#3b82f6",
|
|
163
|
+
defaultSort: { field: "createdAt", direction: "desc" },
|
|
164
|
+
summaryFields: ["firstName", "lastName", "phone", "status"],
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
105
169
|
/**
|
|
106
170
|
* Upsert a lead by phone number. If a lead with the same phone exists,
|
|
107
171
|
* it will be updated; otherwise, a new lead is created.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { APIResource } from "../../resource";
|
|
2
|
+
import type { ResourceManifest } from "../../types/metadata";
|
|
2
3
|
|
|
3
4
|
export interface CreatePipelineParams {
|
|
4
5
|
name: string;
|
|
@@ -26,6 +27,39 @@ export class Pipelines extends APIResource {
|
|
|
26
27
|
return this.get<T>("/api/crm/pipelines");
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Introspect a pipeline and provide a manifest of its stages.
|
|
32
|
+
*
|
|
33
|
+
* Returns metadata about stage colors, probabilities, and order.
|
|
34
|
+
* Erix React uses this to build kanban boards and stage pickers.
|
|
35
|
+
*
|
|
36
|
+
* @param pipelineId - The unique ID of the pipeline.
|
|
37
|
+
*/
|
|
38
|
+
async getStageManifest(pipelineId: string): Promise<ResourceManifest> {
|
|
39
|
+
const pipeline: any = await this.retrieve(pipelineId);
|
|
40
|
+
const stages = Array.isArray(pipeline.data?.stages) ? pipeline.data.stages : [];
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
name: `Pipeline: ${pipeline.data?.name || pipelineId}`,
|
|
44
|
+
fields: stages.map((s: any) => ({
|
|
45
|
+
key: s._id,
|
|
46
|
+
label: s.name,
|
|
47
|
+
type: "string", // Labels are strings
|
|
48
|
+
required: true,
|
|
49
|
+
options: [{ label: s.name, value: s._id }],
|
|
50
|
+
group: "Stages",
|
|
51
|
+
uiHints: {
|
|
52
|
+
color: s.color || "#cbd5e1",
|
|
53
|
+
probability: s.probability,
|
|
54
|
+
},
|
|
55
|
+
})) as any,
|
|
56
|
+
uiHints: {
|
|
57
|
+
icon: "Columns",
|
|
58
|
+
primaryColor: "#6366f1",
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
29
63
|
/**
|
|
30
64
|
* Create a new CRM sales or support pipeline.
|
|
31
65
|
*
|
|
@@ -74,7 +108,9 @@ export class Pipelines extends APIResource {
|
|
|
74
108
|
* Duplicate a pipeline with a new name.
|
|
75
109
|
*/
|
|
76
110
|
async duplicate<T = any>(pipelineId: string, newName: string) {
|
|
77
|
-
return this.post<T>(`/api/crm/pipelines/${pipelineId}/duplicate`, {
|
|
111
|
+
return this.post<T>(`/api/crm/pipelines/${pipelineId}/duplicate`, {
|
|
112
|
+
newName,
|
|
113
|
+
});
|
|
78
114
|
}
|
|
79
115
|
|
|
80
116
|
/**
|
package/src/resources/email.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { AxiosInstance } from "axios";
|
|
2
|
-
import { APIError } from "../error";
|
|
3
1
|
import { APIResource } from "../resource";
|
|
4
2
|
|
|
5
3
|
/**
|
|
@@ -23,38 +21,122 @@ export interface CampaignResult {
|
|
|
23
21
|
[key: string]: any;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
export
|
|
24
|
+
export interface EmailTemplate {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
subject: string;
|
|
29
|
+
preheader?: string;
|
|
30
|
+
htmlBody: string;
|
|
31
|
+
textBody?: string;
|
|
32
|
+
category: "marketing" | "transactional" | "sequence";
|
|
33
|
+
status: "draft" | "published" | "archived";
|
|
34
|
+
type: "standard" | "layout";
|
|
35
|
+
layoutId?: string;
|
|
36
|
+
thumbnail?: string;
|
|
37
|
+
variableMapping?: any[];
|
|
38
|
+
createdAt: string;
|
|
39
|
+
updatedAt: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface CreateTemplateDTO {
|
|
43
|
+
name: string;
|
|
44
|
+
subject: string;
|
|
45
|
+
htmlBody: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
category?: "marketing" | "transactional" | "sequence";
|
|
48
|
+
status?: "draft" | "published" | "archived";
|
|
49
|
+
variableMapping?: any[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface TemplatePreviewResponse {
|
|
53
|
+
success: boolean;
|
|
54
|
+
data: {
|
|
55
|
+
subject: string;
|
|
56
|
+
html: string;
|
|
57
|
+
text?: string;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Outbound email marketing engine and template management.
|
|
63
|
+
*
|
|
64
|
+
* Access via `ecod.email`.
|
|
65
|
+
*/
|
|
66
|
+
export class Email extends APIResource {
|
|
27
67
|
/**
|
|
28
68
|
* Send an HTML email campaign to a list of recipients.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
* @returns The dispatch result indicating success or failure.
|
|
32
|
-
* @example
|
|
33
|
-
* ```typescript
|
|
34
|
-
* await erixClient.email.sendEmailCampaign({
|
|
35
|
-
* recipients: ["user1@example.com", "user2@example.com"],
|
|
36
|
-
* subject: "Monthly Newsletter",
|
|
37
|
-
* html: "<h1>Hello!</h1><p>Check out our latest updates...</p>"
|
|
38
|
-
* });
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
async sendEmailCampaign(payload: SendCampaignPayload): Promise<CampaignResult> {
|
|
69
|
+
*/
|
|
70
|
+
async sendCampaign(payload: SendCampaignPayload): Promise<CampaignResult> {
|
|
42
71
|
return this.post<CampaignResult>("/api/saas/emails/campaign", payload);
|
|
43
72
|
}
|
|
44
73
|
|
|
45
74
|
/**
|
|
46
75
|
* Send a system test email to validate your current SMTP configuration.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
* @returns The dispatch result.
|
|
50
|
-
* @example
|
|
51
|
-
* ```typescript
|
|
52
|
-
* await erixClient.email.sendTestEmail("admin@company.com");
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
async sendTestEmail(to: string): Promise<CampaignResult> {
|
|
76
|
+
*/
|
|
77
|
+
async sendTest(to: string): Promise<CampaignResult> {
|
|
56
78
|
return this.post<CampaignResult>("/api/saas/emails/test", { to });
|
|
57
79
|
}
|
|
58
80
|
|
|
59
|
-
//
|
|
81
|
+
// --- Template Management ---
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* List all email templates.
|
|
85
|
+
*/
|
|
86
|
+
async listTemplates(query?: any): Promise<{ success: boolean; data: EmailTemplate[] }> {
|
|
87
|
+
return this.get<{ success: boolean; data: EmailTemplate[] }>("/api/saas/mail/templates", {
|
|
88
|
+
params: query,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get a single email template by ID.
|
|
94
|
+
*/
|
|
95
|
+
async getTemplate(id: string): Promise<{ success: boolean; data: EmailTemplate }> {
|
|
96
|
+
return this.get<{ success: boolean; data: EmailTemplate }>(`/api/saas/mail/templates/${id}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create a new email template.
|
|
101
|
+
*/
|
|
102
|
+
async createTemplate(
|
|
103
|
+
data: CreateTemplateDTO,
|
|
104
|
+
): Promise<{ success: boolean; data: EmailTemplate }> {
|
|
105
|
+
return this.post<{ success: boolean; data: EmailTemplate }>("/api/saas/mail/templates", data);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Update an existing email template.
|
|
110
|
+
*/
|
|
111
|
+
async updateTemplate(
|
|
112
|
+
id: string,
|
|
113
|
+
data: Partial<CreateTemplateDTO>,
|
|
114
|
+
): Promise<{ success: boolean; data: EmailTemplate }> {
|
|
115
|
+
return this.put<{ success: boolean; data: EmailTemplate }>(
|
|
116
|
+
`/api/saas/mail/templates/${id}`,
|
|
117
|
+
data,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Delete an email template.
|
|
123
|
+
*/
|
|
124
|
+
async deleteTemplate(id: string, force = false): Promise<{ success: boolean }> {
|
|
125
|
+
return this.deleteRequest<{ success: boolean }>(`/api/saas/mail/templates/${id}`, {
|
|
126
|
+
params: { force },
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Preview a template with dynamic variable resolution.
|
|
132
|
+
*/
|
|
133
|
+
async previewTemplate(
|
|
134
|
+
id: string,
|
|
135
|
+
params: { leadId?: string; variables?: Record<string, any> },
|
|
136
|
+
): Promise<TemplatePreviewResponse> {
|
|
137
|
+
return this.post<TemplatePreviewResponse>(`/api/saas/mail/templates/${id}/preview`, params);
|
|
138
|
+
}
|
|
60
139
|
}
|
|
140
|
+
|
|
141
|
+
/** @deprecated Use Email instead */
|
|
142
|
+
export class EmailResource extends Email {}
|
package/src/resources/health.ts
CHANGED
|
@@ -34,48 +34,51 @@ export interface JobStatus {
|
|
|
34
34
|
createdAt: string;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Platform and tenant-specific health diagnostics.
|
|
39
|
+
*
|
|
40
|
+
* Access via `ecod.health`.
|
|
41
|
+
*/
|
|
37
42
|
export class Health extends APIResource {
|
|
38
43
|
/**
|
|
39
44
|
* Perform a global platform health check.
|
|
40
|
-
* Verify that the API, database, and background workers are operational.
|
|
41
|
-
*
|
|
42
|
-
* @returns System health summary (status, version, uptime).
|
|
43
|
-
* @example
|
|
44
|
-
* ```typescript
|
|
45
|
-
* const health = await erixClient.health.system();
|
|
46
|
-
* console.log(`API Status: ${health.status}`);
|
|
47
|
-
* ```
|
|
45
|
+
* Verify that the core API, database, and background workers are operational.
|
|
48
46
|
*/
|
|
49
47
|
async system(): Promise<SystemHealth> {
|
|
50
|
-
const res = await this.get<{ data: SystemHealth }>("/api/saas/health"
|
|
51
|
-
headers: { accept: "application/json" },
|
|
52
|
-
});
|
|
48
|
+
const res = await this.get<{ success: boolean; data: SystemHealth }>("/api/saas/health");
|
|
53
49
|
return res.data;
|
|
54
50
|
}
|
|
55
51
|
|
|
56
52
|
/**
|
|
57
|
-
* Tenant-specific health check.
|
|
53
|
+
* Tenant-specific health check.
|
|
54
|
+
*
|
|
55
|
+
* Identifies correctly configured third-party integrations (WhatsApp, SMTP, Google Meet)
|
|
56
|
+
* and reports active automation counts.
|
|
58
57
|
*/
|
|
59
58
|
async clientHealth(): Promise<ClientHealth> {
|
|
60
|
-
const res = await this.get<{ data: ClientHealth }>("/api/saas/health/client");
|
|
59
|
+
const res = await this.get<{ success: boolean; data: ClientHealth }>("/api/saas/health/client");
|
|
61
60
|
return res.data;
|
|
62
61
|
}
|
|
63
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Alias for clientHealth to match diagnostic terminology.
|
|
65
|
+
*/
|
|
66
|
+
async getDiagnosticReport(): Promise<ClientHealth> {
|
|
67
|
+
return this.clientHealth();
|
|
68
|
+
}
|
|
69
|
+
|
|
64
70
|
/**
|
|
65
71
|
* Lookup the execution status of a background job.
|
|
66
72
|
*
|
|
73
|
+
* Use this to poll for completion of long-running tasks like bulk exports
|
|
74
|
+
* or campaign dispatches.
|
|
75
|
+
*
|
|
67
76
|
* @param jobId - The unique ID of the background job.
|
|
68
|
-
* @returns Job status report (attempts, error trace, completion time).
|
|
69
|
-
* @example
|
|
70
|
-
* ```typescript
|
|
71
|
-
* const status = await erixClient.health.jobStatus("job_123");
|
|
72
|
-
* if (status.status === "completed") {
|
|
73
|
-
* console.log("Job finished successfully!");
|
|
74
|
-
* }
|
|
75
|
-
* ```
|
|
76
77
|
*/
|
|
77
78
|
async jobStatus(jobId: string): Promise<JobStatus> {
|
|
78
|
-
const res = await this.get<{ data: JobStatus }>(
|
|
79
|
+
const res = await this.get<{ success: boolean; data: JobStatus }>(
|
|
80
|
+
`/api/saas/jobs/status/${jobId}`,
|
|
81
|
+
);
|
|
79
82
|
return res.data;
|
|
80
83
|
}
|
|
81
84
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { APIResource } from "../resource";
|
|
2
|
+
|
|
3
|
+
export interface LogPaginationQuery {
|
|
4
|
+
page?: number;
|
|
5
|
+
limit?: number;
|
|
6
|
+
trigger?: string;
|
|
7
|
+
status?: "received" | "processing" | "completed" | "partial" | "failed";
|
|
8
|
+
from?: string;
|
|
9
|
+
to?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface EventLog {
|
|
13
|
+
id: string;
|
|
14
|
+
trigger: string;
|
|
15
|
+
phone?: string;
|
|
16
|
+
email?: string;
|
|
17
|
+
status: "received" | "processing" | "completed" | "partial" | "failed";
|
|
18
|
+
rulesMatched: number;
|
|
19
|
+
jobsCreated: number;
|
|
20
|
+
meetLink?: string;
|
|
21
|
+
callbackUrl?: string;
|
|
22
|
+
callbackStatus: "not_required" | "sent" | "failed";
|
|
23
|
+
payload: any;
|
|
24
|
+
error?: string;
|
|
25
|
+
idempotencyKey?: string;
|
|
26
|
+
processedAt?: string;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface CallbackLog {
|
|
32
|
+
id: string;
|
|
33
|
+
callbackUrl: string;
|
|
34
|
+
method: string;
|
|
35
|
+
payload: any;
|
|
36
|
+
jobId?: string;
|
|
37
|
+
enrollmentId?: string;
|
|
38
|
+
responseStatus: number;
|
|
39
|
+
responseBody: string;
|
|
40
|
+
status: "sent" | "failed" | "pending_retry";
|
|
41
|
+
attempts: number;
|
|
42
|
+
lastAttemptAt?: string;
|
|
43
|
+
signature?: string;
|
|
44
|
+
createdAt: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface LogResponse<T> {
|
|
48
|
+
success: boolean;
|
|
49
|
+
data: T[];
|
|
50
|
+
pagination: {
|
|
51
|
+
total: number;
|
|
52
|
+
page: number;
|
|
53
|
+
limit: number;
|
|
54
|
+
pages: number;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Audit and execution logs for platform events and webhooks.
|
|
60
|
+
*
|
|
61
|
+
* Access via `ecod.logs`.
|
|
62
|
+
*/
|
|
63
|
+
export class Logs extends APIResource {
|
|
64
|
+
/**
|
|
65
|
+
* List event execution logs with optional filtering.
|
|
66
|
+
*
|
|
67
|
+
* Use this to audit automation triggers and debug workflow execution.
|
|
68
|
+
*/
|
|
69
|
+
async listEventLogs(query?: LogPaginationQuery): Promise<LogResponse<EventLog>> {
|
|
70
|
+
return this.get<LogResponse<EventLog>>("/api/saas/events/logs", {
|
|
71
|
+
params: query,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get detailed information for a single event execution.
|
|
77
|
+
*/
|
|
78
|
+
async getEventLog(id: string): Promise<{ success: boolean; data: EventLog }> {
|
|
79
|
+
return this.get<{ success: boolean; data: EventLog }>(`/api/saas/events/logs/${id}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* List webhook callback logs (outbound responses from ECODrIx to your system).
|
|
84
|
+
*/
|
|
85
|
+
async listCallbackLogs(query?: LogPaginationQuery): Promise<LogResponse<CallbackLog>> {
|
|
86
|
+
return this.get<LogResponse<CallbackLog>>("/api/saas/callbacks/logs", {
|
|
87
|
+
params: query,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get high-level execution statistics for the tenant.
|
|
93
|
+
*/
|
|
94
|
+
async getStats(): Promise<{ success: boolean; data: any }> {
|
|
95
|
+
return this.get<{ success: boolean; data: any }>("/api/saas/events/stats");
|
|
96
|
+
}
|
|
97
|
+
}
|
package/src/resources/media.ts
CHANGED
|
@@ -41,7 +41,7 @@ export interface UploadOptions {
|
|
|
41
41
|
* console.log(data.url); // → https://cdn.ecodrix.com/invoices/invoice-001.pdf
|
|
42
42
|
* ```
|
|
43
43
|
*/
|
|
44
|
-
export class
|
|
44
|
+
export class Media extends APIResource {
|
|
45
45
|
/**
|
|
46
46
|
* Get current storage usage metrics for the tenant.
|
|
47
47
|
*
|
|
@@ -83,10 +83,7 @@ export class MediaResource extends APIResource {
|
|
|
83
83
|
* const { data: files } = await ecod.media.list("invoices", { q: "contract" });
|
|
84
84
|
* ```
|
|
85
85
|
*/
|
|
86
|
-
async list(
|
|
87
|
-
folder: string,
|
|
88
|
-
params?: { year?: string; month?: string; q?: string },
|
|
89
|
-
) {
|
|
86
|
+
async list(folder: string, params?: { year?: string; month?: string; q?: string }) {
|
|
90
87
|
return this.get(`/api/saas/storage/files/${folder}`, { params } as any);
|
|
91
88
|
}
|
|
92
89
|
|
|
@@ -158,10 +155,7 @@ export class MediaResource extends APIResource {
|
|
|
158
155
|
*/
|
|
159
156
|
async upload(file: any, options: UploadOptions): Promise<any> {
|
|
160
157
|
// Step 1: Get presigned URL
|
|
161
|
-
const response = await this.post<any>(
|
|
162
|
-
"/api/saas/storage/upload-url",
|
|
163
|
-
options,
|
|
164
|
-
);
|
|
158
|
+
const response = await this.post<any>("/api/saas/storage/upload-url", options);
|
|
165
159
|
const { uploadUrl, key } = response.data;
|
|
166
160
|
|
|
167
161
|
// Step 2: Upload directly to R2 (bypasses the API server for performance)
|
|
@@ -175,3 +169,6 @@ export class MediaResource extends APIResource {
|
|
|
175
169
|
return this.post("/api/saas/storage/confirm-upload", { key, sizeBytes });
|
|
176
170
|
}
|
|
177
171
|
}
|
|
172
|
+
|
|
173
|
+
/** @deprecated Use Media instead */
|
|
174
|
+
export class MediaResource extends Media {}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { APIResource } from "../../resource";
|
|
2
|
+
import type { ResourceManifest } from "../../types/metadata";
|
|
2
3
|
|
|
3
4
|
export interface TemplateMapping {
|
|
4
5
|
mappings: any[];
|
|
@@ -164,6 +165,50 @@ export class Templates extends APIResource {
|
|
|
164
165
|
});
|
|
165
166
|
}
|
|
166
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Introspect a template and provide a manifest of its required variables.
|
|
170
|
+
*
|
|
171
|
+
* This is used by Erix React to build dynamic "Mapping Forms" where users
|
|
172
|
+
* can connect CRM fields to WhatsApp variables.
|
|
173
|
+
*
|
|
174
|
+
* @param templateIdentifier - The name or ID of the template.
|
|
175
|
+
*/
|
|
176
|
+
async getVariableManifest(templateIdentifier: string): Promise<ResourceManifest> {
|
|
177
|
+
const template: any = await this.retrieve(templateIdentifier);
|
|
178
|
+
const components = Array.isArray(template.data?.components) ? template.data.components : [];
|
|
179
|
+
|
|
180
|
+
const fields: any[] = [];
|
|
181
|
+
|
|
182
|
+
for (const comp of components) {
|
|
183
|
+
// Look for {{n}} pattern in text components
|
|
184
|
+
if (comp.text) {
|
|
185
|
+
const vars = comp.text.match(/{{(\d+)}}/g);
|
|
186
|
+
if (vars) {
|
|
187
|
+
for (const v of vars) {
|
|
188
|
+
const index = v.replace(/{{|}}/g, "");
|
|
189
|
+
fields.push({
|
|
190
|
+
key: `var_${index}`,
|
|
191
|
+
label: `${comp.type} Var {{${index}}}`,
|
|
192
|
+
type: "string",
|
|
193
|
+
required: true,
|
|
194
|
+
group: comp.type,
|
|
195
|
+
description: `Variable placeholder in template ${comp.type}`,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
name: `Template variables: ${template.data?.name || templateIdentifier}`,
|
|
204
|
+
fields,
|
|
205
|
+
uiHints: {
|
|
206
|
+
icon: "Variables",
|
|
207
|
+
primaryColor: "#059669",
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
167
212
|
/**
|
|
168
213
|
* Check which automations or sequences are currently using this template.
|
|
169
214
|
*/
|