@d19n/youfibre-odin-sdk 2.0.103-beta.6 → 2.0.103-beta.7
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/dist/wholesale-provider/index.d.ts +18 -11
- package/dist/wholesale-provider/index.js +41 -10
- package/dist/wholesale-provider/interface.d.ts +105 -58
- package/dist/wholesale-provider/providers/netomnia-provider.d.ts +74 -130
- package/dist/wholesale-provider/providers/netomnia-provider.js +37 -110
- package/dist/wholesale-provider/test/netomnia-provider.spec.js +242 -139
- package/package.json +1 -1
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Wholesale provider — subpath barrel.
|
|
3
3
|
*
|
|
4
|
-
* Consumers import from `@d19n/youfibre-odin-sdk/wholesale-provider`:
|
|
4
|
+
* Consumers import from `@d19n/youfibre-odin-sdk/dist/wholesale-provider`:
|
|
5
5
|
*
|
|
6
6
|
* ```ts
|
|
7
7
|
* import {
|
|
8
8
|
* WholesaleProvider,
|
|
9
9
|
* NetomniaProvider,
|
|
10
10
|
* NetomniaProviderDeps,
|
|
11
|
-
* } from '@d19n/youfibre-odin-sdk/wholesale-provider';
|
|
11
|
+
* } from '@d19n/youfibre-odin-sdk/dist/wholesale-provider';
|
|
12
12
|
* ```
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* **Architecture (Path B / pass-through delegation):**
|
|
15
|
+
* - `WholesaleProvider` is a strategy-dispatchable interface. Method names
|
|
16
|
+
* align with VMO2 spec where it makes sense; args match existing NET
|
|
17
|
+
* module method signatures.
|
|
18
|
+
* - `NetomniaProvider implements WholesaleProvider` — pass-through to deps
|
|
19
|
+
* wired by modules to their existing NestJS-injected NET methods. Zero
|
|
20
|
+
* transformation at the boundary.
|
|
21
|
+
* - VMO2-shaped types (`./types/vmo2`) and FibreCafe-shaped types
|
|
22
|
+
* (`./types/fibrecafe`) are exported as **reference types** for future
|
|
23
|
+
* use (Vmo2Provider implementation, module DTO consolidation). They are
|
|
24
|
+
* NOT on the WholesaleProvider public surface in Phase 0.
|
|
18
25
|
*
|
|
19
|
-
* Linked: T-20260508-009
|
|
26
|
+
* Linked: T-20260508-009 / T-20260508-010
|
|
20
27
|
*/
|
|
21
|
-
export type { WholesaleProvider } from './interface';
|
|
28
|
+
export type { WholesaleProvider, CreateOrderOptions, CancellationReasonCode, ReserveAppointmentArgs, ListAppointmentsArgs, ScheduleServiceWorkOrderArgs, RescheduleServiceWorkOrderArgs, AmendAppointmentArgs, SyncWorkOrderToSupplierArgs, UpdateOrderExternalRefArgs, } from './interface';
|
|
22
29
|
export type { WholesaleResult, WholesaleSyncResponse, WholesaleRejectionResponse, WholesaleRejectionMessage, WholesaleBUS, WholesaleSYS, ISO8601DateTime, ISODate, TransactionId, UPRN, UUID, SwitchOrderReference, } from './types/wholesale';
|
|
23
|
-
export
|
|
24
|
-
export type { FibreCafeAddressType, FibreCafeAppointmentPurpose, FibreCafeAvailabilityConstraintCode, FibreCafeInstallationType, FibreCafePortStatus, FibreCafeUnavailabilityReasonCode, FibreCafeTimeslotClassification, FibreCafeServiceCharacteristic, FibreCafeServiceProblemCharacteristic, FibreCafeEngineerTask, FibreCafeProvideOrderType, FibreCafeCeaseOrderType, FibreCafeModifyOrderType, FibreCafeUnsolicitedCeaseOrderType, FibreCafeOrderStatus, FibreCafeUnsolicitedCeaseOrderStatus, FibreCafeUnsolicitedCeaseReason, FibreCafeKciReasonCode, FibreCafeKciProblemCode, FibreCafeResolutionCode, FibreCafeGatewayErrorCode, FibreCafeAddressIdentifier, FibreCafeAddressIdentifierWithAdditional, FibreCafeSubAddress, FibreCafeAddress, FibreCafeAddressAttribute, FibreCafeAddressTenant, FibreCafeContact, FibreCafeTimeslot, FibreCafeReserveTimeslot, FibreCafeServiceCharacteristicObject, FibreCafeServiceProblemCharacteristicObject, FibreCafeServiceCharacteristicAvailability, FibreCafeServiceSpecification, FibreCafeServiceSpecificationAvailability, FibreCafeServiceOrderItem, FibreCafeSupplierNote, FibreCafeResolutionDetails, FibreCafeGatewayError, FibreCafeAvailabilityConstraint, FibreCafeUnavailabilityReason, FibreCafeLineCharacteristic, FibreCafeOntPort, FibreCafeOnt, FibreCafeExistingLine, FibreCafeSiteInformation, FibreCafeServiceAvailabilityQuery, FibreCafeServiceAvailability200, FibreCafeAddressLookupQuery, FibreCafeAddressLookup200, FibreCafeAvailableAppointmentsQuery, FibreCafeAvailableAppointments200, FibreCafeReserveAppointmentDto, FibreCafeReserveAppointment201, FibreCafeServiceWorkOrderAddress, FibreCafeServiceWorkOrderTimeslot, FibreCafeScheduleServiceWorkOrderDto, FibreCafeRescheduleServiceWorkOrderDto, FibreCafeScheduleServiceWorkOrder201, FibreCafeRescheduleServiceWorkOrder200, FibreCafeProvideServiceOrderDto, FibreCafeCeaseServiceOrderDto, FibreCafeModifyServiceOrderDto, FibreCafeOrderCreateDto, FibreCafeOrderCreate202, FibreCafeServiceOrderCancellationDto, FibreCafeProvideServiceOrderAmendmentDto, FibreCafeOrderAmendAccept202, FibreCafeProvideServiceOrder, FibreCafeCeaseServiceOrder, FibreCafeModifyServiceOrder, FibreCafeUnsolicitedCeaseServiceOrder, FibreCafeKciDto, FibreCafeServiceProblemCreateDto, FibreCafeServiceProblemCreate202, FibreCafeServiceProblemAmendmentDto, FibreCafeServiceProblemCancellationDto, FibreCafeServiceProblemDetails, } from './types/fibrecafe';
|
|
25
|
-
export { NetomniaProvider, AggregateNotificationError, NotImplementedError, } from './providers/netomnia-provider';
|
|
30
|
+
export { NetomniaProvider, AggregateNotificationError } from './providers/netomnia-provider';
|
|
26
31
|
export type { NetomniaProviderDeps } from './providers/netomnia-provider';
|
|
32
|
+
export type { VMO2OrderId, VMO2RequestId, VMO2AppointmentKey, VMO2PremiseId, VMO2OrderNotificationType, VMO2SMRNotificationType, VMO2NotificationEnvelope, VMO2OrderNotification, VMO2SMRNotification, VMO2InboundNotification, } from './types/vmo2';
|
|
33
|
+
export * from './types/fibrecafe';
|
|
@@ -2,27 +2,58 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Wholesale provider — subpath barrel.
|
|
4
4
|
*
|
|
5
|
-
* Consumers import from `@d19n/youfibre-odin-sdk/wholesale-provider`:
|
|
5
|
+
* Consumers import from `@d19n/youfibre-odin-sdk/dist/wholesale-provider`:
|
|
6
6
|
*
|
|
7
7
|
* ```ts
|
|
8
8
|
* import {
|
|
9
9
|
* WholesaleProvider,
|
|
10
10
|
* NetomniaProvider,
|
|
11
11
|
* NetomniaProviderDeps,
|
|
12
|
-
* } from '@d19n/youfibre-odin-sdk/wholesale-provider';
|
|
12
|
+
* } from '@d19n/youfibre-odin-sdk/dist/wholesale-provider';
|
|
13
13
|
* ```
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* **Architecture (Path B / pass-through delegation):**
|
|
16
|
+
* - `WholesaleProvider` is a strategy-dispatchable interface. Method names
|
|
17
|
+
* align with VMO2 spec where it makes sense; args match existing NET
|
|
18
|
+
* module method signatures.
|
|
19
|
+
* - `NetomniaProvider implements WholesaleProvider` — pass-through to deps
|
|
20
|
+
* wired by modules to their existing NestJS-injected NET methods. Zero
|
|
21
|
+
* transformation at the boundary.
|
|
22
|
+
* - VMO2-shaped types (`./types/vmo2`) and FibreCafe-shaped types
|
|
23
|
+
* (`./types/fibrecafe`) are exported as **reference types** for future
|
|
24
|
+
* use (Vmo2Provider implementation, module DTO consolidation). They are
|
|
25
|
+
* NOT on the WholesaleProvider public surface in Phase 0.
|
|
19
26
|
*
|
|
20
|
-
* Linked: T-20260508-009
|
|
27
|
+
* Linked: T-20260508-009 / T-20260508-010
|
|
21
28
|
*/
|
|
29
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
32
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
33
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
34
|
+
}
|
|
35
|
+
Object.defineProperty(o, k2, desc);
|
|
36
|
+
}) : (function(o, m, k, k2) {
|
|
37
|
+
if (k2 === undefined) k2 = k;
|
|
38
|
+
o[k2] = m[k];
|
|
39
|
+
}));
|
|
40
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
41
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
42
|
+
};
|
|
22
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.
|
|
24
|
-
// Provider
|
|
44
|
+
exports.AggregateNotificationError = exports.NetomniaProvider = void 0;
|
|
45
|
+
// ── Provider implementation ───────────────────────────────────────────
|
|
25
46
|
var netomnia_provider_1 = require("./providers/netomnia-provider");
|
|
26
47
|
Object.defineProperty(exports, "NetomniaProvider", { enumerable: true, get: function () { return netomnia_provider_1.NetomniaProvider; } });
|
|
27
48
|
Object.defineProperty(exports, "AggregateNotificationError", { enumerable: true, get: function () { return netomnia_provider_1.AggregateNotificationError; } });
|
|
28
|
-
|
|
49
|
+
// ── Reference types (re-exported — not on WholesaleProvider surface) ──
|
|
50
|
+
//
|
|
51
|
+
// FibreCafe wire-format types — useful for module-level DTO consolidation
|
|
52
|
+
// or building the VMO2 wire request inside a future Vmo2Provider. These
|
|
53
|
+
// are NOT used by NetomniaProviderDeps in Path B; the deps shape is YF-
|
|
54
|
+
// context-shaped.
|
|
55
|
+
//
|
|
56
|
+
// Re-exported with `export *` because TS 4.8 doesn't support `export type *`.
|
|
57
|
+
// All declarations in fibrecafe.ts are types/interfaces with no runtime
|
|
58
|
+
// exports, so `export *` re-exports them as types only (no JS code emit).
|
|
59
|
+
__exportStar(require("./types/fibrecafe"), exports);
|
|
@@ -1,65 +1,112 @@
|
|
|
1
|
+
import type { VMO2OrderNotification, VMO2SMRNotification } from './types/vmo2';
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
* Reasons a cancellation request can be made (NET wire-level enum value
|
|
4
|
+
* passed through to the FibreCafe gateway).
|
|
5
|
+
*/
|
|
6
|
+
export declare type CancellationReasonCode = string;
|
|
7
|
+
export interface CreateOrderOptions {
|
|
8
|
+
doNotCreateServiceAppointment?: boolean;
|
|
9
|
+
externalRefBrskFno?: string;
|
|
10
|
+
externalRefBrskIsp?: string;
|
|
11
|
+
/** Provider-specific extras — populated as needed per provider. */
|
|
12
|
+
[extra: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface ReserveAppointmentArgs {
|
|
15
|
+
yfAppointmentId: string;
|
|
16
|
+
uprn: number;
|
|
17
|
+
startDateTime: string;
|
|
18
|
+
endDateTime: string;
|
|
19
|
+
/** 'PROVIDE' / 'REPAIR' / 'MODIFY' or supplier-specific. */
|
|
20
|
+
purpose: string;
|
|
21
|
+
yfOrderId: string;
|
|
22
|
+
woProperties: {
|
|
23
|
+
ServiceCallReason?: string;
|
|
24
|
+
WorkOrderExternalReference?: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface ListAppointmentsArgs {
|
|
28
|
+
uprn: number;
|
|
29
|
+
/** ISO date the appointment search starts from. */
|
|
30
|
+
start: string;
|
|
31
|
+
appointmentPurpose: 'PROVIDE' | 'REPAIR';
|
|
32
|
+
}
|
|
33
|
+
export interface ScheduleServiceWorkOrderArgs {
|
|
34
|
+
yfWorkOrderId: string;
|
|
35
|
+
uprn: number;
|
|
36
|
+
startDateTime: string;
|
|
37
|
+
endDateTime: string;
|
|
38
|
+
yfOrderId: string;
|
|
39
|
+
properties: {
|
|
40
|
+
ServiceCallReason?: string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export interface RescheduleServiceWorkOrderArgs {
|
|
44
|
+
yfWorkOrderId: string;
|
|
45
|
+
uprn: number;
|
|
46
|
+
startDateTime: string;
|
|
47
|
+
endDateTime: string;
|
|
48
|
+
yfOrderId: string;
|
|
49
|
+
}
|
|
50
|
+
export interface AmendAppointmentArgs {
|
|
51
|
+
yfOrderId: string;
|
|
52
|
+
yfWorkOrderId: string;
|
|
53
|
+
supplierAppointmentReference: string;
|
|
54
|
+
}
|
|
55
|
+
export interface SyncWorkOrderToSupplierArgs {
|
|
56
|
+
principal: unknown;
|
|
57
|
+
yfOrderId: string;
|
|
58
|
+
yfWorkOrderId: string;
|
|
59
|
+
yfChangeReason: {
|
|
60
|
+
id?: string;
|
|
61
|
+
externalId: string;
|
|
62
|
+
entity: string;
|
|
63
|
+
type: unknown;
|
|
64
|
+
properties: unknown;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export interface UpdateOrderExternalRefArgs {
|
|
68
|
+
oldYfId: string;
|
|
69
|
+
newYfId: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Capability-shaped interface to a wholesale supplier. Method NAMES align
|
|
73
|
+
* with VMO2 spec where it makes sense; ARGS match existing NET module
|
|
74
|
+
* method signatures. Each provider implementation translates these args
|
|
75
|
+
* into its supplier wire format internally.
|
|
17
76
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* implementations adapt their wire format to/from these shapes — see
|
|
21
|
-
* `comparison-fibrecafe-vs-vmo2.md` for the field-level mapping.
|
|
77
|
+
* Returns are typed loosely — modules know the return shape via the dep
|
|
78
|
+
* function they wire in.
|
|
22
79
|
*/
|
|
23
|
-
import type { WholesaleResult } from './types/wholesale';
|
|
24
|
-
import type { VMO2AddressLookupRequest, VMO2AddressLookupResult, VMO2ListAppointmentRequest, VMO2ListAppointmentResult, VMO2ReserveAppointmentRequest, VMO2ReserveAppointmentResult, VMO2ConfirmAppointmentRequest, VMO2AppointmentDetails, VMO2AppointmentKey, VMO2AmendAppointmentPatch, VMO2CreateOrderRequest, VMO2CreateOrderResult, VMO2AmendOrderPatch, VMO2OrderDetails, VMO2OrderId, VMO2CancellationReasonCode, VMO2PremiseId, VMO2CreateIncidentRequest, VMO2CreateIncidentResult, VMO2AmendIncidentPatch, VMO2IncidentDetails, VMO2RequestId, VMO2OrderNotification, VMO2SMRNotification } from './types/vmo2';
|
|
25
|
-
import type { ISODate, SwitchOrderReference } from './types/wholesale';
|
|
26
80
|
export interface WholesaleProvider {
|
|
27
|
-
searchAddress(
|
|
28
|
-
listAppointments(
|
|
29
|
-
reserveAppointment(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
amendIncident(requestId: VMO2RequestId, patch: VMO2AmendIncidentPatch): Promise<WholesaleResult<{
|
|
57
|
-
requestId: VMO2RequestId;
|
|
58
|
-
}>>;
|
|
59
|
-
cancelIncident(requestId: VMO2RequestId): Promise<WholesaleResult<{
|
|
60
|
-
requestId: VMO2RequestId;
|
|
61
|
-
}>>;
|
|
62
|
-
getIncident(requestId: VMO2RequestId): Promise<WholesaleResult<VMO2IncidentDetails>>;
|
|
81
|
+
searchAddress(uprn: number): Promise<unknown>;
|
|
82
|
+
listAppointments(args: ListAppointmentsArgs): Promise<unknown>;
|
|
83
|
+
reserveAppointment(args: ReserveAppointmentArgs): Promise<unknown>;
|
|
84
|
+
scheduleServiceWorkOrder(args: ScheduleServiceWorkOrderArgs): Promise<unknown>;
|
|
85
|
+
rescheduleServiceWorkOrder(args: RescheduleServiceWorkOrderArgs): Promise<unknown>;
|
|
86
|
+
amendAppointment(args: AmendAppointmentArgs): Promise<unknown>;
|
|
87
|
+
createOrder(principal: unknown, orderId: string, options?: CreateOrderOptions): Promise<unknown>;
|
|
88
|
+
/** Tier-change CoS — wraps `createModifyOrderForYfOrder` style args. */
|
|
89
|
+
amendOrder(principal: unknown, yfOrderId: string): Promise<unknown>;
|
|
90
|
+
/** Pre-install cancel of an in-flight provide order. */
|
|
91
|
+
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<unknown>;
|
|
92
|
+
/** Active-customer cease (post-Active churn / OTS-losing). */
|
|
93
|
+
ceaseOrder(yfOrderId: string, serviceId: string): Promise<unknown>;
|
|
94
|
+
/** Inbound supplier KCI / notification handler. */
|
|
95
|
+
receiveKci(principal: unknown, dto: unknown): Promise<void>;
|
|
96
|
+
/** Outbound YF→supplier WO sync (cancel propagation, etc.). */
|
|
97
|
+
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs): Promise<unknown>;
|
|
98
|
+
/** Inbound supplier→YF WO change application (post-receiveKci). */
|
|
99
|
+
syncWorkOrderFromSupplier(order: unknown, dto: unknown): Promise<unknown>;
|
|
100
|
+
retrieveServiceIdByUprn(uprn: number): Promise<string | null>;
|
|
101
|
+
updateOrderExternalRef(args: UpdateOrderExternalRefArgs): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Register a typed handler for fanout of supplier order notifications.
|
|
104
|
+
* The webhook controller invokes `dispatchOrderNotification` on the
|
|
105
|
+
* provider after envelope-mapping; registered handlers are called in
|
|
106
|
+
* order with the normalized `VMO2OrderNotification` envelope (the
|
|
107
|
+
* SDK uses VMO2 envelope types as the cross-supplier normalization
|
|
108
|
+
* shape — easier to reason about + matches the upcoming VMO2 wire).
|
|
109
|
+
*/
|
|
63
110
|
onOrderNotification(handler: (n: VMO2OrderNotification) => Promise<void>): void;
|
|
64
111
|
onSMRNotification(handler: (n: VMO2SMRNotification) => Promise<void>): void;
|
|
65
112
|
}
|
|
@@ -1,155 +1,99 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* NetomniaProvider — concrete `WholesaleProvider`
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* existing NET module function signatures).
|
|
2
|
+
* NetomniaProvider — concrete `WholesaleProvider` for the Netomnia
|
|
3
|
+
* wholesale platform (which exposes its tenant API via the FibreCafe
|
|
4
|
+
* gateway). Same instance handles all three Netomnia-routed `OrderProvider`
|
|
5
|
+
* values (NETOMNIA / NETOMNIA_LEGACY / BRSK).
|
|
7
6
|
*
|
|
8
|
-
* **Architecture (T-20260508-009 —
|
|
7
|
+
* **Architecture (T-20260508-009/010 — Path B):**
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* existing NestJS-injected NET clients in directly — zero
|
|
16
|
-
* transformation at the dep boundary.
|
|
17
|
-
* 4. **Mapping VMO2 ↔ FibreCafe happens INSIDE each NetomniaProvider
|
|
18
|
-
* method.** VMO2 in → map to FibreCafe → call dep → FibreCafe response
|
|
19
|
-
* → map to VMO2 → return. The single place supplier shape differences
|
|
20
|
-
* are reconciled.
|
|
9
|
+
* NetomniaProvider is a **strategy-dispatch pass-through**. Its public
|
|
10
|
+
* methods take YF-context args (matching existing NET module method
|
|
11
|
+
* signatures) and delegate 1:1 to deps. The deps are wired to the
|
|
12
|
+
* existing module-level `NetomniaProvider` / `NetomniaService` methods
|
|
13
|
+
* — zero behaviour change at the call site.
|
|
21
14
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
15
|
+
* Why a thin pass-through is enough:
|
|
16
|
+
* - The "abstraction value" provided is strategy dispatch — call sites
|
|
17
|
+
* do `factory.get(provider).createOrder(...)` instead of
|
|
18
|
+
* `if (isNetomnia) netomniaProvider.createNetomniaOrder(...)`.
|
|
19
|
+
* - DTO-building / HTTP / PE-log emit semantics already live in the
|
|
20
|
+
* existing NET module methods. Lifting them into the SDK (via deps
|
|
21
|
+
* that take FibreCafe DTOs and a built-in HTTP transport) was
|
|
22
|
+
* considered (Path A/C) but rejected for Phase 0 — that's a follow-up
|
|
23
|
+
* standardization step we can take if/when VMO2 alignment requires it.
|
|
31
24
|
*
|
|
32
25
|
* Inbound notification handling: provider stores registered handlers
|
|
33
|
-
* in-memory.
|
|
34
|
-
* `dispatchOrderNotification` / `dispatchSMRNotification`
|
|
26
|
+
* in-memory. The wholesale webhook controller (T-20260508-010 Step 1d)
|
|
27
|
+
* invokes `dispatchOrderNotification` / `dispatchSMRNotification` after
|
|
28
|
+
* envelope-mapping; registered handlers are fanned out.
|
|
35
29
|
*/
|
|
36
|
-
import type { WholesaleProvider } from '../interface';
|
|
37
|
-
import type {
|
|
38
|
-
import type { ISODate, SwitchOrderReference } from '../types/wholesale';
|
|
39
|
-
import type { VMO2AddressLookupRequest, VMO2AddressLookupResult, VMO2ListAppointmentRequest, VMO2ListAppointmentResult, VMO2ReserveAppointmentRequest, VMO2ReserveAppointmentResult, VMO2ConfirmAppointmentRequest, VMO2AppointmentDetails, VMO2AppointmentKey, VMO2AmendAppointmentPatch, VMO2CreateOrderRequest, VMO2CreateOrderResult, VMO2AmendOrderPatch, VMO2OrderDetails, VMO2OrderId, VMO2CancellationReasonCode, VMO2PremiseId, VMO2CreateIncidentRequest, VMO2CreateIncidentResult, VMO2AmendIncidentPatch, VMO2IncidentDetails, VMO2RequestId, VMO2OrderNotification, VMO2SMRNotification } from '../types/vmo2';
|
|
40
|
-
import type { FibreCafeServiceAvailabilityQuery, FibreCafeServiceAvailability200, FibreCafeAvailableAppointmentsQuery, FibreCafeAvailableAppointments200, FibreCafeReserveAppointmentDto, FibreCafeReserveAppointment201, FibreCafeOrderCreateDto, FibreCafeOrderCreate202, FibreCafeProvideServiceOrderAmendmentDto, FibreCafeOrderAmendAccept202, FibreCafeServiceOrderCancellationDto, FibreCafeServiceProblemCreateDto, FibreCafeServiceProblemCreate202, FibreCafeServiceProblemAmendmentDto, FibreCafeServiceProblemCancellationDto, FibreCafeServiceProblemDetails, FibreCafeProvideServiceOrder } from '../types/fibrecafe';
|
|
30
|
+
import type { WholesaleProvider, CreateOrderOptions, CancellationReasonCode, ReserveAppointmentArgs, ListAppointmentsArgs, ScheduleServiceWorkOrderArgs, RescheduleServiceWorkOrderArgs, AmendAppointmentArgs, SyncWorkOrderToSupplierArgs, UpdateOrderExternalRefArgs } from '../interface';
|
|
31
|
+
import type { VMO2OrderNotification, VMO2SMRNotification } from '../types/vmo2';
|
|
41
32
|
/**
|
|
42
|
-
* Function-bag of
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
33
|
+
* Function-bag of dependencies the NetomniaProvider delegates to.
|
|
34
|
+
*
|
|
35
|
+
* **Deps shape mirrors the WholesaleProvider interface 1:1.** Modules wire
|
|
36
|
+
* each property to their existing NestJS-injected NET service/provider
|
|
37
|
+
* method that already takes the equivalent YF-context args. The adapter
|
|
38
|
+
* boundary is intentionally narrow: zero transformation between dep input
|
|
39
|
+
* and the existing module method's input.
|
|
49
40
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
41
|
+
* Example (in a module's WholesaleModule.useFactory):
|
|
42
|
+
* ```typescript
|
|
43
|
+
* {
|
|
44
|
+
* createOrder: (p, id, opts) => existingNetomniaProvider.createNetomniaOrder(p, id, opts),
|
|
45
|
+
* cancelOrder: (id, reason) => existingNetomniaProvider.cancelProvideOrder(id, reason),
|
|
46
|
+
* amendOrder: (p, id) => existingNetomniaService.createModifyOrderForYfOrder(p, id),
|
|
47
|
+
* ...
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
53
50
|
*/
|
|
54
51
|
export interface NetomniaProviderDeps {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
reserveAppointment: (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
*/
|
|
71
|
-
getAppointment?: (appointmentId: string) => Promise<WholesaleResult<FibreCafeReserveAppointment201>>;
|
|
72
|
-
/** Reappoint flow — same endpoint as reserve with rescheduleType discriminator. */
|
|
73
|
-
amendAppointment?: (dto: FibreCafeReserveAppointmentDto) => Promise<WholesaleResult<FibreCafeReserveAppointment201>>;
|
|
74
|
-
/** WO-level cancellation propagating to NET-side appointment. */
|
|
75
|
-
cancelAppointment?: (appointmentId: string, reasonCode?: string) => Promise<WholesaleResult<{
|
|
76
|
-
appointmentId: string;
|
|
77
|
-
}>>;
|
|
78
|
-
createOrder: (dto: FibreCafeOrderCreateDto) => Promise<WholesaleResult<FibreCafeOrderCreate202>>;
|
|
79
|
-
amendOrder: (dto: FibreCafeProvideServiceOrderAmendmentDto) => Promise<WholesaleResult<FibreCafeOrderAmendAccept202>>;
|
|
80
|
-
cancelOrder: (dto: FibreCafeServiceOrderCancellationDto) => Promise<WholesaleResult<{
|
|
81
|
-
cancellationRequestId: string;
|
|
82
|
-
}>>;
|
|
83
|
-
getOrder: (orderId: string) => Promise<WholesaleResult<FibreCafeProvideServiceOrder>>;
|
|
84
|
-
createIncident?: (dto: FibreCafeServiceProblemCreateDto) => Promise<WholesaleResult<FibreCafeServiceProblemCreate202>>;
|
|
85
|
-
amendIncident?: (dto: FibreCafeServiceProblemAmendmentDto) => Promise<WholesaleResult<{
|
|
86
|
-
amendmentId: string;
|
|
87
|
-
}>>;
|
|
88
|
-
cancelIncident?: (dto: FibreCafeServiceProblemCancellationDto) => Promise<WholesaleResult<{
|
|
89
|
-
cancellationId: string;
|
|
90
|
-
}>>;
|
|
91
|
-
getIncident?: (serviceProblemId: string) => Promise<WholesaleResult<FibreCafeServiceProblemDetails>>;
|
|
52
|
+
searchAddress: (uprn: number) => Promise<unknown>;
|
|
53
|
+
listAppointments: (args: ListAppointmentsArgs) => Promise<unknown>;
|
|
54
|
+
reserveAppointment: (args: ReserveAppointmentArgs) => Promise<unknown>;
|
|
55
|
+
scheduleServiceWorkOrder: (args: ScheduleServiceWorkOrderArgs) => Promise<unknown>;
|
|
56
|
+
rescheduleServiceWorkOrder: (args: RescheduleServiceWorkOrderArgs) => Promise<unknown>;
|
|
57
|
+
amendAppointment: (args: AmendAppointmentArgs) => Promise<unknown>;
|
|
58
|
+
createOrder: (principal: unknown, orderId: string, options?: CreateOrderOptions) => Promise<unknown>;
|
|
59
|
+
amendOrder: (principal: unknown, yfOrderId: string) => Promise<unknown>;
|
|
60
|
+
cancelOrder: (yfOrderId: string, reasonCode: CancellationReasonCode) => Promise<unknown>;
|
|
61
|
+
ceaseOrder: (yfOrderId: string, serviceId: string) => Promise<unknown>;
|
|
62
|
+
receiveKci: (principal: unknown, dto: unknown) => Promise<void>;
|
|
63
|
+
syncWorkOrderToSupplier: (args: SyncWorkOrderToSupplierArgs) => Promise<unknown>;
|
|
64
|
+
syncWorkOrderFromSupplier: (order: unknown, dto: unknown) => Promise<unknown>;
|
|
65
|
+
retrieveServiceIdByUprn: (uprn: number) => Promise<string | null>;
|
|
66
|
+
updateOrderExternalRef: (args: UpdateOrderExternalRefArgs) => Promise<void>;
|
|
92
67
|
}
|
|
93
68
|
declare type OrderNotificationHandler = (n: VMO2OrderNotification) => Promise<void>;
|
|
94
69
|
declare type SMRNotificationHandler = (n: VMO2SMRNotification) => Promise<void>;
|
|
95
|
-
/**
|
|
96
|
-
* Sentinel error surfaced by Phase 0 stub mapping bodies. T-20260508-010
|
|
97
|
-
* fills in real bodies; until then any call to these methods at runtime
|
|
98
|
-
* throws this. Tests verify the *delegation* path works for methods whose
|
|
99
|
-
* mapping is trivial enough to ship in Phase 0.
|
|
100
|
-
*/
|
|
101
|
-
export declare class NotImplementedError extends Error {
|
|
102
|
-
readonly method: string;
|
|
103
|
-
constructor(method: string);
|
|
104
|
-
}
|
|
105
70
|
export declare class NetomniaProvider implements WholesaleProvider {
|
|
106
71
|
private readonly deps;
|
|
107
72
|
private readonly orderHandlers;
|
|
108
73
|
private readonly smrHandlers;
|
|
109
74
|
constructor(deps: NetomniaProviderDeps);
|
|
110
|
-
searchAddress(
|
|
111
|
-
listAppointments(
|
|
112
|
-
reserveAppointment(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
orderId: VMO2OrderId;
|
|
126
|
-
}>>;
|
|
127
|
-
cancelOrder(_orderId: VMO2OrderId, _reason?: VMO2CancellationReasonCode): Promise<WholesaleResult<{
|
|
128
|
-
orderId: VMO2OrderId;
|
|
129
|
-
}>>;
|
|
130
|
-
getOrder(_orderId: VMO2OrderId, _opts?: {
|
|
131
|
-
displaySummary?: boolean;
|
|
132
|
-
}): Promise<WholesaleResult<VMO2OrderDetails>>;
|
|
133
|
-
unsolicitedCease(_req: {
|
|
134
|
-
premiseId: VMO2PremiseId;
|
|
135
|
-
switchOrderReference?: SwitchOrderReference;
|
|
136
|
-
requestedOrderCompletionDate: ISODate;
|
|
137
|
-
}): Promise<WholesaleResult<VMO2CreateOrderResult>>;
|
|
138
|
-
createIncident(_req: VMO2CreateIncidentRequest): Promise<WholesaleResult<VMO2CreateIncidentResult>>;
|
|
139
|
-
amendIncident(_requestId: VMO2RequestId, _patch: VMO2AmendIncidentPatch): Promise<WholesaleResult<{
|
|
140
|
-
requestId: VMO2RequestId;
|
|
141
|
-
}>>;
|
|
142
|
-
cancelIncident(_requestId: VMO2RequestId): Promise<WholesaleResult<{
|
|
143
|
-
requestId: VMO2RequestId;
|
|
144
|
-
}>>;
|
|
145
|
-
getIncident(_requestId: VMO2RequestId): Promise<WholesaleResult<VMO2IncidentDetails>>;
|
|
75
|
+
searchAddress(uprn: number): Promise<unknown>;
|
|
76
|
+
listAppointments(args: ListAppointmentsArgs): Promise<unknown>;
|
|
77
|
+
reserveAppointment(args: ReserveAppointmentArgs): Promise<unknown>;
|
|
78
|
+
scheduleServiceWorkOrder(args: ScheduleServiceWorkOrderArgs): Promise<unknown>;
|
|
79
|
+
rescheduleServiceWorkOrder(args: RescheduleServiceWorkOrderArgs): Promise<unknown>;
|
|
80
|
+
amendAppointment(args: AmendAppointmentArgs): Promise<unknown>;
|
|
81
|
+
createOrder(principal: unknown, orderId: string, options?: CreateOrderOptions): Promise<unknown>;
|
|
82
|
+
amendOrder(principal: unknown, yfOrderId: string): Promise<unknown>;
|
|
83
|
+
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<unknown>;
|
|
84
|
+
ceaseOrder(yfOrderId: string, serviceId: string): Promise<unknown>;
|
|
85
|
+
receiveKci(principal: unknown, dto: unknown): Promise<void>;
|
|
86
|
+
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs): Promise<unknown>;
|
|
87
|
+
syncWorkOrderFromSupplier(order: unknown, dto: unknown): Promise<unknown>;
|
|
88
|
+
retrieveServiceIdByUprn(uprn: number): Promise<string>;
|
|
89
|
+
updateOrderExternalRef(args: UpdateOrderExternalRefArgs): Promise<void>;
|
|
146
90
|
onOrderNotification(handler: OrderNotificationHandler): void;
|
|
147
91
|
onSMRNotification(handler: SMRNotificationHandler): void;
|
|
148
92
|
/**
|
|
149
|
-
* Internal dispatch — invoked by the webhook controller
|
|
150
|
-
*
|
|
151
|
-
* out to every registered handler in registration order. Handler
|
|
152
|
-
* are aggregated and re-thrown after all handlers complete.
|
|
93
|
+
* Internal dispatch — invoked by the wholesale webhook controller after
|
|
94
|
+
* mapping a supplier KCI to a normalized `VMO2OrderNotification` envelope.
|
|
95
|
+
* Fans out to every registered handler in registration order. Handler
|
|
96
|
+
* errors are aggregated and re-thrown after all handlers complete.
|
|
153
97
|
*/
|
|
154
98
|
dispatchOrderNotification(n: VMO2OrderNotification): Promise<void>;
|
|
155
99
|
dispatchSMRNotification(n: VMO2SMRNotification): Promise<void>;
|
|
@@ -9,133 +9,60 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.AggregateNotificationError = exports.NetomniaProvider =
|
|
13
|
-
/**
|
|
14
|
-
* Sentinel error surfaced by Phase 0 stub mapping bodies. T-20260508-010
|
|
15
|
-
* fills in real bodies; until then any call to these methods at runtime
|
|
16
|
-
* throws this. Tests verify the *delegation* path works for methods whose
|
|
17
|
-
* mapping is trivial enough to ship in Phase 0.
|
|
18
|
-
*/
|
|
19
|
-
class NotImplementedError extends Error {
|
|
20
|
-
constructor(method) {
|
|
21
|
-
super(`NetomniaProvider.${method} mapping not yet implemented (Phase 0 stub) — ` +
|
|
22
|
-
`lands in T-20260508-010 alongside call-site refactor.`);
|
|
23
|
-
this.method = method;
|
|
24
|
-
this.name = 'NotImplementedError';
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
exports.NotImplementedError = NotImplementedError;
|
|
12
|
+
exports.AggregateNotificationError = exports.NetomniaProvider = void 0;
|
|
28
13
|
class NetomniaProvider {
|
|
29
14
|
constructor(deps) {
|
|
30
15
|
this.deps = deps;
|
|
31
16
|
this.orderHandlers = [];
|
|
32
17
|
this.smrHandlers = [];
|
|
33
18
|
}
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
searchAddress(_req) {
|
|
38
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
-
// Phase 0 stub: the VMO2→FibreCafe mapping for searchAddress is
|
|
40
|
-
// non-trivial (VMO2 returns premise + capability detail; FibreCafe
|
|
41
|
-
// returns address + service-spec). Real mapping lands in T-010 when
|
|
42
|
-
// call sites convert. Until then this throws to surface accidental
|
|
43
|
-
// call-site exercise.
|
|
44
|
-
throw new NotImplementedError('searchAddress');
|
|
45
|
-
});
|
|
19
|
+
// ── Pass-through delegation ────────────────────────────────────────
|
|
20
|
+
searchAddress(uprn) {
|
|
21
|
+
return this.deps.searchAddress(uprn);
|
|
46
22
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// ──────────────────────────────────────────────────────────────────
|
|
50
|
-
listAppointments(_req) {
|
|
51
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
-
throw new NotImplementedError('listAppointments');
|
|
53
|
-
});
|
|
23
|
+
listAppointments(args) {
|
|
24
|
+
return this.deps.listAppointments(args);
|
|
54
25
|
}
|
|
55
|
-
reserveAppointment(
|
|
56
|
-
return
|
|
57
|
-
throw new NotImplementedError('reserveAppointment');
|
|
58
|
-
});
|
|
26
|
+
reserveAppointment(args) {
|
|
27
|
+
return this.deps.reserveAppointment(args);
|
|
59
28
|
}
|
|
60
|
-
|
|
61
|
-
return
|
|
62
|
-
// FibreCafe has no separate confirm step — would be a no-op for NET
|
|
63
|
-
// path. Stubbed until T-010 validates the assumption end-to-end.
|
|
64
|
-
throw new NotImplementedError('confirmAppointment');
|
|
65
|
-
});
|
|
29
|
+
scheduleServiceWorkOrder(args) {
|
|
30
|
+
return this.deps.scheduleServiceWorkOrder(args);
|
|
66
31
|
}
|
|
67
|
-
|
|
68
|
-
return
|
|
69
|
-
throw new NotImplementedError('getAppointment');
|
|
70
|
-
});
|
|
32
|
+
rescheduleServiceWorkOrder(args) {
|
|
33
|
+
return this.deps.rescheduleServiceWorkOrder(args);
|
|
71
34
|
}
|
|
72
|
-
amendAppointment(
|
|
73
|
-
return
|
|
74
|
-
throw new NotImplementedError('amendAppointment');
|
|
75
|
-
});
|
|
35
|
+
amendAppointment(args) {
|
|
36
|
+
return this.deps.amendAppointment(args);
|
|
76
37
|
}
|
|
77
|
-
|
|
78
|
-
return
|
|
79
|
-
throw new NotImplementedError('cancelAppointment');
|
|
80
|
-
});
|
|
38
|
+
createOrder(principal, orderId, options) {
|
|
39
|
+
return this.deps.createOrder(principal, orderId, options);
|
|
81
40
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// ──────────────────────────────────────────────────────────────────
|
|
85
|
-
createOrder(_req) {
|
|
86
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
87
|
-
throw new NotImplementedError('createOrder');
|
|
88
|
-
});
|
|
41
|
+
amendOrder(principal, yfOrderId) {
|
|
42
|
+
return this.deps.amendOrder(principal, yfOrderId);
|
|
89
43
|
}
|
|
90
|
-
|
|
91
|
-
return
|
|
92
|
-
throw new NotImplementedError('amendOrder');
|
|
93
|
-
});
|
|
44
|
+
cancelOrder(yfOrderId, reasonCode) {
|
|
45
|
+
return this.deps.cancelOrder(yfOrderId, reasonCode);
|
|
94
46
|
}
|
|
95
|
-
|
|
96
|
-
return
|
|
97
|
-
throw new NotImplementedError('cancelOrder');
|
|
98
|
-
});
|
|
47
|
+
ceaseOrder(yfOrderId, serviceId) {
|
|
48
|
+
return this.deps.ceaseOrder(yfOrderId, serviceId);
|
|
99
49
|
}
|
|
100
|
-
|
|
101
|
-
return
|
|
102
|
-
throw new NotImplementedError('getOrder');
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
unsolicitedCease(_req) {
|
|
106
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
-
// FibreCafe doesn't have an outbound "unsolicited cease" — it's an
|
|
108
|
-
// inbound-only KCI on the Netomnia side. NetomniaProvider exposes the
|
|
109
|
-
// method for interface symmetry; calling it always throws.
|
|
110
|
-
throw new NotImplementedError('unsolicitedCease');
|
|
111
|
-
});
|
|
50
|
+
receiveKci(principal, dto) {
|
|
51
|
+
return this.deps.receiveKci(principal, dto);
|
|
112
52
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// ──────────────────────────────────────────────────────────────────
|
|
116
|
-
createIncident(_req) {
|
|
117
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
throw new NotImplementedError('createIncident');
|
|
119
|
-
});
|
|
53
|
+
syncWorkOrderToSupplier(args) {
|
|
54
|
+
return this.deps.syncWorkOrderToSupplier(args);
|
|
120
55
|
}
|
|
121
|
-
|
|
122
|
-
return
|
|
123
|
-
throw new NotImplementedError('amendIncident');
|
|
124
|
-
});
|
|
56
|
+
syncWorkOrderFromSupplier(order, dto) {
|
|
57
|
+
return this.deps.syncWorkOrderFromSupplier(order, dto);
|
|
125
58
|
}
|
|
126
|
-
|
|
127
|
-
return
|
|
128
|
-
throw new NotImplementedError('cancelIncident');
|
|
129
|
-
});
|
|
59
|
+
retrieveServiceIdByUprn(uprn) {
|
|
60
|
+
return this.deps.retrieveServiceIdByUprn(uprn);
|
|
130
61
|
}
|
|
131
|
-
|
|
132
|
-
return
|
|
133
|
-
throw new NotImplementedError('getIncident');
|
|
134
|
-
});
|
|
62
|
+
updateOrderExternalRef(args) {
|
|
63
|
+
return this.deps.updateOrderExternalRef(args);
|
|
135
64
|
}
|
|
136
|
-
//
|
|
137
|
-
// Inbound notification subscription
|
|
138
|
-
// ──────────────────────────────────────────────────────────────────
|
|
65
|
+
// ── Inbound notification subscription ─────────────────────────────
|
|
139
66
|
onOrderNotification(handler) {
|
|
140
67
|
this.orderHandlers.push(handler);
|
|
141
68
|
}
|
|
@@ -143,10 +70,10 @@ class NetomniaProvider {
|
|
|
143
70
|
this.smrHandlers.push(handler);
|
|
144
71
|
}
|
|
145
72
|
/**
|
|
146
|
-
* Internal dispatch — invoked by the webhook controller
|
|
147
|
-
*
|
|
148
|
-
* out to every registered handler in registration order. Handler
|
|
149
|
-
* are aggregated and re-thrown after all handlers complete.
|
|
73
|
+
* Internal dispatch — invoked by the wholesale webhook controller after
|
|
74
|
+
* mapping a supplier KCI to a normalized `VMO2OrderNotification` envelope.
|
|
75
|
+
* Fans out to every registered handler in registration order. Handler
|
|
76
|
+
* errors are aggregated and re-thrown after all handlers complete.
|
|
150
77
|
*/
|
|
151
78
|
dispatchOrderNotification(n) {
|
|
152
79
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -10,25 +10,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
/**
|
|
13
|
-
* NetomniaProvider
|
|
13
|
+
* NetomniaProvider tests — verify pass-through delegation pattern.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Path B (T-20260508-009/010): NetomniaProvider's public methods delegate
|
|
16
|
+
* 1:1 to deps that match the WholesaleProvider interface signature. These
|
|
17
|
+
* tests assert:
|
|
18
|
+
* 1. Each public method calls the matching dep with identical args.
|
|
19
|
+
* 2. The dep's return value is forwarded unchanged.
|
|
20
|
+
* 3. NetomniaProvider is structurally assignable to WholesaleProvider
|
|
17
21
|
* (compile-time check via the class declaration).
|
|
18
|
-
*
|
|
19
|
-
* existing typed NET functions in. Verified by constructing a
|
|
20
|
-
* stub-deps object that passes type-check.
|
|
21
|
-
* 3. Each outbound method throws `NotImplementedError` until T-010 fills
|
|
22
|
-
* in the VMO2↔FibreCafe mapping bodies.
|
|
23
|
-
* 4. Inbound handler registration + dispatch + error aggregation work
|
|
24
|
-
* as documented (these are NOT mapping-dependent — they fan out to
|
|
25
|
-
* registered handlers regardless of supplier).
|
|
26
|
-
*
|
|
27
|
-
* **What's deferred to T-20260508-010 tests:** end-to-end behaviour parity
|
|
28
|
-
* — the real test is "running through NetomniaProvider produces identical
|
|
29
|
-
* NET-side state vs running through legacy direct calls". That requires
|
|
30
|
-
* call sites + real deps + recorded baseline; lives in T-013 acceptance
|
|
31
|
-
* gate.
|
|
22
|
+
* 4. Inbound handler registration + dispatch + error aggregation work.
|
|
32
23
|
*
|
|
33
24
|
* Run: `npm run test:wholesale-provider`
|
|
34
25
|
*/
|
|
@@ -51,134 +42,238 @@ function assert(label, cond, hint) {
|
|
|
51
42
|
function brand(s) {
|
|
52
43
|
return s;
|
|
53
44
|
}
|
|
54
|
-
function ok(data) {
|
|
55
|
-
return {
|
|
56
|
-
status: 'accepted',
|
|
57
|
-
eventDateTime: brand('2026-05-09T00:00:00Z'),
|
|
58
|
-
data,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
45
|
/**
|
|
62
|
-
* Build
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* future tests can add behaviour assertions.
|
|
46
|
+
* Build deps that record their call args + return a sentinel value. Each
|
|
47
|
+
* dep is identical-shape to the corresponding WholesaleProvider method so
|
|
48
|
+
* the pass-through pattern can be tested.
|
|
66
49
|
*/
|
|
67
50
|
function buildDeps() {
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}),
|
|
74
|
-
getAvailableAppointments: stub({ availableTimeslots: [] }),
|
|
75
|
-
reserveAppointment: stub({
|
|
76
|
-
id: 'A1',
|
|
77
|
-
supplierReference: 'NET-A1',
|
|
78
|
-
address: { id: 'X', type: 'UPRN' },
|
|
79
|
-
serviceSpecification: { id: 'fttp' },
|
|
80
|
-
timeslot: {
|
|
81
|
-
timeslotStartDateTime: '2026-05-09T08:00:00Z',
|
|
82
|
-
timeslotEndDateTime: '2026-05-09T13:00:00Z',
|
|
83
|
-
},
|
|
84
|
-
}),
|
|
85
|
-
createOrder: stub({}),
|
|
86
|
-
amendOrder: stub({}),
|
|
87
|
-
cancelOrder: stub({ cancellationRequestId: 'CXL-1' }),
|
|
88
|
-
getOrder: stub({
|
|
89
|
-
id: 'O1',
|
|
90
|
-
tenant: 'YOUFIBRE',
|
|
91
|
-
status: 'IN_PROGRESS',
|
|
92
|
-
address: { id: 'X', type: 'UPRN' },
|
|
93
|
-
serviceOrderItem: {
|
|
94
|
-
serviceSpecification: { id: 'fttp' },
|
|
95
|
-
serviceCharacteristics: [],
|
|
96
|
-
},
|
|
97
|
-
primaryContact: { name: 'Bob', phoneNumber: '01234' },
|
|
98
|
-
}),
|
|
99
|
-
// Optional deps left unset — provider stubs throw when called regardless
|
|
51
|
+
const log = [];
|
|
52
|
+
const sentinel = Symbol('NET-RETURN');
|
|
53
|
+
const record = (method) => (...args) => {
|
|
54
|
+
log.push({ method, args });
|
|
55
|
+
return Promise.resolve(sentinel);
|
|
100
56
|
};
|
|
57
|
+
const recordVoid = (method) => (...args) => {
|
|
58
|
+
log.push({ method, args });
|
|
59
|
+
return Promise.resolve(undefined);
|
|
60
|
+
};
|
|
61
|
+
const deps = {
|
|
62
|
+
searchAddress: record('searchAddress'),
|
|
63
|
+
listAppointments: record('listAppointments'),
|
|
64
|
+
reserveAppointment: record('reserveAppointment'),
|
|
65
|
+
scheduleServiceWorkOrder: record('scheduleServiceWorkOrder'),
|
|
66
|
+
rescheduleServiceWorkOrder: record('rescheduleServiceWorkOrder'),
|
|
67
|
+
amendAppointment: record('amendAppointment'),
|
|
68
|
+
createOrder: record('createOrder'),
|
|
69
|
+
amendOrder: record('amendOrder'),
|
|
70
|
+
cancelOrder: record('cancelOrder'),
|
|
71
|
+
ceaseOrder: record('ceaseOrder'),
|
|
72
|
+
receiveKci: recordVoid('receiveKci'),
|
|
73
|
+
syncWorkOrderToSupplier: record('syncWorkOrderToSupplier'),
|
|
74
|
+
syncWorkOrderFromSupplier: record('syncWorkOrderFromSupplier'),
|
|
75
|
+
retrieveServiceIdByUprn: (uprn) => {
|
|
76
|
+
log.push({ method: 'retrieveServiceIdByUprn', args: [uprn] });
|
|
77
|
+
return Promise.resolve('NET-SVC-1');
|
|
78
|
+
},
|
|
79
|
+
updateOrderExternalRef: recordVoid('updateOrderExternalRef'),
|
|
80
|
+
};
|
|
81
|
+
return { deps, log, sentinel };
|
|
101
82
|
}
|
|
102
83
|
function run() {
|
|
103
84
|
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
-
console.log('NetomniaProvider —
|
|
105
|
-
|
|
106
|
-
console.log('Test: NetomniaProvider implements WholesaleProvider (compile-time)');
|
|
85
|
+
console.log('NetomniaProvider — pass-through delegation tests\n');
|
|
86
|
+
console.log('Test: searchAddress delegates to deps');
|
|
107
87
|
{
|
|
108
|
-
const
|
|
109
|
-
|
|
88
|
+
const { deps, log, sentinel } = buildDeps();
|
|
89
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
90
|
+
const result = yield p.searchAddress(123);
|
|
91
|
+
assert('called once', log.length === 1);
|
|
92
|
+
assert('correct method', log[0].method === 'searchAddress');
|
|
93
|
+
assert('args forwarded', JSON.stringify(log[0].args) === JSON.stringify([123]));
|
|
94
|
+
assert('return forwarded', result === sentinel);
|
|
95
|
+
}
|
|
96
|
+
console.log('Test: listAppointments delegates to deps');
|
|
97
|
+
{
|
|
98
|
+
const { deps, log } = buildDeps();
|
|
99
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
100
|
+
const args = { uprn: 123, start: '2026-06-01', appointmentPurpose: 'PROVIDE' };
|
|
101
|
+
yield p.listAppointments(args);
|
|
102
|
+
assert('called once', log.length === 1);
|
|
103
|
+
assert('correct method', log[0].method === 'listAppointments');
|
|
104
|
+
assert('args forwarded', log[0].args[0] === args);
|
|
105
|
+
}
|
|
106
|
+
console.log('Test: reserveAppointment delegates to deps');
|
|
107
|
+
{
|
|
108
|
+
const { deps, log } = buildDeps();
|
|
109
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
110
|
+
const args = {
|
|
111
|
+
yfAppointmentId: 'APT-1',
|
|
112
|
+
uprn: 123,
|
|
113
|
+
startDateTime: '2026-06-01T08:00:00Z',
|
|
114
|
+
endDateTime: '2026-06-01T13:00:00Z',
|
|
115
|
+
purpose: 'PROVIDE',
|
|
116
|
+
yfOrderId: 'ORD-1',
|
|
117
|
+
woProperties: {},
|
|
118
|
+
};
|
|
119
|
+
yield p.reserveAppointment(args);
|
|
120
|
+
assert('called once', log.length === 1);
|
|
121
|
+
assert('correct method', log[0].method === 'reserveAppointment');
|
|
122
|
+
assert('args forwarded', log[0].args[0] === args);
|
|
110
123
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
124
|
+
console.log('Test: scheduleServiceWorkOrder delegates to deps');
|
|
125
|
+
{
|
|
126
|
+
const { deps, log } = buildDeps();
|
|
127
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
128
|
+
const args = {
|
|
129
|
+
yfWorkOrderId: 'WO-1',
|
|
130
|
+
uprn: 123,
|
|
131
|
+
startDateTime: '2026-06-01T08:00:00Z',
|
|
132
|
+
endDateTime: '2026-06-01T13:00:00Z',
|
|
133
|
+
yfOrderId: 'ORD-1',
|
|
134
|
+
properties: {},
|
|
135
|
+
};
|
|
136
|
+
yield p.scheduleServiceWorkOrder(args);
|
|
137
|
+
assert('called once', log.length === 1);
|
|
138
|
+
assert('correct method', log[0].method === 'scheduleServiceWorkOrder');
|
|
139
|
+
}
|
|
140
|
+
console.log('Test: rescheduleServiceWorkOrder delegates to deps');
|
|
141
|
+
{
|
|
142
|
+
const { deps, log } = buildDeps();
|
|
143
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
144
|
+
const args = {
|
|
145
|
+
yfWorkOrderId: 'WO-1',
|
|
146
|
+
uprn: 123,
|
|
147
|
+
startDateTime: '2026-06-01T08:00:00Z',
|
|
148
|
+
endDateTime: '2026-06-01T13:00:00Z',
|
|
149
|
+
yfOrderId: 'ORD-1',
|
|
150
|
+
};
|
|
151
|
+
yield p.rescheduleServiceWorkOrder(args);
|
|
152
|
+
assert('called once', log.length === 1);
|
|
153
|
+
assert('correct method', log[0].method === 'rescheduleServiceWorkOrder');
|
|
154
|
+
}
|
|
155
|
+
console.log('Test: amendAppointment delegates to deps');
|
|
156
|
+
{
|
|
157
|
+
const { deps, log } = buildDeps();
|
|
158
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
159
|
+
const args = { yfOrderId: 'ORD-1', yfWorkOrderId: 'WO-1', supplierAppointmentReference: 'NET-A1' };
|
|
160
|
+
yield p.amendAppointment(args);
|
|
161
|
+
assert('called once', log.length === 1);
|
|
162
|
+
assert('correct method', log[0].method === 'amendAppointment');
|
|
163
|
+
}
|
|
164
|
+
console.log('Test: createOrder delegates to deps with all args (principal, orderId, options)');
|
|
165
|
+
{
|
|
166
|
+
const { deps, log, sentinel } = buildDeps();
|
|
167
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
168
|
+
const principal = { id: 'user-1' };
|
|
169
|
+
const opts = { doNotCreateServiceAppointment: true };
|
|
170
|
+
const result = yield p.createOrder(principal, 'ORD-1', opts);
|
|
171
|
+
assert('called once', log.length === 1);
|
|
172
|
+
assert('correct method', log[0].method === 'createOrder');
|
|
173
|
+
assert('principal forwarded', log[0].args[0] === principal);
|
|
174
|
+
assert('orderId forwarded', log[0].args[1] === 'ORD-1');
|
|
175
|
+
assert('options forwarded', log[0].args[2] === opts);
|
|
176
|
+
assert('return forwarded', result === sentinel);
|
|
177
|
+
}
|
|
178
|
+
console.log('Test: createOrder forwards undefined options correctly');
|
|
179
|
+
{
|
|
180
|
+
const { deps, log } = buildDeps();
|
|
181
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
182
|
+
yield p.createOrder({ id: 'user-1' }, 'ORD-1');
|
|
183
|
+
assert('called once', log.length === 1);
|
|
184
|
+
assert('options arg is undefined', log[0].args[2] === undefined);
|
|
185
|
+
}
|
|
186
|
+
console.log('Test: amendOrder delegates to deps');
|
|
187
|
+
{
|
|
188
|
+
const { deps, log } = buildDeps();
|
|
189
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
190
|
+
const principal = { id: 'user-1' };
|
|
191
|
+
yield p.amendOrder(principal, 'ORD-1');
|
|
192
|
+
assert('called once', log.length === 1);
|
|
193
|
+
assert('correct method', log[0].method === 'amendOrder');
|
|
194
|
+
assert('principal forwarded', log[0].args[0] === principal);
|
|
195
|
+
assert('orderId forwarded', log[0].args[1] === 'ORD-1');
|
|
196
|
+
}
|
|
197
|
+
console.log('Test: cancelOrder delegates to deps');
|
|
198
|
+
{
|
|
199
|
+
const { deps, log } = buildDeps();
|
|
200
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
201
|
+
yield p.cancelOrder('ORD-1', 'CUSTOMER_CHANGED_MIND');
|
|
202
|
+
assert('called once', log.length === 1);
|
|
203
|
+
assert('correct method', log[0].method === 'cancelOrder');
|
|
204
|
+
assert('orderId forwarded', log[0].args[0] === 'ORD-1');
|
|
205
|
+
assert('reasonCode forwarded', log[0].args[1] === 'CUSTOMER_CHANGED_MIND');
|
|
206
|
+
}
|
|
207
|
+
console.log('Test: ceaseOrder delegates to deps');
|
|
208
|
+
{
|
|
209
|
+
const { deps, log } = buildDeps();
|
|
210
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
211
|
+
yield p.ceaseOrder('ORD-1', 'NET-SVC-1');
|
|
212
|
+
assert('called once', log.length === 1);
|
|
213
|
+
assert('correct method', log[0].method === 'ceaseOrder');
|
|
214
|
+
}
|
|
215
|
+
console.log('Test: receiveKci delegates to deps');
|
|
216
|
+
{
|
|
217
|
+
const { deps, log } = buildDeps();
|
|
218
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
219
|
+
const principal = { id: 'user-1' };
|
|
220
|
+
const dto = { id: 'kci-1', sequenceNumber: 1 };
|
|
221
|
+
yield p.receiveKci(principal, dto);
|
|
222
|
+
assert('called once', log.length === 1);
|
|
223
|
+
assert('correct method', log[0].method === 'receiveKci');
|
|
224
|
+
assert('args forwarded', log[0].args[0] === principal && log[0].args[1] === dto);
|
|
225
|
+
}
|
|
226
|
+
console.log('Test: syncWorkOrderToSupplier delegates to deps');
|
|
227
|
+
{
|
|
228
|
+
const { deps, log } = buildDeps();
|
|
229
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
230
|
+
const args = {
|
|
231
|
+
principal: { id: 'user-1' },
|
|
232
|
+
yfOrderId: 'ORD-1',
|
|
233
|
+
yfWorkOrderId: 'WO-1',
|
|
234
|
+
yfChangeReason: { externalId: 'CR-1', entity: 'ChangeReason', type: 'CANCEL', properties: {} },
|
|
235
|
+
};
|
|
236
|
+
yield p.syncWorkOrderToSupplier(args);
|
|
237
|
+
assert('called once', log.length === 1);
|
|
238
|
+
assert('correct method', log[0].method === 'syncWorkOrderToSupplier');
|
|
239
|
+
}
|
|
240
|
+
console.log('Test: syncWorkOrderFromSupplier delegates to deps');
|
|
241
|
+
{
|
|
242
|
+
const { deps, log } = buildDeps();
|
|
243
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
244
|
+
const order = { id: 'ORD-1' };
|
|
245
|
+
const dto = { id: 'kci-1' };
|
|
246
|
+
yield p.syncWorkOrderFromSupplier(order, dto);
|
|
247
|
+
assert('called once', log.length === 1);
|
|
248
|
+
assert('correct method', log[0].method === 'syncWorkOrderFromSupplier');
|
|
249
|
+
}
|
|
250
|
+
console.log('Test: retrieveServiceIdByUprn delegates to deps');
|
|
251
|
+
{
|
|
252
|
+
const { deps, log } = buildDeps();
|
|
253
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
254
|
+
const result = yield p.retrieveServiceIdByUprn(123);
|
|
255
|
+
assert('called once', log.length === 1);
|
|
256
|
+
assert('correct method', log[0].method === 'retrieveServiceIdByUprn');
|
|
257
|
+
assert('return forwarded', result === 'NET-SVC-1');
|
|
258
|
+
}
|
|
259
|
+
console.log('Test: updateOrderExternalRef delegates to deps');
|
|
260
|
+
{
|
|
261
|
+
const { deps, log } = buildDeps();
|
|
262
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
263
|
+
yield p.updateOrderExternalRef({ oldYfId: 'OLD', newYfId: 'NEW' });
|
|
264
|
+
assert('called once', log.length === 1);
|
|
265
|
+
assert('correct method', log[0].method === 'updateOrderExternalRef');
|
|
266
|
+
}
|
|
267
|
+
// ── Inbound handler registration + dispatch ────────────────────────
|
|
174
268
|
console.log('Test: onOrderNotification registers handler; dispatchOrderNotification fans out');
|
|
175
269
|
{
|
|
176
|
-
const
|
|
270
|
+
const { deps } = buildDeps();
|
|
271
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
177
272
|
const received = [];
|
|
178
|
-
|
|
273
|
+
p.onOrderNotification((n) => __awaiter(this, void 0, void 0, function* () {
|
|
179
274
|
received.push(n);
|
|
180
275
|
}));
|
|
181
|
-
|
|
276
|
+
p.onOrderNotification((n) => __awaiter(this, void 0, void 0, function* () {
|
|
182
277
|
received.push(n);
|
|
183
278
|
}));
|
|
184
279
|
const notif = {
|
|
@@ -188,15 +283,16 @@ function run() {
|
|
|
188
283
|
orderId: brand('OID1'),
|
|
189
284
|
payload: {},
|
|
190
285
|
};
|
|
191
|
-
yield
|
|
286
|
+
yield p.dispatchOrderNotification(notif);
|
|
192
287
|
assert('both handlers fired', received.length === 2);
|
|
193
288
|
assert('handler 1 received correct notif', received[0].orderId === notif.orderId);
|
|
194
289
|
}
|
|
195
290
|
console.log('Test: onSMRNotification registers handler; dispatchSMRNotification fans out');
|
|
196
291
|
{
|
|
197
|
-
const
|
|
292
|
+
const { deps } = buildDeps();
|
|
293
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
198
294
|
const received = [];
|
|
199
|
-
|
|
295
|
+
p.onSMRNotification((n) => __awaiter(this, void 0, void 0, function* () {
|
|
200
296
|
received.push(n);
|
|
201
297
|
}));
|
|
202
298
|
const notif = {
|
|
@@ -206,23 +302,24 @@ function run() {
|
|
|
206
302
|
requestId: brand('RID1'),
|
|
207
303
|
payload: {},
|
|
208
304
|
};
|
|
209
|
-
yield
|
|
305
|
+
yield p.dispatchSMRNotification(notif);
|
|
210
306
|
assert('handler fired', received.length === 1);
|
|
211
307
|
}
|
|
212
308
|
console.log('Test: dispatchOrderNotification aggregates handler errors');
|
|
213
309
|
{
|
|
214
|
-
const
|
|
310
|
+
const { deps } = buildDeps();
|
|
311
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
215
312
|
const callState = { secondCalled: false };
|
|
216
|
-
|
|
313
|
+
p.onOrderNotification(() => __awaiter(this, void 0, void 0, function* () {
|
|
217
314
|
throw new Error('handler 1 boom');
|
|
218
315
|
}));
|
|
219
|
-
|
|
316
|
+
p.onOrderNotification(() => __awaiter(this, void 0, void 0, function* () {
|
|
220
317
|
callState.secondCalled = true;
|
|
221
318
|
throw new Error('handler 2 boom');
|
|
222
319
|
}));
|
|
223
320
|
let caught;
|
|
224
321
|
try {
|
|
225
|
-
yield
|
|
322
|
+
yield p.dispatchOrderNotification({
|
|
226
323
|
notificationType: 'ordercompleted',
|
|
227
324
|
eventDateTime: brand('2026-05-09T00:00:00Z'),
|
|
228
325
|
transactionId: brand('tx-3'),
|
|
@@ -237,6 +334,12 @@ function run() {
|
|
|
237
334
|
assert('aggregate error thrown', caught instanceof netomnia_provider_1.AggregateNotificationError);
|
|
238
335
|
assert('2 underlying errors', caught instanceof netomnia_provider_1.AggregateNotificationError && caught.errors.length === 2);
|
|
239
336
|
}
|
|
337
|
+
console.log('Test: NetomniaProvider implements WholesaleProvider (compile-time)');
|
|
338
|
+
{
|
|
339
|
+
const { deps } = buildDeps();
|
|
340
|
+
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
341
|
+
assert('class instantiates', p instanceof netomnia_provider_1.NetomniaProvider);
|
|
342
|
+
}
|
|
240
343
|
console.log('\n────────────────────────────────────────');
|
|
241
344
|
console.log(`Tests: ${passed} passed, ${failed} failed`);
|
|
242
345
|
if (failed > 0) {
|