@gerege-systems/eid-mongolia-sdk 0.6.1 → 0.8.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/README.md CHANGED
@@ -19,7 +19,94 @@ Node.js ≥ 22 (global `fetch`, `node:crypto`).
19
19
 
20
20
  `POST https://ca.eidmongolia.mn/v3/rp-applications` (эсвэл [developer.eidmongolia.mn](https://developer.eidmongolia.mn)) —
21
21
  оператор баталсны дараа **relyingPartyUUID** ба **API secret** (`rp_sk_…`) олгогдоно; secret **зөвхөн нэг удаа**
22
- харагдана. Дэлгэрэнгүй: <https://developer.eidmongolia.mn/#burtgel>.
22
+ харагдана. Дэлгэрэнгүй: <https://developer.eidmongolia.mn/#registration>.
23
+
24
+ ## 1a. «eID-ээр нэвтрэх» (OpenID Connect)
25
+
26
+ Хамгийн хялбар нэвтрэлт: таны вэбэд нэг товч, нэвтрэх хуудсыг (QR · утсан дээрх аппаар нээх · регистрээр
27
+ мэдэгдэл) eID сервер өөрөө харуулж, гарын үсэг ба гэрчилгээний гинжийг шалгаад танд стандарт OpenID Connect
28
+ (Authorization Code + PKCE `S256`) `id_token` өгнө — Google/Apple нэвтрэлттэй ижил. Утасны хөтчөөс дарахад
29
+ хуудасгүйгээр шууд eID апп нээгдэнэ. Гэрээ: <https://developer.eidmongolia.mn/#oidc>.
30
+
31
+ **Бүртгэл.** `client_id` = таны RP UUID (`relyingPartyUUID`), `client_secret` = RP API secret (`rp_sk_…`).
32
+ RP-д `AUTH` эрх, OIDC асаалттай, `redirect_uri` (https, ≤ 10) бүртгэлтэй байна — authorize/token-ий `redirect_uri`
33
+ бүртгэлтэйтэй **тэмдэгт бүрээрээ** таарах ёстой. Иргэний ETSI дугаар (`pnomn` claim) хэрэгтэй бол `PNOMN` эрх
34
+ хүсэж, `scope: "openid pnomn"`. Token endpoint-д RP-ийн IP allowlist мөрдөгдөнө; `requireMtls` RP OIDC ашиглахгүй.
35
+
36
+ ```ts
37
+ import { EidOidcClient, EidOidcError } from "@gerege-systems/eid-mongolia-sdk";
38
+
39
+ const oidc = new EidOidcClient({
40
+ clientId: process.env.EID_RP_UUID!,
41
+ clientSecret: process.env.EID_SECRET!, // rp_sk_… — зөвхөн backend
42
+ redirectUri: "https://bank.example.mn/auth/eid/callback",
43
+ // issuer анхдагч https://login.eidmongolia.mn, scope анхдагч "openid"
44
+ });
45
+
46
+ const TX = "eid_oidc_tx";
47
+ const cookieOpts = { httpOnly: true, secure: true, sameSite: "lax", path: "/auth/eid", maxAge: 600_000 } as const;
48
+
49
+ // GET /auth/eid/login — товчны href
50
+ app.get("/auth/eid/login", async (_req, res) => {
51
+ const a = await oidc.createAuthorization(); // { url, state, nonce, codeVerifier }
52
+ res.cookie(TX, JSON.stringify({ state: a.state, nonce: a.nonce, codeVerifier: a.codeVerifier }), cookieOpts);
53
+ res.set("Cache-Control", "no-store").redirect(302, a.url);
54
+ });
55
+
56
+ // GET /auth/eid/callback?code&state (эсвэл ?error) — бүртгэлтэй redirect_uri
57
+ app.get("/auth/eid/callback", async (req, res) => {
58
+ const tx = JSON.parse(req.cookies[TX] ?? "null");
59
+ res.clearCookie(TX, { path: "/auth/eid" });
60
+ if (!tx) return res.redirect(303, "/login?error=state");
61
+ try {
62
+ const { claims } = await oidc.handleCallback(req.originalUrl, tx); // state → token → id_token (ES256)
63
+ const user = await users.findOrCreateBySub(claims.sub); // pairwise sub-аар таньна (нэрээр биш)
64
+ await startSession(res, user); // таны session-ийг шинээр үүсгэ (session fixation)
65
+ res.redirect(303, "/");
66
+ } catch (e) {
67
+ const code = e instanceof EidOidcError ? e.code : "server_error"; // access_denied → «дахин оролдоно уу»
68
+ res.redirect(303, `/login?error=${code}`);
69
+ }
70
+ });
71
+ ```
72
+
73
+ Next.js App Router-д ижил: `app/auth/eid/login/route.ts` → `NextResponse.redirect(a.url, 302)` + `res.cookies.set(…)`;
74
+ callback → `oidc.handleCallback(request.nextUrl.searchParams, tx)` (зөвхөн query уншина — прокси ард host хамаагүй).
75
+
76
+ **Товч** — энгийн холбоос (`<a href>` эсвэл form GET). `fetch`/XHR/JS redirect биш: iOS Universal Link зөвхөн
77
+ хэрэглэгчийн tap-аас эхэлсэн redirect гинжид eID аппыг нээнэ.
78
+
79
+ ```html
80
+ <a class="eid-login" href="/auth/eid/login">eID-ээр нэвтрэх</a>
81
+ <style>
82
+ .eid-login { display: inline-flex; align-items: center; justify-content: center; min-height: 44px;
83
+ padding: 0 1.25rem; border-radius: 8px; background: #0b3d91; color: #fff; font: 600 1rem/1 system-ui, sans-serif;
84
+ text-decoration: none; }
85
+ .eid-login:focus-visible { outline: 2px solid #0b3d91; outline-offset: 2px; }
86
+ </style>
87
+ ```
88
+
89
+ `createAuthorization({ display: "page" })` — утсан дээр ч нэвтрэх хуудас (QR / push) харуулна (ж: таблет киоск).
90
+
91
+ **`id_token` claims** (`EidIdTokenClaims`): `sub` (pairwise — RP тус бүрд өөр, иргэнд тогтмол), `acr`
92
+ (`urn:eidmongolia:loa:qualified` | `…:advanced`), `auth_time`, `given_name` / `family_name` (латин, гэрчилгээнээс),
93
+ `given_name_mn` / `family_name_mn` (кирилл, байвал), `pnomn` (`pnomn` scope + эрхтэй үед). `id_token` 5 минут
94
+ хүчинтэй; access_token / refresh_token / userinfo байхгүй — нэвтрэлтийн дараа өөрийн session-оо хэрэглэнэ.
95
+
96
+ **Аюулгүй байдал.**
97
+
98
+ - `state`, `nonce`, `codeVerifier`-ийг **хөтчийн session-тэй** (httpOnly, Secure, SameSite=Lax cookie эсвэл server
99
+ session) холбож хадгална; `handleCallback` state-ийг timing-safe тулгаж, таарахгүй бол code-ийг солихгүй
100
+ (`state_mismatch`). Үүнгүйгээр «өөрийн бүртгэлд хохирогчийн eID-ийг холбуулах» (login CSRF) нээлттэй.
101
+ - `handleCallback` / `verifyIdToken` нь ES256 гарын үсэг (JWKS `kid`, cache 1 цаг, танихгүй `kid` → нэг удаа дахин
102
+ татна), `iss`, `aud` (= `clientId`; олон aud бол `azp`), `exp` / `iat` (±60 сек), `nonce`-ийг шалгана.
103
+ `EidOidcError` (`invalid_id_token`) гарвал **итгэхгүй**.
104
+ - Code нэг удаагийн, 60 секунд — callback-ийг дахин ачаалбал `invalid_grant`; хэрэглэгчийг дахин нэвтрүүлнэ.
105
+ - `error_description` (`EidOidcError.description`)-ийг логт бичиж болно, хэрэглэгчид шууд харуулахгүй.
106
+ - **Native апп (RFC 8252):** authorize-ийг системийн хөтчөөр нээнэ — iOS `ASWebAuthenticationSession`
107
+ (`prefersEphemeralWebBrowserSession = false`), Android Custom Tabs. **WebView хориотой.** `redirect_uri` = таны
108
+ https Universal Link / App Link (custom scheme дэмжихгүй). `state` / `nonce` / `codeVerifier` апп-ын санах ойд;
109
+ code-ийг таны backend `client_secret`-ээр солино (`client_secret`-ийг аппад хадгалахгүй).
23
110
 
24
111
  ## 2. Нэвтрэлт (push)
25
112
 
@@ -67,6 +154,51 @@ const sig = eid.validator.validateSign(result, digest); // digest-ийн эср
67
154
  console.log(sig.signatureValueB64, sig.subject);
68
155
  ```
69
156
 
157
+ ## 3a. Байгууллагын нэрийн өмнөөс гарын үсэг (onBehalfOf)
158
+
159
+ Иргэн **өөрийн PIN2 гэрчилгээгээр** зурна; тухайн мөчид байгууллагыг төлөөлөх эрхтэйг eID **өөрийн бүртгэлээр**
160
+ шалгана (Эстонийн загвар). Энэ нь **хувь хүний квалификацтай гарын үсэг** — байгууллагын гэрчилгээ, тамга (e-Seal) биш.
161
+ e-Seal нь зөвхөн хүнгүй, автомат системийн баримтад. Урьдчилсан нөхцөл: байгууллага eID-д `ACTIVE` (захирал
162
+ аппаараа ХУР-аар холбоно), зурагч нь `ADMIN` эсвэл PIN2-оор баталгаажуулсан `MANAGER`, RP-д `SIGN` эрх.
163
+ Дэлгэрэнгүй: [developer.eidmongolia.mn](https://developer.eidmongolia.mn/).
164
+
165
+ ```ts
166
+ import { ForbiddenError, ApiError, ON_BEHALF_ERROR_CODES } from "@gerege-systems/eid-mongolia-sdk";
167
+
168
+ // 1. Иргэн сүүлийн 24 цагт танай RP-ээр нэвтэрсэн байх ёстой.
169
+ const { representations } = await eid.organization.getRepresentations("PNOMN-12345678");
170
+ // → [{ orgEtsi: "NTRMN-6235972", orgName: "Гэрэгэ Системс ХХК", role: "ceo", rightType: "ADMIN", … }]
171
+
172
+ // 2. PDF (PAdES, CA угсарна) — санал болгох урсгал.
173
+ try {
174
+ const s = await eid.pdf.prepare({
175
+ pdf: pdfBytes, fileName: "Гэрээ №12.pdf",
176
+ signer: { etsi: "PNOMN-12345678" }, flow: "notification",
177
+ onBehalfOf: "NTRMN-6235972",
178
+ });
179
+ showToUser(s.vc);
180
+ const r = await eid.session.waitForResult(s.sessionId);
181
+ // MUST: endResult OK, pdf.documentStatus READY, pdf.signer.onBehalfOf = хүссэн байгууллага,
182
+ // татсан файлын SHA-256 = pdf.outSha256, validation.indication "valid", ltv true.
183
+ if (r.pdf?.documentStatus !== "READY" || r.pdf.signer?.onBehalfOf !== "NTRMN-6235972") throw new Error("…");
184
+ const signed = await eid.pdf.document(s.sessionId);
185
+ console.log(r.pdf.signer.claimedRole); // "Гүйцэтгэх захирал, Гэрэгэ Системс ХХК (NTRMN-6235972)"
186
+ } catch (e) {
187
+ if ((e instanceof ForbiddenError || e instanceof ApiError) && e.code) {
188
+ // REPRESENTATION_DENIED | REPRESENTATION_PENDING | REPRESENTATION_EXPIRED | ORG_NOT_ACTIVE |
189
+ // SIGNER_UNIDENTIFIED (403) · ORG_NOT_FOUND (404) · REPRESENTATION_REVOKED (403, document татах үед)
190
+ }
191
+ throw e;
192
+ }
193
+
194
+ // Raw digest гарын үсэгт ч мөн: eid.sign.digestByEtsi(id, digest, interactions, { onBehalfOf: "NTRMN-6235972" })
195
+ // — CMS/PDF-ийг та угсардаг тул мэдүүлсэн үүргийг (signer-attributes-v2) өөрөө нэмнэ.
196
+ ```
197
+
198
+ Олон талт гэрээ: А байгууллагын гаралтыг өөрчлөлтгүй Б-ийн `prepare`-д (`docID`, өөр `onBehalfOf`) илгээнэ.
199
+ Session-ий `onBehalfOf` блок (`role`/`rightType`) нь хариу угсрах үеийн бүртгэл; `pdf.signer.onBehalfOf`/`claimedRole`
200
+ нь баримтад бичигдсэн утга.
201
+
70
202
  ## 4. QR ба ижил төхөөрөмж — device link v3
71
203
 
72
204
  Иргэн өөр төхөөрөмжийн дэлгэц дээрх **QR**-ийг утсаараа уншина, эсвэл RP-ийн сайт/аппыг eID апптай **ижил
@@ -172,11 +304,12 @@ OK ирж болзошгүй. Иймд `ResponseValidator`:
172
304
  | Алдаа | Утга |
173
305
  |---|---|
174
306
  | `AuthenticationError` | 401 — API secret буруу/байхгүй |
175
- | `ForbiddenError` | 403 — IP allowlist / mTLS зөвшөөрөөгүй |
307
+ | `ForbiddenError` | 403 — IP allowlist / mTLS / RP-ийн эрх; onBehalfOf татгалзвал `.code` (`OnBehalfErrorCode`) |
176
308
  | `SessionFailedError` | endResult ≠ OK (TIMEOUT, USER_REFUSED…) — `.endResult`-оор салга |
177
309
  | `ValidationError` | cert chain/signature/level шалгалт бүтэлгүйтсэн |
178
- | `ApiError` | бусад HTTP алдаа (`.status`, `.body`) |
310
+ | `ApiError` | бусад HTTP алдаа (`.status`, `.body`, серверийн `.code` — ж: 404 `ORG_NOT_FOUND`) |
179
311
  | `NetworkError` | timeout/сүлжээ |
312
+ | `EidOidcError` | «eID-ээр нэвтрэх» (OIDC) — `.code`: `access_denied`, `login_required`, `state_mismatch`, `invalid_grant`, `invalid_id_token`, `server_error` … |
180
313
  | `DeviceLinkError` | device-link холбоос угсрах боломжгүй (`deviceLinkBase` https биш, token/secret/lang хэлбэр, төрөлд хэрэгтэй талбар дутуу) |
181
314
 
182
315
  ## mTLS (eIDAS qualified орчин)
@@ -130,6 +130,61 @@ interface SessionResult {
130
130
  * RP энэ талбарыг л итгэж уншина (клиентийн сонголтод биш). docs/ORG_LOGIN.md.
131
131
  */
132
132
  onBehalfOf: OrgResult | null;
133
+ /**
134
+ * PAdES (`POST /pdf/sign/prepare`) session-ий `pdf` блок — PDF урсгал биш бол null (талбар алга = хуучин SDK-аар
135
+ * угсарсан объект). {@link PdfSessionBlock}.
136
+ */
137
+ pdf?: PdfSessionBlock | null;
138
+ }
139
+ /** PDF баримтын төлөв: PENDING → READY (эсвэл FAILED / EXPIRED). */
140
+ type PdfDocumentStatus = "PENDING" | "READY" | "FAILED" | "EXPIRED";
141
+ /** PAdES гаралтын гарын үсэг зурагч. */
142
+ interface PdfSigner {
143
+ etsi: string;
144
+ certSerial: string;
145
+ /** Байгууллагын нэрийн өмнөөс бол байгууллагын ETSI (`NTRMN-…`) — баримтад бичигдсэн утга. */
146
+ onBehalfOf?: string;
147
+ /** CMS signer-attributes-v2-д бичигдсэн мэдүүлсэн үүрэг: «<албан тушаал>, <нэр> (NTRMN-…)». */
148
+ claimedRole?: string;
149
+ }
150
+ /** GET /session/{id}-ийн `pdf` объект (PAdES, CA угсарна). */
151
+ interface PdfSessionBlock {
152
+ docID: string;
153
+ documentStatus: PdfDocumentStatus | string;
154
+ /** FAILED үед — ж: `REPRESENTATION_REVOKED` (prepare-ээс хойш эрх хасагдсан, баримт үүсээгүй). */
155
+ errorCode?: string;
156
+ /** Гарын үсэгтэй PDF-ийн SHA-256 (hex) — татсан файлтай тулгана. */
157
+ outSha256?: string;
158
+ size?: number;
159
+ expiresAt?: string;
160
+ signatureLevel?: string;
161
+ signer?: PdfSigner;
162
+ validation?: {
163
+ indication: string;
164
+ ltv: boolean;
165
+ signatures: number;
166
+ };
167
+ }
168
+ /** Иргэний төлөөлж чадах нэг байгууллага (GET /organization/representations/etsi/{personEtsi}). */
169
+ interface Representation {
170
+ /** `NTRMN-<бүртгэл>` — `onBehalfOf`-д өгөх утга. */
171
+ orgEtsi: string;
172
+ orgRegister: string;
173
+ orgName: string;
174
+ orgNameEn?: string;
175
+ /** Бүртгэлийн албан тушаал (ХУР-аас холбогдсонд `ceo` / `founder`, MANAGER-т ADMIN-ий бичсэн текст). */
176
+ role?: string;
177
+ rightType: "ADMIN" | "MANAGER" | string;
178
+ source: "REGISTRY" | "MANUAL" | string;
179
+ /** ISO 8601. */
180
+ validFrom: string;
181
+ /** ISO 8601; байхгүй = хугацаагүй. */
182
+ validTo?: string;
183
+ }
184
+ /** GET /organization/representations/etsi/{personEtsi} хариу. */
185
+ interface RepresentationsResponse {
186
+ personEtsi: string;
187
+ representations: Representation[];
133
188
  }
134
189
  /** Session-ий байгууллагын блок — байгууллага + тухайн иргэний эрх (бүртгэлээс real-time). */
135
190
  interface OrgResult {
@@ -206,15 +261,37 @@ declare class EidError extends Error {
206
261
  /** HTTP 401 — API secret буруу/байхгүй. Тохиргооны (RP secret) алдаа. */
207
262
  declare class AuthenticationError extends EidError {
208
263
  }
209
- /** HTTP 403 — IP allowlist/mTLS зөвшөөрөөгүй. Танай серверийн IP бүртгэгдээгүй байж магадгүй. */
264
+ /**
265
+ * HTTP 403 — IP allowlist/mTLS зөвшөөрөөгүй, RP-д эрх алга, эсвэл onBehalfOf-ийн төлөөлөл татгалзсан.
266
+ * Сервер `{"error","code"}` буцаасан бол `code` (ж: `REPRESENTATION_DENIED`) — салааллыг үүгээр хийнэ.
267
+ */
210
268
  declare class ForbiddenError extends EidError {
269
+ /** Серверийн тогтвортой алдааны код (`{"code"}`), байхгүй бол undefined. */
270
+ readonly code?: string | undefined;
271
+ constructor(message: string,
272
+ /** Серверийн тогтвортой алдааны код (`{"code"}`), байхгүй бол undefined. */
273
+ code?: string | undefined);
211
274
  }
212
275
  /** RP-API-аас ирсэн бусад HTTP алдаа (4xx/5xx). status ба хариуны биеийг агуулна. */
213
276
  declare class ApiError extends EidError {
214
277
  readonly status: number;
215
278
  readonly body: string;
216
- constructor(status: number, body: string);
279
+ /** Серверийн тогтвортой алдааны код (`{"error","code"}`-ийн `code`), байхгүй бол undefined. */
280
+ readonly code?: string | undefined;
281
+ constructor(status: number, body: string,
282
+ /** Серверийн тогтвортой алдааны код (`{"error","code"}`-ийн `code`), байхгүй бол undefined. */
283
+ code?: string | undefined);
217
284
  }
285
+ /**
286
+ * Байгууллагын нэрийн өмнөөс (`onBehalfOf`) урсгалын татгалзлын кодууд — `ForbiddenError.code` /
287
+ * `ApiError.code`-д ирнэ. 403: REPRESENTATION_DENIED (идэвхтэй төлөөлөгч биш), REPRESENTATION_PENDING (PIN2-оор
288
+ * баталгаажуулаагүй), REPRESENTATION_EXPIRED (хугацааны гадна), ORG_NOT_ACTIVE, SIGNER_UNIDENTIFIED (anonymous
289
+ * session); 404: ORG_NOT_FOUND; PDF баримт татахад 403 REPRESENTATION_REVOKED (prepare-ээс хойш эрх хасагдсан —
290
+ * баримт үүсээгүй).
291
+ */
292
+ type OnBehalfErrorCode = "REPRESENTATION_DENIED" | "REPRESENTATION_PENDING" | "REPRESENTATION_EXPIRED" | "ORG_NOT_ACTIVE" | "SIGNER_UNIDENTIFIED" | "ORG_NOT_FOUND" | "REPRESENTATION_REVOKED";
293
+ /** {@link OnBehalfErrorCode}-ийн бүх утга (runtime шалгалтад). */
294
+ declare const ON_BEHALF_ERROR_CODES: readonly OnBehalfErrorCode[];
218
295
  /** Сүлжээ/timeout — upstream хариу өгсөнгүй. */
219
296
  declare class NetworkError extends EidError {
220
297
  }
@@ -240,4 +317,4 @@ declare class ValidationError extends EidError {
240
317
  declare class DeviceLinkError extends EidError {
241
318
  }
242
319
 
243
- export { type AcspContext as A, type CertificateLevel as C, type DeviceLinkSession as D, EidError as E, type FlowType as F, type HashAlgorithm as H, type Interaction as I, type NotificationSession as N, type OpenOrShowQROptions as O, type RpCredentials as R, type SignatureAlgorithm as S, ValidationError as V, type SessionResult as a, ApiError as b, AuthenticationError as c, DeviceLinkError as d, type DeviceLinkInput as e, type EndResult as f, ForbiddenError as g, type NavigatorLike as h, NetworkError as i, SessionFailedError as j, type SessionState as k, type SignatureAlgorithmParameters as l, type SignatureProtocol as m, deviceLink as n, isMobileUserAgent as o, openOrShowQR as p };
320
+ export { type AcspContext as A, type CertificateLevel as C, type DeviceLinkSession as D, EidError as E, type FlowType as F, type HashAlgorithm as H, type Interaction as I, type NotificationSession as N, ON_BEHALF_ERROR_CODES as O, type PdfDocumentStatus as P, type RpCredentials as R, type SignatureAlgorithm as S, ValidationError as V, type SessionResult as a, type RepresentationsResponse as b, ApiError as c, AuthenticationError as d, DeviceLinkError as e, type DeviceLinkInput as f, type EndResult as g, ForbiddenError as h, type NavigatorLike as i, NetworkError as j, type OnBehalfErrorCode as k, type OpenOrShowQROptions as l, type OrgResult as m, type PdfSessionBlock as n, type PdfSigner as o, type Representation as p, SessionFailedError as q, type SessionState as r, type SignatureAlgorithmParameters as s, type SignatureProtocol as t, deviceLink as u, isMobileUserAgent as v, openOrShowQR as w };
@@ -130,6 +130,61 @@ interface SessionResult {
130
130
  * RP энэ талбарыг л итгэж уншина (клиентийн сонголтод биш). docs/ORG_LOGIN.md.
131
131
  */
132
132
  onBehalfOf: OrgResult | null;
133
+ /**
134
+ * PAdES (`POST /pdf/sign/prepare`) session-ий `pdf` блок — PDF урсгал биш бол null (талбар алга = хуучин SDK-аар
135
+ * угсарсан объект). {@link PdfSessionBlock}.
136
+ */
137
+ pdf?: PdfSessionBlock | null;
138
+ }
139
+ /** PDF баримтын төлөв: PENDING → READY (эсвэл FAILED / EXPIRED). */
140
+ type PdfDocumentStatus = "PENDING" | "READY" | "FAILED" | "EXPIRED";
141
+ /** PAdES гаралтын гарын үсэг зурагч. */
142
+ interface PdfSigner {
143
+ etsi: string;
144
+ certSerial: string;
145
+ /** Байгууллагын нэрийн өмнөөс бол байгууллагын ETSI (`NTRMN-…`) — баримтад бичигдсэн утга. */
146
+ onBehalfOf?: string;
147
+ /** CMS signer-attributes-v2-д бичигдсэн мэдүүлсэн үүрэг: «<албан тушаал>, <нэр> (NTRMN-…)». */
148
+ claimedRole?: string;
149
+ }
150
+ /** GET /session/{id}-ийн `pdf` объект (PAdES, CA угсарна). */
151
+ interface PdfSessionBlock {
152
+ docID: string;
153
+ documentStatus: PdfDocumentStatus | string;
154
+ /** FAILED үед — ж: `REPRESENTATION_REVOKED` (prepare-ээс хойш эрх хасагдсан, баримт үүсээгүй). */
155
+ errorCode?: string;
156
+ /** Гарын үсэгтэй PDF-ийн SHA-256 (hex) — татсан файлтай тулгана. */
157
+ outSha256?: string;
158
+ size?: number;
159
+ expiresAt?: string;
160
+ signatureLevel?: string;
161
+ signer?: PdfSigner;
162
+ validation?: {
163
+ indication: string;
164
+ ltv: boolean;
165
+ signatures: number;
166
+ };
167
+ }
168
+ /** Иргэний төлөөлж чадах нэг байгууллага (GET /organization/representations/etsi/{personEtsi}). */
169
+ interface Representation {
170
+ /** `NTRMN-<бүртгэл>` — `onBehalfOf`-д өгөх утга. */
171
+ orgEtsi: string;
172
+ orgRegister: string;
173
+ orgName: string;
174
+ orgNameEn?: string;
175
+ /** Бүртгэлийн албан тушаал (ХУР-аас холбогдсонд `ceo` / `founder`, MANAGER-т ADMIN-ий бичсэн текст). */
176
+ role?: string;
177
+ rightType: "ADMIN" | "MANAGER" | string;
178
+ source: "REGISTRY" | "MANUAL" | string;
179
+ /** ISO 8601. */
180
+ validFrom: string;
181
+ /** ISO 8601; байхгүй = хугацаагүй. */
182
+ validTo?: string;
183
+ }
184
+ /** GET /organization/representations/etsi/{personEtsi} хариу. */
185
+ interface RepresentationsResponse {
186
+ personEtsi: string;
187
+ representations: Representation[];
133
188
  }
134
189
  /** Session-ий байгууллагын блок — байгууллага + тухайн иргэний эрх (бүртгэлээс real-time). */
135
190
  interface OrgResult {
@@ -206,15 +261,37 @@ declare class EidError extends Error {
206
261
  /** HTTP 401 — API secret буруу/байхгүй. Тохиргооны (RP secret) алдаа. */
207
262
  declare class AuthenticationError extends EidError {
208
263
  }
209
- /** HTTP 403 — IP allowlist/mTLS зөвшөөрөөгүй. Танай серверийн IP бүртгэгдээгүй байж магадгүй. */
264
+ /**
265
+ * HTTP 403 — IP allowlist/mTLS зөвшөөрөөгүй, RP-д эрх алга, эсвэл onBehalfOf-ийн төлөөлөл татгалзсан.
266
+ * Сервер `{"error","code"}` буцаасан бол `code` (ж: `REPRESENTATION_DENIED`) — салааллыг үүгээр хийнэ.
267
+ */
210
268
  declare class ForbiddenError extends EidError {
269
+ /** Серверийн тогтвортой алдааны код (`{"code"}`), байхгүй бол undefined. */
270
+ readonly code?: string | undefined;
271
+ constructor(message: string,
272
+ /** Серверийн тогтвортой алдааны код (`{"code"}`), байхгүй бол undefined. */
273
+ code?: string | undefined);
211
274
  }
212
275
  /** RP-API-аас ирсэн бусад HTTP алдаа (4xx/5xx). status ба хариуны биеийг агуулна. */
213
276
  declare class ApiError extends EidError {
214
277
  readonly status: number;
215
278
  readonly body: string;
216
- constructor(status: number, body: string);
279
+ /** Серверийн тогтвортой алдааны код (`{"error","code"}`-ийн `code`), байхгүй бол undefined. */
280
+ readonly code?: string | undefined;
281
+ constructor(status: number, body: string,
282
+ /** Серверийн тогтвортой алдааны код (`{"error","code"}`-ийн `code`), байхгүй бол undefined. */
283
+ code?: string | undefined);
217
284
  }
285
+ /**
286
+ * Байгууллагын нэрийн өмнөөс (`onBehalfOf`) урсгалын татгалзлын кодууд — `ForbiddenError.code` /
287
+ * `ApiError.code`-д ирнэ. 403: REPRESENTATION_DENIED (идэвхтэй төлөөлөгч биш), REPRESENTATION_PENDING (PIN2-оор
288
+ * баталгаажуулаагүй), REPRESENTATION_EXPIRED (хугацааны гадна), ORG_NOT_ACTIVE, SIGNER_UNIDENTIFIED (anonymous
289
+ * session); 404: ORG_NOT_FOUND; PDF баримт татахад 403 REPRESENTATION_REVOKED (prepare-ээс хойш эрх хасагдсан —
290
+ * баримт үүсээгүй).
291
+ */
292
+ type OnBehalfErrorCode = "REPRESENTATION_DENIED" | "REPRESENTATION_PENDING" | "REPRESENTATION_EXPIRED" | "ORG_NOT_ACTIVE" | "SIGNER_UNIDENTIFIED" | "ORG_NOT_FOUND" | "REPRESENTATION_REVOKED";
293
+ /** {@link OnBehalfErrorCode}-ийн бүх утга (runtime шалгалтад). */
294
+ declare const ON_BEHALF_ERROR_CODES: readonly OnBehalfErrorCode[];
218
295
  /** Сүлжээ/timeout — upstream хариу өгсөнгүй. */
219
296
  declare class NetworkError extends EidError {
220
297
  }
@@ -240,4 +317,4 @@ declare class ValidationError extends EidError {
240
317
  declare class DeviceLinkError extends EidError {
241
318
  }
242
319
 
243
- export { type AcspContext as A, type CertificateLevel as C, type DeviceLinkSession as D, EidError as E, type FlowType as F, type HashAlgorithm as H, type Interaction as I, type NotificationSession as N, type OpenOrShowQROptions as O, type RpCredentials as R, type SignatureAlgorithm as S, ValidationError as V, type SessionResult as a, ApiError as b, AuthenticationError as c, DeviceLinkError as d, type DeviceLinkInput as e, type EndResult as f, ForbiddenError as g, type NavigatorLike as h, NetworkError as i, SessionFailedError as j, type SessionState as k, type SignatureAlgorithmParameters as l, type SignatureProtocol as m, deviceLink as n, isMobileUserAgent as o, openOrShowQR as p };
320
+ export { type AcspContext as A, type CertificateLevel as C, type DeviceLinkSession as D, EidError as E, type FlowType as F, type HashAlgorithm as H, type Interaction as I, type NotificationSession as N, ON_BEHALF_ERROR_CODES as O, type PdfDocumentStatus as P, type RpCredentials as R, type SignatureAlgorithm as S, ValidationError as V, type SessionResult as a, type RepresentationsResponse as b, ApiError as c, AuthenticationError as d, DeviceLinkError as e, type DeviceLinkInput as f, type EndResult as g, ForbiddenError as h, type NavigatorLike as i, NetworkError as j, type OnBehalfErrorCode as k, type OpenOrShowQROptions as l, type OrgResult as m, type PdfSessionBlock as n, type PdfSigner as o, type Representation as p, SessionFailedError as q, type SessionState as r, type SignatureAlgorithmParameters as s, type SignatureProtocol as t, deviceLink as u, isMobileUserAgent as v, openOrShowQR as w };
@@ -1 +1 @@
1
- export { d as DeviceLinkError, e as DeviceLinkInput, D as DeviceLinkSession, E as EidError, h as NavigatorLike, O as OpenOrShowQROptions, n as deviceLink, o as isMobileUserAgent, p as openOrShowQR } from './browser-BU9ShPWO.cjs';
1
+ export { e as DeviceLinkError, f as DeviceLinkInput, D as DeviceLinkSession, E as EidError, i as NavigatorLike, l as OpenOrShowQROptions, u as deviceLink, v as isMobileUserAgent, w as openOrShowQR } from './browser-Db82DlYN.cjs';
package/dist/browser.d.ts CHANGED
@@ -1 +1 @@
1
- export { d as DeviceLinkError, e as DeviceLinkInput, D as DeviceLinkSession, E as EidError, h as NavigatorLike, O as OpenOrShowQROptions, n as deviceLink, o as isMobileUserAgent, p as openOrShowQR } from './browser-BU9ShPWO.js';
1
+ export { e as DeviceLinkError, f as DeviceLinkInput, D as DeviceLinkSession, E as EidError, i as NavigatorLike, l as OpenOrShowQROptions, u as deviceLink, v as isMobileUserAgent, w as openOrShowQR } from './browser-Db82DlYN.js';
package/dist/browser.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  deviceLink,
5
5
  isMobileUserAgent,
6
6
  openOrShowQR
7
- } from "./chunk-Q5TQMCJC.js";
7
+ } from "./chunk-NXDKQZIW.js";
8
8
  export {
9
9
  DeviceLinkError,
10
10
  EidError,
@@ -8,16 +8,32 @@ var EidError = class extends Error {
8
8
  var AuthenticationError = class extends EidError {
9
9
  };
10
10
  var ForbiddenError = class extends EidError {
11
+ constructor(message, code) {
12
+ super(message);
13
+ this.code = code;
14
+ }
15
+ code;
11
16
  };
12
17
  var ApiError = class extends EidError {
13
- constructor(status, body) {
18
+ constructor(status, body, code) {
14
19
  super(`RP-API ${status}: ${body}`);
15
20
  this.status = status;
16
21
  this.body = body;
22
+ this.code = code;
17
23
  }
18
24
  status;
19
25
  body;
26
+ code;
20
27
  };
28
+ var ON_BEHALF_ERROR_CODES = [
29
+ "REPRESENTATION_DENIED",
30
+ "REPRESENTATION_PENDING",
31
+ "REPRESENTATION_EXPIRED",
32
+ "ORG_NOT_ACTIVE",
33
+ "SIGNER_UNIDENTIFIED",
34
+ "ORG_NOT_FOUND",
35
+ "REPRESENTATION_REVOKED"
36
+ ];
21
37
  var NetworkError = class extends EidError {
22
38
  };
23
39
  var SessionFailedError = class extends EidError {
@@ -79,6 +95,7 @@ export {
79
95
  AuthenticationError,
80
96
  ForbiddenError,
81
97
  ApiError,
98
+ ON_BEHALF_ERROR_CODES,
82
99
  NetworkError,
83
100
  SessionFailedError,
84
101
  ValidationError,