@floristcloud/api-lib 1.2.91 → 1.2.94

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.
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GetAccessPolicyContractQuery = void 0;
4
+ const zod_1 = require("zod");
5
+ const access_policy_schema_1 = require("../../schemas/access-policy/access-policy.schema");
6
+ const GetAccessPolicyResponseSchema = zod_1.z.object({
7
+ message: zod_1.z.string().optional(),
8
+ data: access_policy_schema_1.AccessPolicySchema,
9
+ });
10
+ var GetAccessPolicyContractQuery;
11
+ (function (GetAccessPolicyContractQuery) {
12
+ GetAccessPolicyContractQuery.ResponseSchema = GetAccessPolicyResponseSchema;
13
+ })(GetAccessPolicyContractQuery || (exports.GetAccessPolicyContractQuery = GetAccessPolicyContractQuery = {}));
@@ -0,0 +1,18 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./get-access-policy.query"), exports);
18
+ __exportStar(require("./upsert-access-policy.command"), exports);
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UpsertAccessPolicyContractCommand = void 0;
4
+ const zod_1 = require("zod");
5
+ const access_policy_schema_1 = require("../../schemas/access-policy/access-policy.schema");
6
+ const UpsertAccessPolicyRequestSchema = access_policy_schema_1.AccessPolicySchema;
7
+ const UpsertAccessPolicyResponseSchema = zod_1.z.object({
8
+ message: zod_1.z.string().optional(),
9
+ data: access_policy_schema_1.AccessPolicySchema,
10
+ });
11
+ var UpsertAccessPolicyContractCommand;
12
+ (function (UpsertAccessPolicyContractCommand) {
13
+ UpsertAccessPolicyContractCommand.RequestSchema = UpsertAccessPolicyRequestSchema;
14
+ UpsertAccessPolicyContractCommand.ResponseSchema = UpsertAccessPolicyResponseSchema;
15
+ })(UpsertAccessPolicyContractCommand || (exports.UpsertAccessPolicyContractCommand = UpsertAccessPolicyContractCommand = {}));
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.ValidateWsTicketS2SContractQuery = exports.CreateWsTicketContractCommand = exports.ValidateSessionS2SContractQuery = exports.GetActiveSessionsContractQuery = exports.SessionRevokeAllContractCommand = exports.SessionLogoutContractCommand = void 0;
18
+ __exportStar(require("./access-policy"), exports);
18
19
  __exportStar(require("./auth"), exports);
19
20
  __exportStar(require("./branch"), exports);
20
21
  __exportStar(require("./category"), exports);
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GetMeContractQuery = void 0;
4
+ const zod_1 = require("zod");
5
+ const schemas_1 = require("../../schemas");
6
+ const access_policy_schema_1 = require("../../schemas/access-policy/access-policy.schema");
7
+ const GetMeResponseSchema = zod_1.z.object({
8
+ message: zod_1.z.string().optional(),
9
+ data: zod_1.z.object({
10
+ user: schemas_1.UserSchema.omit({ passwordHash: true, restoreTokenHash: true }),
11
+ permissions: access_policy_schema_1.EffectivePermissionsSchema,
12
+ }),
13
+ });
14
+ var GetMeContractQuery;
15
+ (function (GetMeContractQuery) {
16
+ GetMeContractQuery.ResponseSchema = GetMeResponseSchema;
17
+ })(GetMeContractQuery || (exports.GetMeContractQuery = GetMeContractQuery = {}));
@@ -19,6 +19,7 @@ __exportStar(require("./attachUserToCompany.command"), exports);
19
19
  __exportStar(require("./createUserByClientId.command"), exports);
20
20
  __exportStar(require("./updateRole.command"), exports);
21
21
  __exportStar(require("./getUser.command"), exports);
22
+ __exportStar(require("./get-me.query"), exports);
22
23
  __exportStar(require("./createUserForCompany.command"), exports);
23
24
  __exportStar(require("./get-user-list.query"), exports);
24
25
  __exportStar(require("./get-user-list-s2s.query"), exports);
@@ -1229,4 +1229,6 @@ exports.ERRORS = {
1229
1229
  httpCode: 404,
1230
1230
  },
1231
1231
  CONSIGNMENT_TRANSFER_ACCEPT_FAILED: { code: 'CTR013', message: 'Failed to accept consignment transfer request', httpCode: 500 },
