@nextage/era-lib 1.0.191 → 1.0.193

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 (59) hide show
  1. package/build/constants.d.ts +48 -15
  2. package/build/constants.d.ts.map +1 -1
  3. package/build/constants.js +49 -16
  4. package/build/constants.js.map +1 -1
  5. package/build/enums.d.ts +26 -2
  6. package/build/enums.d.ts.map +1 -1
  7. package/build/enums.js +27 -2
  8. package/build/enums.js.map +1 -1
  9. package/build/events/base/base-event.controller.d.ts +1 -1
  10. package/build/events/base/base-event.controller.js +1 -1
  11. package/build/events/base/base-msg-listener.d.ts +1 -1
  12. package/build/events/base/base-msg-listener.js +1 -1
  13. package/build/events/publisher-registry.d.ts +1 -1
  14. package/build/events/publisher-registry.js +3 -3
  15. package/build/events/revocation-denylist.js +1 -1
  16. package/build/events/transport/nats-client-manager.d.ts +1 -1
  17. package/build/events/transport/nats-client-manager.js +1 -1
  18. package/build/index.d.ts +1 -0
  19. package/build/index.d.ts.map +1 -1
  20. package/build/index.js +1 -0
  21. package/build/index.js.map +1 -1
  22. package/build/interfaces.d.ts +50 -1
  23. package/build/interfaces.d.ts.map +1 -1
  24. package/build/types/base-user/index.d.ts +2 -1
  25. package/build/types/base-user/index.d.ts.map +1 -1
  26. package/build/types/nx-context.d.ts +18 -0
  27. package/build/types/nx-context.d.ts.map +1 -0
  28. package/build/types/nx-context.js +14 -0
  29. package/build/types/nx-context.js.map +1 -0
  30. package/build/utils/claims.d.ts +42 -0
  31. package/build/utils/claims.d.ts.map +1 -0
  32. package/build/utils/claims.interfaces.d.ts +36 -0
  33. package/build/utils/claims.interfaces.d.ts.map +1 -0
  34. package/build/utils/claims.interfaces.js +9 -0
  35. package/build/utils/claims.interfaces.js.map +1 -0
  36. package/build/utils/claims.js +64 -0
  37. package/build/utils/claims.js.map +1 -0
  38. package/build/utils/express.js +2 -2
  39. package/build/utils/functs.d.ts +3 -3
  40. package/build/utils/functs.js +3 -3
  41. package/build/utils/index.d.ts +4 -0
  42. package/build/utils/index.d.ts.map +1 -1
  43. package/build/utils/index.js +4 -0
  44. package/build/utils/index.js.map +1 -1
  45. package/build/utils/scope.d.ts +75 -0
  46. package/build/utils/scope.d.ts.map +1 -0
  47. package/build/utils/scope.interfaces.d.ts +20 -0
  48. package/build/utils/scope.interfaces.d.ts.map +1 -0
  49. package/build/utils/scope.interfaces.js +10 -0
  50. package/build/utils/scope.interfaces.js.map +1 -0
  51. package/build/utils/scope.js +121 -0
  52. package/build/utils/scope.js.map +1 -0
  53. package/build/utils/start-service.js +1 -1
  54. package/build/utils/tenant.d.ts +71 -38
  55. package/build/utils/tenant.d.ts.map +1 -1
  56. package/build/utils/tenant.interfaces.d.ts +5 -5
  57. package/build/utils/tenant.js +83 -54
  58. package/build/utils/tenant.js.map +1 -1
  59. package/package.json +1 -1
