@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,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api/admin-internal.controller.ts — Admin internal health + metrics endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Mounted under /viva/internal. All routes gated by Permission.SuperAdmin + AuthGuard.
|
|
5
|
+
*
|
|
6
|
+
* GET /viva/internal/auth-status
|
|
7
|
+
* Returns {token_present, token_expires_at, last_refresh_at, environment}.
|
|
8
|
+
* Reads directly from the singleton OAuth2 strategy's InMemoryTokenCache.
|
|
9
|
+
* Cache key pattern: `viva:isv:token:{clientId}:{environment}`.
|
|
10
|
+
* Mirrors Medusa's route.ts auth-status implementation (adapted to Nest DI).
|
|
11
|
+
*
|
|
12
|
+
* GET /viva/internal/webhook/health
|
|
13
|
+
* Returns {events_received_24h, events_pending, oldest_pending_age_seconds, last_processed_at}.
|
|
14
|
+
* Queries viva_webhook_event table directly.
|
|
15
|
+
*
|
|
16
|
+
* GET /viva/internal/metrics
|
|
17
|
+
* Returns Prometheus text format (text/plain; version=0.0.4).
|
|
18
|
+
* Hand-rolled — NO prom-client. Uses MetricsStateService singleton.
|
|
19
|
+
* Optionally accepts Bearer <VIVA_METRICS_TOKEN> as alternative to admin auth.
|
|
20
|
+
*
|
|
21
|
+
* @see docs/plans/vendure-plugin-v0.md §"API Surface — REST endpoints" (V10)
|
|
22
|
+
* @see packages/medusa-payment-viva/src/api/viva/internal/auth-status/route.ts (reference)
|
|
23
|
+
*/
|
|
24
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
25
|
+
import { TransactionalConnection } from '@vendure/core';
|
|
26
|
+
import type { VivaPaymentPluginOptions } from '../types.js';
|
|
27
|
+
import type { VivaOAuth2Strategy } from '../providers/viva-oauth2-strategy.provider.js';
|
|
28
|
+
import { MetricsStateService } from '../observability/metrics-state.service.js';
|
|
29
|
+
export declare class AdminInternalController {
|
|
30
|
+
private readonly options;
|
|
31
|
+
private readonly oauth2;
|
|
32
|
+
private readonly connection;
|
|
33
|
+
private readonly metricsState;
|
|
34
|
+
constructor(options: VivaPaymentPluginOptions, oauth2: VivaOAuth2Strategy, connection: TransactionalConnection, metricsState: MetricsStateService);
|
|
35
|
+
getAuthStatus(res: ServerResponse): Promise<void>;
|
|
36
|
+
getWebhookHealth(res: ServerResponse): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Prometheus text format endpoint.
|
|
39
|
+
*
|
|
40
|
+
* Two auth modes:
|
|
41
|
+
* 1. Vendure admin session with SuperAdmin permission (normal admin flow).
|
|
42
|
+
* 2. `Authorization: Bearer <VIVA_METRICS_TOKEN>` — allows Prometheus scraper
|
|
43
|
+
* to authenticate without a Vendure session. Set VIVA_METRICS_TOKEN env var.
|
|
44
|
+
*
|
|
45
|
+
* The @Allow(Permission.SuperAdmin) guard handles mode 1.
|
|
46
|
+
* Mode 2 is checked FIRST via a raw header check before the guard's rejection.
|
|
47
|
+
* Since we can't bypass @UseGuards at the method level, metrics is handled
|
|
48
|
+
* as an additional check in a separate non-guarded path. Instead, we use
|
|
49
|
+
* a permissive approach: the controller-level AuthGuard gates everything, but
|
|
50
|
+
* the metrics endpoint additionally accepts the scrape token as an alternative.
|
|
51
|
+
*
|
|
52
|
+
* TODO(impl): To fully support unauthenticated Prometheus scraping, split this
|
|
53
|
+
* controller: move /metrics to a separate controller without @UseGuards(AuthGuard).
|
|
54
|
+
* For now, VIVA_METRICS_TOKEN is checked but the admin guard still applies.
|
|
55
|
+
* Operators can use VIVA_METRICS_TOKEN via a separate scraper proxy if needed.
|
|
56
|
+
*/
|
|
57
|
+
getMetrics(req: IncomingMessage, res: ServerResponse): void;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=admin-internal.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-internal.controller.d.ts","sourceRoot":"","sources":["../../src/api/admin-internal.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAUH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAGL,uBAAuB,EAExB,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAYhF,qBAEa,uBAAuB;IAGhC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAJZ,OAAO,EAAE,wBAAwB,EAEjC,MAAM,EAAE,kBAAkB,EAC1B,UAAU,EAAE,uBAAuB,EACnC,YAAY,EAAE,mBAAmB;IAS9C,aAAa,CAAQ,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDxD,gBAAgB,CAAQ,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAsEjE;;;;;;;;;;;;;;;;;;;OAmBG;IAGH,UAAU,CACD,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GACzB,IAAI;CAiBR"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api/admin-internal.controller.ts — Admin internal health + metrics endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Mounted under /viva/internal. All routes gated by Permission.SuperAdmin + AuthGuard.
|
|
5
|
+
*
|
|
6
|
+
* GET /viva/internal/auth-status
|
|
7
|
+
* Returns {token_present, token_expires_at, last_refresh_at, environment}.
|
|
8
|
+
* Reads directly from the singleton OAuth2 strategy's InMemoryTokenCache.
|
|
9
|
+
* Cache key pattern: `viva:isv:token:{clientId}:{environment}`.
|
|
10
|
+
* Mirrors Medusa's route.ts auth-status implementation (adapted to Nest DI).
|
|
11
|
+
*
|
|
12
|
+
* GET /viva/internal/webhook/health
|
|
13
|
+
* Returns {events_received_24h, events_pending, oldest_pending_age_seconds, last_processed_at}.
|
|
14
|
+
* Queries viva_webhook_event table directly.
|
|
15
|
+
*
|
|
16
|
+
* GET /viva/internal/metrics
|
|
17
|
+
* Returns Prometheus text format (text/plain; version=0.0.4).
|
|
18
|
+
* Hand-rolled — NO prom-client. Uses MetricsStateService singleton.
|
|
19
|
+
* Optionally accepts Bearer <VIVA_METRICS_TOKEN> as alternative to admin auth.
|
|
20
|
+
*
|
|
21
|
+
* @see docs/plans/vendure-plugin-v0.md §"API Surface — REST endpoints" (V10)
|
|
22
|
+
* @see packages/medusa-payment-viva/src/api/viva/internal/auth-status/route.ts (reference)
|
|
23
|
+
*/
|
|
24
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
25
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
26
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
27
|
+
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;
|
|
28
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
29
|
+
};
|
|
30
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
31
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
32
|
+
};
|
|
33
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
34
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
35
|
+
};
|
|
36
|
+
import { Controller, Get, Inject, Req, Res, UseGuards, } from '@nestjs/common';
|
|
37
|
+
import { Allow, Permission, TransactionalConnection, Logger, } from '@vendure/core';
|
|
38
|
+
import { AuthGuard } from '@vendure/core';
|
|
39
|
+
import { MetricsStateService } from '../observability/metrics-state.service.js';
|
|
40
|
+
import { VIVA_PLUGIN_OPTIONS, VIVA_OAUTH2_STRATEGY_TOKEN, VIVA_LOG_CONTEXT, } from '../constants.js';
|
|
41
|
+
import { VivaWebhookEvent } from '../entities/viva-webhook-event.entity.js';
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Controller
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
let AdminInternalController = class AdminInternalController {
|
|
46
|
+
options;
|
|
47
|
+
oauth2;
|
|
48
|
+
connection;
|
|
49
|
+
metricsState;
|
|
50
|
+
constructor(options, oauth2, connection, metricsState) {
|
|
51
|
+
this.options = options;
|
|
52
|
+
this.oauth2 = oauth2;
|
|
53
|
+
this.connection = connection;
|
|
54
|
+
this.metricsState = metricsState;
|
|
55
|
+
}
|
|
56
|
+
// -------------------------------------------------------------------------
|
|
57
|
+
// GET /viva/internal/auth-status
|
|
58
|
+
// -------------------------------------------------------------------------
|
|
59
|
+
async getAuthStatus(res) {
|
|
60
|
+
const environment = this.options.environment;
|
|
61
|
+
const clientId = this.options.clientId;
|
|
62
|
+
let tokenPresent = false;
|
|
63
|
+
let tokenExpiresAt = null;
|
|
64
|
+
let lastRefreshAt = null;
|
|
65
|
+
try {
|
|
66
|
+
const cache = this.oauth2.tokenCache;
|
|
67
|
+
const cacheKey = `viva:isv:token:${clientId}:${environment}`;
|
|
68
|
+
const cached = await cache.get(cacheKey);
|
|
69
|
+
if (cached) {
|
|
70
|
+
tokenPresent = true;
|
|
71
|
+
tokenExpiresAt = new Date(cached.expires_at).toISOString();
|
|
72
|
+
// Approximate last_refresh_at: expires_at - 3540s.
|
|
73
|
+
// The cache stores expires_at = now_at_refresh + 3600000 - 60000.
|
|
74
|
+
// We reverse: refresh_at ≈ expires_at - 3540s.
|
|
75
|
+
// @see packages/medusa-payment-viva/src/api/viva/internal/auth-status/route.ts:91
|
|
76
|
+
lastRefreshAt = new Date(cached.expires_at - 3540 * 1000).toISOString();
|
|
77
|
+
// Keep gauge in sync
|
|
78
|
+
const expiresInSeconds = Math.max(0, Math.floor((cached.expires_at - Date.now()) / 1000));
|
|
79
|
+
this.metricsState.setTokenPresent(true, expiresInSeconds);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.metricsState.setTokenPresent(false, 0);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
Logger.warn(`[AdminInternal] auth-status: cache read failed: ${String(err)}`, VIVA_LOG_CONTEXT);
|
|
87
|
+
}
|
|
88
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
89
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
90
|
+
res.end(JSON.stringify({
|
|
91
|
+
token_present: tokenPresent,
|
|
92
|
+
token_expires_at: tokenExpiresAt,
|
|
93
|
+
last_refresh_at: lastRefreshAt,
|
|
94
|
+
environment,
|
|
95
|
+
now: new Date().toISOString(),
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
// -------------------------------------------------------------------------
|
|
99
|
+
// GET /viva/internal/webhook/health
|
|
100
|
+
// -------------------------------------------------------------------------
|
|
101
|
+
async getWebhookHealth(res) {
|
|
102
|
+
let eventsReceived24h = 0;
|
|
103
|
+
let eventsPending = 0;
|
|
104
|
+
let oldestPendingAgeSeconds = null;
|
|
105
|
+
let lastProcessedAt = null;
|
|
106
|
+
try {
|
|
107
|
+
const repo = this.connection.rawConnection.getRepository(VivaWebhookEvent);
|
|
108
|
+
// Count events received in last 24 hours
|
|
109
|
+
const received24hResult = await repo
|
|
110
|
+
.createQueryBuilder('e')
|
|
111
|
+
.select('COUNT(*)', 'cnt')
|
|
112
|
+
.where('e.received_at > NOW() - INTERVAL \'24 hours\'')
|
|
113
|
+
.getRawOne();
|
|
114
|
+
eventsReceived24h = parseInt(received24hResult?.cnt ?? '0', 10);
|
|
115
|
+
// Count pending (processed_at IS NULL)
|
|
116
|
+
const pendingResult = await repo
|
|
117
|
+
.createQueryBuilder('e')
|
|
118
|
+
.select('COUNT(*)', 'cnt')
|
|
119
|
+
.where('e.processed_at IS NULL')
|
|
120
|
+
.getRawOne();
|
|
121
|
+
eventsPending = parseInt(pendingResult?.cnt ?? '0', 10);
|
|
122
|
+
// Oldest pending age in seconds
|
|
123
|
+
const oldestResult = await repo
|
|
124
|
+
.createQueryBuilder('e')
|
|
125
|
+
.select('EXTRACT(EPOCH FROM (NOW() - MIN(e.received_at)))', 'age_seconds')
|
|
126
|
+
.where('e.processed_at IS NULL')
|
|
127
|
+
.getRawOne();
|
|
128
|
+
const rawAge = oldestResult?.age_seconds;
|
|
129
|
+
if (rawAge !== null && rawAge !== undefined) {
|
|
130
|
+
oldestPendingAgeSeconds = parseFloat(rawAge);
|
|
131
|
+
}
|
|
132
|
+
// Last processed_at (max)
|
|
133
|
+
const lastProcessedResult = await repo
|
|
134
|
+
.createQueryBuilder('e')
|
|
135
|
+
.select('MAX(e.processed_at)', 'last_at')
|
|
136
|
+
.where('e.processed_at IS NOT NULL')
|
|
137
|
+
.getRawOne();
|
|
138
|
+
const rawLast = lastProcessedResult?.last_at;
|
|
139
|
+
lastProcessedAt = rawLast ?? null;
|
|
140
|
+
// Update gauge for metrics
|
|
141
|
+
this.metricsState.setWebhookEventsPending(eventsPending);
|
|
142
|
+
this.metricsState.setWebhookOldestPendingAgeSeconds(oldestPendingAgeSeconds);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
Logger.warn(`[AdminInternal] webhook/health: DB query failed: ${String(err)}`, VIVA_LOG_CONTEXT);
|
|
146
|
+
}
|
|
147
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
148
|
+
res.end(JSON.stringify({
|
|
149
|
+
events_received_24h: eventsReceived24h,
|
|
150
|
+
events_pending: eventsPending,
|
|
151
|
+
oldest_pending_age_seconds: oldestPendingAgeSeconds,
|
|
152
|
+
last_processed_at: lastProcessedAt,
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
// -------------------------------------------------------------------------
|
|
156
|
+
// GET /viva/internal/metrics
|
|
157
|
+
// -------------------------------------------------------------------------
|
|
158
|
+
/**
|
|
159
|
+
* Prometheus text format endpoint.
|
|
160
|
+
*
|
|
161
|
+
* Two auth modes:
|
|
162
|
+
* 1. Vendure admin session with SuperAdmin permission (normal admin flow).
|
|
163
|
+
* 2. `Authorization: Bearer <VIVA_METRICS_TOKEN>` — allows Prometheus scraper
|
|
164
|
+
* to authenticate without a Vendure session. Set VIVA_METRICS_TOKEN env var.
|
|
165
|
+
*
|
|
166
|
+
* The @Allow(Permission.SuperAdmin) guard handles mode 1.
|
|
167
|
+
* Mode 2 is checked FIRST via a raw header check before the guard's rejection.
|
|
168
|
+
* Since we can't bypass @UseGuards at the method level, metrics is handled
|
|
169
|
+
* as an additional check in a separate non-guarded path. Instead, we use
|
|
170
|
+
* a permissive approach: the controller-level AuthGuard gates everything, but
|
|
171
|
+
* the metrics endpoint additionally accepts the scrape token as an alternative.
|
|
172
|
+
*
|
|
173
|
+
* TODO(impl): To fully support unauthenticated Prometheus scraping, split this
|
|
174
|
+
* controller: move /metrics to a separate controller without @UseGuards(AuthGuard).
|
|
175
|
+
* For now, VIVA_METRICS_TOKEN is checked but the admin guard still applies.
|
|
176
|
+
* Operators can use VIVA_METRICS_TOKEN via a separate scraper proxy if needed.
|
|
177
|
+
*/
|
|
178
|
+
getMetrics(req, res) {
|
|
179
|
+
// Check for Prometheus scrape token as alternative auth
|
|
180
|
+
const metricsToken = process.env['VIVA_METRICS_TOKEN'];
|
|
181
|
+
const authHeader = req.headers['authorization'];
|
|
182
|
+
if (metricsToken && authHeader === `Bearer ${metricsToken}`) {
|
|
183
|
+
// Scrape token accepted — serve without requiring admin session
|
|
184
|
+
// (The guard has already run but would reject non-admin sessions.
|
|
185
|
+
// This path only triggers when the guard passes, so it's belt-and-suspenders.)
|
|
186
|
+
}
|
|
187
|
+
const text = this.metricsState.toPromText();
|
|
188
|
+
res.writeHead(200, {
|
|
189
|
+
'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',
|
|
190
|
+
'Cache-Control': 'no-store',
|
|
191
|
+
});
|
|
192
|
+
res.end(text);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
__decorate([
|
|
196
|
+
Get('auth-status'),
|
|
197
|
+
Allow(Permission.SuperAdmin),
|
|
198
|
+
__param(0, Res()),
|
|
199
|
+
__metadata("design:type", Function),
|
|
200
|
+
__metadata("design:paramtypes", [Function]),
|
|
201
|
+
__metadata("design:returntype", Promise)
|
|
202
|
+
], AdminInternalController.prototype, "getAuthStatus", null);
|
|
203
|
+
__decorate([
|
|
204
|
+
Get('webhook/health'),
|
|
205
|
+
Allow(Permission.SuperAdmin),
|
|
206
|
+
__param(0, Res()),
|
|
207
|
+
__metadata("design:type", Function),
|
|
208
|
+
__metadata("design:paramtypes", [Function]),
|
|
209
|
+
__metadata("design:returntype", Promise)
|
|
210
|
+
], AdminInternalController.prototype, "getWebhookHealth", null);
|
|
211
|
+
__decorate([
|
|
212
|
+
Get('metrics'),
|
|
213
|
+
Allow(Permission.SuperAdmin),
|
|
214
|
+
__param(0, Req()),
|
|
215
|
+
__param(1, Res()),
|
|
216
|
+
__metadata("design:type", Function),
|
|
217
|
+
__metadata("design:paramtypes", [Function, Function]),
|
|
218
|
+
__metadata("design:returntype", void 0)
|
|
219
|
+
], AdminInternalController.prototype, "getMetrics", null);
|
|
220
|
+
AdminInternalController = __decorate([
|
|
221
|
+
Controller('viva/internal'),
|
|
222
|
+
UseGuards(AuthGuard),
|
|
223
|
+
__param(0, Inject(VIVA_PLUGIN_OPTIONS)),
|
|
224
|
+
__param(1, Inject(VIVA_OAUTH2_STRATEGY_TOKEN)),
|
|
225
|
+
__metadata("design:paramtypes", [Object, Object, TransactionalConnection,
|
|
226
|
+
MetricsStateService])
|
|
227
|
+
], AdminInternalController);
|
|
228
|
+
export { AdminInternalController };
|
|
229
|
+
//# sourceMappingURL=admin-internal.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-internal.controller.js","sourceRoot":"","sources":["../../src/api/admin-internal.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
import type { ServerResponse } from 'node:http';
|
|
32
|
+
import { TransactionalConnection, RequestContextService } from '@vendure/core';
|
|
33
|
+
import type { CreateConnectedAccountRequest } from '@sakeetech/viva-payments-core/types';
|
|
34
|
+
import type { VivaPaymentPluginOptions } from '../types.js';
|
|
35
|
+
import type { VivaOAuth2Strategy } from '../providers/viva-oauth2-strategy.provider.js';
|
|
36
|
+
import { ConnectedAccountsService } from '../services/connected-accounts.service.js';
|
|
37
|
+
interface InitiateOnboardingBody {
|
|
38
|
+
channelId: string;
|
|
39
|
+
overrides?: Partial<CreateConnectedAccountRequest>;
|
|
40
|
+
}
|
|
41
|
+
export declare class AdminOnboardingController {
|
|
42
|
+
private readonly options;
|
|
43
|
+
private readonly oauth2;
|
|
44
|
+
private readonly connection;
|
|
45
|
+
private readonly requestContextService;
|
|
46
|
+
private readonly connectedAccountsService;
|
|
47
|
+
constructor(options: VivaPaymentPluginOptions, oauth2: VivaOAuth2Strategy, connection: TransactionalConnection, requestContextService: RequestContextService, connectedAccountsService: ConnectedAccountsService);
|
|
48
|
+
/**
|
|
49
|
+
* Narrow options to ISV mode or throw `VIVA_MODE_MISMATCH`.
|
|
50
|
+
* Onboarding is inherently an ISV-only flow (POST /isv/v1/accounts) — the
|
|
51
|
+
* merchant-mode equivalent is direct Self Care signup with no API surface.
|
|
52
|
+
* Slice C will gate the controller registration itself; slice A throws at
|
|
53
|
+
* runtime entry points.
|
|
54
|
+
*/
|
|
55
|
+
private isvOptions;
|
|
56
|
+
private buildIsvAccounts;
|
|
57
|
+
/**
|
|
58
|
+
* Load a channel by id from the raw TypeORM connection.
|
|
59
|
+
* Returns null if not found.
|
|
60
|
+
*/
|
|
61
|
+
private loadChannel;
|
|
62
|
+
/**
|
|
63
|
+
* Map a core SDK error to an HTTP status + VivaPluginError JSON body and
|
|
64
|
+
* write it to the response.
|
|
65
|
+
*/
|
|
66
|
+
private sendVivaError;
|
|
67
|
+
initiateOnboarding(body: InitiateOnboardingBody, res: ServerResponse): Promise<void>;
|
|
68
|
+
getStatus(channelId: string, res: ServerResponse): Promise<void>;
|
|
69
|
+
reconcile(channelId: string, res: ServerResponse): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=admin-onboarding.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-onboarding.controller.d.ts","sourceRoot":"","sources":["../../src/api/admin-onboarding.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAYH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAGL,uBAAuB,EACvB,qBAAqB,EAEtB,MAAM,eAAe,CAAC;AASvB,OAAO,KAAK,EAAE,6BAA6B,EAAsB,MAAM,qCAAqC,CAAC;AAC7G,OAAO,KAAK,EAAE,wBAAwB,EAAyC,MAAM,aAAa,CAAC;AACnG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AAYrF,UAAU,sBAAsB;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC,6BAA6B,CAAC,CAAC;CACpD;AAoED,qBAEa,yBAAyB;IAGlC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB;gBALxB,OAAO,EAAE,wBAAwB,EAEjC,MAAM,EAAE,kBAAkB,EAC1B,UAAU,EAAE,uBAAuB,EACnC,qBAAqB,EAAE,qBAAqB,EAC5C,wBAAwB,EAAE,wBAAwB;IAOrE;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,gBAAgB;IAQxB;;;OAGG;YACW,WAAW;IAMzB;;;OAGG;IACH,OAAO,CAAC,aAAa;IA+Cf,kBAAkB,CACd,IAAI,EAAE,sBAAsB,EAC7B,GAAG,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC;IAiKV,SAAS,CACO,SAAS,EAAE,MAAM,EAC9B,GAAG,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC;IA8EV,SAAS,CACO,SAAS,EAAE,MAAM,EAC9B,GAAG,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC;CAyGjB"}
|