planvortex 0.0.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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/chunk-B4DEHU6Q.js +140 -0
- package/dist/chunk-B4DEHU6Q.js.map +1 -0
- package/dist/index-CUrq0B7g.d.cts +11074 -0
- package/dist/index-CUrq0B7g.d.ts +11074 -0
- package/dist/index.cjs +1594 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +851 -0
- package/dist/index.d.ts +851 -0
- package/dist/index.js +1414 -0
- package/dist/index.js.map +1 -0
- package/dist/webhooks/index.cjs +255 -0
- package/dist/webhooks/index.cjs.map +1 -0
- package/dist/webhooks/index.d.cts +1 -0
- package/dist/webhooks/index.d.ts +1 -0
- package/dist/webhooks/index.js +188 -0
- package/dist/webhooks/index.js.map +1 -0
- package/package.json +99 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,851 @@
|
|
|
1
|
+
import { P as Paginated, S as SocialNetwork, C as ConnectLink, a as ConnectResult, E as EnableResult, A as Account, b as AccountMetrics, c as PersistentMenu, d as SocialCapabilities, e as CommentActions, f as SocialLimits, g as PublicationLimits, h as AspectRatiosByNetwork, i as Client, O as Organization, j as PlanData, k as ConnectToken, l as PublicationInput, m as Publication, n as PublicationState, o as PublicationStats, p as PublicationStatsHistory, U as Upload } from './index-CUrq0B7g.js';
|
|
2
|
+
export { q as AccountError, r as AccountMetricRow, s as AccountStateChange, t as AccountWebhookChangeBase, u as AiContext, v as AiPlan, w as AiPlanError, x as ApiErrorBody, y as AspectRatios, z as AuthError, B as ClientApp, D as ClientPlan, F as Comment, G as CommentAuthor, H as CommentChange, I as CommentNetwork, J as Contact, K as ContactError, L as Conversation, M as EngagementBase, N as FileError, Q as FileFormat, R as FileProperties, T as FileType, V as Integration, W as IntegrationError, X as IntegrationErrorChange, Y as Message, Z as MessageChange, _ as MessagingError, $ as NO_ERROR_CODE, a0 as OpenApiComponents, a1 as OpenApiOperations, a2 as OpenApiPaths, a3 as OpenApiWebhooks, a4 as OpenEnum, a5 as OrganizationError, a6 as PLANVORTEX_ERROR_RANGES, a7 as PlanLimitError, a8 as PlanVortexAuthenticationError, a9 as PlanVortexConfigError, aa as PlanVortexConnectionError, ab as PlanVortexError, ac as PlanVortexErrorOptions, ad as PlanVortexErrorRange, ae as Product, af as ProductError, ag as PublicationError, ah as PublicationErrorDetail, ai as PublicationMetrics, aj as PublicationStatsPoint, ak as PublicationType, al as SocialCredentials, am as SocialLimitsMap, an as TOKEN_ERROR_CODES, ao as UnknownWebhookChange, ap as UserError, aq as WebhookAlgorithm, ar as WebhookChange, as as WebhookEvent, at as account, au as accountId, av as errorFamilyForCode, aw as isPlanVortexError, ax as isTokenError, ay as messageContact, az as messageContactId, aA as messageDirection, aB as messageFileIds, aC as messageFiles } from './index-CUrq0B7g.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Las dos constantes que todo lo demás necesita. Viven aparte de `index.ts` para que `client.ts`
|
|
6
|
+
* pueda leerlas sin importar el punto de entrada, que a su vez le importa a él: el ciclo compila,
|
|
7
|
+
* pero deja el orden de inicialización en manos del bundler y eso se paga tarde y mal.
|
|
8
|
+
*/
|
|
9
|
+
/** La única URL que un integrador configura. El proveedor de identidad no es parte del contrato. */
|
|
10
|
+
declare const PLANVORTEX_API_URL = "https://api.planvortex.com/v1.0.0";
|
|
11
|
+
/**
|
|
12
|
+
* Versión del paquete, en el `User-Agent` de cada petición.
|
|
13
|
+
*
|
|
14
|
+
* Es una constante y no un `require("../package.json")` a propósito: leer el package.json en tiempo
|
|
15
|
+
* de ejecución obliga a empaquetarlo y se rompe distinto en ESM y en CJS. La mantiene sincronizada
|
|
16
|
+
* un test.
|
|
17
|
+
*/
|
|
18
|
+
declare const VERSION = "0.0.1";
|
|
19
|
+
|
|
20
|
+
/** `fetch` con la firma que usamos. Se puede sustituir en tests o para meter un proxy. */
|
|
21
|
+
type FetchLike = (input: string, init: RequestInit) => Promise<Response>;
|
|
22
|
+
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
23
|
+
/** Valores admitidos en la query. `undefined` y `null` se omiten; un array repite la clave. */
|
|
24
|
+
type QueryValue = string | number | boolean | Date | null | undefined | readonly (string | number | boolean)[];
|
|
25
|
+
interface RetryConfig {
|
|
26
|
+
/** Cuántas veces se REPITE una petición fallida. `0` desactiva los reintentos. */
|
|
27
|
+
maxRetries: number;
|
|
28
|
+
/** Espera base del backoff exponencial, en ms. La real es aleatoria entre 0 y el tope. */
|
|
29
|
+
baseDelayMs: number;
|
|
30
|
+
/**
|
|
31
|
+
* Tope de espera entre intentos, en ms.
|
|
32
|
+
*
|
|
33
|
+
* Además de recortar el backoff, decide qué hacer con un `Retry-After` largo: si el servidor
|
|
34
|
+
* pide más que esto, la librería **no** espera — lanza el error con `retryAfter` puesto y deja
|
|
35
|
+
* que el integrador decida. Un `Retry-After: 300` del freno del token endpoint no puede
|
|
36
|
+
* traducirse en una llamada que se queda cinco minutos colgada.
|
|
37
|
+
*/
|
|
38
|
+
maxDelayMs: number;
|
|
39
|
+
}
|
|
40
|
+
declare const DEFAULT_RETRY: RetryConfig;
|
|
41
|
+
/** 120 s, como el panel: subir y publicar un vídeo es lento de verdad. */
|
|
42
|
+
declare const DEFAULT_TIMEOUT_MS = 120000;
|
|
43
|
+
interface RequestInfo {
|
|
44
|
+
method: HttpMethod;
|
|
45
|
+
url: string;
|
|
46
|
+
/** 1 la primera vez. */
|
|
47
|
+
attempt: number;
|
|
48
|
+
}
|
|
49
|
+
interface ResponseInfo extends RequestInfo {
|
|
50
|
+
status: number;
|
|
51
|
+
/** Milisegundos de ese intento. */
|
|
52
|
+
durationMs: number;
|
|
53
|
+
}
|
|
54
|
+
interface RetryInfo extends RequestInfo {
|
|
55
|
+
/** Espera antes del siguiente intento, en ms. */
|
|
56
|
+
delayMs: number;
|
|
57
|
+
/** El status que provocó el reintento, o `undefined` si fue un fallo de red. */
|
|
58
|
+
status: number | undefined;
|
|
59
|
+
/** El error de red, si lo hubo. */
|
|
60
|
+
error: unknown;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Ganchos para el logger del integrador. Son síncronos a propósito: si uno lanza, lanza en su
|
|
64
|
+
* llamada, no en medio del reintento.
|
|
65
|
+
*/
|
|
66
|
+
interface HttpHooks {
|
|
67
|
+
onRequest?: (info: RequestInfo) => void;
|
|
68
|
+
onResponse?: (info: ResponseInfo) => void;
|
|
69
|
+
onRetry?: (info: RetryInfo) => void;
|
|
70
|
+
}
|
|
71
|
+
interface HttpRequest {
|
|
72
|
+
method: HttpMethod;
|
|
73
|
+
/** Empieza por `/`, relativo a `baseUrl`. */
|
|
74
|
+
path: string;
|
|
75
|
+
query?: Record<string, QueryValue>;
|
|
76
|
+
/**
|
|
77
|
+
* `FormData`, `URLSearchParams` o `string` viajan tal cual; cualquier otra cosa se serializa a
|
|
78
|
+
* JSON. `undefined` es "sin cuerpo".
|
|
79
|
+
*/
|
|
80
|
+
body?: unknown;
|
|
81
|
+
headers?: Record<string, string>;
|
|
82
|
+
timeoutMs?: number;
|
|
83
|
+
/** Del integrador, para cancelar. Se combina con el timeout interno. */
|
|
84
|
+
signal?: AbortSignal | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Fuerza que la petición se pueda reintentar aunque sea un POST. Sólo para POSTs que no crean
|
|
87
|
+
* nada — hoy, `POST /oauth/token`.
|
|
88
|
+
*/
|
|
89
|
+
idempotent?: boolean;
|
|
90
|
+
/** `none` salta el parseo del cuerpo. Por defecto se intenta JSON. */
|
|
91
|
+
parse?: "json" | "none";
|
|
92
|
+
}
|
|
93
|
+
interface HttpResponse<T> {
|
|
94
|
+
data: T;
|
|
95
|
+
status: number;
|
|
96
|
+
headers: Headers;
|
|
97
|
+
/** `x-request-id`, cuando el despliegue lo pone. */
|
|
98
|
+
requestId: string | undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Lo que comparten todos los recursos: una petición autenticada y el desenvuelto del sobre.
|
|
103
|
+
*
|
|
104
|
+
* Un recurso no construye su propio transporte: recibe el {@link PlanVortex} y usa su `request`,
|
|
105
|
+
* que es lo que hace que el token, los reintentos y los hooks sean unos para toda la instancia.
|
|
106
|
+
* Y no importa `client.ts` ni por el tipo — sólo la forma que necesita— porque `client.ts` sí
|
|
107
|
+
* importa los recursos, y el ciclo compilaría dejando el orden de inicialización en manos del
|
|
108
|
+
* bundler.
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
/** Lo único que un recurso necesita del cliente. */
|
|
112
|
+
interface RequestSender {
|
|
113
|
+
request<T>(request: HttpRequest): Promise<HttpResponse<T>>;
|
|
114
|
+
}
|
|
115
|
+
type Query = Record<string, QueryValue>;
|
|
116
|
+
/** Opciones por llamada que cualquier método acepta: cancelar y ajustar el timeout. */
|
|
117
|
+
interface RequestOptions {
|
|
118
|
+
signal?: AbortSignal | undefined;
|
|
119
|
+
timeoutMs?: number | undefined;
|
|
120
|
+
}
|
|
121
|
+
declare abstract class Resource {
|
|
122
|
+
protected readonly client: RequestSender;
|
|
123
|
+
constructor(client: RequestSender);
|
|
124
|
+
protected send<T>(request: HttpRequest, options?: RequestOptions): Promise<T>;
|
|
125
|
+
protected httpGet<T>(path: string, query?: Query, options?: RequestOptions): Promise<T>;
|
|
126
|
+
protected httpPost<T>(path: string, body?: unknown, options?: RequestOptions, query?: Query): Promise<T>;
|
|
127
|
+
protected httpPut<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
128
|
+
protected httpDelete<T>(path: string, query?: Query, options?: RequestOptions): Promise<T>;
|
|
129
|
+
/** `GET` de una lista, ya desenvuelta a `{data, total}`. */
|
|
130
|
+
protected getList<T>(path: string, key: string, query?: Query, options?: RequestOptions): Promise<Paginated<T>>;
|
|
131
|
+
/** `GET` de un recurso suelto, ya sacado de su sobre. */
|
|
132
|
+
protected getOne<T>(path: string, key: string, query?: Query, options?: RequestOptions): Promise<T>;
|
|
133
|
+
/** `POST` que devuelve un recurso envuelto. */
|
|
134
|
+
protected postOne<T>(path: string, key: string, body?: unknown, options?: RequestOptions, query?: Query): Promise<T>;
|
|
135
|
+
/** `PUT` que devuelve un recurso envuelto. */
|
|
136
|
+
protected putOne<T>(path: string, key: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Lo que admite cualquier `list()` del paquete, además de los filtros propios de su dominio. */
|
|
140
|
+
interface PageOptions {
|
|
141
|
+
/** Cuántos elementos pedir. Sin él manda el servidor, que no siempre pagina igual. */
|
|
142
|
+
limit?: number | undefined;
|
|
143
|
+
/** Cuántos saltar. `0` es la primera página. */
|
|
144
|
+
offset?: number | undefined;
|
|
145
|
+
}
|
|
146
|
+
/** Elementos por página cuando `iterate()` no recibe `limit`. */
|
|
147
|
+
declare const DEFAULT_PAGE_SIZE = 50;
|
|
148
|
+
/**
|
|
149
|
+
* El seguro contra un bucle infinito. No es un límite de cuánto se puede leer: es lo que hace que
|
|
150
|
+
* un servidor que ignore el `offset` falle en vez de colgar el proceso.
|
|
151
|
+
*/
|
|
152
|
+
declare const MAX_PAGES = 10000;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Cuentas sociales conectadas a una organización.
|
|
156
|
+
*
|
|
157
|
+
* DOS COSAS QUE NO SE ADIVINAN SOLAS:
|
|
158
|
+
*
|
|
159
|
+
* - **Una app no puede CONECTAR una cuenta.** Conectar Instagram es un OAuth con una persona
|
|
160
|
+
* delante, y las credenciales de app no valen para eso: {@link AccountsResource.connectLinks},
|
|
161
|
+
* {@link AccountsResource.connect} y {@link AccountsResource.enable} contestan 519 si se llaman
|
|
162
|
+
* con ellas. Se emite un token temporal
|
|
163
|
+
* (`organizations.createConnectToken`), se le pasa a la persona, y se llaman con un cliente
|
|
164
|
+
* autenticado con ese token: `pv.asTemporalToken(token)`.
|
|
165
|
+
* - **`error_code` distinto de 0 es una cuenta rota**, no un fallo de esta llamada. Sigue en la
|
|
166
|
+
* lista con sus datos, pero ni publica ni mide hasta que alguien la reconecte.
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Las capacidades por las que se puede filtrar la lista. Son las mismas que publica
|
|
171
|
+
* `catalog.socialCapabilities()`, aplicadas en el servidor: es la forma de pedir "las cuentas con
|
|
172
|
+
* las que puedo publicar" sin mantener tu propia tabla de qué red hace qué.
|
|
173
|
+
*/
|
|
174
|
+
type AccountCapability = "publications" | "messages" | "products" | "webhooks" | "persistent_menu" | "comments";
|
|
175
|
+
interface AccountListOptions extends PageOptions {
|
|
176
|
+
/** Búsqueda libre sobre el nombre y el usuario de la cuenta. */
|
|
177
|
+
name?: string | undefined;
|
|
178
|
+
/** Sólo estas redes. */
|
|
179
|
+
social_network?: readonly SocialNetwork[] | undefined;
|
|
180
|
+
/** Sólo estas cuentas, por identificador. */
|
|
181
|
+
accounts?: readonly string[] | undefined;
|
|
182
|
+
/** Sólo las cuentas cuya red sabe hacer esto. */
|
|
183
|
+
capability?: AccountCapability | undefined;
|
|
184
|
+
}
|
|
185
|
+
interface AccountMetricsOptions extends RequestOptions {
|
|
186
|
+
/** Principio del rango. Por defecto, un día antes de `to_date`. */
|
|
187
|
+
from_date?: Date | string | undefined;
|
|
188
|
+
/** Final del rango. Por defecto, ahora. */
|
|
189
|
+
to_date?: Date | string | undefined;
|
|
190
|
+
/**
|
|
191
|
+
* Sólo estas métricas, por su nombre CRUDO — los que devuelve {@link AccountsResource.metricList}.
|
|
192
|
+
* Sin esto vuelven todas las medidas.
|
|
193
|
+
*/
|
|
194
|
+
names?: readonly string[] | undefined;
|
|
195
|
+
}
|
|
196
|
+
interface ConnectLinksOptions extends RequestOptions {
|
|
197
|
+
/** Sólo estas redes. Sin esto vuelven todas las que la organización pueda conectar ahora. */
|
|
198
|
+
social_network?: readonly SocialNetwork[] | undefined;
|
|
199
|
+
/**
|
|
200
|
+
* A qué front de PlanVortex devuelve la red al usuario, para un despliegue de marca blanca.
|
|
201
|
+
*
|
|
202
|
+
* **No es una URL tuya**, y no puede serlo: las redes sólo aceptan `redirect_uri` registrados
|
|
203
|
+
* en su propia configuración de aplicación. Tiene que ser uno de los fronts que el servidor
|
|
204
|
+
* tiene dados de alta o la llamada contesta 532. A dónde vuelve TU usuario cuando termina se
|
|
205
|
+
* decide en `organizations.createConnectToken({redirect_uri})`.
|
|
206
|
+
*/
|
|
207
|
+
redirect_uri?: string | undefined;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Lo que la red social pegó a la URL de vuelta. Se pasa **tal cual**, sin tocar ni filtrar: cada
|
|
211
|
+
* red manda lo suyo (`code` y `state` casi todas, `oauth_token`/`oauth_verifier` X, ...).
|
|
212
|
+
*/
|
|
213
|
+
type ConnectCallbackParams = Record<string, string | readonly string[] | undefined>;
|
|
214
|
+
declare class AccountsResource extends Resource {
|
|
215
|
+
/**
|
|
216
|
+
* Los enlaces de autorización de cada red conectable, para mandar a la persona a la suya.
|
|
217
|
+
*
|
|
218
|
+
* **Con credenciales de app contesta 519.** Se llama con un cliente autenticado con el token
|
|
219
|
+
* temporal: `pv.asTemporalToken(token).accounts.connectLinks(orgId)`.
|
|
220
|
+
*
|
|
221
|
+
* **Una red que no puede dar enlace simplemente no aparece**, y eso es una respuesta legítima y
|
|
222
|
+
* no un fallo: es lo que pasa con Discord en una organización que todavía no ha guardado sus
|
|
223
|
+
* propias credenciales de bot.
|
|
224
|
+
*
|
|
225
|
+
* OJO: la red devuelve al usuario a un front de PlanVortex, no a una URL tuya — ver
|
|
226
|
+
* `redirect_uri` en {@link ConnectLinksOptions}.
|
|
227
|
+
*/
|
|
228
|
+
connectLinks(idOrganization: string, options?: ConnectLinksOptions): Promise<ConnectLink[]>;
|
|
229
|
+
/**
|
|
230
|
+
* Completa la conexión con lo que la red social pegó a la URL de vuelta.
|
|
231
|
+
*
|
|
232
|
+
* **Esta llamada no la necesita la mayoría.** La URL de vuelta la construye la red a partir del
|
|
233
|
+
* enlace de {@link connectLinks}, y apunta a un front de PlanVortex: es ese front el que llama
|
|
234
|
+
* aquí. El método existe para quien sirve su propia interfaz en uno de los dominios registrados
|
|
235
|
+
* en el servidor. En la integración normal —la del ejemplo `connect-flow`— basta con mandar al
|
|
236
|
+
* usuario a la `url` del token temporal y esperarlo de vuelta.
|
|
237
|
+
*
|
|
238
|
+
* **El endpoint contesta 200 aunque haya fallado**, con el error dentro del cuerpo, porque el
|
|
239
|
+
* navegador aterriza aquí desde una redirección y un 400 crudo sería una página rota. La
|
|
240
|
+
* librería deshace ese apaño: si viene `errorCode`, **lanza** el error que le toca, igual que
|
|
241
|
+
* cualquier otro método. Lo que devuelve son sólo cuentas buenas.
|
|
242
|
+
*
|
|
243
|
+
* **Y vuelven SIN habilitar**: no ocupan plaza del plan ni publican hasta que se llama a
|
|
244
|
+
* {@link enable}. Una sola autorización puede dejar varias — un usuario de Facebook con cuatro
|
|
245
|
+
* páginas son cuatro—, y por eso hay un paso de elección en medio.
|
|
246
|
+
*/
|
|
247
|
+
connect(idOrganization: string, socialNetwork: SocialNetwork, params?: ConnectCallbackParams, options?: RequestOptions): Promise<ConnectResult>;
|
|
248
|
+
/**
|
|
249
|
+
* Da de alta una de las cuentas que dejó {@link connect}, o recupera una que se desconectó
|
|
250
|
+
* mientras su token guardado siga sirviendo (si no, error 700 y hay que autorizar otra vez).
|
|
251
|
+
*
|
|
252
|
+
* **Es el paso que ocupa plaza del plan**: con el cupo lleno contesta 706, así que se llama una
|
|
253
|
+
* a una y se mira el hueco antes (`organizations.limits`). Y es también el que enciende los
|
|
254
|
+
* webhooks de la red, en cualquier plan que no sea el gratuito.
|
|
255
|
+
*/
|
|
256
|
+
enable(idOrganization: string, idAccount: string, options?: RequestOptions): Promise<EnableResult>;
|
|
257
|
+
/** Las cuentas de una organización. */
|
|
258
|
+
list(idOrganization: string, options?: AccountListOptions & RequestOptions): Promise<Paginated<Account>>;
|
|
259
|
+
/** Las cuentas de una organización, encadenando páginas. */
|
|
260
|
+
iterate(idOrganization: string, options?: AccountListOptions & RequestOptions): AsyncGenerator<Account>;
|
|
261
|
+
/** La ficha de una cuenta. */
|
|
262
|
+
get(idOrganization: string, idAccount: string, options?: RequestOptions): Promise<Account>;
|
|
263
|
+
/** Cambia el nombre con el que la cuenta se ve en PlanVortex. Es lo único editable. */
|
|
264
|
+
update(idOrganization: string, idAccount: string, body: {
|
|
265
|
+
name?: string;
|
|
266
|
+
}, options?: RequestOptions): Promise<Account>;
|
|
267
|
+
/**
|
|
268
|
+
* Desconecta la cuenta y **borra sus publicaciones**. Lo ya publicado en la red se queda donde
|
|
269
|
+
* está: esto no la toca.
|
|
270
|
+
*/
|
|
271
|
+
remove(idOrganization: string, idAccount: string, options?: RequestOptions): Promise<void>;
|
|
272
|
+
/**
|
|
273
|
+
* La serie de métricas ya medidas de una cuenta.
|
|
274
|
+
*
|
|
275
|
+
* Es lectura de lo guardado, no una llamada a la red: mirar la gráfica no cuesta créditos. El
|
|
276
|
+
* agrupado lo decide el rango — hasta 31 días por día, hasta 720 por mes, y de ahí por año— y
|
|
277
|
+
* viene dicho en `group`.
|
|
278
|
+
*/
|
|
279
|
+
metrics(idOrganization: string, idAccount: string, options?: AccountMetricsOptions): Promise<AccountMetrics>;
|
|
280
|
+
/**
|
|
281
|
+
* Los nombres CRUDOS de las métricas que publica la red de esta cuenta.
|
|
282
|
+
*
|
|
283
|
+
* Son los que se pasan a {@link metrics} y los que vuelven en cada fila. No es el vocabulario
|
|
284
|
+
* común —eso es `metrics` de una publicación—: aquí cada red habla su idioma
|
|
285
|
+
* (`page_impressions`, `total_interactions`, `allPageViews`).
|
|
286
|
+
*/
|
|
287
|
+
metricList(idOrganization: string, idAccount: string, options?: RequestOptions): Promise<string[]>;
|
|
288
|
+
/**
|
|
289
|
+
* El menú fijo del chat, una entrada por idioma.
|
|
290
|
+
*
|
|
291
|
+
* Sólo las redes con mensajería lo tienen: en las demás la llamada devuelve el error 710. Se
|
|
292
|
+
* comprueba con `persistent_menu` de `catalog.socialCapabilities()`.
|
|
293
|
+
*/
|
|
294
|
+
getPersistentMenu(idOrganization: string, idAccount: string, options?: RequestOptions): Promise<PersistentMenu>;
|
|
295
|
+
/**
|
|
296
|
+
* Reemplaza el menú fijo del chat. Es un REEMPLAZO: lo que no vaya en el array desaparece.
|
|
297
|
+
*
|
|
298
|
+
* La entrada con `locale: "default"` es obligatoria — es la que se enseña cuando ninguna otra
|
|
299
|
+
* encaja.
|
|
300
|
+
*/
|
|
301
|
+
setPersistentMenu(idOrganization: string, idAccount: string, menu: PersistentMenu, options?: RequestOptions): Promise<PersistentMenu>;
|
|
302
|
+
private path;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* El catálogo: qué redes hay, qué sabe hacer cada una y contra qué límites se valida.
|
|
307
|
+
*
|
|
308
|
+
* POR QUÉ SE CACHEA: son constantes del despliegue. No dependen del cliente, no dependen de la
|
|
309
|
+
* organización y no cambian entre dos llamadas — cambian cuando se despliega el servidor. Un
|
|
310
|
+
* compositor que valide el texto mientras se escribe pediría `/social_limits` en cada tecla; con la
|
|
311
|
+
* caché lo pide una vez por instancia de {@link PlanVortex}.
|
|
312
|
+
*
|
|
313
|
+
* POR QUÉ SE PIDEN Y NO SE ESCRIBEN AQUÍ: es la regla de la casa — quien valida el límite es quien
|
|
314
|
+
* lo anuncia. El panel tenía su propia tabla y divergió: contaba LinkedIn hasta 3.000 mientras el
|
|
315
|
+
* servidor lo tumbaba a los 1.300, así que el usuario escribía un texto que el contador daba por
|
|
316
|
+
* bueno y la API rechazaba. Una copia dentro de esta librería sería el mismo error un piso más
|
|
317
|
+
* abajo, y encima repartido por npm.
|
|
318
|
+
*
|
|
319
|
+
* LA CACHÉ ES POR INSTANCIA Y NO CADUCA. Un proceso de días que quiera enterarse de una red nueva
|
|
320
|
+
* llama a {@link CatalogResource.clearCache}; un proceso normal se muere antes de que importe.
|
|
321
|
+
*/
|
|
322
|
+
|
|
323
|
+
declare class CatalogResource extends Resource {
|
|
324
|
+
private readonly cache;
|
|
325
|
+
/**
|
|
326
|
+
* Las redes soportadas.
|
|
327
|
+
*
|
|
328
|
+
* **La lista crece varias veces al año.** No la copies a una constante tuya: pídela.
|
|
329
|
+
*/
|
|
330
|
+
socialNetworks(options?: RequestOptions): Promise<SocialNetwork[]>;
|
|
331
|
+
/** Las redes que aceptan publicaciones. Ni WhatsApp ni Google Business están. */
|
|
332
|
+
allowedSocialPublications(options?: RequestOptions): Promise<SocialNetwork[]>;
|
|
333
|
+
/**
|
|
334
|
+
* Las redes con conversaciones.
|
|
335
|
+
*
|
|
336
|
+
* Va en `POST` y no en `GET`, que es raro y es así: es la ruta que hay. No manda cuerpo.
|
|
337
|
+
*/
|
|
338
|
+
allowedSocialMessages(options?: RequestOptions): Promise<SocialNetwork[]>;
|
|
339
|
+
/**
|
|
340
|
+
* La matriz red → qué sabe hacer: publicar, mensajes, productos, webhooks, menú persistente y
|
|
341
|
+
* comentarios.
|
|
342
|
+
*
|
|
343
|
+
* Es lo que evita ofrecer una cuenta en una pantalla que su red no soporta — WhatsApp en el
|
|
344
|
+
* compositor, LinkedIn en el chat.
|
|
345
|
+
*/
|
|
346
|
+
socialCapabilities(options?: RequestOptions): Promise<Record<string, SocialCapabilities>>;
|
|
347
|
+
/**
|
|
348
|
+
* La matriz red → qué se puede hacer con un comentario: responder, ocultar, borrar el propio y
|
|
349
|
+
* borrar el de otro.
|
|
350
|
+
*
|
|
351
|
+
* Va **aparte** de {@link socialCapabilities} porque aquélla es `{[capacidad]: boolean}` y esto
|
|
352
|
+
* es un objeto por red: meterlo dentro rompería su forma. Que la red tenga comentarios no dice
|
|
353
|
+
* lo suficiente — Instagram, X y Bluesky no dejan borrar el de otro, LinkedIn no tiene
|
|
354
|
+
* "ocultar", y Google Business sólo deja borrar **nuestra propia respuesta**.
|
|
355
|
+
*/
|
|
356
|
+
socialCommentActions(options?: RequestOptions): Promise<Record<string, CommentActions>>;
|
|
357
|
+
/**
|
|
358
|
+
* Los topes de cada red, por los que el servidor valida.
|
|
359
|
+
*
|
|
360
|
+
* Bluesky lleva **dos** cuentas del mismo texto y en unidades distintas: 300 grafemas en
|
|
361
|
+
* `characters` y 3.000 bytes en `max_post_bytes`. `.length` miente en las dos direcciones —un
|
|
362
|
+
* emoji de familia es UN grafema y 25 bytes—, así que un contador que use `.length` da por
|
|
363
|
+
* bueno lo que la API rechaza y al revés.
|
|
364
|
+
*/
|
|
365
|
+
socialLimits(options?: RequestOptions): Promise<SocialLimits>;
|
|
366
|
+
/** Los topes de una publicación que no dependen de la red: hoy, cuántos reintentos manuales admite. */
|
|
367
|
+
publicationLimits(options?: RequestOptions): Promise<PublicationLimits>;
|
|
368
|
+
/**
|
|
369
|
+
* Los recortes que acepta cada red.
|
|
370
|
+
*
|
|
371
|
+
* Se indexa por red **y por formato** (`facebook`, `facebook_reels`, `facebook_stories`), así
|
|
372
|
+
* que no todas las claves son una red. `values` y `text` son arrays paralelos: mismo índice,
|
|
373
|
+
* mismo recorte.
|
|
374
|
+
*/
|
|
375
|
+
allowedAspectRatios(options?: RequestOptions): Promise<AspectRatiosByNetwork>;
|
|
376
|
+
/** Tira la caché. Para un proceso largo que quiera enterarse de una red nueva sin reiniciar. */
|
|
377
|
+
clearCache(): void;
|
|
378
|
+
/**
|
|
379
|
+
* Guarda la PROMESA, no el resultado: dos llamadas a la vez comparten una petición en vez de
|
|
380
|
+
* lanzar dos. Si falla, la entrada se retira para que el siguiente intento vuelva a pedirla —
|
|
381
|
+
* cachear un fallo de red deja la instancia rota para siempre.
|
|
382
|
+
*/
|
|
383
|
+
private cached;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Clientes: quien contrata el plan y a quien cuelgan las organizaciones.
|
|
388
|
+
*
|
|
389
|
+
* LO QUE HAY QUE ENTENDER DEL PLAN, porque el spec lo describía mal hasta la fase 6 y era fácil
|
|
390
|
+
* leer el campo equivocado: `client.actual_plan` es la **suscripción** (si está activa, qué plan
|
|
391
|
+
* es, cuándo acaba el periodo), y los números están dentro, en `actual_plan.plan_data`. Mirar
|
|
392
|
+
* `plan_identifier` para saber los límites es el error clásico: un plan `custom` lleva los suyos.
|
|
393
|
+
*
|
|
394
|
+
* Y el CONSUMO no viaja si no se pide: `actual_use` y `actual_asigned` sólo aparecen con
|
|
395
|
+
* `getUse: true`, porque contarlos es una agregación sobre todas las organizaciones del cliente.
|
|
396
|
+
*/
|
|
397
|
+
|
|
398
|
+
interface ClientListOptions extends PageOptions {
|
|
399
|
+
/** Trae también `actual_use` y `actual_asigned`. Cuesta una agregación: no lo pidas por costumbre. */
|
|
400
|
+
getUse?: boolean | undefined;
|
|
401
|
+
}
|
|
402
|
+
interface OrganizationListOptions extends ClientListOptions {
|
|
403
|
+
/** Búsqueda por nombre. */
|
|
404
|
+
name?: string | undefined;
|
|
405
|
+
}
|
|
406
|
+
/** Lo que se manda para crear una organización. `actual_plan` es el cupo que se le asigna. */
|
|
407
|
+
interface OrganizationInput {
|
|
408
|
+
name: string;
|
|
409
|
+
actual_plan?: Partial<Organization["actual_plan"]> | undefined;
|
|
410
|
+
}
|
|
411
|
+
declare class ClientsResource extends Resource {
|
|
412
|
+
/** Los clientes que puede ver quien llama. Con credenciales de app, el suyo. */
|
|
413
|
+
list(options?: ClientListOptions & RequestOptions): Promise<Paginated<Client>>;
|
|
414
|
+
/** Los clientes, página a página, sin tener que llevar el `offset` a mano. */
|
|
415
|
+
iterate(options?: ClientListOptions & RequestOptions): AsyncGenerator<Client>;
|
|
416
|
+
/** La ficha de un cliente. */
|
|
417
|
+
get(idClient: string, options?: {
|
|
418
|
+
getUse?: boolean | undefined;
|
|
419
|
+
} & RequestOptions): Promise<Client>;
|
|
420
|
+
/** Cambia lo poco que de un cliente se puede cambiar: hoy, su nombre. */
|
|
421
|
+
update(idClient: string, body: {
|
|
422
|
+
name?: string;
|
|
423
|
+
}, options?: RequestOptions): Promise<Client>;
|
|
424
|
+
/** Las organizaciones RAÍZ de un cliente. Las hijas cuelgan de cada una. */
|
|
425
|
+
organizations(idClient: string, options?: OrganizationListOptions & RequestOptions): Promise<Paginated<Organization>>;
|
|
426
|
+
/** Las organizaciones raíz de un cliente, encadenando páginas. */
|
|
427
|
+
iterateOrganizations(idClient: string, options?: OrganizationListOptions & RequestOptions): AsyncGenerator<Organization>;
|
|
428
|
+
/** Crea una organización raíz. Lo que se le asigne se descuenta de lo que el cliente tiene. */
|
|
429
|
+
createOrganization(idClient: string, body: OrganizationInput, options?: RequestOptions): Promise<Organization>;
|
|
430
|
+
/** Cambia una organización raíz: su nombre o el cupo que tiene asignado. */
|
|
431
|
+
updateOrganization(idClient: string, idOrganization: string, body: Partial<OrganizationInput>, options?: RequestOptions): Promise<Organization>;
|
|
432
|
+
/**
|
|
433
|
+
* Borra una organización raíz **con todo lo que tiene dentro**: sus organizaciones hijas, sus
|
|
434
|
+
* cuentas, sus publicaciones, sus ficheros y sus comentarios. No se deshace.
|
|
435
|
+
*/
|
|
436
|
+
deleteOrganization(idClient: string, idOrganization: string, options?: RequestOptions): Promise<void>;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Organizaciones: el contenedor de cuentas, publicaciones y ficheros, y el que reparte el cupo.
|
|
441
|
+
*
|
|
442
|
+
* LO QUE SORPRENDE: `organization.actual_plan` es lo ASIGNADO, y **falta cuando no se le asignó
|
|
443
|
+
* nada**. Una organización sin plan propio comparte el del primer padre que tenga uno, y si no lo
|
|
444
|
+
* hay, el resto sin repartir del cliente. Así que para saber qué puede hacer de verdad no se lee
|
|
445
|
+
* `actual_plan`: se llama a {@link OrganizationsResource.limits}, que es quien resuelve la cascada.
|
|
446
|
+
*/
|
|
447
|
+
|
|
448
|
+
interface OrganizationOptions extends RequestOptions {
|
|
449
|
+
/** Trae también `actual_use` y `actual_asigned`. Cuesta una agregación: no lo pidas por costumbre. */
|
|
450
|
+
getUse?: boolean | undefined;
|
|
451
|
+
}
|
|
452
|
+
interface ChildOrganizationListOptions extends OrganizationOptions, PageOptions {
|
|
453
|
+
/** Búsqueda por nombre. */
|
|
454
|
+
name?: string | undefined;
|
|
455
|
+
}
|
|
456
|
+
/** Lo que se puede repartir a una organización hija. Todo son números del plan del padre. */
|
|
457
|
+
type OrganizationPlanInput = Partial<PlanData>;
|
|
458
|
+
interface ConnectTokenOptions extends RequestOptions {
|
|
459
|
+
/**
|
|
460
|
+
* La red que la persona va a conectar. Viaja dentro de la `url` para que el panel no vuelva a
|
|
461
|
+
* preguntarla. Sin esto, el usuario elige red al llegar.
|
|
462
|
+
*/
|
|
463
|
+
social_network?: SocialNetwork | undefined;
|
|
464
|
+
/**
|
|
465
|
+
* A dónde vuelve el usuario cuando termina. Tiene que ser uno de los `redirect_urls`
|
|
466
|
+
* registrados en la app, o la llamada contesta el error 532.
|
|
467
|
+
*/
|
|
468
|
+
redirect_uri?: string | undefined;
|
|
469
|
+
}
|
|
470
|
+
declare class OrganizationsResource extends Resource {
|
|
471
|
+
/** La ficha de una organización. */
|
|
472
|
+
get(idOrganization: string, options?: OrganizationOptions): Promise<Organization>;
|
|
473
|
+
/** Cambia el nombre de una organización o el cupo que tiene asignado. */
|
|
474
|
+
update(idOrganization: string, body: Partial<OrganizationInput>, options?: RequestOptions): Promise<Organization>;
|
|
475
|
+
/**
|
|
476
|
+
* Borra una organización **con todo lo que tiene dentro**: sus hijas, sus cuentas, sus
|
|
477
|
+
* publicaciones, sus ficheros y sus comentarios. No se deshace.
|
|
478
|
+
*/
|
|
479
|
+
remove(idOrganization: string, options?: RequestOptions): Promise<void>;
|
|
480
|
+
/** Las organizaciones que cuelgan de ésta. */
|
|
481
|
+
children(idOrganization: string, options?: ChildOrganizationListOptions): Promise<Paginated<Organization>>;
|
|
482
|
+
/** Las organizaciones hijas, encadenando páginas. */
|
|
483
|
+
iterateChildren(idOrganization: string, options?: ChildOrganizationListOptions): AsyncGenerator<Organization>;
|
|
484
|
+
/** Crea una organización hija con el cupo que se le reparta del plan de ésta. */
|
|
485
|
+
createChild(idOrganization: string, body: OrganizationInput, options?: RequestOptions): Promise<Organization>;
|
|
486
|
+
/**
|
|
487
|
+
* Lo que esta organización puede usar de verdad, con la cascada ya resuelta: su plan propio, o
|
|
488
|
+
* el del primer padre que tenga uno, o el resto sin repartir del cliente.
|
|
489
|
+
*
|
|
490
|
+
* Es lo que hay que mirar antes de conectar una cuenta o programar una publicación, no
|
|
491
|
+
* `organization.actual_plan`.
|
|
492
|
+
*/
|
|
493
|
+
limits(idOrganization: string, options?: RequestOptions): Promise<PlanData>;
|
|
494
|
+
/**
|
|
495
|
+
* El consumo de esta organización y lo que ya tiene repartido a sus hijas.
|
|
496
|
+
*
|
|
497
|
+
* Es un atajo de `get(id, {getUse: true})` que devuelve sólo las dos cifras, que es lo que se
|
|
498
|
+
* quiere cuando se está pintando una barra de "3 de 5 cuentas".
|
|
499
|
+
*/
|
|
500
|
+
use(idOrganization: string, options?: RequestOptions): Promise<{
|
|
501
|
+
actual_use: PlanData | undefined;
|
|
502
|
+
actual_asigned: PlanData | undefined;
|
|
503
|
+
}>;
|
|
504
|
+
/**
|
|
505
|
+
* Emite el token temporal con el que **una persona** conecta una cuenta social a esta
|
|
506
|
+
* organización. Es la única forma que tiene una app de que se le conecte una cuenta.
|
|
507
|
+
*
|
|
508
|
+
* Y es el reverso exacto del resto del flujo: éste es el endpoint que **exige credenciales de
|
|
509
|
+
* app** —con un token de usuario contesta 514—, mientras que los tres que vienen después
|
|
510
|
+
* (`accounts.connectLinks`, `accounts.connect`, `accounts.enable`) las rechazan con un 519.
|
|
511
|
+
*
|
|
512
|
+
* Vuelven las dos formas del mismo credencial, y las dos sirven:
|
|
513
|
+
*
|
|
514
|
+
* - **`url`** — el camino alojado. Se redirige al usuario ahí y PlanVortex se encarga de la
|
|
515
|
+
* elección de red, del OAuth y de la pantalla donde elige qué cuentas dar de alta. Es lo que
|
|
516
|
+
* hace el ejemplo `examples/connect-flow`, y lo que casi todo el mundo quiere.
|
|
517
|
+
* - **`token`** — el credencial suelto, para `pv.asTemporalToken(token)` cuando la interfaz la
|
|
518
|
+
* pone el integrador.
|
|
519
|
+
*
|
|
520
|
+
* Caduca en una hora y **sólo vale para esta organización**: usarlo contra otra contesta 1101.
|
|
521
|
+
*/
|
|
522
|
+
createConnectToken(idOrganization: string, options?: ConnectTokenOptions): Promise<ConnectToken>;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Publicaciones: el camino que vende `/developers`.
|
|
527
|
+
*
|
|
528
|
+
* LO QUE HAY QUE SABER ANTES DE LLAMAR A NADA DE AQUÍ:
|
|
529
|
+
*
|
|
530
|
+
* - **Crear una publicación con contenido inválido NO da error.** El servidor la guarda en estado
|
|
531
|
+
* `withErrors` con el motivo dentro (`publication_errors`), porque el contenido se valida contra
|
|
532
|
+
* la red y eso no es un fallo de la petición. Un `try/catch` no basta: hay que mirar `state`.
|
|
533
|
+
* - **Sin `publish_date` sale YA**, en la propia petición. Con fecha futura queda `ready` y la
|
|
534
|
+
* manda el robot a su hora.
|
|
535
|
+
* - **`files` se manda como identificadores y vuelve poblado.** Lo que llega en la respuesta son
|
|
536
|
+
* `Upload` enteros, no ids (§ el aviso de `Publication`).
|
|
537
|
+
* - **`id_account` cambia de forma según la operación**: aquí (crear, leer, reintentar) viene
|
|
538
|
+
* resuelto, y en el listado y al actualizar viene como identificador. `accountId(publication)`
|
|
539
|
+
* lo tapa.
|
|
540
|
+
* - **Borrar una publicación la borra TAMBIÉN de la red social.** No es sólo quitarla de la
|
|
541
|
+
* biblioteca.
|
|
542
|
+
*/
|
|
543
|
+
|
|
544
|
+
interface PublicationListOptions extends PageOptions {
|
|
545
|
+
/** Sólo las publicadas o creadas a partir de esta fecha, según `orderByPublish`. */
|
|
546
|
+
from_date?: Date | string | undefined;
|
|
547
|
+
/** Sólo hasta esta fecha. */
|
|
548
|
+
to_date?: Date | string | undefined;
|
|
549
|
+
/** Búsqueda de texto sobre el nombre, el texto y el título. */
|
|
550
|
+
search?: string | undefined;
|
|
551
|
+
/** Ordena y filtra por `publish_date` en vez de por `creation_date`. */
|
|
552
|
+
orderByPublish?: boolean | undefined;
|
|
553
|
+
/** Sólo estos estados. */
|
|
554
|
+
state?: readonly PublicationState[] | undefined;
|
|
555
|
+
/** Sólo estas cuentas, por identificador. */
|
|
556
|
+
accounts?: readonly string[] | undefined;
|
|
557
|
+
/** Sólo estas redes. */
|
|
558
|
+
social_network?: readonly SocialNetwork[] | undefined;
|
|
559
|
+
}
|
|
560
|
+
/** Lo que devuelve reintentar: la publicación tal y como quedó, y el tope que aplica el servidor. */
|
|
561
|
+
interface PublicationRetryResult {
|
|
562
|
+
publication: Publication;
|
|
563
|
+
/** Reintentos manuales que admite en total. Léelo de aquí en vez de escribirlo tú. */
|
|
564
|
+
max_retries: number;
|
|
565
|
+
}
|
|
566
|
+
declare class PublicationsResource extends Resource {
|
|
567
|
+
/**
|
|
568
|
+
* Crea una publicación en una cuenta.
|
|
569
|
+
*
|
|
570
|
+
* Sin `publish_date` se envía en esta misma petición y la respuesta ya dice si salió
|
|
571
|
+
* (`state: "sended"`) o si falló y por qué. Con fecha futura queda `ready`.
|
|
572
|
+
*
|
|
573
|
+
* ```ts
|
|
574
|
+
* const publication = await pv.publications.create(orgId, accountId, {
|
|
575
|
+
* social_network: "instagram",
|
|
576
|
+
* text: "Nuevo horno, nuevas hogazas",
|
|
577
|
+
* files: [upload._id],
|
|
578
|
+
* publish_date: new Date("2026-09-01T10:00:00Z"),
|
|
579
|
+
* });
|
|
580
|
+
* ```
|
|
581
|
+
*/
|
|
582
|
+
create(idOrganization: string, idAccount: string, body: PublicationInput, options?: RequestOptions): Promise<Publication>;
|
|
583
|
+
/** Una publicación, con sus ficheros y su cuenta ya resueltos. */
|
|
584
|
+
get(idOrganization: string, idPublication: string, options?: RequestOptions): Promise<Publication>;
|
|
585
|
+
/** Las publicaciones de una organización. */
|
|
586
|
+
list(idOrganization: string, options?: PublicationListOptions & RequestOptions): Promise<Paginated<Publication>>;
|
|
587
|
+
/** Las publicaciones de una organización, encadenando páginas. */
|
|
588
|
+
iterate(idOrganization: string, options?: PublicationListOptions & RequestOptions): AsyncGenerator<Publication>;
|
|
589
|
+
/** Las publicaciones de UNA cuenta. Mismos filtros que {@link list}. */
|
|
590
|
+
listByAccount(idOrganization: string, idAccount: string, options?: PublicationListOptions & RequestOptions): Promise<Paginated<Publication>>;
|
|
591
|
+
/**
|
|
592
|
+
* Cambia una publicación que todavía no ha salido. Una `sended` devuelve el error 921.
|
|
593
|
+
*
|
|
594
|
+
* Editar PONE EL CONTADOR DE REINTENTOS A CERO: el contador cuenta intentos de publicar *ese*
|
|
595
|
+
* contenido, y acabas de cambiarlo. Es además la salida cuando se agotan los tres.
|
|
596
|
+
*/
|
|
597
|
+
update(idOrganization: string, idPublication: string, body: Partial<PublicationInput>, options?: RequestOptions): Promise<Publication>;
|
|
598
|
+
/**
|
|
599
|
+
* Borra una publicación **y también el post en la red social**.
|
|
600
|
+
*
|
|
601
|
+
* En X borrar cuesta créditos: sin ellos devuelve un 940 en vez de un error genérico.
|
|
602
|
+
*/
|
|
603
|
+
remove(idOrganization: string, idPublication: string, options?: RequestOptions): Promise<void>;
|
|
604
|
+
/**
|
|
605
|
+
* Vuelve a intentar una publicación que falló, sin tocar su contenido.
|
|
606
|
+
*
|
|
607
|
+
* Se reintenta EN LA PETICIÓN, así que la respuesta ya dice si esta vez salió. Cada llamada
|
|
608
|
+
* gasta un reintento aunque vuelva a fallar por el contenido; sólo los créditos de X cortan
|
|
609
|
+
* antes de gastarlo. Una publicación que no está en `withErrors` devuelve un 949, y agotar el
|
|
610
|
+
* tope, un 950.
|
|
611
|
+
*/
|
|
612
|
+
retry(idOrganization: string, idPublication: string, options?: RequestOptions): Promise<PublicationRetryResult>;
|
|
613
|
+
/**
|
|
614
|
+
* Pide las métricas A LA RED, en vivo, y devuelve su desglose crudo.
|
|
615
|
+
*
|
|
616
|
+
* **En X esto cuesta un crédito por lectura.** Para pintar una gráfica usa {@link stats}, que
|
|
617
|
+
* lee lo ya medido y no cuesta nada.
|
|
618
|
+
*/
|
|
619
|
+
metrics(idOrganization: string, idPublication: string, options?: RequestOptions): Promise<PublicationStats>;
|
|
620
|
+
/**
|
|
621
|
+
* La evolución medida de una publicación: una fila por día, más su última medición.
|
|
622
|
+
*
|
|
623
|
+
* Es lectura pura de lo guardado: mirar la gráfica no llama a la red y no cuesta créditos. Una
|
|
624
|
+
* `series` vacía es una respuesta válida —recién enviada, o una red sin estadísticas—, no un
|
|
625
|
+
* error. Cada `metrics` es el ACUMULADO a esa fecha, no el incremento del día.
|
|
626
|
+
*/
|
|
627
|
+
stats(idOrganization: string, idPublication: string, options?: RequestOptions): Promise<PublicationStatsHistory>;
|
|
628
|
+
/**
|
|
629
|
+
* Lo que hay publicado en el muro de la cuenta **según la red**, no según PlanVortex: incluye
|
|
630
|
+
* lo que se publicó por fuera.
|
|
631
|
+
*
|
|
632
|
+
* **En X cuesta un crédito por elemento leído**, así que el `limit` es dinero.
|
|
633
|
+
*/
|
|
634
|
+
listOnNetwork(idOrganization: string, idAccount: string, options?: PageOptions & RequestOptions): Promise<Paginated<Publication>>;
|
|
635
|
+
private path;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Un fichero, en cualquiera de las formas en que un integrador lo tiene a mano.
|
|
640
|
+
*
|
|
641
|
+
* La ruta es la buena para lo grande: es la única que no pasa por memoria.
|
|
642
|
+
*/
|
|
643
|
+
type FileSource = string | Buffer | Uint8Array | Blob;
|
|
644
|
+
interface FileInput {
|
|
645
|
+
/** Ruta en disco, `Buffer` o `Blob`. */
|
|
646
|
+
file: FileSource;
|
|
647
|
+
/**
|
|
648
|
+
* Nombre con el que se guarda. Con una ruta se deduce del último tramo; con un `Buffer` es
|
|
649
|
+
* obligatorio, porque no hay de dónde sacarlo.
|
|
650
|
+
*/
|
|
651
|
+
filename?: string | undefined;
|
|
652
|
+
/**
|
|
653
|
+
* MIME de la parte. Se deduce de la extensión; pásalo cuando el nombre no la tenga o mienta.
|
|
654
|
+
* Es lo que decide `file_type` y `file_format` en el servidor.
|
|
655
|
+
*/
|
|
656
|
+
contentType?: string | undefined;
|
|
657
|
+
}
|
|
658
|
+
/** El MIME que le corresponde a un nombre de fichero, o `undefined` si la extensión no se conoce. */
|
|
659
|
+
declare function guessContentType(filename: string): string | undefined;
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* La biblioteca de ficheros de una organización: lo que se adjunta a una publicación.
|
|
663
|
+
*
|
|
664
|
+
* TRES AVISOS QUE AHORRAN UNA TARDE:
|
|
665
|
+
*
|
|
666
|
+
* 1. **`public_path` caduca.** Es una URL firmada, no un enlace permanente: se mantiene idéntica
|
|
667
|
+
* dentro de la misma hora —cachearla ese rato es correcto— y después deja de servir.
|
|
668
|
+
* Guardarla en tu base de datos es el error clásico; a los tres días están todas rotas.
|
|
669
|
+
* 2. **El tipo lo decide el `content-type` que mandes**, no el contenido ni la extensión. La
|
|
670
|
+
* librería lo deduce del nombre; si el nombre no lleva extensión, pásalo (§ `core/files.ts`).
|
|
671
|
+
* 3. **Los topes son del servidor**: 5 MB por imagen y 200 MB por vídeo, más la cuota de espacio
|
|
672
|
+
* de la organización. Los tres se comprueban contra los bytes que llegan de verdad, así que un
|
|
673
|
+
* fichero grande falla a mitad de subida con un 802, un 803 o un 804 — no antes de empezar.
|
|
674
|
+
*/
|
|
675
|
+
|
|
676
|
+
/** Un fichero de una integración que se quiere traer a la biblioteca. */
|
|
677
|
+
interface ImportFileInput {
|
|
678
|
+
/** Identificador del fichero en el proveedor (el id del fichero en Drive). */
|
|
679
|
+
external_id: string;
|
|
680
|
+
/** Nombre que enseñó el selector. Se usa para el nombre visible y para decir cuál falló. */
|
|
681
|
+
name?: string | undefined;
|
|
682
|
+
/** Tipo que declaró el selector. Sirve para rechazar pronto; manda el tipo real del cuerpo. */
|
|
683
|
+
mime_type?: string | undefined;
|
|
684
|
+
}
|
|
685
|
+
/** Lo que NO entró en una importación, fichero a fichero. */
|
|
686
|
+
interface ImportError {
|
|
687
|
+
external_id?: string;
|
|
688
|
+
name?: string;
|
|
689
|
+
code: number;
|
|
690
|
+
message: string;
|
|
691
|
+
data?: Record<string, unknown>;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* El resultado de una importación, que es PARCIAL a propósito: `uploads` con lo que entró y
|
|
695
|
+
* `errors` con lo que no, para poder decir cuál de los seis ficheros elegidos falló y por qué.
|
|
696
|
+
*/
|
|
697
|
+
interface ImportResult {
|
|
698
|
+
uploads: Upload[];
|
|
699
|
+
errors: ImportError[];
|
|
700
|
+
}
|
|
701
|
+
/** Los ajustes de portada de un vídeo. Lo único que un upload deja cambiar. */
|
|
702
|
+
interface UploadUpdate {
|
|
703
|
+
/**
|
|
704
|
+
* Identificador de OTRO upload, que tiene que ser una imagen, para usarlo de portada.
|
|
705
|
+
* Reemplazar una portada borra la anterior.
|
|
706
|
+
*/
|
|
707
|
+
cover_image?: string | undefined;
|
|
708
|
+
/**
|
|
709
|
+
* Momento del vídeo, en milisegundos, que se usa de fotograma de portada.
|
|
710
|
+
*
|
|
711
|
+
* CUIDADO: **se escribe siempre**, así que omitirlo borra el valor guardado. Si sólo quieres
|
|
712
|
+
* cambiar `cover_image`, manda también el `cover_offset` que ya tenía.
|
|
713
|
+
*/
|
|
714
|
+
cover_offset?: number | undefined;
|
|
715
|
+
}
|
|
716
|
+
declare class UploadsResource extends Resource {
|
|
717
|
+
/**
|
|
718
|
+
* Sube un fichero. Admite una ruta en disco, un `Buffer` o un `Blob`.
|
|
719
|
+
*
|
|
720
|
+
* La ruta es la buena para lo grande: es la única forma que no pasa el fichero por memoria.
|
|
721
|
+
*
|
|
722
|
+
* ```ts
|
|
723
|
+
* await pv.uploads.create(orgId, { file: "./hogaza.jpg" });
|
|
724
|
+
* await pv.uploads.create(orgId, { file: bytes, filename: "hogaza.jpg" });
|
|
725
|
+
* ```
|
|
726
|
+
*/
|
|
727
|
+
create(idOrganization: string, input: FileInput, options?: RequestOptions): Promise<Upload>;
|
|
728
|
+
/**
|
|
729
|
+
* Los ficheros de la biblioteca.
|
|
730
|
+
*
|
|
731
|
+
* No salen aquí los recortes que la plataforma se hace para sí misma (`is_temporal`) ni las
|
|
732
|
+
* portadas de vídeo, que son otro upload y viajan dentro del suyo.
|
|
733
|
+
*/
|
|
734
|
+
list(idOrganization: string, options?: PageOptions & RequestOptions): Promise<Paginated<Upload>>;
|
|
735
|
+
/** Los ficheros de la biblioteca, encadenando páginas. */
|
|
736
|
+
iterate(idOrganization: string, options?: PageOptions & RequestOptions): AsyncGenerator<Upload>;
|
|
737
|
+
/** Un fichero. Pídelo de nuevo cuando necesites un `public_path` vigente. */
|
|
738
|
+
get(idOrganization: string, idUpload: string, options?: RequestOptions): Promise<Upload>;
|
|
739
|
+
/** Cambia la portada de un vídeo. Ojo con `cover_offset`: se escribe siempre (ver arriba). */
|
|
740
|
+
update(idOrganization: string, idUpload: string, body: UploadUpdate, options?: RequestOptions): Promise<Upload>;
|
|
741
|
+
/**
|
|
742
|
+
* Borra un fichero.
|
|
743
|
+
*
|
|
744
|
+
* Con `force` se borra aunque una publicación siga apuntándolo; sin él, un fichero en uso se
|
|
745
|
+
* conserva y sólo se saca de la biblioteca.
|
|
746
|
+
*/
|
|
747
|
+
remove(idOrganization: string, idUpload: string, options?: {
|
|
748
|
+
force?: boolean | undefined;
|
|
749
|
+
} & RequestOptions): Promise<void>;
|
|
750
|
+
/**
|
|
751
|
+
* Trae a la biblioteca ficheros elegidos en una integración (el selector de Drive).
|
|
752
|
+
*
|
|
753
|
+
* La respuesta es PARCIAL a propósito: mira `errors` aunque `uploads` traiga algo — de seis
|
|
754
|
+
* ficheros pueden entrar cuatro. Un `2204` significa que el proveedor no da los bytes: un
|
|
755
|
+
* documento nativo de Google no tiene fichero que descargar.
|
|
756
|
+
*/
|
|
757
|
+
import(idOrganization: string, idIntegration: string, files: readonly ImportFileInput[], options?: RequestOptions): Promise<ImportResult>;
|
|
758
|
+
private path;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
interface PlanVortexOptions {
|
|
762
|
+
/** El identificador de la app de cliente. Por defecto, `process.env.PLANVORTEX_CLIENT_ID`. */
|
|
763
|
+
clientId?: string | undefined;
|
|
764
|
+
/** El secreto de la app. Por defecto, `process.env.PLANVORTEX_CLIENT_SECRET`. */
|
|
765
|
+
clientSecret?: string | undefined;
|
|
766
|
+
/**
|
|
767
|
+
* Un token ya emitido, en vez de credenciales: el `temporal_connect_token` con el que una
|
|
768
|
+
* persona conecta su cuenta social. No se refresca solo (§ trampa 2 del roadmap).
|
|
769
|
+
*/
|
|
770
|
+
accessToken?: string | undefined;
|
|
771
|
+
/** Por defecto `https://api.planvortex.com/v1.0.0`. Sin barra final. */
|
|
772
|
+
baseUrl?: string | undefined;
|
|
773
|
+
/** Timeout por petición. 120 s por defecto: publicar un vídeo es lento. */
|
|
774
|
+
timeoutMs?: number | undefined;
|
|
775
|
+
retry?: Partial<RetryConfig> | undefined;
|
|
776
|
+
/** `onRequest` / `onResponse` / `onRetry`, para enchufar el logger de casa. */
|
|
777
|
+
hooks?: HttpHooks | undefined;
|
|
778
|
+
/** `fetch` alternativo: un proxy, un mock, una implementación instrumentada. */
|
|
779
|
+
fetch?: FetchLike | undefined;
|
|
780
|
+
/** `scope` opcional del `client_credentials`. Casi nadie lo necesita. */
|
|
781
|
+
scope?: string | undefined;
|
|
782
|
+
/**
|
|
783
|
+
* Deja construir el cliente en un navegador. **No lo pongas.** El `client_credentials` exige el
|
|
784
|
+
* `client_secret`, y un secreto en un bundle de front es la cuenta entera regalada
|
|
785
|
+
* (§ trampa 9). Para el navegador existe el token temporal de conexión.
|
|
786
|
+
*/
|
|
787
|
+
dangerouslyAllowBrowser?: boolean | undefined;
|
|
788
|
+
}
|
|
789
|
+
declare class PlanVortex {
|
|
790
|
+
/** Sin barra final. Útil para componer una URL a mano cuando haga falta. */
|
|
791
|
+
readonly baseUrl: string;
|
|
792
|
+
/** Metadatos estáticos de las redes: qué hay, qué sabe hacer cada una y sus límites. Cacheado. */
|
|
793
|
+
readonly catalog: CatalogResource;
|
|
794
|
+
/** Clientes: el plan contratado y sus organizaciones raíz. */
|
|
795
|
+
readonly clients: ClientsResource;
|
|
796
|
+
/** Organizaciones: la ficha, las hijas, y el cupo que tienen y gastan. */
|
|
797
|
+
readonly organizations: OrganizationsResource;
|
|
798
|
+
/** Cuentas sociales conectadas. Conectar una es otra cosa: hace falta una persona (§ fase 9). */
|
|
799
|
+
readonly accounts: AccountsResource;
|
|
800
|
+
/** La biblioteca de ficheros de una organización. */
|
|
801
|
+
readonly uploads: UploadsResource;
|
|
802
|
+
/** Publicaciones: crear, programar, reintentar y medir. */
|
|
803
|
+
readonly publications: PublicationsResource;
|
|
804
|
+
private readonly http;
|
|
805
|
+
private readonly auth;
|
|
806
|
+
private readonly options;
|
|
807
|
+
constructor(options?: PlanVortexOptions);
|
|
808
|
+
/**
|
|
809
|
+
* Una petición autenticada. Es lo que usarán los recursos de las fases 6 y 7; un integrador no
|
|
810
|
+
* debería necesitarla, pero está expuesta para no dejar a nadie tirado ante un endpoint que la
|
|
811
|
+
* librería aún no cubra.
|
|
812
|
+
*
|
|
813
|
+
* Reintenta **una sola vez** ante los códigos de token (501 y 522), que llegan dentro de un 400.
|
|
814
|
+
* Un token puede morir antes de su `expires_in` —un despliegue de Keycloak, la app revocada— y
|
|
815
|
+
* ese caso se arregla pidiendo otro; si el segundo también falla, el error sale.
|
|
816
|
+
*/
|
|
817
|
+
request<T>(request: HttpRequest): Promise<HttpResponse<T>>;
|
|
818
|
+
/**
|
|
819
|
+
* El mismo cliente, con la misma forma, autenticado con un token temporal de conexión.
|
|
820
|
+
*
|
|
821
|
+
* Es la pieza del flujo de conexión de cuentas (§ trampa 2): una app **no** puede conectar una
|
|
822
|
+
* cuenta de Instagram —eso es un OAuth con una persona delante—, así que emite un token
|
|
823
|
+
* temporal, se lo pasa a su usuario y con él se piden los `connect_links`. El token va atado a
|
|
824
|
+
* una sola organización: usarlo contra otra devuelve el error 1101.
|
|
825
|
+
*/
|
|
826
|
+
asTemporalToken(token: string): PlanVortex;
|
|
827
|
+
private send;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/** Lo que devuelve `POST /oauth/token`. Ni `refresh_token` ni `id_token`: no existen aquí. */
|
|
831
|
+
interface ClientCredentialsToken {
|
|
832
|
+
access_token: string;
|
|
833
|
+
token_type: string;
|
|
834
|
+
/** Segundos de vida. Keycloak da 300 hoy, pero es dato del servidor: nunca se asume. */
|
|
835
|
+
expires_in: number;
|
|
836
|
+
scope?: string;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* De dónde sale el `Authorization` de cada petición. Dos implementaciones: las credenciales de app
|
|
840
|
+
* ({@link ClientCredentialsAuth}) y el token temporal de conexión ({@link StaticTokenAuth}).
|
|
841
|
+
*/
|
|
842
|
+
interface AuthProvider {
|
|
843
|
+
/** El token a poner en `Authorization: Bearer`. Pide uno nuevo si hace falta. */
|
|
844
|
+
getToken(): Promise<string>;
|
|
845
|
+
/** Tira el token cacheado. Lo llama el cliente cuando el servidor responde 501 o 522. */
|
|
846
|
+
invalidate(): void;
|
|
847
|
+
}
|
|
848
|
+
/** Margen con el que se pide un token nuevo antes de que caduque el que hay. */
|
|
849
|
+
declare const TOKEN_REFRESH_MARGIN_MS = 60000;
|
|
850
|
+
|
|
851
|
+
export { Account, type AccountCapability, type AccountListOptions, AccountMetrics, type AccountMetricsOptions, AccountsResource, AspectRatiosByNetwork, type AuthProvider, CatalogResource, type ChildOrganizationListOptions, Client, type ClientCredentialsToken, type ClientListOptions, ClientsResource, CommentActions, type ConnectCallbackParams, ConnectLink, type ConnectLinksOptions, ConnectResult, ConnectToken, type ConnectTokenOptions, DEFAULT_PAGE_SIZE, DEFAULT_RETRY, DEFAULT_TIMEOUT_MS, EnableResult, type FetchLike, type FileInput, type FileSource, type HttpHooks, type HttpMethod, type HttpRequest, type HttpResponse, type ImportError, type ImportFileInput, type ImportResult, MAX_PAGES, Organization, type OrganizationInput, type OrganizationListOptions, type OrganizationOptions, type OrganizationPlanInput, OrganizationsResource, PLANVORTEX_API_URL, type PageOptions, Paginated, PersistentMenu, PlanData, PlanVortex, type PlanVortexOptions, Publication, PublicationInput, PublicationLimits, type PublicationListOptions, type PublicationRetryResult, PublicationState, PublicationStats, PublicationStatsHistory, PublicationsResource, type RequestInfo, type RequestOptions, type ResponseInfo, type RetryConfig, type RetryInfo, SocialCapabilities, SocialLimits, SocialNetwork, TOKEN_REFRESH_MARGIN_MS, Upload, type UploadUpdate, UploadsResource, VERSION, guessContentType };
|