@sakeetech/vendure-payment-viva 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +952 -0
- package/dist/api/admin-internal.controller.d.ts +59 -0
- package/dist/api/admin-internal.controller.d.ts.map +1 -0
- package/dist/api/admin-internal.controller.js +229 -0
- package/dist/api/admin-internal.controller.js.map +1 -0
- package/dist/api/admin-onboarding.controller.d.ts +72 -0
- package/dist/api/admin-onboarding.controller.d.ts.map +1 -0
- package/dist/api/admin-onboarding.controller.js +496 -0
- package/dist/api/admin-onboarding.controller.js.map +1 -0
- package/dist/api/admin-sources.controller.d.ts +50 -0
- package/dist/api/admin-sources.controller.d.ts.map +1 -0
- package/dist/api/admin-sources.controller.js +283 -0
- package/dist/api/admin-sources.controller.js.map +1 -0
- package/dist/api/shop-api.extension.d.ts +15 -0
- package/dist/api/shop-api.extension.d.ts.map +1 -0
- package/dist/api/shop-api.extension.js +35 -0
- package/dist/api/shop-api.extension.js.map +1 -0
- package/dist/api/shop-api.resolver.d.ts +42 -0
- package/dist/api/shop-api.resolver.d.ts.map +1 -0
- package/dist/api/shop-api.resolver.js +256 -0
- package/dist/api/shop-api.resolver.js.map +1 -0
- package/dist/api/webhook.controller.d.ts +58 -0
- package/dist/api/webhook.controller.d.ts.map +1 -0
- package/dist/api/webhook.controller.js +204 -0
- package/dist/api/webhook.controller.js.map +1 -0
- package/dist/cli/bin.d.ts +28 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +104 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/plan.d.ts +41 -0
- package/dist/cli/plan.d.ts.map +1 -0
- package/dist/cli/plan.js +115 -0
- package/dist/cli/plan.js.map +1 -0
- package/dist/cli/register-webhooks.d.ts +45 -0
- package/dist/cli/register-webhooks.d.ts.map +1 -0
- package/dist/cli/register-webhooks.js +400 -0
- package/dist/cli/register-webhooks.js.map +1 -0
- package/dist/cli/types.d.ts +75 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +10 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/constants.d.ts +35 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +40 -0
- package/dist/constants.js.map +1 -0
- package/dist/entities/index.d.ts +4 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/index.js +3 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/entities/viva-transaction.entity.d.ts +70 -0
- package/dist/entities/viva-transaction.entity.d.ts.map +1 -0
- package/dist/entities/viva-transaction.entity.js +133 -0
- package/dist/entities/viva-transaction.entity.js.map +1 -0
- package/dist/entities/viva-webhook-event.entity.d.ts +71 -0
- package/dist/entities/viva-webhook-event.entity.d.ts.map +1 -0
- package/dist/entities/viva-webhook-event.entity.js +138 -0
- package/dist/entities/viva-webhook-event.entity.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/process-viva-webhook.handler.d.ts +95 -0
- package/dist/jobs/process-viva-webhook.handler.d.ts.map +1 -0
- package/dist/jobs/process-viva-webhook.handler.js +530 -0
- package/dist/jobs/process-viva-webhook.handler.js.map +1 -0
- package/dist/jobs/queue-names.d.ts +18 -0
- package/dist/jobs/queue-names.d.ts.map +1 -0
- package/dist/jobs/queue-names.js +19 -0
- package/dist/jobs/queue-names.js.map +1 -0
- package/dist/jobs/retention-cleanup.handler.d.ts +31 -0
- package/dist/jobs/retention-cleanup.handler.d.ts.map +1 -0
- package/dist/jobs/retention-cleanup.handler.js +94 -0
- package/dist/jobs/retention-cleanup.handler.js.map +1 -0
- package/dist/loaders/bootstrap.d.ts +28 -0
- package/dist/loaders/bootstrap.d.ts.map +1 -0
- package/dist/loaders/bootstrap.js +90 -0
- package/dist/loaders/bootstrap.js.map +1 -0
- package/dist/migrations/1714000000000-create-viva-tables.d.ts +22 -0
- package/dist/migrations/1714000000000-create-viva-tables.d.ts.map +1 -0
- package/dist/migrations/1714000000000-create-viva-tables.js +105 -0
- package/dist/migrations/1714000000000-create-viva-tables.js.map +1 -0
- package/dist/observability/metrics-state.service.d.ts +43 -0
- package/dist/observability/metrics-state.service.d.ts.map +1 -0
- package/dist/observability/metrics-state.service.js +207 -0
- package/dist/observability/metrics-state.service.js.map +1 -0
- package/dist/payment-method-handler.d.ts +26 -0
- package/dist/payment-method-handler.d.ts.map +1 -0
- package/dist/payment-method-handler.js +693 -0
- package/dist/payment-method-handler.js.map +1 -0
- package/dist/plugin.d.ts +95 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +241 -0
- package/dist/plugin.js.map +1 -0
- package/dist/providers/viva-oauth2-strategy.provider.d.ts +41 -0
- package/dist/providers/viva-oauth2-strategy.provider.d.ts.map +1 -0
- package/dist/providers/viva-oauth2-strategy.provider.js +60 -0
- package/dist/providers/viva-oauth2-strategy.provider.js.map +1 -0
- package/dist/services/connected-accounts.service.d.ts +53 -0
- package/dist/services/connected-accounts.service.d.ts.map +1 -0
- package/dist/services/connected-accounts.service.js +108 -0
- package/dist/services/connected-accounts.service.js.map +1 -0
- package/dist/services/per-merchant-semaphore.service.d.ts +49 -0
- package/dist/services/per-merchant-semaphore.service.d.ts.map +1 -0
- package/dist/services/per-merchant-semaphore.service.js +156 -0
- package/dist/services/per-merchant-semaphore.service.js.map +1 -0
- package/dist/services/state-machine.service.d.ts +100 -0
- package/dist/services/state-machine.service.d.ts.map +1 -0
- package/dist/services/state-machine.service.js +233 -0
- package/dist/services/state-machine.service.js.map +1 -0
- package/dist/types.d.ts +286 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/dist/util/currency.d.ts +32 -0
- package/dist/util/currency.d.ts.map +1 -0
- package/dist/util/currency.js +90 -0
- package/dist/util/currency.js.map +1 -0
- package/dist/util/error-envelope.d.ts +51 -0
- package/dist/util/error-envelope.d.ts.map +1 -0
- package/dist/util/error-envelope.js +157 -0
- package/dist/util/error-envelope.js.map +1 -0
- package/dist/util/ip-allowlist.d.ts +44 -0
- package/dist/util/ip-allowlist.d.ts.map +1 -0
- package/dist/util/ip-allowlist.js +139 -0
- package/dist/util/ip-allowlist.js.map +1 -0
- package/dist/util/normalize-options.d.ts +24 -0
- package/dist/util/normalize-options.d.ts.map +1 -0
- package/dist/util/normalize-options.js +189 -0
- package/dist/util/normalize-options.js.map +1 -0
- package/dist/util/url-template.d.ts +18 -0
- package/dist/util/url-template.d.ts.map +1 -0
- package/dist/util/url-template.js +22 -0
- package/dist/util/url-template.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api/admin-onboarding.controller.ts — Connected Accounts onboarding admin REST endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Routes (all under /viva/admin/connected-accounts):
|
|
5
|
+
*
|
|
6
|
+
* POST /viva/admin/connected-accounts
|
|
7
|
+
* Initiate onboarding for a channel. Calls IsvAccounts.createConnectedAccount,
|
|
8
|
+
* writes vivaAccountId to the channel, returns {accountId, onboardingUrl}.
|
|
9
|
+
*
|
|
10
|
+
* GET /viva/admin/connected-accounts/:channelId
|
|
11
|
+
* Return onboarding status: {accountId, merchantId, payoutsEnabled,
|
|
12
|
+
* verificationStatus, applePayDomainVerified}.
|
|
13
|
+
* Optionally hits IsvAccounts.retrieveConnectedAccount (cached 30s) for a
|
|
14
|
+
* richer verificationStatus when the channel has an accountId.
|
|
15
|
+
*
|
|
16
|
+
* POST /viva/admin/connected-accounts/:channelId/reconcile
|
|
17
|
+
* Manual recovery if webhook 8194 was missed. Calls
|
|
18
|
+
* IsvAccounts.retrieveConnectedAccount and, if verified, writes vivaMerchantId
|
|
19
|
+
* then flips vivaPayoutsEnabled=true via ConnectedAccountsService (preserving
|
|
20
|
+
* the mandatory field-write order).
|
|
21
|
+
*
|
|
22
|
+
* Auth: @Allow(Permission.SuperAdmin) on every handler.
|
|
23
|
+
*
|
|
24
|
+
* Error envelope: every error response is VivaPluginError.toJSON() shape.
|
|
25
|
+
*
|
|
26
|
+
* @see docs/plans/vendure-plugin-v0.md §"API Surface — REST endpoints"
|
|
27
|
+
* @see docs/plans/vendure-plugin-v0.md §"Onboarding Flow (§10)"
|
|
28
|
+
* @see docs/plans/vendure-plugin-v0.md §"Build Plan — V9"
|
|
29
|
+
* @see docs/VENDURE-CONTRACT.MD §10
|
|
30
|
+
*/
|
|
31
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
32
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
33
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
34
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
35
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
36
|
+
};
|
|
37
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
38
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
39
|
+
};
|
|
40
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
41
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
42
|
+
};
|
|
43
|
+
import { Controller, Post, Get, Param, Body, Res, Inject, UseGuards, } from '@nestjs/common';
|
|
44
|
+
import { Allow, Permission, TransactionalConnection, RequestContextService, Logger, } from '@vendure/core';
|
|
45
|
+
import { AuthGuard } from '@vendure/core';
|
|
46
|
+
import { IsvAccounts, IsvHttpClient } from '@sakeetech/viva-payments-core/isv';
|
|
47
|
+
import { VivaApiError, VivaAuthError, VivaModeMismatchError, } from '@sakeetech/viva-payments-core/errors';
|
|
48
|
+
import { ConnectedAccountsService } from '../services/connected-accounts.service.js';
|
|
49
|
+
import { VivaPluginError } from '../util/error-envelope.js';
|
|
50
|
+
import { VIVA_PLUGIN_OPTIONS, VIVA_OAUTH2_STRATEGY_TOKEN, VIVA_LOG_CONTEXT, } from '../constants.js';
|
|
51
|
+
const STATUS_CACHE_TTL_MS = 30_000;
|
|
52
|
+
const retrieveStatusCache = new Map();
|
|
53
|
+
function getCachedStatus(accountId) {
|
|
54
|
+
const entry = retrieveStatusCache.get(accountId);
|
|
55
|
+
if (!entry)
|
|
56
|
+
return undefined;
|
|
57
|
+
if (Date.now() > entry.expiresAt) {
|
|
58
|
+
retrieveStatusCache.delete(accountId);
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return entry.verificationStatus;
|
|
62
|
+
}
|
|
63
|
+
function setCachedStatus(accountId, status) {
|
|
64
|
+
retrieveStatusCache.set(accountId, {
|
|
65
|
+
verificationStatus: status,
|
|
66
|
+
expiresAt: Date.now() + STATUS_CACHE_TTL_MS,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Helpers
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* Derive the local verificationStatus from channel custom fields.
|
|
74
|
+
*
|
|
75
|
+
* Priority: channel custom fields are the authoritative local state.
|
|
76
|
+
* IsvAccounts.retrieve may supply a richer status, but the local state
|
|
77
|
+
* determines the effective gate (payoutsEnabled). When both disagree,
|
|
78
|
+
* channel custom fields win — they were written by the webhook handler
|
|
79
|
+
* which already called retrieve and validated the response.
|
|
80
|
+
*/
|
|
81
|
+
function deriveVerificationStatus(cf) {
|
|
82
|
+
if (!cf['vivaAccountId'])
|
|
83
|
+
return 'not_started';
|
|
84
|
+
if (cf['vivaPayoutsEnabled'] === true)
|
|
85
|
+
return 'verified';
|
|
86
|
+
return 'awaiting_kyc';
|
|
87
|
+
}
|
|
88
|
+
/** Extract typed custom fields from a Channel, defensively. */
|
|
89
|
+
function getCustomFields(channel) {
|
|
90
|
+
return channel.customFields ?? {};
|
|
91
|
+
}
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Controller
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
let AdminOnboardingController = class AdminOnboardingController {
|
|
96
|
+
options;
|
|
97
|
+
oauth2;
|
|
98
|
+
connection;
|
|
99
|
+
requestContextService;
|
|
100
|
+
connectedAccountsService;
|
|
101
|
+
constructor(options, oauth2, connection, requestContextService, connectedAccountsService) {
|
|
102
|
+
this.options = options;
|
|
103
|
+
this.oauth2 = oauth2;
|
|
104
|
+
this.connection = connection;
|
|
105
|
+
this.requestContextService = requestContextService;
|
|
106
|
+
this.connectedAccountsService = connectedAccountsService;
|
|
107
|
+
}
|
|
108
|
+
// -------------------------------------------------------------------------
|
|
109
|
+
// Private helpers
|
|
110
|
+
// -------------------------------------------------------------------------
|
|
111
|
+
/**
|
|
112
|
+
* Narrow options to ISV mode or throw `VIVA_MODE_MISMATCH`.
|
|
113
|
+
* Onboarding is inherently an ISV-only flow (POST /isv/v1/accounts) — the
|
|
114
|
+
* merchant-mode equivalent is direct Self Care signup with no API surface.
|
|
115
|
+
* Slice C will gate the controller registration itself; slice A throws at
|
|
116
|
+
* runtime entry points.
|
|
117
|
+
*/
|
|
118
|
+
isvOptions() {
|
|
119
|
+
if (this.options.mode !== 'isv') {
|
|
120
|
+
throw new VivaModeMismatchError({
|
|
121
|
+
message: 'Connected-Accounts onboarding is ISV-only — POST /isv/v1/accounts ' +
|
|
122
|
+
'is not available under merchant mode.',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return this.options;
|
|
126
|
+
}
|
|
127
|
+
buildIsvAccounts() {
|
|
128
|
+
const client = new IsvHttpClient({
|
|
129
|
+
environment: this.options.environment,
|
|
130
|
+
authStrategy: this.oauth2,
|
|
131
|
+
});
|
|
132
|
+
return new IsvAccounts(client);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Load a channel by id from the raw TypeORM connection.
|
|
136
|
+
* Returns null if not found.
|
|
137
|
+
*/
|
|
138
|
+
async loadChannel(channelId) {
|
|
139
|
+
const repo = this.connection.rawConnection.getRepository('Channel');
|
|
140
|
+
const ch = await repo.findOne({ where: { id: channelId } }).catch(() => null);
|
|
141
|
+
return ch ?? null;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Map a core SDK error to an HTTP status + VivaPluginError JSON body and
|
|
145
|
+
* write it to the response.
|
|
146
|
+
*/
|
|
147
|
+
sendVivaError(res, err) {
|
|
148
|
+
if (err instanceof VivaAuthError || (err instanceof VivaApiError && err.httpStatus >= 500)) {
|
|
149
|
+
const pluginErr = VivaPluginError.authDown(err instanceof Error ? err.message : 'Viva service unavailable', err);
|
|
150
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
151
|
+
res.end(JSON.stringify(pluginErr.toJSON()));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (err instanceof VivaApiError) {
|
|
155
|
+
const apiErr = err;
|
|
156
|
+
const rawVivaCode = apiErr.vivaCode !== undefined ? Number(apiErr.vivaCode) : undefined;
|
|
157
|
+
// TODO(impl): VivaApiError.vivaCode is string; confirm wire numeric type from live API.
|
|
158
|
+
const pluginErrOpts = {
|
|
159
|
+
message: apiErr.message,
|
|
160
|
+
vivaErrorMessage: apiErr.message,
|
|
161
|
+
cause: err,
|
|
162
|
+
};
|
|
163
|
+
if (rawVivaCode !== undefined && !isNaN(rawVivaCode)) {
|
|
164
|
+
pluginErrOpts.vivaErrorCode = rawVivaCode;
|
|
165
|
+
}
|
|
166
|
+
const pluginErr = VivaPluginError.apiError(pluginErrOpts);
|
|
167
|
+
const httpStatus = apiErr.httpStatus ?? 422;
|
|
168
|
+
res.writeHead(httpStatus >= 400 && httpStatus < 600 ? httpStatus : 422, {
|
|
169
|
+
'Content-Type': 'application/json',
|
|
170
|
+
});
|
|
171
|
+
res.end(JSON.stringify(pluginErr.toJSON()));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Unexpected internal error
|
|
175
|
+
const pluginErr = VivaPluginError.internalError(err instanceof Error ? err.message : 'Unexpected error', err);
|
|
176
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
177
|
+
res.end(JSON.stringify(pluginErr.toJSON()));
|
|
178
|
+
}
|
|
179
|
+
// -------------------------------------------------------------------------
|
|
180
|
+
// POST /viva/admin/connected-accounts — Initiate onboarding
|
|
181
|
+
// -------------------------------------------------------------------------
|
|
182
|
+
async initiateOnboarding(body, res) {
|
|
183
|
+
const { channelId, overrides } = body ?? {};
|
|
184
|
+
if (!channelId) {
|
|
185
|
+
const err = VivaPluginError.channelMisconfigured('channelId is required');
|
|
186
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
187
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// 1. Load Channel
|
|
191
|
+
const channel = await this.loadChannel(String(channelId));
|
|
192
|
+
if (!channel) {
|
|
193
|
+
const err = VivaPluginError.channelMisconfigured(`Channel ${channelId} not found`);
|
|
194
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
195
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const cf = getCustomFields(channel);
|
|
199
|
+
// 2. Check Seller exists
|
|
200
|
+
// Vendure Channel has a `seller` relation; surface it from raw TypeORM.
|
|
201
|
+
const channelRepo = this.connection.rawConnection.getRepository('Channel');
|
|
202
|
+
const channelWithSeller = await channelRepo
|
|
203
|
+
.findOne({ where: { id: channel.id }, relations: ['seller'] })
|
|
204
|
+
.catch(() => null);
|
|
205
|
+
const seller = channelWithSeller?.seller;
|
|
206
|
+
if (!seller) {
|
|
207
|
+
const err = VivaPluginError.channelMisconfigured('Channel must have a Seller before onboarding');
|
|
208
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
209
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// 3. Already onboarded?
|
|
213
|
+
const existingAccountId = cf['vivaAccountId'];
|
|
214
|
+
if (existingAccountId) {
|
|
215
|
+
const err = VivaPluginError.alreadyOnboarded(existingAccountId);
|
|
216
|
+
res.writeHead(409, { 'Content-Type': 'application/json' });
|
|
217
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
// 4. Build payload from Seller fields + plugin config + overrides
|
|
221
|
+
// POST /isv/v1/accounts accepts: email (required), returnUrl (required),
|
|
222
|
+
// branding (optional: partnerName + logoUrl required, primaryColor optional).
|
|
223
|
+
// The ISV API collects countryCode, firstName, lastName, currency, etc. from
|
|
224
|
+
// the merchant during Viva-hosted KYC; the plugin does not forward them.
|
|
225
|
+
const sellerCf = seller['customFields'] ?? {};
|
|
226
|
+
const email = overrides?.email ??
|
|
227
|
+
sellerCf['contactEmail'] ??
|
|
228
|
+
sellerCf['email'] ??
|
|
229
|
+
seller['email'];
|
|
230
|
+
const ctxForResolvers = {
|
|
231
|
+
channelId: channel.id,
|
|
232
|
+
channel: {
|
|
233
|
+
id: channel.id,
|
|
234
|
+
code: channel.code,
|
|
235
|
+
customFields: cf,
|
|
236
|
+
},
|
|
237
|
+
apiType: 'admin',
|
|
238
|
+
};
|
|
239
|
+
const isvOpts = this.isvOptions();
|
|
240
|
+
const returnUrl = overrides?.returnUrl ??
|
|
241
|
+
(typeof isvOpts.onboardingReturnUrl === 'function'
|
|
242
|
+
? isvOpts.onboardingReturnUrl(ctxForResolvers)
|
|
243
|
+
: isvOpts.onboardingReturnUrl);
|
|
244
|
+
if (!email) {
|
|
245
|
+
const err = VivaPluginError.channelMisconfigured('Seller must have an email (customFields.contactEmail, customFields.email, or seller.email) — or pass `overrides.email`.');
|
|
246
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
247
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (!returnUrl) {
|
|
251
|
+
const err = VivaPluginError.channelMisconfigured('`onboardingReturnUrl` is required in plugin options (or pass `overrides.returnUrl`).');
|
|
252
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
253
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const basePayload = {
|
|
257
|
+
email,
|
|
258
|
+
returnUrl,
|
|
259
|
+
...(overrides?.branding
|
|
260
|
+
? { branding: overrides.branding }
|
|
261
|
+
: isvOpts.onboardingBranding
|
|
262
|
+
? { branding: isvOpts.onboardingBranding }
|
|
263
|
+
: {}),
|
|
264
|
+
};
|
|
265
|
+
Logger.info(`[AdminOnboarding] Initiating onboarding for channel ${String(channel.id)}.`, VIVA_LOG_CONTEXT);
|
|
266
|
+
// 5. Call IsvAccounts.createConnectedAccount
|
|
267
|
+
let accountId;
|
|
268
|
+
let onboardingUrl;
|
|
269
|
+
try {
|
|
270
|
+
const isvAccounts = this.buildIsvAccounts();
|
|
271
|
+
const result = await isvAccounts.createConnectedAccount(basePayload);
|
|
272
|
+
accountId = result.accountId;
|
|
273
|
+
onboardingUrl = result.invitation.redirectUrl;
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
Logger.error(`[AdminOnboarding] IsvAccounts.createConnectedAccount failed for channel ${String(channel.id)}: ${String(err)}`, VIVA_LOG_CONTEXT);
|
|
277
|
+
this.sendVivaError(res, err);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
// 6. Write accountId to channel via ConnectedAccountsService
|
|
281
|
+
try {
|
|
282
|
+
const ctx = await this.requestContextService.create({
|
|
283
|
+
apiType: 'admin',
|
|
284
|
+
channelOrToken: channel,
|
|
285
|
+
});
|
|
286
|
+
await this.connectedAccountsService.writeAccountId(ctx, channel, accountId);
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
Logger.error(`[AdminOnboarding] Failed to write vivaAccountId to channel ${String(channel.id)}: ${String(err)}`, VIVA_LOG_CONTEXT);
|
|
290
|
+
// accountId was created at Viva — still return it so the admin can record it
|
|
291
|
+
Logger.warn(`[AdminOnboarding] accountId=${accountId} was created at Viva but could not be persisted locally. Manual recovery required.`, VIVA_LOG_CONTEXT);
|
|
292
|
+
}
|
|
293
|
+
// 7. Return response
|
|
294
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
295
|
+
res.end(JSON.stringify({
|
|
296
|
+
accountId,
|
|
297
|
+
onboardingUrl,
|
|
298
|
+
channelId: channel.id,
|
|
299
|
+
instructions: 'Send onboardingUrl to the shop principal to complete KYC.',
|
|
300
|
+
}));
|
|
301
|
+
}
|
|
302
|
+
// -------------------------------------------------------------------------
|
|
303
|
+
// GET /viva/admin/connected-accounts/:channelId — Onboarding status
|
|
304
|
+
// -------------------------------------------------------------------------
|
|
305
|
+
async getStatus(channelId, res) {
|
|
306
|
+
const channel = await this.loadChannel(channelId);
|
|
307
|
+
if (!channel) {
|
|
308
|
+
const err = VivaPluginError.channelMisconfigured(`Channel ${channelId} not found`);
|
|
309
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
310
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const cf = getCustomFields(channel);
|
|
314
|
+
const accountId = cf['vivaAccountId'] ?? null;
|
|
315
|
+
const merchantId = cf['vivaMerchantId'] ?? null;
|
|
316
|
+
const payoutsEnabled = cf['vivaPayoutsEnabled'] ?? false;
|
|
317
|
+
const applePayDomainVerified = cf['vivaApplePayDomainVerified'] ?? false;
|
|
318
|
+
// Derive local status from channel fields
|
|
319
|
+
const localStatus = deriveVerificationStatus(cf);
|
|
320
|
+
// Optionally enrich with Viva's status (cached 30s) when accountId is known
|
|
321
|
+
let verificationStatus = localStatus;
|
|
322
|
+
if (accountId) {
|
|
323
|
+
const cached = getCachedStatus(accountId);
|
|
324
|
+
if (cached !== undefined) {
|
|
325
|
+
// Use cached Viva status only for informational display;
|
|
326
|
+
// local field state (payoutsEnabled) governs the actual gate.
|
|
327
|
+
// If Viva says 'verified' but local hasn't flipped yet, local wins.
|
|
328
|
+
// This avoids race conditions during the webhook-write window.
|
|
329
|
+
// Strategy: show the more favorable (local if verified, viva if richer).
|
|
330
|
+
if (payoutsEnabled) {
|
|
331
|
+
verificationStatus = 'verified';
|
|
332
|
+
}
|
|
333
|
+
else if (cached === 'verified') {
|
|
334
|
+
// Viva says verified but local webhook hasn't landed yet — show awaiting_kyc
|
|
335
|
+
// to avoid premature gate flip via a status endpoint poll.
|
|
336
|
+
// TODO(impl): expose vivaRawStatus as a separate field if SaaS needs it.
|
|
337
|
+
verificationStatus = 'awaiting_kyc';
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
// Attempt a fresh retrieve — best effort, don't fail the request
|
|
342
|
+
try {
|
|
343
|
+
const isvAccounts = this.buildIsvAccounts();
|
|
344
|
+
const retrieved = await isvAccounts.retrieveConnectedAccount(accountId);
|
|
345
|
+
const rawStatus = retrieved.verified ? 'verified' : 'pending';
|
|
346
|
+
setCachedStatus(accountId, rawStatus);
|
|
347
|
+
// Same local-wins rule as above
|
|
348
|
+
if (payoutsEnabled) {
|
|
349
|
+
verificationStatus = 'verified';
|
|
350
|
+
}
|
|
351
|
+
// rawStatus from Viva does not override local payoutsEnabled flag
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
// Best effort — log and proceed with local state
|
|
355
|
+
Logger.warn(`[AdminOnboarding] IsvAccounts.retrieveConnectedAccount failed for accountId=${accountId}: ${String(err)}`, VIVA_LOG_CONTEXT);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const payload = {
|
|
360
|
+
channelId: channel.id,
|
|
361
|
+
accountId,
|
|
362
|
+
merchantId,
|
|
363
|
+
payoutsEnabled,
|
|
364
|
+
verificationStatus,
|
|
365
|
+
applePayDomainVerified,
|
|
366
|
+
};
|
|
367
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
368
|
+
res.end(JSON.stringify(payload));
|
|
369
|
+
}
|
|
370
|
+
// -------------------------------------------------------------------------
|
|
371
|
+
// POST /viva/admin/connected-accounts/:channelId/reconcile — Manual recovery
|
|
372
|
+
// -------------------------------------------------------------------------
|
|
373
|
+
async reconcile(channelId, res) {
|
|
374
|
+
const channel = await this.loadChannel(channelId);
|
|
375
|
+
if (!channel) {
|
|
376
|
+
const err = VivaPluginError.channelMisconfigured(`Channel ${channelId} not found`);
|
|
377
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
378
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const cf = getCustomFields(channel);
|
|
382
|
+
const accountId = cf['vivaAccountId'];
|
|
383
|
+
if (!accountId) {
|
|
384
|
+
const err = VivaPluginError.channelMisconfigured('Channel does not have a vivaAccountId. Initiate onboarding first.');
|
|
385
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
386
|
+
res.end(JSON.stringify(err.toJSON()));
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
// Already verified — idempotent no-op
|
|
390
|
+
if (cf['vivaPayoutsEnabled'] === true && cf['vivaMerchantId']) {
|
|
391
|
+
const payload = {
|
|
392
|
+
channelId: channel.id,
|
|
393
|
+
accountId,
|
|
394
|
+
merchantId: cf['vivaMerchantId'],
|
|
395
|
+
payoutsEnabled: true,
|
|
396
|
+
verificationStatus: 'verified',
|
|
397
|
+
applePayDomainVerified: cf['vivaApplePayDomainVerified'] ?? false,
|
|
398
|
+
};
|
|
399
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
400
|
+
res.end(JSON.stringify(payload));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
// Call IsvAccounts.retrieveConnectedAccount
|
|
404
|
+
let retrieved;
|
|
405
|
+
try {
|
|
406
|
+
const isvAccounts = this.buildIsvAccounts();
|
|
407
|
+
retrieved = await isvAccounts.retrieveConnectedAccount(accountId);
|
|
408
|
+
}
|
|
409
|
+
catch (err) {
|
|
410
|
+
Logger.error(`[AdminOnboarding] reconcile: IsvAccounts.retrieveConnectedAccount failed for channel ${channelId}: ${String(err)}`, VIVA_LOG_CONTEXT);
|
|
411
|
+
this.sendVivaError(res, err);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const isVerified = retrieved.verified === true;
|
|
415
|
+
const merchantId = retrieved.merchantId;
|
|
416
|
+
if (isVerified && merchantId) {
|
|
417
|
+
// Write in the mandatory order: vivaMerchantId FIRST, vivaPayoutsEnabled LAST
|
|
418
|
+
try {
|
|
419
|
+
const ctx = await this.requestContextService.create({
|
|
420
|
+
apiType: 'admin',
|
|
421
|
+
channelOrToken: channel,
|
|
422
|
+
});
|
|
423
|
+
await this.connectedAccountsService.writeMerchantId(ctx, channel, merchantId);
|
|
424
|
+
await this.connectedAccountsService.flipPayoutsEnabled(ctx, channel, true);
|
|
425
|
+
Logger.info(`[AdminOnboarding] reconcile: wrote merchantId=${merchantId} and flipped payoutsEnabled for channel ${channelId}.`, VIVA_LOG_CONTEXT);
|
|
426
|
+
}
|
|
427
|
+
catch (err) {
|
|
428
|
+
Logger.error(`[AdminOnboarding] reconcile: failed to write channel fields for channel ${channelId}: ${String(err)}`, VIVA_LOG_CONTEXT);
|
|
429
|
+
const pluginErr = VivaPluginError.internalError('Failed to persist reconciliation data', err);
|
|
430
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
431
|
+
res.end(JSON.stringify(pluginErr.toJSON()));
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const payload = {
|
|
435
|
+
channelId: channel.id,
|
|
436
|
+
accountId,
|
|
437
|
+
merchantId,
|
|
438
|
+
payoutsEnabled: true,
|
|
439
|
+
verificationStatus: 'verified',
|
|
440
|
+
applePayDomainVerified: cf['vivaApplePayDomainVerified'] ?? false,
|
|
441
|
+
};
|
|
442
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
443
|
+
res.end(JSON.stringify(payload));
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
// Viva says still pending — no writes; return current state
|
|
447
|
+
const payload = {
|
|
448
|
+
channelId: channel.id,
|
|
449
|
+
accountId,
|
|
450
|
+
merchantId: cf['vivaMerchantId'] ?? null,
|
|
451
|
+
payoutsEnabled: false,
|
|
452
|
+
verificationStatus: 'awaiting_kyc',
|
|
453
|
+
applePayDomainVerified: cf['vivaApplePayDomainVerified'] ?? false,
|
|
454
|
+
};
|
|
455
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
456
|
+
res.end(JSON.stringify(payload));
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
__decorate([
|
|
460
|
+
Post(),
|
|
461
|
+
Allow(Permission.SuperAdmin),
|
|
462
|
+
__param(0, Body()),
|
|
463
|
+
__param(1, Res()),
|
|
464
|
+
__metadata("design:type", Function),
|
|
465
|
+
__metadata("design:paramtypes", [Object, Function]),
|
|
466
|
+
__metadata("design:returntype", Promise)
|
|
467
|
+
], AdminOnboardingController.prototype, "initiateOnboarding", null);
|
|
468
|
+
__decorate([
|
|
469
|
+
Get(':channelId'),
|
|
470
|
+
Allow(Permission.SuperAdmin),
|
|
471
|
+
__param(0, Param('channelId')),
|
|
472
|
+
__param(1, Res()),
|
|
473
|
+
__metadata("design:type", Function),
|
|
474
|
+
__metadata("design:paramtypes", [String, Function]),
|
|
475
|
+
__metadata("design:returntype", Promise)
|
|
476
|
+
], AdminOnboardingController.prototype, "getStatus", null);
|
|
477
|
+
__decorate([
|
|
478
|
+
Post(':channelId/reconcile'),
|
|
479
|
+
Allow(Permission.SuperAdmin),
|
|
480
|
+
__param(0, Param('channelId')),
|
|
481
|
+
__param(1, Res()),
|
|
482
|
+
__metadata("design:type", Function),
|
|
483
|
+
__metadata("design:paramtypes", [String, Function]),
|
|
484
|
+
__metadata("design:returntype", Promise)
|
|
485
|
+
], AdminOnboardingController.prototype, "reconcile", null);
|
|
486
|
+
AdminOnboardingController = __decorate([
|
|
487
|
+
Controller('viva/admin/connected-accounts'),
|
|
488
|
+
UseGuards(AuthGuard),
|
|
489
|
+
__param(0, Inject(VIVA_PLUGIN_OPTIONS)),
|
|
490
|
+
__param(1, Inject(VIVA_OAUTH2_STRATEGY_TOKEN)),
|
|
491
|
+
__metadata("design:paramtypes", [Object, Object, TransactionalConnection,
|
|
492
|
+
RequestContextService,
|
|
493
|
+
ConnectedAccountsService])
|
|
494
|
+
], AdminOnboardingController);
|
|
495
|
+
export { AdminOnboardingController };
|
|
496
|
+
//# sourceMappingURL=admin-onboarding.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-onboarding.controller.js","sourceRoot":"","sources":["../../src/api/admin-onboarding.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api/admin-sources.controller.ts — ISV-only admin REST for /api/sources wrapping.
|
|
3
|
+
*
|
|
4
|
+
* Single route:
|
|
5
|
+
*
|
|
6
|
+
* POST /viva/admin/connected-accounts/:id/sources
|
|
7
|
+
* Creates a payment source (ecommerce or physical) on a connected
|
|
8
|
+
* merchant's Viva account via POST /api/sources on the legacy host,
|
|
9
|
+
* authenticated with Reseller Basic auth (per AUTH.md §1.2).
|
|
10
|
+
*
|
|
11
|
+
* Flow:
|
|
12
|
+
* 1. Mode gate: 404 in merchant mode (mirrors Medusa _mode-gate.ts).
|
|
13
|
+
* 2. Reseller gate: 412 VIVA_RESELLER_CREDENTIALS_MISSING when
|
|
14
|
+
* options.reseller is absent.
|
|
15
|
+
* 3. Body parse: 400 on missing/invalid fields or unknown kind.
|
|
16
|
+
* 4. Account lookup: IsvAccounts.retrieveConnectedAccount(:id).
|
|
17
|
+
* → 409 VIVA_ACCOUNT_NOT_VERIFIED when verified !== true or
|
|
18
|
+
* merchantId is null.
|
|
19
|
+
* 5. BasicAuthClient {authVariant:'reseller'} built with the connected
|
|
20
|
+
* merchant's UUID (account.merchantId — NOT config.reseller.merchantId).
|
|
21
|
+
* 6. IsvSources.createEcommerceSource / createPhysicalSource.
|
|
22
|
+
* 7. 201 with {sourceCode, name, kind}.
|
|
23
|
+
*
|
|
24
|
+
* Viva 4xx on /api/sources → 422 VIVA_SOURCE_CREATION_FAILED.
|
|
25
|
+
* Viva 5xx / auth errors → 503 VIVA_AUTH_DOWN (existing envelope rule).
|
|
26
|
+
*
|
|
27
|
+
* @see docs/plans/multi-mode-v0.md §6 (admin REST table)
|
|
28
|
+
* @see docs/AUTH.md §1.2 (Reseller Basic)
|
|
29
|
+
* @see docs/ENDPOINTS.md §5.1
|
|
30
|
+
* @see packages/medusa-payment-viva/src/api/viva/admin/connected-accounts/[id]/sources/route.ts
|
|
31
|
+
*/
|
|
32
|
+
import type { ServerResponse } from 'node:http';
|
|
33
|
+
import type { VivaPaymentPluginOptions } from '../types.js';
|
|
34
|
+
import type { VivaOAuth2Strategy } from '../providers/viva-oauth2-strategy.provider.js';
|
|
35
|
+
export declare class AdminSourcesController {
|
|
36
|
+
private readonly options;
|
|
37
|
+
private readonly oauth2;
|
|
38
|
+
constructor(options: VivaPaymentPluginOptions, oauth2: VivaOAuth2Strategy);
|
|
39
|
+
/**
|
|
40
|
+
* Narrow options to ISV mode + reseller block.
|
|
41
|
+
* Returns:
|
|
42
|
+
* - { ok: true, isv } on success.
|
|
43
|
+
* - { ok: false, status, err } on mode mismatch (404) or missing reseller (412).
|
|
44
|
+
*/
|
|
45
|
+
private requireIsvWithReseller;
|
|
46
|
+
/** Build the OAuth2-backed IsvAccounts client (platform creds). */
|
|
47
|
+
private buildIsvAccounts;
|
|
48
|
+
createSource(id: string, body: unknown, res: ServerResponse): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=admin-sources.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-sources.controller.d.ts","sourceRoot":"","sources":["../../src/api/admin-sources.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAWH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAchD,OAAO,KAAK,EACV,wBAAwB,EAEzB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AA+GxF,qBAEa,sBAAsB;IAG/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAFN,OAAO,EAAE,wBAAwB,EAEjC,MAAM,EAAE,kBAAkB;IAG7C;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IA2B9B,mEAAmE;IACnE,OAAO,CAAC,gBAAgB;IAclB,YAAY,CACH,EAAE,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,EACd,GAAG,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC;CAgJjB"}
|