emilsoftware-utilities 2.0.0-dev.71 → 2.0.0-dev.73
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 +43 -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 +7 -13
- package/dist/accessi/client/index.js +16 -29
- 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/console.js +6 -0
- package/dist/accessi-module/Console/wiki.js +6 -0
- 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/emilsoftware-utilities-2.0.0-dev.73.tgz +0 -0
- package/docs/accessi-openapi-baseline.json +4500 -0
- package/docs/accessi-openapi-breaking-allowlist.json +1 -0
- package/docs/adr/0001-split-package.md +79 -0
- package/integration-prompt.md +6 -2
- package/package.json +37 -4
- package/dist/emilsoftware-utilities-2.0.0-dev.71.tgz +0 -0
package/README.MD
CHANGED
|
@@ -116,6 +116,48 @@ La CI (`.github/workflows/ci.yml`) esegue typecheck, test con coverage e build,
|
|
|
116
116
|
integration test in matrice su Firebird 5 e 3. Il workflow di release (`publish.yml`) esegue
|
|
117
117
|
typecheck e test prima di build e pubblicazione.
|
|
118
118
|
|
|
119
|
+
### Packaging
|
|
120
|
+
|
|
121
|
+
Il pacchetto e pubblicato come **CommonJS** (build `tsc` in `dist/`) con export map esplicita per
|
|
122
|
+
ogni entry point; gli `import` ESM funzionano tramite interop Node. La scelta CJS e intenzionale:
|
|
123
|
+
il pacchetto gira in host Nest/Express e non esiste un bundle ESM separato da mantenere.
|
|
124
|
+
|
|
125
|
+
- `sideEffects` elenca solo i moduli con effetti collaterali (root barrel, `firebird-compat`,
|
|
126
|
+
bundle console), tutto il resto resta tree-shakable.
|
|
127
|
+
- `typesVersions` copre i TypeScript precedenti al campo `exports`.
|
|
128
|
+
- `npm run test:pack` crea il tarball con `npm pack`, lo installa in un progetto temporaneo e
|
|
129
|
+
verifica ogni subpath (`accessi/server`, `resource-server/*`, `client/*`, `contracts`, `openapi`,
|
|
130
|
+
`console`, `ui`), l'assenza di dipendenze server-side in `contracts` e l'interop ESM. La CI lo
|
|
131
|
+
esegue in un job dedicato dopo la build.
|
|
132
|
+
|
|
133
|
+
La decisione di mantenere un pacchetto singolo (con entry point per scope) e il piano per un
|
|
134
|
+
eventuale split futuro sono documentati nell'[ADR 0001](docs/adr/0001-split-package.md).
|
|
135
|
+
|
|
136
|
+
### OpenAPI semantic diff
|
|
137
|
+
|
|
138
|
+
`docs/accessi-openapi-fingerprint.json` blocca la rimozione di operation e schema, ma non i cambi
|
|
139
|
+
di tipo o le nuove restrizioni. Il build esegue anche un diff semantico contro
|
|
140
|
+
`docs/accessi-openapi-baseline.json`:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm run check:accessi-openapi-diff # verifica (eseguita dal build e dalla CI)
|
|
144
|
+
npm run accessi:update-openapi-baseline # accetta il contratto corrente come nuova baseline
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Sono **breaking**: operation/parametri/risposte rimosse, cambi di tipo o formato, `required` aggiunto
|
|
148
|
+
in input o rimosso in output, valori enum rimossi, `security` cambiata e vincoli piu stretti
|
|
149
|
+
sull'input. Aggiungere campi opzionali (input o output) non e breaking.
|
|
150
|
+
|
|
151
|
+
Un breaking change intenzionale va dichiarato in
|
|
152
|
+
`docs/accessi-openapi-breaking-allowlist.json` con `id`, `reason` (obbligatoria) e, se esiste, `issue`:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
[{ "id": "operation:legacyLogin:removed", "reason": "Rimosso nella major 3.0", "issue": "#123" }]
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
La CI fallisce se un breaking change non e coperto, se un'eccezione non ha `reason` o se l'eccezione
|
|
159
|
+
e diventata obsoleta (il cambio non esiste piu).
|
|
160
|
+
|
|
119
161
|
### Integration test su Redis reale
|
|
120
162
|
|
|
121
163
|
Gli store condivisi (rate limit, ticket console, revoca sessioni, revoca `jti`, rotazione refresh
|
|
@@ -226,6 +268,7 @@ lista utenti apre un pannello in cui inserire l'URL dell'applicazione e generare
|
|
|
226
268
|
| Applicazione NestJS | importa `AccessiModule.forRoot(accessiOptions)` (e/o `AllegatiModule.forRoot(allegatiOptions)`) |
|
|
227
269
|
| Accessi + Allegati insieme | `EmilsoftwareModule.forRoot({ accessiOptions, allegatiOptions })` |
|
|
228
270
|
| Client multi-istanza / multi-tenant | `createAccessiClient({ baseUrl, getToken })` isola base URL e token per istanza (concorrenza sicura); `configureAccessiClient` resta il default globale |
|
|
271
|
+
| 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 |
|
|
229
272
|
|
|
230
273
|
Tutta la configurazione e riservata al backend: segreti JWT/SMTP/DB non devono mai raggiungere il browser.
|
|
231
274
|
|
|
@@ -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"]}
|