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.
Files changed (37) hide show
  1. package/README.MD +43 -0
  2. package/dist/accessi/client/admin/index.d.ts +18 -0
  3. package/dist/accessi/client/admin/index.js +58 -0
  4. package/dist/accessi/client/admin/index.js.map +1 -0
  5. package/dist/accessi/client/createAccessiClient.d.ts +21 -0
  6. package/dist/accessi/client/createAccessiClient.js +31 -0
  7. package/dist/accessi/client/createAccessiClient.js.map +1 -0
  8. package/dist/accessi/client/generated/admin.d.ts +601 -0
  9. package/dist/accessi/client/generated/admin.js +557 -0
  10. package/dist/accessi/client/generated/admin.js.map +1 -0
  11. package/dist/accessi/client/generated/public.d.ts +121 -0
  12. package/dist/accessi/client/generated/public.js +119 -0
  13. package/dist/accessi/client/generated/public.js.map +1 -0
  14. package/dist/accessi/client/generated/service.d.ts +53 -0
  15. package/dist/accessi/client/generated/service.js +63 -0
  16. package/dist/accessi/client/generated/service.js.map +1 -0
  17. package/dist/accessi/client/index.d.ts +7 -13
  18. package/dist/accessi/client/index.js +16 -29
  19. package/dist/accessi/client/index.js.map +1 -1
  20. package/dist/accessi/client/public/index.d.ts +18 -0
  21. package/dist/accessi/client/public/index.js +58 -0
  22. package/dist/accessi/client/public/index.js.map +1 -0
  23. package/dist/accessi/client/service/index.d.ts +17 -0
  24. package/dist/accessi/client/service/index.js +57 -0
  25. package/dist/accessi/client/service/index.js.map +1 -0
  26. package/dist/accessi-module/Console/console.js +6 -0
  27. package/dist/accessi-module/Console/wiki.js +6 -0
  28. package/dist/accessi-module/Console/wiki.js.map +1 -1
  29. package/dist/accessi-module/Controllers/AccessiIntrospectionController.js +1 -1
  30. package/dist/accessi-module/Controllers/AccessiIntrospectionController.js.map +1 -1
  31. package/dist/emilsoftware-utilities-2.0.0-dev.73.tgz +0 -0
  32. package/docs/accessi-openapi-baseline.json +4500 -0
  33. package/docs/accessi-openapi-breaking-allowlist.json +1 -0
  34. package/docs/adr/0001-split-package.md +79 -0
  35. package/integration-prompt.md +6 -2
  36. package/package.json +37 -4
  37. 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"]}