eimzo-ts 0.1.1 → 0.1.3
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/AI_INTEGRATION.md +43 -0
- package/CHANGELOG.md +17 -1
- package/README.md +196 -143
- package/README.ru.md +233 -0
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.global.js +2 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -9
- package/skills/eimzo-ts/SKILL.md +115 -0
- package/skills/eimzo-ts/references/api.md +74 -0
- package/skills/eimzo-ts/references/backend.md +45 -0
- package/skills/eimzo-ts/references/examples.md +150 -0
- package/skills/eimzo-ts/references/troubleshooting.md +39 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Using eimzo-ts with AI coding tools
|
|
2
|
+
|
|
3
|
+
Resources that help AI assistants (Claude Code, Cursor, Codex, Gemini CLI, ChatGPT and others) use this
|
|
4
|
+
library correctly. None of them is discovered automatically unless your tool is configured to read it.
|
|
5
|
+
|
|
6
|
+
| Resource | What it is | Where |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| `llms.txt` | Index of the documentation in the [llms.txt](https://llmstxt.org/) format | https://abduazimkhuja.github.io/eimzo-ts/llms.txt |
|
|
9
|
+
| `llms-full.txt` | README, backend guide and skill references in one text file | https://abduazimkhuja.github.io/eimzo-ts/llms-full.txt |
|
|
10
|
+
| Agent Skill | Task instructions in the [Agent Skills](https://agentskills.io/specification) format | [`skills/eimzo-ts/`](skills/eimzo-ts/SKILL.md), also inside the npm package |
|
|
11
|
+
| `AGENTS.md` | Rules for agents working on this repository or integrating the library | [`AGENTS.md`](AGENTS.md) |
|
|
12
|
+
| Type declarations | Full TypeScript API with JSDoc (comments in Russian) | `node_modules/eimzo-ts/dist/index.d.ts` |
|
|
13
|
+
|
|
14
|
+
## Installing the Agent Skill
|
|
15
|
+
|
|
16
|
+
The skill is the folder `skills/eimzo-ts/` (a `SKILL.md` plus `references/`). Copy it into the skills
|
|
17
|
+
directory your tool reads. After `npm install eimzo-ts` it is available at
|
|
18
|
+
`node_modules/eimzo-ts/skills/eimzo-ts/`.
|
|
19
|
+
|
|
20
|
+
Claude Code (project-level):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
mkdir -p .claude/skills
|
|
24
|
+
cp -r node_modules/eimzo-ts/skills/eimzo-ts .claude/skills/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Claude Code (user-level, all projects): copy to `~/.claude/skills/eimzo-ts/` instead.
|
|
28
|
+
|
|
29
|
+
Other tools that support Agent Skills: copy the same folder into the location described in that tool's
|
|
30
|
+
documentation. The folder name must stay `eimzo-ts` (it must match `name` in `SKILL.md`).
|
|
31
|
+
|
|
32
|
+
Without skill support, point the assistant to the file directly, e.g.
|
|
33
|
+
"Read node_modules/eimzo-ts/skills/eimzo-ts/SKILL.md and follow it."
|
|
34
|
+
|
|
35
|
+
## Prompts that work well
|
|
36
|
+
|
|
37
|
+
- "Add login with E-IMZO to this app using eimzo-ts. Backend endpoints: …"
|
|
38
|
+
- "Replace e-imzo.js / e-imzo-client.js with eimzo-ts, keep the same UI."
|
|
39
|
+
- "Add a 'Sign' button that signs the order JSON with a timestamp and posts it to /api/orders/:id/sign."
|
|
40
|
+
- "eimzo-ts throws API_KEY_REJECTED on staging — what is wrong?"
|
|
41
|
+
|
|
42
|
+
Ask the assistant to also implement or review the backend: the library creates signatures, but only the
|
|
43
|
+
server (via e-imzo-server) can verify them.
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.1.3]
|
|
9
|
+
|
|
10
|
+
### Документация
|
|
11
|
+
|
|
12
|
+
- README на английском (русский — `README.ru.md`), сайт документации с примерами, FAQ и разбором ошибок.
|
|
13
|
+
- `llms.txt`, `llms-full.txt`, `AGENTS.md`, Agent Skill `skills/eimzo-ts/` (входит в npm-пакет), `AI_INTEGRATION.md`.
|
|
14
|
+
|
|
15
|
+
## [0.1.2]
|
|
16
|
+
|
|
17
|
+
### Исправлено
|
|
18
|
+
|
|
19
|
+
- Неверный пароль в E-IMZO 6.3 (`status -9999`, «Sequence tag error» / «Password is not ASCII»)
|
|
20
|
+
теперь даёт `WRONG_PASSWORD`, а не `EIMZO_ERROR`.
|
|
21
|
+
|
|
8
22
|
## [0.1.1]
|
|
9
23
|
|
|
10
24
|
### Исправлено
|
|
@@ -28,6 +42,8 @@
|
|
|
28
42
|
- Сборки ESM, CJS и IIFE (`EimzoClient`) с типами.
|
|
29
43
|
- Демо с режимом без E-IMZO и просмотром содержимого PKCS#7.
|
|
30
44
|
|
|
31
|
-
[Unreleased]: https://github.com/abduazimkhuja/eimzo-ts/compare/v0.1.
|
|
45
|
+
[Unreleased]: https://github.com/abduazimkhuja/eimzo-ts/compare/v0.1.3...HEAD
|
|
46
|
+
[0.1.3]: https://github.com/abduazimkhuja/eimzo-ts/compare/v0.1.2...v0.1.3
|
|
47
|
+
[0.1.2]: https://github.com/abduazimkhuja/eimzo-ts/compare/v0.1.1...v0.1.2
|
|
32
48
|
[0.1.1]: https://github.com/abduazimkhuja/eimzo-ts/compare/v0.1.0...v0.1.1
|
|
33
49
|
[0.1.0]: https://github.com/abduazimkhuja/eimzo-ts/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -1,93 +1,100 @@
|
|
|
1
|
-
# eimzo-ts
|
|
1
|
+
# eimzo-ts — TypeScript client for E-IMZO
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/eimzo-ts)
|
|
4
4
|
[](https://github.com/abduazimkhuja/eimzo-ts/actions/workflows/ci.yml)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Без зависимостей и без привязки к фреймворку: Angular, React, Vue, Svelte или обычная страница.
|
|
7
|
+
**English** · [Русский](README.ru.md)
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
`eimzo-ts` lets a web page talk to [E-IMZO](https://e-imzo.uz), the desktop application used in
|
|
10
|
+
Uzbekistan for electronic digital signatures (ЭЦП / ERI). With it you can list the user's signing keys,
|
|
11
|
+
create PKCS#7 (CMS) signatures, and log users in with their digital signature.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
It replaces `e-imzo.js` and `e-imzo-client.js` from the official E-IMZO example with a typed,
|
|
14
|
+
Promise-based API: no global variables, no changes to `String.prototype` or `Date.prototype`,
|
|
15
|
+
zero runtime dependencies.
|
|
14
16
|
|
|
15
|
-
**
|
|
17
|
+
> **Unofficial.** This project is not affiliated with the developers of E-IMZO.
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
[Documentation](https://abduazimkhuja.github.io/eimzo-ts/) ·
|
|
20
|
+
[Live demo](https://abduazimkhuja.github.io/eimzo-ts/demo/) (works without E-IMZO, using mock keys) ·
|
|
21
|
+
[npm](https://www.npmjs.com/package/eimzo-ts) ·
|
|
22
|
+
[Changelog](CHANGELOG.md)
|
|
19
23
|
|
|
20
|
-
##
|
|
24
|
+
## Use cases
|
|
25
|
+
|
|
26
|
+
- **Login with a digital signature.** Get a one-time challenge from your backend, sign it with the user's key,
|
|
27
|
+
and send the signature to your backend for verification.
|
|
28
|
+
- **Sign a document or form** (attached or detached PKCS#7), optionally with a trusted timestamp.
|
|
29
|
+
- **Sign a file** picked with `<input type="file">`.
|
|
30
|
+
- **Show the user's keys:** owner name, TIN (INN), PINFL, organization, validity, and an `expired` flag.
|
|
31
|
+
- **Migrate from `e-imzo.js` / `e-imzo-client.js`** callbacks to `async`/`await` ([migration guide](docs/migration.md), in Russian).
|
|
32
|
+
|
|
33
|
+
## How it works
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
your page (eimzo-ts) ──WebSocket──► E-IMZO on the user's PC (asks for the key password)
|
|
37
|
+
│
|
|
38
|
+
└── fetch ──► your backend ──► e-imzo-server (verifies the signature)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The library runs in the **browser**. It connects to E-IMZO at `ws://127.0.0.1:64646` (pages served over
|
|
42
|
+
http) or `wss://127.0.0.1:64443` (https). If the `EIMZOEXT` browser extension object is present on the
|
|
43
|
+
page, it is used instead. The password is typed into E-IMZO's own window; your page never sees it.
|
|
44
|
+
|
|
45
|
+
Signatures are **verified on the server** by e-imzo-server, not by this library.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
21
48
|
|
|
22
49
|
```bash
|
|
23
50
|
npm install eimzo-ts
|
|
24
51
|
```
|
|
25
52
|
|
|
26
|
-
|
|
53
|
+
Without a bundler, use the IIFE build. It exposes a global `EimzoClient`:
|
|
27
54
|
|
|
28
55
|
```html
|
|
29
|
-
<script src="https://unpkg.com/eimzo-ts@0.1
|
|
56
|
+
<script src="https://unpkg.com/eimzo-ts@0.1/dist/index.global.js"></script>
|
|
30
57
|
<script>
|
|
31
58
|
const eimzo = EimzoClient.createEimzo({ apiKeys: EimzoClient.DEV_API_KEYS });
|
|
32
59
|
</script>
|
|
33
60
|
```
|
|
34
61
|
|
|
35
|
-
|
|
62
|
+
The package ships ESM, CommonJS, and IIFE builds with TypeScript declarations. It is side-effect free.
|
|
63
|
+
|
|
64
|
+
## Quick start
|
|
36
65
|
|
|
37
66
|
```ts
|
|
38
67
|
import { createEimzo, createFetchBackend, DEV_API_KEYS } from 'eimzo-ts';
|
|
39
68
|
|
|
40
69
|
const eimzo = createEimzo({
|
|
41
|
-
apiKeys: { ...DEV_API_KEYS, 'my-site.uz': 'API
|
|
70
|
+
apiKeys: { ...DEV_API_KEYS, 'my-site.uz': 'API key for my-site.uz' },
|
|
42
71
|
backend: createFetchBackend({
|
|
43
72
|
challengeUrl: '/api/eimzo/challenge',
|
|
44
73
|
loginUrl: '/api/eimzo/login',
|
|
45
74
|
timestampUrl: '/api/eimzo/timestamp',
|
|
46
|
-
init: { credentials: 'include' }, //
|
|
75
|
+
init: { credentials: 'include' }, // headers, CSRF token, etc.
|
|
47
76
|
}),
|
|
48
77
|
});
|
|
49
78
|
|
|
50
|
-
const keys = await eimzo.listKeys();
|
|
51
|
-
const user = await eimzo.login(keys[0]);
|
|
52
|
-
const pkcs7 = await eimzo.signDocument('
|
|
79
|
+
const keys = await eimzo.listKeys(); // the user's keys
|
|
80
|
+
const user = await eimzo.login(keys[0]); // E-IMZO asks for the password
|
|
81
|
+
const pkcs7 = await eimzo.signDocument('document'); // signature + timestamp
|
|
53
82
|
```
|
|
54
83
|
|
|
55
|
-
|
|
84
|
+
Create **one** instance per application. It keeps the `keyId` of the loaded key, and E-IMZO remembers
|
|
85
|
+
the password per `keyId`.
|
|
56
86
|
|
|
57
|
-
|
|
87
|
+
### Sign without a backend
|
|
58
88
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
| `sign(data, { detached, base64, keyId })` | PKCS#7 в base64. `data` — строка, `Uint8Array` или `ArrayBuffer`. |
|
|
67
|
-
| `signFile(file, { detached, maxSize })` | Подпись `File`/`Blob`. По умолчанию detached, не больше 10 МБ. |
|
|
68
|
-
| `login(key)` | Вход: challenge → `loadKey` → подпись → `backend.login`. |
|
|
69
|
-
| `signDocument(data, options)` | `sign` → `backend.timestamp`. |
|
|
70
|
-
| `unloadKey()` | Выгружает ключ из E-IMZO. Вызывайте при выходе пользователя. |
|
|
71
|
-
| `call(plugin, name, args)` | Любая функция E-IMZO, см. `http://127.0.0.1:64646/apidoc.html`. |
|
|
72
|
-
| `setLocale(locale)`, `t(error)` | Язык сообщений об ошибках. |
|
|
73
|
-
|
|
74
|
-
### Опции `createEimzo`
|
|
75
|
-
|
|
76
|
-
| Опция | По умолчанию | |
|
|
77
|
-
|---|---|---|
|
|
78
|
-
| `apiKeys` | — | `{ домен: ключ }` или `[домен, ключ, ...]`. Для localhost — `DEV_API_KEYS`. |
|
|
79
|
-
| `backend` | — | `createFetchBackend(...)` или свой объект, см. ниже. |
|
|
80
|
-
| `minVersion` | `'4.86'` | Ниже — ошибка `OUTDATED_VERSION`. |
|
|
81
|
-
| `locale` | `'ru'` | `'ru'`, `'uz-Latn'`, `'uz-Cyrl'`, `'kaa'`, `'en'` или свой код. |
|
|
82
|
-
| `messages` | — | Свои тексты ошибок. |
|
|
83
|
-
| `autoReloadKey` | `true` | Если E-IMZO забыл `keyId`, загрузить ключ заново и повторить подпись. |
|
|
84
|
-
| `timeoutMs` | без ограничения | Таймаут вызова E-IMZO. |
|
|
85
|
-
| `url`, `WebSocketImpl`, `transport` | | Для тестов и нестандартного окружения. |
|
|
86
|
-
|
|
87
|
-
## Ошибки
|
|
89
|
+
```ts
|
|
90
|
+
const keys = await eimzo.listKeys();
|
|
91
|
+
await eimzo.loadKey(keys.find((k) => !k.expired)!);
|
|
92
|
+
const pkcs7 = await eimzo.sign('text to sign'); // attached PKCS#7, base64
|
|
93
|
+
const detached = await eimzo.sign(bytes, { detached: true }); // Uint8Array or ArrayBuffer
|
|
94
|
+
const filePkcs7 = await eimzo.signFile(input.files[0]); // detached by default, max 10 MB
|
|
95
|
+
```
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
(уже на языке `locale`) или `eimzo.t(error)`.
|
|
97
|
+
### Handle errors
|
|
91
98
|
|
|
92
99
|
```ts
|
|
93
100
|
import { isEimzoError } from 'eimzo-ts';
|
|
@@ -95,127 +102,173 @@ import { isEimzoError } from 'eimzo-ts';
|
|
|
95
102
|
try {
|
|
96
103
|
await eimzo.login(key);
|
|
97
104
|
} catch (e) {
|
|
98
|
-
if (isEimzoError(e, 'CANCELLED')) return;
|
|
99
|
-
if (isEimzoError(e, 'NOT_INSTALLED'))
|
|
100
|
-
else showError(eimzo.t(e));
|
|
105
|
+
if (isEimzoError(e, 'CANCELLED')) return; // the user closed the password window
|
|
106
|
+
if (isEimzoError(e, 'NOT_INSTALLED')) showInstallHint();
|
|
107
|
+
else showError(eimzo.t(e)); // localized message
|
|
101
108
|
}
|
|
102
109
|
```
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
|---|---|
|
|
106
|
-
| `NOT_INSTALLED` | E-IMZO не установлен или не запущен. |
|
|
107
|
-
| `OUTDATED_VERSION` | Версия ниже `minVersion`; в `params` — `installed` и `min`. |
|
|
108
|
-
| `API_KEY_REJECTED` | Нет API-KEY для домена страницы. |
|
|
109
|
-
| `WRONG_PASSWORD` | Неверный пароль ключа. |
|
|
110
|
-
| `CANCELLED` | Пользователь закрыл окно пароля. |
|
|
111
|
-
| `KEY_NOT_FOUND` | E-IMZO не знает `keyId` (прошло 24 часа, перезапуск E-IMZO). |
|
|
112
|
-
| `KEY_NOT_LOADED` | `sign()` до `loadKey()` — ошибка в коде. |
|
|
113
|
-
| `FILE_TOO_LARGE` | Файл больше `maxSize`. |
|
|
114
|
-
| `BACKEND_NOT_CONFIGURED` | Нет нужного метода в `backend` — ошибка в коде. |
|
|
115
|
-
| `BACKEND_ERROR` | Backend ответил ошибкой; `httpStatus`, `params.detail`. |
|
|
116
|
-
| `EIMZO_ERROR` | Прочие ошибки E-IMZO; исходный текст в `reason`, код в `status`. |
|
|
117
|
-
| `TIMEOUT`, `WEBSOCKET_UNSUPPORTED` | Редкие случаи. |
|
|
118
|
-
|
|
119
|
-
### Языки
|
|
111
|
+
## Features
|
|
120
112
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
113
|
+
- Typed API for keys, signing, login, and timestamps; Promise-based.
|
|
114
|
+
- PFX keys, ID card, BAIK token, and CKC devices (`listDevices`, `loadKey('idcard' | 'baikey' | 'ckc')`).
|
|
115
|
+
- Typed `EimzoError` with a stable `code`. E-IMZO's raw `reason` and `status` are kept.
|
|
116
|
+
- Error messages in Russian, Uzbek (Latin and Cyrillic), Karakalpak, and English; you can override any text.
|
|
117
|
+
- Concurrent `sign()` calls are queued, so a double click does not open two password windows.
|
|
118
|
+
- If E-IMZO has forgotten the `keyId` (24 hours passed, or E-IMZO restarted), the key is loaded again and
|
|
119
|
+
the signature is retried (`autoReloadKey`).
|
|
120
|
+
- `unloadKey()` on logout removes the key and its remembered password from E-IMZO.
|
|
121
|
+
- `createFetchBackend()` matches e-imzo-server's response format, so your backend can proxy it as-is.
|
|
122
|
+
- Zero runtime dependencies; ESM, CJS, and IIFE builds; `.d.ts` included.
|
|
131
123
|
|
|
132
|
-
|
|
124
|
+
Behaviour for cancel, wrong password, signing, and unloading was checked against E-IMZO 6.3.5.
|
|
133
125
|
|
|
134
|
-
##
|
|
126
|
+
## API
|
|
135
127
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
|
|
128
|
+
| Method | Description |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `createEimzo(options)` | Creates a client. See options below. |
|
|
131
|
+
| `init()` | Checks the E-IMZO version and installs API keys. Called automatically. |
|
|
132
|
+
| `getVersion()` | Installed E-IMZO version, `{ major, minor }`. |
|
|
133
|
+
| `listKeys()` | User keys as `EimzoKey[]`: `CN`, `TIN`, `PINFL`, `O`, `T`, `validFrom`, `validTo`, `expired`. Keys without TIN and PINFL are skipped. |
|
|
134
|
+
| `listDevices()` | `{ idcard, baikey, ckc }` — which hardware devices are connected. |
|
|
135
|
+
| `loadKey(key, { verifyPassword })` | Loads a key (or `'idcard' \| 'baikey' \| 'ckc'`) and stores its `keyId`. Unloads the previous key. |
|
|
136
|
+
| `sign(data, { detached, base64, keyId })` | Returns a base64 PKCS#7. `data`: `string`, `Uint8Array`, or `ArrayBuffer`. |
|
|
137
|
+
| `signFile(blob, { detached, maxSize, keyId })` | Signs a `File` or `Blob`. Detached by default, 10 MB limit. |
|
|
138
|
+
| `login(key)` | Challenge → `loadKey` → sign → `backend.login`. Returns what `backend.login` returns. |
|
|
139
|
+
| `signDocument(data, options)` | `sign` → `backend.timestamp`. |
|
|
140
|
+
| `unloadKey()` | Unloads the key from E-IMZO. Call it on logout. |
|
|
141
|
+
| `call(plugin, name, args)` | Calls any E-IMZO function (see `http://127.0.0.1:64646/apidoc.html`). |
|
|
142
|
+
| `keyId`, `locale`, `setLocale(locale)`, `t(error)` | Current key and language of error messages. |
|
|
142
143
|
|
|
143
|
-
|
|
144
|
+
Other exports: `createFetchBackend`, `EimzoError`, `isEimzoError`, `formatEimzoError`, `parseX500`,
|
|
145
|
+
`parseCertificateInfo`, `createWebSocketTransport`, `createCapiwsTransport`, `createDefaultTransport`,
|
|
146
|
+
`defaultEimzoUrl`, `DEV_API_KEYS`, `DEFAULT_MAX_FILE_SIZE`, the locale objects (`ru`, `uzLatn`, `uzCyrl`,
|
|
147
|
+
`kaa`, `en`), and all types.
|
|
144
148
|
|
|
145
|
-
|
|
146
|
-
e-imzo-server, поэтому backend может проксировать запросы:
|
|
149
|
+
### Options
|
|
147
150
|
|
|
148
|
-
|
|
|
151
|
+
| Option | Default | Description |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `apiKeys` | — | `{ domain: key }` or `[domain, key, ...]`. Use `DEV_API_KEYS` for `localhost` and `127.0.0.1`. If omitted, `apikey` is not called. |
|
|
154
|
+
| `backend` | — | `createFetchBackend(...)` or your own `{ getChallenge, login, timestamp }`. |
|
|
155
|
+
| `minVersion` | `'4.86'` | Older E-IMZO → `OUTDATED_VERSION`. |
|
|
156
|
+
| `locale` | `'ru'` | `'ru'`, `'uz-Latn'`, `'uz-Cyrl'`, `'kaa'`, `'en'`, or your own code with `messages`. |
|
|
157
|
+
| `messages` | — | Override texts: `{ en: { WRONG_PASSWORD: () => '...' } }`. Missing texts fall back to Russian. |
|
|
158
|
+
| `autoReloadKey` | `true` | Reload the key and retry when E-IMZO no longer knows the `keyId`. |
|
|
159
|
+
| `timeoutMs` | none | Timeout of one E-IMZO call. Off by default because signing waits for the user. |
|
|
160
|
+
| `url`, `WebSocketImpl`, `transport` | — | For tests and non-standard environments. |
|
|
161
|
+
|
|
162
|
+
### Error codes
|
|
163
|
+
|
|
164
|
+
| `code` | Meaning |
|
|
165
|
+
|---|---|
|
|
166
|
+
| `NOT_INSTALLED` | E-IMZO is not installed or not running. |
|
|
167
|
+
| `OUTDATED_VERSION` | E-IMZO is older than `minVersion` (`params.installed`, `params.min`). |
|
|
168
|
+
| `API_KEY_REJECTED` | E-IMZO rejected the API key for this domain. |
|
|
169
|
+
| `WRONG_PASSWORD` | Wrong key password. |
|
|
170
|
+
| `CANCELLED` | The user closed the password window. Usually not worth showing. |
|
|
171
|
+
| `KEY_NOT_FOUND` | E-IMZO does not know this `keyId`. |
|
|
172
|
+
| `KEY_NOT_LOADED` | `sign()` was called before `loadKey()` — a bug in the calling code. |
|
|
173
|
+
| `FILE_TOO_LARGE` | File is larger than `maxSize` (`params.size`, `params.max`). |
|
|
174
|
+
| `BACKEND_NOT_CONFIGURED` | A required `backend` method is missing — a bug in the calling code. |
|
|
175
|
+
| `BACKEND_ERROR` | Your backend returned an error (`httpStatus`, `params.detail`). |
|
|
176
|
+
| `EIMZO_ERROR` | Any other E-IMZO error; see `reason` and `status`. |
|
|
177
|
+
| `TIMEOUT`, `WEBSOCKET_UNSUPPORTED` | Rare. |
|
|
178
|
+
|
|
179
|
+
## Backend contract
|
|
180
|
+
|
|
181
|
+
The browser never calls e-imzo-server directly. `createFetchBackend` expects e-imzo-server's response
|
|
182
|
+
format, so your backend can proxy these calls:
|
|
183
|
+
|
|
184
|
+
| Client request | Your backend calls | Response |
|
|
149
185
|
|---|---|---|
|
|
150
|
-
| `GET challengeUrl` | `GET /frontend/challenge
|
|
151
|
-
| `POST loginUrl`,
|
|
152
|
-
| `POST timestampUrl`,
|
|
186
|
+
| `GET challengeUrl` | `GET /frontend/challenge` (do not cache) | `{ "status": 1, "challenge": "..." }` |
|
|
187
|
+
| `POST loginUrl`, body: PKCS#7 (`text/plain`) | `POST /backend/auth`, then finds the user by PINFL/TIN and opens a session | any JSON, returned from `login()` |
|
|
188
|
+
| `POST timestampUrl`, body: PKCS#7 (`text/plain`) | `POST /frontend/timestamp/pkcs7` | `{ "status": 1, "pkcs7b64": "..." }` |
|
|
153
189
|
|
|
154
|
-
|
|
190
|
+
A full guide with a Spring Boot example, status codes, and security checklist (in Russian):
|
|
191
|
+
[docs/backend.md](docs/backend.md).
|
|
155
192
|
|
|
156
|
-
|
|
193
|
+
## Compatibility
|
|
157
194
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
```
|
|
195
|
+
- **Browsers:** any modern browser with WebSocket. The build targets ES2020.
|
|
196
|
+
- **TypeScript:** declarations included for ESM and CJS.
|
|
197
|
+
- **Frameworks:** framework-agnostic: plain functions and a class, no framework dependency. It can be used
|
|
198
|
+
from Angular, React, Vue, Svelte, or a plain page. With SSR frameworks (Next.js, Nuxt, Angular SSR), call
|
|
199
|
+
it only on the client: E-IMZO runs on the user's computer, not on your server.
|
|
200
|
+
- **Node.js:** not the intended environment. It can talk to a local E-IMZO from a script if you pass a
|
|
201
|
+
`WebSocketImpl` that sends an `Origin` header (see `scripts/check-real-eimzo.mjs`).
|
|
202
|
+
- **E-IMZO:** 4.86 or newer by default (`minVersion`). Tested with E-IMZO 6.3.5.
|
|
167
203
|
|
|
168
|
-
##
|
|
204
|
+
## When not to use it
|
|
169
205
|
|
|
170
|
-
**
|
|
206
|
+
- **To verify signatures.** Verification needs e-imzo-server on your backend; this is a client library.
|
|
207
|
+
- **For mobile signing** (ID-CARD E-IMZO MOBILE, QR code / deep link). Not supported yet.
|
|
208
|
+
- **If you need a ready-made UI** (key picker modal). `eimzo-ts` has no UI components.
|
|
209
|
+
- **If you need another provider** (for example RS-IMZO).
|
|
171
210
|
|
|
172
|
-
|
|
173
|
-
@Injectable({ providedIn: 'root' })
|
|
174
|
-
export class EimzoService {
|
|
175
|
-
readonly client = createEimzo({ apiKeys: environment.eimzoApiKeys, backend: createFetchBackend({ /* ... */ }) });
|
|
176
|
-
}
|
|
211
|
+
## Alternatives
|
|
177
212
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
213
|
+
- The official `e-imzo.js` + `e-imzo-client.js` example: callback-based, uses globals.
|
|
214
|
+
- Other npm packages for E-IMZO exist. Some are framework-specific (Vue or React wrappers, UI modals),
|
|
215
|
+
some are framework-agnostic clients, and some are server-side clients for e-imzo-server. Search npm for
|
|
216
|
+
[`e-imzo`](https://www.npmjs.com/search?q=e-imzo) and compare their APIs and maintenance with your needs.
|
|
217
|
+
This project has not audited or benchmarked them.
|
|
183
218
|
|
|
184
|
-
|
|
219
|
+
## FAQ
|
|
185
220
|
|
|
186
|
-
**
|
|
221
|
+
**Does it work over HTTPS?** Yes. On https pages it connects to `wss://127.0.0.1:64443`.
|
|
187
222
|
|
|
188
|
-
|
|
189
|
-
|
|
223
|
+
**Do I need an API key?** For `localhost` and `127.0.0.1`, use `DEV_API_KEYS` (public keys from the official
|
|
224
|
+
example). For another domain during development, enable "Developer mode" in the E-IMZO tray menu. For
|
|
225
|
+
production, request an API key for each domain and subdomain.
|
|
190
226
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const [error, setError] = useState<string>();
|
|
194
|
-
useEffect(() => { eimzo.listKeys().then(setKeys, (e) => setError(eimzo.t(e))); }, []);
|
|
195
|
-
// ...
|
|
196
|
-
}
|
|
197
|
-
```
|
|
227
|
+
**Is the password sent to my site?** No. E-IMZO asks for it in its own window. Without "Remember for 6 hours"
|
|
228
|
+
it is remembered for 1 minute per `keyId`.
|
|
198
229
|
|
|
199
|
-
**
|
|
230
|
+
**How do I test my code without E-IMZO?** Pass your own `transport` — a function
|
|
231
|
+
`(request) => Promise<response>`:
|
|
200
232
|
|
|
201
233
|
```ts
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
234
|
+
const eimzo = createEimzo({
|
|
235
|
+
transport: async (req) => {
|
|
236
|
+
if (req.name === 'version') return { success: true, major: '6', minor: '3' };
|
|
237
|
+
if (req.plugin === 'pfx' && req.name === 'list_all_certificates') return { success: true, certificates: [] };
|
|
238
|
+
return { success: false, reason: `not mocked: ${req.plugin}.${req.name}` };
|
|
239
|
+
},
|
|
240
|
+
});
|
|
206
241
|
```
|
|
207
242
|
|
|
208
|
-
|
|
243
|
+
The demo's mock ([`demo/mock-eimzo.js`](demo/mock-eimzo.js)) is a fuller example.
|
|
244
|
+
|
|
245
|
+
**Can I read what is inside a PKCS#7?** The demo has a viewer ([`demo/pkcs7-viewer.js`](demo/pkcs7-viewer.js))
|
|
246
|
+
that shows the document, signer, and signing time. It does not verify the signature.
|
|
247
|
+
|
|
248
|
+
**Is `signingTime` trustworthy?** No. It comes from the user's computer clock. Use a timestamp
|
|
249
|
+
(`signDocument`) and verify it on the server.
|
|
209
250
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
251
|
+
## Troubleshooting
|
|
252
|
+
|
|
253
|
+
| Symptom | Cause and fix |
|
|
254
|
+
|---|---|
|
|
255
|
+
| `NOT_INSTALLED` | E-IMZO is not running. Start it (tray icon) or install it from [e-imzo.uz](https://e-imzo.uz/main/downloads/). |
|
|
256
|
+
| `API_KEY_REJECTED`, or E-IMZO functions fail on a new domain | No API key for this domain. Use Developer mode for testing; add the production key to `apiKeys`. |
|
|
257
|
+
| `OUTDATED_VERSION` | Update E-IMZO, or lower `minVersion` if you know your users' versions. |
|
|
258
|
+
| `WRONG_PASSWORD` with `reason` "Password is not ASCII" | The password was typed in another keyboard layout. |
|
|
259
|
+
| `listKeys()` returns fewer keys than E-IMZO shows | Keys without TIN and PINFL are skipped, as in the official client. |
|
|
260
|
+
| Password is asked on every signature | A new `Eimzo` instance or `loadKey()` per signature creates a new `keyId`. Keep one instance. |
|
|
261
|
+
| `KEY_NOT_FOUND` with `autoReloadKey: false` | E-IMZO restarted or 24 hours passed. Call `loadKey()` again. |
|
|
262
|
+
| `BACKEND_ERROR` | Check `httpStatus` and `params.detail`; for `/backend/auth` status codes see [docs/backend.md](docs/backend.md). |
|
|
213
263
|
|
|
214
|
-
##
|
|
264
|
+
## For AI coding assistants
|
|
215
265
|
|
|
216
|
-
|
|
266
|
+
- [`llms.txt`](https://abduazimkhuja.github.io/eimzo-ts/llms.txt) and
|
|
267
|
+
[`llms-full.txt`](https://abduazimkhuja.github.io/eimzo-ts/llms-full.txt) — documentation index and full text.
|
|
268
|
+
- [Agent Skill](skills/eimzo-ts/SKILL.md) for tools that support the Agent Skills format.
|
|
269
|
+
- See [AI_INTEGRATION.md](AI_INTEGRATION.md).
|
|
217
270
|
|
|
218
|
-
##
|
|
271
|
+
## Development
|
|
219
272
|
|
|
220
273
|
```bash
|
|
221
274
|
npm install
|
|
@@ -223,9 +276,9 @@ npm test # vitest
|
|
|
223
276
|
npm run typecheck
|
|
224
277
|
npm run build # dist/: ESM, CJS, IIFE + .d.ts
|
|
225
278
|
npm run demo # http://localhost:3000/demo/
|
|
226
|
-
npm run check:eimzo #
|
|
279
|
+
npm run check:eimzo # checks against a locally installed E-IMZO; --interactive N signs with key N
|
|
227
280
|
```
|
|
228
281
|
|
|
229
|
-
##
|
|
282
|
+
## License
|
|
230
283
|
|
|
231
284
|
[MIT](LICENSE)
|