@corelicense/node 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CoreLicense
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,193 +1,83 @@
1
1
  # @corelicense/node
2
2
 
3
- CoreLicense Node.js SDK — runtime license và policy layer cho ứng dụng Node.js.
3
+ Runtime license và policy layer cho ứng dụng Node.js — không chỉ middleware HTTP, mà là lớp kiểm soát **bootstrap**, **module registry**, **DI**, **worker/CLI**, **quota** và **feature gate** theo policy đã ký.
4
4
 
5
- > **Trạng thái:** v0.4 — tích hợp sâu (module registry & DI), production default URL, revoke handling.
5
+ **Phiên bản:** `0.5.1`
6
+ **License:** [MIT](./LICENSE)
7
+ **Repository:** [github.com/trailanglc/corelicense](https://github.com/trailanglc/corelicense)
8
+ **Docs trực tuyến:** [corelicense.net/docs](https://corelicense.net/docs/nodejs-sdk/quick-start)
6
9
 
7
- ## Triết lý
10
+ ---
8
11
 
9
- CoreLicense không chỉ middleware. SDK được thiết kế như một **Runtime Layer** nằm sâu trong bootstrap, runtime config, module registry, service guard, worker/CLI guard và quota enforcement.
12
+ ## CoreLicense là gì?
10
13
 
11
- ## Cài đặt
14
+ CoreLicense gồm **License Server** (API Go) và **Node.js SDK** (package này). Admin cấp license key + policy (features, limits, quotas). SDK:
12
15
 
13
- ```bash
14
- npm install @corelicense/node
15
- ```
16
-
17
- Peer dependencies tùy chọn (chỉ cài khi dùng integration tương ứng):
18
-
19
- ```bash
20
- npm install express # Express middleware
21
- npm install fastify # Fastify plugin
22
- npm install @nestjs/common # NestJS module/guard
23
- ```
24
-
25
- ## Quick start
26
-
27
- Chỉ cần **2 biến môi trường**. SDK mặc định kết nối `https://api.corelicense.net` — không cần cấu hình thêm cho production.
28
-
29
- License key mới (CL1.*) vẫn ưu tiên URL nhúng trong key nếu server generate với `SDK_PUBLIC_URL` khác.
30
-
31
- ```env
32
- CORELICENSE_KEY=CL1.xxxxx.CL-AAAAA-BBBBB-...
33
- CORELICENSE_PRODUCT_ID=demo
34
- ```
35
-
36
- `CORELICENSE_PUBLIC_KEY` **optional** — pin public key (enterprise / air-gapped).
37
- `CORELICENSE_API_URL` **optional** — override thủ công (dev local hoặc legacy key).
38
-
39
- Dev local với server Go chạy localhost:
40
-
41
- ```env
42
- CORELICENSE_API_URL=http://localhost:8080
43
- ```
44
-
45
- ```ts
46
- import express from 'express';
47
- import { CoreLicense, loadOptionsFromEnv } from '@corelicense/node';
16
+ 1. Kích hoạt / kiểm tra license với server
17
+ 2. Verify **policy token** bằng public key (EdDSA)
18
+ 3. Cache policy local, refresh định kỳ
19
+ 4. Chặn runtime khi revoke / suspend / expired
20
+ 5. (Tùy chọn) Chỉ bind module & service được cấp trong policy
48
21
 
49
- const app = express();
22
+ ---
50
23
 
51
- const license = new CoreLicense(loadOptionsFromEnv({
52
- cachePath: './storage/corelicense',
53
- instance: {
54
- strategy: 'install-id-domain-hash',
55
- domain: process.env.APP_DOMAIN,
56
- },
57
- }));
24
+ ## Tài liệu
58
25
 
59
- async function main() {
60
- await license.boot();
26
+ | Tài liệu | Nội dung |
27
+ |----------|----------|
28
+ | [Cài đặt](./docs/installation.md) | `npm install`, biến môi trường, boot lần đầu, dev/prod |
29
+ | [Tích hợp](./docs/integration.md) | **Hướng dẫn chi tiết** — Express, Fastify, NestJS, registry/DI, worker, quota, production |
30
+ | [API Reference](./docs/api-reference.md) | Public API, options, error codes |
31
+ | [LICENSE](./LICENSE) | MIT |
61
32
 
62
- app.use(license.express({
63
- allowPaths: ['/health', '/license/status'],
64
- }));
33
+ > Dành cho agent / CI: đọc [docs/integration.md](./docs/integration.md) trước khi generate code tích hợp.
65
34
 
66
- app.get('/license/status', async (_req, res) => {
67
- res.json(await license.getStatus());
68
- });
35
+ ---
69
36
 
70
- app.listen(3000);
71
- }
37
+ ## Quick links
72
38
 
73
- main().catch(console.error);
39
+ ```bash
40
+ npm install @corelicense/node
74
41
  ```
75
42
 
76
- ### Pin public key (optional)
43
+ Production mặc định: `https://api.corelicense.net` — chỉ cần `CORELICENSE_KEY` + `CORELICENSE_PRODUCT_ID`.
77
44
 
78
45
  ```ts
79
- const license = new CoreLicense(loadOptionsFromEnv({
80
- publicKey: process.env.CORELICENSE_PUBLIC_KEY, // pinned mode
81
- }));
82
- ```
83
-
84
- Khi pin, SDK không fetch keys từ server. Nếu verify fail sau key rotation, cập nhật `CORELICENSE_PUBLIC_KEY` thủ công.
85
-
86
- ## Public API
87
-
88
- | Method | Mô tả |
89
- |--------|-------|
90
- | `boot()` | Khởi tạo SDK, fetch/cache public keys, load cache, verify token |
91
- | `refresh()` | Refresh policy token từ server |
92
- | `requireActive()` | Yêu cầu license active |
93
- | `requireFeature(name)` | Kiểm tra feature flag |
94
- | `checkLimit(name, value)` | Kiểm tra limit |
95
- | `consumeQuota(name, amount?)` | Tiêu thụ quota local |
96
- | `getStatus()` | Trạng thái license hiện tại |
97
- | `getPolicy()` | Policy đang active |
98
- | `getRuntimeConfig()` | Runtime config cho app bootstrap |
99
- | `express(options?)` | Express middleware |
100
- | `fastifyPlugin(options?)` | Fastify plugin |
101
- | `guardWorker(name)` | Guard worker |
102
- | `guardCommand(name)` | Guard CLI/cron command |
103
- | `createLicensedRegistry()` | Module registry gắn license |
104
- | `createLicensedContainer()` | DI container gắn license |
105
- | `bootstrap(options?)` | Bootstrap modules + services theo policy |
106
-
107
- ## Tích hợp sâu (v0.4)
46
+ import { CoreLicense, loadOptionsFromEnv } from '@corelicense/node';
108
47
 
109
- ```ts
48
+ const license = new CoreLicense(loadOptionsFromEnv({ cachePath: './storage/corelicense' }));
110
49
  await license.boot();
111
-
112
- const { modules, services, skipped } = await license.bootstrap({
113
- modules: [
114
- { name: 'automation', feature: 'automation', factory: ({ license }) => new AutomationModule(license) },
115
- ],
116
- services: [
117
- { name: 'ExportService', feature: 'export', factory: ({ license }) => new ExportService(license) },
118
- ],
119
- });
120
-
121
- const automation = await modules.get<AutomationModule>('automation');
122
- const exportService = await services.resolve<ExportService>('ExportService');
123
-
124
- import { registerLicensedRoutes } from '@corelicense/node';
125
- registerLicensedRoutes(app, modules, [
126
- { path: '/automation', module: 'automation', router: automationRouter },
127
- ]);
128
- ```
129
-
130
- `get()` và `resolve()` gọi `requireFeature` mỗi lần truy cập — revoke/suspend chặn ngay. Đổi feature trong policy vẫn cần **restart** để bind/unbind module mới.
131
-
132
- Xem [Tích hợp sâu](https://corelicense.net/docs/nodejs-sdk/deep-integration) trên docs site.
133
-
134
- ## Xử lý lỗi
135
-
136
- Mọi lỗi SDK đều có `code` (mã định vị) và `source` (module SDK phát sinh):
137
-
138
- ```ts
139
- import { isLicenseError, formatLicenseError, LicenseErrorCode } from '@corelicense/node';
140
-
141
- try {
142
- await license.boot();
143
- } catch (error) {
144
- if (isLicenseError(error)) {
145
- console.error(error.code, error.source); // e.g. CONFIG_MISSING_ENV, load-options-from-env
146
- }
147
- }
148
50
  ```
149
51
 
150
- Dùng `error.toJSON()` hoặc `formatLicenseError(error)` khi trả lỗi qua HTTP API.
151
-
152
- ## Production deploy
52
+ Chi tiết: [docs/installation.md](./docs/installation.md) [docs/integration.md](./docs/integration.md).
153
53
 
154
- **SDK:** `cd SDK/corelicense-node && npm test && npm run build && npm publish --access public`
54
+ ---
155
55
 
156
- **API (Go):** deploy backend với `SDK_PUBLIC_URL=https://api.corelicense.net`, policy signer configured, và `APP_ENV=production`. Production validate yêu cầu HTTPS URL (không localhost) và secrets không dùng `change-me`.
56
+ ## Subpath exports
157
57
 
158
- ## Cấu trúc module
159
-
160
- ```txt
161
- src/
162
- core-license.ts # Class chính
163
- types/ # TypeScript interfaces
164
- errors/ # Error hierarchy
165
- crypto/ # Policy token verification + public key resolver
166
- client/ # License API + public keys client
167
- cache/ # File/memory cache
168
- instance/ # Instance ID resolution
169
- guards/ # Express, Fastify, NestJS, worker, CLI
170
- runtime/ # Runtime config, module registry, DI container
171
- audit/ # Local audit log
172
- events/ # Event bus
173
- ```
58
+ | Import | Mục đích |
59
+ |--------|----------|
60
+ | `@corelicense/node` | Core API |
61
+ | `@corelicense/node/express` | Express middleware |
62
+ | `@corelicense/node/fastify` | Fastify plugin |
63
+ | `@corelicense/node/nestjs` | NestJS module, guards, filter |
174
64
 
175
- ## Tài liệu thiết kế
65
+ ---
176
66
 
177
- Xem [CoreLicense Node.js SDK — Tài liệu thiết kế & tích hợp sâu](../../docs/CoreLicense_NodeJS_SDK_Deep_Integration.md).
67
+ ## Yêu cầu
178
68
 
179
- ## Roadmap
69
+ - Node.js **≥ 18**
70
+ - License Server reachable (hoặc cache + offline grace hợp lệ)
180
71
 
181
- - **v0.1** — Types, errors, boot, express middleware, file cache, local audit
182
- - **v0.2** — Auto-fetch public keys, key rotation retry, worker/CLI guard, offline grace
183
- - **v0.3** — Production default URL, activate flow, revoke handling, server contract sync
184
- - **v0.4** — Licensed module registry, DI container, Express routes, NestJS `@RequireFeature`
185
- - **v0.4.1** — Runtime re-check license trên `get()` / `resolve()`, fix `ModuleNotLicensedError` status
186
- - **v0.4.2** — Mã lỗi (`code`) + `source` trên mọi `LicenseError`, `LicenseErrorCode`, `formatLicenseError()`
187
- - **v0.4.3** — Re-check registry/DI không ghi audit; middleware 403 trả `source` qua `toClientPayload()`
188
- - **v0.5.0** — Fail-closed offline boot, quota/limit gates, apiUrl pin, Nest 403 filter, sync mutex
189
- - **v1.0** — Stable API, production-ready, security review
72
+ ---
190
73
 
191
- ## License
74
+ ## Changelog (tóm tắt)
192
75
 
193
- MIT
76
+ | Version | Highlights |
77
+ |---------|------------|
78
+ | **0.5.1** | Tách tài liệu (installation, integration, api-reference), sửa repository URL |
79
+ | **0.5.0** | Fail-closed offline boot, quota/limit gates, apiUrl pin, sync mutex, Nest 403 filter |
80
+ | **0.4.x** | Deep integration (registry/DI), error `code` + `source`, runtime re-check |
81
+ | **0.3.x** | Production default URL, activate/revoke sync |
82
+ | **0.2.x** | Auto-fetch public keys, worker/CLI guard |
83
+ | **0.1.x** | Boot, express middleware, file cache |
@@ -25,7 +25,7 @@ import { PolicySignatureError } from './errors/policy-error.js';
25
25
  import { throwForTerminalStatus } from './errors/throw-for-status.js';
26
26
  import { resolveApiUrl, parseEmbeddedApiUrl } from './env/resolve-api-url.js';
27
27
  const SDK_NAME = '@corelicense/node';
28
- const SDK_VERSION = '0.5.0';
28
+ const SDK_VERSION = '0.5.1';
29
29
  const DEFAULT_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000;
30
30
  function hashPolicyToken(token) {
31
31
  return createHash('sha256').update(token).digest('hex');
@@ -0,0 +1,210 @@
1
+ # API Reference
2
+
3
+ Public API `@corelicense/node` v0.5.1.
4
+
5
+ ---
6
+
7
+ ## CoreLicense
8
+
9
+ ### Constructor
10
+
11
+ ```ts
12
+ new CoreLicense(options: CoreLicenseOptions)
13
+ ```
14
+
15
+ ### Lifecycle
16
+
17
+ | Method | Returns | Mô tả |
18
+ |--------|---------|--------|
19
+ | `boot()` | `Promise<void>` | Khởi tạo, sync server, fail-closed |
20
+ | `refresh()` | `Promise<LicenseStatus>` | Force refresh policy |
21
+ | `startBackgroundCheck()` | `void` | Bật interval sync |
22
+ | `stopBackgroundCheck()` | `void` | Tắt interval |
23
+
24
+ ### License gates
25
+
26
+ | Method | Mô tả |
27
+ |--------|--------|
28
+ | `requireActive()` | Throw nếu không active |
29
+ | `requireFeature(feature)` | Throw + audit nếu feature off |
30
+ | `checkLimit(name, current)` | Throw nếu vượt limit |
31
+ | `consumeQuota(name, amount?)` | Tiêu thụ quota local |
32
+ | `getStatus()` | Trạng thái hiện tại |
33
+ | `getPolicy()` | Policy đã verify (null nếu chưa có) |
34
+ | `getRuntimeConfig()` | Config derived từ policy |
35
+
36
+ ### HTTP integrations
37
+
38
+ | Method | Mô tả |
39
+ |--------|--------|
40
+ | `express(options?)` | Express `RequestHandler` |
41
+ | `fastifyPlugin(options?)` | Fastify plugin |
42
+
43
+ ### Worker / CLI
44
+
45
+ | Method | Mô tả |
46
+ |--------|--------|
47
+ | `guardWorker(name)` | Guard worker process |
48
+ | `guardCommand(name)` | Guard CLI/cron command |
49
+
50
+ ### Deep integration
51
+
52
+ | Method | Mô tả |
53
+ |--------|--------|
54
+ | `bootstrap(options)` | Register modules + services |
55
+ | `createLicensedRegistry()` | `LicensedModuleRegistry` riêng |
56
+ | `createLicensedContainer()` | `LicensedServiceContainer` riêng |
57
+
58
+ ### Events
59
+
60
+ ```ts
61
+ license.on(event, handler)
62
+ license.off(event, handler)
63
+ ```
64
+
65
+ Events: `statusChanged` | `policyUpdated` | `licenseRevoked` | `licenseSuspended` | `offlineMode`
66
+
67
+ ---
68
+
69
+ ## LicensedModuleRegistry
70
+
71
+ | Method | Mô tả |
72
+ |--------|--------|
73
+ | `bootstrap(definitions, ctx)` | Register hàng loạt |
74
+ | `registerLicensed(def, ctx)` | Register một module |
75
+ | `has(name)` | Module đã bind? |
76
+ | `get<T>(name)` | Lấy module + re-check license |
77
+ | `list()` | Tên modules đã register |
78
+
79
+ ---
80
+
81
+ ## LicensedServiceContainer
82
+
83
+ | Method | Mô tả |
84
+ |--------|--------|
85
+ | `bootstrap(definitions, ctx)` | Bind services |
86
+ | `resolve<T>(name)` | Resolve + re-check license |
87
+ | `has(name)` | Service đã bind? |
88
+
89
+ ---
90
+
91
+ ## Helpers
92
+
93
+ ```ts
94
+ loadOptionsFromEnv(overrides?: Partial<CoreLicenseOptions>): CoreLicenseOptions
95
+ resolveApiUrl(options, cachedApiUrl?): string
96
+ parseEmbeddedApiUrl(licenseKey): string | null
97
+ registerLicensedRoutes(app, registry, routes): string[]
98
+ isLicenseError(error): boolean
99
+ formatLicenseError(error): string
100
+ isFeatureEnabled(policy, feature): boolean
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Subpath exports
106
+
107
+ ### `@corelicense/node/express`
108
+
109
+ ```ts
110
+ createExpressMiddleware(license, options?): RequestHandler
111
+ ```
112
+
113
+ ### `@corelicense/node/fastify`
114
+
115
+ ```ts
116
+ createFastifyPlugin(license, options?): FastifyPluginAsync
117
+ coreLicenseFastifyPlugin
118
+ ```
119
+
120
+ ### `@corelicense/node/nestjs`
121
+
122
+ ```ts
123
+ CoreLicenseModule.forRoot(options): DynamicModule
124
+ CoreLicenseGuard
125
+ CoreLicenseFeatureGuard
126
+ CoreLicenseExceptionFilter
127
+ RequireFeature(feature) // decorator
128
+ REQUIRE_FEATURE_KEY
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Types
134
+
135
+ ### `CoreLicenseOptions`
136
+
137
+ Xem [installation.md](./installation.md#4-corelicenseoptions-constructor).
138
+
139
+ ### `ExpressGuardOptions` / `FastifyGuardOptions`
140
+
141
+ ```ts
142
+ {
143
+ allowPaths?: string[];
144
+ mode?: 'block' | 'limited';
145
+ }
146
+ ```
147
+
148
+ ### `BootstrapResult`
149
+
150
+ ```ts
151
+ {
152
+ modules: LicensedModuleRegistry;
153
+ services: LicensedServiceContainer;
154
+ registeredModules: string[];
155
+ registeredServices: string[];
156
+ skipped: { name: string; feature: string; reason: 'feature_disabled' }[];
157
+ }
158
+ ```
159
+
160
+ ### `LicenseStatus`
161
+
162
+ ```ts
163
+ {
164
+ status: 'active' | 'suspended' | 'revoked' | 'expired' | 'invalid' | 'blocked';
165
+ policyVersion?: string;
166
+ expiresAt?: string;
167
+ // ...
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Error codes
174
+
175
+ Mọi `LicenseError` có `code`, `source`, `message`, `toClientPayload()`, `toJSON()`.
176
+
177
+ | Code | HTTP (middleware) |
178
+ |------|-------------------|
179
+ | `LICENSE_REVOKED` | 403 |
180
+ | `LICENSE_SUSPENDED` | 403 |
181
+ | `LICENSE_EXPIRED` | 403 |
182
+ | `LICENSE_INVALID` | 403 |
183
+ | `OFFLINE_GRACE_EXPIRED` | 403 |
184
+ | `FEATURE_DISABLED` | 403 |
185
+ | `MODULE_NOT_LICENSED` | 403 |
186
+ | `QUOTA_EXCEEDED` | 403 |
187
+ | `MAX_INSTANCES` | 403 |
188
+ | `INSTANCE_BLOCKED` | 403 |
189
+ | `CONFIG_MISSING_ENV` | — (boot fail) |
190
+ | `POLICY_SIGNATURE_ERROR` | — (boot fail) |
191
+ | `BOOT_NOT_CALLED` | — |
192
+ | `WORKER_NOT_ALLOWED` | — |
193
+ | `COMMAND_NOT_ALLOWED` | — |
194
+
195
+ Danh sách đầy đủ trong source: `src/errors/codes.ts`
196
+
197
+ ---
198
+
199
+ ## Client API (License Server)
200
+
201
+ SDK gọi các endpoint (không gọi trực tiếp từ app thường):
202
+
203
+ | Endpoint | Mô tả |
204
+ |----------|--------|
205
+ | `POST /v1/client/activate` | Lần đầu |
206
+ | `POST /v1/client/check` | Periodic check |
207
+ | `POST /v1/client/refresh` | Force refresh |
208
+ | `GET /v1/public/products/{id}/keys` | Public keys |
209
+
210
+ Chi tiết: [corelicense.net/docs/client-api](https://corelicense.net/docs/client-api)
@@ -0,0 +1,188 @@
1
+ # Cài đặt
2
+
3
+ Hướng dẫn cài package, cấu hình môi trường và chạy `boot()` lần đầu.
4
+
5
+ ---
6
+
7
+ ## 1. Cài package
8
+
9
+ ```bash
10
+ npm install @corelicense/node
11
+ ```
12
+
13
+ ### Peer dependencies (tùy framework)
14
+
15
+ Chỉ cài khi dùng integration tương ứng:
16
+
17
+ ```bash
18
+ npm install express # Express middleware
19
+ npm install fastify # Fastify plugin
20
+ npm install @nestjs/common @nestjs/core # NestJS
21
+ ```
22
+
23
+ SDK không bắt buộc peer deps — tree-shake an toàn nếu chỉ dùng `CoreLicense` trực tiếp.
24
+
25
+ ---
26
+
27
+ ## 2. Biến môi trường
28
+
29
+ ### Bắt buộc
30
+
31
+ | Biến | Mô tả |
32
+ |------|--------|
33
+ | `CORELICENSE_KEY` | License key do admin cấp (`CL-...` hoặc `CL1.<base64url-api>.CL-...`) |
34
+ | `CORELICENSE_PRODUCT_ID` | Product ID trên License Server |
35
+
36
+ ### Tùy chọn
37
+
38
+ | Biến | Mô tả | Mặc định |
39
+ |------|--------|----------|
40
+ | `CORELICENSE_API_URL` | Override URL License API | `https://api.corelicense.net` |
41
+ | `CORELICENSE_PUBLIC_KEY` | Pin public key (SPKI PEM) — bỏ qua fetch keys | auto-fetch |
42
+
43
+ **Thứ tự resolve API URL** (không cần set thủ công trên production):
44
+
45
+ 1. `options.apiUrl` / `CORELICENSE_API_URL`
46
+ 2. URL nhúng trong key `CL1.<base64url>.CL-...`
47
+ 3. Cache `sdk.endpoint.json`
48
+ 4. `https://api.corelicense.net`
49
+
50
+ ### Dev local
51
+
52
+ ```env
53
+ CORELICENSE_KEY=CL-AAAAA-BBBBB-CCCCC-DDDDD-EEEEE
54
+ CORELICENSE_PRODUCT_ID=demo
55
+ CORELICENSE_API_URL=http://localhost:8080
56
+ ```
57
+
58
+ ### Production
59
+
60
+ ```env
61
+ CORELICENSE_KEY=CL1.xxxxx.CL-AAAAA-BBBBB-...
62
+ CORELICENSE_PRODUCT_ID=my-product
63
+ # Không cần CORELICENSE_API_URL — SDK dùng api.corelicense.net
64
+ ```
65
+
66
+ Server Go production cần `SDK_PUBLIC_URL=https://api.corelicense.net` khi generate key `CL1.*`.
67
+
68
+ ---
69
+
70
+ ## 3. Khởi tạo tối thiểu
71
+
72
+ ```ts
73
+ import { CoreLicense, loadOptionsFromEnv } from '@corelicense/node';
74
+
75
+ const license = new CoreLicense(
76
+ loadOptionsFromEnv({
77
+ cachePath: './storage/corelicense',
78
+ instance: {
79
+ strategy: 'install-id-domain-hash',
80
+ domain: process.env.APP_DOMAIN, // ví dụ: app.example.com
81
+ },
82
+ audit: {
83
+ enabled: true,
84
+ path: './storage/logs/corelicense.log',
85
+ },
86
+ }),
87
+ );
88
+
89
+ await license.boot();
90
+ ```
91
+
92
+ `loadOptionsFromEnv()` throw `ConfigError` (`CONFIG_MISSING_ENV`) nếu thiếu biến bắt buộc.
93
+
94
+ ---
95
+
96
+ ## 4. `CoreLicenseOptions` (constructor)
97
+
98
+ | Field | Type | Mặc định | Mô tả |
99
+ |-------|------|----------|--------|
100
+ | `productId` | `string` | — | **Bắt buộc** |
101
+ | `licenseKey` | `string` | — | **Bắt buộc** |
102
+ | `apiUrl` | `string` | auto | License Server base URL |
103
+ | `publicKey` | `string` | — | Pin SPKI PEM |
104
+ | `cachePath` | `string` | `./storage/corelicense` | Thư mục cache |
105
+ | `checkIntervalMs` | `number` | `21600000` (6h) | Background refresh; `0` = tắt |
106
+ | `requestTimeoutMs` | `number` | `5000` | HTTP timeout |
107
+ | `offlineGrace` | `boolean` | `true` | Cho phép dùng cache khi server unreachable |
108
+ | `defaultBlockMode` | `'block' \| 'limited'` | `'limited'` | Middleware mode mặc định |
109
+ | `instance.strategy` | `'install-id-domain-hash' \| 'custom'` | `'install-id-domain-hash'` | Cách tính instance ID |
110
+ | `instance.domain` | `string` | — | Domain app (cho hash) |
111
+ | `instance.customId` | `string` | — | Khi `strategy: 'custom'` |
112
+ | `audit.enabled` | `boolean` | `true` | Ghi audit local |
113
+ | `audit.path` | `string` | `./storage/logs/corelicense.log` | File audit |
114
+ | `appVersion` | `string` | — | Gửi kèm SDK info lên server |
115
+
116
+ ---
117
+
118
+ ## 5. Luồng `boot()`
119
+
120
+ 1. Resolve API URL (pin / cache / env / default)
121
+ 2. Tính **instance ID** (install-id + domain hash)
122
+ 3. Fetch hoặc dùng **pinned public key**
123
+ 4. Load policy token từ cache → verify
124
+ 5. Nếu cần: `activate` (lần đầu) hoặc `check` (refresh)
125
+ 6. Bật background checker (nếu `checkIntervalMs > 0`)
126
+ 7. **`requireActive()`** — fail-closed nếu license không active
127
+
128
+ **Lưu ý v0.5:** Offline + grace hết hạn → `boot()` **throw**, không cho app chạy “im lặng”.
129
+
130
+ ---
131
+
132
+ ## 6. Pin public key (enterprise)
133
+
134
+ ```ts
135
+ const license = new CoreLicense(
136
+ loadOptionsFromEnv({
137
+ publicKey: process.env.CORELICENSE_PUBLIC_KEY,
138
+ }),
139
+ );
140
+ ```
141
+
142
+ Khi pin, SDK **không** gọi `GET /v1/public/products/{id}/keys`. Sau key rotation trên server, cập nhật `CORELICENSE_PUBLIC_KEY` và restart app.
143
+
144
+ ---
145
+
146
+ ## 7. File trên disk
147
+
148
+ ```
149
+ storage/corelicense/
150
+ instance.json # instanceId đã resolve
151
+ policy.token # JWT policy (signed)
152
+ usage.json # quota usage theo ngày
153
+ sdk.endpoint.json # apiUrl tin cậy từ server
154
+
155
+ storage/logs/
156
+ corelicense.log # audit events (JSON lines)
157
+ ```
158
+
159
+ Thêm `storage/` vào `.gitignore` của app khách.
160
+
161
+ ---
162
+
163
+ ## 8. Kiểm tra sau cài
164
+
165
+ ```ts
166
+ const status = await license.getStatus();
167
+ console.log(status); // { status: 'active', ... }
168
+
169
+ const policy = await license.getPolicy();
170
+ console.log(policy?.features);
171
+ ```
172
+
173
+ HTTP health route (không qua license guard):
174
+
175
+ ```ts
176
+ app.get('/health', (_req, res) => res.json({ ok: true }));
177
+ app.get('/license/status', async (_req, res) => {
178
+ res.json(await license.getStatus());
179
+ });
180
+ ```
181
+
182
+ ---
183
+
184
+ ## 9. Bước tiếp theo
185
+
186
+ → [Tích hợp chi tiết](./integration.md) — Express, NestJS, module registry, DI, worker, production checklist.
187
+
188
+ → [API Reference](./api-reference.md) — danh sách method và error codes.