@consentera/react-native-consent 2.0.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 +21 -0
- package/README.md +200 -0
- package/lib/commonjs/gate.js +87 -0
- package/lib/commonjs/gate.js.map +1 -0
- package/lib/commonjs/index.js +92 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/session.js +805 -0
- package/lib/commonjs/session.js.map +1 -0
- package/lib/module/gate.js +80 -0
- package/lib/module/gate.js.map +1 -0
- package/lib/module/index.js +23 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/session.js +789 -0
- package/lib/module/session.js.map +1 -0
- package/lib/typescript/src/gate.d.ts +45 -0
- package/lib/typescript/src/gate.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +25 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/session.d.ts +600 -0
- package/lib/typescript/src/session.d.ts.map +1 -0
- package/package.json +130 -0
- package/src/gate.ts +81 -0
- package/src/index.ts +50 -0
- package/src/session.ts +1051 -0
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this SDK calls itself on the wire, in `X-Consentera-SDK`.
|
|
3
|
+
*
|
|
4
|
+
* ONE declaration. The Android and iOS twins each had an SDK_VERSION constant
|
|
5
|
+
* that no request builder ever read, which is the same as not having one.
|
|
6
|
+
*/
|
|
7
|
+
export declare const SDK_VERSION = "2.0.0";
|
|
8
|
+
export declare const SDK_IDENTIFIER = "react-native/2.0.0";
|
|
9
|
+
/**
|
|
10
|
+
* The User-Agent the platform's audit coarsening actually parses.
|
|
11
|
+
*
|
|
12
|
+
* THE PLATFORM PARSES User-Agent, SO THAT IS WHERE THE VERSION GOES.
|
|
13
|
+
*
|
|
14
|
+
* consentera-api/internal/core/audit/user_agent_coarsening_test.go:39-40 drives
|
|
15
|
+
* CoarsenUserAgent with `ConsenteraSDK/2.3.1 (Android 14; SM-G991B; build 4471)`
|
|
16
|
+
* and asserts it coarsens to `ConsenteraSDK/2` — the platform has a rule, a test
|
|
17
|
+
* and an audit consequence for exactly that spelling. The other string in the
|
|
18
|
+
* platform tree, `consentera-sdk/1.2` (validation_envelope_test.go:233), is an
|
|
19
|
+
* inert fixture with no parser behind it. So `ConsenteraSDK/<version>` is the one
|
|
20
|
+
* that is agreed by evidence rather than by preference; raised with the platform
|
|
21
|
+
* lane as MANIFEST-CORRECTIONS M-11.
|
|
22
|
+
*
|
|
23
|
+
* AND X-Consentera-SDK STAYS, because the two answer different questions.
|
|
24
|
+
* User-Agent is DELIBERATELY COARSENED into the audit record — `ConsenteraSDK/2`
|
|
25
|
+
* is all that survives, which is the point: an audit row must not carry a
|
|
26
|
+
* fingerprint of the person's device. A support ticket needs the exact build, and
|
|
27
|
+
* that is what the custom header carries, outside the audit trail.
|
|
28
|
+
*/
|
|
29
|
+
export declare const SDK_USER_AGENT = "ConsenteraSDK/2.0.0 (react-native)";
|
|
30
|
+
/**
|
|
31
|
+
* `Retry-After` in either RFC 9110 form — delta-seconds, or an HTTP-date — as
|
|
32
|
+
* milliseconds, or null when the header is absent or unparseable.
|
|
33
|
+
*
|
|
34
|
+
* Capped at 60s: a server that asks for an hour is not something a consent UI
|
|
35
|
+
* can wait out, and the caller's own deadline should decide.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseRetryAfter(header: string | null | undefined, now?: number): number | null;
|
|
38
|
+
/**
|
|
39
|
+
* A typed error with the status, the canonical code and the request id.
|
|
40
|
+
*
|
|
41
|
+
* Errors used to be `new Error(\`Consentera \${path} \${status}: \${body}\`)` — a
|
|
42
|
+
* string, with the response body interpolated into the message (where it could
|
|
43
|
+
* carry the person's own identifiers into whatever the host logs), and nothing
|
|
44
|
+
* a caller could switch on.
|
|
45
|
+
*/
|
|
46
|
+
export declare class ConsenteraError extends Error {
|
|
47
|
+
/** HTTP status, when this came from a non-2xx answer. */
|
|
48
|
+
readonly status?: number;
|
|
49
|
+
/** The platform's canonical error code, e.g. `VALIDATION_ERROR`. */
|
|
50
|
+
readonly code?: string;
|
|
51
|
+
/**
|
|
52
|
+
* The platform's own sentence for a refusal: the `message` of its
|
|
53
|
+
* `{code, message}` envelope, verbatim (SDK register MOB-042). It is what
|
|
54
|
+
* an app shows the person to say WHY: "\"phone\" is not one of this
|
|
55
|
+
* organisation's identifier fields — send email". It is kept out of
|
|
56
|
+
* `message`, like the rest of the body: `message` goes wherever the host
|
|
57
|
+
* logs, and this is a sentence for a screen. Undefined when the answer had
|
|
58
|
+
* no envelope, for example a proxy's HTML page.
|
|
59
|
+
*/
|
|
60
|
+
readonly platformMessage?: string;
|
|
61
|
+
/** `X-Request-Id` off the response, for a support ticket. */
|
|
62
|
+
readonly requestId?: string;
|
|
63
|
+
/** True for a timeout or a transport failure — the call may be retried. */
|
|
64
|
+
readonly retryable: boolean;
|
|
65
|
+
constructor(message: string, opts?: {
|
|
66
|
+
status?: number;
|
|
67
|
+
code?: string;
|
|
68
|
+
platformMessage?: string;
|
|
69
|
+
requestId?: string;
|
|
70
|
+
retryable?: boolean;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The platform's error envelope, `{code, message}` (core/apierrors/errors.go
|
|
75
|
+
* APIError), read out of a response body. Tolerates the older
|
|
76
|
+
* `{error: {code, message}}` nesting. Never throws: a body that is not an
|
|
77
|
+
* envelope yields nothing.
|
|
78
|
+
*/
|
|
79
|
+
export declare function readErrorEnvelope(text: string): {
|
|
80
|
+
code?: string;
|
|
81
|
+
message?: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* 160 bits from the platform CSPRNG, URL-safe, unpadded.
|
|
85
|
+
*
|
|
86
|
+
* REFUSES RATHER THAN DEGRADING. React Native ships no `crypto.getRandomValues`
|
|
87
|
+
* by default, and the obvious substitute — `Math.random` — is not a CSPRNG: this
|
|
88
|
+
* nonce is the only thing standing between a forged
|
|
89
|
+
* `myapp://consent/callback?status=granted` from another app and a host that
|
|
90
|
+
* believes it, so a predictable one is worse than none. Install
|
|
91
|
+
* `react-native-get-random-values` and import it once at the top of your entry
|
|
92
|
+
* file, which is what every RN crypto consumer already does.
|
|
93
|
+
*/
|
|
94
|
+
export declare function newCallbackState(): string;
|
|
95
|
+
/** The one shape the SDK needs from whichever in-app browser the host installed. */
|
|
96
|
+
export interface InAppBrowserAdapter {
|
|
97
|
+
/** Open `url`, intercept `redirectScheme`, resolve the URL or null on dismiss. */
|
|
98
|
+
openAuth(url: string, redirectScheme: string): Promise<string | null>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Supply the in-app browser explicitly — for Expo, or for a host that already
|
|
102
|
+
* has one:
|
|
103
|
+
*
|
|
104
|
+
* import * as WebBrowser from 'expo-web-browser';
|
|
105
|
+
* setInAppBrowser({
|
|
106
|
+
* openAuth: async (url, scheme) => {
|
|
107
|
+
* const r = await WebBrowser.openAuthSessionAsync(url, scheme);
|
|
108
|
+
* return r.type === 'success' ? r.url : null;
|
|
109
|
+
* },
|
|
110
|
+
* });
|
|
111
|
+
*/
|
|
112
|
+
export declare function setInAppBrowser(adapter: InAppBrowserAdapter | null): void;
|
|
113
|
+
/**
|
|
114
|
+
* The injected adapter, else `react-native-inappbrowser-reborn` if the host
|
|
115
|
+
* installed it, else null — and null makes `presentConsent` THROW rather than
|
|
116
|
+
* fall back to `Linking.openURL`.
|
|
117
|
+
*
|
|
118
|
+
* The peer is resolved with a guarded `require` rather than a top-level import
|
|
119
|
+
* on purpose: a static import would make the peer mandatory for every consumer,
|
|
120
|
+
* including the ones that inject their own.
|
|
121
|
+
*/
|
|
122
|
+
export declare function resolveInAppBrowser(): InAppBrowserAdapter | null;
|
|
123
|
+
export interface SessionConfig {
|
|
124
|
+
/**
|
|
125
|
+
* Your backend/proxy base, e.g. https://api.yourbank.in/consentera.
|
|
126
|
+
* REQUIRED, with no default: a blank or non-http(s) value throws
|
|
127
|
+
* `ConsenteraError` (`code: 'BACKEND_BASE_URL_REQUIRED'`) from the constructor.
|
|
128
|
+
*/
|
|
129
|
+
backendBaseUrl: string;
|
|
130
|
+
/** Registered deep-link scheme (ops: ALLOWED_CALLBACK_APP_SCHEMES) */
|
|
131
|
+
callbackScheme: string;
|
|
132
|
+
callbackHost?: string;
|
|
133
|
+
callbackPath?: string;
|
|
134
|
+
/** Per-ATTEMPT timeout in ms (default 30000) — a dead backend fails fast. */
|
|
135
|
+
requestTimeoutMs?: number;
|
|
136
|
+
/**
|
|
137
|
+
* Ceiling on the whole call including retries (default 2x requestTimeoutMs).
|
|
138
|
+
* Without it, N retries multiply the caller's wait by N and a consent screen
|
|
139
|
+
* hangs for a minute and a half on a bad network.
|
|
140
|
+
*/
|
|
141
|
+
totalTimeoutMs?: number;
|
|
142
|
+
/** Attempts INCLUDING the first (default 3). 1 disables retrying. */
|
|
143
|
+
maxAttempts?: number;
|
|
144
|
+
/** Full-jitter base delay in ms (default 250). */
|
|
145
|
+
retryBaseDelayMs?: number;
|
|
146
|
+
/**
|
|
147
|
+
* The identifier fields of your organisation's locked integration key, in
|
|
148
|
+
* the order you prefer them for signing a person in to the privacy portal —
|
|
149
|
+
* e.g. `['customer_id', 'mobile']`. Optional. {@link ConsenteraSession.openPortal}
|
|
150
|
+
* uses it to choose which ONE identifier to send when you pass it several;
|
|
151
|
+
* without it, pass exactly one (MOB-043).
|
|
152
|
+
*/
|
|
153
|
+
identifierScheme?: string[];
|
|
154
|
+
/**
|
|
155
|
+
* Opt-in diagnostics sink. Undefined (the default) means the SDK is SILENT.
|
|
156
|
+
*
|
|
157
|
+
* It replaces a bare `console.warn`, which could not be turned off, redirected
|
|
158
|
+
* or levelled. Nothing PII-bearing is passed here: the messages name
|
|
159
|
+
* conditions, never values, and the transport deliberately keeps response
|
|
160
|
+
* bodies out of its errors for the same reason.
|
|
161
|
+
*/
|
|
162
|
+
onDiagnostic?: (message: string) => void;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* The deep link handed to the platform as `callback_url`, carrying `state`.
|
|
166
|
+
*
|
|
167
|
+
* THE STATE SURVIVES THE ROUND TRIP, AND THAT IS A PLATFORM FACT, not an
|
|
168
|
+
* assumption: `addRedirectParams` (consent/collection.go) appends with `&` when
|
|
169
|
+
* the callback URL already contains a `?`, so `myapp://consent/callback?state=X`
|
|
170
|
+
* comes back as `…?artifact_id=…&pending=1&session_id=…&state=X&status=…`
|
|
171
|
+
* (setRedirectParam re-encodes the query, so the keys arrive sorted). If that ever
|
|
172
|
+
* changes, `parseCallback` starts refusing every callback rather than silently
|
|
173
|
+
* accepting a forged one.
|
|
174
|
+
*/
|
|
175
|
+
export declare function callbackUrlFor(cfg: SessionConfig, state: string): string;
|
|
176
|
+
/**
|
|
177
|
+
* THE STATUS VOCABULARY THE PLATFORM PUTS ON A CALLBACK — and only these.
|
|
178
|
+
*
|
|
179
|
+
* consent/collection.go (platform pre-main 35cd853ac7) derives it at
|
|
180
|
+
* :4094-4098 — `granted`; no purpose granted → `denied`; some denied →
|
|
181
|
+
* `partial` — and SETS it on the redirect at :4243. Any other value
|
|
182
|
+
* (`success`, `completed`, `expired`, a different case, none at all) did not
|
|
183
|
+
* come from the platform and is `unknown`: never read it as a grant.
|
|
184
|
+
*/
|
|
185
|
+
export type CallbackStatus = 'granted' | 'partial' | 'denied' | 'unknown';
|
|
186
|
+
/** Map a raw `status` query value onto the platform's vocabulary. Exact match: the server writes lowercase. */
|
|
187
|
+
export declare function callbackStatusOf(raw: string | null | undefined): CallbackStatus;
|
|
188
|
+
/**
|
|
189
|
+
* Parsed from the deep link the hosted page redirects to on submit.
|
|
190
|
+
*
|
|
191
|
+
* A CALLBACK IS A HINT AND NEVER A DECISION. What `parseCallback` guarantees is
|
|
192
|
+
* narrower and still worth having: this callback came back to the deep link THIS
|
|
193
|
+
* SDK asked for, carrying the nonce THIS SDK generated.
|
|
194
|
+
*/
|
|
195
|
+
export interface ConsentCallback {
|
|
196
|
+
sessionId?: string;
|
|
197
|
+
artifactId?: string;
|
|
198
|
+
/** The raw `status` query value, exactly as it arrived. Prefer {@link callbackStatus}. */
|
|
199
|
+
status?: string;
|
|
200
|
+
/**
|
|
201
|
+
* `status` read against the platform's vocabulary: `granted`, `partial`
|
|
202
|
+
* (some purposes declined) or `denied`, else `unknown`. A HINT, not proof —
|
|
203
|
+
* confirm by reading the consent back through your backend (`validate`).
|
|
204
|
+
*/
|
|
205
|
+
callbackStatus: CallbackStatus;
|
|
206
|
+
/**
|
|
207
|
+
* `pending=1` on the return (collection.go:4274, walk finding F018): the
|
|
208
|
+
* consent was recorded and its record is STILL BEING WRITTEN. The platform
|
|
209
|
+
* sets it on every capture. It is not signed and says nothing about whether
|
|
210
|
+
* a consent exists — it tells your backend to expect the read-back to wait
|
|
211
|
+
* (202 + Retry-After) rather than to treat an early miss as "no consent".
|
|
212
|
+
*/
|
|
213
|
+
pending: boolean;
|
|
214
|
+
/**
|
|
215
|
+
* The nonce this SDK generated, echoed back by the platform and already
|
|
216
|
+
* compared against the expected value before this object was returned.
|
|
217
|
+
*/
|
|
218
|
+
state?: string;
|
|
219
|
+
/**
|
|
220
|
+
* The platform's HMAC over (session_id, artifact_id, status), present only
|
|
221
|
+
* when the DF has a `callback_signing_secret` (collection.go:4175-4182).
|
|
222
|
+
*
|
|
223
|
+
* DO NOT VERIFY IT IN THE APP. Verifying needs the secret, and a secret in an
|
|
224
|
+
* app binary is not a secret. Send it to your own backend.
|
|
225
|
+
*/
|
|
226
|
+
signature?: string;
|
|
227
|
+
/** Every query parameter, for logging. */
|
|
228
|
+
parameters: Record<string, string>;
|
|
229
|
+
}
|
|
230
|
+
export interface ConsentSession {
|
|
231
|
+
consent_session_id: string;
|
|
232
|
+
consent_url: string;
|
|
233
|
+
notice_hash?: string;
|
|
234
|
+
/**
|
|
235
|
+
* When this session stops being usable. Read it: a host that cannot see the
|
|
236
|
+
* expiry cannot decide whether to re-create rather than re-open. camelCase is
|
|
237
|
+
* the API's entrenched contract (collection.go:241).
|
|
238
|
+
*/
|
|
239
|
+
expiresAt?: string;
|
|
240
|
+
/** The notice VERSION this session is bound to (collection.go:243). */
|
|
241
|
+
notice_version_id?: string;
|
|
242
|
+
/** The language the platform actually served, after its fallback chain. */
|
|
243
|
+
languageCode?: string;
|
|
244
|
+
/** The schema version the hosted page renders with (collection.go:247). */
|
|
245
|
+
ui_schema_version?: string;
|
|
246
|
+
/**
|
|
247
|
+
* The client-generated nonce this SDK put on the callback URL.
|
|
248
|
+
*
|
|
249
|
+
* NOT FROM THE SERVER — `createSession` sets it after parsing the response.
|
|
250
|
+
* `challengeNonce` is the SERVER's nonce for the render/submit legs and is a
|
|
251
|
+
* different value with a different job. It is not persisted: if the app is
|
|
252
|
+
* killed while the browser is open it is gone, which is the case
|
|
253
|
+
* resume-revalidate covers.
|
|
254
|
+
*/
|
|
255
|
+
callbackState?: string;
|
|
256
|
+
/**
|
|
257
|
+
* camelCase on the wire, and that is the wire, not a transcription error:
|
|
258
|
+
* `expiresAt`, `languageCode` and `challengeNonce` are pinned camelCase in the
|
|
259
|
+
* API's own struct as an entrenched contract while the rest of the response is
|
|
260
|
+
* snake_case.
|
|
261
|
+
*/
|
|
262
|
+
challengeNonce?: string;
|
|
263
|
+
/**
|
|
264
|
+
* The platform's own uuid for the person. Always returned — store it and send
|
|
265
|
+
* it as `dataPrincipalId` next time.
|
|
266
|
+
*/
|
|
267
|
+
data_principal_id?: string;
|
|
268
|
+
/**
|
|
269
|
+
* Consequences that did not refuse the request. READ THEM: an unknown age, or
|
|
270
|
+
* a guardian channel whose invitation could not be sent, arrives here with a
|
|
271
|
+
* 200 and is otherwise invisible.
|
|
272
|
+
*/
|
|
273
|
+
warnings?: string[];
|
|
274
|
+
/**
|
|
275
|
+
* Present when this session is a child's and an invitation went out to the
|
|
276
|
+
* guardian channel the request carried. The consent is NOT recorded until that
|
|
277
|
+
* guardian verifies.
|
|
278
|
+
*/
|
|
279
|
+
guardian_verification?: GuardianVerificationPending;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* The §9(1) state a child's session rests in while the guardian verifies.
|
|
283
|
+
*
|
|
284
|
+
* IT CARRIES NO LINK AND NO TOKEN, deliberately. The verification URL is a
|
|
285
|
+
* bearer credential — address-bound, 72 hours, single use — and it goes to the
|
|
286
|
+
* guardian's own address. Returning it here would put it in the organisation's
|
|
287
|
+
* logs, and the organisation is not the party the link is for.
|
|
288
|
+
*/
|
|
289
|
+
export interface GuardianVerificationPending {
|
|
290
|
+
/** `'pending'`: the guardianship exists and nothing about it is proven yet. */
|
|
291
|
+
status: string;
|
|
292
|
+
/** Which channel the invitation went out on — `'email'` or `'sms'`. */
|
|
293
|
+
channel: string;
|
|
294
|
+
/** Names the guardianship, so it can be followed on the guardian APIs. */
|
|
295
|
+
link_id: string;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* `data_principal_identifiers` — how every consent LIFECYCLE road names a
|
|
299
|
+
* person.
|
|
300
|
+
*
|
|
301
|
+
* ─── IT IS THE SAME SHAPE AS `dataPrincipal` ON SESSION CREATE (F015) ─────
|
|
302
|
+
*
|
|
303
|
+
* An OPEN map keyed by THE TENANT'S OWN LOCKED INTEGRATION KEY — the same
|
|
304
|
+
* value `data_principal` carries on create (update_context.go:104-119).
|
|
305
|
+
* F015 (consent/one-identifier-vocabulary-20260922) deleted the earlier
|
|
306
|
+
* closed five-field object, because a closed struct cannot carry a per-tenant
|
|
307
|
+
* vocabulary:
|
|
308
|
+
*
|
|
309
|
+
* * ONE VOCABULARY NOW, ONE SPELLING. The mobile atom is `mobile` on BOTH
|
|
310
|
+
* roads; F015 removed the old server-side fold, so `phone` is refused BY
|
|
311
|
+
* NAME (400 UNKNOWN_IDENTIFIER_FIELD, "…use mobile"). Do NOT send `phone`.
|
|
312
|
+
* * THE ADMISSIBLE SET IS PER-TENANT, so this SDK cannot know it and must NOT
|
|
313
|
+
* allow-list. Send the fields the organisation locked; the SERVER answers
|
|
314
|
+
* UNKNOWN_IDENTIFIER_FIELD, naming the field, when you get it wrong.
|
|
315
|
+
* * THERE IS NO `pan` KEY — it is evidence-class and can never be a scheme
|
|
316
|
+
* field.
|
|
317
|
+
*
|
|
318
|
+
* Only the wire KEY differs from create (`data_principal` may mint a person,
|
|
319
|
+
* `data_principal_identifiers` resolves only). Any ONE field is enough. A raw
|
|
320
|
+
* 12-digit `aadhaar` value is refused 400 INVALID_IDENTIFIER_FORMAT (F015
|
|
321
|
+
* folded the old AADHAAR_RAW_REFUSED into that one refusal); send the
|
|
322
|
+
* Aadhaar-LINKED token, never the number.
|
|
323
|
+
*/
|
|
324
|
+
export type DataPrincipalIdentifiers = Record<string, string>;
|
|
325
|
+
/**
|
|
326
|
+
* The ONE way a consent lifecycle road names a person.
|
|
327
|
+
*
|
|
328
|
+
* `data_principal_ref` is REFUSED OUTRIGHT since 2026-09-21 — no transition
|
|
329
|
+
* period (consent/lifecycle_identity.go:8-11) — and the refusal fires even when
|
|
330
|
+
* `data_principal_id` is also present, because two fields naming a person can
|
|
331
|
+
* disagree and the caller would never learn which one the answer was about.
|
|
332
|
+
* A union makes the refused request unrepresentable rather than a round trip.
|
|
333
|
+
*/
|
|
334
|
+
export type PrincipalRef = {
|
|
335
|
+
dataPrincipalId: string;
|
|
336
|
+
dataPrincipalIdentifiers?: never;
|
|
337
|
+
} | {
|
|
338
|
+
dataPrincipalIdentifiers: DataPrincipalIdentifiers;
|
|
339
|
+
dataPrincipalId?: never;
|
|
340
|
+
};
|
|
341
|
+
/** Turn a {@link PrincipalRef} into the body fields that name the person. */
|
|
342
|
+
export declare function principalBody(who: PrincipalRef): Record<string, unknown>;
|
|
343
|
+
/**
|
|
344
|
+
* The ONE identifier the portal road is sent, as `[kind, value]`.
|
|
345
|
+
*
|
|
346
|
+
* The map's only entry, or, when it has several, the first field of
|
|
347
|
+
* `scheme` that it carries. It throws (a ConsenteraError whose `code` is the
|
|
348
|
+
* one the server would use) rather than guess: an empty map is
|
|
349
|
+
* IDENTIFIER_REQUIRED, several entries and no scheme to choose by is
|
|
350
|
+
* IDENTIFIER_AMBIGUOUS, and `phone` is UNKNOWN_IDENTIFIER_FIELD.
|
|
351
|
+
*/
|
|
352
|
+
export declare function portalIdentifier(identifiers: DataPrincipalIdentifiers, scheme?: readonly string[]): [kind: string, value: string];
|
|
353
|
+
export interface ConsentDecision {
|
|
354
|
+
decision: string;
|
|
355
|
+
reason_code?: string;
|
|
356
|
+
purpose_code?: string;
|
|
357
|
+
effective_at?: string;
|
|
358
|
+
expires_at?: string;
|
|
359
|
+
}
|
|
360
|
+
export interface PortalSession {
|
|
361
|
+
portal_url: string;
|
|
362
|
+
expires_in_seconds: number;
|
|
363
|
+
auto_provisioned: boolean;
|
|
364
|
+
}
|
|
365
|
+
export interface CreateSessionRequest {
|
|
366
|
+
/**
|
|
367
|
+
* The person's identifiers, KEYED BY THE FIELD NAMES OF YOUR ORGANISATION'S
|
|
368
|
+
* LOCKED INTEGRATION KEY — `{ email: 'riya@example.in' }`,
|
|
369
|
+
* `{ customer_id: 'CUST-90210', mobile: '+919876500000' }`.
|
|
370
|
+
*
|
|
371
|
+
* A MAP AND NOT A SET OF NAMED FIELDS (U58). The admissible key set is a
|
|
372
|
+
* PER-TENANT fact the platform reads at request time, and THE TYPE COMES FROM
|
|
373
|
+
* THE FIELD NAME: there is no declared type to disagree with the value and no
|
|
374
|
+
* shape to guess from. A field outside your key is refused 400
|
|
375
|
+
* UNKNOWN_IDENTIFIER_FIELD, whose message LISTS the allowed fields; too few of
|
|
376
|
+
* them is 400 IDENTIFIER_REQUIRED.
|
|
377
|
+
*
|
|
378
|
+
* NO SPELLING IS FOLDED ANY MORE. On a key of {email, mobile}, `phone` is an
|
|
379
|
+
* unknown field, not a spelling of `mobile`.
|
|
380
|
+
*/
|
|
381
|
+
dataPrincipal?: Record<string, string>;
|
|
382
|
+
/** The platform's own uuid for the person, from any previous createSession response. */
|
|
383
|
+
dataPrincipalId?: string;
|
|
384
|
+
noticeInternalName: string;
|
|
385
|
+
/** Bind exactly this version NUMBER of the notice code; omit for its default version. */
|
|
386
|
+
noticeVersionNumber?: number;
|
|
387
|
+
sessionRef?: string;
|
|
388
|
+
/**
|
|
389
|
+
* YYYY-MM-DD, sent as `age.date_of_birth` (U58; it was
|
|
390
|
+
* `data_principal_details.date_of_birth`). Age is server-authoritative: the
|
|
391
|
+
* date is re-read every time, so a person graduates at eighteen without
|
|
392
|
+
* anyone updating a flag. Omit it and the person's age is UNKNOWN — the
|
|
393
|
+
* session is still created, and purposes restricted for children are then
|
|
394
|
+
* refused. A malformed or implausible date is refused 400
|
|
395
|
+
* INVALID_DATE_OF_BIRTH.
|
|
396
|
+
*/
|
|
397
|
+
dateOfBirth?: string;
|
|
398
|
+
/**
|
|
399
|
+
* Preferred language for the consent page, sent as `language` — ONE field,
|
|
400
|
+
* replacing `locale_pref`, `notice_language` and `template_language`
|
|
401
|
+
* together (U58). It goes AHEAD of the tenant's own default in the server's
|
|
402
|
+
* fallback chain, so send it only when a language was actually asked for. A
|
|
403
|
+
* language the platform does not serve is refused 400 UNSUPPORTED_LANGUAGE.
|
|
404
|
+
*/
|
|
405
|
+
language?: string;
|
|
406
|
+
/** Where the guardian's verification request is sent. Not with [guardianPhone]. */
|
|
407
|
+
guardianEmail?: string;
|
|
408
|
+
/** Where the guardian's verification request is sent. Not with [guardianEmail]. */
|
|
409
|
+
guardianPhone?: string;
|
|
410
|
+
/**
|
|
411
|
+
* What the child SAYS the guardian is to them ('mother', 'father', 'legal
|
|
412
|
+
* guardian', …). Recorded as a CLAIM and confirmed or corrected by the
|
|
413
|
+
* guardian on the verification road; nothing downstream treats it as proven.
|
|
414
|
+
*/
|
|
415
|
+
guardianRelationship?: string;
|
|
416
|
+
}
|
|
417
|
+
export declare class ConsenteraSession {
|
|
418
|
+
private cfg;
|
|
419
|
+
constructor(cfg: SessionConfig);
|
|
420
|
+
/**
|
|
421
|
+
* ONE transport for every road.
|
|
422
|
+
*
|
|
423
|
+
* WHAT IT ADDS, and why each one:
|
|
424
|
+
*
|
|
425
|
+
* * **Identity.** `X-Consentera-SDK: react-native/<version>` on every
|
|
426
|
+
* request. Without it the platform cannot tell which SDK build produced a
|
|
427
|
+
* failure, which is the first question on every support ticket.
|
|
428
|
+
* * **Idempotency.** One key per OPERATION, not per attempt: a retried
|
|
429
|
+
* mutation must not record a second consent or a second withdrawal. The key
|
|
430
|
+
* is minted once per `post` call and reused across its retries.
|
|
431
|
+
* * **Retry with backoff and FULL JITTER**, on 429, 5xx and transport
|
|
432
|
+
* failures only. Never on a 4xx: a refused body is refused on every
|
|
433
|
+
* attempt, and retrying it just spends the tenant's rate budget.
|
|
434
|
+
* * **`Retry-After` is obeyed** when the server sends one, in either its
|
|
435
|
+
* delta-seconds or HTTP-date form. The platform rate-limits these roads
|
|
436
|
+
* (routes_consent.go:377,389,406,567), so this is not hypothetical.
|
|
437
|
+
* * **Request id**, surfaced on the error rather than discarded.
|
|
438
|
+
* * **A per-ATTEMPT timeout inside a per-CALL deadline**, so N retries cannot
|
|
439
|
+
* silently multiply the caller's wait by N.
|
|
440
|
+
*/
|
|
441
|
+
private post;
|
|
442
|
+
/**
|
|
443
|
+
* Sleep before the next attempt. Returns false when the call's deadline would
|
|
444
|
+
* be passed, in which case the caller throws instead of sleeping into it.
|
|
445
|
+
*
|
|
446
|
+
* FULL JITTER: `random(0, base * 2^n)`, the AWS architecture-blog form. A
|
|
447
|
+
* fixed backoff synchronises every client that failed on the same server
|
|
448
|
+
* event and reproduces the spike that caused it.
|
|
449
|
+
*/
|
|
450
|
+
private backoff;
|
|
451
|
+
/**
|
|
452
|
+
* Create a consent session; returns the hosted collect URL.
|
|
453
|
+
*
|
|
454
|
+
* createSession({
|
|
455
|
+
* dataPrincipal: { email: 'riya@example.in' },
|
|
456
|
+
* noticeInternalName: 'bnb_consent_v2',
|
|
457
|
+
* dateOfBirth: '1998-04-12',
|
|
458
|
+
* })
|
|
459
|
+
*
|
|
460
|
+
* Send `dataPrincipal` — the identifiers, keyed by YOUR organisation's locked
|
|
461
|
+
* integration key — or `dataPrincipalId` when you already hold the platform's
|
|
462
|
+
* uuid for the person. Sent together they must agree, or the call is refused
|
|
463
|
+
* 409 IDENTITY_MISMATCH. A request carrying neither falls to the key's floor,
|
|
464
|
+
* 400 IDENTIFIER_REQUIRED.
|
|
465
|
+
*
|
|
466
|
+
* ─── THIS IS THE U58 WIRE, AND THERE IS NO OVERLAP WINDOW ──────────────
|
|
467
|
+
*
|
|
468
|
+
* EVERY KEY BELOW IS ONE THE API DECODES. The handler decodes with NO
|
|
469
|
+
* DisallowUnknownFields — on the old wire and on this one alike — so a key it
|
|
470
|
+
* does not know is dropped in SILENCE; the request is then refused for
|
|
471
|
+
* carrying no identifier, which names a condition and not the field you sent.
|
|
472
|
+
* That is why an SDK on the wrong wire fails obscurely rather than loudly,
|
|
473
|
+
* and why this version talks to an API carrying U58 and to no other.
|
|
474
|
+
*/
|
|
475
|
+
createSession(req: CreateSessionRequest): Promise<ConsentSession>;
|
|
476
|
+
/**
|
|
477
|
+
* Present the hosted consent notice in an IN-APP browser.
|
|
478
|
+
*
|
|
479
|
+
* ─── WHY A PEER AND NOT `Linking.openURL` ───────────────────────────────
|
|
480
|
+
*
|
|
481
|
+
* This used to be `Linking.openURL`, which leaves the app entirely for the
|
|
482
|
+
* external browser. Three things follow and none is acceptable for a consent
|
|
483
|
+
* surface: the callback comes back over a custom scheme any installed app can
|
|
484
|
+
* also claim; nothing tells the caller whether the page even opened; and the
|
|
485
|
+
* person is gone from the app with no cancellation signal. React Native has no
|
|
486
|
+
* built-in Custom Tabs / SFSafariViewController binding, so the in-app browser
|
|
487
|
+
* comes from a peer.
|
|
488
|
+
*
|
|
489
|
+
* INSTALL THE PEER:
|
|
490
|
+
*
|
|
491
|
+
* npm i react-native-inappbrowser-reborn # then: cd ios && pod install
|
|
492
|
+
*
|
|
493
|
+
* Expo apps can pass `expo-web-browser`'s `openAuthSessionAsync` through
|
|
494
|
+
* {@link SessionConfig} instead — see `openInAppBrowser` below.
|
|
495
|
+
*
|
|
496
|
+
* ─── IT REFUSES RATHER THAN DEGRADING ───────────────────────────────────
|
|
497
|
+
*
|
|
498
|
+
* With no peer available this THROWS. It does not fall back to
|
|
499
|
+
* `Linking.openURL`, because that would quietly restore every property above
|
|
500
|
+
* on exactly the devices where the peer failed to link.
|
|
501
|
+
*
|
|
502
|
+
* @returns the callback URL the in-app browser intercepted, or null when the
|
|
503
|
+
* person dismissed it. THE DEEP LINK IS STILL BEST-EFFORT — Chrome blocks
|
|
504
|
+
* gesture-less custom-scheme redirects — so treat null as "unknown" and
|
|
505
|
+
* re-validate, never as "denied".
|
|
506
|
+
*/
|
|
507
|
+
presentConsent(session: ConsentSession | string): Promise<string | null>;
|
|
508
|
+
/**
|
|
509
|
+
* Open a non-consent hosted page (the DP portal) in the same in-app browser.
|
|
510
|
+
* Returns nothing to check: the portal has no consent callback.
|
|
511
|
+
*/
|
|
512
|
+
private presentHosted;
|
|
513
|
+
/**
|
|
514
|
+
* Authoritative decision check — the ONLY source of consent truth.
|
|
515
|
+
*
|
|
516
|
+
* validate({ dataPrincipalIdentifiers: { email: 'riya@example.in' } }, 'product_analytics')
|
|
517
|
+
* validate({ dataPrincipalId: '…' }, 'product_analytics')
|
|
518
|
+
*
|
|
519
|
+
* `data_principal_ref` is REFUSED OUTRIGHT (400, message prefixed
|
|
520
|
+
* `DATA_PRINCIPAL_REF_REFUSED`). Name people by the organisation's locked
|
|
521
|
+
* key fields — the mobile atom is `mobile` here and on create alike (F015);
|
|
522
|
+
* `phone` is refused by name.
|
|
523
|
+
*/
|
|
524
|
+
validate(who: PrincipalRef, purposeCode: string): Promise<ConsentDecision>;
|
|
525
|
+
/** Withdraw purposes (codes or UUIDs) for the person named by [who]. */
|
|
526
|
+
withdraw(who: PrincipalRef, purposes: string[]): Promise<unknown>;
|
|
527
|
+
/**
|
|
528
|
+
* Mint a fresh single-use DP-portal SSO link (never cache it).
|
|
529
|
+
*
|
|
530
|
+
* createPortalSession({ mobile: '+919876500000' })
|
|
531
|
+
* createPortalSession({ customer_id: 'CUST-90210' })
|
|
532
|
+
*
|
|
533
|
+
* The person is named THE SAME WAY AS EVERYWHERE ELSE in this SDK: a map
|
|
534
|
+
* keyed by your organisation's identifier fields (F015). The KEY is the
|
|
535
|
+
* identifier's kind. Before MOB-043 this took a bare string and always
|
|
536
|
+
* declared it `email`, whatever your organisation is keyed on, so an
|
|
537
|
+
* organisation keyed on mobile or customer_id sent every person's number as
|
|
538
|
+
* an email address.
|
|
539
|
+
*
|
|
540
|
+
* THE WIRE IS STILL THE PAIR. The portal road (rights/principal
|
|
541
|
+
* portal_session_handlers.go at 4fda7e3d05) takes one `data_principal_ref`
|
|
542
|
+
* and its `data_principal_ref_type`, and defaults an absent type to email.
|
|
543
|
+
* So this SDK always sends the type, and sends exactly ONE identifier: the
|
|
544
|
+
* map's only entry, or, when you pass several and configured
|
|
545
|
+
* {@link SessionConfig.identifierScheme}, the first scheme field present.
|
|
546
|
+
*
|
|
547
|
+
* `phone` is refused here, before the wire (UNKNOWN_IDENTIFIER_FIELD). The
|
|
548
|
+
* portal road would silently fold it to `mobile`, but this SDK's
|
|
549
|
+
* vocabulary has one spelling, and on every other road `phone` is refused
|
|
550
|
+
* by name. The accepted kinds are the platform's resolver set:
|
|
551
|
+
* customer_id, email, mobile, aadhaar. The platform refuses anything else
|
|
552
|
+
* and names that set. It auto-provisions a portal account only from an
|
|
553
|
+
* email; for another kind the person must already have one (404, whose
|
|
554
|
+
* `platformMessage` says so).
|
|
555
|
+
*/
|
|
556
|
+
createPortalSession(identifiers: DataPrincipalIdentifiers): Promise<PortalSession>;
|
|
557
|
+
/** Mint + open the full DP portal in one tap, in the same in-app browser. */
|
|
558
|
+
openPortal(identifiers: DataPrincipalIdentifiers): Promise<void>;
|
|
559
|
+
/**
|
|
560
|
+
* Parse and CHECK the deep link the hosted page redirects to on submit.
|
|
561
|
+
*
|
|
562
|
+
* ─── WHAT IS CHECKED, AND WHY EACH ONE ──────────────────────────────────
|
|
563
|
+
*
|
|
564
|
+
* scheme AND host AND path, all three. This used to compare only
|
|
565
|
+
* `url.startsWith('myapp://')`, which accepts
|
|
566
|
+
* `myapp://anything/anywhere?status=granted`. A custom scheme is first-come on
|
|
567
|
+
* Android and undefined on iOS: another installed app can register the same
|
|
568
|
+
* one, and the only thing that distinguishes OUR callback from its invention
|
|
569
|
+
* is the whole URL plus the nonce.
|
|
570
|
+
*
|
|
571
|
+
* `state` must equal `expectedState` when one is given — the nonce
|
|
572
|
+
* `createSession` put on `callback_url`, echoed back because
|
|
573
|
+
* `addRedirectParams` (consent/collection.go) appends to an existing query
|
|
574
|
+
* rather than replacing it.
|
|
575
|
+
*
|
|
576
|
+
* The query is parsed with the platform URL parser, not by splitting on `=`.
|
|
577
|
+
* The old hand-rolled split kept only the first two parts of each pair, so any
|
|
578
|
+
* value containing `=` — a base64 artifact id, for instance — was silently
|
|
579
|
+
* truncated.
|
|
580
|
+
*
|
|
581
|
+
* ─── WHAT IS STILL NOT PROVEN ───────────────────────────────────────────
|
|
582
|
+
*
|
|
583
|
+
* That the person granted anything. `status=granted` is a query parameter, and
|
|
584
|
+
* this SDK cannot verify the platform's `sig` without the DF's signing secret,
|
|
585
|
+
* which must not be in the app. ALWAYS confirm by reading the consent back
|
|
586
|
+
* through your backend (`validate`) — and expect that read to wait while
|
|
587
|
+
* `pending` is true.
|
|
588
|
+
*
|
|
589
|
+
* `callbackStatus` is `granted | partial | denied` exactly as the platform
|
|
590
|
+
* issues them; anything else is `unknown`, never a grant.
|
|
591
|
+
*
|
|
592
|
+
* Pass `expectedState` as null ONLY when the app was killed during the browser
|
|
593
|
+
* leg and `ConsentSession.callbackState` is genuinely gone — then re-validate
|
|
594
|
+
* rather than trusting this.
|
|
595
|
+
*
|
|
596
|
+
* @throws ConsenteraError when the link is not ours.
|
|
597
|
+
*/
|
|
598
|
+
parseCallback(url: string, expectedState: string | null): ConsentCallback;
|
|
599
|
+
}
|
|
600
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/session.ts"],"names":[],"mappings":"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"}
|