emilsoftware-utilities 2.0.0-dev.70 → 2.0.0-dev.72
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 +30 -0
- package/dist/accessi/client/admin/index.d.ts +18 -0
- package/dist/accessi/client/admin/index.js +58 -0
- package/dist/accessi/client/admin/index.js.map +1 -0
- package/dist/accessi/client/createAccessiClient.d.ts +21 -0
- package/dist/accessi/client/createAccessiClient.js +31 -0
- package/dist/accessi/client/createAccessiClient.js.map +1 -0
- package/dist/accessi/client/generated/admin.d.ts +601 -0
- package/dist/accessi/client/generated/admin.js +557 -0
- package/dist/accessi/client/generated/admin.js.map +1 -0
- package/dist/accessi/client/generated/public.d.ts +121 -0
- package/dist/accessi/client/generated/public.js +119 -0
- package/dist/accessi/client/generated/public.js.map +1 -0
- package/dist/accessi/client/generated/service.d.ts +53 -0
- package/dist/accessi/client/generated/service.js +63 -0
- package/dist/accessi/client/generated/service.js.map +1 -0
- package/dist/accessi/client/index.d.ts +29 -11
- package/dist/accessi/client/index.js +52 -2
- package/dist/accessi/client/index.js.map +1 -1
- package/dist/accessi/client/public/index.d.ts +18 -0
- package/dist/accessi/client/public/index.js +58 -0
- package/dist/accessi/client/public/index.js.map +1 -0
- package/dist/accessi/client/service/index.d.ts +17 -0
- package/dist/accessi/client/service/index.js +57 -0
- package/dist/accessi/client/service/index.js.map +1 -0
- package/dist/accessi-module/Console/accessiFetch.d.ts +27 -0
- package/dist/accessi-module/Console/accessiFetch.js +41 -5
- package/dist/accessi-module/Console/accessiFetch.js.map +1 -1
- package/dist/accessi-module/Console/console.js +14 -3
- package/dist/accessi-module/Console/wiki.js +10 -1
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/AccessiIntrospectionController.js +1 -1
- package/dist/accessi-module/Controllers/AccessiIntrospectionController.js.map +1 -1
- package/dist/accessi-module/security/accessTokenRevocation.js +5 -2
- package/dist/accessi-module/security/accessTokenRevocation.js.map +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.72.tgz +0 -0
- package/integration-prompt.md +6 -2
- package/package.json +23 -4
- package/dist/emilsoftware-utilities-2.0.0-dev.70.tgz +0 -0
package/README.MD
CHANGED
|
@@ -82,6 +82,7 @@ temi light/dark e i token Bootstrap 5.3.
|
|
|
82
82
|
| `npm run test:coverage` | Test unitari con report e **soglie minime** di copertura |
|
|
83
83
|
| `npm run test:integration` | Integration test su Firebird reale (default: porta 3055) |
|
|
84
84
|
| `npm run test:integration:fb5` / `:fb3` / `:fb25` | Integration test su Firebird 5 / 3 / 2.5 |
|
|
85
|
+
| `npm run test:integration:redis` | Integration test degli store Redis (opt-in, salta senza `ACCESSI_TEST_REDIS_URL`) |
|
|
85
86
|
| `npm run test:accessi-console` | Test end-to-end della console (richiede un browser Chromium e la build) |
|
|
86
87
|
|
|
87
88
|
### Integration test su Firebird reale
|
|
@@ -115,6 +116,33 @@ La CI (`.github/workflows/ci.yml`) esegue typecheck, test con coverage e build,
|
|
|
115
116
|
integration test in matrice su Firebird 5 e 3. Il workflow di release (`publish.yml`) esegue
|
|
116
117
|
typecheck e test prima di build e pubblicazione.
|
|
117
118
|
|
|
119
|
+
### Integration test su Redis reale
|
|
120
|
+
|
|
121
|
+
Gli store condivisi (rate limit, ticket console, revoca sessioni, revoca `jti`, rotazione refresh
|
|
122
|
+
token) hanno adapter Redis che nei test unitari girano su fake in memoria. La suite di integrazione
|
|
123
|
+
li verifica contro un Redis reale, inclusi i `consume` atomici in concorrenza e gli `healthCheck()`.
|
|
124
|
+
|
|
125
|
+
E' **opt-in**: senza la variabile `ACCESSI_TEST_REDIS_URL` i test vengono marcati come `skip`.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
docker run --rm -d --name accessi-test-redis -p 6380:6379 redis:7-alpine
|
|
129
|
+
npm run test:integration:redis
|
|
130
|
+
docker stop accessi-test-redis
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Su PowerShell:
|
|
134
|
+
|
|
135
|
+
```powershell
|
|
136
|
+
$env:ACCESSI_TEST_REDIS_URL = 'redis://127.0.0.1:6380'
|
|
137
|
+
npm run test:integration:redis
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Variabili: `ACCESSI_TEST_REDIS_URL` (formato `redis://[:password@]host:port[/db]`) e
|
|
141
|
+
`ACCESSI_TEST_REQUIRE_REDIS=1` per fallire invece di saltare quando Redis non e raggiungibile
|
|
142
|
+
(usato dalla CI). I test usano chiavi con prefisso per processo e cancellano solo quelle, quindi
|
|
143
|
+
possono girare anche su un Redis condiviso. `docker-compose.test.yml` resta dedicato solo a
|
|
144
|
+
Firebird: la CI avvia Redis come service del job `Redis stores`.
|
|
145
|
+
|
|
118
146
|
## Firebird: drop-in di `es-node-firebird`
|
|
119
147
|
|
|
120
148
|
La libreria **ri-esporta l'intera API di `node-firebird`** (`export * from "node-firebird"` piu il
|
|
@@ -197,6 +225,8 @@ lista utenti apre un pannello in cui inserire l'URL dell'applicazione e generare
|
|
|
197
225
|
| Backend Express esistente | `await initializeAccessiModule(app, accessiOptions)` monta le rotte `/api/accessi` su un host Nest isolato |
|
|
198
226
|
| Applicazione NestJS | importa `AccessiModule.forRoot(accessiOptions)` (e/o `AllegatiModule.forRoot(allegatiOptions)`) |
|
|
199
227
|
| Accessi + Allegati insieme | `EmilsoftwareModule.forRoot({ accessiOptions, allegatiOptions })` |
|
|
228
|
+
| Client multi-istanza / multi-tenant | `createAccessiClient({ baseUrl, getToken })` isola base URL e token per istanza (concorrenza sicura); `configureAccessiClient` resta il default globale |
|
|
229
|
+
| Client per scope | `accessi/client/public` (frontend), `accessi/client/admin` (tool admin), `accessi/client/service` (backend fratelli): stesse tipi del client completo, nessuna operazione fuori scope |
|
|
200
230
|
|
|
201
231
|
Tutta la configurazione e riservata al backend: segreti JWT/SMTP/DB non devono mai raggiungere il browser.
|
|
202
232
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client per le API amministrative di Accessi: utenti, ruoli, menu, scope,
|
|
3
|
+
* filtri, configurazione console, provider federati e schema.
|
|
4
|
+
*
|
|
5
|
+
* Richiede un token con privilegi admin. Per login e reset password usare
|
|
6
|
+
* `accessi/client/public`.
|
|
7
|
+
*/
|
|
8
|
+
import * as generated from '../generated/admin';
|
|
9
|
+
import type { AccessiClientConfig } from '../../../accessi-module/Console/accessiFetch';
|
|
10
|
+
import { type AccessiScopedClient } from '../createAccessiClient';
|
|
11
|
+
export * from '../generated/admin';
|
|
12
|
+
export * from '../../../accessi-module/Console/generated/model';
|
|
13
|
+
export { AccessiRequestError } from '../../../accessi-module/Console/accessiFetch';
|
|
14
|
+
export type { AccessiClientConfig } from '../../../accessi-module/Console/accessiFetch';
|
|
15
|
+
/** Client admin con configurazione isolata per istanza. */
|
|
16
|
+
export type AccessiAdminClient = AccessiScopedClient<typeof generated>;
|
|
17
|
+
/** Crea un client delle sole API amministrative, con base URL e token propri. */
|
|
18
|
+
export declare function createAccessiAdminClient(config?: AccessiClientConfig): AccessiAdminClient;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.AccessiRequestError = void 0;
|
|
40
|
+
exports.createAccessiAdminClient = createAccessiAdminClient;
|
|
41
|
+
/**
|
|
42
|
+
* Client per le API amministrative di Accessi: utenti, ruoli, menu, scope,
|
|
43
|
+
* filtri, configurazione console, provider federati e schema.
|
|
44
|
+
*
|
|
45
|
+
* Richiede un token con privilegi admin. Per login e reset password usare
|
|
46
|
+
* `accessi/client/public`.
|
|
47
|
+
*/
|
|
48
|
+
const generated = __importStar(require("../generated/admin"));
|
|
49
|
+
const createAccessiClient_1 = require("../createAccessiClient");
|
|
50
|
+
__exportStar(require("../generated/admin"), exports);
|
|
51
|
+
__exportStar(require("../../../accessi-module/Console/generated/model"), exports);
|
|
52
|
+
var accessiFetch_1 = require("../../../accessi-module/Console/accessiFetch");
|
|
53
|
+
Object.defineProperty(exports, "AccessiRequestError", { enumerable: true, get: function () { return accessiFetch_1.AccessiRequestError; } });
|
|
54
|
+
/** Crea un client delle sole API amministrative, con base URL e token propri. */
|
|
55
|
+
function createAccessiAdminClient(config = {}) {
|
|
56
|
+
return (0, createAccessiClient_1.createAccessiClientFromModule)(generated, config);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/accessi/client/admin/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,4DAIC;AA3BD;;;;;;GAMG;AACH,8DAAgD;AAEhD,gEAGgC;AAEhC,qDAAmC;AACnC,kFAAgE;AAChE,6EAAmF;AAA1E,mHAAA,mBAAmB,OAAA;AAM5B,iFAAiF;AACjF,SAAgB,wBAAwB,CACtC,SAA8B,EAAE;IAEhC,OAAO,IAAA,mDAA6B,EAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAC1D,CAAC","sourcesContent":["/**\n * Client per le API amministrative di Accessi: utenti, ruoli, menu, scope,\n * filtri, configurazione console, provider federati e schema.\n *\n * Richiede un token con privilegi admin. Per login e reset password usare\n * `accessi/client/public`.\n */\nimport * as generated from '../generated/admin';\nimport type { AccessiClientConfig } from '../../../accessi-module/Console/accessiFetch';\nimport {\n createAccessiClientFromModule,\n type AccessiScopedClient,\n} from '../createAccessiClient';\n\nexport * from '../generated/admin';\nexport * from '../../../accessi-module/Console/generated/model';\nexport { AccessiRequestError } from '../../../accessi-module/Console/accessiFetch';\nexport type { AccessiClientConfig } from '../../../accessi-module/Console/accessiFetch';\n\n/** Client admin con configurazione isolata per istanza. */\nexport type AccessiAdminClient = AccessiScopedClient<typeof generated>;\n\n/** Crea un client delle sole API amministrative, con base URL e token propri. */\nexport function createAccessiAdminClient(\n config: AccessiClientConfig = {},\n): AccessiAdminClient {\n return createAccessiClientFromModule(generated, config);\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type AccessiClientConfig } from '../../accessi-module/Console/accessiFetch';
|
|
2
|
+
/**
|
|
3
|
+
* Client generato con configurazione isolata per istanza.
|
|
4
|
+
*
|
|
5
|
+
* `TModule` e il modulo generato da Orval per lo scope: il client espone solo
|
|
6
|
+
* le operazioni di quello scope (pubblico, admin o service token).
|
|
7
|
+
*/
|
|
8
|
+
export type AccessiScopedClient<TModule extends object> = TModule & {
|
|
9
|
+
/** Sostituisce la configurazione dell'istanza senza toccare quella globale. */
|
|
10
|
+
configure(config: AccessiClientConfig): void;
|
|
11
|
+
/** Copia della configurazione corrente dell'istanza. */
|
|
12
|
+
getConfig(): AccessiClientConfig;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Avvolge un modulo generato da Orval con una configurazione per istanza.
|
|
16
|
+
*
|
|
17
|
+
* La configurazione viene applicata alla singola chiamata tramite
|
|
18
|
+
* `runWithAccessiClient`, quindi istanze diverse possono chiamare in concorrenza
|
|
19
|
+
* senza sovrascriversi. Le funzioni in `TModule` sono le sole esposte.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createAccessiClientFromModule<TModule extends object>(api: TModule, config?: AccessiClientConfig): AccessiScopedClient<TModule>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAccessiClientFromModule = createAccessiClientFromModule;
|
|
4
|
+
const accessiFetch_1 = require("../../accessi-module/Console/accessiFetch");
|
|
5
|
+
/**
|
|
6
|
+
* Avvolge un modulo generato da Orval con una configurazione per istanza.
|
|
7
|
+
*
|
|
8
|
+
* La configurazione viene applicata alla singola chiamata tramite
|
|
9
|
+
* `runWithAccessiClient`, quindi istanze diverse possono chiamare in concorrenza
|
|
10
|
+
* senza sovrascriversi. Le funzioni in `TModule` sono le sole esposte.
|
|
11
|
+
*/
|
|
12
|
+
function createAccessiClientFromModule(api, config = {}) {
|
|
13
|
+
let current = Object.assign({}, config);
|
|
14
|
+
return new Proxy(api, {
|
|
15
|
+
get(target, property, receiver) {
|
|
16
|
+
if (property === 'configure') {
|
|
17
|
+
return (next) => {
|
|
18
|
+
current = Object.assign({}, next);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (property === 'getConfig') {
|
|
22
|
+
return () => (Object.assign({}, current));
|
|
23
|
+
}
|
|
24
|
+
const value = Reflect.get(target, property, receiver);
|
|
25
|
+
if (typeof value !== 'function')
|
|
26
|
+
return value;
|
|
27
|
+
return (...args) => (0, accessiFetch_1.runWithAccessiClient)(current, () => value(...args));
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=createAccessiClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createAccessiClient.js","sourceRoot":"","sources":["../../../src/accessi/client/createAccessiClient.ts"],"names":[],"mappings":";;AAyBA,sEAwBC;AAjDD,4EAGmD;AAenD;;;;;;GAMG;AACH,SAAgB,6BAA6B,CAC3C,GAAY,EACZ,SAA8B,EAAE;IAEhC,IAAI,OAAO,qBAA6B,MAAM,CAAE,CAAC;IAEjD,OAAO,IAAI,KAAK,CAAC,GAAmC,EAAE;QACpD,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ;YAC5B,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;gBAC7B,OAAO,CAAC,IAAyB,EAAE,EAAE;oBACnC,OAAO,qBAAQ,IAAI,CAAE,CAAC;gBACxB,CAAC,CAAC;YACJ,CAAC;YACD,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;gBAC7B,OAAO,GAAG,EAAE,CAAC,mBAAM,OAAO,EAAG,CAAC;YAChC,CAAC;YAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAY,CAAC;YACjE,IAAI,OAAO,KAAK,KAAK,UAAU;gBAAE,OAAO,KAAK,CAAC;YAE9C,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE,CAC5B,IAAA,mCAAoB,EAAC,OAAO,EAAE,GAAG,EAAE,CAAE,KAA6C,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACjG,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import {\n runWithAccessiClient,\n type AccessiClientConfig,\n} from '../../accessi-module/Console/accessiFetch';\n\n/**\n * Client generato con configurazione isolata per istanza.\n *\n * `TModule` e il modulo generato da Orval per lo scope: il client espone solo\n * le operazioni di quello scope (pubblico, admin o service token).\n */\nexport type AccessiScopedClient<TModule extends object> = TModule & {\n /** Sostituisce la configurazione dell'istanza senza toccare quella globale. */\n configure(config: AccessiClientConfig): void;\n /** Copia della configurazione corrente dell'istanza. */\n getConfig(): AccessiClientConfig;\n};\n\n/**\n * Avvolge un modulo generato da Orval con una configurazione per istanza.\n *\n * La configurazione viene applicata alla singola chiamata tramite\n * `runWithAccessiClient`, quindi istanze diverse possono chiamare in concorrenza\n * senza sovrascriversi. Le funzioni in `TModule` sono le sole esposte.\n */\nexport function createAccessiClientFromModule<TModule extends object>(\n api: TModule,\n config: AccessiClientConfig = {},\n): AccessiScopedClient<TModule> {\n let current: AccessiClientConfig = { ...config };\n\n return new Proxy(api as AccessiScopedClient<TModule>, {\n get(target, property, receiver) {\n if (property === 'configure') {\n return (next: AccessiClientConfig) => {\n current = { ...next };\n };\n }\n if (property === 'getConfig') {\n return () => ({ ...current });\n }\n\n const value = Reflect.get(target, property, receiver) as unknown;\n if (typeof value !== 'function') return value;\n\n return (...args: unknown[]) =>\n runWithAccessiClient(current, () => (value as (...callArgs: unknown[]) => unknown)(...args));\n },\n });\n}\n"]}
|