@vivoa/plugin-sdk 0.6.2 → 0.6.5

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/README.md CHANGED
@@ -7,8 +7,8 @@ A plugin author depends on this package; the Vivoa host re-exports it as its
7
7
  single source of truth for plugin shapes.
8
8
 
9
9
  > **Building a plugin?** Read [`AUTHORING.md`](./AUTHORING.md) — the complete,
10
- > AI-legible guide (anatomy, `IPaymentPlugin`/`IShippingPlugin`, config, setup
11
- > layout, permissions, build/publish, and the host landmines to avoid).
10
+ > AI-legible guide (anatomy, capabilities, config, setup layout, permissions,
11
+ > build/publish, and the host landmines to avoid).
12
12
 
13
13
  ## Install
14
14
 
@@ -16,41 +16,177 @@ single source of truth for plugin shapes.
16
16
  npm install @vivoa/plugin-sdk
17
17
  ```
18
18
 
19
- ## What's inside
19
+ ## Capabilities
20
20
 
21
- | Module | Exports |
22
- | ---------------- | ----------------------------------------------------------------------- |
23
- | `types` | `IPlugin`, `IPaymentPlugin`, `IShippingPlugin`, payment/shipping models, DI tokens |
24
- | `manifest` | `PluginManifest` |
25
- | `config-schema` | `createPluginConfig`, `field` — declarative config + superstruct validation |
26
- | `setup-layout` | `SetupLayout` types, `validateSetupLayout`, `crossValidateSetupLayout` |
21
+ A plugin is a **factory function** `(host: HostApi) => Plugin` that declares
22
+ capabilities instead of extending a NestJS module. The host routes by
23
+ `CapabilityKind` string — adding a new kind never touches host-core code.
27
24
 
28
- All exported from the package root:
25
+ | `CapabilityKind` | Interface | Helper |
26
+ |---|---|---|
27
+ | `payment` | `IPaymentPlugin` | `paymentCapability(impl)` |
28
+ | `shipping` | `IShippingPlugin` | `shippingCapability(impl)` |
29
+ | `suppliers` | `ISuppliersPlugin` | `suppliersCapability(impl)` |
30
+ | `analytics` | `IAnalyticsPlugin` | `analyticsCapability(impl)` |
31
+ | `invoicing` | `IInvoicingPlugin` | `invoicingCapability(impl)` |
32
+
33
+ A plugin may expose any combination of capabilities (or a custom `kind`).
34
+
35
+ ## Quick start
29
36
 
30
37
  ```ts
31
38
  import {
39
+ definePlugin,
40
+ paymentCapability,
32
41
  IPaymentPlugin,
33
42
  createPluginConfig,
34
43
  field,
35
- validateSetupLayout,
44
+ } from '@vivoa/plugin-sdk';
45
+
46
+ const config = createPluginConfig({
47
+ apiKey: field({ label: 'API Key', type: 'password' }),
48
+ sandbox: field({ label: 'Sandbox mode', type: 'boolean', required: false }),
49
+ });
50
+
51
+ const myPaymentPlugin: IPaymentPlugin = {
52
+ name: 'my-gateway',
53
+ paymentConfig: {
54
+ supportedCountries: ['SV'],
55
+ configSchema: config.configFields,
56
+ supportedCurrencies: ['USD'],
57
+ },
58
+ async createPaymentSession(req, ctx) { /* ... */ },
59
+ async processPayment(req, ctx) { /* ... */ },
60
+ async refundPayment(req, ctx) { /* ... */ },
61
+ };
62
+
63
+ export default definePlugin((host) => ({
64
+ manifest: { code: 'my-gateway', name: 'My Gateway', sdkVersion: SDK_VERSION },
65
+ capabilities: [paymentCapability(myPaymentPlugin)],
66
+ onActivate(host) {
67
+ host.logger.info('my-gateway activated');
68
+ },
69
+ }));
70
+ ```
71
+
72
+ ## Modules
73
+
74
+ | Module | Key exports |
75
+ |---|---|
76
+ | `plugin` | `IPlugin` |
77
+ | `capability` | `Capability`, `CapabilityKind`, `definePlugin`, `Plugin`, `PluginFactory`, `paymentCapability`, `shippingCapability`, `suppliersCapability`, `analyticsCapability`, `invoicingCapability` |
78
+ | `host-api` | `HostApi`, `Logger`, `HttpClient`, `SecretStore`, `StorageBroker`, `SequenceStore` |
79
+ | `payment` | `IPaymentPlugin`, `PaymentSession`, payment models |
80
+ | `shipping` | `IShippingPlugin`, `ShippingQuote`, shipping models |
81
+ | `suppliers` | `ISuppliersPlugin`, suppliers models |
82
+ | `analytics` | `IAnalyticsPlugin`, `AnalyticsEvent`, `AnalyticsUserData`, `AnalyticsActionSource` |
83
+ | `invoicing` | `IInvoicingPlugin`, `InvoiceRequest`, `InvoiceResult`, `InvoiceStatus`, `InvoiceDocumentType`, `InvoicingFeature` |
84
+ | `manifest` | `PluginManifest` |
85
+ | `config` | `PluginConfigField` |
86
+ | `config-schema` | `createPluginConfig`, `field` — declarative config + superstruct validation |
87
+ | `setup-layout` | `SetupLayout` types, `validateSetupLayout`, `crossValidateSetupLayout` |
88
+ | `permissions` | `Permission`, `parsePermission`, `isPermissionGranted`, `checkPermissions` |
89
+ | `dispatch` | `DispatchContext` |
90
+ | `tokens` | DI tokens (`PAYMENT_PLUGIN_TOKEN`, `SHIPPING_PLUGIN_TOKEN`, ...) |
91
+ | `version` | `SDK_VERSION`, `isSdkCompatible` |
92
+
93
+ All exported from the package root:
94
+
95
+ ```ts
96
+ import {
97
+ definePlugin,
98
+ paymentCapability,
99
+ invoicingCapability,
100
+ createPluginConfig,
101
+ field,
102
+ SDK_VERSION,
36
103
  } from '@vivoa/plugin-sdk';
37
104
  ```
38
105
 
39
- ## Defining a configurable plugin
106
+ ## HostApi
107
+
108
+ The factory receives a `HostApi` — the plugin's entire window into the host.
109
+ No `@nestjs/*`, no Prisma, no `process.env`.
110
+
111
+ ```ts
112
+ interface HostApi {
113
+ readonly logger: Logger; // structured logging
114
+ readonly http: HttpClient; // outbound HTTP (permission-gated)
115
+ readonly secrets: SecretStore; // per-tenant secrets
116
+ readonly storage: StorageBroker; // object storage (presigned)
117
+ readonly sequence: SequenceStore; // monotonic counters (e.g. audit_no)
118
+ on(event: string, handler: DomainEventHandler): void;
119
+ registerCapability<T>(cap: Capability<T>): void;
120
+ }
121
+ ```
122
+
123
+ ## DispatchContext
124
+
125
+ Every interface method receives a `DispatchContext` — the host resolves it per
126
+ call, per tenant. The plugin holds **no per-tenant state**.
127
+
128
+ ```ts
129
+ interface DispatchContext {
130
+ config: Record<string, unknown>; // merged global config
131
+ countryConfig?: Record<string, unknown>; // country-scoped config
132
+ countryConfigs?: Record<string, Record<string, unknown>>;
133
+ countryCode?: string;
134
+ }
135
+ ```
136
+
137
+ ## Invoicing capability (0.6.4)
138
+
139
+ Country-agnostic electronic-invoicing (DTE / CFDI / …) contract.
140
+
141
+ ```ts
142
+ import {
143
+ definePlugin,
144
+ invoicingCapability,
145
+ IInvoicingPlugin,
146
+ InvoicingFeature,
147
+ InvoiceDocumentType,
148
+ InvoiceStatus,
149
+ } from '@vivoa/plugin-sdk';
150
+
151
+ const myInvoicingAdapter: IInvoicingPlugin = {
152
+ name: 'my-dte-adapter',
153
+ invoicingConfig: {
154
+ supportedCountries: ['SV'],
155
+ supportedFeatures: [InvoicingFeature.Issue, InvoicingFeature.Void],
156
+ supportedDocumentTypes: [
157
+ InvoiceDocumentType.Invoice,
158
+ InvoiceDocumentType.CreditInvoice,
159
+ ],
160
+ configSchema: [],
161
+ },
162
+ async issueInvoice(req, ctx) {
163
+ // call provider API, return InvoiceResult
164
+ return { status: InvoiceStatus.Accepted, generationCode: '...' };
165
+ },
166
+ async voidInvoice(input, ctx) { /* ... */ },
167
+ };
168
+
169
+ export default definePlugin((host) => ({
170
+ manifest: { code: 'my-dte', name: 'My DTE', sdkVersion: SDK_VERSION },
171
+ capabilities: [invoicingCapability(myInvoicingAdapter)],
172
+ }));
173
+ ```
174
+
175
+ ## Declarative config
40
176
 
41
177
  ```ts
42
178
  import { createPluginConfig, field } from '@vivoa/plugin-sdk';
43
179
 
44
180
  const config = createPluginConfig({
45
- apiKey: field({ label: 'API Key', type: 'password' }),
181
+ apiKey: field({ label: 'API Key', type: 'password' }),
46
182
  sandbox: field({ label: 'Sandbox', type: 'boolean', required: false }),
47
183
  });