1232
+ ACCESS_POLICY_FETCH_FAILED: { code: 'AP001', message: 'Error when retrieving the access policy', httpCode: 500 },
1233
+ ACCESS_POLICY_NOT_UPDATED: { code: 'AP002', message: 'Failed to update the access policy', httpCode: 500 },
1232
1234
  };
@@ -108,3 +108,4 @@ __exportStar(require("./moysklad-sync-status.enum"), exports);
108
108
  __exportStar(require("./consignment-transfer-request-status.enum"), exports);
109
109
  __exportStar(require("./consignment-transfer-direction.enum"), exports);
110
110
  __exportStar(require("./legal-identifier-field.enum"), exports);
111
+ __exportStar(require("./permission-key.enum"), exports);
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PERMISSION_KEY_LIST = exports.PermissionKeyEnum = void 0;
4
+ var PermissionKeyEnum;
5
+ (function (PermissionKeyEnum) {
6
+ PermissionKeyEnum["PRODUCT_VIEW"] = "product.view";
7
+ PermissionKeyEnum["PRODUCT_EDIT"] = "product.edit";
8
+ PermissionKeyEnum["PRODUCT_DELETE"] = "product.delete";
9
+ PermissionKeyEnum["CONSIGNMENT_VIEW"] = "consignment.view";
10
+ PermissionKeyEnum["CONSIGNMENT_EDIT"] = "consignment.edit";
11
+ PermissionKeyEnum["CONSIGNMENT_DELETE"] = "consignment.delete";
12
+ PermissionKeyEnum["COST_VIEW"] = "cost.view";
13
+ })(PermissionKeyEnum || (exports.PermissionKeyEnum = PermissionKeyEnum = {}));
14
+ exports.PERMISSION_KEY_LIST = [
15
+ PermissionKeyEnum.PRODUCT_VIEW,
16
+ PermissionKeyEnum.PRODUCT_EDIT,
17
+ PermissionKeyEnum.PRODUCT_DELETE,
18
+ PermissionKeyEnum.CONSIGNMENT_VIEW,
19
+ PermissionKeyEnum.CONSIGNMENT_EDIT,
20
+ PermissionKeyEnum.CONSIGNMENT_DELETE,
21
+ PermissionKeyEnum.COST_VIEW,
22
+ ];
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeStoredAccessPolicy = exports.EffectivePermissionsSchema = exports.AccessPolicySchema = exports.PermissionMapSchema = exports.CONFIGURABLE_PANEL_ROLE_LIST = void 0;
4
+ const zod_1 = require("zod");
5
+ const permission_key_enum_1 = require("../../enum/permission-key.enum");
6
+ const userRole_enum_1 = require("../../enum/userRole.enum");
7
+ /**
8
+ * Panel roles that can actually be configured. ADMIN is intentionally excluded:
9
+ * it always bypasses UI restrictions, so any ADMIN entry in a policy is dead
10
+ * config. The admin panel must not offer it, and the sanitizer drops it.
11
+ */
12
+ exports.CONFIGURABLE_PANEL_ROLE_LIST = [userRole_enum_1.UserPanelRoleEnum.MANAGER, userRole_enum_1.UserPanelRoleEnum.EMPLOYEE];
13
+ /**
14
+ * A sparse map of permission key -> boolean.
15
+ * Semantics are default-allow: a missing key means "allowed", so in practice
16
+ * only explicit `false` (denials) are ever stored.
17
+ */
18
+ exports.PermissionMapSchema = zod_1.z.partialRecord(zod_1.z.nativeEnum(permission_key_enum_1.PermissionKeyEnum), zod_1.z.boolean());
19
+ /**
20
+ * Full company access policy — the raw configuration edited by an admin.
21
+ * `roles` holds per-role denials; `users` holds per-employee overrides keyed by userUUID.
22
+ */
23
+ exports.AccessPolicySchema = zod_1.z.object({
24
+ roles: zod_1.z.partialRecord(zod_1.z.nativeEnum(userRole_enum_1.UserPanelRoleEnum), exports.PermissionMapSchema).default({}),
25
+ users: zod_1.z.record(zod_1.z.uuid(), exports.PermissionMapSchema).default({}),
26
+ });
27
+ /**
28
+ * Resolved permissions for a single user — the sparse denial map after merging
29
+ * role defaults with the user's own overrides. Empty for ADMIN / global users.
30
+ * Frontend contract: `can(key) === effective[key] !== false`.
31
+ */
32
+ exports.EffectivePermissionsSchema = exports.PermissionMapSchema;
33
+ const pickPermissionMap = (value) => {
34
+ const map = {};
35
+ if (value && typeof value === 'object') {
36
+ const record = value;
37
+ for (const key of permission_key_enum_1.PERMISSION_KEY_LIST) {
38
+ if (typeof record[key] === 'boolean') {
39
+ map[key] = record[key];
40
+ }
41
+ }
42
+ }
43
+ return map;
44
+ };
45
+ /**
46
+ * Tolerant reader for a stored policy blob. Unlike `AccessPolicySchema.parse`,
47
+ * this NEVER throws on unknown/renamed keys — it strips anything not in the
48
+ * current `PermissionKeyEnum` / configurable roles and keeps the rest.
49
+ *
50
+ * Why: `AccessPolicySchema` uses `partialRecord`, which throws "Invalid key in
51
+ * record" on an unknown key. If a permission key or role is ever renamed/removed
52
+ * while a company still has the old value persisted, a strict parse at the read
53
+ * boundary would bubble up as a 500 from `getMe` for every user in that company.
54
+ * Adding keys is safe; removing/renaming must degrade gracefully — hence this.
55
+ */
56
+ const sanitizeStoredAccessPolicy = (raw) => {
57
+ const source = raw && typeof raw === 'object' ? raw : {};
58
+ const roles = {};
59
+ const rawRoles = source.roles && typeof source.roles === 'object' ? source.roles : {};
60
+ for (const role of exports.CONFIGURABLE_PANEL_ROLE_LIST) {
61
+ if (role in rawRoles) {
62
+ roles[role] = pickPermissionMap(rawRoles[role]);
63
+ }
64
+ }
65
+ const users = {};
66
+ const rawUsers = source.users && typeof source.users === 'object' ? source.users : {};
67
+ for (const userUUID of Object.keys(rawUsers)) {
68
+ users[userUUID] = pickPermissionMap(rawUsers[userUUID]);
69
+ }
70
+ return { roles, users };
71
+ };
72
+ exports.sanitizeStoredAccessPolicy = sanitizeStoredAccessPolicy;
@@ -0,0 +1,17 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./access-policy.schema"), exports);
@@ -83,3 +83,4 @@ __exportStar(require("./messenger-profile"), exports);
83
83
  __exportStar(require("./error-message.schema"), exports);