@@ -1,65 +1,98 @@
1
1
  /*********************************************************************************************
2
2
  * *
3
- * Multi-tenancy helpers — single source of truth for how a request is scoped to a tenant. *
3
+ * Multi-tenancy helpers - single source of truth for how a request is scoped to a tenant. *
4
4
  * *
5
- * Every rule about "which organisation is this operation allowed to touch" lives here and *
6
- * nowhere else: the services (app-srv, auth-srv, …) import these helpers, they never *
7
- * re-implement the scoping. See ADR-0005 §4 (capability matrix) and §5 (tenant resolution). *
5
+ * Every rule about "which organization is this operation allowed to touch" lives here and *
6
+ * nowhere else: the services (app-srv, auth-srv, ...) import these helpers, they never *
7
+ * re-implement the scoping. See ADR-0005 section 4 (capability matrix) and section 5 *
8
+ * (tenant resolution). *
8
9
  * *
9
10
  *********************************************************************************************/
10
11
  import { BaseUser, NxContext, NxObject } from '@nextage/nx-frame-be';
11
12
  import { ScopedReadModel } from './tenant.interfaces';
12
13
  /**
13
- * Sets the tenantId on the given payload based on the user's role and organizations.
14
- * - Normal users: tenantId is always set to their first organization
15
- * - System/provider users (SYSTEM_ROLES):
16
- * - If applyDefaultForAdmin = false → can access all tenants
17
- * - If applyDefaultForAdmin = true and tenantId not provided → tenantId set to first org (subset view)
14
+ * Resolves the organization a request operates on - ALWAYS exactly one.
15
+ *
16
+ * The selection NEVER comes from the payload: it travels out of band (`X-Org-Id`
17
+ * header, or `orgId` in the WebSocket connection params) and lands on
18
+ * `NxContext.orgId`. Reading it from the body would let a client name any tenant
19
+ * simply by adding a field to a mutation input (T34).
20
+ *
21
+ * Resolution order (ADR-0005 section 5.1) - the first match wins:
22
+ *
23
+ * 1. no selection -> the user's own organization, for EVERYONE
24
+ * 2. cross-tenant role -> the selection, whichever it is
25
+ * 3. selection within reach-> the selection itself (membership or grant)
26
+ * 4. otherwise -> throws (fail-closed: an unreachable selection is never
27
+ * silently downgraded to the user's own tenant)
28
+ *
29
+ * A cross-tenant role does NOT mean "sees every tenant at once": it means it may
30
+ * operate on ANY tenant, ONE at a time, upon selection. Without a selection it is
31
+ * scoped to its own organization exactly like everybody else - the provider one is
32
+ * an organization like the others and holds its own application data.
33
+ *
34
+ * It follows that the return type is a plain `string`: there is no unscoped outcome.
35
+ * A cross-tenant aggregation - a future dashboard - is a DIFFERENT query, built on
36
+ * `reachableOrgIds` in its own resolver, and never a relaxation of this helper.
37
+ *
38
+ * Built on `reachableOrgIds` on purpose: the set of organizations a selection may
39
+ * name is the same set a list may show. Two independent implementations would
40
+ * eventually disagree, and any disagreement is a leak.
41
+ *
42
+ * @param user the authenticated user (`NxContext.user`)
43
+ * @param orgId the organization named by the request, when any
44
+ * @returns the tenant id to enforce
45
+ * @throws `AppError('messages.forbidden')` when the selection is out of reach
18
46
  */
19
- export declare function setTenant(item: NxObject, user?: BaseUser, applyDefaultForAdmin?: boolean): void;
47
+ export declare function resolveTenant(user?: BaseUser, orgId?: string): string;
20
48
  /**
21
- * Scopes a query filter to the user's tenant (multi-tenancy guard).
49
+ * Forces `tenantId` on a payload or on a query filter, from the resolved organization.
22
50
  *
23
- * System/provider roles (`SYSTEM_ROLES`) are left unscoped so they can query across
24
- * tenants; every other user gets `tenantId` forced to their first organization.
25
- * Throws when a non-admin user has no organization.
51
+ * The field is ALWAYS overwritten, never read: whatever the client sent under that
52
+ * name is irrelevant, which is what makes the helper safe to call on user input.
53
+ * There is no way out of the scoping and no flag to opt out of it - that was exactly
54
+ * defect D2 of ADR-0005 section 5.1, a fail-open by default.
26
55
  *
27
- * @param item the query filter object, mutated in place
28
- * @param user the authenticated user (roles + organizations)
56
+ * @param item the payload or filter, mutated in place
57
+ * @param context the request context (authenticated user + selected organization)
58
+ * @throws when no tenant can be resolved
29
59
  */
