@ontemper/sdk 0.5.1 → 0.6.0
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 +28 -4
- package/dist/As2.d.ts +158 -0
- package/dist/As2.d.ts.map +1 -0
- package/dist/As2.js +529 -0
- package/dist/As2.js.map +1 -0
- package/dist/As2Destination.d.ts +10 -0
- package/dist/As2Destination.d.ts.map +1 -0
- package/dist/As2Destination.js +63 -0
- package/dist/As2Destination.js.map +1 -0
- package/dist/As2Error.d.ts +19 -0
- package/dist/As2Error.d.ts.map +1 -0
- package/dist/As2Error.js +16 -0
- package/dist/As2Error.js.map +1 -0
- package/dist/As2Route.d.ts +13 -0
- package/dist/As2Route.d.ts.map +1 -0
- package/dist/As2Route.js +13 -0
- package/dist/As2Route.js.map +1 -0
- package/dist/As2Testing.d.ts +78 -0
- package/dist/As2Testing.d.ts.map +1 -0
- package/dist/As2Testing.js +355 -0
- package/dist/As2Testing.js.map +1 -0
- package/dist/As2Transport.d.ts +30 -0
- package/dist/As2Transport.d.ts.map +1 -0
- package/dist/As2Transport.js +88 -0
- package/dist/As2Transport.js.map +1 -0
- package/dist/As2Wire.d.ts +338 -0
- package/dist/As2Wire.d.ts.map +1 -0
- package/dist/As2Wire.js +202 -0
- package/dist/As2Wire.js.map +1 -0
- package/dist/HttpClient.d.ts +19 -0
- package/dist/HttpClient.d.ts.map +1 -1
- package/dist/HttpClient.js +10 -5
- package/dist/HttpClient.js.map +1 -1
- package/dist/Manifest.d.ts +1 -1
- package/dist/Manifest.js +1 -1
- package/dist/Middleware.d.ts.map +1 -1
- package/dist/Middleware.js +49 -14
- package/dist/Middleware.js.map +1 -1
- package/dist/Workflow.d.ts.map +1 -1
- package/dist/Workflow.js +15 -2
- package/dist/Workflow.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +10 -2
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { lookup } from 'node:dns/promises';
|
|
2
|
+
import { BlockList, isIP } from 'node:net';
|
|
3
|
+
export const lookupAllAddresses = async (hostname) => (await lookup(hostname, { all: true, order: 'verbatim' })).map(({ address }) => address);
|
|
4
|
+
// The same special-use registry as apps/api/src/Infrastructure/Http/Client/PublicEndpoint.ts, which
|
|
5
|
+
// checks at claim time; scripts/check-sdk-consistency.ts fails CI when the lists drift.
|
|
6
|
+
// IPv4-mapped IPv6 falls outside 2000::/3 below.
|
|
7
|
+
const SPECIAL_USE = new BlockList();
|
|
8
|
+
for (const [network, prefix] of [
|
|
9
|
+
['0.0.0.0', 8],
|
|
10
|
+
['10.0.0.0', 8],
|
|
11
|
+
['100.64.0.0', 10],
|
|
12
|
+
['127.0.0.0', 8],
|
|
13
|
+
['169.254.0.0', 16],
|
|
14
|
+
['172.16.0.0', 12],
|
|
15
|
+
['192.0.0.0', 24],
|
|
16
|
+
['192.0.2.0', 24],
|
|
17
|
+
['192.31.196.0', 24],
|
|
18
|
+
['192.52.193.0', 24],
|
|
19
|
+
['192.88.99.0', 24],
|
|
20
|
+
['192.168.0.0', 16],
|
|
21
|
+
['192.175.48.0', 24],
|
|
22
|
+
['198.18.0.0', 15],
|
|
23
|
+
['198.51.100.0', 24],
|
|
24
|
+
['203.0.113.0', 24],
|
|
25
|
+
['224.0.0.0', 4],
|
|
26
|
+
['240.0.0.0', 4],
|
|
27
|
+
]) {
|
|
28
|
+
SPECIAL_USE.addSubnet(network, prefix, 'ipv4');
|
|
29
|
+
}
|
|
30
|
+
for (const [network, prefix] of [
|
|
31
|
+
['2001::', 23],
|
|
32
|
+
['2001:db8::', 32],
|
|
33
|
+
['2002::', 16],
|
|
34
|
+
['2620:4f:8000::', 48],
|
|
35
|
+
['3fff::', 20],
|
|
36
|
+
]) {
|
|
37
|
+
SPECIAL_USE.addSubnet(network, prefix, 'ipv6');
|
|
38
|
+
}
|
|
39
|
+
const GLOBAL_UNICAST_IPV6 = new BlockList();
|
|
40
|
+
GLOBAL_UNICAST_IPV6.addSubnet('2000::', 3, 'ipv6');
|
|
41
|
+
/** Only global unicast addresses pass: loopback, private, link-local, metadata, and mapped forms fail. */
|
|
42
|
+
export const isPublicAddress = (address) => {
|
|
43
|
+
const family = isIP(address);
|
|
44
|
+
if (family === 4)
|
|
45
|
+
return !SPECIAL_USE.check(address, 'ipv4');
|
|
46
|
+
if (family === 6)
|
|
47
|
+
return GLOBAL_UNICAST_IPV6.check(address, 'ipv6') && !SPECIAL_USE.check(address, 'ipv6');
|
|
48
|
+
return false;
|
|
49
|
+
};
|
|
50
|
+
/** The addresses a host reaches when every one is public; `undefined` for a private, reserved, or unresolved host. */
|
|
51
|
+
export const publicAddressesOf = async (host, lookupAddresses) => {
|
|
52
|
+
const bare = host.replace(/^\[|\]$/g, '');
|
|
53
|
+
if (isIP(bare) !== 0)
|
|
54
|
+
return isPublicAddress(bare) ? [bare] : undefined;
|
|
55
|
+
const lower = bare.toLowerCase().replace(/\.$/, '');
|
|
56
|
+
if (lower === 'localhost' || lower.endsWith('.localhost'))
|
|
57
|
+
return undefined;
|
|
58
|
+
const addresses = await lookupAddresses(bare);
|
|
59
|
+
return addresses.length > 0 && addresses.every(isPublicAddress) ? addresses : undefined;
|
|
60
|
+
};
|
|
61
|
+
/** An IP literal must be public; a name passes only when every address it resolves to is public. */
|
|
62
|
+
export const isPublicDestination = async (host, lookupAddresses) => (await publicAddressesOf(host, lookupAddresses)) !== undefined;
|
|
63
|
+
//# sourceMappingURL=As2Destination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"As2Destination.js","sourceRoot":"","sources":["../src/As2Destination.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
declare const As2Error_base: Schema.Class<As2Error, Schema.TaggedStruct<"As2Error", {
|
|
3
|
+
readonly operation: Schema.Literals<readonly ["receive", "acknowledge", "send", "confirm", "deliverMdn"]>;
|
|
4
|
+
readonly code: Schema.String;
|
|
5
|
+
readonly retryable: Schema.Boolean;
|
|
6
|
+
readonly status: Schema.optional<Schema.Number>;
|
|
7
|
+
readonly message: Schema.String;
|
|
8
|
+
}>, import("effect/Cause").YieldableError>;
|
|
9
|
+
/**
|
|
10
|
+
* An AS2 call failed. `code` is the platform error code (`DECRYPT_FAILED`, `ENGINE_BUSY`, …) or an SDK code
|
|
11
|
+
* (`NOT_CONFIGURED`, `DELIVERY_FAILED`, `MDN_MISSING`, …); `status` is the HTTP status behind it, when one exists;
|
|
12
|
+
* `retryable` says whether the same call may succeed later. The message never quotes a URL path, a credential, or
|
|
13
|
+
* the document, and the error carries no `cause`: a transport error quotes the URL and the request.
|
|
14
|
+
*/
|
|
15
|
+
export declare class As2Error extends As2Error_base {
|
|
16
|
+
}
|
|
17
|
+
export type As2Operation = As2Error['operation'];
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=As2Error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"As2Error.d.ts","sourceRoot":"","sources":["../src/As2Error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;;;;;AAEhC;;;;;GAKG;AACH,qBAAa,QAAS,SAAQ,aAM5B;CAAG;AAEL,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC"}
|
package/dist/As2Error.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
/**
|
|
3
|
+
* An AS2 call failed. `code` is the platform error code (`DECRYPT_FAILED`, `ENGINE_BUSY`, …) or an SDK code
|
|
4
|
+
* (`NOT_CONFIGURED`, `DELIVERY_FAILED`, `MDN_MISSING`, …); `status` is the HTTP status behind it, when one exists;
|
|
5
|
+
* `retryable` says whether the same call may succeed later. The message never quotes a URL path, a credential, or
|
|
6
|
+
* the document, and the error carries no `cause`: a transport error quotes the URL and the request.
|
|
7
|
+
*/
|
|
8
|
+
export class As2Error extends Schema.TaggedError()('As2Error', {
|
|
9
|
+
operation: Schema.Literals(['receive', 'acknowledge', 'send', 'confirm', 'deliverMdn']),
|
|
10
|
+
code: Schema.String,
|
|
11
|
+
retryable: Schema.Boolean,
|
|
12
|
+
status: Schema.optional(Schema.Number),
|
|
13
|
+
message: Schema.String,
|
|
14
|
+
}) {
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=As2Error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"As2Error.js","sourceRoot":"","sources":["../src/As2Error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,OAAO,QAAS,SAAQ,MAAM,CAAC,WAAW,EAAY,CAAC,UAAU,EAAE;IACvE,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACvF,IAAI,EAAE,MAAM,CAAC,MAAM;IACnB,SAAS,EAAE,MAAM,CAAC,OAAO;IACzB,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CAAC;CAAG"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
declare const As2Route_base: Context.ServiceClass<As2Route, "@temper/workflow/As2Route", boolean>;
|
|
3
|
+
/**
|
|
4
|
+
* Marks an endpoint that a trading partner posts AS2 to (`/as2/inbound`, `/as2/mdn`): `.annotate(As2Route, true)`.
|
|
5
|
+
* Its requests log as legacy `as2Endpoint` logged them, on a fresh trace, also when the gateway does not admit one
|
|
6
|
+
* as AS2 because a header is missing.
|
|
7
|
+
*/
|
|
8
|
+
export declare class As2Route extends As2Route_base {
|
|
9
|
+
}
|
|
10
|
+
/** `<METHOD> <path>` of every endpoint marked `As2Route`; `workflow()` provides it. */
|
|
11
|
+
export declare const As2RouteKeys: Context.Reference<ReadonlySet<string>>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=As2Route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"As2Route.d.ts","sourceRoot":"","sources":["../src/As2Route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;;AAEjC;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,aAAiE;CAAG;AAElG,uFAAuF;AACvF,eAAO,MAAM,YAAY,wCAEvB,CAAC"}
|
package/dist/As2Route.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
/**
|
|
3
|
+
* Marks an endpoint that a trading partner posts AS2 to (`/as2/inbound`, `/as2/mdn`): `.annotate(As2Route, true)`.
|
|
4
|
+
* Its requests log as legacy `as2Endpoint` logged them, on a fresh trace, also when the gateway does not admit one
|
|
5
|
+
* as AS2 because a header is missing.
|
|
6
|
+
*/
|
|
7
|
+
export class As2Route extends Context.Service()('@temper/workflow/As2Route') {
|
|
8
|
+
}
|
|
9
|
+
/** `<METHOD> <path>` of every endpoint marked `As2Route`; `workflow()` provides it. */
|
|
10
|
+
export const As2RouteKeys = Context.Reference('@temper/workflow/As2RouteKeys', {
|
|
11
|
+
defaultValue: () => new Set(),
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=As2Route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"As2Route.js","sourceRoot":"","sources":["../src/As2Route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC;;;;GAIG;AACH,MAAM,OAAO,QAAS,SAAQ,OAAO,CAAC,OAAO,EAAqB,CAAC,2BAA2B,CAAC;CAAG;AAElG,uFAAuF;AACvF,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAAsB,+BAA+B,EAAE;IAClG,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE;CAC9B,CAAC,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type Layer } from 'effect';
|
|
2
|
+
import type { HttpClient } from 'effect/http';
|
|
3
|
+
import { As2, type As2Mdn } from './As2.js';
|
|
4
|
+
import type { OutboundFetch } from './HttpClient.js';
|
|
5
|
+
/** How a memory partner answers one delivery. */
|
|
6
|
+
export interface MemoryAs2PartnerOptions {
|
|
7
|
+
/** HTTP status of the answer. Default 200. */
|
|
8
|
+
readonly status?: number;
|
|
9
|
+
/** The disposition its MDN reports. Default `automatic-action/MDN-sent-automatically; processed`. */
|
|
10
|
+
readonly disposition?: string;
|
|
11
|
+
/** Answer 200 without the MDN a sync partner owes. */
|
|
12
|
+
readonly omitMdn?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** One envelope a memory partner received. */
|
|
15
|
+
export interface MemoryAs2Delivery {
|
|
16
|
+
readonly url: string;
|
|
17
|
+
readonly messageId: string;
|
|
18
|
+
/** The document: the memory engine does not encrypt, so the envelope is the payload. */
|
|
19
|
+
readonly payload: Uint8Array;
|
|
20
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
21
|
+
}
|
|
22
|
+
/** One platform call the client made. */
|
|
23
|
+
export interface MemoryAs2Call {
|
|
24
|
+
readonly path: string;
|
|
25
|
+
/** The bearer credential it sent. */
|
|
26
|
+
readonly token: string | undefined;
|
|
27
|
+
}
|
|
28
|
+
export interface MemoryAs2Options {
|
|
29
|
+
/** The `UNNBOUND_API_URL` the workflow config names. Default `https://api.example.invalid`. */
|
|
30
|
+
readonly apiUrl?: string;
|
|
31
|
+
/** Answers every request that is not to the AS2 API or a registered partner. Default: reject. */
|
|
32
|
+
readonly fetch?: OutboundFetch;
|
|
33
|
+
/** Host → the addresses its name resolves to, for the async-MDN destination check. Default: one public address. */
|
|
34
|
+
readonly addresses?: Readonly<Record<string, ReadonlyArray<string>>>;
|
|
35
|
+
/**
|
|
36
|
+
* The runtime the client acts as. `bun` applies partner TLS and proxies as `fetch` options and pins an async MDN
|
|
37
|
+
* to the checked address, so `fetch` sees the address URL. Default: `fetch`, whatever runs the test.
|
|
38
|
+
*/
|
|
39
|
+
readonly runtime?: 'bun' | 'fetch';
|
|
40
|
+
}
|
|
41
|
+
export interface MemoryAs2 {
|
|
42
|
+
/** Pass as `testPlatform({ fetch })`: it answers the AS2 API, registered partners, and `options.fetch`. */
|
|
43
|
+
readonly fetch: OutboundFetch;
|
|
44
|
+
/** Provide in place of `As2.layer`, so the async-MDN destination check reads `options.addresses`. */
|
|
45
|
+
readonly layer: Layer.Layer<As2, never, HttpClient.HttpClient>;
|
|
46
|
+
/** Serves a partner at `url` that answers each envelope by the receipt it asks for. */
|
|
47
|
+
readonly partner: (url: string, options?: MemoryAs2PartnerOptions) => void;
|
|
48
|
+
/** A partner's AS2 POST of `payload` to a workflow route, as the gateway forwards it. */
|
|
49
|
+
readonly inboundRequest: (options: {
|
|
50
|
+
readonly url: string;
|
|
51
|
+
readonly from: string;
|
|
52
|
+
readonly to: string;
|
|
53
|
+
readonly payload: Uint8Array | string;
|
|
54
|
+
readonly messageId?: string;
|
|
55
|
+
readonly contentType?: string;
|
|
56
|
+
/** Ask for an async receipt at this URL instead of a sync one. */
|
|
57
|
+
readonly receiptUrl?: string;
|
|
58
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
59
|
+
}) => Request;
|
|
60
|
+
/** The signed receipt a partner sends for a packed message, for an async-MDN route test. */
|
|
61
|
+
readonly mdnFor: (messageId: string, disposition?: string) => As2Mdn;
|
|
62
|
+
/** Inbound message ids the memory engine parks instead of claiming. */
|
|
63
|
+
readonly park: (messageId: string) => void;
|
|
64
|
+
readonly deliveries: Array<MemoryAs2Delivery>;
|
|
65
|
+
/** Receipts posted to async-MDN URLs, with the URL. */
|
|
66
|
+
readonly mdns: Array<As2Mdn & {
|
|
67
|
+
readonly url: string;
|
|
68
|
+
}>;
|
|
69
|
+
readonly calls: Array<MemoryAs2Call>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* An in-memory AS2 platform and partner for workflow tests: the SDK client runs unchanged on top of it, so the
|
|
73
|
+
* Run token, retries, outcomes, span lines, and redaction behave as in production. It keeps the platform's ledger
|
|
74
|
+
* rules (duplicates, in-flight claims, idempotent packs, receipt settlement) but runs no crypto: an envelope is the
|
|
75
|
+
* document, and a receipt is plain text that names its message, disposition, and MIC.
|
|
76
|
+
*/
|
|
77
|
+
export declare const memoryAs2: (options?: MemoryAs2Options) => MemoryAs2;
|
|
78
|
+
//# sourceMappingURL=As2Testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"As2Testing.d.ts","sourceRoot":"","sources":["../src/As2Testing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { Option, Predicate, Schema } from 'effect';
|
|
3
|
+
import { As2, unquoteAs2Id } from './As2.js';
|
|
4
|
+
const PROCESSED = 'automatic-action/MDN-sent-automatically; processed';
|
|
5
|
+
const MDN_TYPE = 'multipart/report; report-type=disposition-notification; boundary=memory-as2';
|
|
6
|
+
const ENVELOPE_TYPE = 'application/pkcs7-mime; smime-type=enveloped-data';
|
|
7
|
+
// The request bodies of apps/api/src/Platform/As2/Domain.ts, as far as the memory engine reads them.
|
|
8
|
+
const Parties = {
|
|
9
|
+
partner: Schema.Struct({
|
|
10
|
+
as2Id: Schema.String,
|
|
11
|
+
url: Schema.optional(Schema.NullOr(Schema.String)),
|
|
12
|
+
receipt: Schema.optional(Schema.Literals(['none', 'sync', 'async'])),
|
|
13
|
+
}),
|
|
14
|
+
identity: Schema.Struct({ as2Id: Schema.String }),
|
|
15
|
+
};
|
|
16
|
+
const Optional = Schema.optional(Schema.NullOr(Schema.String));
|
|
17
|
+
const ReceiveBody = Schema.Struct({
|
|
18
|
+
...Parties,
|
|
19
|
+
headers: Schema.Record(Schema.String, Schema.String),
|
|
20
|
+
bodyB64: Schema.String,
|
|
21
|
+
});
|
|
22
|
+
const AcknowledgeBody = Schema.Struct({ deliveryToken: Schema.String });
|
|
23
|
+
const PackBody = Schema.Struct({
|
|
24
|
+
...Parties,
|
|
25
|
+
payloadB64: Schema.String,
|
|
26
|
+
payloadContentType: Schema.optional(Schema.String),
|
|
27
|
+
subject: Optional,
|
|
28
|
+
idempotencyKey: Optional,
|
|
29
|
+
receiptUrl: Optional,
|
|
30
|
+
});
|
|
31
|
+
const ConfirmBody = Schema.Struct({ originalMessageId: Optional, mdnBodyB64: Schema.String });
|
|
32
|
+
const SettleBody = Schema.Struct({ messageId: Schema.String });
|
|
33
|
+
const decode = (schema) => (text) => Schema.decodeUnknownOption(Schema.fromJsonString(schema))(text);
|
|
34
|
+
const micOf = (bytes) => `${createHash('sha256').update(bytes).digest('base64')}, sha-256`;
|
|
35
|
+
const b64 = (bytes) => Buffer.from(bytes).toString('base64');
|
|
36
|
+
const lower = (headers) => Object.fromEntries(Object.entries(headers).map(([name, value]) => [name.toLowerCase(), value]));
|
|
37
|
+
const json = (body, status = 200) => new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });
|
|
38
|
+
const failure = (status, code, message) => json({ error: { code, message } }, status);
|
|
39
|
+
const unparseable = () => failure(400, 'BAD_REQUEST', 'unparseable request body');
|
|
40
|
+
const headersOf = (init) => init.headers instanceof Headers
|
|
41
|
+
? Object.fromEntries(init.headers.entries())
|
|
42
|
+
: Array.isArray(init.headers)
|
|
43
|
+
? Object.fromEntries(init.headers)
|
|
44
|
+
: lower({ ...(init.headers ?? {}) });
|
|
45
|
+
const bodyOf = async (init) => new Uint8Array(await new Response(init.body ?? null).arrayBuffer());
|
|
46
|
+
const mdnBody = (messageId, mic, disposition) => `Original-Message-ID: ${messageId}\r\nDisposition: ${disposition}\r\nReceived-Content-MIC: ${mic}\r\n`;
|
|
47
|
+
// The platform ledger's receipt rules (apps/api/src/Platform/As2/Ledger.ts): `processed`, with or without a warning.
|
|
48
|
+
const successfulDisposition = (disposition) => disposition !== null && /;\s*processed(?:\s*\/\s*warning(?::.*)?)?\s*$/u.test(disposition.trim().toLowerCase());
|
|
49
|
+
/** Digest exact, algorithm token folded: `sha-256`, `SHA256`, and `sha_256` are one algorithm. */
|
|
50
|
+
const micsMatch = (left, right) => {
|
|
51
|
+
const split = (value) => {
|
|
52
|
+
const comma = value.lastIndexOf(',');
|
|
53
|
+
return comma === -1
|
|
54
|
+
? undefined
|
|
55
|
+
: {
|
|
56
|
+
digest: value.slice(0, comma).trim(),
|
|
57
|
+
algorithm: value
|
|
58
|
+
.slice(comma + 1)
|
|
59
|
+
.toLowerCase()
|
|
60
|
+
.replace(/[^a-z0-9]/gu, ''),
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
const a = split(left);
|
|
64
|
+
const b = split(right);
|
|
65
|
+
return a === undefined || b === undefined
|
|
66
|
+
? left.trim() === right.trim()
|
|
67
|
+
: a.digest === b.digest && a.algorithm === b.algorithm;
|
|
68
|
+
};
|
|
69
|
+
const fieldOf = (text, name) => new RegExp(`^${name}:\\s*(.+?)\\s*$`, 'imu').exec(text)?.[1] ?? null;
|
|
70
|
+
/**
|
|
71
|
+
* An in-memory AS2 platform and partner for workflow tests: the SDK client runs unchanged on top of it, so the
|
|
72
|
+
* Run token, retries, outcomes, span lines, and redaction behave as in production. It keeps the platform's ledger
|
|
73
|
+
* rules (duplicates, in-flight claims, idempotent packs, receipt settlement) but runs no crypto: an envelope is the
|
|
74
|
+
* document, and a receipt is plain text that names its message, disposition, and MIC.
|
|
75
|
+
*/
|
|
76
|
+
export const memoryAs2 = (options = {}) => {
|
|
77
|
+
const apiUrl = (options.apiUrl ?? 'https://api.example.invalid').replace(/\/+$/u, '');
|
|
78
|
+
const partners = new Map();
|
|
79
|
+
const outbound = new Map();
|
|
80
|
+
const byKey = new Map();
|
|
81
|
+
const inbound = new Map();
|
|
82
|
+
const tokens = new Map();
|
|
83
|
+
const parked = new Set();
|
|
84
|
+
const deliveries = [];
|
|
85
|
+
const mdns = [];
|
|
86
|
+
const calls = [];
|
|
87
|
+
let sequence = 0;
|
|
88
|
+
const nextId = (prefix) => `${prefix}-${++sequence}`;
|
|
89
|
+
const mdnOf = (from, to, messageId, mic, disposition) => ({
|
|
90
|
+
headers: {
|
|
91
|
+
'content-type': MDN_TYPE,
|
|
92
|
+
'as2-from': from,
|
|
93
|
+
'as2-to': to,
|
|
94
|
+
'message-id': `<${nextId('mdn')}@memory.as2>`,
|
|
95
|
+
},
|
|
96
|
+
body: new TextEncoder().encode(mdnBody(messageId, mic, disposition)),
|
|
97
|
+
});
|
|
98
|
+
const receive = (body) => {
|
|
99
|
+
const { partner, identity } = body;
|
|
100
|
+
const sent = lower(body.headers);
|
|
101
|
+
const messageId = sent['message-id'];
|
|
102
|
+
if (messageId === undefined)
|
|
103
|
+
return failure(422, 'MALFORMED_ENVELOPE', 'Message-ID is missing');
|
|
104
|
+
if (unquoteAs2Id(sent['as2-from']) !== partner.as2Id)
|
|
105
|
+
return failure(422, 'As2PartnerMismatchError', 'AS2-From does not match the partner');
|
|
106
|
+
if (unquoteAs2Id(sent['as2-to']) !== identity.as2Id)
|
|
107
|
+
return failure(422, 'As2PartnerMismatchError', 'AS2-To does not match the identity');
|
|
108
|
+
if (parked.has(messageId))
|
|
109
|
+
return json({ kind: 'parked', messageId });
|
|
110
|
+
const key = `${partner.as2Id}|${identity.as2Id}|${messageId}`;
|
|
111
|
+
const known = inbound.get(key);
|
|
112
|
+
if (known !== undefined && !known.acknowledged)
|
|
113
|
+
return json({ kind: 'inFlight', messageId });
|
|
114
|
+
if (known !== undefined) {
|
|
115
|
+
return json({
|
|
116
|
+
kind: 'duplicate',
|
|
117
|
+
messageId,
|
|
118
|
+
mic: known.mic,
|
|
119
|
+
mdnHeaders: known.mdn?.headers ?? null,
|
|
120
|
+
mdnBodyB64: known.mdn === null ? null : b64(known.mdn.body),
|
|
121
|
+
mdnMode: known.mdnMode,
|
|
122
|
+
mdnDeliveryUrl: known.mdnDeliveryUrl,
|
|
123
|
+
customerTraceId: known.customerTraceId,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const record = {
|
|
127
|
+
messageId,
|
|
128
|
+
from: partner.as2Id,
|
|
129
|
+
to: identity.as2Id,
|
|
130
|
+
payloadB64: body.bodyB64,
|
|
131
|
+
contentType: sent['content-type'] ?? null,
|
|
132
|
+
mic: micOf(Buffer.from(body.bodyB64, 'base64')),
|
|
133
|
+
mdnMode: sent['receipt-delivery-option'] === undefined ? 'sync' : 'async',
|
|
134
|
+
mdnDeliveryUrl: sent['receipt-delivery-option'] ?? null,
|
|
135
|
+
customerTraceId: crypto.randomUUID(),
|
|
136
|
+
mdn: null,
|
|
137
|
+
acknowledged: false,
|
|
138
|
+
};
|
|
139
|
+
inbound.set(key, record);
|
|
140
|
+
const deliveryToken = nextId('delivery');
|
|
141
|
+
tokens.set(deliveryToken, key);
|
|
142
|
+
return json({
|
|
143
|
+
kind: 'received',
|
|
144
|
+
messageId,
|
|
145
|
+
payloadB64: record.payloadB64,
|
|
146
|
+
payloadContentType: record.contentType,
|
|
147
|
+
mic: record.mic,
|
|
148
|
+
deliveryToken,
|
|
149
|
+
mdnMode: record.mdnMode,
|
|
150
|
+
customerTraceId: record.customerTraceId,
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
const acknowledge = (body) => {
|
|
154
|
+
const key = tokens.get(body.deliveryToken);
|
|
155
|
+
const record = key === undefined ? undefined : inbound.get(key);
|
|
156
|
+
if (record === undefined)
|
|
157
|
+
return failure(409, 'As2ClaimLostError', 'the delivery claim is unknown');
|
|
158
|
+
const already = record.acknowledged;
|
|
159
|
+
record.acknowledged = true;
|
|
160
|
+
record.mdn ??= mdnOf(record.to, record.from, record.messageId, record.mic, PROCESSED);
|
|
161
|
+
return json({
|
|
162
|
+
messageId: record.messageId,
|
|
163
|
+
mic: record.mic,
|
|
164
|
+
mdnHeaders: record.mdn.headers,
|
|
165
|
+
mdnBodyB64: b64(record.mdn.body),
|
|
166
|
+
mdnMode: record.mdnMode,
|
|
167
|
+
mdnDeliveryUrl: record.mdnDeliveryUrl,
|
|
168
|
+
alreadyAcknowledged: already,
|
|
169
|
+
customerTraceId: record.customerTraceId,
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
const packed = (body, receipt, contentType, fingerprint) => {
|
|
173
|
+
const messageId = `<${nextId('message')}@as2.ontemper.com>`;
|
|
174
|
+
const receiptHeaders = receipt === 'none'
|
|
175
|
+
? []
|
|
176
|
+
: [
|
|
177
|
+
['Disposition-Notification-To', body.identity.as2Id],
|
|
178
|
+
['Disposition-Notification-Options', 'signed-receipt-protocol=required, pkcs7-signature'],
|
|
179
|
+
];
|
|
180
|
+
const deliveryHeaders = receipt === 'async' && body.receiptUrl !== undefined && body.receiptUrl !== null
|
|
181
|
+
? [['Receipt-Delivery-Option', body.receiptUrl]]
|
|
182
|
+
: [];
|
|
183
|
+
return {
|
|
184
|
+
messageId,
|
|
185
|
+
mic: micOf(Buffer.from(body.payloadB64, 'base64')),
|
|
186
|
+
mdnMode: receipt,
|
|
187
|
+
fingerprint,
|
|
188
|
+
partner: body.partner.as2Id,
|
|
189
|
+
identity: body.identity.as2Id,
|
|
190
|
+
as2Headers: Object.fromEntries([
|
|
191
|
+
['AS2-From', body.identity.as2Id],
|
|
192
|
+
['AS2-To', body.partner.as2Id],
|
|
193
|
+
['AS2-Version', '1.2'],
|
|
194
|
+
['Message-ID', messageId],
|
|
195
|
+
['Content-Type', ENVELOPE_TYPE],
|
|
196
|
+
['X-Memory-As2-Content-Type', contentType],
|
|
197
|
+
...receiptHeaders,
|
|
198
|
+
...deliveryHeaders,
|
|
199
|
+
]),
|
|
200
|
+
payloadB64: body.payloadB64,
|
|
201
|
+
partnerUrl: body.partner.url ?? null,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
const pack = (body) => {
|
|
205
|
+
const receipt = body.partner.receipt ?? 'sync';
|
|
206
|
+
if (receipt === 'async' && (body.receiptUrl === undefined || body.receiptUrl === null))
|
|
207
|
+
return failure(422, 'As2ConfigError', `partner ${body.partner.as2Id} requests async receipts; receiptUrl is required`);
|
|
208
|
+
const contentType = body.payloadContentType ?? 'application/edi-x12';
|
|
209
|
+
const fingerprint = `${body.payloadB64}\0${contentType}\0${body.subject ?? ''}`;
|
|
210
|
+
// The platform scopes a key to the workflow, our identity, and the partner.
|
|
211
|
+
const idempotencyKey = body.idempotencyKey === undefined || body.idempotencyKey === null
|
|
212
|
+
? undefined
|
|
213
|
+
: `${body.identity.as2Id}|${body.partner.as2Id}|${body.idempotencyKey}`;
|
|
214
|
+
const replay = idempotencyKey === undefined ? undefined : outbound.get(byKey.get(idempotencyKey) ?? '');
|
|
215
|
+
if (replay !== undefined && replay.fingerprint !== fingerprint)
|
|
216
|
+
return failure(409, 'As2MessageConflictError', 'the idempotency key names another document');
|
|
217
|
+
const record = replay ?? packed(body, receipt, contentType, fingerprint);
|
|
218
|
+
outbound.set(record.messageId, record);
|
|
219
|
+
if (idempotencyKey !== undefined)
|
|
220
|
+
byKey.set(idempotencyKey, record.messageId);
|
|
221
|
+
return json({
|
|
222
|
+
messageId: record.messageId,
|
|
223
|
+
as2Headers: record.as2Headers,
|
|
224
|
+
envelopeBodyB64: record.payloadB64,
|
|
225
|
+
mic: record.mic,
|
|
226
|
+
partnerUrl: record.partnerUrl,
|
|
227
|
+
mdnMode: record.mdnMode,
|
|
228
|
+
replayed: replay !== undefined,
|
|
229
|
+
customerTraceId: null,
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
const confirm = (body) => {
|
|
233
|
+
const text = Buffer.from(body.mdnBodyB64, 'base64').toString('utf8');
|
|
234
|
+
const original = fieldOf(text, 'Original-Message-ID');
|
|
235
|
+
const record = original === null ? undefined : outbound.get(original);
|
|
236
|
+
if (record === undefined)
|
|
237
|
+
return failure(404, 'As2MessageNotFoundError', 'no outbound message matches the receipt');
|
|
238
|
+
if (body.originalMessageId !== undefined && body.originalMessageId !== null && body.originalMessageId !== original)
|
|
239
|
+
return failure(409, 'As2MessageConflictError', 'the receipt names another message');
|
|
240
|
+
const already = record.verdict !== undefined;
|
|
241
|
+
if (record.verdict === undefined) {
|
|
242
|
+
const disposition = fieldOf(text, 'Disposition');
|
|
243
|
+
const receivedMic = fieldOf(text, 'Received-Content-MIC');
|
|
244
|
+
const micMatched = receivedMic !== null && micsMatch(receivedMic, record.mic);
|
|
245
|
+
const outcome = micMatched && successfulDisposition(disposition) ? 'confirmed' : 'failed';
|
|
246
|
+
record.verdict = { outcome, disposition, receivedMic, micMatched };
|
|
247
|
+
}
|
|
248
|
+
return json({
|
|
249
|
+
...record.verdict,
|
|
250
|
+
messageId: record.messageId,
|
|
251
|
+
packMic: record.mic,
|
|
252
|
+
alreadyRecorded: already,
|
|
253
|
+
originatingTraceId: null,
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
const settle = (body) => {
|
|
257
|
+
const record = outbound.get(body.messageId);
|
|
258
|
+
if (record === undefined)
|
|
259
|
+
return failure(404, 'As2MessageNotFoundError', 'no outbound message has this id');
|
|
260
|
+
const already = record.verdict !== undefined;
|
|
261
|
+
record.verdict ??= { outcome: 'confirmed', disposition: null, receivedMic: null, micMatched: false };
|
|
262
|
+
return json({ outcome: 'confirmed', messageId: record.messageId, alreadyRecorded: already, customerTraceId: null });
|
|
263
|
+
};
|
|
264
|
+
const route = (path, text) => {
|
|
265
|
+
switch (path) {
|
|
266
|
+
case 'receive':
|
|
267
|
+
return Option.match(decode(ReceiveBody)(text), { onNone: unparseable, onSome: receive });
|
|
268
|
+
case 'acknowledge':
|
|
269
|
+
return Option.match(decode(AcknowledgeBody)(text), { onNone: unparseable, onSome: acknowledge });
|
|
270
|
+
case 'pack':
|
|
271
|
+
return Option.match(decode(PackBody)(text), { onNone: unparseable, onSome: pack });
|
|
272
|
+
case 'confirm':
|
|
273
|
+
return Option.match(decode(ConfirmBody)(text), { onNone: unparseable, onSome: confirm });
|
|
274
|
+
case 'settle-delivery':
|
|
275
|
+
return Option.match(decode(SettleBody)(text), { onNone: unparseable, onSome: settle });
|
|
276
|
+
default:
|
|
277
|
+
return failure(404, 'NOT_FOUND', `no AS2 route ${path}`);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const platform = (path, headers, text) => {
|
|
281
|
+
const token = /^Bearer (.+)$/u.exec(headers.authorization ?? '')?.[1];
|
|
282
|
+
calls.push({ path, token });
|
|
283
|
+
if (token === undefined)
|
|
284
|
+
return failure(401, 'UNAUTHORIZED', 'AS2 requires a workflow-scoped token');
|
|
285
|
+
return route(path, text);
|
|
286
|
+
};
|
|
287
|
+
const deliver = async (url, partnerOptions, headers, payload) => {
|
|
288
|
+
const messageId = headers['message-id'] ?? '';
|
|
289
|
+
deliveries.push({ url, messageId, payload, headers });
|
|
290
|
+
if ((partnerOptions.status ?? 200) >= 300)
|
|
291
|
+
return new Response('partner failure', { status: partnerOptions.status });
|
|
292
|
+
const record = outbound.get(messageId);
|
|
293
|
+
if (record === undefined || record.mdnMode !== 'sync' || partnerOptions.omitMdn === true)
|
|
294
|
+
return new Response(null, { status: partnerOptions.status ?? 200 });
|
|
295
|
+
const mdn = mdnOf(record.partner, record.identity, messageId, micOf(payload), partnerOptions.disposition ?? PROCESSED);
|
|
296
|
+
return new Response(Buffer.from(mdn.body), { status: 200, headers: mdn.headers });
|
|
297
|
+
};
|
|
298
|
+
const fetch = async (url, init) => {
|
|
299
|
+
const headers = headersOf(init);
|
|
300
|
+
const body = await bodyOf(init);
|
|
301
|
+
const prefix = `${apiUrl}/api/v2/internal/as2/`;
|
|
302
|
+
if (url.href.startsWith(prefix)) {
|
|
303
|
+
return platform(url.href.slice(prefix.length), headers, new TextDecoder().decode(body));
|
|
304
|
+
}
|
|
305
|
+
const partnerOptions = partners.get(url.href);
|
|
306
|
+
if (partnerOptions !== undefined)
|
|
307
|
+
return deliver(url.href, partnerOptions, headers, body);
|
|
308
|
+
if (headers['content-type']?.startsWith('multipart/report') === true) {
|
|
309
|
+
mdns.push({ url: url.href, headers, body });
|
|
310
|
+
return new Response(null, { status: 200 });
|
|
311
|
+
}
|
|
312
|
+
if (options.fetch !== undefined)
|
|
313
|
+
return options.fetch(url, init);
|
|
314
|
+
throw new Error(`Unexpected outbound request: ${init.method ?? 'GET'} ${url.href}`);
|
|
315
|
+
};
|
|
316
|
+
return {
|
|
317
|
+
fetch,
|
|
318
|
+
layer: As2.layerWith({
|
|
319
|
+
lookupAddresses: async (hostname) => options.addresses?.[hostname] ?? ['93.184.216.34'],
|
|
320
|
+
runtime: options.runtime ?? 'fetch',
|
|
321
|
+
}),
|
|
322
|
+
partner: (url, partnerOptions = {}) => {
|
|
323
|
+
partners.set(new URL(url).href, partnerOptions);
|
|
324
|
+
},
|
|
325
|
+
inboundRequest: (request) => {
|
|
326
|
+
const receipt = request.receiptUrl === undefined ? [] : [['receipt-delivery-option', request.receiptUrl]];
|
|
327
|
+
const headers = Object.fromEntries([
|
|
328
|
+
['content-type', request.contentType ?? 'application/edi-x12'],
|
|
329
|
+
['as2-from', request.from],
|
|
330
|
+
['as2-to', request.to],
|
|
331
|
+
['as2-version', '1.2'],
|
|
332
|
+
['message-id', request.messageId ?? `<${nextId('inbound')}@memory.as2>`],
|
|
333
|
+
['x-forwarded-proto', 'https'],
|
|
334
|
+
['disposition-notification-to', request.from],
|
|
335
|
+
...receipt,
|
|
336
|
+
...Object.entries(request.headers ?? {}),
|
|
337
|
+
]);
|
|
338
|
+
const body = Predicate.isString(request.payload) ? request.payload : Buffer.from(request.payload);
|
|
339
|
+
return new Request(request.url, { method: 'POST', headers, body });
|
|
340
|
+
},
|
|
341
|
+
mdnFor: (messageId, disposition = PROCESSED) => {
|
|
342
|
+
const record = outbound.get(messageId);
|
|
343
|
+
if (record === undefined)
|
|
344
|
+
throw new Error(`memoryAs2 has no outbound message ${messageId}`);
|
|
345
|
+
return mdnOf(record.partner, record.identity, messageId, record.mic, disposition);
|
|
346
|
+
},
|
|
347
|
+
park: (messageId) => {
|
|
348
|
+
parked.add(messageId);
|
|
349
|
+
},
|
|
350
|
+
deliveries,
|
|
351
|
+
mdns,
|
|
352
|
+
calls,
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
//# sourceMappingURL=As2Testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"As2Testing.js","sourceRoot":"","sources":["../src/As2Testing.ts"],"names":[],"mappings":"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"}
|