84
84
  __exportStar(require("./account-deletion-request/account-deletion-request.schema"), exports);
85
85
  __exportStar(require("./consignment-transfer"), exports);
86
+ __exportStar(require("./access-policy"), exports);
@@ -0,0 +1,12 @@
1
+ import { z } from 'zod';
2
+ import { AccessPolicySchema } from '../../schemas/access-policy/access-policy.schema';
3
+
4
+ const GetAccessPolicyResponseSchema = z.object({
5
+ message: z.string().optional(),
6
+ data: AccessPolicySchema,
7
+ });
8
+
9
+ export namespace GetAccessPolicyContractQuery {
10
+ export const ResponseSchema = GetAccessPolicyResponseSchema;
11
+ export type Response = z.infer<typeof ResponseSchema>;
12
+ }
@@ -0,0 +1,2 @@
1
+ export * from './get-access-policy.query';
2
+ export * from './upsert-access-policy.command';
@@ -0,0 +1,17 @@
1
+ import { z } from 'zod';
2
+ import { AccessPolicySchema } from '../../schemas/access-policy/access-policy.schema';
3
+
4
+ const UpsertAccessPolicyRequestSchema = AccessPolicySchema;
5
+
6
+ const UpsertAccessPolicyResponseSchema = z.object({
7
+ message: z.string().optional(),
8
+ data: AccessPolicySchema,
9
+ });
10
+
11
+ export namespace UpsertAccessPolicyContractCommand {
12
+ export const RequestSchema = UpsertAccessPolicyRequestSchema;
13
+ export type Request = z.infer<typeof RequestSchema>;
14
+
15
+ export const ResponseSchema = UpsertAccessPolicyResponseSchema;
16
+ export type Response = z.infer<typeof ResponseSchema>;
17
+ }
package/commands/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './access-policy';
1
2
  export * from './auth';
