piper-utils 1.1.69 → 1.1.70

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "piper-utils",
3
- "version": "1.1.69",
3
+ "version": "1.1.70",
4
4
  "description": "Utility library for Piper",
5
5
  "main": "bin/main.js",
6
6
  "scripts": {
@@ -1,99 +1,128 @@
1
- import _ from 'lodash';
2
- import { ensurePartnerScope } from './accessContext.js';
3
- import { errorList } from '../../../requestResponse/errorCodes.js';
4
-
5
- /**
6
- * Scope a WHERE clause to the partner's own business (partnerBusinessId).
7
- * Use for "mine" resources: deal, activity, application, template.
8
- *
9
- * global → deletes where.businessId (super sees everything)
10
- * partner → sets where.businessId = partnerBusinessId
11
- * throws partnerNotConfigured if partnerBusinessId is missing
12
- * standard no-op (createFilters already handled)
13
- *
14
- * @param {object} where - Sequelize WHERE clause to mutate.
15
- * @param {object} access - Access object from resolveAccess.
16
- * @param {{ getPartnerById: Function }} deps
17
- */
18
- export async function scopeToOwnBusiness(where, access, { getPartnerById } = {}) {
19
- if (!access) {
20
- throw errorList.unauthorized;
21
- }
22
- if (access.level === 'global') {
23
- delete where.businessId;
24
- return;
25
- }
26
- if (access.level === 'partner') {
27
- await ensurePartnerScope(access, { getPartnerById });
28
- if (!access.partnerBusinessId) {
29
- throw errorList.partnerNotConfigured;
30
- }
31
- where.businessId = access.partnerBusinessId;
32
- return;
33
- }
34
- // standard → no-op (createFilters already injected from JWT)
35
- }
36
-
37
- /**
38
- * Scope a WHERE clause to the partner's portfolio (businessIds array).
39
- * Use for "book" resources (future transaction lists, merchant inbox views).
40
- *
41
- * global → deletes where.businessId
42
- * partner → sets where.businessId = businessIds[]
43
- * standard → no-op
44
- *
45
- * @param {object} where - Sequelize WHERE clause to mutate.
46
- * @param {object} access - Access object from resolveAccess.
47
- * @param {{ getPartnerById: Function }} deps
48
- */
49
- export async function scopeToPartnerBook(where, access, { getPartnerById } = {}) {
50
- if (!access) {
51
- throw errorList.unauthorized;
52
- }
53
- if (access.level === 'global') {
54
- delete where.businessId;
55
- return;
56
- }
57
- if (access.level === 'partner') {
58
- await ensurePartnerScope(access, { getPartnerById });
59
- where.businessId = access.businessIds || [];
60
- return;
61
- }
62
- // standard no-op
63
- }
64
-
65
- /**
66
- * Scope to the union of partnerBusinessId + businessIds.
67
- * Use for tickets — partner sees own tickets + portfolio merchants' tickets.
68
- *
69
- * global deletes where.businessId
70
- * partner → sets where.businessId = [partnerBusinessId, ...businessIds]
71
- * standard → sets where.businessId = access.businessIds
72
- * (explicitly handled here because ticket routes may not call
73
- * createFilters before scoping, e.g. delete/resolve handlers)
74
- *
75
- * @param {object} where - Sequelize WHERE clause to mutate.
76
- * @param {object} access - Access object from resolveAccess.
77
- * @param {{ getPartnerById: Function }} deps
78
- */
79
- export async function scopeToBookUnionOwn(where, access, { getPartnerById } = {}) {
80
- if (!access) {
81
- throw errorList.unauthorized;
82
- }
83
- if (access.level === 'global') {
84
- delete where.businessId;
85
- return;
86
- }
87
- if (access.level === 'partner') {
88
- await ensurePartnerScope(access, { getPartnerById });
89
- const ids = _.uniq(
90
- [access.partnerBusinessId, ...(access.businessIds || [])].filter(Boolean)
91
- );
92
- where.businessId = ids;
93
- return;
94
- }
95
- if (access.level === 'standard') {
96
- where.businessId = access.businessIds;
97
- return;
98
- }
99
- }
1
+ import _ from 'lodash';
2
+ import { ensurePartnerScope } from './accessContext.js';
3
+ import { errorList } from '../../../requestResponse/errorCodes.js';
4
+
5
+ // `requested` is the caller-supplied businessIds array (what the route extracts via
6
+ // getRequestedBusinessIds(event)). Empty array = no explicit filter (back-compat path).
7
+ // When non-empty it is intersected against the role's allowed set so a user can never
8
+ // widen their scope past what their role permits by passing a query-string businessId.
9
+
10
+ /**
11
+ * Scope a WHERE clause to the partner's own business (partnerBusinessId).
12
+ * Use for "mine" resources: deal, activity, application, template.
13
+ *
14
+ * global → requested ? where.businessId = requested : deletes where.businessId
15
+ * partner → requested ? [partnerBusinessId] requested : where.businessId = partnerBusinessId
16
+ * throws partnerNotConfigured if partnerBusinessId is missing
17
+ * standard → no-op (createFilters already handled)
18
+ *
19
+ * @param {object} where - Sequelize WHERE clause to mutate.
20
+ * @param {object} access - Access object from resolveAccess.
21
+ * @param {string[]} [requested] - Explicit businessIds from the query string.
22
+ * @param {{ getPartnerById: Function }} deps
23
+ */
24
+ export async function scopeToOwnBusiness(where, access, requested = [], { getPartnerById } = {}) {
25
+ if (!access) {
26
+ throw errorList.unauthorized;
27
+ }
28
+ if (access.level === 'global') {
29
+ if (requested.length) {
30
+ where.businessId = requested;
31
+ } else {
32
+ delete where.businessId;
33
+ }
34
+ return;
35
+ }
36
+ if (access.level === 'partner') {
37
+ await ensurePartnerScope(access, { getPartnerById });
38
+ if (!access.partnerBusinessId) {
39
+ throw errorList.partnerNotConfigured;
40
+ }
41
+ if (requested.length) {
42
+ where.businessId = _.intersection([access.partnerBusinessId], requested);
43
+ } else {
44
+ where.businessId = access.partnerBusinessId;
45
+ }
46
+ return;
47
+ }
48
+ // standard → no-op (createFilters already injected from JWT)
49
+ }
50
+
51
+ /**
52
+ * Scope a WHERE clause to the partner's portfolio (businessIds array).
53
+ * Use for "book" resources (future transaction lists, merchant inbox views).
54
+ *
55
+ * global → requested ? where.businessId = requested : deletes where.businessId
56
+ * partner → requested ? businessIds ∩ requested : where.businessId = businessIds[]
57
+ * (own business is intentionally excluded — book is portfolio only)
58
+ * standard no-op
59
+ *
60
+ * @param {object} where - Sequelize WHERE clause to mutate.
61
+ * @param {object} access - Access object from resolveAccess.
62
+ * @param {string[]} [requested] - Explicit businessIds from the query string.
63
+ * @param {{ getPartnerById: Function }} deps
64
+ */
65
+ export async function scopeToPartnerBook(where, access, requested = [], { getPartnerById } = {}) {
66
+ if (!access) {
67
+ throw errorList.unauthorized;
68
+ }
69
+ if (access.level === 'global') {
70
+ if (requested.length) {
71
+ where.businessId = requested;
72
+ } else {
73
+ delete where.businessId;
74
+ }
75
+ return;
76
+ }
77
+ if (access.level === 'partner') {
78
+ await ensurePartnerScope(access, { getPartnerById });
79
+ const allowed = access.businessIds || [];
80
+ where.businessId = requested.length ? _.intersection(allowed, requested) : allowed;
81
+ return;
82
+ }
83
+ // standard no-op
84
+ }
85
+
86
+ /**
87
+ * Scope to the union of partnerBusinessId + businessIds.
88
+ * Use for tickets — partner sees own tickets + portfolio merchants' tickets.
89
+ *
90
+ * global → requested ? where.businessId = requested : deletes where.businessId
91
+ * partner → allowed = uniq([partnerBusinessId, ...businessIds]);
92
+ * requested ? allowed ∩ requested : where.businessId = allowed
93
+ * standard → allowed = businessIds;
94
+ * requested ? allowed ∩ requested : where.businessId = allowed
95
+ * (explicitly handled here because ticket routes may not call
96
+ * createFilters before scoping, e.g. delete/resolve handlers)
97
+ *
98
+ * @param {object} where - Sequelize WHERE clause to mutate.
99
+ * @param {object} access - Access object from resolveAccess.
100
+ * @param {string[]} [requested] - Explicit businessIds from the query string.
101
+ * @param {{ getPartnerById: Function }} deps
102
+ */
103
+ export async function scopeToBookUnionOwn(where, access, requested = [], { getPartnerById } = {}) {
104
+ if (!access) {
105
+ throw errorList.unauthorized;
106
+ }
107
+ if (access.level === 'global') {
108
+ if (requested.length) {
109
+ where.businessId = requested;
110
+ } else {
111
+ delete where.businessId;
112
+ }
113
+ return;
114
+ }
115
+ if (access.level === 'partner') {
116
+ await ensurePartnerScope(access, { getPartnerById });
117
+ const allowed = _.uniq(
118
+ [access.partnerBusinessId, ...(access.businessIds || [])].filter(Boolean)
119
+ );
120
+ where.businessId = requested.length ? _.intersection(allowed, requested) : allowed;
121
+ return;
122
+ }
123
+ if (access.level === 'standard') {
124
+ const allowed = access.businessIds || [];
125
+ where.businessId = requested.length ? _.intersection(allowed, requested) : allowed;
126
+ return;
127
+ }
128
+ }
@@ -27,9 +27,9 @@ export function createAccessHelpers({ getPartnerById }) {
27
27
  const deps = { getPartnerById };
28
28
  return {
29
29
  ensurePartnerScope: (access) => ensurePartnerScope(access, deps),
30
- scopeToOwnBusiness: (where, access) => scopeToOwnBusiness(where, access, deps),
31
- scopeToPartnerBook: (where, access) => scopeToPartnerBook(where, access, deps),
32
- scopeToBookUnionOwn: (where, access) => scopeToBookUnionOwn(where, access, deps),
30
+ scopeToOwnBusiness: (where, access, requested) => scopeToOwnBusiness(where, access, requested, deps),
31
+ scopeToPartnerBook: (where, access, requested) => scopeToPartnerBook(where, access, requested, deps),
32
+ scopeToBookUnionOwn: (where, access, requested) => scopeToBookUnionOwn(where, access, requested, deps),
33
33
  assertCanWriteOwnBusiness: (access, businessId) => assertCanWriteOwnBusiness(access, businessId, deps),
34
34
  assertCanWriteBookBusiness: (access, businessId) => assertCanWriteBookBusiness(access, businessId, deps),
35
35
  assertCanWriteBookUnionOwn: (access, businessId) => assertCanWriteBookUnionOwn(access, businessId, deps),