@inno-isw/react-native-rtp 0.0.0-stage → 0.2.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/LICENSE +20 -0
- package/README.md +385 -2
- package/lib/module/client.js +391 -0
- package/lib/module/client.js.map +1 -0
- package/lib/module/constants.js +49 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/emitter.js +46 -0
- package/lib/module/emitter.js.map +1 -0
- package/lib/module/index.js +16 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/mock/makeRtpPayload.js +54 -0
- package/lib/module/mock/makeRtpPayload.js.map +1 -0
- package/lib/module/mock/mockTransport.js +89 -0
- package/lib/module/mock/mockTransport.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/push.js +96 -0
- package/lib/module/push.js.map +1 -0
- package/lib/module/react/RtpProvider.js +152 -0
- package/lib/module/react/RtpProvider.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/validate.js +122 -0
- package/lib/module/validate.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/client.d.ts +20 -0
- package/lib/typescript/src/client.d.ts.map +1 -0
- package/lib/typescript/src/constants.d.ts +50 -0
- package/lib/typescript/src/constants.d.ts.map +1 -0
- package/lib/typescript/src/emitter.d.ts +15 -0
- package/lib/typescript/src/emitter.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +14 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/mock/makeRtpPayload.d.ts +17 -0
- package/lib/typescript/src/mock/makeRtpPayload.d.ts.map +1 -0
- package/lib/typescript/src/mock/mockTransport.d.ts +35 -0
- package/lib/typescript/src/mock/mockTransport.d.ts.map +1 -0
- package/lib/typescript/src/push.d.ts +41 -0
- package/lib/typescript/src/push.d.ts.map +1 -0
- package/lib/typescript/src/react/RtpProvider.d.ts +60 -0
- package/lib/typescript/src/react/RtpProvider.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +153 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/validate.d.ts +33 -0
- package/lib/typescript/src/validate.d.ts.map +1 -0
- package/package.json +141 -4
- package/src/client.ts +428 -0
- package/src/constants.ts +54 -0
- package/src/emitter.ts +53 -0
- package/src/index.tsx +45 -0
- package/src/mock/makeRtpPayload.ts +69 -0
- package/src/mock/mockTransport.ts +119 -0
- package/src/push.ts +109 -0
- package/src/react/RtpProvider.tsx +235 -0
- package/src/types.ts +172 -0
- package/src/validate.ts +141 -0
package/src/validate.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { RtpParty, RtpPayload, RtpRequest } from './types';
|
|
2
|
+
|
|
3
|
+
/** Required top-level fields for a valid RTP payload. */
|
|
4
|
+
const REQUIRED_FIELDS = [
|
|
5
|
+
'rtpId',
|
|
6
|
+
'amount',
|
|
7
|
+
'currency',
|
|
8
|
+
'payer',
|
|
9
|
+
'payee',
|
|
10
|
+
'expiresAt',
|
|
11
|
+
] as const;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Type guard for RTP payloads.
|
|
15
|
+
*
|
|
16
|
+
* NOTE: this intentionally inspects the *decoded* payload, not a push
|
|
17
|
+
* envelope. Hosts are responsible for extracting the payload from their own
|
|
18
|
+
* notification system first.
|
|
19
|
+
*
|
|
20
|
+
* `amount` is accepted as either a number (minor units) or a numeric string,
|
|
21
|
+
* because push payloads frequently stringify scalars in transit.
|
|
22
|
+
*/
|
|
23
|
+
export function isRtpPayload(payload: unknown): payload is RtpPayload {
|
|
24
|
+
if (!payload || typeof payload !== 'object') {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const candidate = payload as Record<string, unknown>;
|
|
28
|
+
return candidate.type === 'RTP' && typeof candidate.rtpId === 'string';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns the list of missing/invalid required fields. Empty array means the
|
|
33
|
+
* payload is structurally valid.
|
|
34
|
+
*/
|
|
35
|
+
export function findValidationErrors(payload: RtpPayload): string[] {
|
|
36
|
+
const errors: string[] = [];
|
|
37
|
+
const record = payload as unknown as Record<string, unknown>;
|
|
38
|
+
|
|
39
|
+
for (const field of REQUIRED_FIELDS) {
|
|
40
|
+
if (record[field] === undefined || record[field] === null) {
|
|
41
|
+
errors.push(field);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (
|
|
46
|
+
payload.expiresAt !== undefined &&
|
|
47
|
+
Number.isNaN(new Date(payload.expiresAt).getTime())
|
|
48
|
+
) {
|
|
49
|
+
errors.push('expiresAt');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (const side of ['payer', 'payee'] as const) {
|
|
53
|
+
const party = payload[side] as RtpParty | undefined;
|
|
54
|
+
if (!party || typeof party !== 'object' || typeof party.name !== 'string') {
|
|
55
|
+
errors.push(`${side}.name`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return errors;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Coerce an amount that may arrive as a number or numeric string. */
|
|
63
|
+
function toAmount(value: unknown): number {
|
|
64
|
+
if (typeof value === 'number') {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
const parsed = Number(value);
|
|
68
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Map a validated payload into the normalized request held by the SDK. */
|
|
72
|
+
export function toRtpRequest(payload: RtpPayload): RtpRequest {
|
|
73
|
+
return {
|
|
74
|
+
id: payload.rtpId,
|
|
75
|
+
amount: toAmount(payload.amount),
|
|
76
|
+
currency: payload.currency,
|
|
77
|
+
payer: payload.payer,
|
|
78
|
+
payee: payload.payee,
|
|
79
|
+
narration: payload.narration,
|
|
80
|
+
transactionRef: payload.transactionRef,
|
|
81
|
+
orderNumber: payload.orderNumber,
|
|
82
|
+
deepLink: payload.deepLink,
|
|
83
|
+
actionMessage: payload.actionMessage,
|
|
84
|
+
expiresAt: payload.expiresAt,
|
|
85
|
+
recipient: payload.recipient,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Build a partial-request patch from an incoming payload, copying only the
|
|
91
|
+
* fields that are actually present. Used to overlay retrieved backend details
|
|
92
|
+
* without a partial response erasing data already held from the push.
|
|
93
|
+
*/
|
|
94
|
+
export function toRequestPatch(
|
|
95
|
+
payload: Partial<RtpPayload>
|
|
96
|
+
): Partial<RtpRequest> {
|
|
97
|
+
const patch: Partial<RtpRequest> = {};
|
|
98
|
+
if (payload.rtpId !== undefined) patch.id = payload.rtpId;
|
|
99
|
+
if (payload.amount !== undefined) patch.amount = toAmount(payload.amount);
|
|
100
|
+
if (payload.currency !== undefined) patch.currency = payload.currency;
|
|
101
|
+
if (payload.payer !== undefined) patch.payer = payload.payer;
|
|
102
|
+
if (payload.payee !== undefined) patch.payee = payload.payee;
|
|
103
|
+
if (payload.narration !== undefined) patch.narration = payload.narration;
|
|
104
|
+
if (payload.transactionRef !== undefined)
|
|
105
|
+
patch.transactionRef = payload.transactionRef;
|
|
106
|
+
if (payload.orderNumber !== undefined)
|
|
107
|
+
patch.orderNumber = payload.orderNumber;
|
|
108
|
+
if (payload.deepLink !== undefined) patch.deepLink = payload.deepLink;
|
|
109
|
+
if (payload.actionMessage !== undefined)
|
|
110
|
+
patch.actionMessage = payload.actionMessage;
|
|
111
|
+
if (payload.expiresAt !== undefined) patch.expiresAt = payload.expiresAt;
|
|
112
|
+
if (payload.recipient !== undefined) patch.recipient = payload.recipient;
|
|
113
|
+
return patch;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Overlay a patch onto an existing request. Only defined, non-null values are
|
|
118
|
+
* copied so a partial response never erases information already held.
|
|
119
|
+
*/
|
|
120
|
+
export function mergeRequest(
|
|
121
|
+
current: RtpRequest,
|
|
122
|
+
patch: Partial<RtpRequest>
|
|
123
|
+
): RtpRequest {
|
|
124
|
+
const next: RtpRequest = { ...current };
|
|
125
|
+
for (const key of Object.keys(patch) as (keyof RtpRequest)[]) {
|
|
126
|
+
const value = patch[key];
|
|
127
|
+
if (value !== undefined && value !== null) {
|
|
128
|
+
(next as any)[key] = value;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return next;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Pure expiry check. Re-evaluated on every transition, not just on receive. */
|
|
135
|
+
export function isExpired(request: RtpRequest, now: number): boolean {
|
|
136
|
+
const expiry = new Date(request.expiresAt).getTime();
|
|
137
|
+
if (Number.isNaN(expiry)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
return expiry <= now;
|
|
141
|
+
}
|