2
3
  export * from './branch';
3
4
  export * from './category';
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod';
2
+ import { UserSchema } from '../../schemas';
3
+ import { EffectivePermissionsSchema } from '../../schemas/access-policy/access-policy.schema';
4
+
5
+ const GetMeResponseSchema = z.object({
6
+ message: z.string().optional(),
7
+ data: z.object({
8
+ user: UserSchema.omit({ passwordHash: true, restoreTokenHash: true }),
9
+ permissions: EffectivePermissionsSchema,
10
+ }),
11
+ });
12
+
13
+ export namespace GetMeContractQuery {
14
+ export const ResponseSchema = GetMeResponseSchema;
15
+ export type Response = z.infer<typeof ResponseSchema>;
16
+ }
@@ -3,6 +3,7 @@ export * from './attachUserToCompany.command';
3
3
  export * from './createUserByClientId.command';
4
4
  export * from './updateRole.command';
5
5
  export * from './getUser.command';
6
+ export * from './get-me.query';
6
7
  export * from './createUserForCompany.command';
7
8
  export * from './get-user-list.query';
8
9
  export * from './get-user-list-s2s.query';
package/constant/error.ts CHANGED
@@ -1294,4 +1294,6 @@ export const ERRORS = {
1294
1294
  httpCode: 404,
1295
1295
  },
1296
1296
  CONSIGNMENT_TRANSFER_ACCEPT_FAILED: { code: 'CTR013', message: 'Failed to accept consignment transfer request', httpCode: 500 },
1297
+ ACCESS_POLICY_FETCH_FAILED: { code: 'AP001', message: 'Error when retrieving the access policy', httpCode: 500 },
1298
+ ACCESS_POLICY_NOT_UPDATED: { code: 'AP002', message: 'Failed to update the access policy', httpCode: 500 },
1297
1299
  } as const;
package/enum/index.ts CHANGED
@@ -92,3 +92,4 @@ export * from './moysklad-sync-status.enum';
92
92
  export * from './consignment-transfer-request-status.enum';
93
93
  export * from './consignment-transfer-direction.enum';
94
94
  export * from './legal-identifier-field.enum';
