@proveanything/smartlinks 1.15.10 → 1.15.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/authKit.d.ts +58 -3
- package/dist/api/authKit.js +116 -4
- package/dist/docs/API_SUMMARY.md +125 -9
- package/dist/docs/analytics-metadata-conventions.md +4 -0
- package/dist/docs/analytics.md +37 -3
- package/dist/docs/appConfig.md +46 -5
- package/dist/docs/auth-kit.md +110 -0
- package/dist/docs/item-context.md +1 -2
- package/dist/docs/utils.md +2 -2
- package/dist/openapi.yaml +415 -1
- package/dist/types/analytics.d.ts +37 -2
- package/dist/types/appConfiguration.d.ts +16 -0
- package/dist/types/authKit.d.ts +90 -0
- package/dist/utils/conditions.d.ts +7 -11
- package/dist/utils/conditions.js +4 -10
- package/docs/API_SUMMARY.md +125 -9
- package/docs/analytics-metadata-conventions.md +4 -0
- package/docs/analytics.md +37 -3
- package/docs/appConfig.md +46 -5
- package/docs/auth-kit.md +110 -0
- package/docs/item-context.md +1 -2
- package/docs/utils.md +2 -2
- package/openapi.yaml +415 -1
- package/package.json +1 -1
package/dist/docs/auth-kit.md
CHANGED
|
@@ -304,6 +304,116 @@ clearPersistedTokens();
|
|
|
304
304
|
|
|
305
305
|
---
|
|
306
306
|
|
|
307
|
+
## Step-up MFA (Phase 1)
|
|
308
|
+
|
|
309
|
+
Backend-only for now — **no admin-console UI and no challenge UI ship with this pass.**
|
|
310
|
+
Factors: **email OTP, SMS OTP, recovery codes**. WhatsApp OTP, TOTP, and passkeys are
|
|
311
|
+
deferred to a later phase; don't build against them yet.
|
|
312
|
+
|
|
313
|
+
The step-up gate is wired into **`login()` only** — `register`, `verifyPhoneCode`, and
|
|
314
|
+
`verifyMagicLink` never return `MFA_REQUIRED`, regardless of client config.
|
|
315
|
+
|
|
316
|
+
### Handling `MFA_REQUIRED` from `login()`
|
|
317
|
+
|
|
318
|
+
`login()`'s return type is unchanged. When the client's MFA policy requires a step-up,
|
|
319
|
+
the server returns 403 instead of a session, and `login()` throws:
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
import { authKit, SmartlinksApiError } from '@proveanything/smartlinks';
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
const session = await authKit.login(clientId, email, password);
|
|
326
|
+
// logged in, no MFA required
|
|
327
|
+
} catch (err) {
|
|
328
|
+
if (err instanceof SmartlinksApiError && err.errorCode === 'MFA_REQUIRED') {
|
|
329
|
+
const { mfaSessionToken, availableFactors, preferredFactor, maskedDestinations } = err.details!;
|
|
330
|
+
// → route to a challenge UI; call authKit.mfaChallengeSend(clientId, mfaSessionToken, preferredFactor)
|
|
331
|
+
} else {
|
|
332
|
+
throw err;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Completing the challenge
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
// Send (or resend, or switch factor) a code on the same mfaSessionToken
|
|
341
|
+
const sent = await authKit.mfaChallengeSend(clientId, mfaSessionToken, 'sms');
|
|
342
|
+
// sent.destination is masked, e.g. "+1******1234"
|
|
343
|
+
|
|
344
|
+
// Verify the code — behaves like login() on success: bearer token is adopted automatically
|
|
345
|
+
const session = await authKit.mfaChallengeVerify(clientId, mfaSessionToken, '123456', /* trustDevice */ true, 'My Laptop');
|
|
346
|
+
|
|
347
|
+
// Or finalize with a single-use recovery code instead
|
|
348
|
+
const session = await authKit.mfaRecoveryCode(clientId, mfaSessionToken, recoveryCode);
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
`mfaSessionToken` is short-lived (10 min) and single-use — burned on 5 failed attempts
|
|
352
|
+
(`MFA_TOO_MANY_ATTEMPTS`) or on success. Once burned/expired, there's no "resend within the
|
|
353
|
+
same session" — the caller must restart from `login()`.
|
|
354
|
+
|
|
355
|
+
### Trusted devices — "don't ask again on this device"
|
|
356
|
+
|
|
357
|
+
There's no fingerprinting involved: a "recognized device" is purely "the caller presented a
|
|
358
|
+
valid, unexpired, unrevoked `trustedDeviceToken`". Handle it like the native refresh token
|
|
359
|
+
above — same secure storage, same persist-before-next-call discipline:
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
// 1) Persist trustedDeviceToken from a successful challenge (trustDevice: true)
|
|
363
|
+
persistTrustedDeviceToken(session.trustedDeviceToken, session.trustedDeviceExpiresAt);
|
|
364
|
+
|
|
365
|
+
// 2) Send it on every subsequent login() — if still valid, the challenge is skipped entirely
|
|
366
|
+
const session = await authKit.login(clientId, email, password, storedTrustedDeviceToken);
|
|
367
|
+
// If it's revoked/expired, the server silently falls back to requiring a fresh challenge —
|
|
368
|
+
// login() just throws MFA_REQUIRED again, no special-case handling needed.
|
|
369
|
+
|
|
370
|
+
// 3) Let users audit/revoke devices from a Settings screen
|
|
371
|
+
const { devices } = await authKit.listTrustedDevices(clientId);
|
|
372
|
+
await authKit.revokeTrustedDevice(clientId, deviceId);
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Factor management (Settings → Security)
|
|
376
|
+
|
|
377
|
+
Authenticated (bearer token) — same `mfaSessionToken` + code mechanism as login challenges,
|
|
378
|
+
just against a `purpose: 'enroll'` challenge instead of `'login'`.
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
// Enroll email (uses the account's existing email)
|
|
382
|
+
const { mfaSessionToken } = await authKit.enrollEmailMfa(clientId);
|
|
383
|
+
await authKit.confirmEmailMfa(clientId, mfaSessionToken, code);
|
|
384
|
+
|
|
385
|
+
// Enroll SMS
|
|
386
|
+
const { mfaSessionToken: smsToken } = await authKit.enrollSmsMfa(clientId, '+61400000000');
|
|
387
|
+
await authKit.confirmSmsMfa(clientId, smsToken, code);
|
|
388
|
+
|
|
389
|
+
// Recovery codes — plaintext, shown exactly once; nothing else in the API returns them again
|
|
390
|
+
const { recoveryCodes } = await authKit.generateMfaRecoveryCodes(clientId, password);
|
|
391
|
+
|
|
392
|
+
// Inspect / remove
|
|
393
|
+
const factors = await authKit.getMfaFactors(clientId);
|
|
394
|
+
// factors: { enrolledFactors: { email?, sms? }, recoveryCodesRemaining, mfaEnabledForClient }
|
|
395
|
+
await authKit.removeMfaFactor(clientId, 'sms', password);
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
> Enrollment endpoints don't currently check the client's `mfa.mode` — enrolling is possible
|
|
399
|
+
> even when MFA is configured `'off'` for a client. Those factors simply won't be challenged
|
|
400
|
+
> at login until an admin turns the mode on (via the existing admin AuthKit config update,
|
|
401
|
+
> no new admin route in this pass).
|
|
402
|
+
|
|
403
|
+
### MFA error codes
|
|
404
|
+
|
|
405
|
+
| `errorCode` | HTTP | Meaning / client action |
|
|
406
|
+
|---|---|---|
|
|
407
|
+
| `MFA_REQUIRED` | 403 | From `login()` only — see above |
|
|
408
|
+
| `INVALID_MFA_CODE` | 401 | Wrong code — let the user retry (attempts are capped) |
|
|
409
|
+
| `MFA_TOO_MANY_ATTEMPTS` | 429 | 5 wrong attempts — the challenge is burned; restart from `login()` |
|
|
410
|
+
| `MFA_FACTOR_NOT_ENROLLED` | 400 | Requested factor isn't enrolled — programming error if the UI only offers `availableFactors` |
|
|
411
|
+
| `MFA_SESSION_EXPIRED` | 401 | `mfaSessionToken` past its 10-minute TTL — restart from `login()` |
|
|
412
|
+
| `MFA_SESSION_INVALID` | 401 | Unknown/wrong-client/already-consumed token, or (on enroll confirm) mismatched user |
|
|
413
|
+
| `RECOVERY_CODE_INVALID` | 401 | Wrong or already-used recovery code |
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
307
417
|
## Profile management
|
|
308
418
|
|
|
309
419
|
```ts
|
|
@@ -163,8 +163,7 @@ const showFakeWarning = await validateCondition({
|
|
|
163
163
|
- `isAuthentic` — passes when `itemContext.isAuthentic` is true (`valid`/`rescan`)
|
|
164
164
|
- `notAuthentic` — passes when an `itemContext` was resolved but isn't authentic (`invalid`/`not-found`/`error`)
|
|
165
165
|
- `invalidProof` — passes specifically when resolution was attempted and came back `invalid` or `not-found` — the "someone scanned a fake tag / typed a bad serial" case, as distinct from `noProof` ("nothing was on the URL to check at all")
|
|
166
|
-
- `
|
|
167
|
-
- `isRescan` — authentic but a duplicate/replayed tap (`status === 'rescan'`) — use this to suppress "first scan" celebration UX without treating the tag as fake; `isAuthentic` alone is true for both `isFirstScan` and `isRescan` cases
|
|
166
|
+
- `isRescan` — authentic but a duplicate/replayed tap (`status === 'rescan'`) — use this to suppress "first scan" celebration UX without treating the tag as fake; `isAuthentic` alone is true for both a fresh tap and a rescan
|
|
168
167
|
|
|
169
168
|
## Deprecated
|
|
170
169
|
|
package/dist/docs/utils.md
CHANGED
|
@@ -530,9 +530,9 @@ await utils.validateCondition({
|
|
|
530
530
|
Status types:
|
|
531
531
|
- Claim/ownership (reads `proof`): `'isClaimable'`, `'notClaimable'`, `'isVirtual'`, `'notVirtual'`
|
|
532
532
|
- Presence (reads `proof`): `'hasProof'`, `'noProof'` — `noProof` only means *nothing was attempted*, not that an attempt failed
|
|
533
|
-
- Authenticity (reads `itemContext`): `'isAuthentic'`, `'notAuthentic'`, `'invalidProof'`, `'
|
|
533
|
+
- Authenticity (reads `itemContext`): `'isAuthentic'`, `'notAuthentic'`, `'invalidProof'`, `'isRescan'`
|
|
534
534
|
- `invalidProof` is specifically "an identifier was passed and resolution came back `invalid`/`not-found`", distinct from `noProof`'s "nothing on the URL to check at all"
|
|
535
|
-
- `isAuthentic` is true for both a fresh tap and a rescan. Use `
|
|
535
|
+
- `isAuthentic` is true for both a fresh tap and a rescan. Use `isRescan` (authentic but `status === 'rescan'`) to suppress "first scan" celebration UX without treating the tag as fake
|
|
536
536
|
|
|
537
537
|
#### Version Conditions
|
|
538
538
|
For A/B testing or versioned content:
|
package/dist/openapi.yaml
CHANGED
|
@@ -8077,7 +8077,7 @@ paths:
|
|
|
8077
8077
|
get:
|
|
8078
8078
|
tags:
|
|
8079
8079
|
- authKit
|
|
8080
|
-
summary:
|
|
8080
|
+
summary: Revoke a single trusted device by id (authenticated).
|
|
8081
8081
|
operationId: authKit_load
|
|
8082
8082
|
security: []
|
|
8083
8083
|
parameters:
|
|
@@ -8970,6 +8970,285 @@ paths:
|
|
|
8970
8970
|
application/json:
|
|
8971
8971
|
schema:
|
|
8972
8972
|
$ref: "#/components/schemas/UpsertContactRequest"
|
|
8973
|
+
/authkit/{clientId}/mfa/challenge/recovery-code:
|
|
8974
|
+
post:
|
|
8975
|
+
tags:
|
|
8976
|
+
- authKit
|
|
8977
|
+
summary: Finalize a challenged login using a single-use recovery code instead of a sent code (public).
|
|
8978
|
+
operationId: authKit_mfaRecoveryCode
|
|
8979
|
+
security: []
|
|
8980
|
+
parameters:
|
|
8981
|
+
- name: clientId
|
|
8982
|
+
in: path
|
|
8983
|
+
required: true
|
|
8984
|
+
schema:
|
|
8985
|
+
type: string
|
|
8986
|
+
responses:
|
|
8987
|
+
200:
|
|
8988
|
+
description: Success
|
|
8989
|
+
content:
|
|
8990
|
+
application/json:
|
|
8991
|
+
schema:
|
|
8992
|
+
$ref: "#/components/schemas/MfaFinalizeResponse"
|
|
8993
|
+
400:
|
|
8994
|
+
description: Bad request
|
|
8995
|
+
401:
|
|
8996
|
+
description: Unauthorized
|
|
8997
|
+
404:
|
|
8998
|
+
description: Not found
|
|
8999
|
+
/authkit/{clientId}/mfa/challenge/send:
|
|
9000
|
+
post:
|
|
9001
|
+
tags:
|
|
9002
|
+
- authKit
|
|
9003
|
+
summary: Send (or resend) an MFA challenge code to the given factor (public).
|
|
9004
|
+
operationId: authKit_mfaChallengeSend
|
|
9005
|
+
security: []
|
|
9006
|
+
parameters:
|
|
9007
|
+
- name: clientId
|
|
9008
|
+
in: path
|
|
9009
|
+
required: true
|
|
9010
|
+
schema:
|
|
9011
|
+
type: string
|
|
9012
|
+
responses:
|
|
9013
|
+
200:
|
|
9014
|
+
description: Success
|
|
9015
|
+
content:
|
|
9016
|
+
application/json:
|
|
9017
|
+
schema:
|
|
9018
|
+
$ref: "#/components/schemas/MfaChallengeSendResponse"
|
|
9019
|
+
400:
|
|
9020
|
+
description: Bad request
|
|
9021
|
+
401:
|
|
9022
|
+
description: Unauthorized
|
|
9023
|
+
404:
|
|
9024
|
+
description: Not found
|
|
9025
|
+
requestBody:
|
|
9026
|
+
required: true
|
|
9027
|
+
content:
|
|
9028
|
+
application/json:
|
|
9029
|
+
schema:
|
|
9030
|
+
type: string
|
|
9031
|
+
enum:
|
|
9032
|
+
- email
|
|
9033
|
+
- sms
|
|
9034
|
+
/authkit/{clientId}/mfa/challenge/verify:
|
|
9035
|
+
post:
|
|
9036
|
+
tags:
|
|
9037
|
+
- authKit
|
|
9038
|
+
summary: Verify an MFA challenge code and finalize the login (public).
|
|
9039
|
+
operationId: authKit_mfaChallengeVerify
|
|
9040
|
+
security: []
|
|
9041
|
+
parameters:
|
|
9042
|
+
- name: clientId
|
|
9043
|
+
in: path
|
|
9044
|
+
required: true
|
|
9045
|
+
schema:
|
|
9046
|
+
type: string
|
|
9047
|
+
responses:
|
|
9048
|
+
200:
|
|
9049
|
+
description: Success
|
|
9050
|
+
content:
|
|
9051
|
+
application/json:
|
|
9052
|
+
schema:
|
|
9053
|
+
$ref: "#/components/schemas/MfaFinalizeResponse"
|
|
9054
|
+
400:
|
|
9055
|
+
description: Bad request
|
|
9056
|
+
401:
|
|
9057
|
+
description: Unauthorized
|
|
9058
|
+
404:
|
|
9059
|
+
description: Not found
|
|
9060
|
+
/authkit/{clientId}/mfa/factors:
|
|
9061
|
+
get:
|
|
9062
|
+
tags:
|
|
9063
|
+
- authKit
|
|
9064
|
+
summary: List enrolled factors and recovery-code count for the current user (authenticated).
|
|
9065
|
+
operationId: authKit_getMfaFactors
|
|
9066
|
+
security: []
|
|
9067
|
+
parameters:
|
|
9068
|
+
- name: clientId
|
|
9069
|
+
in: path
|
|
9070
|
+
required: true
|
|
9071
|
+
schema:
|
|
9072
|
+
type: string
|
|
9073
|
+
responses:
|
|
9074
|
+
200:
|
|
9075
|
+
description: Success
|
|
9076
|
+
content:
|
|
9077
|
+
application/json:
|
|
9078
|
+
schema:
|
|
9079
|
+
$ref: "#/components/schemas/MfaFactorsResponse"
|
|
9080
|
+
400:
|
|
9081
|
+
description: Bad request
|
|
9082
|
+
401:
|
|
9083
|
+
description: Unauthorized
|
|
9084
|
+
404:
|
|
9085
|
+
description: Not found
|
|
9086
|
+
/authkit/{clientId}/mfa/factors/email/confirm:
|
|
9087
|
+
post:
|
|
9088
|
+
tags:
|
|
9089
|
+
- authKit
|
|
9090
|
+
summary: "Confirm email-factor enrollment with the code sent by {@link enrollEmailMfa} (authenticated)."
|
|
9091
|
+
operationId: authKit_confirmEmailMfa
|
|
9092
|
+
security: []
|
|
9093
|
+
parameters:
|
|
9094
|
+
- name: clientId
|
|
9095
|
+
in: path
|
|
9096
|
+
required: true
|
|
9097
|
+
schema:
|
|
9098
|
+
type: string
|
|
9099
|
+
responses:
|
|
9100
|
+
200:
|
|
9101
|
+
description: Success
|
|
9102
|
+
content:
|
|
9103
|
+
application/json:
|
|
9104
|
+
schema:
|
|
9105
|
+
$ref: "#/components/schemas/MfaEnrolledResponse"
|
|
9106
|
+
400:
|
|
9107
|
+
description: Bad request
|
|
9108
|
+
401:
|
|
9109
|
+
description: Unauthorized
|
|
9110
|
+
404:
|
|
9111
|
+
description: Not found
|
|
9112
|
+
/authkit/{clientId}/mfa/factors/email/enroll:
|
|
9113
|
+
post:
|
|
9114
|
+
tags:
|
|
9115
|
+
- authKit
|
|
9116
|
+
summary: "Begin email-factor enrollment; sends a code to the account's existing email (authenticated)."
|
|
9117
|
+
operationId: authKit_enrollEmailMfa
|
|
9118
|
+
security: []
|
|
9119
|
+
parameters:
|
|
9120
|
+
- name: clientId
|
|
9121
|
+
in: path
|
|
9122
|
+
required: true
|
|
9123
|
+
schema:
|
|
9124
|
+
type: string
|
|
9125
|
+
responses:
|
|
9126
|
+
200:
|
|
9127
|
+
description: Success
|
|
9128
|
+
content:
|
|
9129
|
+
application/json:
|
|
9130
|
+
schema:
|
|
9131
|
+
$ref: "#/components/schemas/MfaEnrollSendResponse"
|
|
9132
|
+
400:
|
|
9133
|
+
description: Bad request
|
|
9134
|
+
401:
|
|
9135
|
+
description: Unauthorized
|
|
9136
|
+
404:
|
|
9137
|
+
description: Not found
|
|
9138
|
+
/authkit/{clientId}/mfa/factors/sms/confirm:
|
|
9139
|
+
post:
|
|
9140
|
+
tags:
|
|
9141
|
+
- authKit
|
|
9142
|
+
summary: "Confirm SMS-factor enrollment with the code sent by {@link enrollSmsMfa} (authenticated)."
|
|
9143
|
+
operationId: authKit_confirmSmsMfa
|
|
9144
|
+
security: []
|
|
9145
|
+
parameters:
|
|
9146
|
+
- name: clientId
|
|
9147
|
+
in: path
|
|
9148
|
+
required: true
|
|
9149
|
+
schema:
|
|
9150
|
+
type: string
|
|
9151
|
+
responses:
|
|
9152
|
+
200:
|
|
9153
|
+
description: Success
|
|
9154
|
+
content:
|
|
9155
|
+
application/json:
|
|
9156
|
+
schema:
|
|
9157
|
+
$ref: "#/components/schemas/MfaEnrolledResponse"
|
|
9158
|
+
400:
|
|
9159
|
+
description: Bad request
|
|
9160
|
+
401:
|
|
9161
|
+
description: Unauthorized
|
|
9162
|
+
404:
|
|
9163
|
+
description: Not found
|
|
9164
|
+
/authkit/{clientId}/mfa/factors/sms/enroll:
|
|
9165
|
+
post:
|
|
9166
|
+
tags:
|
|
9167
|
+
- authKit
|
|
9168
|
+
summary: Begin SMS-factor enrollment; sends a code to the given phone number (authenticated).
|
|
9169
|
+
operationId: authKit_enrollSmsMfa
|
|
9170
|
+
security: []
|
|
9171
|
+
parameters:
|
|
9172
|
+
- name: clientId
|
|
9173
|
+
in: path
|
|
9174
|
+
required: true
|
|
9175
|
+
schema:
|
|
9176
|
+
type: string
|
|
9177
|
+
responses:
|
|
9178
|
+
200:
|
|
9179
|
+
description: Success
|
|
9180
|
+
content:
|
|
9181
|
+
application/json:
|
|
9182
|
+
schema:
|
|
9183
|
+
$ref: "#/components/schemas/MfaEnrollSendResponse"
|
|
9184
|
+
400:
|
|
9185
|
+
description: Bad request
|
|
9186
|
+
401:
|
|
9187
|
+
description: Unauthorized
|
|
9188
|
+
404:
|
|
9189
|
+
description: Not found
|
|
9190
|
+
/authkit/{clientId}/mfa/factors/{factor}:
|
|
9191
|
+
get:
|
|
9192
|
+
tags:
|
|
9193
|
+
- authKit
|
|
9194
|
+
summary: Remove an enrolled MFA factor (authenticated).
|
|
9195
|
+
operationId: authKit_removeMfaFactor
|
|
9196
|
+
security: []
|
|
9197
|
+
parameters:
|
|
9198
|
+
- name: clientId
|
|
9199
|
+
in: path
|
|
9200
|
+
required: true
|
|
9201
|
+
schema:
|
|
9202
|
+
type: string
|
|
9203
|
+
- name: factor
|
|
9204
|
+
in: path
|
|
9205
|
+
required: true
|
|
9206
|
+
schema:
|
|
9207
|
+
type: string
|
|
9208
|
+
responses:
|
|
9209
|
+
200:
|
|
9210
|
+
description: Success
|
|
9211
|
+
content:
|
|
9212
|
+
application/json:
|
|
9213
|
+
schema:
|
|
9214
|
+
$ref: "#/components/schemas/SuccessResponse"
|
|
9215
|
+
400:
|
|
9216
|
+
description: Bad request
|
|
9217
|
+
401:
|
|
9218
|
+
description: Unauthorized
|
|
9219
|
+
404:
|
|
9220
|
+
description: Not found
|
|
9221
|
+
/authkit/{clientId}/mfa/trusted-devices/{id}:
|
|
9222
|
+
delete:
|
|
9223
|
+
tags:
|
|
9224
|
+
- authKit
|
|
9225
|
+
summary: Revoke a single trusted device by id (authenticated).
|
|
9226
|
+
operationId: authKit_revokeTrustedDevice
|
|
9227
|
+
security: []
|
|
9228
|
+
parameters:
|
|
9229
|
+
- name: clientId
|
|
9230
|
+
in: path
|
|
9231
|
+
required: true
|
|
9232
|
+
schema:
|
|
9233
|
+
type: string
|
|
9234
|
+
- name: id
|
|
9235
|
+
in: path
|
|
9236
|
+
required: true
|
|
9237
|
+
schema:
|
|
9238
|
+
type: string
|
|
9239
|
+
responses:
|
|
9240
|
+
200:
|
|
9241
|
+
description: Success
|
|
9242
|
+
content:
|
|
9243
|
+
application/json:
|
|
9244
|
+
schema:
|
|
9245
|
+
$ref: "#/components/schemas/SuccessResponse"
|
|
9246
|
+
400:
|
|
9247
|
+
description: Bad request
|
|
9248
|
+
401:
|
|
9249
|
+
description: Unauthorized
|
|
9250
|
+
404:
|
|
9251
|
+
description: Not found
|
|
8973
9252
|
/platform/location:
|
|
8974
9253
|
post:
|
|
8975
9254
|
tags:
|
|
@@ -14979,6 +15258,8 @@ components:
|
|
|
14979
15258
|
type: boolean
|
|
14980
15259
|
location:
|
|
14981
15260
|
$ref: "#/components/schemas/AnalyticsLocation"
|
|
15261
|
+
source:
|
|
15262
|
+
type: string
|
|
14982
15263
|
metadata:
|
|
14983
15264
|
type: object
|
|
14984
15265
|
additionalProperties: true
|
|
@@ -15014,6 +15295,8 @@ components:
|
|
|
15014
15295
|
$ref: "#/components/schemas/AnalyticsLocation"
|
|
15015
15296
|
isAdmin:
|
|
15016
15297
|
type: boolean
|
|
15298
|
+
redirectMode:
|
|
15299
|
+
type: string
|
|
15017
15300
|
metadata:
|
|
15018
15301
|
type: object
|
|
15019
15302
|
additionalProperties: true
|
|
@@ -15222,6 +15505,16 @@ components:
|
|
|
15222
15505
|
type: boolean
|
|
15223
15506
|
hasLocation:
|
|
15224
15507
|
type: boolean
|
|
15508
|
+
sources:
|
|
15509
|
+
type: array
|
|
15510
|
+
items:
|
|
15511
|
+
type: string
|
|
15512
|
+
redirectMode:
|
|
15513
|
+
type: string
|
|
15514
|
+
redirectModes:
|
|
15515
|
+
type: array
|
|
15516
|
+
items:
|
|
15517
|
+
type: string
|
|
15225
15518
|
AnalyticsSummaryRequest:
|
|
15226
15519
|
type: object
|
|
15227
15520
|
properties:
|
|
@@ -15666,6 +15959,9 @@ components:
|
|
|
15666
15959
|
properties:
|
|
15667
15960
|
basePlanId:
|
|
15668
15961
|
type: string
|
|
15962
|
+
productMode:
|
|
15963
|
+
type: object
|
|
15964
|
+
additionalProperties: true
|
|
15669
15965
|
addOnKeys:
|
|
15670
15966
|
type: array
|
|
15671
15967
|
items:
|
|
@@ -18413,6 +18709,124 @@ components:
|
|
|
18413
18709
|
userInfo:
|
|
18414
18710
|
type: object
|
|
18415
18711
|
additionalProperties: true
|
|
18712
|
+
MfaRequiredDetails:
|
|
18713
|
+
type: object
|
|
18714
|
+
properties:
|
|
18715
|
+
mfaSessionToken:
|
|
18716
|
+
type: string
|
|
18717
|
+
availableFactors:
|
|
18718
|
+
type: array
|
|
18719
|
+
items:
|
|
18720
|
+
type: string
|
|
18721
|
+
enum:
|
|
18722
|
+
- email
|
|
18723
|
+
- sms
|
|
18724
|
+
preferredFactor:
|
|
18725
|
+
type: string
|
|
18726
|
+
enum:
|
|
18727
|
+
- email
|
|
18728
|
+
- sms
|
|
18729
|
+
maskedDestinations:
|
|
18730
|
+
type: object
|
|
18731
|
+
additionalProperties: true
|
|
18732
|
+
required:
|
|
18733
|
+
- mfaSessionToken
|
|
18734
|
+
- availableFactors
|
|
18735
|
+
- preferredFactor
|
|
18736
|
+
- maskedDestinations
|
|
18737
|
+
MfaChallengeSendResponse:
|
|
18738
|
+
type: object
|
|
18739
|
+
properties:
|
|
18740
|
+
success:
|
|
18741
|
+
type: object
|
|
18742
|
+
additionalProperties: true
|
|
18743
|
+
factor:
|
|
18744
|
+
type: string
|
|
18745
|
+
enum:
|
|
18746
|
+
- email
|
|
18747
|
+
- sms
|
|
18748
|
+
destination:
|
|
18749
|
+
type: string
|
|
18750
|
+
expiresAt:
|
|
18751
|
+
type: string
|
|
18752
|
+
required:
|
|
18753
|
+
- success
|
|
18754
|
+
- factor
|
|
18755
|
+
- destination
|
|
18756
|
+
- expiresAt
|
|
18757
|
+
MfaFinalizeResponse:
|
|
18758
|
+
type: object
|
|
18759
|
+
properties:
|
|
18760
|
+
trustedDeviceToken:
|
|
18761
|
+
type: string
|
|
18762
|
+
trustedDeviceExpiresAt:
|
|
18763
|
+
type: string
|
|
18764
|
+
MfaEnrollSendResponse:
|
|
18765
|
+
type: object
|
|
18766
|
+
properties:
|
|
18767
|
+
mfaSessionToken:
|
|
18768
|
+
type: string
|
|
18769
|
+
destination:
|
|
18770
|
+
type: string
|
|
18771
|
+
expiresAt:
|
|
18772
|
+
type: string
|
|
18773
|
+
required:
|
|
18774
|
+
- mfaSessionToken
|
|
18775
|
+
- destination
|
|
18776
|
+
- expiresAt
|
|
18777
|
+
MfaEnrolledResponse:
|
|
18778
|
+
type: object
|
|
18779
|
+
properties:
|
|
18780
|
+
enrolled:
|
|
18781
|
+
type: object
|
|
18782
|
+
additionalProperties: true
|
|
18783
|
+
factor:
|
|
18784
|
+
type: string
|
|
18785
|
+
enum:
|
|
18786
|
+
- email
|
|
18787
|
+
- sms
|
|
18788
|
+
required:
|
|
18789
|
+
- enrolled
|
|
18790
|
+
- factor
|
|
18791
|
+
MfaFactorsResponse:
|
|
18792
|
+
type: object
|
|
18793
|
+
properties:
|
|
18794
|
+
enrolledFactors:
|
|
18795
|
+
type: object
|
|
18796
|
+
additionalProperties: true
|
|
18797
|
+
email:
|
|
18798
|
+
type: object
|
|
18799
|
+
additionalProperties: true
|
|
18800
|
+
sms:
|
|
18801
|
+
type: object
|
|
18802
|
+
additionalProperties: true
|
|
18803
|
+
recoveryCodesRemaining:
|
|
18804
|
+
type: number
|
|
18805
|
+
mfaEnabledForClient:
|
|
18806
|
+
type: boolean
|
|
18807
|
+
required:
|
|
18808
|
+
- enrolledFactors
|
|
18809
|
+
- recoveryCodesRemaining
|
|
18810
|
+
- mfaEnabledForClient
|
|
18811
|
+
TrustedDevice:
|
|
18812
|
+
type: object
|
|
18813
|
+
properties:
|
|
18814
|
+
id:
|
|
18815
|
+
type: string
|
|
18816
|
+
label:
|
|
18817
|
+
type: string
|
|
18818
|
+
createdAtMs:
|
|
18819
|
+
type: number
|
|
18820
|
+
lastUsedAtMs:
|
|
18821
|
+
type: number
|
|
18822
|
+
expiresAtMs:
|
|
18823
|
+
type: number
|
|
18824
|
+
required:
|
|
18825
|
+
- id
|
|
18826
|
+
- label
|
|
18827
|
+
- createdAtMs
|
|
18828
|
+
- lastUsedAtMs
|
|
18829
|
+
- expiresAtMs
|
|
18416
18830
|
MagicLinkSendResponse:
|
|
18417
18831
|
type: object
|
|
18418
18832
|
properties:
|
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
* analytics, click tracking, and tag scan analytics for collection dashboards.
|
|
6
6
|
*/
|
|
7
7
|
export type AnalyticsSource = 'events' | 'tag';
|
|
8
|
+
/**
|
|
9
|
+
* Includes `scan_redirect` - logged automatically by the server (not the
|
|
10
|
+
* client) at the moment a GS1 digital-link scan, claim short-link scan, or
|
|
11
|
+
* NFC tap decides on a redirect destination, before the client ever loads
|
|
12
|
+
* anything. Distinct from `scan_tag`, which the client still writes on
|
|
13
|
+
* landing exactly as before.
|
|
14
|
+
*/
|
|
8
15
|
export type AnalyticsEventType = string;
|
|
9
16
|
export type AnalyticsGranularity = 'hour' | 'day' | 'week' | 'month';
|
|
10
17
|
export type AnalyticsMetric = 'count' | 'uniqueSessions' | 'uniqueVisitors';
|
|
@@ -59,6 +66,12 @@ export interface CollectionAnalyticsEvent extends AnalyticsStandardEventFields {
|
|
|
59
66
|
path?: string;
|
|
60
67
|
isExternal?: boolean;
|
|
61
68
|
location?: AnalyticsLocation;
|
|
69
|
+
/**
|
|
70
|
+
* Free-form identifier for which client app logged the event, e.g.
|
|
71
|
+
* `'portal'`, `'hub'`. No enum/whitelist - send whatever string identifies
|
|
72
|
+
* your app. Web-events only; not recorded on tag events.
|
|
73
|
+
*/
|
|
74
|
+
source?: string;
|
|
62
75
|
metadata?: Record<string, any>;
|
|
63
76
|
}
|
|
64
77
|
export interface TagAnalyticsEvent extends AnalyticsStandardEventFields {
|
|
@@ -75,6 +88,13 @@ export interface TagAnalyticsEvent extends AnalyticsStandardEventFields {
|
|
|
75
88
|
path?: string;
|
|
76
89
|
location?: AnalyticsLocation;
|
|
77
90
|
isAdmin?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Only relevant if you're logging a redirect-style event yourself. In
|
|
93
|
+
* practice this is mostly written by the server automatically at the
|
|
94
|
+
* moment a GS1 digital-link scan, claim short-link scan, or NFC tap
|
|
95
|
+
* decides on a redirect destination - see the `scan_redirect` eventType.
|
|
96
|
+
*/
|
|
97
|
+
redirectMode?: string;
|
|
78
98
|
metadata?: Record<string, any>;
|
|
79
99
|
}
|
|
80
100
|
export interface AnalyticsTrackOptions {
|
|
@@ -171,6 +191,21 @@ export interface AnalyticsFilterRequest {
|
|
|
171
191
|
claimIds?: string[];
|
|
172
192
|
isAdmin?: boolean;
|
|
173
193
|
hasLocation?: boolean;
|
|
194
|
+
/**
|
|
195
|
+
* Filter web-events rows by the `source` column (list-match). Web-events
|
|
196
|
+
* only - has no effect on `source: 'tag'` queries.
|
|
197
|
+
*
|
|
198
|
+
* There is deliberately no singular `source` filter: the request's own
|
|
199
|
+
* top-level `source` field (`'events'` vs `'tag'`) already owns that name
|
|
200
|
+
* as the table selector and predates this column - same word, two
|
|
201
|
+
* different things. Use a single-element array (`sources: ['portal']`)
|
|
202
|
+
* for an exact-match filter.
|
|
203
|
+
*/
|
|
204
|
+
sources?: string[];
|
|
205
|
+
/** Filter tag-events rows by `redirectMode`. Tag-events only. */
|
|
206
|
+
redirectMode?: string;
|
|
207
|
+
/** Filter tag-events rows by `redirectMode` (list-match). Tag-events only. */
|
|
208
|
+
redirectModes?: string[];
|
|
174
209
|
}
|
|
175
210
|
export interface AnalyticsSummaryRequest extends AnalyticsFilterRequest {
|
|
176
211
|
source: AnalyticsSource;
|
|
@@ -215,8 +250,8 @@ export interface AnalyticsTimeseriesResponse {
|
|
|
215
250
|
metric: AnalyticsMetric;
|
|
216
251
|
rows: AnalyticsTimeseriesRow[];
|
|
217
252
|
}
|
|
218
|
-
export type EventAnalyticsDimension = 'eventType' | 'country' | 'linkId' | 'href' | 'path' | 'appId' | 'destinationAppId' | 'deviceType' | 'isExternal' | 'productId' | 'proofId' | 'batchId' | 'variantId' | 'sessionId' | 'metadata';
|
|
219
|
-
export type TagAnalyticsDimension = 'eventType' | 'country' | 'codeId' | 'claimId' | 'proofId' | 'productId' | 'batchId' | 'variantId' | 'deviceType' | 'sessionId' | 'isAdmin' | 'location' | 'metadata';
|
|
253
|
+
export type EventAnalyticsDimension = 'eventType' | 'country' | 'linkId' | 'href' | 'path' | 'appId' | 'destinationAppId' | 'deviceType' | 'isExternal' | 'productId' | 'proofId' | 'batchId' | 'variantId' | 'sessionId' | 'metadata' | 'source';
|
|
254
|
+
export type TagAnalyticsDimension = 'eventType' | 'country' | 'codeId' | 'claimId' | 'proofId' | 'productId' | 'batchId' | 'variantId' | 'deviceType' | 'sessionId' | 'isAdmin' | 'location' | 'metadata' | 'redirectMode';
|
|
220
255
|
export interface AnalyticsBreakdownRequest extends AnalyticsFilterRequest {
|
|
221
256
|
source: AnalyticsSource;
|
|
222
257
|
dimension: EventAnalyticsDimension | TagAnalyticsDimension;
|