@sakeetech/medusa-payment-viva 0.2.2

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.
Files changed (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +816 -0
  3. package/dist/api/index.d.ts +15 -0
  4. package/dist/api/index.d.ts.map +1 -0
  5. package/dist/api/index.js +22 -0
  6. package/dist/api/index.js.map +1 -0
  7. package/dist/api/middlewares.d.ts +27 -0
  8. package/dist/api/middlewares.d.ts.map +1 -0
  9. package/dist/api/middlewares.js +62 -0
  10. package/dist/api/middlewares.js.map +1 -0
  11. package/dist/api/viva/admin/_admin-auth.d.ts +26 -0
  12. package/dist/api/viva/admin/_admin-auth.d.ts.map +1 -0
  13. package/dist/api/viva/admin/_admin-auth.js +49 -0
  14. package/dist/api/viva/admin/_admin-auth.js.map +1 -0
  15. package/dist/api/viva/admin/_mode-gate.d.ts +28 -0
  16. package/dist/api/viva/admin/_mode-gate.d.ts.map +1 -0
  17. package/dist/api/viva/admin/_mode-gate.js +45 -0
  18. package/dist/api/viva/admin/_mode-gate.js.map +1 -0
  19. package/dist/api/viva/admin/connected-accounts/[id]/reconcile/route.d.ts +21 -0
  20. package/dist/api/viva/admin/connected-accounts/[id]/reconcile/route.d.ts.map +1 -0
  21. package/dist/api/viva/admin/connected-accounts/[id]/reconcile/route.js +93 -0
  22. package/dist/api/viva/admin/connected-accounts/[id]/reconcile/route.js.map +1 -0
  23. package/dist/api/viva/admin/connected-accounts/[id]/route.d.ts +18 -0
  24. package/dist/api/viva/admin/connected-accounts/[id]/route.d.ts.map +1 -0
  25. package/dist/api/viva/admin/connected-accounts/[id]/route.js +59 -0
  26. package/dist/api/viva/admin/connected-accounts/[id]/route.js.map +1 -0
  27. package/dist/api/viva/admin/connected-accounts/[id]/sources/route.d.ts +34 -0
  28. package/dist/api/viva/admin/connected-accounts/[id]/sources/route.d.ts.map +1 -0
  29. package/dist/api/viva/admin/connected-accounts/[id]/sources/route.js +234 -0
  30. package/dist/api/viva/admin/connected-accounts/[id]/sources/route.js.map +1 -0
  31. package/dist/api/viva/admin/connected-accounts/route.d.ts +19 -0
  32. package/dist/api/viva/admin/connected-accounts/route.d.ts.map +1 -0
  33. package/dist/api/viva/admin/connected-accounts/route.js +78 -0
  34. package/dist/api/viva/admin/connected-accounts/route.js.map +1 -0
  35. package/dist/api/viva/internal/auth-status/route.d.ts +19 -0
  36. package/dist/api/viva/internal/auth-status/route.d.ts.map +1 -0
  37. package/dist/api/viva/internal/auth-status/route.js +91 -0
  38. package/dist/api/viva/internal/auth-status/route.js.map +1 -0
  39. package/dist/api/viva/internal/metrics/route.d.ts +13 -0
  40. package/dist/api/viva/internal/metrics/route.d.ts.map +1 -0
  41. package/dist/api/viva/internal/metrics/route.js +48 -0
  42. package/dist/api/viva/internal/metrics/route.js.map +1 -0
  43. package/dist/api/viva/webhook/health/route.d.ts +16 -0
  44. package/dist/api/viva/webhook/health/route.d.ts.map +1 -0
  45. package/dist/api/viva/webhook/health/route.js +27 -0
  46. package/dist/api/viva/webhook/health/route.js.map +1 -0
  47. package/dist/api/viva/webhook/route.d.ts +57 -0
  48. package/dist/api/viva/webhook/route.d.ts.map +1 -0
  49. package/dist/api/viva/webhook/route.js +269 -0
  50. package/dist/api/viva/webhook/route.js.map +1 -0
  51. package/dist/cli/bin.d.ts +12 -0
  52. package/dist/cli/bin.d.ts.map +1 -0
  53. package/dist/cli/bin.js +78 -0
  54. package/dist/cli/bin.js.map +1 -0
  55. package/dist/cli/index.d.ts +12 -0
  56. package/dist/cli/index.d.ts.map +1 -0
  57. package/dist/cli/index.js +14 -0
  58. package/dist/cli/index.js.map +1 -0
  59. package/dist/cli/plan.d.ts +51 -0
  60. package/dist/cli/plan.d.ts.map +1 -0
  61. package/dist/cli/plan.js +128 -0
  62. package/dist/cli/plan.js.map +1 -0
  63. package/dist/cli/register-webhooks.d.ts +54 -0
  64. package/dist/cli/register-webhooks.d.ts.map +1 -0
  65. package/dist/cli/register-webhooks.js +366 -0
  66. package/dist/cli/register-webhooks.js.map +1 -0
  67. package/dist/cli/types.d.ts +62 -0
  68. package/dist/cli/types.d.ts.map +1 -0
  69. package/dist/cli/types.js +12 -0
  70. package/dist/cli/types.js.map +1 -0
  71. package/dist/config.d.ts +158 -0
  72. package/dist/config.d.ts.map +1 -0
  73. package/dist/config.js +236 -0
  74. package/dist/config.js.map +1 -0
  75. package/dist/index.d.ts +21 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +29 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/loaders/viva-oauth2-strategy.d.ts +26 -0
  80. package/dist/loaders/viva-oauth2-strategy.d.ts.map +1 -0
  81. package/dist/loaders/viva-oauth2-strategy.js +58 -0
  82. package/dist/loaders/viva-oauth2-strategy.js.map +1 -0
  83. package/dist/migrations/Migration_20260425000001_init_viva_payments.d.ts +19 -0
  84. package/dist/migrations/Migration_20260425000001_init_viva_payments.d.ts.map +1 -0
  85. package/dist/migrations/Migration_20260425000001_init_viva_payments.js +136 -0
  86. package/dist/migrations/Migration_20260425000001_init_viva_payments.js.map +1 -0
  87. package/dist/migrations/Migration_20260425000002_allow_null_order_code.d.ts +31 -0
  88. package/dist/migrations/Migration_20260425000002_allow_null_order_code.d.ts.map +1 -0
  89. package/dist/migrations/Migration_20260425000002_allow_null_order_code.js +71 -0
  90. package/dist/migrations/Migration_20260425000002_allow_null_order_code.js.map +1 -0
  91. package/dist/migrations/Migration_20260425000003_webhook_retry_count.d.ts +18 -0
  92. package/dist/migrations/Migration_20260425000003_webhook_retry_count.d.ts.map +1 -0
  93. package/dist/migrations/Migration_20260425000003_webhook_retry_count.js +42 -0
  94. package/dist/migrations/Migration_20260425000003_webhook_retry_count.js.map +1 -0
  95. package/dist/migrations/Migration_20260425000004_webhook_error_and_nullable_merchant.d.ts +29 -0
  96. package/dist/migrations/Migration_20260425000004_webhook_error_and_nullable_merchant.d.ts.map +1 -0
  97. package/dist/migrations/Migration_20260425000004_webhook_error_and_nullable_merchant.js +74 -0
  98. package/dist/migrations/Migration_20260425000004_webhook_error_and_nullable_merchant.js.map +1 -0
  99. package/dist/models/index.d.ts +7 -0
  100. package/dist/models/index.d.ts.map +1 -0
  101. package/dist/models/index.js +10 -0
  102. package/dist/models/index.js.map +1 -0
  103. package/dist/models/viva-tenant-merchant.d.ts +11 -0
  104. package/dist/models/viva-tenant-merchant.d.ts.map +1 -0
  105. package/dist/models/viva-tenant-merchant.js +54 -0
  106. package/dist/models/viva-tenant-merchant.js.map +1 -0
  107. package/dist/models/viva-transaction.d.ts +34 -0
  108. package/dist/models/viva-transaction.d.ts.map +1 -0
  109. package/dist/models/viva-transaction.js +104 -0
  110. package/dist/models/viva-transaction.js.map +1 -0
  111. package/dist/models/viva-webhook-event.d.ts +32 -0
  112. package/dist/models/viva-webhook-event.d.ts.map +1 -0
  113. package/dist/models/viva-webhook-event.js +88 -0
  114. package/dist/models/viva-webhook-event.js.map +1 -0
  115. package/dist/observability/config.d.ts +34 -0
  116. package/dist/observability/config.d.ts.map +1 -0
  117. package/dist/observability/config.js +57 -0
  118. package/dist/observability/config.js.map +1 -0
  119. package/dist/observability/index.d.ts +8 -0
  120. package/dist/observability/index.d.ts.map +1 -0
  121. package/dist/observability/index.js +15 -0
  122. package/dist/observability/index.js.map +1 -0
  123. package/dist/observability/prom-metrics.d.ts +41 -0
  124. package/dist/observability/prom-metrics.d.ts.map +1 -0
  125. package/dist/observability/prom-metrics.js +219 -0
  126. package/dist/observability/prom-metrics.js.map +1 -0
  127. package/dist/providers/payment-provider.d.ts +19 -0
  128. package/dist/providers/payment-provider.d.ts.map +1 -0
  129. package/dist/providers/payment-provider.js +24 -0
  130. package/dist/providers/payment-provider.js.map +1 -0
  131. package/dist/resolvers/auth-strategy-factory.d.ts +42 -0
  132. package/dist/resolvers/auth-strategy-factory.d.ts.map +1 -0
  133. package/dist/resolvers/auth-strategy-factory.js +60 -0
  134. package/dist/resolvers/auth-strategy-factory.js.map +1 -0
  135. package/dist/resolvers/tenant-resolver.d.ts +104 -0
  136. package/dist/resolvers/tenant-resolver.d.ts.map +1 -0
  137. package/dist/resolvers/tenant-resolver.js +118 -0
  138. package/dist/resolvers/tenant-resolver.js.map +1 -0
  139. package/dist/service.d.ts +200 -0
  140. package/dist/service.d.ts.map +1 -0
  141. package/dist/service.js +1003 -0
  142. package/dist/service.js.map +1 -0
  143. package/dist/subscribers/index.d.ts +5 -0
  144. package/dist/subscribers/index.d.ts.map +1 -0
  145. package/dist/subscribers/index.js +10 -0
  146. package/dist/subscribers/index.js.map +1 -0
  147. package/dist/subscribers/viva-webhook-event.d.ts +38 -0
  148. package/dist/subscribers/viva-webhook-event.d.ts.map +1 -0
  149. package/dist/subscribers/viva-webhook-event.js +133 -0
  150. package/dist/subscribers/viva-webhook-event.js.map +1 -0
  151. package/dist/workflows/cleanup-old-webhook-events.d.ts +39 -0
  152. package/dist/workflows/cleanup-old-webhook-events.d.ts.map +1 -0
  153. package/dist/workflows/cleanup-old-webhook-events.js +68 -0
  154. package/dist/workflows/cleanup-old-webhook-events.js.map +1 -0
  155. package/dist/workflows/index.d.ts +14 -0
  156. package/dist/workflows/index.d.ts.map +1 -0
  157. package/dist/workflows/index.js +19 -0
  158. package/dist/workflows/index.js.map +1 -0
  159. package/dist/workflows/per-tenant-semaphore.d.ts +47 -0
  160. package/dist/workflows/per-tenant-semaphore.d.ts.map +1 -0
  161. package/dist/workflows/per-tenant-semaphore.js +89 -0
  162. package/dist/workflows/per-tenant-semaphore.js.map +1 -0
  163. package/dist/workflows/process-webhook-event.d.ts +80 -0
  164. package/dist/workflows/process-webhook-event.d.ts.map +1 -0
  165. package/dist/workflows/process-webhook-event.js +280 -0
  166. package/dist/workflows/process-webhook-event.js.map +1 -0
  167. package/dist/workflows/reprocess-unresolved-tenants.d.ts +58 -0
  168. package/dist/workflows/reprocess-unresolved-tenants.d.ts.map +1 -0
  169. package/dist/workflows/reprocess-unresolved-tenants.js +121 -0
  170. package/dist/workflows/reprocess-unresolved-tenants.js.map +1 -0
  171. package/package.json +63 -0
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ /**
3
+ * route.ts — POST /viva/admin/connected-accounts/:id/sources
4
+ *
5
+ * ISV-only admin endpoint. Creates a payment source (ecommerce or physical)
6
+ * on a connected merchant's Viva account via `POST /api/sources` on the
7
+ * legacy host, authenticated with **Reseller Basic** auth.
8
+ *
9
+ * 1. Validates plugin is in ISV mode (404 in merchant mode).
10
+ * 2. Validates admin token (401 if missing/wrong).
11
+ * 3. Requires `config.reseller` (412 with `VIVA_RESELLER_CREDENTIALS_MISSING`).
12
+ * 4. Resolves the connected merchant's `merchantId` UUID via
13
+ * `IsvAccounts.retrieveConnectedAccount(:id)` — 409 with
14
+ * `VIVA_ACCOUNT_NOT_VERIFIED` when `verified !== true` or `merchantId`
15
+ * is null.
16
+ * 5. Builds a per-request `BasicAuthClient` with `authVariant: 'reseller'`
17
+ * whose username slot carries `resellerId:account.merchantId` (NOT the
18
+ * platform's merchant id — see AUTH.md §1.2 line 98 + ENDPOINTS.md §5.1).
19
+ * 6. Calls `IsvSources.createEcommerceSource` or `createPhysicalSource`
20
+ * based on the body's `kind` discriminator.
21
+ * 7. Returns 201 + `{ sourceCode, name, kind }`.
22
+ *
23
+ * Viva 4xx on `/api/sources` is mapped to 422 with `VIVA_SOURCE_CREATION_FAILED`.
24
+ * Viva 5xx / non-API errors fall through to the existing 5xx envelope.
25
+ *
26
+ * @see docs/plans/multi-mode-v0.md §6 (admin REST table)
27
+ * @see docs/ENDPOINTS.md §5.1
28
+ * @see docs/AUTH.md §1.2 (Reseller Basic)
29
+ * @see docs/ERRORS.md (VIVA_SOURCE_CREATION_FAILED, VIVA_RESELLER_CREDENTIALS_MISSING)
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.POST = void 0;
33
+ const isv_1 = require("@sakeetech/viva-payments-core/isv");
34
+ const legacy_1 = require("@sakeetech/viva-payments-core/legacy");
35
+ const errors_1 = require("@sakeetech/viva-payments-core/errors");
36
+ const config_js_1 = require("../../../../../../config.js");
37
+ const auth_strategy_factory_js_1 = require("../../../../../../resolvers/auth-strategy-factory.js");
38
+ const _mode_gate_js_1 = require("../../../_mode-gate.js");
39
+ const _admin_auth_js_1 = require("../../../_admin-auth.js");
40
+ /**
41
+ * Narrow the raw body into an IsvSources input by `kind`. Returns either a
42
+ * validated `{ kind, input }` pair or a `{ error }` envelope describing the
43
+ * first validation failure.
44
+ */
45
+ function parseBody(raw) {
46
+ const body = (raw ?? {});
47
+ const kind = body.kind;
48
+ if (kind !== 'ecommerce' && kind !== 'physical') {
49
+ return {
50
+ ok: false,
51
+ status: 400,
52
+ body: {
53
+ error: 'invalid_request',
54
+ message: "body.kind must be 'ecommerce' or 'physical'",
55
+ },
56
+ };
57
+ }
58
+ const sourceCode = body.sourceCode;
59
+ if (sourceCode !== undefined && typeof sourceCode !== 'number') {
60
+ return {
61
+ ok: false,
62
+ status: 400,
63
+ body: { error: 'invalid_request', message: 'sourceCode must be a number' },
64
+ };
65
+ }
66
+ if (kind === 'physical') {
67
+ if (typeof body.name !== 'string' || body.name.trim() === '') {
68
+ return {
69
+ ok: false,
70
+ status: 400,
71
+ body: { error: 'invalid_request', message: 'name is required for physical sources' },
72
+ };
73
+ }
74
+ const input = {
75
+ name: body.name,
76
+ ...(sourceCode !== undefined ? { sourceCode: sourceCode } : {}),
77
+ };
78
+ return { ok: true, kind, input };
79
+ }
80
+ // ecommerce
81
+ if (typeof body.domain !== 'string' || body.domain.trim() === '') {
82
+ return {
83
+ ok: false,
84
+ status: 400,
85
+ body: { error: 'invalid_request', message: 'domain is required for ecommerce sources' },
86
+ };
87
+ }
88
+ if (typeof body.pathSuccess !== 'string' || body.pathSuccess.trim() === '') {
89
+ return {
90
+ ok: false,
91
+ status: 400,
92
+ body: { error: 'invalid_request', message: 'pathSuccess is required for ecommerce sources' },
93
+ };
94
+ }
95
+ if (typeof body.pathFail !== 'string' || body.pathFail.trim() === '') {
96
+ return {
97
+ ok: false,
98
+ status: 400,
99
+ body: { error: 'invalid_request', message: 'pathFail is required for ecommerce sources' },
100
+ };
101
+ }
102
+ const ecomInput = {
103
+ domain: body.domain,
104
+ pathSuccess: body.pathSuccess,
105
+ pathFail: body.pathFail,
106
+ ...(typeof body.name === 'string' ? { name: body.name } : {}),
107
+ ...(typeof body.isSecure === 'boolean' ? { isSecure: body.isSecure } : {}),
108
+ ...(sourceCode !== undefined ? { sourceCode: sourceCode } : {}),
109
+ };
110
+ return { ok: true, kind, input: ecomInput };
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // Handler
114
+ // ---------------------------------------------------------------------------
115
+ const POST = async (req, res) => {
116
+ if ((0, _mode_gate_js_1.reject404IfNotIsv)(req, res))
117
+ return;
118
+ if ((0, _admin_auth_js_1.reject401IfUnauthorized)(req, res))
119
+ return;
120
+ const id = req.params?.id;
121
+ if (!id) {
122
+ res.status(400).json({ error: 'id is required' });
123
+ return;
124
+ }
125
+ // Load config + check reseller block before parsing body so misconfigured
126
+ // deployments fail fast with a clear envelope.
127
+ let config;
128
+ try {
129
+ config = (0, config_js_1.loadConfigFromEnv)(process.env);
130
+ }
131
+ catch (err) {
132
+ const message = err instanceof Error ? err.message : String(err);
133
+ res.status(500).json({ error: 'internal_error', message });
134
+ return;
135
+ }
136
+ if (config.mode !== 'isv') {
137
+ // Defensive: reject404IfNotIsv already covered this, but the type guard
138
+ // narrows config to VivaIsvConfig below.
139
+ res.status(404).json({ error: 'Not Found' });
140
+ return;
141
+ }
142
+ if (!config.reseller) {
143
+ res.status(412).json({
144
+ error: 'precondition_failed',
145
+ code: 'VIVA_RESELLER_CREDENTIALS_MISSING',
146
+ message: 'POST /viva/admin/connected-accounts/:id/sources requires reseller credentials. ' +
147
+ 'Set VIVA_RESELLER_ID, VIVA_RESELLER_MERCHANT_ID, VIVA_RESELLER_API_KEY.',
148
+ });
149
+ return;
150
+ }
151
+ const parsed = parseBody(req.body);
152
+ if (!parsed.ok) {
153
+ res.status(parsed.status).json(parsed.body);
154
+ return;
155
+ }
156
+ try {
157
+ // 1. Resolve the connected merchant's UUID via OAuth2 (platform) creds.
158
+ const authStrategies = (0, auth_strategy_factory_js_1.buildAuthStrategies)(config);
159
+ const httpClient = new isv_1.IsvHttpClient({
160
+ environment: config.environment,
161
+ authStrategy: authStrategies.primary,
162
+ });
163
+ const accounts = new isv_1.IsvAccounts(httpClient);
164
+ const account = await accounts.retrieveConnectedAccount(id);
165
+ if (account.verified !== true || account.merchantId == null) {
166
+ res.status(409).json({
167
+ error: 'conflict',
168
+ code: 'VIVA_ACCOUNT_NOT_VERIFIED',
169
+ message: `Connected account ${id} is not verified yet (verified=${String(account.verified)}, ` +
170
+ `merchantId=${account.merchantId == null ? 'null' : 'set'}). ` +
171
+ `Wait for webhook 8194 or POST /viva/admin/connected-accounts/${id}/reconcile.`,
172
+ });
173
+ return;
174
+ }
175
+ // 2. Build Reseller Basic client scoped to THIS connected merchant.
176
+ // Per AUTH.md §1.2 line 98 + ENDPOINTS.md §5.1: the MerchantId slot of
177
+ // Reseller Basic is the connected merchant's UUID (account.merchantId),
178
+ // NOT the platform's merchant id (config.reseller.merchantId — which
179
+ // is unused here, despite the field name).
180
+ const basic = new legacy_1.BasicAuthClient({
181
+ authVariant: 'reseller',
182
+ environment: config.environment,
183
+ resellerId: config.reseller.resellerId,
184
+ merchantId: account.merchantId,
185
+ resellerApiKey: config.reseller.resellerApiKey,
186
+ });
187
+ const sources = new isv_1.IsvSources(basic);
188
+ // 3. Dispatch on kind.
189
+ const response = parsed.kind === 'ecommerce'
190
+ ? await sources.createEcommerceSource(parsed.input)
191
+ : await sources.createPhysicalSource(parsed.input);
192
+ res.status(201).json({
193
+ sourceCode: response.sourceCode,
194
+ name: response.name ?? parsed.input.name,
195
+ kind: parsed.kind,
196
+ });
197
+ }
198
+ catch (err) {
199
+ if (err instanceof errors_1.VivaValidationError) {
200
+ res.status(400).json({
201
+ error: 'invalid_request',
202
+ code: err.code,
203
+ message: err.message,
204
+ });
205
+ return;
206
+ }
207
+ if (err instanceof errors_1.VivaApiError) {
208
+ const status = err.httpStatus;
209
+ // Map Viva 4xx on /api/sources to VIVA_SOURCE_CREATION_FAILED (422 envelope).
210
+ if (typeof status === 'number' && status >= 400 && status < 500) {
211
+ res.status(422).json({
212
+ error: 'unprocessable_entity',
213
+ code: 'VIVA_SOURCE_CREATION_FAILED',
214
+ vivaStatus: status,
215
+ vivaCode: err.code,
216
+ message: err.message,
217
+ });
218
+ return;
219
+ }
220
+ // Non-4xx Viva error (network, 5xx) — pass through.
221
+ res.status(status ?? 502).json({
222
+ error: 'viva_api_error',
223
+ code: err.code,
224
+ message: err.message,
225
+ });
226
+ return;
227
+ }
228
+ const logger = req.scope?.resolve?.('logger');
229
+ logger?.error?.(`[viva] POST /viva/admin/connected-accounts/:id/sources failed: ${err instanceof Error ? err.message : String(err)}`);
230
+ res.status(500).json({ error: 'internal_error' });
231
+ }
232
+ };
233
+ exports.POST = POST;
234
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../../../../src/api/viva/admin/connected-accounts/[id]/sources/route.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * route.ts — POST /viva/admin/connected-accounts
3
+ *
4
+ * ISV-only admin endpoint. Initiates a Viva connected-account onboarding flow:
5
+ * 1. Validates that the plugin is in ISV mode (404 in merchant mode).
6
+ * 2. Validates admin token (401 if missing/wrong).
7
+ * 3. Calls `IsvAccounts.createConnectedAccount` against Viva.
8
+ * 4. Returns `{ accountId, onboardingUrl }`.
9
+ *
10
+ * Merchant-mode gating uses Option 2 (per-handler 404 short-circuit) — see
11
+ * `_mode-gate.ts` for the rationale. Medusa v2 has no clean way to skip a
12
+ * `route.ts` file at boot based on plugin config.
13
+ *
14
+ * @see docs/plans/multi-mode-v0.md §6 (mode-surface gating)
15
+ * @see references/viva-docs/md/payment-isv-api.txt:1 (Connected Accounts API)
16
+ */
17
+ import type { MedusaRequest, MedusaResponse } from '@medusajs/framework/http';
18
+ export declare const POST: (req: MedusaRequest, res: MedusaResponse) => Promise<void>;
19
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/api/viva/admin/connected-accounts/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAmB9E,eAAO,MAAM,IAAI,GACf,KAAK,aAAa,EAClB,KAAK,cAAc,KAClB,OAAO,CAAC,IAAI,CAsDd,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * route.ts — POST /viva/admin/connected-accounts
4
+ *
5
+ * ISV-only admin endpoint. Initiates a Viva connected-account onboarding flow:
6
+ * 1. Validates that the plugin is in ISV mode (404 in merchant mode).
7
+ * 2. Validates admin token (401 if missing/wrong).
8
+ * 3. Calls `IsvAccounts.createConnectedAccount` against Viva.
9
+ * 4. Returns `{ accountId, onboardingUrl }`.
10
+ *
11
+ * Merchant-mode gating uses Option 2 (per-handler 404 short-circuit) — see
12
+ * `_mode-gate.ts` for the rationale. Medusa v2 has no clean way to skip a
13
+ * `route.ts` file at boot based on plugin config.
14
+ *
15
+ * @see docs/plans/multi-mode-v0.md §6 (mode-surface gating)
16
+ * @see references/viva-docs/md/payment-isv-api.txt:1 (Connected Accounts API)
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.POST = void 0;
20
+ const isv_1 = require("@sakeetech/viva-payments-core/isv");
21
+ const isv_2 = require("@sakeetech/viva-payments-core/isv");
22
+ const errors_1 = require("@sakeetech/viva-payments-core/errors");
23
+ const config_js_1 = require("../../../../config.js");
24
+ const auth_strategy_factory_js_1 = require("../../../../resolvers/auth-strategy-factory.js");
25
+ const _mode_gate_js_1 = require("../_mode-gate.js");
26
+ const _admin_auth_js_1 = require("../_admin-auth.js");
27
+ const POST = async (req, res) => {
28
+ // 1. Mode gate first — merchant mode pretends route doesn't exist.
29
+ if ((0, _mode_gate_js_1.reject404IfNotIsv)(req, res))
30
+ return;
31
+ // 2. Admin token gate.
32
+ if ((0, _admin_auth_js_1.reject401IfUnauthorized)(req, res))
33
+ return;
34
+ // 3. Body validation.
35
+ const body = (req.body ?? {});
36
+ if (!body.email || typeof body.email !== 'string') {
37
+ res.status(400).json({ error: 'email is required' });
38
+ return;
39
+ }
40
+ if (!body.returnUrl || typeof body.returnUrl !== 'string') {
41
+ res.status(400).json({ error: 'returnUrl is required' });
42
+ return;
43
+ }
44
+ // 4. Build client + call Viva.
45
+ try {
46
+ const config = (0, config_js_1.loadConfigFromEnv)(process.env);
47
+ const authStrategies = (0, auth_strategy_factory_js_1.buildAuthStrategies)(config);
48
+ const httpClient = new isv_1.IsvHttpClient({
49
+ environment: config.environment,
50
+ authStrategy: authStrategies.primary,
51
+ });
52
+ const accounts = new isv_2.IsvAccounts(httpClient);
53
+ const created = await accounts.createConnectedAccount({
54
+ email: body.email,
55
+ returnUrl: body.returnUrl,
56
+ ...(body.branding ? { branding: body.branding } : {}),
57
+ });
58
+ res.status(200).json({
59
+ accountId: created.accountId,
60
+ onboardingUrl: created.invitation.redirectUrl,
61
+ });
62
+ }
63
+ catch (err) {
64
+ if (err instanceof errors_1.VivaApiError) {
65
+ res.status(err.httpStatus ?? 502).json({
66
+ error: 'viva_api_error',
67
+ code: err.code,
68
+ message: err.message,
69
+ });
70
+ return;
71
+ }
72
+ const logger = req.scope?.resolve?.('logger');
73
+ logger?.error?.(`[viva] POST /viva/admin/connected-accounts failed: ${err instanceof Error ? err.message : String(err)}`);
74
+ res.status(500).json({ error: 'internal_error' });
75
+ }
76
+ };
77
+ exports.POST = POST;
78
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../../src/api/viva/admin/connected-accounts/route.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * route.ts — GET /viva/internal/auth-status
3
+ *
4
+ * Admin-guarded endpoint. Returns current OAuth2 token expiry state for
5
+ * readiness checks and debugging.
6
+ *
7
+ * Auth gate: constant-time comparison of X-Viva-Admin-Token header against
8
+ * VIVA_ADMIN_TOKEN env var. 401 if missing or mismatch.
9
+ *
10
+ * Design decision: using env-var shared secret rather than Medusa admin auth
11
+ * because this route is accessed by ops tooling (healthcheck scripts, monitoring
12
+ * agents) that may not have a Medusa admin session. VIVA_ADMIN_TOKEN is rotated
13
+ * independently via secrets manager. Document this choice for operators.
14
+ *
15
+ * @see references/viva-docs/md/isv-partner-program.txt:61 (P16 health endpoints)
16
+ */
17
+ import type { MedusaRequest, MedusaResponse } from '@medusajs/framework/http';
18
+ export declare const GET: (req: MedusaRequest, res: MedusaResponse) => Promise<void>;
19
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/api/viva/internal/auth-status/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAuB9E,eAAO,MAAM,GAAG,GACd,KAAK,aAAa,EAClB,KAAK,cAAc,KAClB,OAAO,CAAC,IAAI,CA8Dd,CAAC"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * route.ts — GET /viva/internal/auth-status
4
+ *
5
+ * Admin-guarded endpoint. Returns current OAuth2 token expiry state for
6
+ * readiness checks and debugging.
7
+ *
8
+ * Auth gate: constant-time comparison of X-Viva-Admin-Token header against
9
+ * VIVA_ADMIN_TOKEN env var. 401 if missing or mismatch.
10
+ *
11
+ * Design decision: using env-var shared secret rather than Medusa admin auth
12
+ * because this route is accessed by ops tooling (healthcheck scripts, monitoring
13
+ * agents) that may not have a Medusa admin session. VIVA_ADMIN_TOKEN is rotated
14
+ * independently via secrets manager. Document this choice for operators.
15
+ *
16
+ * @see references/viva-docs/md/isv-partner-program.txt:61 (P16 health endpoints)
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.GET = void 0;
20
+ const node_crypto_1 = require("node:crypto");
21
+ const viva_oauth2_strategy_js_1 = require("../../../../loaders/viva-oauth2-strategy.js");
22
+ // ---------------------------------------------------------------------------
23
+ // Admin token guard
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Constant-time comparison of two strings.
27
+ * Returns false immediately if lengths differ (avoids timing side-channel on length).
28
+ */
29
+ function isTokenValid(provided, expected) {
30
+ if (provided.length !== expected.length)
31
+ return false;
32
+ return (0, node_crypto_1.timingSafeEqual)(Buffer.from(provided, 'utf-8'), Buffer.from(expected, 'utf-8'));
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // GET handler
36
+ // ---------------------------------------------------------------------------
37
+ const GET = async (req, res) => {
38
+ const adminToken = process.env['VIVA_ADMIN_TOKEN'];
39
+ // If VIVA_ADMIN_TOKEN is not configured: always deny, document reason.
40
+ if (!adminToken) {
41
+ res.status(401).json({
42
+ error: 'unauthorized',
43
+ reason: 'admin-token-not-configured',
44
+ });
45
+ return;
46
+ }
47
+ const provided = req.headers['x-viva-admin-token'];
48
+ const providedStr = Array.isArray(provided) ? provided[0] : provided;
49
+ if (!providedStr || !isTokenValid(providedStr, adminToken)) {
50
+ res.status(401).json({ error: 'unauthorized' });
51
+ return;
52
+ }
53
+ // ---- Read token cache state from the singleton strategy ----
54
+ const environment = process.env['VIVA_ENVIRONMENT'] ?? 'demo';
55
+ let tokenExpiresAt = null;
56
+ let lastRefreshAt = null;
57
+ let tokenPresent = false;
58
+ try {
59
+ // Resolve the singleton OAuth2 strategy registered by the plugin loader.
60
+ // Using allowUnregistered so the route degrades gracefully when the loader
61
+ // hasn't run (e.g. bare test environments without full Medusa bootstrap).
62
+ const strategy = req.scope?.resolve(viva_oauth2_strategy_js_1.VIVA_OAUTH2_STRATEGY_KEY, { allowUnregistered: true });
63
+ if (strategy) {
64
+ const cache = strategy.tokenCache;
65
+ const clientId = process.env['VIVA_ISV_CLIENT_ID'] ?? '';
66
+ const cacheKey = `viva:isv:token:${clientId}:${environment}`;
67
+ const cached = await cache.get(cacheKey);
68
+ if (cached) {
69
+ tokenPresent = true;
70
+ tokenExpiresAt = new Date(cached.expires_at).toISOString();
71
+ // last_refresh_at: approximate — expires_at - (3600 - 60) seconds = expires_at - 3540s
72
+ // The cache stores expires_at = now_at_refresh + 3600000 - 60000.
73
+ // We can approximate refresh time = expires_at - 3540000ms.
74
+ lastRefreshAt = new Date(cached.expires_at - 3540 * 1000).toISOString();
75
+ }
76
+ }
77
+ }
78
+ catch {
79
+ // Strategy not available — return what we can
80
+ }
81
+ res.setHeader('Cache-Control', 'no-store');
82
+ res.status(200).json({
83
+ environment,
84
+ token_present: tokenPresent,
85
+ token_expires_at: tokenExpiresAt,
86
+ last_refresh_at: lastRefreshAt,
87
+ now: new Date().toISOString(),
88
+ });
89
+ };
90
+ exports.GET = GET;
91
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../../src/api/viva/internal/auth-status/route.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * route.ts — GET /viva/internal/metrics
3
+ *
4
+ * Admin-guarded Prometheus text format scrape endpoint.
5
+ * Returns in-process metric counters and histograms from PromMetricsHook.
6
+ *
7
+ * Auth gate: same X-Viva-Admin-Token / VIVA_ADMIN_TOKEN as auth-status.
8
+ *
9
+ * @see references/viva-docs/md/isv-partner-program.txt:61 (P16 observability)
10
+ */
11
+ import type { MedusaRequest, MedusaResponse } from '@medusajs/framework/http';
12
+ export declare const GET: (req: MedusaRequest, res: MedusaResponse) => Promise<void>;
13
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/api/viva/internal/metrics/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAiB9E,eAAO,MAAM,GAAG,GACd,KAAK,aAAa,EAClB,KAAK,cAAc,KAClB,OAAO,CAAC,IAAI,CAwBd,CAAC"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /**
3
+ * route.ts — GET /viva/internal/metrics
4
+ *
5
+ * Admin-guarded Prometheus text format scrape endpoint.
6
+ * Returns in-process metric counters and histograms from PromMetricsHook.
7
+ *
8
+ * Auth gate: same X-Viva-Admin-Token / VIVA_ADMIN_TOKEN as auth-status.
9
+ *
10
+ * @see references/viva-docs/md/isv-partner-program.txt:61 (P16 observability)
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.GET = void 0;
14
+ const node_crypto_1 = require("node:crypto");
15
+ const index_js_1 = require("../../../../observability/index.js");
16
+ // ---------------------------------------------------------------------------
17
+ // Admin token guard (same pattern as auth-status)
18
+ // ---------------------------------------------------------------------------
19
+ function isTokenValid(provided, expected) {
20
+ if (provided.length !== expected.length)
21
+ return false;
22
+ return (0, node_crypto_1.timingSafeEqual)(Buffer.from(provided, 'utf-8'), Buffer.from(expected, 'utf-8'));
23
+ }
24
+ // ---------------------------------------------------------------------------
25
+ // GET handler
26
+ // ---------------------------------------------------------------------------
27
+ const GET = async (req, res) => {
28
+ const adminToken = process.env['VIVA_ADMIN_TOKEN'];
29
+ if (!adminToken) {
30
+ res.status(401).json({
31
+ error: 'unauthorized',
32
+ reason: 'admin-token-not-configured',
33
+ });
34
+ return;
35
+ }
36
+ const provided = req.headers['x-viva-admin-token'];
37
+ const providedStr = Array.isArray(provided) ? provided[0] : provided;
38
+ if (!providedStr || !isTokenValid(providedStr, adminToken)) {
39
+ res.status(401).json({ error: 'unauthorized' });
40
+ return;
41
+ }
42
+ const exposition = (0, index_js_1.getSharedMetrics)().toExposition();
43
+ res.setHeader('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');
44
+ res.setHeader('Cache-Control', 'no-store');
45
+ res.status(200).send(exposition);
46
+ };
47
+ exports.GET = GET;
48
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../../src/api/viva/internal/metrics/route.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAGH,6CAA8C;AAC9C,iEAAsE;AAEtE,8EAA8E;AAC9E,kDAAkD;AAClD,8EAA8E;AAE9E,SAAS,YAAY,CAAC,QAAgB,EAAE,QAAgB;IACtD,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACtD,OAAO,IAAA,6BAAe,EAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AACzF,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAEvE,MAAM,GAAG,GAAG,KAAK,EACtB,GAAkB,EAClB,GAAmB,EACJ,EAAE;IACjB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAEnD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,cAAc;YACrB,MAAM,EAAE,4BAA4B;SACrC,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAErE,IAAI,CAAC,WAAW,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,IAAA,2BAAgB,GAAE,CAAC,YAAY,EAAE,CAAC;IAErD,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,0CAA0C,CAAC,CAAC;IAC1E,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IAC3C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC,CAAC;AA3BW,QAAA,GAAG,OA2Bd"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * route.ts — GET /viva/webhook/health
3
+ *
4
+ * Liveness probe. No auth. Returns 200 { ok: true, environment, timestamp }.
5
+ *
6
+ * @see references/viva-docs/md/isv-partner-program.txt:61 (P16 health endpoints)
7
+ */
8
+ import type { MedusaRequest, MedusaResponse } from '@medusajs/framework/http';
9
+ /**
10
+ * GET /viva/webhook/health
11
+ *
12
+ * Returns 200 { ok: true } unconditionally.
13
+ * Cache-Control: no-store to prevent proxy caching.
14
+ */
15
+ export declare const GET: (_req: MedusaRequest, res: MedusaResponse) => Promise<void>;
16
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/api/viva/webhook/health/route.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,GAAG,GACd,MAAM,aAAa,EACnB,KAAK,cAAc,KAClB,OAAO,CAAC,IAAI,CASd,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ /**
3
+ * route.ts — GET /viva/webhook/health
4
+ *
5
+ * Liveness probe. No auth. Returns 200 { ok: true, environment, timestamp }.
6
+ *
7
+ * @see references/viva-docs/md/isv-partner-program.txt:61 (P16 health endpoints)
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.GET = void 0;
11
+ /**
12
+ * GET /viva/webhook/health
13
+ *
14
+ * Returns 200 { ok: true } unconditionally.
15
+ * Cache-Control: no-store to prevent proxy caching.
16
+ */
17
+ const GET = async (_req, res) => {
18
+ const environment = process.env['VIVA_ENVIRONMENT'] ?? 'demo';
19
+ res.setHeader('Cache-Control', 'no-store');
20
+ res.status(200).json({
21
+ ok: true,
22
+ environment,
23
+ timestamp: new Date().toISOString(),
24
+ });
25
+ };
26
+ exports.GET = GET;
27
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../../src/api/viva/webhook/health/route.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAIH;;;;;GAKG;AACI,MAAM,GAAG,GAAG,KAAK,EACtB,IAAmB,EACnB,GAAmB,EACJ,EAAE;IACjB,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,MAAM,CAAC;IAE9D,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IAC3C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,EAAE,EAAE,IAAI;QACR,WAAW;QACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;AACL,CAAC,CAAC;AAZW,QAAA,GAAG,OAYd"}