95
+ export * from './permission-key.enum';
@@ -0,0 +1,19 @@
1
+ export enum PermissionKeyEnum {
2
+ PRODUCT_VIEW = 'product.view',
3
+ PRODUCT_EDIT = 'product.edit',
4
+ PRODUCT_DELETE = 'product.delete',
5
+ CONSIGNMENT_VIEW = 'consignment.view',
6
+ CONSIGNMENT_EDIT = 'consignment.edit',
7
+ CONSIGNMENT_DELETE = 'consignment.delete',
8
+ COST_VIEW = 'cost.view',
9
+ }
10
+
11
+ export const PERMISSION_KEY_LIST: PermissionKeyEnum[] = [
12
+ PermissionKeyEnum.PRODUCT_VIEW,
13
+ PermissionKeyEnum.PRODUCT_EDIT,
14
+ PermissionKeyEnum.PRODUCT_DELETE,
15
+ PermissionKeyEnum.CONSIGNMENT_VIEW,
16
+ PermissionKeyEnum.CONSIGNMENT_EDIT,
17
+ PermissionKeyEnum.CONSIGNMENT_DELETE,
18
+ PermissionKeyEnum.COST_VIEW,
19
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floristcloud/api-lib",
3
- "version": "1.2.91",
3
+ "version": "1.2.94",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "scripts": {
@@ -0,0 +1,80 @@
1
+ import { z } from 'zod';
2
+ import { PermissionKeyEnum, PERMISSION_KEY_LIST } from '../../enum/permission-key.enum';
3
+ import { UserPanelRoleEnum } from '../../enum/userRole.enum';
4
+
5
+ /**
6
+ * Panel roles that can actually be configured. ADMIN is intentionally excluded:
7
+ * it always bypasses UI restrictions, so any ADMIN entry in a policy is dead
8
+ * config. The admin panel must not offer it, and the sanitizer drops it.
9
+ */
10
+ export const CONFIGURABLE_PANEL_ROLE_LIST: UserPanelRoleEnum[] = [UserPanelRoleEnum.MANAGER, UserPanelRoleEnum.EMPLOYEE];
11
+
12
+ /**
13
+ * A sparse map of permission key -> boolean.
14
+ * Semantics are default-allow: a missing key means "allowed", so in practice
15
+ * only explicit `false` (denials) are ever stored.
16
+ */
17
+ export const PermissionMapSchema = z.partialRecord(z.nativeEnum(PermissionKeyEnum), z.boolean());
18
+ export type PermissionMap = z.infer<typeof PermissionMapSchema>;
19
+
20
+ /**
21
+ * Full company access policy — the raw configuration edited by an admin.
22
+ * `roles` holds per-role denials; `users` holds per-employee overrides keyed by userUUID.
23
+ */
24
+ export const AccessPolicySchema = z.object({
25
+ roles: z.partialRecord(z.nativeEnum(UserPanelRoleEnum), PermissionMapSchema).default({}),
26
+ users: z.record(z.uuid(), PermissionMapSchema).default({}),
27
+ });
28
+ export type AccessPolicy = z.infer<typeof AccessPolicySchema>;
29
+
30
+ /**
31
+ * Resolved permissions for a single user — the sparse denial map after merging
32
+ * role defaults with the user's own overrides. Empty for ADMIN / global users.
33
+ * Frontend contract: `can(key) === effective[key] !== false`.
34
+ */
35
+ export const EffectivePermissionsSchema = PermissionMapSchema;
36
+ export type EffectivePermissions = z.infer<typeof EffectivePermissionsSchema>;
37
+
38
+ const pickPermissionMap = (value: unknown): PermissionMap => {
39
+ const map: PermissionMap = {};
40
+ if (value && typeof value === 'object') {
41
+ const record = value as Record<string, unknown>;
42
+ for (const key of PERMISSION_KEY_LIST) {
43
+ if (typeof record[key] === 'boolean') {
44
+ map[key] = record[key] as boolean;
45
+ }
46
+ }
47
+ }
48
+ return map;
49
+ };
50
+
51
+ /**
52
+ * Tolerant reader for a stored policy blob. Unlike `AccessPolicySchema.parse`,
53
+ * this NEVER throws on unknown/renamed keys — it strips anything not in the
54
+ * current `PermissionKeyEnum` / configurable roles and keeps the rest.
55
+ *
56
+ * Why: `AccessPolicySchema` uses `partialRecord`, which throws "Invalid key in
57
+ * record" on an unknown key. If a permission key or role is ever renamed/removed
58
+ * while a company still has the old value persisted, a strict parse at the read
59
+ * boundary would bubble up as a 500 from `getMe` for every user in that company.
60
+ * Adding keys is safe; removing/renaming must degrade gracefully — hence this.
61
+ */
62
+ export const sanitizeStoredAccessPolicy = (raw: unknown): AccessPolicy => {
63
+ const source = raw && typeof raw === 'object' ? (raw as Record<string, unknown>) : {};
64
+
65
+ const roles: AccessPolicy['roles'] = {};
66
+ const rawRoles = source.roles && typeof source.roles === 'object' ? (source.roles as Record<string, unknown>) : {};
67
+ for (const role of CONFIGURABLE_PANEL_ROLE_LIST) {
68
+ if (role in rawRoles) {
69
+ roles[role] = pickPermissionMap(rawRoles[role]);
70
+ }
71
+ }
72
+
73
+ const users: AccessPolicy['users'] = {};
74
+ const rawUsers = source.users && typeof source.users === 'object' ? (source.users as Record<string, unknown>) : {};
75
+ for (const userUUID of Object.keys(rawUsers)) {
76
+ users[userUUID] = pickPermissionMap(rawUsers[userUUID]);
77
+ }
78
+
79
+ return { roles, users };
80
+ };
@@ -0,0 +1 @@
1
+ export * from './access-policy.schema';
package/schemas/index.ts CHANGED
@@ -67,3 +67,4 @@ export * from './messenger-profile';
67
67
  export * from './error-message.schema';
68
68
  export * from './account-deletion-request/account-deletion-request.schema';
69
69
  export * from './consignment-transfer';
70
+ export * from './access-policy';