48
184
 
49
- config.configFields; // -> PluginConfigField[] for the admin UI
50
- config.validate(input); // -> { success, data | errors }
185
+ config.configFields; // PluginConfigField[] → rendered by the admin UI
186
+ config.validate(userInput); // { success, data } | { success: false, errors }
51
187
  ```
52
188
 
53
- ## Validating a setup layout
189
+ ## Setup-layout validation
54
190
 
55
191
  ```ts
56
192
  import { validateSetupLayout, crossValidateSetupLayout } from '@vivoa/plugin-sdk';
@@ -61,10 +197,34 @@ if (!res.success) throw new Error(res.errors.join('\n'));
61
197
  const keyErrors = crossValidateSetupLayout(res.data, config.configFields);
62
198
  ```
63
199
 
200
+ ## Permissions
201
+
202
+ Plugins declare `permissions: string[]` in their manifest. The host enforces
203
+ each mediated port before it executes.
204
+
205
+ ```ts
206
+ // domain.action or domain.action:resource
207
+ const required = parsePermission('http.outbound:api.provider.com');
208
+ const ok = isPermissionGranted(required, grantedList);
209
+ ```
210
+
64
211
  ## Versioning
65
212
 
66
- Semver. Breaking changes to any exported type or validator bump the major.
67
- Plugins should pin a caret range (`^0.1.0`).
213
+ Semver. `SDK_VERSION` constant mirrors `package.json`. Use `isSdkCompatible` in
214
+ the host to check plugin compatibility.
215
+
216
+ **0.x convention:** the minor acts as the breaking boundary (matching
217
+ `^0.x` semantics). Additive changes ship as a **PATCH** to keep 0.x plugins
218
+ compatible across the same minor.
219
+
220
+ ```ts
221
+ import { SDK_VERSION, isSdkCompatible } from '@vivoa/plugin-sdk';
222
+
223
+ // in the host loader:
224
+ if (!isSdkCompatible(plugin.manifest.sdkVersion, SDK_VERSION)) {
225
+ throw new Error('Incompatible plugin SDK version');
226
+ }
227
+ ```
68
228
 
69
229
  ## License
70
230
 
package/dist/index.d.mts CHANGED
@@ -2,6 +2,7 @@ declare const PAYMENT_PLUGIN_TOKEN: "PAYMENT_PLUGINS";
2
2
  declare const SHIPPING_PLUGIN_TOKEN: "SHIPPING_PLUGINS";
3
3
  declare const SUPPLIERS_PLUGIN_TOKEN: "SUPPLIERS_PLUGINS";
4
4
  declare const ANALYTICS_PLUGIN_TOKEN: "ANALYTICS_PLUGINS";
5
+ declare const INVOICING_PLUGIN_TOKEN: "INVOICING_PLUGINS";
5
6
 
6
7
  declare enum FieldType {
7
8
  String = "string",
@@ -310,6 +311,7 @@ declare enum PluginType {
310
311
  Payment = "payment",
311
312
  Shipping = "shipping",
312
313
  Analytics = "analytics",
314
+ Invoicing = "invoicing",
313
315
  Generic = "generic"
314
316
  }
315
317
  /** Visual tone for messages, callouts and action results. */
@@ -473,6 +475,13 @@ interface PaymentResult {
473
475
  redirectUrl?: string;
474
476
  rawResponse?: unknown;
475
477
  }
478
+ /**
479
+ * How the host should render the payment step for this gateway.
480
+ * - `card-in` host-owned card form, charged via `processPayment` (default).
481
+ * - `offsite-redirect` host sends the shopper to `redirectUrl`.
482
+ * - `embed` gateway-owned iframe initialised via `createPaymentSession`.
483
+ */
484
+ type PaymentRenderMode = 'card-in' | 'offsite-redirect' | 'embed';
476
485
  interface GatewayStaticConfig {
477
486
  code: PaymentGatewayCode;
478
487
  displayName: string;
@@ -480,6 +489,53 @@ interface GatewayStaticConfig {
480
489
  environment: GatewayEnvironment;
481
490
  supportedMethods: string[];
482
491
  requiredEnvVars: string[];
492
+ /**
493
+ * OPTIONAL render mode. Absent ⇒ host treats the gateway as `'card-in'`.
494
+ * Back-compat: existing card-in plugins (Wompi/Serfinsa) omit this field.
495
+ */
496
+ renderMode?: PaymentRenderMode;
497
+ }
498
+ /**
499
+ * Cardless payload for creating a gateway-hosted payment session (INV-1).
500
+ * Used by `embed` / `offsite-redirect` gateways where the host never touches
501
+ * card data — the shopper enters it inside the gateway's own surface.
502
+ */
503
+ interface PaymentSessionPayload {
504
+ /**
505
+ * Charge amount in DECIMAL major units, 2 decimal places (e.g. `12.34`).
506
+ * Matches Boxful `@boxful/contracts` `getTwoDecimals` / `toFixed(2)`.
507
+ */
508
+ amount: number;
509
+ currency: string;
510
+ orderId: string;
511
+ customer: PaymentCustomer;
512
+ /** Optional display/reconciliation hints shown on the gateway surface. */
513
+ orderSummary?: {
514
+ description?: string;
515
+ merchant?: string;
516
+ reference?: string;
517
+ };
518
+ }
519
+ /**
520
+ * Everything the host needs to mount a gateway-owned payment iframe.
521
+ * `sessionToken` is OPAQUE to the host; the amount is sealed server-side by the
522
+ * gateway, so the host cannot tamper with it.
523
+ */
524
+ interface EmbedInit {
525
+ sessionToken: string;
526
+ iframeUrl: string;
527
+ allowedOrigins: string[];
528
+ /** Expiry as epoch SECONDS. Owner TTL guidance: 15 minutes. */
529
+ expiresAt?: number;
530
+ }
531
+ /**
532
+ * Result of `createPaymentSession`. `embedInit` is present iff
533
+ * `renderMode === 'embed'`; `redirectUrl` iff `renderMode === 'offsite-redirect'`.
534
+ */
535
+ interface PaymentSessionResult {
536
+ renderMode: PaymentRenderMode;
537
+ embedInit?: EmbedInit;
538
+ redirectUrl?: string;
483
539
  }
484
540
  interface PaymentPluginConfig {
485
541
  configSchema: PluginConfigField[];
@@ -505,6 +561,13 @@ interface IPaymentPlugin extends IPlugin {
505
561
  queryTransaction?(ref: {
506
562
  transactionId: string;
507
563
  }, ctx: DispatchContext): Promise<PaymentResult>;
564
+ /**
565
+ * Create a gateway-hosted payment session for `embed` / `offsite-redirect`
566
+ * render modes. OPTIONAL — `card-in` plugins never implement it and charge
567
+ * via `processPayment` instead. STATELESS: gateway credentials arrive per
568
+ * call via `ctx.config` (INV-4); no card data is ever passed here (INV-1).
569
+ */
570
+ createPaymentSession?(payload: PaymentSessionPayload, ctx: DispatchContext): Promise<PaymentSessionResult>;
508
571
  }
509
572
 
510
573
  declare enum ShippingFeature {
@@ -1012,6 +1075,221 @@ interface IAnalyticsPlugin extends IPlugin {
1012
1075
  isConfigured?(ctx: DispatchContext): boolean;
1013
1076
  }
1014
1077
 
1078
+ declare enum InvoicingFeature {
1079
+ /** Emit a fiscal document against the authority. */
1080
+ Issue = "issue",
1081
+ /** Invalidate / annul a previously issued document. */
1082
+ Void = "void",
1083
+ /** Query the current authority status of an issued document. */
1084
+ StatusQuery = "status-query",
1085
+ /** Retrieve the rendered PDF of an issued document. */
1086
+ Pdf = "pdf"
1087
+ }
1088
+ /**
1089
+ * Generic fiscal document types. The adapter maps each to its national catalog
1090
+ * (e.g. SV MH: Invoice→Factura Consumidor Final "01", CreditInvoice→Comprobante
1091
+ * de Crédito Fiscal "03", ExcludedSubject→Factura Sujeto Excluido "14", ...).
1092
+ */
1093
+ declare enum InvoiceDocumentType {
1094
+ /** Final-consumer invoice. */
1095
+ Invoice = "invoice",
1096
+ /** Tax-credit document for registered taxpayers (SV CCF). */
1097
+ CreditInvoice = "credit-invoice",
1098
+ /** Credit note against a prior document. */
1099
+ CreditNote = "credit-note",
1100
+ /** Debit note against a prior document. */
1101
+ DebitNote = "debit-note",
1102
+ /** Document for suppliers not registered as taxpayers (SV Sujeto Excluido). */
1103
+ ExcludedSubject = "excluded-subject",
1104
+ /** Export invoice. */
1105
+ Export = "export"
1106
+ }
1107
+ /**
1108
+ * Authority status of an issued document. `unknown` is a first-class value for
1109
+ * provider states the adapter does not map — the host treats it as "not yet
1110
+ * resolved" instead of guessing.
1111
+ */
1112
+ declare enum InvoiceStatus {
1113
+ /** Submitted, awaiting the authority's acceptance. */
1114
+ Pending = "pending",
1115
+ /** Accepted and sealed by the authority. */
1116
+ Accepted = "accepted",
1117
+ /** Rejected by the authority (see statusDescription for the reason). */
1118
+ Rejected = "rejected",
1119
+ /** Previously accepted, later invalidated/annulled. */
1120
+ Voided = "voided",
1121
+ Unknown = "unknown"
1122
+ }
1123
+ /**
1124
+ * ISO-4217 money in minor units — mirrors the store's Money VO so the host maps
1125
+ * 1:1 without a currency guess. Kept local so the SDK stays dependency-free.
1126
+ */
1127
+ interface InvoiceMoney {
1128
+ amountMinor: number;
1129
+ currency: string;
1130
+ }
1131
+ /**
1132
+ * A party to the document (issuer or recipient). Fields are generic; the adapter
1133
+ * maps `taxId` to the national identifier it needs (NIT/NRC/DUI in SV, RFC in
1134
+ * MX). Most are optional because a final-consumer invoice needs far less than a
1135
+ * tax-credit document.
1136
+ */
1137
+ interface InvoiceParty {
1138
+ /** Legal / trade name of the party. */
1139
+ name: string;
1140
+ /** National tax identifier (SV NIT, MX RFC, ...). */
1141
+ taxId?: string | null;
1142
+ /** Secondary fiscal registry id where the country splits them (SV NRC). */
1143
+ taxRegistryId?: string | null;
1144
+ /** Personal id when the party is a natural person (SV DUI). */
1145
+ personalId?: string | null;
1146
+ email?: string | null;
1147
+ phone?: string | null;
1148
+ address?: string | null;
1149
+ city?: string | null;
1150
+ state?: string | null;
1151
+ country?: string | null;
1152
+ /** Economic-activity code where the authority requires it. */
1153
+ activityCode?: string | null;
1154
+ activityDescription?: string | null;
1155
+ }
1156
+ /** A tax applied to a line or to the whole document. */
1157
+ interface InvoiceTax {
1158
+ /** Generic code (adapter maps to the national tax code, e.g. SV IVA "20"). */
1159
+ code: string;
1160
+ description?: string;
1161
+ /** Rate as a fraction (0.13 for 13% IVA), when the tax is rate-based. */
1162
+ rate?: number;
1163
+ amount: InvoiceMoney;
1164
+ }
1165
+ /** A single line item of the document. */
1166
+ interface InvoiceLine {
1167
+ /** Store product id, for traceability back to the catalog. */
1168
+ productId?: string | null;
1169
+ variantId?: string | null;
1170
+ sku?: string | null;
1171
+ description: string;
1172
+ quantity: number;
1173
+ /** Unit of measure code where the authority requires it. */
1174
+ unitCode?: string | null;
1175
+ unitPrice: InvoiceMoney;
1176
+ /** Line discount, when any. */
1177
+ discount?: InvoiceMoney;
1178
+ /** Line subtotal (quantity * unitPrice - discount), before document taxes. */
1179
+ subtotal: InvoiceMoney;
1180
+ /** Per-line taxes, when the country computes tax at the line level. */
1181
+ taxes?: InvoiceTax[];
1182
+ }
1183
+ /**
1184
+ * The host builds this from an Order (or a manual admin action) and hands it to
1185
+ * the adapter. Fiscal identifiers are NOT part of the request — the provider
1186
+ * assigns them and returns them on {@link InvoiceResult}.
1187
+ */
1188
+ interface InvoiceRequest {
1189
+ /** Store order id, used by the adapter as the idempotency key. */
1190
+ orderId: string;
1191
+ documentType: InvoiceDocumentType;
1192
+ /** ISO-4217 currency of the whole document. */
1193
+ currency: string;
1194
+ /** The seller — defaults to the store's fiscal identity when omitted by host. */
1195
+ issuer?: InvoiceParty;
1196
+ /** The buyer. */
1197
+ recipient: InvoiceParty;
1198
+ lines: InvoiceLine[];
1199
+ /** Document-level taxes (when the country totals tax at the document level). */
1200
+ taxes?: InvoiceTax[];
1201
+ /** Sum of line subtotals before taxes. */
1202
+ subtotal: InvoiceMoney;
1203
+ /** Total taxes applied. */
1204
+ taxTotal?: InvoiceMoney;
1205
+ /** Grand total the customer pays. */
1206
+ total: InvoiceMoney;
1207
+ /** ISO-8601 instant the sale happened. */
1208
+ issuedAt?: string;
1209
+ /** Free-form notes to print on the document. */
1210
+ notes?: string;
1211
+ /** Provider-specific extras the host cannot model generically. */
1212
+ metadata?: Record<string, unknown>;
1213
+ }
1214
+ /**
1215
+ * Outcome of an issue / void / query. The fiscal identifiers are provider output
1216
+ * — all optional because a Rejected result may carry none of them. `status`
1217
+ * drives the host's control flow; `rawResponse` is for diagnostics only.
1218
+ */
1219
+ interface InvoiceResult {
1220
+ status: InvoiceStatus;
1221
+ /** Authority generation code / UUID (SV "Código de Generación"). */
1222
+ generationCode?: string | null;
1223
+ /** Control number assigned to the document (SV "Número de Control"). */
1224
+ controlNumber?: string | null;
1225
+ /** Authority reception seal confirming validity (SV "Sello de Recepción"). */
1226
+ receptionSeal?: string | null;
1227
+ /** URL to the rendered PDF, when the provider exposes one. */
1228
+ pdfUrl?: string | null;
1229
+ /** URL to the signed JSON artifact, when the provider exposes one. */
1230
+ jsonUrl?: string | null;
1231
+ /** Human-readable authority/provider status, for audit/logging. */
1232
+ statusDescription?: string;
1233
+ /** Untouched provider payload, for diagnostics. Never trusted for control flow. */
1234
+ rawResponse?: Record<string, unknown>;
1235
+ }
1236
+ /** Input to invalidate a previously issued document. */
1237
+ interface VoidInvoiceInput {
1238
+ /** The generation code of the document to invalidate. */
1239
+ generationCode: string;
1240
+ /** Reason for the invalidation, required by most authorities. */
1241
+ reason: string;
1242
+ }
1243
+ interface InvoicingDefaultConfig {
1244
+ global?: Record<string, unknown>;
1245
+ countries?: Record<string, Record<string, unknown>>;
1246
+ }
1247
+ interface InvoicingPluginConfig {
1248
+ supportedCountries: string[];
1249
+ supportedFeatures: InvoicingFeature[];
1250
+ supportedDocumentTypes: InvoiceDocumentType[];
1251
+ configSchema: PluginConfigField[];
1252
+ /** GLOBAL + per-country defaults merged under the tenant DB config by the host. */
1253
+ defaultConfig?: InvoicingDefaultConfig;
1254
+ }
1255
+ interface InvoicingStaticConfig {
1256
+ code: string;
1257
+ displayName: string;
1258
+ description: string;
1259
+ iconUrl?: string;
1260
+ supportedCountries: string[];
1261
+ supportedFeatures: InvoicingFeature[];
1262
+ supportedDocumentTypes: InvoiceDocumentType[];
1263
+ configSchema: PluginConfigField[];
1264
+ }
1265
+ interface IInvoicingPlugin extends IPlugin {
1266
+ readonly name: string;
1267
+ readonly invoicingConfig: InvoicingPluginConfig;
1268
+ /**
1269
+ * Emit a fiscal document against the authority. Stateless: the tenant's
1270
+ * resolved credentials arrive in `ctx.config` on every call. The adapter uses
1271
+ * `req.orderId` as the idempotency key so a retry never double-issues.
1272
+ */
1273
+ issueInvoice(req: InvoiceRequest, ctx: DispatchContext): Promise<InvoiceResult>;
1274
+ /**
1275
+ * Invalidate a previously issued document.
1276
+ * @compat Only plugins advertising the {@link InvoicingFeature.Void} feature.
1277
+ */
1278
+ voidInvoice?(input: VoidInvoiceInput, ctx: DispatchContext): Promise<InvoiceResult>;
1279
+ /**
1280
+ * Query the authority's current status of an issued document.
1281
+ * @compat Only plugins advertising the {@link InvoicingFeature.StatusQuery} feature.
1282
+ */
1283
+ queryStatus?(ref: {
1284
+ generationCode: string;
1285
+ }, ctx: DispatchContext): Promise<InvoiceResult>;
1286
+ /**
1287
+ * Optional readiness probe. Availability = enabled AND isConfigured.
1288
+ * @compat When omitted, the host assumes the adapter is ready.
1289
+ */
1290
+ isConfigured?(ctx: DispatchContext): boolean;
1291
+ }
1292
+
1015
1293
  /** A named unit of behaviour a plugin exposes to the host registry. */
1016
1294
  interface Capability<T = unknown> {
1017
1295
  kind: string;
@@ -1027,6 +1305,7 @@ declare const CapabilityKind: {
1027
1305
  readonly Shipping: "shipping";
1028
1306
  readonly Suppliers: "suppliers";
1029
1307
  readonly Analytics: "analytics";
1308
+ readonly Invoicing: "invoicing";
1030
1309
  };
1031
1310
  type CapabilityKind = (typeof CapabilityKind)[keyof typeof CapabilityKind];
1032
1311
  declare function capability<T>(kind: string, impl: T): Capability<T>;
@@ -1034,6 +1313,7 @@ declare function paymentCapability(impl: IPaymentPlugin): Capability<IPaymentPlu
1034
1313
  declare function shippingCapability(impl: IShippingPlugin): Capability<IShippingPlugin>;
1035
1314
  declare function suppliersCapability(impl: ISuppliersPlugin): Capability<ISuppliersPlugin>;
1036
1315
  declare function analyticsCapability(impl: IAnalyticsPlugin): Capability<IAnalyticsPlugin>;
1316
+ declare function invoicingCapability(impl: IInvoicingPlugin): Capability<IInvoicingPlugin>;
1037
1317
  /**
1038
1318
  * A constructed plugin. `capabilities` is the static declaration the host reads
1039
1319
  * up front; `onActivate` runs when the host mounts the plugin for a tenant and
@@ -1171,7 +1451,7 @@ declare function checkPermissions(required: string[], grantedRaw: string[]): Per
1171
1451
  * - MINOR: additive (new optional fields, new tokens) — backwards compatible.
1172
1452
  * - PATCH: docs/fixes with zero shape changes.
1173
1453
  */
1174
- declare const SDK_VERSION = "0.6.2";
1454
+ declare const SDK_VERSION = "0.6.5";
1175
1455
  /**
1176
1456
  * True when a plugin built against `pluginSdkVersion` can run on a host that
1177
1457
  * ships `hostSdkVersion`. Rule: same major, host minor >= plugin minor.
@@ -1180,4 +1460,4 @@ declare const SDK_VERSION = "0.6.2";
1180
1460
  */
1181
1461
  declare function isSdkCompatible(pluginSdkVersion: string, hostSdkVersion: string): boolean;
1182
1462
 
1183
- export { ANALYTICS_PLUGIN_TOKEN, type AccordionBlock, type AccordionSection, type ActionBlock, ActionVariant, type AnalyticsActionSource, type AnalyticsConsent, type AnalyticsEvent, type AnalyticsEventName, AnalyticsFeature, type AnalyticsItem, type AnalyticsMoney, type AnalyticsPluginConfig, type AnalyticsStaticConfig, type AnalyticsUserData, type AnalyticsUtm, type BannerBlock, type Block, type BlockBase, BlockType, type CalloutBlock, type Capability, CapabilityKind, type CardBlock, type CodConfig, type CodFeeConfig, CodFeeType, type ConditionalBlock, type ConditionalEquals, type ConditionalWhen, ConfigScope, type ConfigurablePlugin, type CopyFieldBlock, type CreateShipmentParams, type DispatchContext, type DividerBlock, type DomainEventHandler, type DomainEventName, type FieldBlock, type FieldDefinition, type FieldDependsOn, type FieldMap, type FieldOption, FieldType, FieldVariant, GatewayEnvironment, type GatewayStaticConfig, type GroupBlock, type HostApi, type HttpClient, type HttpRequest, type HttpResponse, type IAnalyticsPlugin, type IPaymentPlugin, type IPlugin, type IShippingPlugin, type ISuppliersPlugin, type InlineRowBlock, type KeyValueBlock, type KeyValueRow, LayoutMode, type Logger, type MarkdownBlock, MessageVariant, PAYMENT_PLUGIN_TOKEN, type PaymentCard, type PaymentCustomer, type PaymentGatewayCode, type PaymentPayload, type PaymentPluginConfig, type PaymentResult, type PaymentVerifyPayload, type Permission, type PermissionCheck, type PlaceSupplierOrderInput, type Plugin, type PluginActionContext, type PluginActionResult, type PluginConfigField, type PluginConfigFieldDependency, type PluginConfigResult, type PluginConfigValidation, type PluginFactory, type PluginManifest, PluginType, type RepeaterBlock, RepeaterSource, SDK_VERSION, SHIPPING_PLUGIN_TOKEN, SUPPLIERS_PLUGIN_TOKEN, type SecretStore, type SelectOption, type SequenceStore, type SetupAction, type SetupLayout, type SetupLayoutValidation, type SetupStep, type ShipmentAddress, type ShipmentParcel, type ShipmentResult, type ShippingDefaultConfig, ShippingFeature, type ShippingPluginConfig, type ShippingQuote, type ShippingQuoteParams, type ShippingStaticConfig, StepStatusFrom, type StepStatusFromAction, type StepStatusFromFields, type StepStatusSource, type StorageBroker, type SupplierCatalogQuery, type SupplierFulfillmentEvent, type SupplierListing, type SupplierListingAttribute, type SupplierListingPage, type SupplierListingVariant, type SupplierMoney, type SupplierOrderAddressLevel, type SupplierOrderCustomer, type SupplierOrderLine, type SupplierOrderResult, type SupplierOrderStatus, type SupplierShipTo, type SupplierStock, type SuppliersDefaultConfig, SuppliersFeature, type SuppliersPluginConfig, type SuppliersStaticConfig, type TabItem, type TabsBlock, type ToggleBlock, type TrackingEvent, TransactionStatus, type WebhookSignatureResult, analyticsCapability, capability, checkPermissions, createPluginConfig, crossValidateSetupLayout, definePlugin, field, isConfigurablePlugin, isPermissionGranted, isPluginFactory, isSdkCompatible, parsePermission, paymentCapability, shippingCapability, suppliersCapability, validateSetupLayout };
1463
+ export { ANALYTICS_PLUGIN_TOKEN, type AccordionBlock, type AccordionSection, type ActionBlock, ActionVariant, type AnalyticsActionSource, type AnalyticsConsent, type AnalyticsEvent, type AnalyticsEventName, AnalyticsFeature, type AnalyticsItem, type AnalyticsMoney, type AnalyticsPluginConfig, type AnalyticsStaticConfig, type AnalyticsUserData, type AnalyticsUtm, type BannerBlock, type Block, type BlockBase, BlockType, type CalloutBlock, type Capability, CapabilityKind, type CardBlock, type CodConfig, type CodFeeConfig, CodFeeType, type ConditionalBlock, type ConditionalEquals, type ConditionalWhen, ConfigScope, type ConfigurablePlugin, type CopyFieldBlock, type CreateShipmentParams, type DispatchContext, type DividerBlock, type DomainEventHandler, type DomainEventName, type EmbedInit, type FieldBlock, type FieldDefinition, type FieldDependsOn, type FieldMap, type FieldOption, FieldType, FieldVariant, GatewayEnvironment, type GatewayStaticConfig, type GroupBlock, type HostApi, type HttpClient, type HttpRequest, type HttpResponse, type IAnalyticsPlugin, type IInvoicingPlugin, INVOICING_PLUGIN_TOKEN, type IPaymentPlugin, type IPlugin, type IShippingPlugin, type ISuppliersPlugin, type InlineRowBlock, InvoiceDocumentType, type InvoiceLine, type InvoiceMoney, type InvoiceParty, type InvoiceRequest, type InvoiceResult, InvoiceStatus, type InvoiceTax, type InvoicingDefaultConfig, InvoicingFeature, type InvoicingPluginConfig, type InvoicingStaticConfig, type KeyValueBlock, type KeyValueRow, LayoutMode, type Logger, type MarkdownBlock, MessageVariant, PAYMENT_PLUGIN_TOKEN, type PaymentCard, type PaymentCustomer, type PaymentGatewayCode, type PaymentPayload, type PaymentPluginConfig, type PaymentRenderMode, type PaymentResult, type PaymentSessionPayload, type PaymentSessionResult, type PaymentVerifyPayload, type Permission, type PermissionCheck, type PlaceSupplierOrderInput, type Plugin, type PluginActionContext, type PluginActionResult, type PluginConfigField, type PluginConfigFieldDependency, type PluginConfigResult, type PluginConfigValidation, type PluginFactory, type PluginManifest, PluginType, type RepeaterBlock, RepeaterSource, SDK_VERSION, SHIPPING_PLUGIN_TOKEN, SUPPLIERS_PLUGIN_TOKEN, type SecretStore, type SelectOption, type SequenceStore, type SetupAction, type SetupLayout, type SetupLayoutValidation, type SetupStep, type ShipmentAddress, type ShipmentParcel, type ShipmentResult, type ShippingDefaultConfig, ShippingFeature, type ShippingPluginConfig, type ShippingQuote, type ShippingQuoteParams, type ShippingStaticConfig, StepStatusFrom, type StepStatusFromAction, type StepStatusFromFields, type StepStatusSource, type StorageBroker, type SupplierCatalogQuery, type SupplierFulfillmentEvent, type SupplierListing, type SupplierListingAttribute, type SupplierListingPage, type SupplierListingVariant, type SupplierMoney, type SupplierOrderAddressLevel, type SupplierOrderCustomer, type SupplierOrderLine, type SupplierOrderResult, type SupplierOrderStatus, type SupplierShipTo, type SupplierStock, type SuppliersDefaultConfig, SuppliersFeature, type SuppliersPluginConfig, type SuppliersStaticConfig, type TabItem, type TabsBlock, type ToggleBlock, type TrackingEvent, TransactionStatus, type VoidInvoiceInput, type WebhookSignatureResult, analyticsCapability, capability, checkPermissions, createPluginConfig, crossValidateSetupLayout, definePlugin, field, invoicingCapability, isConfigurablePlugin, isPermissionGranted, isPluginFactory, isSdkCompatible, parsePermission, paymentCapability, shippingCapability, suppliersCapability, validateSetupLayout };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ declare const PAYMENT_PLUGIN_TOKEN: "PAYMENT_PLUGINS";
2
2
  declare const SHIPPING_PLUGIN_TOKEN: "SHIPPING_PLUGINS";
3
3
  declare const SUPPLIERS_PLUGIN_TOKEN: "SUPPLIERS_PLUGINS";
4
4
  declare const ANALYTICS_PLUGIN_TOKEN: "ANALYTICS_PLUGINS";
5
+ declare const INVOICING_PLUGIN_TOKEN: "INVOICING_PLUGINS";
5
6
 
6
7
  declare enum FieldType {
7
8
  String = "string",
@@ -310,6 +311,7 @@ declare enum PluginType {
310
311
  Payment = "payment",
311
312
  Shipping = "shipping",
312
313
  Analytics = "analytics",
314
+ Invoicing = "invoicing",
313
315
  Generic = "generic"
314
316
  }
315
317
  /** Visual tone for messages, callouts and action results. */
@@ -473,6 +475,13 @@ interface PaymentResult {
473
475
  redirectUrl?: string;
474
476
  rawResponse?: unknown;
475
477
  }
478
+ /**
479
+ * How the host should render the payment step for this gateway.
480
+ * - `card-in` host-owned card form, charged via `processPayment` (default).
481
+ * - `offsite-redirect` host sends the shopper to `redirectUrl`.
482
+ * - `embed` gateway-owned iframe initialised via `createPaymentSession`.
483
+ */
484
+ type PaymentRenderMode = 'card-in' | 'offsite-redirect' | 'embed';
476
485
  interface GatewayStaticConfig {
477
486
  code: PaymentGatewayCode;
478
487
  displayName: string;
@@ -480,6 +489,53 @@ interface GatewayStaticConfig {
480
489
  environment: GatewayEnvironment;
481
490
  supportedMethods: string[];
482
491
  requiredEnvVars: string[];
492
+ /**
493
+ * OPTIONAL render mode. Absent ⇒ host treats the gateway as `'card-in'`.
494
+ * Back-compat: existing card-in plugins (Wompi/Serfinsa) omit this field.
495
+ */
496
+ renderMode?: PaymentRenderMode;
497
+ }
498
+ /**
499
+ * Cardless payload for creating a gateway-hosted payment session (INV-1).
500
+ * Used by `embed` / `offsite-redirect` gateways where the host never touches
501
+ * card data — the shopper enters it inside the gateway's own surface.
502
+ */
503
+ interface PaymentSessionPayload {
504
+ /**
505
+ * Charge amount in DECIMAL major units, 2 decimal places (e.g. `12.34`).
506
+ * Matches Boxful `@boxful/contracts` `getTwoDecimals` / `toFixed(2)`.
507
+ */
508
+ amount: number;
509
+ currency: string;
510
+ orderId: string;
511
+ customer: PaymentCustomer;
512
+ /** Optional display/reconciliation hints shown on the gateway surface. */
513
+ orderSummary?: {
514
+ description?: string;
515
+ merchant?: string;
516
+ reference?: string;
517
+ };
518
+ }
519
+ /**
520
+ * Everything the host needs to mount a gateway-owned payment iframe.
521
+ * `sessionToken` is OPAQUE to the host; the amount is sealed server-side by the
522
+ * gateway, so the host cannot tamper with it.
523
+ */
524
+ interface EmbedInit {
525
+ sessionToken: string;
526
+ iframeUrl: string;
527
+ allowedOrigins: string[];
528
+ /** Expiry as epoch SECONDS. Owner TTL guidance: 15 minutes. */
529
+ expiresAt?: number;
530
+ }
531
+ /**
532
+ * Result of `createPaymentSession`. `embedInit` is present iff
533
+ * `renderMode === 'embed'`; `redirectUrl` iff `renderMode === 'offsite-redirect'`.
534
+ */
535
+ interface PaymentSessionResult {
536
+ renderMode: PaymentRenderMode;
537
+ embedInit?: EmbedInit;
538
+ redirectUrl?: string;
483
539
  }
484
540
  interface PaymentPluginConfig {
485
541
  configSchema: PluginConfigField[];
@@ -505,6 +561,13 @@ interface IPaymentPlugin extends IPlugin {
505
561
  queryTransaction?(ref: {
506
562
  transactionId: string;
507
563
  }, ctx: DispatchContext): Promise<PaymentResult>;
564
+ /**
565
+ * Create a gateway-hosted payment session for `embed` / `offsite-redirect`
566
+ * render modes. OPTIONAL — `card-in` plugins never implement it and charge
567
+ * via `processPayment` instead. STATELESS: gateway credentials arrive per
568
+ * call via `ctx.config` (INV-4); no card data is ever passed here (INV-1).
569
+ */
570
+ createPaymentSession?(payload: PaymentSessionPayload, ctx: DispatchContext): Promise<PaymentSessionResult>;
508
571
  }
509
572
 
510
573
  declare enum ShippingFeature {
@@ -1012,6 +1075,221 @@ interface IAnalyticsPlugin extends IPlugin {
1012
1075
  isConfigured?(ctx: DispatchContext): boolean;
1013
1076
  }
1014
1077
 
1078
+ declare enum InvoicingFeature {
1079
+ /** Emit a fiscal document against the authority. */
1080
+ Issue = "issue",
1081
+ /** Invalidate / annul a previously issued document. */
1082
+ Void = "void",
1083
+ /** Query the current authority status of an issued document. */
1084
+ StatusQuery = "status-query",
1085
+ /** Retrieve the rendered PDF of an issued document. */
1086
+ Pdf = "pdf"
1087
+ }
1088
+ /**
1089
+ * Generic fiscal document types. The adapter maps each to its national catalog
1090
+ * (e.g. SV MH: Invoice→Factura Consumidor Final "01", CreditInvoice→Comprobante
1091
+ * de Crédito Fiscal "03", ExcludedSubject→Factura Sujeto Excluido "14", ...).
1092
+ */
1093
+ declare enum InvoiceDocumentType {
1094
+ /** Final-consumer invoice. */
1095
+ Invoice = "invoice",
1096
+ /** Tax-credit document for registered taxpayers (SV CCF). */
1097
+ CreditInvoice = "credit-invoice",
1098
+ /** Credit note against a prior document. */
1099
+ CreditNote = "credit-note",
1100
+ /** Debit note against a prior document. */
1101
+ DebitNote = "debit-note",
1102
+ /** Document for suppliers not registered as taxpayers (SV Sujeto Excluido). */
1103
+ ExcludedSubject = "excluded-subject",
1104
+ /** Export invoice. */
1105
+ Export = "export"
1106
+ }
1107
+ /**
1108
+ * Authority status of an issued document. `unknown` is a first-class value for
1109
+ * provider states the adapter does not map — the host treats it as "not yet
1110
+ * resolved" instead of guessing.
1111
+ */
1112
+ declare enum InvoiceStatus {
1113
+ /** Submitted, awaiting the authority's acceptance. */
1114
+ Pending = "pending",
1115
+ /** Accepted and sealed by the authority. */
1116
+ Accepted = "accepted",
1117
+ /** Rejected by the authority (see statusDescription for the reason). */
1118
+ Rejected = "rejected",
1119
+ /** Previously accepted, later invalidated/annulled. */
1120
+ Voided = "voided",
1121
+ Unknown = "unknown"
1122
+ }
1123
+ /**
1124
+ * ISO-4217 money in minor units — mirrors the store's Money VO so the host maps
1125
+ * 1:1 without a currency guess. Kept local so the SDK stays dependency-free.
1126
+ */
1127
+ interface InvoiceMoney {
1128
+ amountMinor: number;
1129
+ currency: string;
1130
+ }
1131
+ /**
1132
+ * A party to the document (issuer or recipient). Fields are generic; the adapter
1133
+ * maps `taxId` to the national identifier it needs (NIT/NRC/DUI in SV, RFC in
1134
+ * MX). Most are optional because a final-consumer invoice needs far less than a
1135
+ * tax-credit document.
1136
+ */
1137
+ interface InvoiceParty {
1138
+ /** Legal / trade name of the party. */
1139
+ name: string;
1140
+ /** National tax identifier (SV NIT, MX RFC, ...). */
1141
+ taxId?: string | null;
1142
+ /** Secondary fiscal registry id where the country splits them (SV NRC). */
1143
+ taxRegistryId?: string | null;
1144
+ /** Personal id when the party is a natural person (SV DUI). */
1145
+ personalId?: string | null;
1146
+ email?: string | null;
1147
+ phone?: string | null;
1148
+ address?: string | null;
1149
+ city?: string | null;
1150
+ state?: string | null;
1151
+ country?: string | null;
1152
+ /** Economic-activity code where the authority requires it. */
1153
+ activityCode?: string | null;
1154
+ activityDescription?: string | null;
1155
+ }
1156
+ /** A tax applied to a line or to the whole document. */
1157
+ interface InvoiceTax {
1158
+ /** Generic code (adapter maps to the national tax code, e.g. SV IVA "20"). */
1159
+ code: string;
1160
+ description?: string;
1161
+ /** Rate as a fraction (0.13 for 13% IVA), when the tax is rate-based. */
1162
+ rate?: number;
1163
+ amount: InvoiceMoney;
1164
+ }
1165
+ /** A single line item of the document. */
1166
+ interface InvoiceLine {
1167
+ /** Store product id, for traceability back to the catalog. */
1168
+ productId?: string | null;
1169
+ variantId?: string | null;
1170
+ sku?: string | null;
1171
+ description: string;
1172
+ quantity: number;
1173
+ /** Unit of measure code where the authority requires it. */
1174
+ unitCode?: string | null;
1175
+ unitPrice: InvoiceMoney;
1176
+ /** Line discount, when any. */
1177
+ discount?: InvoiceMoney;
1178
+ /** Line subtotal (quantity * unitPrice - discount), before document taxes. */
1179
+ subtotal: InvoiceMoney;
1180
+ /** Per-line taxes, when the country computes tax at the line level. */
1181
+ taxes?: InvoiceTax[];
1182
+ }
1183
+ /**
1184
+ * The host builds this from an Order (or a manual admin action) and hands it to
1185
+ * the adapter. Fiscal identifiers are NOT part of the request — the provider
1186
+ * assigns them and returns them on {@link InvoiceResult}.
1187
+ */
1188
+ interface InvoiceRequest {
1189
+ /** Store order id, used by the adapter as the idempotency key. */
1190
+ orderId: string;
1191
+ documentType: InvoiceDocumentType;
1192
+ /** ISO-4217 currency of the whole document. */
1193
+ currency: string;
1194
+ /** The seller — defaults to the store's fiscal identity when omitted by host. */
1195
+ issuer?: InvoiceParty;
1196
+ /** The buyer. */
1197
+ recipient: InvoiceParty;
1198
+ lines: InvoiceLine[];
1199
+ /** Document-level taxes (when the country totals tax at the document level). */
1200
+ taxes?: InvoiceTax[];
1201
+ /** Sum of line subtotals before taxes. */
1202
+ subtotal: InvoiceMoney;
1203
+ /** Total taxes applied. */
1204
+ taxTotal?: InvoiceMoney;
1205
+ /** Grand total the customer pays. */
1206
+ total: InvoiceMoney;
1207
+ /** ISO-8601 instant the sale happened. */
1208
+ issuedAt?: string;
1209
+ /** Free-form notes to print on the document. */
1210
+ notes?: string;
1211
+ /** Provider-specific extras the host cannot model generically. */
1212
+ metadata?: Record<string, unknown>;
1213
+ }
1214
+ /**
1215
+ * Outcome of an issue / void / query. The fiscal identifiers are provider output
1216
+ * — all optional because a Rejected result may carry none of them. `status`
1217
+ * drives the host's control flow; `rawResponse` is for diagnostics only.
1218
+ */
1219
+ interface InvoiceResult {
1220
+ status: InvoiceStatus;
1221
+ /** Authority generation code / UUID (SV "Código de Generación"). */
1222
+ generationCode?: string | null;
1223
+ /** Control number assigned to the document (SV "Número de Control"). */
1224
+ controlNumber?: string | null;
1225
+ /** Authority reception seal confirming validity (SV "Sello de Recepción"). */
1226
+ receptionSeal?: string | null;
1227
+ /** URL to the rendered PDF, when the provider exposes one. */
1228
+ pdfUrl?: string | null;
1229
+ /** URL to the signed JSON artifact, when the provider exposes one. */
1230
+ jsonUrl?: string | null;
1231
+ /** Human-readable authority/provider status, for audit/logging. */
1232
+ statusDescription?: string;
1233
+ /** Untouched provider payload, for diagnostics. Never trusted for control flow. */
1234
+ rawResponse?: Record<string, unknown>;
1235
+ }
1236
+ /** Input to invalidate a previously issued document. */
1237
+ interface VoidInvoiceInput {
1238
+ /** The generation code of the document to invalidate. */
1239
+ generationCode: string;
1240
+ /** Reason for the invalidation, required by most authorities. */
1241
+ reason: string;
1242
+ }
1243
+ interface InvoicingDefaultConfig {
1244
+ global?: Record<string, unknown>;
1245
+ countries?: Record<string, Record<string, unknown>>;
1246
+ }
1247
+ interface InvoicingPluginConfig {
1248
+ supportedCountries: string[];
1249
+ supportedFeatures: InvoicingFeature[];
1250
+ supportedDocumentTypes: InvoiceDocumentType[];
1251
+ configSchema: PluginConfigField[];
1252
+ /** GLOBAL + per-country defaults merged under the tenant DB config by the host. */
1253
+ defaultConfig?: InvoicingDefaultConfig;
1254
+ }
1255
+ interface InvoicingStaticConfig {
1256
+ code: string;
1257
+ displayName: string;
1258
+ description: string;
1259
+ iconUrl?: string;
1260
+ supportedCountries: string[];
1261
+ supportedFeatures: InvoicingFeature[];
1262
+ supportedDocumentTypes: InvoiceDocumentType[];
1263
+ configSchema: PluginConfigField[];
1264
+ }
1265
+ interface IInvoicingPlugin extends IPlugin {
1266
+ readonly name: string;
1267
+ readonly invoicingConfig: InvoicingPluginConfig;
1268
+ /**
1269
+ * Emit a fiscal document against the authority. Stateless: the tenant's
1270
+ * resolved credentials arrive in `ctx.config` on every call. The adapter uses
1271
+ * `req.orderId` as the idempotency key so a retry never double-issues.
1272
+ */
1273
+ issueInvoice(req: InvoiceRequest, ctx: DispatchContext): Promise<InvoiceResult>;
1274
+ /**
1275
+ * Invalidate a previously issued document.
1276
+ * @compat Only plugins advertising the {@link InvoicingFeature.Void} feature.
1277
+ */
1278
+ voidInvoice?(input: VoidInvoiceInput, ctx: DispatchContext): Promise<InvoiceResult>;
1279
+ /**
1280
+ * Query the authority's current status of an issued document.
1281
+ * @compat Only plugins advertising the {@link InvoicingFeature.StatusQuery} feature.
1282
+ */
1283
+ queryStatus?(ref: {
1284
+ generationCode: string;
1285
+ }, ctx: DispatchContext): Promise<InvoiceResult>;
1286
+ /**
1287
+ * Optional readiness probe. Availability = enabled AND isConfigured.
1288
+ * @compat When omitted, the host assumes the adapter is ready.
1289
+ */
1290
+ isConfigured?(ctx: DispatchContext): boolean;
1291
+ }
1292
+
1015
1293
  /** A named unit of behaviour a plugin exposes to the host registry. */
1016
1294
  interface Capability<T = unknown> {
1017
1295
  kind: string;
@@ -1027,6 +1305,7 @@ declare const CapabilityKind: {
1027
1305
  readonly Shipping: "shipping";
1028
1306
  readonly Suppliers: "suppliers";
1029
1307
  readonly Analytics: "analytics";
1308
+ readonly Invoicing: "invoicing";
1030
1309
  };
1031
1310
  type CapabilityKind = (typeof CapabilityKind)[keyof typeof CapabilityKind];
1032
1311
  declare function capability<T>(kind: string, impl: T): Capability<T>;
@@ -1034,6 +1313,7 @@ declare function paymentCapability(impl: IPaymentPlugin): Capability<IPaymentPlu
1034
1313
  declare function shippingCapability(impl: IShippingPlugin): Capability<IShippingPlugin>;
1035
1314
  declare function suppliersCapability(impl: ISuppliersPlugin): Capability<ISuppliersPlugin>;
1036
1315
  declare function analyticsCapability(impl: IAnalyticsPlugin): Capability<IAnalyticsPlugin>;
1316
+ declare function invoicingCapability(impl: IInvoicingPlugin): Capability<IInvoicingPlugin>;
1037
1317
  /**
1038
1318
  * A constructed plugin. `capabilities` is the static declaration the host reads
1039
1319
  * up front; `onActivate` runs when the host mounts the plugin for a tenant and
@@ -1171,7 +1451,7 @@ declare function checkPermissions(required: string[], grantedRaw: string[]): Per
1171
1451
  * - MINOR: additive (new optional fields, new tokens) — backwards compatible.
1172
1452
  * - PATCH: docs/fixes with zero shape changes.
1173
1453
  */
1174
- declare const SDK_VERSION = "0.6.2";
1454
+ declare const SDK_VERSION = "0.6.5";
1175
1455
  /**
1176
1456
  * True when a plugin built against `pluginSdkVersion` can run on a host that
1177
1457
  * ships `hostSdkVersion`. Rule: same major, host minor >= plugin minor.
@@ -1180,4 +1460,4 @@ declare const SDK_VERSION = "0.6.2";
1180
1460
  */
1181
1461
  declare function isSdkCompatible(pluginSdkVersion: string, hostSdkVersion: string): boolean;
1182
1462
 
1183
- export { ANALYTICS_PLUGIN_TOKEN, type AccordionBlock, type AccordionSection, type ActionBlock, ActionVariant, type AnalyticsActionSource, type AnalyticsConsent, type AnalyticsEvent, type AnalyticsEventName, AnalyticsFeature, type AnalyticsItem, type AnalyticsMoney, type AnalyticsPluginConfig, type AnalyticsStaticConfig, type AnalyticsUserData, type AnalyticsUtm, type BannerBlock, type Block, type BlockBase, BlockType, type CalloutBlock, type Capability, CapabilityKind, type CardBlock, type CodConfig, type CodFeeConfig, CodFeeType, type ConditionalBlock, type ConditionalEquals, type ConditionalWhen, ConfigScope, type ConfigurablePlugin, type CopyFieldBlock, type CreateShipmentParams, type DispatchContext, type DividerBlock, type DomainEventHandler, type DomainEventName, type FieldBlock, type FieldDefinition, type FieldDependsOn, type FieldMap, type FieldOption, FieldType, FieldVariant, GatewayEnvironment, type GatewayStaticConfig, type GroupBlock, type HostApi, type HttpClient, type HttpRequest, type HttpResponse, type IAnalyticsPlugin, type IPaymentPlugin, type IPlugin, type IShippingPlugin, type ISuppliersPlugin, type InlineRowBlock, type KeyValueBlock, type KeyValueRow, LayoutMode, type Logger, type MarkdownBlock, MessageVariant, PAYMENT_PLUGIN_TOKEN, type PaymentCard, type PaymentCustomer, type PaymentGatewayCode, type PaymentPayload, type PaymentPluginConfig, type PaymentResult, type PaymentVerifyPayload, type Permission, type PermissionCheck, type PlaceSupplierOrderInput, type Plugin, type PluginActionContext, type PluginActionResult, type PluginConfigField, type PluginConfigFieldDependency, type PluginConfigResult, type PluginConfigValidation, type PluginFactory, type PluginManifest, PluginType, type RepeaterBlock, RepeaterSource, SDK_VERSION, SHIPPING_PLUGIN_TOKEN, SUPPLIERS_PLUGIN_TOKEN, type SecretStore, type SelectOption, type SequenceStore, type SetupAction, type SetupLayout, type SetupLayoutValidation, type SetupStep, type ShipmentAddress, type ShipmentParcel, type ShipmentResult, type ShippingDefaultConfig, ShippingFeature, type ShippingPluginConfig, type ShippingQuote, type ShippingQuoteParams, type ShippingStaticConfig, StepStatusFrom, type StepStatusFromAction, type StepStatusFromFields, type StepStatusSource, type StorageBroker, type SupplierCatalogQuery, type SupplierFulfillmentEvent, type SupplierListing, type SupplierListingAttribute, type SupplierListingPage, type SupplierListingVariant, type SupplierMoney, type SupplierOrderAddressLevel, type SupplierOrderCustomer, type SupplierOrderLine, type SupplierOrderResult, type SupplierOrderStatus, type SupplierShipTo, type SupplierStock, type SuppliersDefaultConfig, SuppliersFeature, type SuppliersPluginConfig, type SuppliersStaticConfig, type TabItem, type TabsBlock, type ToggleBlock, type TrackingEvent, TransactionStatus, type WebhookSignatureResult, analyticsCapability, capability, checkPermissions, createPluginConfig, crossValidateSetupLayout, definePlugin, field, isConfigurablePlugin, isPermissionGranted, isPluginFactory, isSdkCompatible, parsePermission, paymentCapability, shippingCapability, suppliersCapability, validateSetupLayout };
1463
+ export { ANALYTICS_PLUGIN_TOKEN, type AccordionBlock, type AccordionSection, type ActionBlock, ActionVariant, type AnalyticsActionSource, type AnalyticsConsent, type AnalyticsEvent, type AnalyticsEventName, AnalyticsFeature, type AnalyticsItem, type AnalyticsMoney, type AnalyticsPluginConfig, type AnalyticsStaticConfig, type AnalyticsUserData, type AnalyticsUtm, type BannerBlock, type Block, type BlockBase, BlockType, type CalloutBlock, type Capability, CapabilityKind, type CardBlock, type CodConfig, type CodFeeConfig, CodFeeType, type ConditionalBlock, type ConditionalEquals, type ConditionalWhen, ConfigScope, type ConfigurablePlugin, type CopyFieldBlock, type CreateShipmentParams, type DispatchContext, type DividerBlock, type DomainEventHandler, type DomainEventName, type EmbedInit, type FieldBlock, type FieldDefinition, type FieldDependsOn, type FieldMap, type FieldOption, FieldType, FieldVariant, GatewayEnvironment, type GatewayStaticConfig, type GroupBlock, type HostApi, type HttpClient, type HttpRequest, type HttpResponse, type IAnalyticsPlugin, type IInvoicingPlugin, INVOICING_PLUGIN_TOKEN, type IPaymentPlugin, type IPlugin, type IShippingPlugin, type ISuppliersPlugin, type InlineRowBlock, InvoiceDocumentType, type InvoiceLine, type InvoiceMoney, type InvoiceParty, type InvoiceRequest, type InvoiceResult, InvoiceStatus, type InvoiceTax, type InvoicingDefaultConfig, InvoicingFeature, type InvoicingPluginConfig, type InvoicingStaticConfig, type KeyValueBlock, type KeyValueRow, LayoutMode, type Logger, type MarkdownBlock, MessageVariant, PAYMENT_PLUGIN_TOKEN, type PaymentCard, type PaymentCustomer, type PaymentGatewayCode, type PaymentPayload, type PaymentPluginConfig, type PaymentRenderMode, type PaymentResult, type PaymentSessionPayload, type PaymentSessionResult, type PaymentVerifyPayload, type Permission, type PermissionCheck, type PlaceSupplierOrderInput, type Plugin, type PluginActionContext, type PluginActionResult, type PluginConfigField, type PluginConfigFieldDependency, type PluginConfigResult, type PluginConfigValidation, type PluginFactory, type PluginManifest, PluginType, type RepeaterBlock, RepeaterSource, SDK_VERSION, SHIPPING_PLUGIN_TOKEN, SUPPLIERS_PLUGIN_TOKEN, type SecretStore, type SelectOption, type SequenceStore, type SetupAction, type SetupLayout, type SetupLayoutValidation, type SetupStep, type ShipmentAddress, type ShipmentParcel, type ShipmentResult, type ShippingDefaultConfig, ShippingFeature, type ShippingPluginConfig, type ShippingQuote, type ShippingQuoteParams, type ShippingStaticConfig, StepStatusFrom, type StepStatusFromAction, type StepStatusFromFields, type StepStatusSource, type StorageBroker, type SupplierCatalogQuery, type SupplierFulfillmentEvent, type SupplierListing, type SupplierListingAttribute, type SupplierListingPage, type SupplierListingVariant, type SupplierMoney, type SupplierOrderAddressLevel, type SupplierOrderCustomer, type SupplierOrderLine, type SupplierOrderResult, type SupplierOrderStatus, type SupplierShipTo, type SupplierStock, type SuppliersDefaultConfig, SuppliersFeature, type SuppliersPluginConfig, type SuppliersStaticConfig, type TabItem, type TabsBlock, type ToggleBlock, type TrackingEvent, TransactionStatus, type VoidInvoiceInput, type WebhookSignatureResult, analyticsCapability, capability, checkPermissions, createPluginConfig, crossValidateSetupLayout, definePlugin, field, invoicingCapability, isConfigurablePlugin, isPermissionGranted, isPluginFactory, isSdkCompatible, parsePermission, paymentCapability, shippingCapability, suppliersCapability, validateSetupLayout };
package/dist/index.js CHANGED
@@ -30,6 +30,10 @@ __export(index_exports, {
30
30
  FieldType: () => FieldType,
31
31
  FieldVariant: () => FieldVariant,
32
32
  GatewayEnvironment: () => GatewayEnvironment,
33
+ INVOICING_PLUGIN_TOKEN: () => INVOICING_PLUGIN_TOKEN,
34
+ InvoiceDocumentType: () => InvoiceDocumentType,
35
+ InvoiceStatus: () => InvoiceStatus,
36
+ InvoicingFeature: () => InvoicingFeature,
33
37
  LayoutMode: () => LayoutMode,
34
38
  MessageVariant: () => MessageVariant,
35
39
  PAYMENT_PLUGIN_TOKEN: () => PAYMENT_PLUGIN_TOKEN,
@@ -49,6 +53,7 @@ __export(index_exports, {
49
53
  crossValidateSetupLayout: () => crossValidateSetupLayout,
50
54
  definePlugin: () => definePlugin,
51
55
  field: () => field,
56
+ invoicingCapability: () => invoicingCapability,
52
57
  isConfigurablePlugin: () => isConfigurablePlugin,
53
58
  isPermissionGranted: () => isPermissionGranted,
54
59
  isPluginFactory: () => isPluginFactory,
@@ -66,12 +71,14 @@ var PAYMENT_PLUGIN_TOKEN = "PAYMENT_PLUGINS";
66
71
  var SHIPPING_PLUGIN_TOKEN = "SHIPPING_PLUGINS";
67
72
  var SUPPLIERS_PLUGIN_TOKEN = "SUPPLIERS_PLUGINS";
68
73
  var ANALYTICS_PLUGIN_TOKEN = "ANALYTICS_PLUGINS";
74
+ var INVOICING_PLUGIN_TOKEN = "INVOICING_PLUGINS";
69
75
 
70
76
  // src/plugin.ts
71
77
  var PluginType = /* @__PURE__ */ ((PluginType2) => {
72
78
  PluginType2["Payment"] = "payment";
73
79
  PluginType2["Shipping"] = "shipping";
74
80
  PluginType2["Analytics"] = "analytics";
81
+ PluginType2["Invoicing"] = "invoicing";
75
82
  PluginType2["Generic"] = "generic";
76
83
  return PluginType2;
77
84
  })(PluginType || {});
@@ -211,6 +218,32 @@ var AnalyticsFeature = /* @__PURE__ */ ((AnalyticsFeature2) => {
211
218
  return AnalyticsFeature2;
212
219
  })(AnalyticsFeature || {});
213
220
 
221
+ // src/invoicing.ts
222
+ var InvoicingFeature = /* @__PURE__ */ ((InvoicingFeature2) => {
223
+ InvoicingFeature2["Issue"] = "issue";
224
+ InvoicingFeature2["Void"] = "void";
225
+ InvoicingFeature2["StatusQuery"] = "status-query";
226
+ InvoicingFeature2["Pdf"] = "pdf";
227
+ return InvoicingFeature2;
228
+ })(InvoicingFeature || {});
229
+ var InvoiceDocumentType = /* @__PURE__ */ ((InvoiceDocumentType2) => {
230
+ InvoiceDocumentType2["Invoice"] = "invoice";
231
+ InvoiceDocumentType2["CreditInvoice"] = "credit-invoice";
232
+ InvoiceDocumentType2["CreditNote"] = "credit-note";
233
+ InvoiceDocumentType2["DebitNote"] = "debit-note";
234
+ InvoiceDocumentType2["ExcludedSubject"] = "excluded-subject";
235
+ InvoiceDocumentType2["Export"] = "export";
236
+ return InvoiceDocumentType2;
237
+ })(InvoiceDocumentType || {});
238
+ var InvoiceStatus = /* @__PURE__ */ ((InvoiceStatus2) => {
239
+ InvoiceStatus2["Pending"] = "pending";
240
+ InvoiceStatus2["Accepted"] = "accepted";
241
+ InvoiceStatus2["Rejected"] = "rejected";
242
+ InvoiceStatus2["Voided"] = "voided";
243
+ InvoiceStatus2["Unknown"] = "unknown";
244
+ return InvoiceStatus2;
245
+ })(InvoiceStatus || {});
246
+
214
247
  // src/setup-layout.ts
215
248
  var import_superstruct2 = require("superstruct");
216
249
  var FieldVariant = /* @__PURE__ */ ((FieldVariant2) => {
@@ -482,7 +515,8 @@ var CapabilityKind = {
482
515
  Payment: "payment",
483
516
  Shipping: "shipping",
484
517
  Suppliers: "suppliers",
485
- Analytics: "analytics"
518
+ Analytics: "analytics",
519
+ Invoicing: "invoicing"
486
520
  };
487
521
  function capability(kind, impl) {
488
522
  return { kind, impl };
@@ -499,6 +533,9 @@ function suppliersCapability(impl) {
499
533
  function analyticsCapability(impl) {
500
534
  return { kind: CapabilityKind.Analytics, impl };
501
535
  }
536
+ function invoicingCapability(impl) {
537
+ return { kind: CapabilityKind.Invoicing, impl };
538
+ }
502
539
  var PLUGIN_FACTORY_BRAND = /* @__PURE__ */ Symbol.for("vivoa.plugin.factory");
503
540
  function definePlugin(factory) {
504
541
  Object.defineProperty(factory, PLUGIN_FACTORY_BRAND, {
@@ -544,7 +581,7 @@ function checkPermissions(required, grantedRaw) {
544
581
  }
545
582
 
546
583
  // src/version.ts
547
- var SDK_VERSION = "0.6.2";
584
+ var SDK_VERSION = "0.6.5";
548
585
  function isSdkCompatible(pluginSdkVersion, hostSdkVersion) {
549
586
  const parse = (v) => {
550
587
  const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v);
@@ -571,6 +608,10 @@ function isSdkCompatible(pluginSdkVersion, hostSdkVersion) {
571
608
  FieldType,
572
609
  FieldVariant,
573
610
  GatewayEnvironment,
611
+ INVOICING_PLUGIN_TOKEN,
612
+ InvoiceDocumentType,
613
+ InvoiceStatus,
614
+ InvoicingFeature,
574
615
  LayoutMode,
575
616
  MessageVariant,
576
617
  PAYMENT_PLUGIN_TOKEN,
@@ -590,6 +631,7 @@ function isSdkCompatible(pluginSdkVersion, hostSdkVersion) {
590
631
  crossValidateSetupLayout,
591
632
  definePlugin,
592
633
  field,
634
+ invoicingCapability,
593
635
  isConfigurablePlugin,
594
636
  isPermissionGranted,
595
637
  isPluginFactory,
package/dist/index.mjs CHANGED
@@ -3,12 +3,14 @@ var PAYMENT_PLUGIN_TOKEN = "PAYMENT_PLUGINS";
3
3
  var SHIPPING_PLUGIN_TOKEN = "SHIPPING_PLUGINS";
4
4
  var SUPPLIERS_PLUGIN_TOKEN = "SUPPLIERS_PLUGINS";
5
5
  var ANALYTICS_PLUGIN_TOKEN = "ANALYTICS_PLUGINS";
6
+ var INVOICING_PLUGIN_TOKEN = "INVOICING_PLUGINS";
6
7
 
7
8
  // src/plugin.ts
8
9
  var PluginType = /* @__PURE__ */ ((PluginType2) => {
9
10
  PluginType2["Payment"] = "payment";
10
11
  PluginType2["Shipping"] = "shipping";
11
12
  PluginType2["Analytics"] = "analytics";
13
+ PluginType2["Invoicing"] = "invoicing";
12
14
  PluginType2["Generic"] = "generic";
13
15
  return PluginType2;
14
16
  })(PluginType || {});
@@ -156,6 +158,32 @@ var AnalyticsFeature = /* @__PURE__ */ ((AnalyticsFeature2) => {
156
158
  return AnalyticsFeature2;
157
159
  })(AnalyticsFeature || {});
158
160
 
161
+ // src/invoicing.ts
162
+ var InvoicingFeature = /* @__PURE__ */ ((InvoicingFeature2) => {
163
+ InvoicingFeature2["Issue"] = "issue";
164
+ InvoicingFeature2["Void"] = "void";
165
+ InvoicingFeature2["StatusQuery"] = "status-query";
166
+ InvoicingFeature2["Pdf"] = "pdf";
167
+ return InvoicingFeature2;
168
+ })(InvoicingFeature || {});
169
+ var InvoiceDocumentType = /* @__PURE__ */ ((InvoiceDocumentType2) => {
170
+ InvoiceDocumentType2["Invoice"] = "invoice";
171
+ InvoiceDocumentType2["CreditInvoice"] = "credit-invoice";
172
+ InvoiceDocumentType2["CreditNote"] = "credit-note";
173
+ InvoiceDocumentType2["DebitNote"] = "debit-note";
174
+ InvoiceDocumentType2["ExcludedSubject"] = "excluded-subject";
175
+ InvoiceDocumentType2["Export"] = "export";
176
+ return InvoiceDocumentType2;
177
+ })(InvoiceDocumentType || {});
178
+ var InvoiceStatus = /* @__PURE__ */ ((InvoiceStatus2) => {
179
+ InvoiceStatus2["Pending"] = "pending";
180
+ InvoiceStatus2["Accepted"] = "accepted";
181
+ InvoiceStatus2["Rejected"] = "rejected";
182
+ InvoiceStatus2["Voided"] = "voided";
183
+ InvoiceStatus2["Unknown"] = "unknown";
184
+ return InvoiceStatus2;
185
+ })(InvoiceStatus || {});
186
+
159
187
  // src/setup-layout.ts
160
188
  import {
161
189
  array,
@@ -440,7 +468,8 @@ var CapabilityKind = {
440
468
  Payment: "payment",
441
469
  Shipping: "shipping",
442
470
  Suppliers: "suppliers",
443
- Analytics: "analytics"
471
+ Analytics: "analytics",
472
+ Invoicing: "invoicing"
444
473
  };
445
474
  function capability(kind, impl) {
446
475
  return { kind, impl };
@@ -457,6 +486,9 @@ function suppliersCapability(impl) {
457
486
  function analyticsCapability(impl) {
458
487
  return { kind: CapabilityKind.Analytics, impl };
459
488
  }
489
+ function invoicingCapability(impl) {
490
+ return { kind: CapabilityKind.Invoicing, impl };
491
+ }
460
492
  var PLUGIN_FACTORY_BRAND = /* @__PURE__ */ Symbol.for("vivoa.plugin.factory");
461
493
  function definePlugin(factory) {
462
494
  Object.defineProperty(factory, PLUGIN_FACTORY_BRAND, {
@@ -502,7 +534,7 @@ function checkPermissions(required, grantedRaw) {
502
534
  }
503
535
 
504
536
  // src/version.ts
505
- var SDK_VERSION = "0.6.2";
537
+ var SDK_VERSION = "0.6.5";
506
538
  function isSdkCompatible(pluginSdkVersion, hostSdkVersion) {
507
539
  const parse = (v) => {
508
540
  const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v);
@@ -528,6 +560,10 @@ export {
528
560
  FieldType,
529
561
  FieldVariant,
530
562
  GatewayEnvironment,
563
+ INVOICING_PLUGIN_TOKEN,
564
+ InvoiceDocumentType,
565
+ InvoiceStatus,
566
+ InvoicingFeature,
531
567
  LayoutMode,
532
568
  MessageVariant,
533
569
  PAYMENT_PLUGIN_TOKEN,
@@ -547,6 +583,7 @@ export {
547
583
  crossValidateSetupLayout,
548
584
  definePlugin,
549
585
  field,
586
+ invoicingCapability,
550
587
  isConfigurablePlugin,
551
588
  isPermissionGranted,
552
589
  isPluginFactory,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vivoa/plugin-sdk",
3
- "version": "0.6.2",
3
+ "version": "0.6.5",
4
4
  "description": "Public contracts for Vivoa plugins (types, DI tokens, config + setup-layout validators)",
5
5
  "license": "MIT",
6
6
  "author": "Vivoa",