@zentto/platform-client 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.
- package/LICENSE +21 -0
- package/README.md +72 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/notify/client.d.ts +149 -0
- package/dist/notify/client.d.ts.map +1 -0
- package/dist/notify/client.js +133 -0
- package/dist/notify/client.js.map +1 -0
- package/dist/notify/index.d.ts +2 -0
- package/dist/notify/index.d.ts.map +1 -0
- package/dist/notify/index.js +2 -0
- package/dist/notify/index.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zentto ERP
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# @zentto/platform-client
|
|
2
|
+
|
|
3
|
+
Cliente oficial tipado para los servicios de plataforma Zentto: **notify**, **cache** (pronto), **auth** (pronto), **landing** (pronto).
|
|
4
|
+
|
|
5
|
+
Úsalo desde el ERP, cualquier vertical (hotel, medical, tickets, rental, education, inmobiliario…) o un sitio externo de un tenant cliente.
|
|
6
|
+
|
|
7
|
+
## Instalación
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @zentto/platform-client
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Uso rápido
|
|
14
|
+
|
|
15
|
+
### Server-to-server (ERP API, vertical, backoffice)
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { notify } from "@zentto/platform-client";
|
|
19
|
+
|
|
20
|
+
const n = notify.notifyFromEnv();
|
|
21
|
+
|
|
22
|
+
// Email con template centralizado en notify.zentto.net
|
|
23
|
+
await n.email.sendTemplate("lead-confirmacion", {
|
|
24
|
+
to: "lead@acme.com",
|
|
25
|
+
variables: { firstName: "Juan", topicLabel: "Demo" },
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Contactos (CRM notify para campañas/unsubscribe/tracking)
|
|
29
|
+
await n.contacts.upsert({ email, name, phone, tags: ["hotel", "booking"] });
|
|
30
|
+
|
|
31
|
+
// OTP por email o SMS
|
|
32
|
+
await n.otp.send({ channel: "email", destination: email });
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Variables de entorno:
|
|
36
|
+
|
|
37
|
+
| Var | Default | Notas |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `NOTIFY_API_URL` | `https://notify.zentto.net` | Endpoint del servicio |
|
|
40
|
+
| `NOTIFY_API_KEY` | — | Master key del servicio (server-to-server) |
|
|
41
|
+
| `API_MASTER_KEY` | — | Fallback legacy |
|
|
42
|
+
|
|
43
|
+
### Construcción manual (multi-tenant, tests)
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { notify } from "@zentto/platform-client";
|
|
47
|
+
|
|
48
|
+
const n = new notify.NotifyClient({
|
|
49
|
+
baseUrl: "https://notify-dev.zentto.net",
|
|
50
|
+
apiKey: process.env.NOTIFY_DEV_KEY!,
|
|
51
|
+
timeoutMs: 5000,
|
|
52
|
+
retries: 2,
|
|
53
|
+
onError: (err, ctx) => logger.error({ err, ctx }, "[notify] failed"),
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Principios
|
|
58
|
+
|
|
59
|
+
1. **Best-effort**: los métodos de negocio nunca tumban el flujo de negocio. Retornan `{ ok: false, error }` cuando algo falla.
|
|
60
|
+
2. **Retries con backoff exponencial** en errores de red o 5xx; sin retry en 4xx.
|
|
61
|
+
3. **Typed**: todos los inputs/outputs tienen interfaces exportadas.
|
|
62
|
+
4. **Sin dependencias externas**: usa `fetch` nativo de Node 20+ / navegadores modernos.
|
|
63
|
+
|
|
64
|
+
## Documentación extendida
|
|
65
|
+
|
|
66
|
+
Arquitectura, matriz de auth por contexto y guía de adopción:
|
|
67
|
+
|
|
68
|
+
- `docs/wiki/14-integracion-ecosistema.md` en [zentto-erp/zentto-web](https://github.com/zentto-erp/zentto-web).
|
|
69
|
+
|
|
70
|
+
## Licencia
|
|
71
|
+
|
|
72
|
+
MIT © Zentto ERP
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Barrel del platform-client. Cada submódulo expone su propia API; acá
|
|
2
|
+
// re-exportamos en namespaces para llamadas tipo `platform.notify.email.send(...)`.
|
|
3
|
+
export * as notify from "./notify/index.js";
|
|
4
|
+
// Placeholders — se llenan cuando se migren cache/auth/landing al mismo patrón.
|
|
5
|
+
// export * as cache from "./cache/index.js";
|
|
6
|
+
// export * as auth from "./auth/index.js";
|
|
7
|
+
// export * as landing from "./landing/index.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,oFAAoF;AAEpF,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAE5C,gFAAgF;AAChF,6CAA6C;AAC7C,2CAA2C;AAC3C,iDAAiD"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NotifyClient — único cliente tipado para https://notify.zentto.net.
|
|
3
|
+
*
|
|
4
|
+
* Diseño:
|
|
5
|
+
* - Factory (no singleton global) → permite tests y múltiples instancias
|
|
6
|
+
* (p.ej. enviar como tenant X vs tenant master master-key).
|
|
7
|
+
* - Best-effort por default en los métodos de negocio (nunca lanzan). Los
|
|
8
|
+
* métodos bajos (`request`) sí propagan errores para que el caller decida.
|
|
9
|
+
* - Timeouts + 1 retry exponencial en errores de red (no en 4xx).
|
|
10
|
+
* - Sin dependencias externas: usa fetch nativo de Node 20+.
|
|
11
|
+
*/
|
|
12
|
+
export interface NotifyConfig {
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/** Timeout por request en ms. Default 10000. */
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
/** Cantidad de reintentos ante fallos de red o 5xx. Default 1. */
|
|
18
|
+
retries?: number;
|
|
19
|
+
/** Hook para logs/observability. Default no-op. */
|
|
20
|
+
onError?: (err: Error, context: {
|
|
21
|
+
path: string;
|
|
22
|
+
attempt: number;
|
|
23
|
+
}) => void;
|
|
24
|
+
}
|
|
25
|
+
export interface NotifyResult<T = unknown> {
|
|
26
|
+
ok: boolean;
|
|
27
|
+
messageId?: string;
|
|
28
|
+
via?: string;
|
|
29
|
+
data?: T;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface SendEmailParams {
|
|
33
|
+
to: string | string[];
|
|
34
|
+
subject?: string;
|
|
35
|
+
html?: string;
|
|
36
|
+
text?: string;
|
|
37
|
+
from?: string;
|
|
38
|
+
replyTo?: string;
|
|
39
|
+
/** Si se pasa, sobreescribe subject/html con el template de notify. */
|
|
40
|
+
templateId?: string;
|
|
41
|
+
variables?: Record<string, string>;
|
|
42
|
+
track?: boolean;
|
|
43
|
+
attachments?: Array<{
|
|
44
|
+
filename: string;
|
|
45
|
+
content?: string;
|
|
46
|
+
path?: string;
|
|
47
|
+
contentType?: string;
|
|
48
|
+
encoding?: string;
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
export interface UpsertContactParams {
|
|
52
|
+
email: string;
|
|
53
|
+
name?: string;
|
|
54
|
+
phone?: string;
|
|
55
|
+
company?: string;
|
|
56
|
+
country?: string;
|
|
57
|
+
tags?: string[];
|
|
58
|
+
metadata?: Record<string, string | number | null>;
|
|
59
|
+
subscribed?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface SendOtpParams {
|
|
62
|
+
channel: "email" | "sms";
|
|
63
|
+
destination: string;
|
|
64
|
+
carrier?: string;
|
|
65
|
+
brandName?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface VerifyOtpParams {
|
|
68
|
+
channel: "email" | "sms";
|
|
69
|
+
destination: string;
|
|
70
|
+
code: string;
|
|
71
|
+
}
|
|
72
|
+
export interface SendWebPushParams {
|
|
73
|
+
subscription: {
|
|
74
|
+
endpoint: string;
|
|
75
|
+
keys: {
|
|
76
|
+
p256dh: string;
|
|
77
|
+
auth: string;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
title: string;
|
|
81
|
+
body: string;
|
|
82
|
+
icon?: string;
|
|
83
|
+
url?: string;
|
|
84
|
+
data?: Record<string, unknown>;
|
|
85
|
+
}
|
|
86
|
+
export declare class NotifyClient {
|
|
87
|
+
private readonly baseUrl;
|
|
88
|
+
private readonly apiKey;
|
|
89
|
+
private readonly timeoutMs;
|
|
90
|
+
private readonly retries;
|
|
91
|
+
private readonly onError;
|
|
92
|
+
constructor(cfg: NotifyConfig);
|
|
93
|
+
request<T = unknown>(method: "POST" | "GET" | "DELETE" | "PUT", path: string, body?: object): Promise<NotifyResult<T>>;
|
|
94
|
+
email: {
|
|
95
|
+
send: (params: SendEmailParams) => Promise<NotifyResult>;
|
|
96
|
+
sendQueued: (params: SendEmailParams & {
|
|
97
|
+
scheduledAt?: string;
|
|
98
|
+
}) => Promise<NotifyResult>;
|
|
99
|
+
/** Atajo: `email.sendTemplate('lead-confirmacion', { to, variables })` */
|
|
100
|
+
sendTemplate: (templateId: string, opts: {
|
|
101
|
+
to: string | string[];
|
|
102
|
+
variables: Record<string, string>;
|
|
103
|
+
replyTo?: string;
|
|
104
|
+
from?: string;
|
|
105
|
+
track?: boolean;
|
|
106
|
+
}) => Promise<NotifyResult>;
|
|
107
|
+
};
|
|
108
|
+
contacts: {
|
|
109
|
+
upsert: (c: UpsertContactParams) => Promise<NotifyResult>;
|
|
110
|
+
};
|
|
111
|
+
otp: {
|
|
112
|
+
send: (p: SendOtpParams) => Promise<NotifyResult>;
|
|
113
|
+
verify: (p: VerifyOtpParams) => Promise<NotifyResult>;
|
|
114
|
+
};
|
|
115
|
+
push: {
|
|
116
|
+
send: (p: SendWebPushParams) => Promise<NotifyResult>;
|
|
117
|
+
};
|
|
118
|
+
sms: {
|
|
119
|
+
send: (p: {
|
|
120
|
+
to: string;
|
|
121
|
+
carrier: string;
|
|
122
|
+
message: string;
|
|
123
|
+
}) => Promise<NotifyResult>;
|
|
124
|
+
};
|
|
125
|
+
whatsapp: {
|
|
126
|
+
send: (instanceId: string, p: {
|
|
127
|
+
to: string;
|
|
128
|
+
message: string;
|
|
129
|
+
media?: {
|
|
130
|
+
url: string;
|
|
131
|
+
caption?: string;
|
|
132
|
+
};
|
|
133
|
+
}) => Promise<NotifyResult>;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Devuelve un NotifyClient configurado desde env vars estándar. Las variables
|
|
138
|
+
* son:
|
|
139
|
+
*
|
|
140
|
+
* NOTIFY_API_URL (default https://notify.zentto.net)
|
|
141
|
+
* NOTIFY_API_KEY (preferida)
|
|
142
|
+
* API_MASTER_KEY (fallback)
|
|
143
|
+
*
|
|
144
|
+
* Si ninguna key está seteada, el cliente igual se construye pero los métodos
|
|
145
|
+
* retornan `{ ok: false, error: "apiKey not configured" }` — mantiene la
|
|
146
|
+
* propiedad "best-effort, nunca tumba el flujo de negocio".
|
|
147
|
+
*/
|
|
148
|
+
export declare function notifyFromEnv(overrides?: Partial<NotifyConfig>): NotifyClient;
|
|
149
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/notify/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NotifyClient — único cliente tipado para https://notify.zentto.net.
|
|
3
|
+
*
|
|
4
|
+
* Diseño:
|
|
5
|
+
* - Factory (no singleton global) → permite tests y múltiples instancias
|
|
6
|
+
* (p.ej. enviar como tenant X vs tenant master master-key).
|
|
7
|
+
* - Best-effort por default en los métodos de negocio (nunca lanzan). Los
|
|
8
|
+
* métodos bajos (`request`) sí propagan errores para que el caller decida.
|
|
9
|
+
* - Timeouts + 1 retry exponencial en errores de red (no en 4xx).
|
|
10
|
+
* - Sin dependencias externas: usa fetch nativo de Node 20+.
|
|
11
|
+
*/
|
|
12
|
+
export class NotifyClient {
|
|
13
|
+
baseUrl;
|
|
14
|
+
apiKey;
|
|
15
|
+
timeoutMs;
|
|
16
|
+
retries;
|
|
17
|
+
onError;
|
|
18
|
+
constructor(cfg) {
|
|
19
|
+
this.baseUrl = (cfg.baseUrl || "https://notify.zentto.net").replace(/\/$/, "");
|
|
20
|
+
this.apiKey = cfg.apiKey;
|
|
21
|
+
this.timeoutMs = cfg.timeoutMs ?? 10_000;
|
|
22
|
+
this.retries = Math.max(0, cfg.retries ?? 1);
|
|
23
|
+
this.onError = cfg.onError ?? (() => { });
|
|
24
|
+
}
|
|
25
|
+
// ── Low-level ────────────────────────────────────────────────────────────
|
|
26
|
+
async request(method, path, body) {
|
|
27
|
+
if (!this.apiKey)
|
|
28
|
+
return { ok: false, error: "apiKey not configured" };
|
|
29
|
+
let lastErr;
|
|
30
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
31
|
+
try {
|
|
32
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
33
|
+
method,
|
|
34
|
+
headers: {
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
"X-API-Key": this.apiKey,
|
|
37
|
+
},
|
|
38
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
39
|
+
signal: AbortSignal.timeout(this.timeoutMs),
|
|
40
|
+
});
|
|
41
|
+
const json = (await res.json().catch(() => ({})));
|
|
42
|
+
if (res.ok) {
|
|
43
|
+
return {
|
|
44
|
+
ok: true,
|
|
45
|
+
messageId: json.messageId ?? json.id,
|
|
46
|
+
via: json.via,
|
|
47
|
+
data: json,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// 4xx: no retry — es error del caller o auth
|
|
51
|
+
if (res.status >= 400 && res.status < 500) {
|
|
52
|
+
return { ok: false, error: json.error ?? `HTTP ${res.status}` };
|
|
53
|
+
}
|
|
54
|
+
lastErr = new Error(`HTTP ${res.status}`);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
lastErr = err;
|
|
58
|
+
}
|
|
59
|
+
if (attempt < this.retries) {
|
|
60
|
+
this.onError(lastErr, { path, attempt });
|
|
61
|
+
await new Promise((r) => setTimeout(r, 250 * Math.pow(2, attempt)));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const err = lastErr ?? new Error("unknown error");
|
|
65
|
+
this.onError(err, { path, attempt: this.retries });
|
|
66
|
+
return { ok: false, error: err.message };
|
|
67
|
+
}
|
|
68
|
+
// ── Email ────────────────────────────────────────────────────────────────
|
|
69
|
+
email = {
|
|
70
|
+
send: (params) => this.request("POST", "/api/email/send", {
|
|
71
|
+
...params,
|
|
72
|
+
track: params.track ?? true,
|
|
73
|
+
}),
|
|
74
|
+
sendQueued: (params) => this.request("POST", "/api/email/send-queued", params),
|
|
75
|
+
/** Atajo: `email.sendTemplate('lead-confirmacion', { to, variables })` */
|
|
76
|
+
sendTemplate: (templateId, opts) => this.request("POST", "/api/email/send", {
|
|
77
|
+
templateId,
|
|
78
|
+
to: opts.to,
|
|
79
|
+
variables: opts.variables,
|
|
80
|
+
replyTo: opts.replyTo,
|
|
81
|
+
from: opts.from,
|
|
82
|
+
track: opts.track ?? true,
|
|
83
|
+
}),
|
|
84
|
+
};
|
|
85
|
+
// ── Contacts (CRM notify) ────────────────────────────────────────────────
|
|
86
|
+
contacts = {
|
|
87
|
+
upsert: (c) => this.request("POST", "/api/contacts", {
|
|
88
|
+
...c,
|
|
89
|
+
subscribed: c.subscribed ?? true,
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
// ── OTP ──────────────────────────────────────────────────────────────────
|
|
93
|
+
otp = {
|
|
94
|
+
send: (p) => this.request("POST", "/api/otp/send", {
|
|
95
|
+
...p,
|
|
96
|
+
brandName: p.brandName ?? "Zentto",
|
|
97
|
+
}),
|
|
98
|
+
verify: (p) => this.request("POST", "/api/otp/verify", p),
|
|
99
|
+
};
|
|
100
|
+
// ── Push web ─────────────────────────────────────────────────────────────
|
|
101
|
+
push = {
|
|
102
|
+
send: (p) => this.request("POST", "/api/push/send", p),
|
|
103
|
+
};
|
|
104
|
+
// ── SMS (carrier-based) ──────────────────────────────────────────────────
|
|
105
|
+
sms = {
|
|
106
|
+
send: (p) => this.request("POST", "/api/sms/send", p),
|
|
107
|
+
};
|
|
108
|
+
// ── WhatsApp (multi-instance) ────────────────────────────────────────────
|
|
109
|
+
whatsapp = {
|
|
110
|
+
send: (instanceId, p) => this.request("POST", `/api/whatsapp/instances/${instanceId}/send`, p),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// ── Factory convenience ─────────────────────────────────────────────────────
|
|
114
|
+
/**
|
|
115
|
+
* Devuelve un NotifyClient configurado desde env vars estándar. Las variables
|
|
116
|
+
* son:
|
|
117
|
+
*
|
|
118
|
+
* NOTIFY_API_URL (default https://notify.zentto.net)
|
|
119
|
+
* NOTIFY_API_KEY (preferida)
|
|
120
|
+
* API_MASTER_KEY (fallback)
|
|
121
|
+
*
|
|
122
|
+
* Si ninguna key está seteada, el cliente igual se construye pero los métodos
|
|
123
|
+
* retornan `{ ok: false, error: "apiKey not configured" }` — mantiene la
|
|
124
|
+
* propiedad "best-effort, nunca tumba el flujo de negocio".
|
|
125
|
+
*/
|
|
126
|
+
export function notifyFromEnv(overrides) {
|
|
127
|
+
return new NotifyClient({
|
|
128
|
+
baseUrl: process.env.NOTIFY_API_URL,
|
|
129
|
+
apiKey: process.env.NOTIFY_API_KEY || process.env.API_MASTER_KEY || "",
|
|
130
|
+
...overrides,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/notify/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/notify/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/notify/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zentto/platform-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Cliente tipado para los servicios de plataforma Zentto (notify, cache, auth, landing). Uso oficial en ERP, verticals y sitios de tenants clientes.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./notify": {
|
|
14
|
+
"types": "./dist/notify/index.d.ts",
|
|
15
|
+
"import": "./dist/notify/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"dev": "tsc --watch",
|
|
26
|
+
"clean": "rm -rf dist",
|
|
27
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"zentto",
|
|
31
|
+
"erp",
|
|
32
|
+
"notify",
|
|
33
|
+
"sdk",
|
|
34
|
+
"platform"
|
|
35
|
+
],
|
|
36
|
+
"author": "Zentto ERP",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/zentto-erp/zentto-web.git",
|
|
41
|
+
"directory": "web/platform-client"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://zentto.net",
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public",
|
|
46
|
+
"registry": "https://registry.npmjs.org"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^25.6.0",
|
|
50
|
+
"typescript": "^5.7.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=20"
|
|
54
|
+
}
|
|
55
|
+
}
|