30
- export declare function setTenantFilter(item: any, user?: BaseUser): void;
60
+ export declare function setTenant(item: NxObject, context?: NxContext): void;
31
61
  /**
32
- * Returns the user's tenant id (their first organization).
62
+ * Returns the user's own tenant id, that is their membership organization.
63
+ *
64
+ * Membership is an invariant of exactly one entry (ADR-0005 section 3.1), so the
65
+ * first entry IS the organization; the array shape only exists to stay compatible
66
+ * with the shared application base.
33
67
  *
34
68
  * @param user the authenticated user
35
69
  * @returns the tenant id
36
70
  * @throws if the user has no organization
37
71
  */
38
- export declare function getTenant(user?: BaseUser): string | undefined;
72
+ export declare function getTenant(user?: BaseUser): string;
39
73
  /**
40
- * Verifica che `id` sia raggiungibile dall'utente del contesto, prima di una
41
- * scrittura distruttiva.
74
+ * Checks that `id` is reachable by the context user, ahead of a destructive write.
42
75
  *
43
- * Serve a colmare **T37**: `BaseModel.remove(id)` chiama `beforeRemove` e poi
44
- * `findByIdAndDelete(id)`, senza applicare né `updateFilters` né alcun vincolo di
45
- * `tenantId` — e `bulkRemove(ids)` non è che `ids.map(remove)`. Senza questo
46
- * controllo un utente qualsiasi cancella documenti di **altre organizzazioni**
47
- * conoscendone l'`_id`.
76
+ * Fills the gap of **T37**: `BaseModel.remove(id)` calls `beforeRemove` and then
77
+ * `findByIdAndDelete(id)`, applying neither `updateFilters` nor any `tenantId`
78
+ * constraint - and `bulkRemove(ids)` is nothing but `ids.map(remove)`. Without this
79
+ * check any user deletes documents belonging to OTHER organizations, knowing only
80
+ * their `_id`.
48
81
  *
49
- * Il controllo riusa `model.get`, che passa da `beforeGet` e quindi applica già lo
50
- * scoping del tenant: un solo punto di verità, nessuna regola di tenancy duplicata
51
- * qui. Ne consegue che i ruoli cross-tenant, per i quali `setTenant` non aggiunge
52
- * il filtro, continuano a cancellare ovunque — come previsto dalla matrice
53
- * ADR-0005 §4.
82
+ * The check reuses `model.get`, which goes through `beforeGet` and therefore already
83
+ * applies the tenant scoping: one single source of truth, no tenancy rule duplicated
84
+ * here. It follows that a cross-tenant role deletes in the organization it SELECTED,
85
+ * and in its own when it selected none - never across several at once, exactly as
86
+ * `resolveTenant` prescribes.
54
87
  *
55
- * **Fail-closed**: un `id` inesistente o fuori scope solleva un errore, senza
56
- * distinguere i due casi (non si conferma l'esistenza di un documento altrui).
88
+ * **Fail-closed**: a missing or out-of-scope `id` raises an error, without telling
89
+ * the two cases apart (the existence of someone else's document is never confirmed).
57
90
  *
58
- * @param model il modello su cui avviene la rimozione (`this` nell'hook)
59
- * @param id identificativo del documento
60
- * @param context contesto di richiesta, con l'utente autenticato
61
- * @returns lo stesso `id`, così da poter essere usato direttamente in `beforeRemove`
62
- * @throws `AppError('messages.notFound')` se il documento non è nello scope
91
+ * @param model the model the removal happens on (`this` inside the hook)
92
+ * @param id the document identifier
93
+ * @param context the request context, carrying the authenticated user
94
+ * @returns the same `id`, so it can be used directly inside `beforeRemove`
95
+ * @throws `AppError('messages.notFound')` when the document is out of scope
63
96
  */
