sinfactura-types 1.10.424 → 1.10.425
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/cjs/index.js +1 -0
- package/dist/cjs/terminal.js +97 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/terminal.d.ts +266 -0
- package/dist/terminal.js +94 -0
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -88,6 +88,7 @@ __exportStar(require("./store.js"), exports);
|
|
|
88
88
|
__exportStar(require("./storefrontEvent.js"), exports);
|
|
89
89
|
__exportStar(require("./subscription.js"), exports);
|
|
90
90
|
__exportStar(require("./support.js"), exports);
|
|
91
|
+
__exportStar(require("./terminal.js"), exports);
|
|
91
92
|
__exportStar(require("./supplier.js"), exports);
|
|
92
93
|
__exportStar(require("./supplierClaim.js"), exports);
|
|
93
94
|
__exportStar(require("./survey.js"), exports);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// POS terminal sessions — a shared till enrolled once, activated once per shift
|
|
3
|
+
// by a full login, and handed between cashiers by PIN.
|
|
4
|
+
//
|
|
5
|
+
// Four credentials, four lifetimes, and they are NOT interchangeable:
|
|
6
|
+
//
|
|
7
|
+
// 1. The TERMINAL ENROLMENT SECRET — minted by `POST /terminal/pair`, carried
|
|
8
|
+
// ONLY in the HttpOnly `sf_terminal` cookie (`Path=/terminal`, about one
|
|
9
|
+
// year, revocable by an admin). It never appears in a JSON body, so no type
|
|
10
|
+
// here has a slot for it.
|
|
11
|
+
// 2. The TERMINAL ACTIVATION — a full login (password + the TOTP step-up when
|
|
12
|
+
// the employee has 2FA) performed ON an enrolled terminal. It ends when the
|
|
13
|
+
// activating employee's shift closes or after 12 hours, whichever comes
|
|
14
|
+
// first.
|
|
15
|
+
// 3. The OPERATOR TOKEN — a 15-minute access token minted by a PIN inside a
|
|
16
|
+
// live activation. The PIN only re-selects WHO operates the till; it is
|
|
17
|
+
// never a standalone authentication.
|
|
18
|
+
// 4. The ELEVATION TOKEN — 90 seconds, single use, bound to one exact action.
|
|
19
|
+
// Not described here yet; its shapes land with the slice that serves it.
|
|
20
|
+
//
|
|
21
|
+
// ⚠️ Rollout is sliced. ENROLMENT (pairing codes, redeem, list, revoke) is served
|
|
22
|
+
// today. ACTIVATION, the OPERATOR PIN and PIN ENROLMENT are published AHEAD of
|
|
23
|
+
// the routes that serve them, so the app can be built against a fixed shape; a
|
|
24
|
+
// client must treat those routes as absent until the api's deployment is
|
|
25
|
+
// verified, and every such shape says so in its own doc comment.
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.TERMINAL_PAIRING_CODE_TTL_SECONDS = exports.TERMINAL_ENROLMENT_TTL_SECONDS = exports.TERMINAL_SESSION_ERROR_CODES = exports.TERMINAL_ENROLMENT_ERROR_CODES = void 0;
|
|
28
|
+
/**
|
|
29
|
+
* `body.error` codes the SERVED enrolment routes refuse with —
|
|
30
|
+
* `POST /terminal/pair/codes`, `POST /terminal/pair`, `GET /terminal/sessions`
|
|
31
|
+
* and `DELETE /terminal/sessions/{terminalId}`.
|
|
32
|
+
*
|
|
33
|
+
* - `VALIDATION_FAILED` · 400 — the body or path failed its schema.
|
|
34
|
+
* - `PAIRING_CODE_INVALID` · 400 — `POST /terminal/pair`: the code is unknown or
|
|
35
|
+
* has expired. One code for both on purpose; ask the admin for a new one.
|
|
36
|
+
* - `PAIRING_CODE_CONSUMED` · 409 — `POST /terminal/pair`: the code was already
|
|
37
|
+
* redeemed. No second terminal is created. Ask for a new code.
|
|
38
|
+
* - `TERMINAL_NOT_FOUND` · 404 — `DELETE /terminal/sessions/{terminalId}`: no
|
|
39
|
+
* such terminal in the caller's store (another store's terminal answers the
|
|
40
|
+
* same, so the route is not an existence oracle).
|
|
41
|
+
* - `IMPERSONATION_TERMINAL_FORBIDDEN` · 403 — `POST /terminal/pair/codes` under
|
|
42
|
+
* an impersonated support session: an enrolment outlives the session, so a
|
|
43
|
+
* support operator may not plant one.
|
|
44
|
+
*/
|
|
45
|
+
exports.TERMINAL_ENROLMENT_ERROR_CODES = [
|
|
46
|
+
'VALIDATION_FAILED',
|
|
47
|
+
'PAIRING_CODE_INVALID',
|
|
48
|
+
'PAIRING_CODE_CONSUMED',
|
|
49
|
+
'TERMINAL_NOT_FOUND',
|
|
50
|
+
'IMPERSONATION_TERMINAL_FORBIDDEN',
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* `body.error` codes the ACTIVATION, OPERATOR-PIN and PIN-ENROLMENT routes will
|
|
54
|
+
* refuse with — PUBLISHED AHEAD of those routes, which are not served yet.
|
|
55
|
+
*
|
|
56
|
+
* Activation also answers the ordinary login refusals (`LOGIN_ERROR_CODES`), its
|
|
57
|
+
* step-up (`STEP_UP_ERROR_CODES`) and second-factor failures
|
|
58
|
+
* (`LOGIN_2FA_ERROR_CODES`); they are not repeated here.
|
|
59
|
+
*
|
|
60
|
+
* - `TERMINAL_NOT_PAIRED` · 401 — the request carried no `sf_terminal` cookie,
|
|
61
|
+
* or one naming an unknown, expired or revoked terminal. Re-pair the till.
|
|
62
|
+
* - `SHIFT_NOT_OPEN` · 409 — activation by an employee who holds no open shift.
|
|
63
|
+
* - `TERMINAL_NOT_ACTIVATED` · 401 — a PIN on a terminal with no live
|
|
64
|
+
* activation (never activated, its shift closed, or past its 12-hour cap).
|
|
65
|
+
* Run the full-login activation again.
|
|
66
|
+
* - `INVALID_PIN` · 401 — UNIFORM: wrong PIN, unknown employee and employee
|
|
67
|
+
* with no PIN set answer the byte-identical body. Nothing distinguishes them.
|
|
68
|
+
* - `ACCOUNT_LOCKED` · 403 — the employee's PASSWORD lockout is live; the body
|
|
69
|
+
* carries `retryAfterSeconds`. A PIN never bypasses a password lockout.
|
|
70
|
+
* - `PIN_LOCKED` · 429 — too many wrong PINs, for that employee across every
|
|
71
|
+
* terminal or on this terminal across every employee. Back off.
|
|
72
|
+
* - `ROLE_NOT_ALLOWED` · 403 — the employee's roles may not operate a till (a
|
|
73
|
+
* PRINTER claim, alone or combined, or no operator role at all).
|
|
74
|
+
* - `INVALID_PIN_FORMAT` · 400 — `POST /terminal/pin`: not 4–6 digits.
|
|
75
|
+
* - `WRONG_CREDENTIALS` · 400 — `POST /terminal/pin`: the re-verified password
|
|
76
|
+
* did not match.
|
|
77
|
+
* - `IDEMPOTENCY_KEY_REUSE` · 422 / `IDEMPOTENCY_IN_PROGRESS` · 409 /
|
|
78
|
+
* `INVALID_IDEMPOTENCY_KEY` · 400 — the `Idempotency-Key` header's own
|
|
79
|
+
* refusals on `POST /terminal/operators`.
|
|
80
|
+
*/
|
|
81
|
+
exports.TERMINAL_SESSION_ERROR_CODES = [
|
|
82
|
+
'TERMINAL_NOT_PAIRED',
|
|
83
|
+
'SHIFT_NOT_OPEN',
|
|
84
|
+
'TERMINAL_NOT_ACTIVATED',
|
|
85
|
+
'INVALID_PIN',
|
|
86
|
+
'ACCOUNT_LOCKED',
|
|
87
|
+
'PIN_LOCKED',
|
|
88
|
+
'ROLE_NOT_ALLOWED',
|
|
89
|
+
'INVALID_PIN_FORMAT',
|
|
90
|
+
'WRONG_CREDENTIALS',
|
|
91
|
+
'IDEMPOTENCY_KEY_REUSE',
|
|
92
|
+
'IDEMPOTENCY_IN_PROGRESS',
|
|
93
|
+
'INVALID_IDEMPOTENCY_KEY',
|
|
94
|
+
];
|
|
95
|
+
/** The `sf_terminal` cookie's lifetime and the pairing code's, in seconds — the two numbers a client may display. */
|
|
96
|
+
exports.TERMINAL_ENROLMENT_TTL_SECONDS = 365 * 24 * 60 * 60;
|
|
97
|
+
exports.TERMINAL_PAIRING_CODE_TTL_SECONDS = 10 * 60;
|
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,7 @@ export * from './store.ts';
|
|
|
64
64
|
export * from './storefrontEvent.ts';
|
|
65
65
|
export * from './subscription.ts';
|
|
66
66
|
export * from './support.ts';
|
|
67
|
+
export * from './terminal.ts';
|
|
67
68
|
export * from './supplier.ts';
|
|
68
69
|
export * from './supplierClaim.ts';
|
|
69
70
|
export * from './survey.ts';
|
package/dist/index.js
CHANGED
|
@@ -72,6 +72,7 @@ export * from "./store.js";
|
|
|
72
72
|
export * from "./storefrontEvent.js";
|
|
73
73
|
export * from "./subscription.js";
|
|
74
74
|
export * from "./support.js";
|
|
75
|
+
export * from "./terminal.js";
|
|
75
76
|
export * from "./supplier.js";
|
|
76
77
|
export * from "./supplierClaim.js";
|
|
77
78
|
export * from "./survey.js";
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
/**
|
|
3
|
+
* One enrolled terminal, as the admin roster reads it.
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ An ALLOW-list projection of the stored row: the secret's digest, the
|
|
6
|
+
* storage keys and the housekeeping `ttl` never reach the wire, and a field
|
|
7
|
+
* added to the stored row later does not appear here by default.
|
|
8
|
+
*/
|
|
9
|
+
interface TerminalSummary {
|
|
10
|
+
/** Server-minted, opaque (`TRM` + 16 hex). The same value a till's cart/order `terminalId` carries once enrolment is wired into sales. */
|
|
11
|
+
terminalId: string;
|
|
12
|
+
/** The admin's name for the till, given when the pairing code was minted ("Caja 1"). */
|
|
13
|
+
label: string;
|
|
14
|
+
/** When the pairing code was redeemed, unix ms. */
|
|
15
|
+
pairedAt: number;
|
|
16
|
+
/** The admin (`USR…`) who minted the pairing code this terminal redeemed. */
|
|
17
|
+
pairedBy: string;
|
|
18
|
+
/**
|
|
19
|
+
* When the enrolment stops being honoured without any admin action, unix
|
|
20
|
+
* ms — about one year after pairing. Enforced on READ, never by the
|
|
21
|
+
* cookie's own Max-Age.
|
|
22
|
+
*/
|
|
23
|
+
expiresAt: number;
|
|
24
|
+
/** Set once an admin revoked the terminal. A revoked terminal is refused everywhere; re-pair it to use it again. */
|
|
25
|
+
revokedAt?: number;
|
|
26
|
+
/** The admin (`USR…`) who revoked it. */
|
|
27
|
+
revokedBy?: string;
|
|
28
|
+
}
|
|
29
|
+
/** `POST /terminal/pair/codes` (adminToken) — mint a single-use pairing code for a till. */
|
|
30
|
+
interface TerminalPairingCodeRequest {
|
|
31
|
+
/** The till's display name, 1–40 characters after trimming. */
|
|
32
|
+
label: string;
|
|
33
|
+
}
|
|
34
|
+
/** What `POST /terminal/pair/codes` returns in `data`. */
|
|
35
|
+
interface TerminalPairingCode {
|
|
36
|
+
/**
|
|
37
|
+
* Eight characters from an unambiguous alphabet, rendered `XXXX-XXXX`.
|
|
38
|
+
* Redeem is case-insensitive and ignores spaces and dashes.
|
|
39
|
+
*
|
|
40
|
+
* ⚠️ A live credential until it is redeemed or expires: show it on the
|
|
41
|
+
* admin's screen, never persist or log it.
|
|
42
|
+
*/
|
|
43
|
+
pairingCode: string;
|
|
44
|
+
label: string;
|
|
45
|
+
/** Unix ms — ten minutes after minting. After this the code is `PAIRING_CODE_INVALID`. */
|
|
46
|
+
expiresAt: number;
|
|
47
|
+
}
|
|
48
|
+
interface TerminalPairingCodeResponse {
|
|
49
|
+
message: string;
|
|
50
|
+
data: TerminalPairingCode;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `POST /terminal/pair` (PUBLIC) — the till redeems the code the admin read
|
|
54
|
+
* to it. Exactly once: the code is consumed and the terminal row created in
|
|
55
|
+
* one transaction.
|
|
56
|
+
*/
|
|
57
|
+
interface TerminalPairRequest {
|
|
58
|
+
pairingCode: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `POST /terminal/pair` → `data`. The enrolment SECRET is not here and never
|
|
62
|
+
* will be: it arrives as the HttpOnly `sf_terminal` cookie on this same
|
|
63
|
+
* response, so the client must send the request with credentials included.
|
|
64
|
+
*/
|
|
65
|
+
interface TerminalPair {
|
|
66
|
+
terminalId: string;
|
|
67
|
+
label: string;
|
|
68
|
+
}
|
|
69
|
+
interface TerminalPairResponse {
|
|
70
|
+
message: string;
|
|
71
|
+
data: TerminalPair;
|
|
72
|
+
}
|
|
73
|
+
/** `GET /terminal/sessions` (adminToken) → this store's enrolled terminals, revoked ones included until they age out. */
|
|
74
|
+
interface TerminalListResponse {
|
|
75
|
+
message: string;
|
|
76
|
+
data: TerminalSummary[];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* `DELETE /terminal/sessions/{terminalId}` (adminToken) → the revoked
|
|
80
|
+
* terminal. Idempotent: revoking an already-revoked terminal answers 200 with
|
|
81
|
+
* the STORED `revokedAt`.
|
|
82
|
+
*/
|
|
83
|
+
interface TerminalRevokeResponse {
|
|
84
|
+
message: string;
|
|
85
|
+
data: {
|
|
86
|
+
terminalId: string;
|
|
87
|
+
revokedAt: number;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* `POST /terminal/activation` — NOT SERVED YET. Sent from an enrolled till
|
|
92
|
+
* (the `sf_terminal` cookie rides along); the body is an ordinary login.
|
|
93
|
+
*
|
|
94
|
+
* The step-up is the login's own: a 2FA-enrolled employee first receives
|
|
95
|
+
* `401 REQUIRES_2FA` and re-submits the same body with `totpCode`. A
|
|
96
|
+
* `totp.enabled` employee is NOT refused — this full login is where the
|
|
97
|
+
* second factor is performed, once per activation.
|
|
98
|
+
*/
|
|
99
|
+
interface TerminalActivationRequest {
|
|
100
|
+
email: string;
|
|
101
|
+
password: string;
|
|
102
|
+
/** TOTP step-up code — only after a `REQUIRES_2FA` answer. */
|
|
103
|
+
totpCode?: string;
|
|
104
|
+
/** reCAPTCHA v3 token — only after a `CAPTCHA_REQUIRED` answer. */
|
|
105
|
+
captchaToken?: string;
|
|
106
|
+
}
|
|
107
|
+
/** `POST /terminal/activation` → `data` — NOT SERVED YET. */
|
|
108
|
+
interface TerminalActivation {
|
|
109
|
+
/** Every operator token minted inside this activation carries it as `activationId`. */
|
|
110
|
+
activationId: string;
|
|
111
|
+
terminalId: string;
|
|
112
|
+
/** The employee (`USR…`) whose full login activated the till. */
|
|
113
|
+
activatedBy: string;
|
|
114
|
+
/** Their display name, for the till's header. */
|
|
115
|
+
activatedByName: string;
|
|
116
|
+
/**
|
|
117
|
+
* The activating employee's OPEN shift. The activation ends the moment
|
|
118
|
+
* this shift closes; activating with no open shift is `409 SHIFT_NOT_OPEN`.
|
|
119
|
+
*/
|
|
120
|
+
shiftId: string;
|
|
121
|
+
activatedAt: number;
|
|
122
|
+
/** The 12-hour hard cap, unix ms. The shift closing ends it sooner. */
|
|
123
|
+
expiresAt: number;
|
|
124
|
+
}
|
|
125
|
+
interface TerminalActivationResponse {
|
|
126
|
+
message: string;
|
|
127
|
+
data: TerminalActivation;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* `POST /terminal/operators` — NOT SERVED YET. A cashier takes the till
|
|
131
|
+
* inside a live activation.
|
|
132
|
+
*
|
|
133
|
+
* The attempt id rides the `Idempotency-Key` HEADER, not this body: a
|
|
134
|
+
* retried submission with the same key answers the cached verdict and is not
|
|
135
|
+
* scored as a second wrong PIN. A different body under the same key is
|
|
136
|
+
* `IDEMPOTENCY_KEY_REUSE`.
|
|
137
|
+
*/
|
|
138
|
+
interface TerminalOperatorLoginRequest {
|
|
139
|
+
/** The employee (`USR…`) taking the till. Always sent — the PIN is never matched against a roster. */
|
|
140
|
+
employeeId: string;
|
|
141
|
+
/** 4–6 digits. */
|
|
142
|
+
pin: string;
|
|
143
|
+
}
|
|
144
|
+
/** `POST /terminal/operators` → `data` — NOT SERVED YET. */
|
|
145
|
+
interface TerminalOperatorSession {
|
|
146
|
+
/**
|
|
147
|
+
* A 15-minute access token for every route a `userToken` reaches, held
|
|
148
|
+
* in MEMORY only. No refresh token is minted: re-entering the PIN is the
|
|
149
|
+
* only renewal, and the token never outlives its activation.
|
|
150
|
+
*/
|
|
151
|
+
accessToken: string;
|
|
152
|
+
/** Unix ms — the token's `exp`. */
|
|
153
|
+
expiresAt: number;
|
|
154
|
+
/** The operator-session id — the token's `sid`. */
|
|
155
|
+
sid: string;
|
|
156
|
+
terminalId: string;
|
|
157
|
+
activationId: string;
|
|
158
|
+
operator: {
|
|
159
|
+
userId: string;
|
|
160
|
+
name: string;
|
|
161
|
+
roles: string;
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
interface TerminalOperatorLoginResponse {
|
|
165
|
+
message: string;
|
|
166
|
+
data: TerminalOperatorSession;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The operator token's claims, for a client that decodes it for UI state
|
|
170
|
+
* (`exp` for the idle countdown). NOT SERVED YET.
|
|
171
|
+
*
|
|
172
|
+
* ⚠️ ONE live operator per terminal. A second employee's PIN replaces the
|
|
173
|
+
* terminal's operator session, and the first employee's still-unexpired
|
|
174
|
+
* token is refused `401` on its very next request (`sid` mismatch). Render
|
|
175
|
+
* that as "another operator took this till", not as a session error.
|
|
176
|
+
*/
|
|
177
|
+
interface OperatorSessionClaims {
|
|
178
|
+
storeId: string;
|
|
179
|
+
userId: string;
|
|
180
|
+
/** Space-joined, exactly as every access token carries them. */
|
|
181
|
+
roles: string;
|
|
182
|
+
name: string;
|
|
183
|
+
terminalId: string;
|
|
184
|
+
sid: string;
|
|
185
|
+
activationId: string;
|
|
186
|
+
/** Seconds since epoch, per JWT. */
|
|
187
|
+
exp: number;
|
|
188
|
+
iat?: number;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* `GET /terminal/operator-sessions` → `data` — NOT SERVED YET. Who holds the
|
|
192
|
+
* till right now, or `null` when nobody does.
|
|
193
|
+
*/
|
|
194
|
+
type TerminalOperatorSummary = {
|
|
195
|
+
userId: string;
|
|
196
|
+
name: string;
|
|
197
|
+
startedAt: number;
|
|
198
|
+
} | null;
|
|
199
|
+
/**
|
|
200
|
+
* `POST /terminal/pin` (userToken) — NOT SERVED YET. An employee sets or
|
|
201
|
+
* replaces their own PIN. The account password is re-verified on the same
|
|
202
|
+
* request, because a PIN is a credential and a stolen live session must not
|
|
203
|
+
* be enough to plant one.
|
|
204
|
+
*
|
|
205
|
+
* ⚠️ No PIN, digest or attempt counter is ever returned by any route.
|
|
206
|
+
*/
|
|
207
|
+
interface TerminalPinSetRequest {
|
|
208
|
+
/** 4–6 digits. */
|
|
209
|
+
pin: string;
|
|
210
|
+
password: string;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* `body.error` codes the SERVED enrolment routes refuse with —
|
|
215
|
+
* `POST /terminal/pair/codes`, `POST /terminal/pair`, `GET /terminal/sessions`
|
|
216
|
+
* and `DELETE /terminal/sessions/{terminalId}`.
|
|
217
|
+
*
|
|
218
|
+
* - `VALIDATION_FAILED` · 400 — the body or path failed its schema.
|
|
219
|
+
* - `PAIRING_CODE_INVALID` · 400 — `POST /terminal/pair`: the code is unknown or
|
|
220
|
+
* has expired. One code for both on purpose; ask the admin for a new one.
|
|
221
|
+
* - `PAIRING_CODE_CONSUMED` · 409 — `POST /terminal/pair`: the code was already
|
|
222
|
+
* redeemed. No second terminal is created. Ask for a new code.
|
|
223
|
+
* - `TERMINAL_NOT_FOUND` · 404 — `DELETE /terminal/sessions/{terminalId}`: no
|
|
224
|
+
* such terminal in the caller's store (another store's terminal answers the
|
|
225
|
+
* same, so the route is not an existence oracle).
|
|
226
|
+
* - `IMPERSONATION_TERMINAL_FORBIDDEN` · 403 — `POST /terminal/pair/codes` under
|
|
227
|
+
* an impersonated support session: an enrolment outlives the session, so a
|
|
228
|
+
* support operator may not plant one.
|
|
229
|
+
*/
|
|
230
|
+
export declare const TERMINAL_ENROLMENT_ERROR_CODES: readonly ["VALIDATION_FAILED", "PAIRING_CODE_INVALID", "PAIRING_CODE_CONSUMED", "TERMINAL_NOT_FOUND", "IMPERSONATION_TERMINAL_FORBIDDEN"];
|
|
231
|
+
export type TerminalEnrolmentErrorCode = (typeof TERMINAL_ENROLMENT_ERROR_CODES)[number];
|
|
232
|
+
/**
|
|
233
|
+
* `body.error` codes the ACTIVATION, OPERATOR-PIN and PIN-ENROLMENT routes will
|
|
234
|
+
* refuse with — PUBLISHED AHEAD of those routes, which are not served yet.
|
|
235
|
+
*
|
|
236
|
+
* Activation also answers the ordinary login refusals (`LOGIN_ERROR_CODES`), its
|
|
237
|
+
* step-up (`STEP_UP_ERROR_CODES`) and second-factor failures
|
|
238
|
+
* (`LOGIN_2FA_ERROR_CODES`); they are not repeated here.
|
|
239
|
+
*
|
|
240
|
+
* - `TERMINAL_NOT_PAIRED` · 401 — the request carried no `sf_terminal` cookie,
|
|
241
|
+
* or one naming an unknown, expired or revoked terminal. Re-pair the till.
|
|
242
|
+
* - `SHIFT_NOT_OPEN` · 409 — activation by an employee who holds no open shift.
|
|
243
|
+
* - `TERMINAL_NOT_ACTIVATED` · 401 — a PIN on a terminal with no live
|
|
244
|
+
* activation (never activated, its shift closed, or past its 12-hour cap).
|
|
245
|
+
* Run the full-login activation again.
|
|
246
|
+
* - `INVALID_PIN` · 401 — UNIFORM: wrong PIN, unknown employee and employee
|
|
247
|
+
* with no PIN set answer the byte-identical body. Nothing distinguishes them.
|
|
248
|
+
* - `ACCOUNT_LOCKED` · 403 — the employee's PASSWORD lockout is live; the body
|
|
249
|
+
* carries `retryAfterSeconds`. A PIN never bypasses a password lockout.
|
|
250
|
+
* - `PIN_LOCKED` · 429 — too many wrong PINs, for that employee across every
|
|
251
|
+
* terminal or on this terminal across every employee. Back off.
|
|
252
|
+
* - `ROLE_NOT_ALLOWED` · 403 — the employee's roles may not operate a till (a
|
|
253
|
+
* PRINTER claim, alone or combined, or no operator role at all).
|
|
254
|
+
* - `INVALID_PIN_FORMAT` · 400 — `POST /terminal/pin`: not 4–6 digits.
|
|
255
|
+
* - `WRONG_CREDENTIALS` · 400 — `POST /terminal/pin`: the re-verified password
|
|
256
|
+
* did not match.
|
|
257
|
+
* - `IDEMPOTENCY_KEY_REUSE` · 422 / `IDEMPOTENCY_IN_PROGRESS` · 409 /
|
|
258
|
+
* `INVALID_IDEMPOTENCY_KEY` · 400 — the `Idempotency-Key` header's own
|
|
259
|
+
* refusals on `POST /terminal/operators`.
|
|
260
|
+
*/
|
|
261
|
+
export declare const TERMINAL_SESSION_ERROR_CODES: readonly ["TERMINAL_NOT_PAIRED", "SHIFT_NOT_OPEN", "TERMINAL_NOT_ACTIVATED", "INVALID_PIN", "ACCOUNT_LOCKED", "PIN_LOCKED", "ROLE_NOT_ALLOWED", "INVALID_PIN_FORMAT", "WRONG_CREDENTIALS", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "INVALID_IDEMPOTENCY_KEY"];
|
|
262
|
+
export type TerminalSessionErrorCode = (typeof TERMINAL_SESSION_ERROR_CODES)[number];
|
|
263
|
+
/** The `sf_terminal` cookie's lifetime and the pairing code's, in seconds — the two numbers a client may display. */
|
|
264
|
+
export declare const TERMINAL_ENROLMENT_TTL_SECONDS: number;
|
|
265
|
+
export declare const TERMINAL_PAIRING_CODE_TTL_SECONDS: number;
|
|
266
|
+
export {};
|
package/dist/terminal.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// POS terminal sessions — a shared till enrolled once, activated once per shift
|
|
2
|
+
// by a full login, and handed between cashiers by PIN.
|
|
3
|
+
//
|
|
4
|
+
// Four credentials, four lifetimes, and they are NOT interchangeable:
|
|
5
|
+
//
|
|
6
|
+
// 1. The TERMINAL ENROLMENT SECRET — minted by `POST /terminal/pair`, carried
|
|
7
|
+
// ONLY in the HttpOnly `sf_terminal` cookie (`Path=/terminal`, about one
|
|
8
|
+
// year, revocable by an admin). It never appears in a JSON body, so no type
|
|
9
|
+
// here has a slot for it.
|
|
10
|
+
// 2. The TERMINAL ACTIVATION — a full login (password + the TOTP step-up when
|
|
11
|
+
// the employee has 2FA) performed ON an enrolled terminal. It ends when the
|
|
12
|
+
// activating employee's shift closes or after 12 hours, whichever comes
|
|
13
|
+
// first.
|
|
14
|
+
// 3. The OPERATOR TOKEN — a 15-minute access token minted by a PIN inside a
|
|
15
|
+
// live activation. The PIN only re-selects WHO operates the till; it is
|
|
16
|
+
// never a standalone authentication.
|
|
17
|
+
// 4. The ELEVATION TOKEN — 90 seconds, single use, bound to one exact action.
|
|
18
|
+
// Not described here yet; its shapes land with the slice that serves it.
|
|
19
|
+
//
|
|
20
|
+
// ⚠️ Rollout is sliced. ENROLMENT (pairing codes, redeem, list, revoke) is served
|
|
21
|
+
// today. ACTIVATION, the OPERATOR PIN and PIN ENROLMENT are published AHEAD of
|
|
22
|
+
// the routes that serve them, so the app can be built against a fixed shape; a
|
|
23
|
+
// client must treat those routes as absent until the api's deployment is
|
|
24
|
+
// verified, and every such shape says so in its own doc comment.
|
|
25
|
+
/**
|
|
26
|
+
* `body.error` codes the SERVED enrolment routes refuse with —
|
|
27
|
+
* `POST /terminal/pair/codes`, `POST /terminal/pair`, `GET /terminal/sessions`
|
|
28
|
+
* and `DELETE /terminal/sessions/{terminalId}`.
|
|
29
|
+
*
|
|
30
|
+
* - `VALIDATION_FAILED` · 400 — the body or path failed its schema.
|
|
31
|
+
* - `PAIRING_CODE_INVALID` · 400 — `POST /terminal/pair`: the code is unknown or
|
|
32
|
+
* has expired. One code for both on purpose; ask the admin for a new one.
|
|
33
|
+
* - `PAIRING_CODE_CONSUMED` · 409 — `POST /terminal/pair`: the code was already
|
|
34
|
+
* redeemed. No second terminal is created. Ask for a new code.
|
|
35
|
+
* - `TERMINAL_NOT_FOUND` · 404 — `DELETE /terminal/sessions/{terminalId}`: no
|
|
36
|
+
* such terminal in the caller's store (another store's terminal answers the
|
|
37
|
+
* same, so the route is not an existence oracle).
|
|
38
|
+
* - `IMPERSONATION_TERMINAL_FORBIDDEN` · 403 — `POST /terminal/pair/codes` under
|
|
39
|
+
* an impersonated support session: an enrolment outlives the session, so a
|
|
40
|
+
* support operator may not plant one.
|
|
41
|
+
*/
|
|
42
|
+
export const TERMINAL_ENROLMENT_ERROR_CODES = [
|
|
43
|
+
'VALIDATION_FAILED',
|
|
44
|
+
'PAIRING_CODE_INVALID',
|
|
45
|
+
'PAIRING_CODE_CONSUMED',
|
|
46
|
+
'TERMINAL_NOT_FOUND',
|
|
47
|
+
'IMPERSONATION_TERMINAL_FORBIDDEN',
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* `body.error` codes the ACTIVATION, OPERATOR-PIN and PIN-ENROLMENT routes will
|
|
51
|
+
* refuse with — PUBLISHED AHEAD of those routes, which are not served yet.
|
|
52
|
+
*
|
|
53
|
+
* Activation also answers the ordinary login refusals (`LOGIN_ERROR_CODES`), its
|
|
54
|
+
* step-up (`STEP_UP_ERROR_CODES`) and second-factor failures
|
|
55
|
+
* (`LOGIN_2FA_ERROR_CODES`); they are not repeated here.
|
|
56
|
+
*
|
|
57
|
+
* - `TERMINAL_NOT_PAIRED` · 401 — the request carried no `sf_terminal` cookie,
|
|
58
|
+
* or one naming an unknown, expired or revoked terminal. Re-pair the till.
|
|
59
|
+
* - `SHIFT_NOT_OPEN` · 409 — activation by an employee who holds no open shift.
|
|
60
|
+
* - `TERMINAL_NOT_ACTIVATED` · 401 — a PIN on a terminal with no live
|
|
61
|
+
* activation (never activated, its shift closed, or past its 12-hour cap).
|
|
62
|
+
* Run the full-login activation again.
|
|
63
|
+
* - `INVALID_PIN` · 401 — UNIFORM: wrong PIN, unknown employee and employee
|
|
64
|
+
* with no PIN set answer the byte-identical body. Nothing distinguishes them.
|
|
65
|
+
* - `ACCOUNT_LOCKED` · 403 — the employee's PASSWORD lockout is live; the body
|
|
66
|
+
* carries `retryAfterSeconds`. A PIN never bypasses a password lockout.
|
|
67
|
+
* - `PIN_LOCKED` · 429 — too many wrong PINs, for that employee across every
|
|
68
|
+
* terminal or on this terminal across every employee. Back off.
|
|
69
|
+
* - `ROLE_NOT_ALLOWED` · 403 — the employee's roles may not operate a till (a
|
|
70
|
+
* PRINTER claim, alone or combined, or no operator role at all).
|
|
71
|
+
* - `INVALID_PIN_FORMAT` · 400 — `POST /terminal/pin`: not 4–6 digits.
|
|
72
|
+
* - `WRONG_CREDENTIALS` · 400 — `POST /terminal/pin`: the re-verified password
|
|
73
|
+
* did not match.
|
|
74
|
+
* - `IDEMPOTENCY_KEY_REUSE` · 422 / `IDEMPOTENCY_IN_PROGRESS` · 409 /
|
|
75
|
+
* `INVALID_IDEMPOTENCY_KEY` · 400 — the `Idempotency-Key` header's own
|
|
76
|
+
* refusals on `POST /terminal/operators`.
|
|
77
|
+
*/
|
|
78
|
+
export const TERMINAL_SESSION_ERROR_CODES = [
|
|
79
|
+
'TERMINAL_NOT_PAIRED',
|
|
80
|
+
'SHIFT_NOT_OPEN',
|
|
81
|
+
'TERMINAL_NOT_ACTIVATED',
|
|
82
|
+
'INVALID_PIN',
|
|
83
|
+
'ACCOUNT_LOCKED',
|
|
84
|
+
'PIN_LOCKED',
|
|
85
|
+
'ROLE_NOT_ALLOWED',
|
|
86
|
+
'INVALID_PIN_FORMAT',
|
|
87
|
+
'WRONG_CREDENTIALS',
|
|
88
|
+
'IDEMPOTENCY_KEY_REUSE',
|
|
89
|
+
'IDEMPOTENCY_IN_PROGRESS',
|
|
90
|
+
'INVALID_IDEMPOTENCY_KEY',
|
|
91
|
+
];
|
|
92
|
+
/** The `sf_terminal` cookie's lifetime and the pairing code's, in seconds — the two numbers a client may display. */
|
|
93
|
+
export const TERMINAL_ENROLMENT_TTL_SECONDS = 365 * 24 * 60 * 60;
|
|
94
|
+
export const TERMINAL_PAIRING_CODE_TTL_SECONDS = 10 * 60;
|