@operaris/license-sdk 1.0.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 ADDED
@@ -0,0 +1,138 @@
1
+ # @operaris/license-sdk
2
+
3
+ SDK para validação de licenças do Operaris no ERP/PDV.
4
+
5
+ ## Instalação
6
+
7
+ ```bash
8
+ npm install @operaris/license-sdk
9
+ ```
10
+
11
+ ## Uso rápido
12
+
13
+ ```typescript
14
+ import { LicenseClient } from '@operaris/license-sdk'
15
+
16
+ const client = new LicenseClient({
17
+ apiUrl: 'https://api.operaris.com.br',
18
+ apiKey: process.env.OPERARIS_API_KEY!,
19
+ licenseKey: process.env.OPERARIS_LICENSE_KEY!,
20
+ })
21
+
22
+ // Na inicialização do ERP — lança erro se licença inválida
23
+ const license = await client.validateOrThrow({
24
+ fingerprint: getMachineFingerprint(),
25
+ hostname: os.hostname(),
26
+ os: process.platform,
27
+ })
28
+
29
+ console.log('Licença válida até:', license.validUntil)
30
+ console.log('Máx. dispositivos:', license.maxDevices)
31
+ ```
32
+
33
+ ## Configuração
34
+
35
+ | Opção | Tipo | Padrão | Descrição |
36
+ |---------------|----------|----------|--------------------------------------------------------|
37
+ | `apiUrl` | `string` | — | URL base da API Operaris (obrigatório) |
38
+ | `apiKey` | `string` | — | Chave de API fornecida pela Operaris (obrigatório) |
39
+ | `licenseKey` | `string` | — | Chave da licença do estabelecimento (obrigatório) |
40
+ | `cacheTtlMs` | `number` | `300000` | TTL do cache em ms (padrão: 5 minutos) |
41
+ | `timeoutMs` | `number` | `10000` | Timeout da requisição em ms (padrão: 10 segundos) |
42
+ | `retries` | `number` | `2` | Tentativas em falha de rede (não retenta em 4xx/5xx) |
43
+
44
+ ## Métodos
45
+
46
+ ### `validate(input): Promise<ValidateResult>`
47
+
48
+ Valida a licença. Retorna o resultado do cache se ainda válido (dentro do TTL).
49
+ Em falha de rede, retorna o último cache como **fallback offline** (mesmo que expirado).
50
+
51
+ ```typescript
52
+ const result = await client.validate({ fingerprint: '...', hostname: '...', os: '...' })
53
+
54
+ if (result.valid) {
55
+ // result.status — 'ACTIVE' | 'GRACE'
56
+ // result.validUntil — Date
57
+ // result.graceDaysRemaining — number | undefined
58
+ // result.maxDevices — number
59
+ // result.features — Record<string, unknown>
60
+ // result.establishment — { id, name, city, state }
61
+ // result.fromCache — boolean
62
+ // result.offlineFallback — boolean (true = API inacessível, usando cache antigo)
63
+ } else {
64
+ // result.reason — motivo da rejeição
65
+ }
66
+ ```
67
+
68
+ **Valores possíveis de `reason`:**
69
+
70
+ | Valor | Descrição |
71
+ |--------------------------|----------------------------------------------------|
72
+ | `LICENSE_NOT_FOUND` | Licença não existe |
73
+ | `LICENSE_EXPIRED` | Licença expirada (além do período de carência) |
74
+ | `LICENSE_CANCELLED` | Licença cancelada |
75
+ | `LICENSE_REVOKED` | Licença revogada |
76
+ | `DEVICE_NOT_REGISTERED` | Fingerprint não registrado nesta licença |
77
+ | `MAX_DEVICES_REACHED` | Limite de dispositivos atingido |
78
+ | `DEVICE_INACTIVE` | Dispositivo desativado manualmente |
79
+ | `API_UNREACHABLE` | API inacessível e sem cache disponível |
80
+
81
+ ### `validateOrThrow(input): Promise<ValidateSuccess>`
82
+
83
+ Igual ao `validate`, mas **lança erro** se a licença for inválida.
84
+ Ideal para bloquear a inicialização do ERP.
85
+
86
+ ```typescript
87
+ try {
88
+ const license = await client.validateOrThrow({ fingerprint, hostname, os })
89
+ // prossegue normalmente
90
+ } catch (err) {
91
+ if (err instanceof LicenseValidationError) {
92
+ console.error('Licença inválida:', err.reason)
93
+ process.exit(1)
94
+ }
95
+ if (err instanceof LicenseApiUnreachableError) {
96
+ console.error('API inacessível e sem cache — verifique a conexão')
97
+ process.exit(1)
98
+ }
99
+ }
100
+ ```
101
+
102
+ ### `clearCache(): void`
103
+
104
+ Invalida o cache local, forçando nova consulta na próxima chamada.
105
+
106
+ ## Comportamento offline
107
+
108
+ O SDK mantém um cache em memória do último resultado válido. Em caso de falha de rede:
109
+
110
+ - Se houver cache (mesmo expirado) → retorna o cache com `offlineFallback: true`
111
+ - Se não houver cache → retorna `{ valid: false, reason: 'API_UNREACHABLE' }`
112
+
113
+ Isso garante que o ERP continue funcionando por um período durante instabilidades de rede.
114
+
115
+ ## Erros
116
+
117
+ ```typescript
118
+ import { LicenseValidationError, LicenseApiUnreachableError } from '@operaris/license-sdk'
119
+
120
+ // LicenseValidationError
121
+ err.reason // string — motivo da rejeição
122
+ err.message // string — mensagem legível
123
+
124
+ // LicenseApiUnreachableError
125
+ err.message // 'License API is unreachable and no cache is available'
126
+ ```
127
+
128
+ ## Build
129
+
130
+ ```bash
131
+ npm run build # compila para dist/
132
+ npm run dev # watch mode
133
+ ```
134
+
135
+ ## Requisitos
136
+
137
+ - Node.js >= 20
138
+ - `fetch` nativo (disponível a partir do Node 18)
@@ -0,0 +1,27 @@
1
+ import { LicenseClientConfig, ValidateInput, ValidateResult, ValidateSuccess } from './types';
2
+ export declare class LicenseClient {
3
+ private readonly apiUrl;
4
+ private readonly apiKey;
5
+ private readonly licenseKey;
6
+ private readonly cacheTtlMs;
7
+ private readonly timeoutMs;
8
+ private readonly retries;
9
+ private cache;
10
+ constructor(config: LicenseClientConfig);
11
+ /**
12
+ * Valida a licença do dispositivo.
13
+ * Retorna resultado do cache se ainda válido.
14
+ * Em falha de rede, retorna o último cache como fallback offline.
15
+ */
16
+ validate(input: ValidateInput): Promise<ValidateResult>;
17
+ /**
18
+ * Valida a licença e lança erro se inválida.
19
+ * Útil para bloquear a inicialização do ERP.
20
+ */
21
+ validateOrThrow(input: ValidateInput): Promise<ValidateSuccess>;
22
+ /** Invalida o cache forçando nova consulta na próxima chamada. */
23
+ clearCache(): void;
24
+ private fetchWithRetry;
25
+ private fetchValidate;
26
+ }
27
+ //# sourceMappingURL=LicenseClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LicenseClient.d.ts","sourceRoot":"","sources":["../src/LicenseClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,SAAS,CAAA;AAQhB,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAEhC,OAAO,CAAC,KAAK,CAA0B;gBAE3B,MAAM,EAAE,mBAAmB;IASvC;;;;OAIG;IACG,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAqD7D;;;OAGG;IACG,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC;IAarE,kEAAkE;IAClE,UAAU,IAAI,IAAI;YAIJ,cAAc;YAgBd,aAAa;CA6B5B"}
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LicenseClient = void 0;
4
+ const errors_1 = require("./errors");
5
+ class LicenseClient {
6
+ apiUrl;
7
+ apiKey;
8
+ licenseKey;
9
+ cacheTtlMs;
10
+ timeoutMs;
11
+ retries;
12
+ cache = null;
13
+ constructor(config) {
14
+ this.apiUrl = config.apiUrl.replace(/\/$/, '');
15
+ this.apiKey = config.apiKey;
16
+ this.licenseKey = config.licenseKey;
17
+ this.cacheTtlMs = config.cacheTtlMs ?? 300_000;
18
+ this.timeoutMs = config.timeoutMs ?? 10_000;
19
+ this.retries = config.retries ?? 2;
20
+ }
21
+ /**
22
+ * Valida a licença do dispositivo.
23
+ * Retorna resultado do cache se ainda válido.
24
+ * Em falha de rede, retorna o último cache como fallback offline.
25
+ */
26
+ async validate(input) {
27
+ // Cache hit dentro do TTL
28
+ if (this.cache && Date.now() - this.cache.cachedAt < this.cacheTtlMs) {
29
+ return { ...this.cache.result, fromCache: true, offlineFallback: false };
30
+ }
31
+ try {
32
+ const raw = await this.fetchWithRetry(input);
33
+ if (raw.valid) {
34
+ const result = {
35
+ valid: true,
36
+ status: raw.status,
37
+ licenseKey: raw.licenseKey,
38
+ validUntil: new Date(raw.validUntil),
39
+ graceDaysRemaining: raw.graceDaysRemaining,
40
+ maxDevices: raw.maxDevices,
41
+ features: raw.features,
42
+ establishment: raw.establishment,
43
+ fromCache: false,
44
+ offlineFallback: false,
45
+ };
46
+ this.cache = { result, cachedAt: Date.now() };
47
+ return result;
48
+ }
49
+ // Resposta inválida da API — limpa o cache para não retornar stale
50
+ this.cache = null;
51
+ return {
52
+ valid: false,
53
+ reason: raw.reason,
54
+ fromCache: false,
55
+ offlineFallback: false,
56
+ };
57
+ }
58
+ catch (err) {
59
+ // Fallback offline: API inacessível mas temos cache (mesmo expirado)
60
+ if (this.cache) {
61
+ return {
62
+ ...this.cache.result,
63
+ fromCache: true,
64
+ offlineFallback: true,
65
+ };
66
+ }
67
+ return {
68
+ valid: false,
69
+ reason: 'API_UNREACHABLE',
70
+ fromCache: false,
71
+ offlineFallback: false,
72
+ };
73
+ }
74
+ }
75
+ /**
76
+ * Valida a licença e lança erro se inválida.
77
+ * Útil para bloquear a inicialização do ERP.
78
+ */
79
+ async validateOrThrow(input) {
80
+ const result = await this.validate(input);
81
+ if (!result.valid) {
82
+ if (result.reason === 'API_UNREACHABLE') {
83
+ throw new errors_1.LicenseApiUnreachableError();
84
+ }
85
+ throw new errors_1.LicenseValidationError(result.reason);
86
+ }
87
+ return result;
88
+ }
89
+ /** Invalida o cache forçando nova consulta na próxima chamada. */
90
+ clearCache() {
91
+ this.cache = null;
92
+ }
93
+ async fetchWithRetry(input) {
94
+ let lastError;
95
+ for (let attempt = 0; attempt <= this.retries; attempt++) {
96
+ try {
97
+ return await this.fetchValidate(input);
98
+ }
99
+ catch (err) {
100
+ lastError = err;
101
+ // Não retenta em erros de resposta (4xx/5xx) — só em falhas de rede
102
+ if (err instanceof ApiResponseError)
103
+ throw err;
104
+ }
105
+ }
106
+ throw lastError;
107
+ }
108
+ async fetchValidate(input) {
109
+ const controller = new AbortController();
110
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
111
+ try {
112
+ const response = await fetch(`${this.apiUrl}/api/validate`, {
113
+ method: 'POST',
114
+ headers: {
115
+ 'Content-Type': 'application/json',
116
+ 'x-api-key': this.apiKey,
117
+ },
118
+ body: JSON.stringify({
119
+ licenseKey: this.licenseKey,
120
+ fingerprint: input.fingerprint,
121
+ hostname: input.hostname,
122
+ os: input.os,
123
+ }),
124
+ signal: controller.signal,
125
+ });
126
+ if (!response.ok && response.status !== 403) {
127
+ throw new ApiResponseError(response.status);
128
+ }
129
+ return response.json();
130
+ }
131
+ finally {
132
+ clearTimeout(timer);
133
+ }
134
+ }
135
+ }
136
+ exports.LicenseClient = LicenseClient;
137
+ class ApiResponseError extends Error {
138
+ status;
139
+ constructor(status) {
140
+ super(`API responded with status ${status}`);
141
+ this.status = status;
142
+ }
143
+ }
144
+ //# sourceMappingURL=LicenseClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LicenseClient.js","sourceRoot":"","sources":["../src/LicenseClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare class LicenseValidationError extends Error {
2
+ readonly reason: string;
3
+ constructor(reason: string, message?: string);
4
+ }
5
+ export declare class LicenseApiUnreachableError extends Error {
6
+ constructor(cause?: unknown);
7
+ }
8
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAC9B,OAAO,CAAC,EAAE,MAAM;CAKnB;AAED,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,KAAK,CAAC,EAAE,OAAO;CAK5B"}
package/dist/errors.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LicenseApiUnreachableError = exports.LicenseValidationError = void 0;
4
+ class LicenseValidationError extends Error {
5
+ reason;
6
+ constructor(reason, message) {
7
+ super(message ?? `License validation failed: ${reason}`);
8
+ this.reason = reason;
9
+ this.name = 'LicenseValidationError';
10
+ }
11
+ }
12
+ exports.LicenseValidationError = LicenseValidationError;
13
+ class LicenseApiUnreachableError extends Error {
14
+ constructor(cause) {
15
+ super('License API is unreachable');
16
+ this.name = 'LicenseApiUnreachableError';
17
+ if (cause)
18
+ this.cause = cause;
19
+ }
20
+ }
21
+ exports.LicenseApiUnreachableError = LicenseApiUnreachableError;
22
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,sBAAuB,SAAQ,KAAK;IAE7B;IADlB,YACkB,MAAc,EAC9B,OAAgB;QAEhB,KAAK,CAAC,OAAO,IAAI,8BAA8B,MAAM,EAAE,CAAC,CAAA;QAHxC,WAAM,GAAN,MAAM,CAAQ;QAI9B,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAA;IACtC,CAAC;CACF;AARD,wDAQC;AAED,MAAa,0BAA2B,SAAQ,KAAK;IACnD,YAAY,KAAe;QACzB,KAAK,CAAC,4BAA4B,CAAC,CAAA;QACnC,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAA;QACxC,IAAI,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IAC/B,CAAC;CACF;AAND,gEAMC"}
@@ -0,0 +1,4 @@
1
+ export { LicenseClient } from './LicenseClient';
2
+ export { LicenseValidationError, LicenseApiUnreachableError } from './errors';
3
+ export type { LicenseClientConfig, ValidateInput, ValidateResult, ValidateSuccess, ValidateFailure, } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAA;AAC7E,YAAY,EACV,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LicenseApiUnreachableError = exports.LicenseValidationError = exports.LicenseClient = void 0;
4
+ var LicenseClient_1 = require("./LicenseClient");
5
+ Object.defineProperty(exports, "LicenseClient", { enumerable: true, get: function () { return LicenseClient_1.LicenseClient; } });
6
+ var errors_1 = require("./errors");
7
+ Object.defineProperty(exports, "LicenseValidationError", { enumerable: true, get: function () { return errors_1.LicenseValidationError; } });
8
+ Object.defineProperty(exports, "LicenseApiUnreachableError", { enumerable: true, get: function () { return errors_1.LicenseApiUnreachableError; } });
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,iDAA+C;AAAtC,8GAAA,aAAa,OAAA;AACtB,mCAA6E;AAApE,gHAAA,sBAAsB,OAAA;AAAE,oHAAA,0BAA0B,OAAA"}
@@ -0,0 +1,57 @@
1
+ export interface LicenseClientConfig {
2
+ /** URL base da API SaaS. Ex: https://saas.operaris.com.br */
3
+ apiUrl: string;
4
+ /** Chave de API do ERP (x-api-key) */
5
+ apiKey: string;
6
+ /** UUID da licença do estabelecimento */
7
+ licenseKey: string;
8
+ /**
9
+ * TTL do cache de validação em ms.
10
+ * Durante o TTL, o SDK retorna o resultado em memória sem bater na API.
11
+ * @default 300_000 (5 minutos)
12
+ */
13
+ cacheTtlMs?: number;
14
+ /**
15
+ * Timeout de cada requisição em ms.
16
+ * @default 10_000 (10 segundos)
17
+ */
18
+ timeoutMs?: number;
19
+ /**
20
+ * Número de retentativas em caso de falha de rede.
21
+ * @default 2
22
+ */
23
+ retries?: number;
24
+ }
25
+ export interface ValidateInput {
26
+ /** Identificador único e estável do dispositivo (hash de hardware, MAC, etc.) */
27
+ fingerprint: string;
28
+ /** Nome da máquina (opcional, para exibição no painel) */
29
+ hostname?: string;
30
+ /** Sistema operacional (opcional, para exibição no painel) */
31
+ os?: string;
32
+ }
33
+ export interface ValidateSuccess {
34
+ valid: true;
35
+ status: 'ACTIVE' | 'GRACE';
36
+ licenseKey: string;
37
+ validUntil: Date;
38
+ graceDaysRemaining: number;
39
+ maxDevices: number;
40
+ features: Record<string, unknown>;
41
+ establishment: {
42
+ id: string;
43
+ name: string;
44
+ };
45
+ /** true quando o resultado veio do cache local */
46
+ fromCache: boolean;
47
+ /** true quando a API estava inacessível e foi usado o último cache válido */
48
+ offlineFallback: boolean;
49
+ }
50
+ export interface ValidateFailure {
51
+ valid: false;
52
+ reason: 'LICENSE_NOT_FOUND' | 'LICENSE_REVOKED' | 'LICENSE_SUSPENDED' | 'LICENSE_EXPIRED' | 'DEVICE_DEACTIVATED' | 'DEVICE_LIMIT_REACHED' | 'API_UNREACHABLE';
53
+ offlineFallback: false;
54
+ fromCache: false;
55
+ }
56
+ export type ValidateResult = ValidateSuccess | ValidateFailure;
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAA;IACd,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAA;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8DAA8D;IAC9D,EAAE,CAAC,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,IAAI,CAAA;IACX,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,IAAI,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,aAAa,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C,kDAAkD;IAClD,SAAS,EAAE,OAAO,CAAA;IAClB,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EACF,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,GACnB,iBAAiB,GACjB,oBAAoB,GACpB,sBAAsB,GACtB,iBAAiB,CAAA;IACrB,eAAe,EAAE,KAAK,CAAA;IACtB,SAAS,EAAE,KAAK,CAAA;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,eAAe,CAAA"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@operaris/license-sdk",
3
+ "version": "1.0.0",
4
+ "description": "SDK para validação de licenças do ERP Operaris",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": ["dist"],
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "dev": "tsc --watch"
11
+ },
12
+ "devDependencies": {
13
+ "typescript": "^5.4.0"
14
+ },
15
+ "engines": {
16
+ "node": ">=20"
17
+ }
18
+ }