64
97
  export declare function assertTenantScope(model: ScopedReadModel, id: string, context?: NxContext): Promise<string>;
65
98
  //# sourceMappingURL=tenant.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/utils/tenant.ts"],"names":[],"mappings":"AAAA;;;;;;;;+FAQ+F;AAE/F,OAAO,EAAY,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAG/E,OAAO,EAAE,eAAe,EAAE,MAA8B,qBAAqB,CAAC;AAE9E;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,oBAAoB,UAAQ,GAAG,IAAI,CAc7F;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAShE;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAM7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpH"}
1
+ {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/utils/tenant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;+FAS+F;AAE/F,OAAO,EAAY,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAG/E,OAAO,EAAE,eAAe,EAAE,MAA8B,qBAAqB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAerE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAE,SAAc,GAAG,IAAI,CAGvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAMjD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpH"}
@@ -6,12 +6,12 @@
6
6
  */
7
7
  import { NxContext } from '@nextage/nx-frame-be';
8
8
  /**
9
- * Modello di cui serve la sola lettura per `_id`, già scopata sul tenant dal
10
- * proprio `beforeGet`.
9
+ * A model of which only the read-by-`_id` is needed, already tenant-scoped by its
10
+ * own `beforeGet`.
11
11
  *
12
- * Volutamente **strutturale** e non `BaseModel<Attrs, Doc, Model>`: la libreria non
13
- * deve dipendere dai tipi concreti dei modelli di un singolo servizio, e qualunque
14
- * modello che sappia leggere per `_id` soddisfa il contratto.
12
+ * Deliberately **structural** and not `BaseModel<Attrs, Doc, Model>`: the library
13
+ * must not depend on the concrete model types of a single service, and any model
14
+ * able to read by `_id` satisfies the contract.
15
15
  */
16
16
  export interface ScopedReadModel {
17
17
  get(id: string, context: NxContext): Promise<unknown>;
@@ -1,57 +1,87 @@
1
1
  "use strict";
2
2
  /*********************************************************************************************
3
3
  * *
4
- * Multi-tenancy helpers — single source of truth for how a request is scoped to a tenant. *
4
+ * Multi-tenancy helpers - single source of truth for how a request is scoped to a tenant. *
5
5
  * *
6
- * Every rule about "which organisation is this operation allowed to touch" lives here and *
7
- * nowhere else: the services (app-srv, auth-srv, …) import these helpers, they never *
8
- * re-implement the scoping. See ADR-0005 §4 (capability matrix) and §5 (tenant resolution). *
6
+ * Every rule about "which organization is this operation allowed to touch" lives here and *
7
+ * nowhere else: the services (app-srv, auth-srv, ...) import these helpers, they never *
8
+ * re-implement the scoping. See ADR-0005 section 4 (capability matrix) and section 5 *
9
+ * (tenant resolution). *
9
10
  * *
10
11
  *********************************************************************************************/
11
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.resolveTenant = resolveTenant;
12
14
  exports.setTenant = setTenant;
13
- exports.setTenantFilter = setTenantFilter;
14
15
  exports.getTenant = getTenant;
15
16
  exports.assertTenantScope = assertTenantScope;
16
17
  const nx_frame_be_1 = require("@nextage/nx-frame-be");
17
- const constants_1 = require("../constants");
18
+ const scope_1 = require("./scope");
18
19
  /**
19
- * Sets the tenantId on the given payload based on the user's role and organizations.
20
- * - Normal users: tenantId is always set to their first organization
21
- * - System/provider users (SYSTEM_ROLES):
22
- * - If applyDefaultForAdmin = false → can access all tenants
23
- * - If applyDefaultForAdmin = true and tenantId not provided → tenantId set to first org (subset view)
20
+ * Resolves the organization a request operates on - ALWAYS exactly one.
21
+ *
22
+ * The selection NEVER comes from the payload: it travels out of band (`X-Org-Id`
23
+ * header, or `orgId` in the WebSocket connection params) and lands on
24
+ * `NxContext.orgId`. Reading it from the body would let a client name any tenant
25
+ * simply by adding a field to a mutation input (T34).
26
+ *
27
+ * Resolution order (ADR-0005 section 5.1) - the first match wins:
28
+ *
29
+ * 1. no selection -> the user's own organization, for EVERYONE
30
+ * 2. cross-tenant role -> the selection, whichever it is
31
+ * 3. selection within reach-> the selection itself (membership or grant)
32
+ * 4. otherwise -> throws (fail-closed: an unreachable selection is never
33
+ * silently downgraded to the user's own tenant)
34
+ *
35
+ * A cross-tenant role does NOT mean "sees every tenant at once": it means it may
36
+ * operate on ANY tenant, ONE at a time, upon selection. Without a selection it is
37
+ * scoped to its own organization exactly like everybody else - the provider one is
38
+ * an organization like the others and holds its own application data.
39
+ *
40
+ * It follows that the return type is a plain `string`: there is no unscoped outcome.
41
+ * A cross-tenant aggregation - a future dashboard - is a DIFFERENT query, built on
42
+ * `reachableOrgIds` in its own resolver, and never a relaxation of this helper.
43
+ *
44
+ * Built on `reachableOrgIds` on purpose: the set of organizations a selection may
45
+ * name is the same set a list may show. Two independent implementations would
46
+ * eventually disagree, and any disagreement is a leak.
47
+ *
48
+ * @param user the authenticated user (`NxContext.user`)
49
+ * @param orgId the organization named by the request, when any
50
+ * @returns the tenant id to enforce
51
+ * @throws `AppError('messages.forbidden')` when the selection is out of reach
24
52
  */
25
- function setTenant(item, user, applyDefaultForAdmin = false) {
26
- const isAdmin = user?.hasRole(constants_1.SYSTEM_ROLES);
27
- // Admins who can see all tenants or already have tenantId specified → exit
28
- if (isAdmin && (!applyDefaultForAdmin || item.tenantId))
29
- return;
30
- if (!user?.organizations?.length)
31
- throw new Error('Cannot proceed: organization not set');
32
- // Admin with applyDefaultForAdmin=true and tenantId absent
33
- // OR normal user → force tenantId
34
- item.tenantId = user.organizations[0].id;
53
+ function resolveTenant(user, orgId) {
54
+ if (!orgId)
55
+ return getTenant(user);
56
+ const reachable = (0, scope_1.reachableOrgIds)(user);
57
+ // `undefined` means no constraint on WHICH organization may be named.
58
+ if (!reachable)
59
+ return orgId;
60
+ if (!reachable.includes(orgId))
61
+ throw new nx_frame_be_1.AppError('messages.forbidden');
62
+ return orgId;
35
63
  }
36
64
  /**
37
- * Scopes a query filter to the user's tenant (multi-tenancy guard).
65
+ * Forces `tenantId` on a payload or on a query filter, from the resolved organization.
38
66
  *
39
- * System/provider roles (`SYSTEM_ROLES`) are left unscoped so they can query across
40
- * tenants; every other user gets `tenantId` forced to their first organization.
41
- * Throws when a non-admin user has no organization.
67
+ * The field is ALWAYS overwritten, never read: whatever the client sent under that
68
+ * name is irrelevant, which is what makes the helper safe to call on user input.
69
+ * There is no way out of the scoping and no flag to opt out of it - that was exactly
70
+ * defect D2 of ADR-0005 section 5.1, a fail-open by default.
42
71
  *
43
- * @param item the query filter object, mutated in place
44
- * @param user the authenticated user (roles + organizations)
72
+ * @param item the payload or filter, mutated in place
73
+ * @param context the request context (authenticated user + selected organization)
74
+ * @throws when no tenant can be resolved
45
75
  */
46
- function setTenantFilter(item, user) {
47
- if (user?.hasRole(constants_1.SYSTEM_ROLES))
48
- return;
49
- if (!user?.organizations?.length)
50
- throw new Error('Cannot proceed: organization not set');
51
- item.tenantId = user.organizations[0].id;
76
+ function setTenant(item, context = {}) {
77
+ item.tenantId = resolveTenant(context.user, context.orgId);
52
78
  }
53
79
  /**
54
- * Returns the user's tenant id (their first organization).
80
+ * Returns the user's own tenant id, that is their membership organization.
81
+ *
82
+ * Membership is an invariant of exactly one entry (ADR-0005 section 3.1), so the
83
+ * first entry IS the organization; the array shape only exists to stay compatible
84
+ * with the shared application base.
55
85
  *
56
86
  * @param user the authenticated user
57
87
  * @returns the tenant id
@@ -60,32 +90,31 @@ function setTenantFilter(item, user) {
60
90
  function getTenant(user) {
61
91
  if (!user?.organizations?.length)
62
92
  throw new Error('Cannot proceed: organization not set');
63
- return user.organizations[0].id;
93
+ return String(user.organizations[0].id);
64
94
  }
65
95
  /**
66
- * Verifica che `id` sia raggiungibile dall'utente del contesto, prima di una
67
- * scrittura distruttiva.
96
+ * Checks that `id` is reachable by the context user, ahead of a destructive write.
68
97
  *
69
- * Serve a colmare **T37**: `BaseModel.remove(id)` chiama `beforeRemove` e poi
70
- * `findByIdAndDelete(id)`, senza applicare né `updateFilters` né alcun vincolo di
71
- * `tenantId` — e `bulkRemove(ids)` non è che `ids.map(remove)`. Senza questo
72
- * controllo un utente qualsiasi cancella documenti di **altre organizzazioni**
73
- * conoscendone l'`_id`.
98
+ * Fills the gap of **T37**: `BaseModel.remove(id)` calls `beforeRemove` and then
99
+ * `findByIdAndDelete(id)`, applying neither `updateFilters` nor any `tenantId`
100
+ * constraint - and `bulkRemove(ids)` is nothing but `ids.map(remove)`. Without this
101
+ * check any user deletes documents belonging to OTHER organizations, knowing only
102
+ * their `_id`.
74
103
  *
75
- * Il controllo riusa `model.get`, che passa da `beforeGet` e quindi applica già lo
76
- * scoping del tenant: un solo punto di verità, nessuna regola di tenancy duplicata
77
- * qui. Ne consegue che i ruoli cross-tenant, per i quali `setTenant` non aggiunge
78
- * il filtro, continuano a cancellare ovunque — come previsto dalla matrice
79
- * ADR-0005 §4.
104
+ * The check reuses `model.get`, which goes through `beforeGet` and therefore already
105
+ * applies the tenant scoping: one single source of truth, no tenancy rule duplicated
106
+ * here. It follows that a cross-tenant role deletes in the organization it SELECTED,
107
+ * and in its own when it selected none - never across several at once, exactly as
108
+ * `resolveTenant` prescribes.
80
109
  *
81
- * **Fail-closed**: un `id` inesistente o fuori scope solleva un errore, senza
82
- * distinguere i due casi (non si conferma l'esistenza di un documento altrui).
110
+ * **Fail-closed**: a missing or out-of-scope `id` raises an error, without telling
111
+ * the two cases apart (the existence of someone else's document is never confirmed).
83
112
  *
84
- * @param model il modello su cui avviene la rimozione (`this` nell'hook)
85
- * @param id identificativo del documento
86
- * @param context contesto di richiesta, con l'utente autenticato
87
- * @returns lo stesso `id`, così da poter essere usato direttamente in `beforeRemove`
88
- * @throws `AppError('messages.notFound')` se il documento non è nello scope
113
+ * @param model the model the removal happens on (`this` inside the hook)
114
+ * @param id the document identifier
115
+ * @param context the request context, carrying the authenticated user
116
+ * @returns the same `id`, so it can be used directly inside `beforeRemove`
117
+ * @throws `AppError('messages.notFound')` when the document is out of scope
89
118
  */
90
119
  async function assertTenantScope(model, id, context = {}) {
91
120
  if (!await model.get(id, context))
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/utils/tenant.ts"],"names":[],"mappings":";AAAA;;;;;;;;+FAQ+F;;AAc/F,8BAcC;AAYD,0CASC;AASD,8BAMC;AA2BD,8CAMC;AA/FD,sDAA+E;AAE/E,4CAAuE;AAGvE;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,IAAc,EAAE,IAAe,EAAE,oBAAoB,GAAG,KAAK;IAErF,MAAM,OAAO,GAAI,IAAI,EAAE,OAAO,CAAC,wBAAY,CAAC,CAAC;IAE7C,2EAA2E;IAC3E,IAAI,OAAO,IAAI,CAAC,CAAC,oBAAoB,IAAI,IAAI,CAAC,QAAQ,CAAC;QACrD,OAAO;IAET,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAE1D,2DAA2D;IAC3D,kCAAkC;IAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,eAAe,CAAC,IAAS,EAAE,IAAe;IAExD,IAAI,IAAI,EAAE,OAAO,CAAC,wBAAY,CAAC;QAC7B,OAAO;IAET,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAE1D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,IAAe;IAEvC,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAE1D,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACI,KAAK,UAAU,iBAAiB,CAAC,KAAsB,EAAE,EAAU,EAAE,UAAqB,EAAE;IAEjG,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC;QAC/B,MAAM,IAAI,sBAAQ,CAAC,mBAAmB,CAAC,CAAC;IAE1C,OAAO,EAAE,CAAC;AACZ,CAAC"}
1
+ {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/utils/tenant.ts"],"names":[],"mappings":";AAAA;;;;;;;;;+FAS+F;;AAyC/F,sCAeC;AAcD,8BAGC;AAaD,8BAMC;AA0BD,8CAMC;AA1HD,sDAA+E;AAE/E,mCAAkE;AAGlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,SAAgB,aAAa,CAAC,IAAe,EAAE,KAAc;IAE3D,IAAI,CAAC,KAAK;QACR,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IAEzB,MAAM,SAAS,GAAG,IAAA,uBAAe,EAAC,IAAI,CAAC,CAAC;IAExC,sEAAsE;IACtE,IAAI,CAAC,SAAS;QACZ,OAAO,KAAK,CAAC;IAEf,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC5B,MAAM,IAAI,sBAAQ,CAAC,oBAAoB,CAAC,CAAC;IAE3C,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,SAAS,CAAC,IAAc,EAAE,UAAqB,EAAE;IAE/D,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,SAAS,CAAC,IAAe;IAEvC,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAE1D,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACI,KAAK,UAAU,iBAAiB,CAAC,KAAsB,EAAE,EAAU,EAAE,UAAqB,EAAE;IAEjG,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC;QAC/B,MAAM,IAAI,sBAAQ,CAAC,mBAAmB,CAAC,CAAC;IAE1C,OAAO,EAAE,CAAC;AACZ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextage/era-lib",
3
- "version": "1.0.191",
3
+ "version": "1.0.193",
4
4
  "main": "./build/index.js",
5
5
  "types": "./build/index.d.ts",
6
6
  "files": [