@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
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const extractId = path => {
|
|
4
|
+
const parts = path.split('/');
|
|
5
|
+
return parts[parts.length - 2] ?? '';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Deterministic in-memory transport. No real network calls are made.
|
|
10
|
+
*/
|
|
11
|
+
export function createMockTransport(options = {}) {
|
|
12
|
+
const {
|
|
13
|
+
latencyMs = 250,
|
|
14
|
+
failAccept = false,
|
|
15
|
+
failDecline = false,
|
|
16
|
+
failRetrieve = false,
|
|
17
|
+
acceptStatus = 'ACCEPTED',
|
|
18
|
+
retrieveStatus = 'READY',
|
|
19
|
+
retrieveRequest
|
|
20
|
+
} = options;
|
|
21
|
+
const calls = [];
|
|
22
|
+
const delay = () => new Promise(resolve => setTimeout(resolve, latencyMs));
|
|
23
|
+
const transport = {
|
|
24
|
+
async post(path, body, headers) {
|
|
25
|
+
calls.push({
|
|
26
|
+
method: 'post',
|
|
27
|
+
path,
|
|
28
|
+
body,
|
|
29
|
+
headers
|
|
30
|
+
});
|
|
31
|
+
await delay();
|
|
32
|
+
if (path.endsWith('/accept')) {
|
|
33
|
+
if (failAccept) {
|
|
34
|
+
throw new Error('Mock network failure on accept');
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
status: 200,
|
|
38
|
+
data: {
|
|
39
|
+
id: extractId(path),
|
|
40
|
+
status: acceptStatus
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (path.endsWith('/decline')) {
|
|
45
|
+
if (failDecline) {
|
|
46
|
+
throw new Error('Mock network failure on decline');
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
status: 200,
|
|
50
|
+
data: {
|
|
51
|
+
id: extractId(path),
|
|
52
|
+
status: 'DECLINED'
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
status: 200,
|
|
58
|
+
data: {}
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
async get(path, headers) {
|
|
62
|
+
calls.push({
|
|
63
|
+
method: 'get',
|
|
64
|
+
path,
|
|
65
|
+
headers
|
|
66
|
+
});
|
|
67
|
+
await delay();
|
|
68
|
+
if (failRetrieve) {
|
|
69
|
+
throw new Error('Mock network failure on retrieve');
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
status: 200,
|
|
73
|
+
data: {
|
|
74
|
+
id: extractId(path),
|
|
75
|
+
status: retrieveStatus,
|
|
76
|
+
request: retrieveRequest
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
transport,
|
|
83
|
+
calls,
|
|
84
|
+
reset: () => {
|
|
85
|
+
calls.length = 0;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=mockTransport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["extractId","path","parts","split","length","createMockTransport","options","latencyMs","failAccept","failDecline","failRetrieve","acceptStatus","retrieveStatus","retrieveRequest","calls","delay","Promise","resolve","setTimeout","transport","post","body","headers","push","method","endsWith","Error","status","data","id","get","request","reset"],"sourceRoot":"../../../src","sources":["mock/mockTransport.ts"],"mappings":";;AAkCA,MAAMA,SAAS,GAAIC,IAAY,IAAa;EAC1C,MAAMC,KAAK,GAAGD,IAAI,CAACE,KAAK,CAAC,GAAG,CAAC;EAC7B,OAAOD,KAAK,CAACA,KAAK,CAACE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE;AACtC,CAAC;;AAED;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CACjCC,OAA6B,GAAG,CAAC,CAAC,EACnB;EACf,MAAM;IACJC,SAAS,GAAG,GAAG;IACfC,UAAU,GAAG,KAAK;IAClBC,WAAW,GAAG,KAAK;IACnBC,YAAY,GAAG,KAAK;IACpBC,YAAY,GAAG,UAAU;IACzBC,cAAc,GAAG,OAAO;IACxBC;EACF,CAAC,GAAGP,OAAO;EAEX,MAAMQ,KAAqB,GAAG,EAAE;EAChC,MAAMC,KAAK,GAAGA,CAAA,KACZ,IAAIC,OAAO,CAAQC,OAAO,IAAKC,UAAU,CAACD,OAAO,EAAEV,SAAS,CAAC,CAAC;EAEhE,MAAMY,SAAuB,GAAG;IAC9B,MAAMC,IAAIA,CACRnB,IAAY,EACZoB,IAAc,EACdC,OAAgC,EACH;MAC7BR,KAAK,CAACS,IAAI,CAAC;QAAEC,MAAM,EAAE,MAAM;QAAEvB,IAAI;QAAEoB,IAAI;QAAEC;MAAQ,CAAC,CAAC;MACnD,MAAMP,KAAK,CAAC,CAAC;MAEb,IAAId,IAAI,CAACwB,QAAQ,CAAC,SAAS,CAAC,EAAE;QAC5B,IAAIjB,UAAU,EAAE;UACd,MAAM,IAAIkB,KAAK,CAAC,gCAAgC,CAAC;QACnD;QACA,OAAO;UACLC,MAAM,EAAE,GAAG;UACXC,IAAI,EAAE;YAAEC,EAAE,EAAE7B,SAAS,CAACC,IAAI,CAAC;YAAE0B,MAAM,EAAEhB;UAAa;QACpD,CAAC;MACH;MAEA,IAAIV,IAAI,CAACwB,QAAQ,CAAC,UAAU,CAAC,EAAE;QAC7B,IAAIhB,WAAW,EAAE;UACf,MAAM,IAAIiB,KAAK,CAAC,iCAAiC,CAAC;QACpD;QACA,OAAO;UACLC,MAAM,EAAE,GAAG;UACXC,IAAI,EAAE;YAAEC,EAAE,EAAE7B,SAAS,CAACC,IAAI,CAAC;YAAE0B,MAAM,EAAE;UAAW;QAClD,CAAC;MACH;MAEA,OAAO;QAAEA,MAAM,EAAE,GAAG;QAAEC,IAAI,EAAE,CAAC;MAAO,CAAC;IACvC,CAAC;IAED,MAAME,GAAGA,CACP7B,IAAY,EACZqB,OAAgC,EACH;MAC7BR,KAAK,CAACS,IAAI,CAAC;QAAEC,MAAM,EAAE,KAAK;QAAEvB,IAAI;QAAEqB;MAAQ,CAAC,CAAC;MAC5C,MAAMP,KAAK,CAAC,CAAC;MACb,IAAIL,YAAY,EAAE;QAChB,MAAM,IAAIgB,KAAK,CAAC,kCAAkC,CAAC;MACrD;MACA,OAAO;QACLC,MAAM,EAAE,GAAG;QACXC,IAAI,EAAE;UACJC,EAAE,EAAE7B,SAAS,CAACC,IAAI,CAAC;UACnB0B,MAAM,EAAEf,cAAc;UACtBmB,OAAO,EAAElB;QACX;MACF,CAAC;IACH;EACF,CAAC;EAED,OAAO;IACLM,SAAS;IACTL,KAAK;IACLkB,KAAK,EAAEA,CAAA,KAAM;MACXlB,KAAK,CAACV,MAAM,GAAG,CAAC;IAClB;EACF,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { isRtpPayload } from "./validate.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A generic push notification envelope.
|
|
7
|
+
*
|
|
8
|
+
* The SDK does not know or care what a push looks like — every host platform
|
|
9
|
+
* has a different shape, and this is the single seam where that difference is
|
|
10
|
+
* absorbed. A Kotlin/Swift integration implements the equivalent of
|
|
11
|
+
* `mapPushToRtp` against the same `RtpPayload` contract.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extract an RTP payload from a push envelope, or return null if the push is
|
|
16
|
+
* not an RTP request.
|
|
17
|
+
*
|
|
18
|
+
* RTCP delivers two distinct shapes for the same notification:
|
|
19
|
+
*
|
|
20
|
+
* 1. `onRemoteNotification` (foreground/background):
|
|
21
|
+
* `{ data: { app_data: { type: 'RTP', ... } } }`
|
|
22
|
+
*
|
|
23
|
+
* 2. `onNotificationTapped`: scalars are stringified and the custom payload
|
|
24
|
+
* arrives as a JSON string:
|
|
25
|
+
* `{ data: { app_data: '{"type":"RTP",...}' } }`
|
|
26
|
+
*
|
|
27
|
+
* Both are normalized here so callers only ever deal with `RtpPayload`.
|
|
28
|
+
*
|
|
29
|
+
* `getData` is injectable so hosts that expose push data differently (e.g. a
|
|
30
|
+
* Map-like object on native) can plug in their accessor without changing the
|
|
31
|
+
* rest of the SDK.
|
|
32
|
+
*/
|
|
33
|
+
export function mapPushToRtp(envelope, getData) {
|
|
34
|
+
if (!envelope) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const data = (getData ? getData(envelope) : envelope.data) ?? {};
|
|
38
|
+
|
|
39
|
+
// Some providers nest the custom payload under `app_data` (RTCP/FCM).
|
|
40
|
+
const candidate = unwrapAppData(data);
|
|
41
|
+
if (!isRtpPayload(candidate)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return normalizePayload(candidate);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* RTCP/FCM delivers the custom payload as a JSON string under `app_data`.
|
|
49
|
+
* The tapped shape sits one level deeper, under `data` / `body`.
|
|
50
|
+
*/
|
|
51
|
+
function unwrapAppData(data) {
|
|
52
|
+
let source = data;
|
|
53
|
+
|
|
54
|
+
// Tapped shape: `{ time, app_id, message, read, push_id, app_data }`
|
|
55
|
+
// Received shape: `{ app_data, message, app_id, push_id, time, read }`
|
|
56
|
+
// In both cases `app_data` holds the custom payload.
|
|
57
|
+
const appData = source.app_data;
|
|
58
|
+
if (appData === undefined) {
|
|
59
|
+
return source;
|
|
60
|
+
}
|
|
61
|
+
let parsed = {};
|
|
62
|
+
if (typeof appData === 'string') {
|
|
63
|
+
try {
|
|
64
|
+
parsed = JSON.parse(appData);
|
|
65
|
+
} catch {
|
|
66
|
+
return source;
|
|
67
|
+
}
|
|
68
|
+
} else if (appData && typeof appData === 'object') {
|
|
69
|
+
parsed = appData;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
...source,
|
|
73
|
+
...parsed
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Push transports stringify scalars. Coerce the fields the SDK cares about so
|
|
79
|
+
* the decoded payload always has stable types (this is what makes the payload
|
|
80
|
+
* portable across platforms).
|
|
81
|
+
*/
|
|
82
|
+
function normalizePayload(payload) {
|
|
83
|
+
const normalized = {
|
|
84
|
+
...payload
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// `amount` may arrive as "250000" on tapped notifications.
|
|
88
|
+
if (typeof normalized.amount === 'string') {
|
|
89
|
+
const parsed = Number(normalized.amount);
|
|
90
|
+
if (!Number.isNaN(parsed)) {
|
|
91
|
+
normalized.amount = parsed;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return normalized;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["isRtpPayload","mapPushToRtp","envelope","getData","data","candidate","unwrapAppData","normalizePayload","source","appData","app_data","undefined","parsed","JSON","parse","payload","normalized","amount","Number","isNaN"],"sourceRoot":"../../src","sources":["push.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,eAAY;;AAGzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAaA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,YAAYA,CAC1BC,QAAyC,EACzCC,OAAyE,EACtD;EACnB,IAAI,CAACD,QAAQ,EAAE;IACb,OAAO,IAAI;EACb;EAEA,MAAME,IAAI,GAAG,CAACD,OAAO,GAAGA,OAAO,CAACD,QAAQ,CAAC,GAAGA,QAAQ,CAACE,IAAI,KAAK,CAAC,CAAC;;EAEhE;EACA,MAAMC,SAAS,GAAGC,aAAa,CAACF,IAAI,CAAC;EAErC,IAAI,CAACJ,YAAY,CAACK,SAAS,CAAC,EAAE;IAC5B,OAAO,IAAI;EACb;EAEA,OAAOE,gBAAgB,CAACF,SAAS,CAAC;AACpC;;AAEA;AACA;AACA;AACA;AACA,SAASC,aAAaA,CAACF,IAA6B,EAA2B;EAC7E,IAAII,MAAM,GAAGJ,IAAI;;EAEjB;EACA;EACA;EACA,MAAMK,OAAO,GAAGD,MAAM,CAACE,QAAQ;EAC/B,IAAID,OAAO,KAAKE,SAAS,EAAE;IACzB,OAAOH,MAAM;EACf;EAEA,IAAII,MAA+B,GAAG,CAAC,CAAC;EACxC,IAAI,OAAOH,OAAO,KAAK,QAAQ,EAAE;IAC/B,IAAI;MACFG,MAAM,GAAGC,IAAI,CAACC,KAAK,CAACL,OAAO,CAA4B;IACzD,CAAC,CAAC,MAAM;MACN,OAAOD,MAAM;IACf;EACF,CAAC,MAAM,IAAIC,OAAO,IAAI,OAAOA,OAAO,KAAK,QAAQ,EAAE;IACjDG,MAAM,GAAGH,OAAkC;EAC7C;EAEA,OAAO;IAAE,GAAGD,MAAM;IAAE,GAAGI;EAAO,CAAC;AACjC;;AAEA;AACA;AACA;AACA;AACA;AACA,SAASL,gBAAgBA,CAACQ,OAAgC,EAAc;EACtE,MAAMC,UAAmC,GAAG;IAAE,GAAGD;EAAQ,CAAC;;EAE1D;EACA,IAAI,OAAOC,UAAU,CAACC,MAAM,KAAK,QAAQ,EAAE;IACzC,MAAML,MAAM,GAAGM,MAAM,CAACF,UAAU,CAACC,MAAM,CAAC;IACxC,IAAI,CAACC,MAAM,CAACC,KAAK,CAACP,MAAM,CAAC,EAAE;MACzBI,UAAU,CAACC,MAAM,GAAGL,MAAM;IAC5B;EACF;EAEA,OAAOI,UAAU;AACnB","ignoreList":[]}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { RTP_STATUS } from "../constants.js";
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
const STORAGE_KEY = 'rtp.pendingPayload';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A minimal persistence port for the provider. The host supplies its own
|
|
10
|
+
* storage (e.g. react-native-default-preference / AsyncStorage) so the SDK
|
|
11
|
+
* stays dependency-free. When omitted, persistence is in-memory only.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const RtpContext = /*#__PURE__*/createContext(null);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Bridges the framework-agnostic RTP client into React. Owns no UI — hosts
|
|
18
|
+
* render their own bottom sheet / modal and react to `request` + `status`.
|
|
19
|
+
*/
|
|
20
|
+
export function RtpProvider({
|
|
21
|
+
client,
|
|
22
|
+
isAuthenticated,
|
|
23
|
+
storage,
|
|
24
|
+
onIncomingPayload,
|
|
25
|
+
children
|
|
26
|
+
}) {
|
|
27
|
+
const [request, setRequest] = useState(null);
|
|
28
|
+
const [status, setStatus] = useState(null);
|
|
29
|
+
const [lastResult, setLastResult] = useState(null);
|
|
30
|
+
|
|
31
|
+
// Keep the latest request id so async resume/drain can target it.
|
|
32
|
+
const activeIdRef = useRef(null);
|
|
33
|
+
const receive = useCallback(async payload => {
|
|
34
|
+
onIncomingPayload?.(payload);
|
|
35
|
+
return client.receive(payload);
|
|
36
|
+
}, [client, onIncomingPayload]);
|
|
37
|
+
|
|
38
|
+
// Subscribe to client events exactly once per client.
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const offRequest = client.on('request', req => {
|
|
41
|
+
activeIdRef.current = req.id;
|
|
42
|
+
setRequest(req);
|
|
43
|
+
});
|
|
44
|
+
const offState = client.on('state', ({
|
|
45
|
+
id,
|
|
46
|
+
status: next
|
|
47
|
+
}) => {
|
|
48
|
+
if (activeIdRef.current && id !== activeIdRef.current) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
setStatus(next);
|
|
52
|
+
});
|
|
53
|
+
const offResult = client.on('result', result => {
|
|
54
|
+
setLastResult(result);
|
|
55
|
+
});
|
|
56
|
+
return () => {
|
|
57
|
+
offRequest();
|
|
58
|
+
offState();
|
|
59
|
+
offResult();
|
|
60
|
+
};
|
|
61
|
+
}, [client]);
|
|
62
|
+
|
|
63
|
+
// Drain any payload persisted before React mounted (cold start / killed app).
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
let cancelled = false;
|
|
66
|
+
async function drain() {
|
|
67
|
+
if (!storage) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const raw = await storage.getItem(STORAGE_KEY);
|
|
71
|
+
if (!raw || cancelled) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
await storage.removeItem(STORAGE_KEY);
|
|
75
|
+
client.receive(JSON.parse(raw));
|
|
76
|
+
}
|
|
77
|
+
drain();
|
|
78
|
+
return () => {
|
|
79
|
+
cancelled = true;
|
|
80
|
+
};
|
|
81
|
+
}, [client, storage]);
|
|
82
|
+
|
|
83
|
+
// Auth gate: once authenticated, release any AWAITING_AUTH requests.
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (isAuthenticated) {
|
|
86
|
+
client.resumeAuth();
|
|
87
|
+
}
|
|
88
|
+
}, [client, isAuthenticated]);
|
|
89
|
+
const accept = useCallback(async credential => {
|
|
90
|
+
const id = request?.id ?? activeIdRef.current;
|
|
91
|
+
if (!id) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
return client.accept({
|
|
95
|
+
id,
|
|
96
|
+
credential
|
|
97
|
+
});
|
|
98
|
+
}, [client, request]);
|
|
99
|
+
const decline = useCallback(async reason => {
|
|
100
|
+
const id = request?.id ?? activeIdRef.current;
|
|
101
|
+
if (!id) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
return client.decline({
|
|
105
|
+
id,
|
|
106
|
+
reason
|
|
107
|
+
});
|
|
108
|
+
}, [client, request]);
|
|
109
|
+
const retrieve = useCallback(async id => {
|
|
110
|
+
const target = id ?? request?.id ?? activeIdRef.current;
|
|
111
|
+
if (!target) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
return client.retrieve(target);
|
|
115
|
+
}, [client, request]);
|
|
116
|
+
const dismiss = useCallback(() => {
|
|
117
|
+
setRequest(null);
|
|
118
|
+
setStatus(null);
|
|
119
|
+
setLastResult(null);
|
|
120
|
+
activeIdRef.current = null;
|
|
121
|
+
}, []);
|
|
122
|
+
const isReady = status === RTP_STATUS.READY;
|
|
123
|
+
const isLoading = status === RTP_STATUS.RETRIEVING;
|
|
124
|
+
const value = useMemo(() => ({
|
|
125
|
+
request,
|
|
126
|
+
status,
|
|
127
|
+
isReady,
|
|
128
|
+
isLoading,
|
|
129
|
+
accept,
|
|
130
|
+
decline,
|
|
131
|
+
retrieve,
|
|
132
|
+
dismiss,
|
|
133
|
+
receive,
|
|
134
|
+
lastResult
|
|
135
|
+
}), [request, status, isReady, isLoading, accept, decline, retrieve, dismiss, receive, lastResult]);
|
|
136
|
+
return /*#__PURE__*/_jsx(RtpContext.Provider, {
|
|
137
|
+
value: value,
|
|
138
|
+
children: children
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Access the RTP context. Throws when used outside of an `<RtpProvider>`.
|
|
144
|
+
*/
|
|
145
|
+
export function useRtp() {
|
|
146
|
+
const context = useContext(RtpContext);
|
|
147
|
+
if (!context) {
|
|
148
|
+
throw new Error('[react-native-rtp] useRtp must be used within RtpProvider');
|
|
149
|
+
}
|
|
150
|
+
return context;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=RtpProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","RTP_STATUS","jsx","_jsx","STORAGE_KEY","RtpContext","RtpProvider","client","isAuthenticated","storage","onIncomingPayload","children","request","setRequest","status","setStatus","lastResult","setLastResult","activeIdRef","receive","payload","offRequest","on","req","current","id","offState","next","offResult","result","cancelled","drain","raw","getItem","removeItem","JSON","parse","resumeAuth","accept","credential","undefined","decline","reason","retrieve","target","dismiss","isReady","READY","isLoading","RETRIEVING","value","Provider","useRtp","context","Error"],"sourceRoot":"../../../src","sources":["react/RtpProvider.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/** Required top-level fields for a valid RTP payload. */
|
|
4
|
+
const REQUIRED_FIELDS = ['rtpId', 'amount', 'currency', 'payer', 'payee', 'expiresAt'];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Type guard for RTP payloads.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: this intentionally inspects the *decoded* payload, not a push
|
|
10
|
+
* envelope. Hosts are responsible for extracting the payload from their own
|
|
11
|
+
* notification system first.
|
|
12
|
+
*
|
|
13
|
+
* `amount` is accepted as either a number (minor units) or a numeric string,
|
|
14
|
+
* because push payloads frequently stringify scalars in transit.
|
|
15
|
+
*/
|
|
16
|
+
export function isRtpPayload(payload) {
|
|
17
|
+
if (!payload || typeof payload !== 'object') {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const candidate = payload;
|
|
21
|
+
return candidate.type === 'RTP' && typeof candidate.rtpId === 'string';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns the list of missing/invalid required fields. Empty array means the
|
|
26
|
+
* payload is structurally valid.
|
|
27
|
+
*/
|
|
28
|
+
export function findValidationErrors(payload) {
|
|
29
|
+
const errors = [];
|
|
30
|
+
const record = payload;
|
|
31
|
+
for (const field of REQUIRED_FIELDS) {
|
|
32
|
+
if (record[field] === undefined || record[field] === null) {
|
|
33
|
+
errors.push(field);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (payload.expiresAt !== undefined && Number.isNaN(new Date(payload.expiresAt).getTime())) {
|
|
37
|
+
errors.push('expiresAt');
|
|
38
|
+
}
|
|
39
|
+
for (const side of ['payer', 'payee']) {
|
|
40
|
+
const party = payload[side];
|
|
41
|
+
if (!party || typeof party !== 'object' || typeof party.name !== 'string') {
|
|
42
|
+
errors.push(`${side}.name`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return errors;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Coerce an amount that may arrive as a number or numeric string. */
|
|
49
|
+
function toAmount(value) {
|
|
50
|
+
if (typeof value === 'number') {
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
const parsed = Number(value);
|
|
54
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Map a validated payload into the normalized request held by the SDK. */
|
|
58
|
+
export function toRtpRequest(payload) {
|
|
59
|
+
return {
|
|
60
|
+
id: payload.rtpId,
|
|
61
|
+
amount: toAmount(payload.amount),
|
|
62
|
+
currency: payload.currency,
|
|
63
|
+
payer: payload.payer,
|
|
64
|
+
payee: payload.payee,
|
|
65
|
+
narration: payload.narration,
|
|
66
|
+
transactionRef: payload.transactionRef,
|
|
67
|
+
orderNumber: payload.orderNumber,
|
|
68
|
+
deepLink: payload.deepLink,
|
|
69
|
+
actionMessage: payload.actionMessage,
|
|
70
|
+
expiresAt: payload.expiresAt,
|
|
71
|
+
recipient: payload.recipient
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Build a partial-request patch from an incoming payload, copying only the
|
|
77
|
+
* fields that are actually present. Used to overlay retrieved backend details
|
|
78
|
+
* without a partial response erasing data already held from the push.
|
|
79
|
+
*/
|
|
80
|
+
export function toRequestPatch(payload) {
|
|
81
|
+
const patch = {};
|
|
82
|
+
if (payload.rtpId !== undefined) patch.id = payload.rtpId;
|
|
83
|
+
if (payload.amount !== undefined) patch.amount = toAmount(payload.amount);
|
|
84
|
+
if (payload.currency !== undefined) patch.currency = payload.currency;
|
|
85
|
+
if (payload.payer !== undefined) patch.payer = payload.payer;
|
|
86
|
+
if (payload.payee !== undefined) patch.payee = payload.payee;
|
|
87
|
+
if (payload.narration !== undefined) patch.narration = payload.narration;
|
|
88
|
+
if (payload.transactionRef !== undefined) patch.transactionRef = payload.transactionRef;
|
|
89
|
+
if (payload.orderNumber !== undefined) patch.orderNumber = payload.orderNumber;
|
|
90
|
+
if (payload.deepLink !== undefined) patch.deepLink = payload.deepLink;
|
|
91
|
+
if (payload.actionMessage !== undefined) patch.actionMessage = payload.actionMessage;
|
|
92
|
+
if (payload.expiresAt !== undefined) patch.expiresAt = payload.expiresAt;
|
|
93
|
+
if (payload.recipient !== undefined) patch.recipient = payload.recipient;
|
|
94
|
+
return patch;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Overlay a patch onto an existing request. Only defined, non-null values are
|
|
99
|
+
* copied so a partial response never erases information already held.
|
|
100
|
+
*/
|
|
101
|
+
export function mergeRequest(current, patch) {
|
|
102
|
+
const next = {
|
|
103
|
+
...current
|
|
104
|
+
};
|
|
105
|
+
for (const key of Object.keys(patch)) {
|
|
106
|
+
const value = patch[key];
|
|
107
|
+
if (value !== undefined && value !== null) {
|
|
108
|
+
next[key] = value;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return next;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Pure expiry check. Re-evaluated on every transition, not just on receive. */
|
|
115
|
+
export function isExpired(request, now) {
|
|
116
|
+
const expiry = new Date(request.expiresAt).getTime();
|
|
117
|
+
if (Number.isNaN(expiry)) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
return expiry <= now;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["REQUIRED_FIELDS","isRtpPayload","payload","candidate","type","rtpId","findValidationErrors","errors","record","field","undefined","push","expiresAt","Number","isNaN","Date","getTime","side","party","name","toAmount","value","parsed","toRtpRequest","id","amount","currency","payer","payee","narration","transactionRef","orderNumber","deepLink","actionMessage","recipient","toRequestPatch","patch","mergeRequest","current","next","key","Object","keys","isExpired","request","now","expiry"],"sourceRoot":"../../src","sources":["validate.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RtpStatus } from './constants.js';
|
|
2
|
+
import type { RtpClient, RtpClientOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Map a backend status string onto the normalized SDK status.
|
|
5
|
+
*
|
|
6
|
+
* Unknown values are deliberately **not** treated as success — they map to
|
|
7
|
+
* `undefined` so the caller can decide, rather than silently reporting an
|
|
8
|
+
* approved payment for a status the client does not understand.
|
|
9
|
+
*/
|
|
10
|
+
export declare function normalizeBackendStatus(raw: unknown): RtpStatus | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Create a portable Request-to-Pay client.
|
|
13
|
+
*
|
|
14
|
+
* The client owns validation, de-duplication, expiry, status computation and
|
|
15
|
+
* the accept/decline/retrieve calls. It owns no UI, no navigation and no
|
|
16
|
+
* crypto. Every external effect is injected so the same contract can be
|
|
17
|
+
* re-implemented on other platforms.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createRtpClient(options: RtpClientOptions): RtpClient;
|
|
20
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAY,SAAS,EAAE,MAAM,gBAAa,CAAC;AAUvD,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAMjB,MAAM,YAAS,CAAC;AAejB;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAwB1E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAgWpE"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalized RTP status.
|
|
3
|
+
*
|
|
4
|
+
* The SDK is the single source of truth for these values so that every host
|
|
5
|
+
* platform (React Native, Kotlin, Swift) renders the same UI states.
|
|
6
|
+
*/
|
|
7
|
+
export declare const RTP_STATUS: {
|
|
8
|
+
/** Payload arrived and passed validation, but is not yet actionable. */
|
|
9
|
+
readonly RECEIVED: "RECEIVED";
|
|
10
|
+
/** Authorization details are being fetched from the backend. */
|
|
11
|
+
readonly RETRIEVING: "RETRIEVING";
|
|
12
|
+
/** Expired before it could be actioned. */
|
|
13
|
+
readonly EXPIRED: "EXPIRED";
|
|
14
|
+
/** Valid, but the user is not authenticated yet (login gate). */
|
|
15
|
+
readonly AWAITING_AUTH: "AWAITING_AUTH";
|
|
16
|
+
/** Valid, authenticated, and ready for the user to accept/decline. */
|
|
17
|
+
readonly READY: "READY";
|
|
18
|
+
/** Accept/decline in flight. */
|
|
19
|
+
readonly PROCESSING: "PROCESSING";
|
|
20
|
+
/** Backend accepted the action but a final decision is still pending. */
|
|
21
|
+
readonly PENDING: "PENDING";
|
|
22
|
+
/** Backend confirmed acceptance. */
|
|
23
|
+
readonly ACCEPTED: "ACCEPTED";
|
|
24
|
+
/** Backend confirmed (or user initiated) a decline. */
|
|
25
|
+
readonly DECLINED: "DECLINED";
|
|
26
|
+
/** Terminal failure (network, validation, recipient mismatch, etc.). */
|
|
27
|
+
readonly FAILED: "FAILED";
|
|
28
|
+
};
|
|
29
|
+
export type RtpStatus = (typeof RTP_STATUS)[keyof typeof RTP_STATUS];
|
|
30
|
+
/** Events emitted by the client. */
|
|
31
|
+
export declare const RTP_EVENT: {
|
|
32
|
+
/** A new, actionable request is available. */
|
|
33
|
+
readonly REQUEST: "request";
|
|
34
|
+
/** Status transition for a request. */
|
|
35
|
+
readonly STATE: "state";
|
|
36
|
+
/** Terminal outcome for a request. */
|
|
37
|
+
readonly RESULT: "result";
|
|
38
|
+
};
|
|
39
|
+
export type RtpEvent = (typeof RTP_EVENT)[keyof typeof RTP_EVENT];
|
|
40
|
+
/** Reasons a request can end in FAILED, exposed for UI/diagnostics. */
|
|
41
|
+
export declare const RTP_ERROR: {
|
|
42
|
+
readonly INVALID_PAYLOAD: "INVALID_PAYLOAD";
|
|
43
|
+
readonly RECIPIENT_MISMATCH: "RECIPIENT_MISMATCH";
|
|
44
|
+
readonly RETRIEVE_FAILED: "RETRIEVE_FAILED";
|
|
45
|
+
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
46
|
+
readonly BACKEND_REJECTED: "BACKEND_REJECTED";
|
|
47
|
+
readonly UNKNOWN: "UNKNOWN";
|
|
48
|
+
};
|
|
49
|
+
export type RtpError = (typeof RTP_ERROR)[keyof typeof RTP_ERROR];
|
|
50
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,UAAU;IACrB,wEAAwE;;IAExE,gEAAgE;;IAEhE,2CAA2C;;IAE3C,iEAAiE;;IAEjE,sEAAsE;;IAEtE,gCAAgC;;IAEhC,yEAAyE;;IAEzE,oCAAoC;;IAEpC,uDAAuD;;IAEvD,wEAAwE;;CAEhE,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAErE,oCAAoC;AACpC,eAAO,MAAM,SAAS;IACpB,8CAA8C;;IAE9C,uCAAuC;;IAEvC,sCAAsC;;CAE9B,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAElE,uEAAuE;AACvE,eAAO,MAAM,SAAS;;;;;;;CAOZ,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RtpClientOptions, RtpEventMap, RtpUnsubscribe } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Tiny typed event emitter. Deliberately dependency-free so the same contract
|
|
4
|
+
* is trivial to re-implement in Kotlin/Swift.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createEmitter(): {
|
|
7
|
+
on: <E extends keyof RtpEventMap>(event: E, handler: RtpEventMap[E]) => RtpUnsubscribe;
|
|
8
|
+
emit: <E extends keyof RtpEventMap>(event: E, payload: Parameters<RtpEventMap[E]>[0]) => void;
|
|
9
|
+
clear: () => void;
|
|
10
|
+
};
|
|
11
|
+
/** Default logger used when the host does not provide one. */
|
|
12
|
+
export declare const noopLogger: NonNullable<RtpClientOptions['logger']>;
|
|
13
|
+
/** Default clock. */
|
|
14
|
+
export declare const defaultNow: () => number;
|
|
15
|
+
//# sourceMappingURL=emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../../src/emitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAS,CAAC;AAI7E;;;GAGG;AACH,wBAAgB,aAAa;SAOf,CAAC,SAAS,MAAM,WAAW,SAC9B,CAAC,WACC,WAAW,CAAC,CAAC,CAAC,KACtB,cAAc;WAWH,CAAC,SAAS,MAAM,WAAW,SAChC,CAAC,WACC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KACrC,IAAI;iBAOW,IAAI;EAOvB;AAED,8DAA8D;AAC9D,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAY,CAAC;AAE5E,qBAAqB;AACrB,eAAO,MAAM,UAAU,cAAmB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { createRtpClient, normalizeBackendStatus } from './client.js';
|
|
2
|
+
export { RTP_STATUS, RTP_EVENT, RTP_ERROR } from './constants.js';
|
|
3
|
+
export type { RtpStatus, RtpEvent, RtpError } from './constants.js';
|
|
4
|
+
export { isRtpPayload, findValidationErrors, toRtpRequest, toRequestPatch, mergeRequest, isExpired, } from './validate.js';
|
|
5
|
+
export { mapPushToRtp } from './push.js';
|
|
6
|
+
export type { PushEnvelope } from './push.js';
|
|
7
|
+
export type { RtpPayload, RtpParty, RtpRequest, RtpCredential, RtpResult, RtpReceiveOutcome, RtpTransport, RtpStorage, RtpHttpResponse, RtpClient, RtpClientOptions, RtpEventMap, RtpUnsubscribe, } from './types.js';
|
|
8
|
+
export { RtpProvider, useRtp, RtpContext } from './react/RtpProvider.js';
|
|
9
|
+
export type { RtpProviderProps, RtpContextValue } from './react/RtpProvider.js';
|
|
10
|
+
export { createMockTransport } from './mock/mockTransport.js';
|
|
11
|
+
export type { MockTransport, MockTransportOptions, RecordedCall, } from './mock/mockTransport.js';
|
|
12
|
+
export { makeRtpPayload, makeExpiredPayload } from './mock/makeRtpPayload.js';
|
|
13
|
+
export type { MakeRtpPayloadOverrides } from './mock/makeRtpPayload.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,aAAU,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAa,CAAC;AAC/D,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAa,CAAC;AACjE,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,SAAS,GACV,MAAM,eAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAQ,CAAC;AACtC,YAAY,EAAE,YAAY,EAAE,MAAM,WAAQ,CAAC;AAG3C,YAAY,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,cAAc,GACf,MAAM,YAAS,CAAC;AAGjB,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,wBAAqB,CAAC;AACtE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAG7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAsB,CAAC;AAC3D,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,YAAY,GACb,MAAM,yBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,0BAAuB,CAAC;AAC3E,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAAuB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RtpPayload } from '../types.js';
|
|
2
|
+
export interface MakeRtpPayloadOverrides extends Partial<Omit<RtpPayload, 'type' | 'payer' | 'payee' | 'expiresAt'>> {
|
|
3
|
+
payer?: Partial<RtpPayload['payer']>;
|
|
4
|
+
payee?: Partial<RtpPayload['payee']>;
|
|
5
|
+
/** Milliseconds from `now` until expiry (negative = already expired). */
|
|
6
|
+
expiresInMs?: number;
|
|
7
|
+
/** Base time to compute expiry from. Defaults to Date.now(). */
|
|
8
|
+
from?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Build a valid RTP payload for tests, fixtures and the example app.
|
|
12
|
+
* Every field is overridable so edge cases are trivial to express.
|
|
13
|
+
*/
|
|
14
|
+
export declare function makeRtpPayload(overrides?: MakeRtpPayloadOverrides): RtpPayload;
|
|
15
|
+
/** A payload that has already expired. */
|
|
16
|
+
export declare function makeExpiredPayload(overrides?: MakeRtpPayloadOverrides): RtpPayload;
|
|
17
|
+
//# sourceMappingURL=makeRtpPayload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"makeRtpPayload.d.ts","sourceRoot":"","sources":["../../../../src/mock/makeRtpPayload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAU,CAAC;AAO3C,MAAM,WAAW,uBAAwB,SAAQ,OAAO,CACtD,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,CAAC,CAC3D;IACC,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IACrC,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,GAAE,uBAA4B,GACtC,UAAU,CAqCZ;AAED,0CAA0C;AAC1C,wBAAgB,kBAAkB,CAChC,SAAS,GAAE,uBAA4B,GACtC,UAAU,CAEZ"}
|