@corelicense/node 0.2.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.
Files changed (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -98
  3. package/dist/client/license-api-client.d.ts +3 -2
  4. package/dist/client/license-api-client.d.ts.map +1 -1
  5. package/dist/client/license-api-client.js +44 -4
  6. package/dist/client/license-api-client.js.map +1 -1
  7. package/dist/client/map-client-error.d.ts +5 -0
  8. package/dist/client/map-client-error.d.ts.map +1 -0
  9. package/dist/client/map-client-error.js +63 -0
  10. package/dist/client/map-client-error.js.map +1 -0
  11. package/dist/client/public-keys-client.d.ts.map +1 -1
  12. package/dist/client/public-keys-client.js +20 -2
  13. package/dist/client/public-keys-client.js.map +1 -1
  14. package/dist/core-license.d.ts +19 -1
  15. package/dist/core-license.d.ts.map +1 -1
  16. package/dist/core-license.js +195 -51
  17. package/dist/core-license.js.map +1 -1
  18. package/dist/crypto/verify-policy-token.d.ts.map +1 -1
  19. package/dist/crypto/verify-policy-token.js +75 -5
  20. package/dist/crypto/verify-policy-token.js.map +1 -1
  21. package/dist/env/load-options-from-env.d.ts.map +1 -1
  22. package/dist/env/load-options-from-env.js +2 -1
  23. package/dist/env/load-options-from-env.js.map +1 -1
  24. package/dist/env/resolve-api-url.js +1 -1
  25. package/dist/env/resolve-api-url.js.map +1 -1
  26. package/dist/errors/api-error.d.ts +17 -0
  27. package/dist/errors/api-error.d.ts.map +1 -0
  28. package/dist/errors/api-error.js +43 -0
  29. package/dist/errors/api-error.js.map +1 -0
  30. package/dist/errors/codes.d.ts +40 -0
  31. package/dist/errors/codes.d.ts.map +1 -0
  32. package/dist/errors/codes.js +39 -0
  33. package/dist/errors/codes.js.map +1 -0
  34. package/dist/errors/config-error.d.ts +7 -0
  35. package/dist/errors/config-error.d.ts.map +1 -0
  36. package/dist/errors/config-error.js +21 -0
  37. package/dist/errors/config-error.js.map +1 -0
  38. package/dist/errors/feature-error.d.ts +2 -1
  39. package/dist/errors/feature-error.d.ts.map +1 -1
  40. package/dist/errors/feature-error.js +13 -2
  41. package/dist/errors/feature-error.js.map +1 -1
  42. package/dist/errors/index.d.ts +6 -0
  43. package/dist/errors/index.d.ts.map +1 -1
  44. package/dist/errors/index.js +6 -0
  45. package/dist/errors/index.js.map +1 -1
  46. package/dist/errors/license-error.d.ts +48 -7
  47. package/dist/errors/license-error.d.ts.map +1 -1
  48. package/dist/errors/license-error.js +104 -14
  49. package/dist/errors/license-error.js.map +1 -1
  50. package/dist/errors/module-error.d.ts +7 -0
  51. package/dist/errors/module-error.d.ts.map +1 -0
  52. package/dist/errors/module-error.js +20 -0
  53. package/dist/errors/module-error.js.map +1 -0
  54. package/dist/errors/policy-error.d.ts +10 -1
  55. package/dist/errors/policy-error.d.ts.map +1 -1
  56. package/dist/errors/policy-error.js +16 -2
  57. package/dist/errors/policy-error.js.map +1 -1
  58. package/dist/errors/quota-error.d.ts +2 -1
  59. package/dist/errors/quota-error.d.ts.map +1 -1
  60. package/dist/errors/quota-error.js +15 -2
  61. package/dist/errors/quota-error.js.map +1 -1
  62. package/dist/errors/runtime-error.d.ts +12 -0
  63. package/dist/errors/runtime-error.d.ts.map +1 -0
  64. package/dist/errors/runtime-error.js +37 -0
  65. package/dist/errors/runtime-error.js.map +1 -0
  66. package/dist/errors/throw-for-status.d.ts +3 -0
  67. package/dist/errors/throw-for-status.d.ts.map +1 -0
  68. package/dist/errors/throw-for-status.js +21 -0
  69. package/dist/errors/throw-for-status.js.map +1 -0
  70. package/dist/guards/cli-guard.d.ts.map +1 -1
  71. package/dist/guards/cli-guard.js +12 -6
  72. package/dist/guards/cli-guard.js.map +1 -1
  73. package/dist/guards/express-middleware.d.ts.map +1 -1
  74. package/dist/guards/express-middleware.js +1 -5
  75. package/dist/guards/express-middleware.js.map +1 -1
  76. package/dist/guards/express-routes.d.ts +9 -0
  77. package/dist/guards/express-routes.d.ts.map +1 -0
  78. package/dist/guards/express-routes.js +12 -0
  79. package/dist/guards/express-routes.js.map +1 -0
  80. package/dist/guards/fastify-plugin.d.ts.map +1 -1
  81. package/dist/guards/fastify-plugin.js +1 -5
  82. package/dist/guards/fastify-plugin.js.map +1 -1
  83. package/dist/guards/feature-guard.d.ts +1 -0
  84. package/dist/guards/feature-guard.d.ts.map +1 -1
  85. package/dist/guards/feature-guard.js +14 -0
  86. package/dist/guards/feature-guard.js.map +1 -1
  87. package/dist/guards/nest-exception-filter.d.ts +6 -0
  88. package/dist/guards/nest-exception-filter.d.ts.map +1 -0
  89. package/dist/guards/nest-exception-filter.js +60 -0
  90. package/dist/guards/nest-exception-filter.js.map +1 -0
  91. package/dist/guards/nest-feature-guard.d.ts +10 -0
  92. package/dist/guards/nest-feature-guard.d.ts.map +1 -0
  93. package/dist/guards/nest-feature-guard.js +72 -0
  94. package/dist/guards/nest-feature-guard.js.map +1 -0
  95. package/dist/guards/nest-module.d.ts +3 -0
  96. package/dist/guards/nest-module.d.ts.map +1 -1
  97. package/dist/guards/nest-module.js +13 -2
  98. package/dist/guards/nest-module.js.map +1 -1
  99. package/dist/guards/nestjs.d.ts +6 -0
  100. package/dist/guards/nestjs.d.ts.map +1 -0
  101. package/dist/guards/nestjs.js +6 -0
  102. package/dist/guards/nestjs.js.map +1 -0
  103. package/dist/guards/quota-guard.d.ts.map +1 -1
  104. package/dist/guards/quota-guard.js +6 -1
  105. package/dist/guards/quota-guard.js.map +1 -1
  106. package/dist/guards/require-feature.decorator.d.ts +3 -0
  107. package/dist/guards/require-feature.decorator.d.ts.map +1 -0
  108. package/dist/guards/require-feature.decorator.js +4 -0
  109. package/dist/guards/require-feature.decorator.js.map +1 -0
  110. package/dist/guards/worker-guard.d.ts.map +1 -1
  111. package/dist/guards/worker-guard.js +8 -6
  112. package/dist/guards/worker-guard.js.map +1 -1
  113. package/dist/index.d.ts +6 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +5 -0
  116. package/dist/index.js.map +1 -1
  117. package/dist/instance/domain-hash.d.ts +3 -0
  118. package/dist/instance/domain-hash.d.ts.map +1 -0
  119. package/dist/instance/domain-hash.js +11 -0
  120. package/dist/instance/domain-hash.js.map +1 -0
  121. package/dist/instance/instance-id.d.ts.map +1 -1
  122. package/dist/instance/instance-id.js +1 -6
  123. package/dist/instance/instance-id.js.map +1 -1
  124. package/dist/runtime/licensed-module-registry.d.ts +22 -0
  125. package/dist/runtime/licensed-module-registry.d.ts.map +1 -0
  126. package/dist/runtime/licensed-module-registry.js +80 -0
  127. package/dist/runtime/licensed-module-registry.js.map +1 -0
  128. package/dist/runtime/licensed-service-container.d.ts +23 -0
  129. package/dist/runtime/licensed-service-container.d.ts.map +1 -0
  130. package/dist/runtime/licensed-service-container.js +89 -0
  131. package/dist/runtime/licensed-service-container.js.map +1 -0
  132. package/dist/runtime/licensed-service.d.ts +7 -0
  133. package/dist/runtime/licensed-service.d.ts.map +1 -0
  134. package/dist/runtime/licensed-service.js +10 -0
  135. package/dist/runtime/licensed-service.js.map +1 -0
  136. package/dist/runtime/module-registry.d.ts.map +1 -1
  137. package/dist/runtime/module-registry.js +2 -1
  138. package/dist/runtime/module-registry.js.map +1 -1
  139. package/dist/runtime/service-container.d.ts.map +1 -1
  140. package/dist/runtime/service-container.js +2 -1
  141. package/dist/runtime/service-container.js.map +1 -1
  142. package/dist/types/bootstrap.d.ts +32 -0
  143. package/dist/types/bootstrap.d.ts.map +1 -0
  144. package/dist/types/bootstrap.js +2 -0
  145. package/dist/types/bootstrap.js.map +1 -0
  146. package/dist/types/index.d.ts +1 -0
  147. package/dist/types/index.d.ts.map +1 -1
  148. package/dist/types/index.js +1 -0
  149. package/dist/types/index.js.map +1 -1
  150. package/dist/types/options.d.ts +14 -3
  151. package/dist/types/options.d.ts.map +1 -1
  152. package/dist/types/policy.d.ts +2 -0
  153. package/dist/types/policy.d.ts.map +1 -1
  154. package/docs/api-reference.md +210 -0
  155. package/docs/installation.md +188 -0
  156. package/docs/integration.md +789 -0
  157. package/package.json +23 -6
@@ -15,6 +15,7 @@ export interface PolicyTokenPayload {
15
15
  licenseId: string;
16
16
  productId: string;
17
17
  customerId?: string;
18
+ applicationId?: string;
18
19
  instanceId: string;
19
20
  status: LicenseStatusValue;
20
21
  features: PolicyFeatures;
@@ -28,6 +29,7 @@ export interface Policy {
28
29
  licenseId: string;
29
30
  productId: string;
30
31
  customerId?: string;
32
+ applicationId?: string;
31
33
  instanceId: string;
32
34
  status: LicenseStatusValue;
33
35
  features: PolicyFeatures;
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/types/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/types/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -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.