@vivoa/partner-sdk 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +94 -88
- package/dist/cjs/adapters/in-memory/fake-vivoa.js +4 -2
- package/dist/cjs/application/partner-client.d.ts +2 -1
- package/dist/cjs/application/partner-client.js +3 -2
- package/dist/cjs/application/resources/merchants.js +2 -1
- package/dist/cjs/application/use-cases/provision-store.js +2 -2
- package/dist/cjs/domain/webhook.d.ts +1 -1
- package/dist/cjs/version.d.ts +1 -0
- package/dist/cjs/version.js +4 -0
- package/dist/esm/adapters/in-memory/fake-vivoa.js +4 -2
- package/dist/esm/application/partner-client.d.ts +2 -1
- package/dist/esm/application/partner-client.js +2 -1
- package/dist/esm/application/resources/merchants.js +2 -1
- package/dist/esm/application/use-cases/provision-store.js +2 -2
- package/dist/esm/domain/webhook.d.ts +1 -1
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
- fix: `provisionStore` now throws `VivoaProvisioningFailedError` on `'unknown'` runtime instead of returning a broken store silently.
|
|
6
|
+
- fix: `FakeVivoa.activate` now returns 409 on merchants in `'unknown'` state, matching platform behavior.
|
|
7
|
+
- fix: `SDK_VERSION` extracted to `src/version.ts` — User-Agent header stays in sync with `package.json` on every bump.
|
|
8
|
+
- fix: `WebhookConfig.events` typed as `MerchantEventType[]` instead of `string[]`.
|
|
9
|
+
- fix: `listAll` throws after 10 000 pages instead of looping forever on a misbehaving server.
|
|
10
|
+
- test: contract suite covers `suspend → reactivate` lifecycle.
|
|
11
|
+
|
|
3
12
|
## 0.1.0
|
|
4
13
|
|
|
5
14
|
Primera versión.
|
package/README.md
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
# @vivoa/partner-sdk
|
|
2
2
|
|
|
3
|
+
**Embed full commerce stores in your product — provisioned via API, branded as yours.**
|
|
4
|
+
|
|
5
|
+
Your users launch their store through your platform. Vivoa runs the infrastructure. They never see Vivoa.
|
|
6
|
+
|
|
3
7
|
```bash
|
|
4
|
-
pnpm add @vivoa/partner-sdk
|
|
8
|
+
pnpm add @vivoa/partner-sdk
|
|
5
9
|
```
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
[](https://www.npmjs.com/package/@vivoa/partner-sdk)
|
|
12
|
+
[](https://www.typescriptlang.org/)
|
|
13
|
+
[](https://nodejs.org/)
|
|
14
|
+
|
|
15
|
+
---
|
|
8
16
|
|
|
9
|
-
|
|
10
|
-
- **Arquitectura hexagonal**: el núcleo no hace I/O. El transporte, la criptografía y el reloj son puertos que puedes cambiar.
|
|
11
|
-
- **El handle lo asigna Vivoa**: no lo eliges tú al crear un merchant — la plataforma lo genera a partir de `name` y garantiza que sea único. Menos que validar, nada que pueda chocar.
|
|
12
|
-
- **Seguro ante reintentos**: `provisionStore()` usa tu propio `externalId` como clave de idempotencia. Si lo vuelves a llamar después de un crash o un timeout, retoma la misma tienda en vez de crear otra.
|
|
13
|
-
- **Testeable sin Vivoa**: `@vivoa/partner-sdk/testing` trae un Vivoa en memoria que verifica la firma HMAC real y aplica las mismas reglas que la plataforma.
|
|
17
|
+
## What you get
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
- **One call to provision a store.** `provisionStore()` handles creation, activation, and recovery — idempotent by design. Crash, retry, same store.
|
|
20
|
+
- **Your brand, your API.** Merchants interact with your product. The Vivoa layer is yours to expose however you want.
|
|
21
|
+
- **Production-safe from day one.** Fully typed errors, automatic retries on reads, HMAC-signed requests, webhook verification included.
|
|
22
|
+
- **Test without hitting Vivoa.** The built-in `FakeVivoa` runs the same business rules as production — including real HMAC verification. No brittle mocks.
|
|
23
|
+
- **Zero runtime dependencies.** Uses native `fetch` and `node:crypto`. No supply-chain risk. Drop-in on any runtime.
|
|
24
|
+
|
|
25
|
+
---
|
|
16
26
|
|
|
17
27
|
## Quickstart
|
|
18
28
|
|
|
@@ -20,56 +30,69 @@ Guía de producto: [`docs/PARTNERS.md`](https://github.com/VivoaPlatform/vivoa-p
|
|
|
20
30
|
import { createPartnerClient } from '@vivoa/partner-sdk';
|
|
21
31
|
|
|
22
32
|
const vivoa = createPartnerClient({
|
|
23
|
-
apiKey:
|
|
33
|
+
apiKey: process.env.VIVOA_PARTNER_KEY!,
|
|
24
34
|
apiSecret: process.env.VIVOA_PARTNER_SECRET!,
|
|
25
|
-
// baseUrl: 'https://api.vivoa.app' (default)
|
|
26
35
|
});
|
|
27
36
|
|
|
28
|
-
|
|
37
|
+
// Provision a store for one of your users — idempotent on externalId
|
|
38
|
+
const { merchant, status } = await vivoa.provisionStore({
|
|
39
|
+
externalId: 'cus_9f3a2e10', // your internal reference — customer id, order id, etc.
|
|
40
|
+
email: 'owner@acme.com',
|
|
41
|
+
name: 'Acme',
|
|
42
|
+
countries: ['SV'],
|
|
43
|
+
});
|
|
29
44
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{ onProgress: (p) => console.log(p.phase, p.runtime) },
|
|
33
|
-
);
|
|
34
|
-
// merchant.handle → asignado por Vivoa; status.deployStatus === 'live'; status.domain → dominio de la tienda
|
|
45
|
+
console.log(status.domain); // store is live at this domain
|
|
46
|
+
console.log(merchant.handle); // Vivoa-assigned handle, guaranteed unique
|
|
35
47
|
```
|
|
36
48
|
|
|
37
|
-
`externalId`
|
|
49
|
+
`externalId` is your key. Use it to find the store later (`findByExternalId`), and call `provisionStore` again safely — it won't create a duplicate.
|
|
50
|
+
|
|
51
|
+
---
|
|
38
52
|
|
|
39
|
-
`provisionStore`
|
|
53
|
+
## `provisionStore` — full flow
|
|
40
54
|
|
|
41
|
-
|
|
42
|
-
2. Activa la tienda si está `not_activated` o `failed`.
|
|
43
|
-
3. Si queda `creating`, consulta el estado hasta que se asiente.
|
|
44
|
-
4. Si el `activate` devuelve 409 o se cae la conexión, se recupera leyendo `GET /status`.
|
|
45
|
-
5. Nunca reintenta por su cuenta un `failed`: lanza `VivoaProvisioningFailedError` y la decisión queda en tus manos.
|
|
55
|
+
One call drives the entire lifecycle:
|
|
46
56
|
|
|
47
|
-
|
|
57
|
+
1. Looks up `externalId` in your fleet — if it exists, resumes from current state.
|
|
58
|
+
2. Creates the store if it doesn't exist (Vivoa assigns the `handle` from `name`).
|
|
59
|
+
3. Activates if `not_activated` or `failed`.
|
|
60
|
+
4. Polls until settled if `creating`.
|
|
61
|
+
5. Recovers from a dropped `activate` by reading `GET /status`.
|
|
62
|
+
6. Never silently retries a `failed` — throws `VivoaProvisioningFailedError` so you decide what happens next.
|
|
48
63
|
|
|
49
|
-
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## API surface
|
|
67
|
+
|
|
68
|
+
| Resource | Methods |
|
|
50
69
|
|---|---|
|
|
51
|
-
| `me` | `get()`, `rotateSecret()`
|
|
52
|
-
| `merchants` | `create`, `list`, `listAll()` (
|
|
70
|
+
| `me` | `get()`, `rotateSecret()` |
|
|
71
|
+
| `merchants` | `create`, `list`, `listAll()` (async iterator), `findByExternalId`, `status`, `activate`, `suspend`, `reactivate` |
|
|
53
72
|
| `webhooks` | `get`, `set`, `remove`, `rotateSecret`, `test`, `deliveries` |
|
|
54
73
|
| `fleet` | `analytics()` |
|
|
55
|
-
|
|
|
74
|
+
| client | `provisionStore`, `waitUntilSettled`, `verifyWebhook` |
|
|
75
|
+
|
|
76
|
+
---
|
|
56
77
|
|
|
57
|
-
##
|
|
78
|
+
## Errors
|
|
58
79
|
|
|
59
|
-
|
|
80
|
+
All errors extend `VivoaError`. HTTP errors are `VivoaApiError` with `status`, `method`, `path`, and `body`.
|
|
60
81
|
|
|
61
|
-
|
|
|
82
|
+
| Class | When |
|
|
62
83
|
|---|---|
|
|
63
|
-
| `VivoaValidationError` |
|
|
64
|
-
| `VivoaBadRequestError` (400) |
|
|
65
|
-
| `VivoaAuthenticationError` (401) |
|
|
66
|
-
| `VivoaForbiddenError` (403) |
|
|
67
|
-
| `VivoaNotFoundError` (404) |
|
|
68
|
-
| `VivoaConflictError` (409) | `activate`
|
|
69
|
-
| `VivoaRateLimitError` (429) |
|
|
70
|
-
| `VivoaServerError`
|
|
84
|
+
| `VivoaValidationError` | Invalid input caught client-side before any request |
|
|
85
|
+
| `VivoaBadRequestError` (400) | Invalid payload or country outside `allowedRegions` |
|
|
86
|
+
| `VivoaAuthenticationError` (401) | HMAC signature, key, or clock skew (±300 s) |
|
|
87
|
+
| `VivoaForbiddenError` (403) | Inactive account or quota exhausted |
|
|
88
|
+
| `VivoaNotFoundError` (404) | Store not in your fleet |
|
|
89
|
+
| `VivoaConflictError` (409) | `activate` on a store already live or in progress |
|
|
90
|
+
| `VivoaRateLimitError` (429) | Plan request limit exceeded |
|
|
91
|
+
| `VivoaServerError` · `VivoaNetworkError` · `VivoaTimeoutError` · `VivoaProvisioningFailedError` | Server, network, polling, or provisioning failures |
|
|
71
92
|
|
|
72
|
-
|
|
93
|
+
**Retry policy:** `GET` only, on 429 / 5xx / network errors, with exponential backoff. Writes are not retried at the transport level — but `merchants.create()` and `provisionStore()` are safe to repeat thanks to `externalId` idempotency.
|
|
94
|
+
|
|
95
|
+
---
|
|
73
96
|
|
|
74
97
|
## Webhooks
|
|
75
98
|
|
|
@@ -80,83 +103,66 @@ import { verifyWebhook, VivoaWebhookSignatureError } from '@vivoa/partner-sdk';
|
|
|
80
103
|
app.post('/vivoa-hooks', express.raw({ type: 'application/json' }), async (req, res) => {
|
|
81
104
|
try {
|
|
82
105
|
const event = await verifyWebhook({
|
|
83
|
-
rawBody:
|
|
106
|
+
rawBody: req.body,
|
|
84
107
|
signatureHeader: req.header('x-vivoa-signature'),
|
|
85
|
-
signingSecret:
|
|
108
|
+
signingSecret: process.env.VIVOA_WEBHOOK_SECRET!,
|
|
86
109
|
});
|
|
87
|
-
res.sendStatus(204);
|
|
88
|
-
queue.push(event);
|
|
110
|
+
res.sendStatus(204); // respond fast, process async
|
|
111
|
+
queue.push(event);
|
|
89
112
|
} catch (err) {
|
|
90
113
|
res.sendStatus(err instanceof VivoaWebhookSignatureError ? 401 : 500);
|
|
91
114
|
}
|
|
92
115
|
});
|
|
93
116
|
```
|
|
94
117
|
|
|
95
|
-
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Testing
|
|
121
|
+
|
|
122
|
+
`@vivoa/partner-sdk/testing` ships a `FakeVivoa` that runs the same rules as the real server — real HMAC verification, real business logic, zero network.
|
|
96
123
|
|
|
97
124
|
```ts
|
|
98
125
|
import { createPartnerClient } from '@vivoa/partner-sdk';
|
|
99
126
|
import { FakeVivoa, ManualClock } from '@vivoa/partner-sdk/testing';
|
|
100
127
|
|
|
101
|
-
const clock
|
|
102
|
-
const
|
|
128
|
+
const clock = new ManualClock();
|
|
129
|
+
const fake = new FakeVivoa({
|
|
103
130
|
clock,
|
|
104
|
-
operators:
|
|
105
|
-
activation: 'slow',
|
|
106
|
-
onWebhook:
|
|
131
|
+
operators: [{ apiKey: 'k', apiSecret: 's', allowedRegions: ['SV'], maxStores: 3 }],
|
|
132
|
+
activation: 'slow', // 'live' | 'slow' | 'fail' | 'drop'
|
|
133
|
+
onWebhook: (d) => deliveries.push(d),
|
|
107
134
|
});
|
|
108
|
-
const client = createPartnerClient({ apiKey: 'k', apiSecret: 's', transport:
|
|
135
|
+
const client = createPartnerClient({ apiKey: 'k', apiSecret: 's', transport: fake, clock });
|
|
109
136
|
```
|
|
110
137
|
|
|
111
|
-
|
|
138
|
+
The same contract suite runs against `FakeVivoa` and against production. If the fake drifts from the real server, the live run fails on the same assertion.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Architecture
|
|
112
143
|
|
|
113
144
|
```
|
|
114
145
|
src/
|
|
115
|
-
domain/
|
|
146
|
+
domain/ types, lifecycle rules, errors (pure — no I/O)
|
|
116
147
|
ports/ HttpTransport · CryptoProvider · Clock · SdkLogger
|
|
117
|
-
application/ SignedHttpClient · resources/ ·
|
|
118
|
-
adapters/ fetch · node-crypto · system
|
|
148
|
+
application/ SignedHttpClient · resources/ · provision-store · VivoaPartnerClient
|
|
149
|
+
adapters/ fetch · node-crypto · system clock · ManualClock · FakeVivoa
|
|
119
150
|
webhooks/ verifyWebhook
|
|
120
151
|
index.ts composition root (createPartnerClient)
|
|
121
152
|
cli.ts driving adapter (vivoa-partner)
|
|
122
153
|
```
|
|
123
154
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Para llevar el SDK a otro runtime basta con un adapter nuevo, por ejemplo WebCrypto para edge o un transporte con métricas. Cuando el backend sume endpoints, se agregan como recursos. En ningún caso hay que tocar el núcleo.
|
|
127
|
-
|
|
128
|
-
## CLI
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
export VIVOA_PARTNER_KEY=… VIVOA_PARTNER_SECRET=… # solo por env, nunca por flags
|
|
132
|
-
node src/cli.ts me
|
|
133
|
-
node src/cli.ts merchants list --search acme
|
|
134
|
-
node src/cli.ts store create --external-id cus_1 --name Acme --email owner@acme.com --countries SV --yes
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Publicar
|
|
155
|
+
`domain` imports nothing external. `application` imports only `domain` and `ports`. `adapters` implement `ports`. A new runtime needs only a new adapter — the core is untouched.
|
|
138
156
|
|
|
139
|
-
|
|
140
|
-
# subir "version" en package.json + CHANGELOG.md
|
|
141
|
-
pnpm publish # prepublishOnly: typecheck + test + build + test:dist
|
|
142
|
-
```
|
|
157
|
+
---
|
|
143
158
|
|
|
144
|
-
|
|
159
|
+
## Further reading
|
|
145
160
|
|
|
146
|
-
|
|
161
|
+
- [Partner program guide](https://github.com/VivoaPlatform/vivoa-platform/blob/main/docs/PARTNERS.md)
|
|
162
|
+
- [Server contract](https://github.com/VivoaPlatform/vivoa-platform/blob/main/packages/backend/src/engine/partner-api/CONTRACT.md)
|
|
147
163
|
|
|
148
|
-
|
|
164
|
+
---
|
|
149
165
|
|
|
150
|
-
|
|
151
|
-
pnpm test # unit + contrato contra FakeVivoa
|
|
152
|
-
pnpm typecheck # tsc (src + tests)
|
|
153
|
-
pnpm build # dist/esm + dist/cjs (+ .d.ts)
|
|
154
|
-
pnpm test:dist # smoke de los entry points publicados (require + import)
|
|
155
|
-
|
|
156
|
-
# Mismo contrato contra la API real. Por defecto solo lee:
|
|
157
|
-
VIVOA_LIVE=1 VIVOA_PARTNER_KEY=… VIVOA_PARTNER_SECRET=… pnpm test:live
|
|
158
|
-
# Crea y activa UNA tienda sdk-e2e-<ts> (consume cupo e infraestructura real):
|
|
159
|
-
VIVOA_LIVE=1 VIVOA_LIVE_WRITE=1 … pnpm test:live
|
|
160
|
-
```
|
|
166
|
+
## License
|
|
161
167
|
|
|
162
|
-
|
|
168
|
+
Private — authorized Vivoa partners only.
|
|
@@ -271,10 +271,12 @@ class FakeVivoa {
|
|
|
271
271
|
throw new HttpError(500, `Could not allocate a free handle for "${name}"`);
|
|
272
272
|
}
|
|
273
273
|
activate(op, m) {
|
|
274
|
-
if (m.runtime === 'creating' || m.runtime === 'live' || m.runtime === 'suspended') {
|
|
274
|
+
if (m.runtime === 'creating' || m.runtime === 'live' || m.runtime === 'suspended' || m.runtime === 'unknown') {
|
|
275
275
|
throw new HttpError(409, m.runtime === 'suspended'
|
|
276
276
|
? `Merchant '${m.handle}' is suspended — use reactivate instead`
|
|
277
|
-
:
|
|
277
|
+
: m.runtime === 'unknown'
|
|
278
|
+
? `Merchant '${m.handle}' is in an unrecoverable state`
|
|
279
|
+
: `Merchant '${m.handle}' is already ${m.runtime}`);
|
|
278
280
|
}
|
|
279
281
|
switch (this.activation) {
|
|
280
282
|
case 'fail':
|
|
@@ -10,7 +10,8 @@ import { type ProvisionStoreOptions, type ProvisionStoreResult } from './use-cas
|
|
|
10
10
|
import { type VerifyWebhookParams } from '../webhooks/verify-webhook.ts';
|
|
11
11
|
import type { CreateMerchantInput, MerchantStatus } from '../domain/merchant.ts';
|
|
12
12
|
import type { WebhookEvent } from '../domain/webhook.ts';
|
|
13
|
-
|
|
13
|
+
import { SDK_VERSION } from '../version.ts';
|
|
14
|
+
export { SDK_VERSION };
|
|
14
15
|
/** Every adapter is injected — the client itself has no I/O of its own. */
|
|
15
16
|
export interface PartnerClientDeps {
|
|
16
17
|
baseUrl: string;
|
|
@@ -9,7 +9,8 @@ const webhooks_ts_1 = require("./resources/webhooks.js");
|
|
|
9
9
|
const fleet_ts_1 = require("./resources/fleet.js");
|
|
10
10
|
const provision_store_ts_1 = require("./use-cases/provision-store.js");
|
|
11
11
|
const verify_webhook_ts_1 = require("../webhooks/verify-webhook.js");
|
|
12
|
-
|
|
12
|
+
const version_ts_1 = require("../version.js");
|
|
13
|
+
Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return version_ts_1.SDK_VERSION; } });
|
|
13
14
|
class VivoaPartnerClient {
|
|
14
15
|
me;
|
|
15
16
|
merchants;
|
|
@@ -28,7 +29,7 @@ class VivoaPartnerClient {
|
|
|
28
29
|
logger: deps.logger ?? logger_port_ts_1.silentLogger,
|
|
29
30
|
timeoutMs: deps.timeoutMs ?? 30_000,
|
|
30
31
|
maxRetries: deps.maxRetries ?? 2,
|
|
31
|
-
userAgent: `vivoa-partner-sdk/${
|
|
32
|
+
userAgent: `vivoa-partner-sdk/${version_ts_1.SDK_VERSION}`,
|
|
32
33
|
});
|
|
33
34
|
this.crypto = deps.crypto;
|
|
34
35
|
this.me = new me_ts_1.MeResource(http);
|
|
@@ -30,12 +30,13 @@ class MerchantsResource {
|
|
|
30
30
|
/** Walks every page of the fleet. */
|
|
31
31
|
async *listAll(query = {}) {
|
|
32
32
|
const limit = query.limit ?? 100;
|
|
33
|
-
for (let page = 1
|
|
33
|
+
for (let page = 1; page <= 10_000; page++) {
|
|
34
34
|
const res = await this.list({ ...query, page, limit });
|
|
35
35
|
yield* res.data;
|
|
36
36
|
if (res.data.length === 0 || page * limit >= res.meta.total)
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
+
throw new Error('listAll: exceeded maximum page limit (10 000)');
|
|
39
40
|
}
|
|
40
41
|
/** The merchant created with this reference, or `null` — an exact server-side match. */
|
|
41
42
|
async findByExternalId(externalId) {
|
|
@@ -46,8 +46,8 @@ class ProvisionStoreUseCase {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
progress('settled', merchant, status.deployStatus);
|
|
49
|
-
if (status.deployStatus === 'failed') {
|
|
50
|
-
throw new errors_ts_1.VivoaProvisioningFailedError(merchant.id,
|
|
49
|
+
if (status.deployStatus === 'failed' || status.deployStatus === 'unknown') {
|
|
50
|
+
throw new errors_ts_1.VivoaProvisioningFailedError(merchant.id, `the platform reported runtime status "${status.deployStatus}"`);
|
|
51
51
|
}
|
|
52
52
|
return { merchant: { ...merchant, runtime: status.deployStatus, domain: status.domain }, status, created };
|
|
53
53
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SDK_VERSION = "0.1.1";
|
|
@@ -268,10 +268,12 @@ export class FakeVivoa {
|
|
|
268
268
|
throw new HttpError(500, `Could not allocate a free handle for "${name}"`);
|
|
269
269
|
}
|
|
270
270
|
activate(op, m) {
|
|
271
|
-
if (m.runtime === 'creating' || m.runtime === 'live' || m.runtime === 'suspended') {
|
|
271
|
+
if (m.runtime === 'creating' || m.runtime === 'live' || m.runtime === 'suspended' || m.runtime === 'unknown') {
|
|
272
272
|
throw new HttpError(409, m.runtime === 'suspended'
|
|
273
273
|
? `Merchant '${m.handle}' is suspended — use reactivate instead`
|
|
274
|
-
:
|
|
274
|
+
: m.runtime === 'unknown'
|
|
275
|
+
? `Merchant '${m.handle}' is in an unrecoverable state`
|
|
276
|
+
: `Merchant '${m.handle}' is already ${m.runtime}`);
|
|
275
277
|
}
|
|
276
278
|
switch (this.activation) {
|
|
277
279
|
case 'fail':
|
|
@@ -10,7 +10,8 @@ import { type ProvisionStoreOptions, type ProvisionStoreResult } from './use-cas
|
|
|
10
10
|
import { type VerifyWebhookParams } from '../webhooks/verify-webhook.ts';
|
|
11
11
|
import type { CreateMerchantInput, MerchantStatus } from '../domain/merchant.ts';
|
|
12
12
|
import type { WebhookEvent } from '../domain/webhook.ts';
|
|
13
|
-
|
|
13
|
+
import { SDK_VERSION } from '../version.ts';
|
|
14
|
+
export { SDK_VERSION };
|
|
14
15
|
/** Every adapter is injected — the client itself has no I/O of its own. */
|
|
15
16
|
export interface PartnerClientDeps {
|
|
16
17
|
baseUrl: string;
|
|
@@ -6,7 +6,8 @@ import { WebhooksResource } from "./resources/webhooks.js";
|
|
|
6
6
|
import { FleetResource } from "./resources/fleet.js";
|
|
7
7
|
import { ProvisionStoreUseCase, } from "./use-cases/provision-store.js";
|
|
8
8
|
import { verifyWebhook } from "../webhooks/verify-webhook.js";
|
|
9
|
-
|
|
9
|
+
import { SDK_VERSION } from "../version.js";
|
|
10
|
+
export { SDK_VERSION };
|
|
10
11
|
export class VivoaPartnerClient {
|
|
11
12
|
me;
|
|
12
13
|
merchants;
|
|
@@ -26,12 +26,13 @@ export class MerchantsResource {
|
|
|
26
26
|
/** Walks every page of the fleet. */
|
|
27
27
|
async *listAll(query = {}) {
|
|
28
28
|
const limit = query.limit ?? 100;
|
|
29
|
-
for (let page = 1
|
|
29
|
+
for (let page = 1; page <= 10_000; page++) {
|
|
30
30
|
const res = await this.list({ ...query, page, limit });
|
|
31
31
|
yield* res.data;
|
|
32
32
|
if (res.data.length === 0 || page * limit >= res.meta.total)
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
|
+
throw new Error('listAll: exceeded maximum page limit (10 000)');
|
|
35
36
|
}
|
|
36
37
|
/** The merchant created with this reference, or `null` — an exact server-side match. */
|
|
37
38
|
async findByExternalId(externalId) {
|
|
@@ -43,8 +43,8 @@ export class ProvisionStoreUseCase {
|
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
progress('settled', merchant, status.deployStatus);
|
|
46
|
-
if (status.deployStatus === 'failed') {
|
|
47
|
-
throw new VivoaProvisioningFailedError(merchant.id,
|
|
46
|
+
if (status.deployStatus === 'failed' || status.deployStatus === 'unknown') {
|
|
47
|
+
throw new VivoaProvisioningFailedError(merchant.id, `the platform reported runtime status "${status.deployStatus}"`);
|
|
48
48
|
}
|
|
49
49
|
return { merchant: { ...merchant, runtime: status.deployStatus, domain: status.domain }, status, created };
|
|
50
50
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SDK_VERSION = "0.1.1";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SDK_VERSION = '0.1.1';
|