@uniforge/core 0.1.0-alpha.2
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/dist/auth/index.d.cts +165 -0
- package/dist/auth/index.d.ts +165 -0
- package/dist/auth/index.js +443 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/index.mjs +406 -0
- package/dist/auth/index.mjs.map +1 -0
- package/dist/billing/index.d.cts +34 -0
- package/dist/billing/index.d.ts +34 -0
- package/dist/billing/index.js +254 -0
- package/dist/billing/index.js.map +1 -0
- package/dist/billing/index.mjs +225 -0
- package/dist/billing/index.mjs.map +1 -0
- package/dist/config/index.d.cts +12 -0
- package/dist/config/index.d.ts +12 -0
- package/dist/config/index.js +186 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.mjs +156 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/database/index.d.cts +33 -0
- package/dist/database/index.d.ts +33 -0
- package/dist/database/index.js +127 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/index.mjs +95 -0
- package/dist/database/index.mjs.map +1 -0
- package/dist/graphql/index.d.cts +36 -0
- package/dist/graphql/index.d.ts +36 -0
- package/dist/graphql/index.js +209 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/index.mjs +179 -0
- package/dist/graphql/index.mjs.map +1 -0
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +1 -0
- package/dist/multi-store/index.d.cts +11 -0
- package/dist/multi-store/index.d.ts +11 -0
- package/dist/multi-store/index.js +473 -0
- package/dist/multi-store/index.js.map +1 -0
- package/dist/multi-store/index.mjs +447 -0
- package/dist/multi-store/index.mjs.map +1 -0
- package/dist/multi-tenant/index.d.cts +23 -0
- package/dist/multi-tenant/index.d.ts +23 -0
- package/dist/multi-tenant/index.js +69 -0
- package/dist/multi-tenant/index.js.map +1 -0
- package/dist/multi-tenant/index.mjs +41 -0
- package/dist/multi-tenant/index.mjs.map +1 -0
- package/dist/performance/index.d.cts +34 -0
- package/dist/performance/index.d.ts +34 -0
- package/dist/performance/index.js +319 -0
- package/dist/performance/index.js.map +1 -0
- package/dist/performance/index.mjs +290 -0
- package/dist/performance/index.mjs.map +1 -0
- package/dist/platform/index.d.cts +25 -0
- package/dist/platform/index.d.ts +25 -0
- package/dist/platform/index.js +91 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/index.mjs +62 -0
- package/dist/platform/index.mjs.map +1 -0
- package/dist/rbac/index.d.cts +24 -0
- package/dist/rbac/index.d.ts +24 -0
- package/dist/rbac/index.js +267 -0
- package/dist/rbac/index.js.map +1 -0
- package/dist/rbac/index.mjs +236 -0
- package/dist/rbac/index.mjs.map +1 -0
- package/dist/schema-CM7mHj_H.d.cts +53 -0
- package/dist/schema-CM7mHj_H.d.ts +53 -0
- package/dist/security/index.d.cts +47 -0
- package/dist/security/index.d.ts +47 -0
- package/dist/security/index.js +505 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/index.mjs +474 -0
- package/dist/security/index.mjs.map +1 -0
- package/dist/session-storage/index.d.cts +70 -0
- package/dist/session-storage/index.d.ts +70 -0
- package/dist/session-storage/index.js +271 -0
- package/dist/session-storage/index.js.map +1 -0
- package/dist/session-storage/index.mjs +242 -0
- package/dist/session-storage/index.mjs.map +1 -0
- package/dist/webhooks/index.d.cts +89 -0
- package/dist/webhooks/index.d.ts +89 -0
- package/dist/webhooks/index.js +380 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/index.mjs +348 -0
- package/dist/webhooks/index.mjs.map +1 -0
- package/package.json +119 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
// src/multi-store/account-service.ts
|
|
2
|
+
import { ACCOUNT_ROLE_HIERARCHY } from "@uniforge/platform-core/multi-store";
|
|
3
|
+
function mapAccount(row) {
|
|
4
|
+
return {
|
|
5
|
+
id: row.id,
|
|
6
|
+
name: row.name,
|
|
7
|
+
type: row.type,
|
|
8
|
+
isActive: row.isActive,
|
|
9
|
+
createdAt: row.createdAt,
|
|
10
|
+
updatedAt: row.updatedAt
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function mapAccountStore(row) {
|
|
14
|
+
return {
|
|
15
|
+
id: row.id,
|
|
16
|
+
accountId: row.accountId,
|
|
17
|
+
shopDomain: row.shopDomain,
|
|
18
|
+
storeName: row.storeName,
|
|
19
|
+
region: row.region ?? null,
|
|
20
|
+
currency: row.currency ?? null,
|
|
21
|
+
locale: row.locale ?? null,
|
|
22
|
+
timezone: row.timezone ?? null,
|
|
23
|
+
storeSettings: row.storeSettings && typeof row.storeSettings === "object" ? row.storeSettings : {},
|
|
24
|
+
isActive: row.isActive,
|
|
25
|
+
isPrimary: row.isPrimary,
|
|
26
|
+
createdAt: row.createdAt,
|
|
27
|
+
updatedAt: row.updatedAt
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function mapAccountMember(row) {
|
|
31
|
+
return {
|
|
32
|
+
id: row.id,
|
|
33
|
+
accountId: row.accountId,
|
|
34
|
+
userEmail: row.userEmail,
|
|
35
|
+
role: row.role,
|
|
36
|
+
allStoresAccess: row.allStoresAccess,
|
|
37
|
+
allowedStoreIds: Array.isArray(row.allowedStoreIds) ? row.allowedStoreIds : [],
|
|
38
|
+
permissions: Array.isArray(row.permissions) ? row.permissions : [],
|
|
39
|
+
createdAt: row.createdAt,
|
|
40
|
+
updatedAt: row.updatedAt
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function createAccountService(prisma) {
|
|
44
|
+
return {
|
|
45
|
+
async createAccount(input) {
|
|
46
|
+
const row = await prisma.account.create({
|
|
47
|
+
data: {
|
|
48
|
+
name: input.name,
|
|
49
|
+
type: input.type
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return mapAccount(row);
|
|
53
|
+
},
|
|
54
|
+
async getAccount(accountId) {
|
|
55
|
+
const row = await prisma.account.findUnique({
|
|
56
|
+
where: { id: accountId }
|
|
57
|
+
});
|
|
58
|
+
if (!row) return null;
|
|
59
|
+
return mapAccount(row);
|
|
60
|
+
},
|
|
61
|
+
async updateAccount(accountId, input) {
|
|
62
|
+
const data = {};
|
|
63
|
+
if (input.name !== void 0) {
|
|
64
|
+
data.name = input.name;
|
|
65
|
+
}
|
|
66
|
+
if (input.type !== void 0) {
|
|
67
|
+
data.type = input.type;
|
|
68
|
+
}
|
|
69
|
+
if (input.isActive !== void 0) {
|
|
70
|
+
data.isActive = input.isActive;
|
|
71
|
+
}
|
|
72
|
+
const row = await prisma.account.update({
|
|
73
|
+
where: { id: accountId },
|
|
74
|
+
data
|
|
75
|
+
});
|
|
76
|
+
return mapAccount(row);
|
|
77
|
+
},
|
|
78
|
+
async deleteAccount(accountId) {
|
|
79
|
+
await prisma.account.delete({ where: { id: accountId } });
|
|
80
|
+
},
|
|
81
|
+
async addStore(input) {
|
|
82
|
+
const data = {
|
|
83
|
+
accountId: input.accountId,
|
|
84
|
+
shopDomain: input.shopDomain,
|
|
85
|
+
storeName: input.storeName
|
|
86
|
+
};
|
|
87
|
+
if (input.region !== void 0) {
|
|
88
|
+
data.region = input.region;
|
|
89
|
+
}
|
|
90
|
+
if (input.currency !== void 0) {
|
|
91
|
+
data.currency = input.currency;
|
|
92
|
+
}
|
|
93
|
+
if (input.locale !== void 0) {
|
|
94
|
+
data.locale = input.locale;
|
|
95
|
+
}
|
|
96
|
+
if (input.timezone !== void 0) {
|
|
97
|
+
data.timezone = input.timezone;
|
|
98
|
+
}
|
|
99
|
+
if (input.storeSettings !== void 0) {
|
|
100
|
+
data.storeSettings = input.storeSettings;
|
|
101
|
+
}
|
|
102
|
+
if (input.isPrimary !== void 0) {
|
|
103
|
+
data.isPrimary = input.isPrimary;
|
|
104
|
+
}
|
|
105
|
+
const row = await prisma.accountStore.create({ data });
|
|
106
|
+
return mapAccountStore(row);
|
|
107
|
+
},
|
|
108
|
+
async getStore(storeId) {
|
|
109
|
+
const row = await prisma.accountStore.findUnique({
|
|
110
|
+
where: { id: storeId }
|
|
111
|
+
});
|
|
112
|
+
if (!row) return null;
|
|
113
|
+
return mapAccountStore(row);
|
|
114
|
+
},
|
|
115
|
+
async getStoreByDomain(shopDomain) {
|
|
116
|
+
const row = await prisma.accountStore.findUnique({
|
|
117
|
+
where: { shopDomain }
|
|
118
|
+
});
|
|
119
|
+
if (!row) return null;
|
|
120
|
+
return mapAccountStore(row);
|
|
121
|
+
},
|
|
122
|
+
async listStores(accountId) {
|
|
123
|
+
const rows = await prisma.accountStore.findMany({
|
|
124
|
+
where: { accountId }
|
|
125
|
+
});
|
|
126
|
+
return rows.map(mapAccountStore);
|
|
127
|
+
},
|
|
128
|
+
async updateStore(storeId, input) {
|
|
129
|
+
const data = {};
|
|
130
|
+
if (input.storeName !== void 0) {
|
|
131
|
+
data.storeName = input.storeName;
|
|
132
|
+
}
|
|
133
|
+
if (input.region !== void 0) {
|
|
134
|
+
data.region = input.region;
|
|
135
|
+
}
|
|
136
|
+
if (input.currency !== void 0) {
|
|
137
|
+
data.currency = input.currency;
|
|
138
|
+
}
|
|
139
|
+
if (input.locale !== void 0) {
|
|
140
|
+
data.locale = input.locale;
|
|
141
|
+
}
|
|
142
|
+
if (input.timezone !== void 0) {
|
|
143
|
+
data.timezone = input.timezone;
|
|
144
|
+
}
|
|
145
|
+
if (input.storeSettings !== void 0) {
|
|
146
|
+
data.storeSettings = input.storeSettings;
|
|
147
|
+
}
|
|
148
|
+
if (input.isActive !== void 0) {
|
|
149
|
+
data.isActive = input.isActive;
|
|
150
|
+
}
|
|
151
|
+
if (input.isPrimary !== void 0) {
|
|
152
|
+
data.isPrimary = input.isPrimary;
|
|
153
|
+
}
|
|
154
|
+
const row = await prisma.accountStore.update({
|
|
155
|
+
where: { id: storeId },
|
|
156
|
+
data
|
|
157
|
+
});
|
|
158
|
+
return mapAccountStore(row);
|
|
159
|
+
},
|
|
160
|
+
async removeStore(storeId) {
|
|
161
|
+
await prisma.accountStore.delete({ where: { id: storeId } });
|
|
162
|
+
},
|
|
163
|
+
async addMember(input) {
|
|
164
|
+
const data = {
|
|
165
|
+
accountId: input.accountId,
|
|
166
|
+
userEmail: input.userEmail,
|
|
167
|
+
role: input.role
|
|
168
|
+
};
|
|
169
|
+
if (input.allStoresAccess !== void 0) {
|
|
170
|
+
data.allStoresAccess = input.allStoresAccess;
|
|
171
|
+
}
|
|
172
|
+
if (input.allowedStoreIds !== void 0) {
|
|
173
|
+
data.allowedStoreIds = JSON.stringify(input.allowedStoreIds);
|
|
174
|
+
}
|
|
175
|
+
if (input.permissions !== void 0) {
|
|
176
|
+
data.permissions = JSON.stringify(input.permissions);
|
|
177
|
+
}
|
|
178
|
+
const row = await prisma.accountMember.create({ data });
|
|
179
|
+
return mapAccountMember(row);
|
|
180
|
+
},
|
|
181
|
+
async getMember(memberId) {
|
|
182
|
+
const row = await prisma.accountMember.findUnique({
|
|
183
|
+
where: { id: memberId }
|
|
184
|
+
});
|
|
185
|
+
if (!row) return null;
|
|
186
|
+
return mapAccountMember(row);
|
|
187
|
+
},
|
|
188
|
+
async getMemberByEmail(accountId, userEmail) {
|
|
189
|
+
const row = await prisma.accountMember.findUnique({
|
|
190
|
+
where: { accountId_userEmail: { accountId, userEmail } }
|
|
191
|
+
});
|
|
192
|
+
if (!row) return null;
|
|
193
|
+
return mapAccountMember(row);
|
|
194
|
+
},
|
|
195
|
+
async listMembers(accountId) {
|
|
196
|
+
const rows = await prisma.accountMember.findMany({
|
|
197
|
+
where: { accountId }
|
|
198
|
+
});
|
|
199
|
+
return rows.map(mapAccountMember);
|
|
200
|
+
},
|
|
201
|
+
async updateMember(memberId, input) {
|
|
202
|
+
const data = {};
|
|
203
|
+
if (input.role !== void 0) {
|
|
204
|
+
data.role = input.role;
|
|
205
|
+
}
|
|
206
|
+
if (input.allStoresAccess !== void 0) {
|
|
207
|
+
data.allStoresAccess = input.allStoresAccess;
|
|
208
|
+
}
|
|
209
|
+
if (input.allowedStoreIds !== void 0) {
|
|
210
|
+
data.allowedStoreIds = JSON.stringify(input.allowedStoreIds);
|
|
211
|
+
}
|
|
212
|
+
if (input.permissions !== void 0) {
|
|
213
|
+
data.permissions = JSON.stringify(input.permissions);
|
|
214
|
+
}
|
|
215
|
+
const row = await prisma.accountMember.update({
|
|
216
|
+
where: { id: memberId },
|
|
217
|
+
data
|
|
218
|
+
});
|
|
219
|
+
return mapAccountMember(row);
|
|
220
|
+
},
|
|
221
|
+
async removeMember(memberId) {
|
|
222
|
+
await prisma.accountMember.delete({ where: { id: memberId } });
|
|
223
|
+
},
|
|
224
|
+
async canAccessStore(accountId, userEmail, storeId) {
|
|
225
|
+
const row = await prisma.accountMember.findUnique({
|
|
226
|
+
where: { accountId_userEmail: { accountId, userEmail } }
|
|
227
|
+
});
|
|
228
|
+
if (!row) return false;
|
|
229
|
+
const member = mapAccountMember(row);
|
|
230
|
+
if (member.role === "owner" || member.role === "admin") return true;
|
|
231
|
+
if (member.allStoresAccess) return true;
|
|
232
|
+
return member.allowedStoreIds.includes(storeId);
|
|
233
|
+
},
|
|
234
|
+
async isRoleAtLeast(accountId, userEmail, minimumRole) {
|
|
235
|
+
const row = await prisma.accountMember.findUnique({
|
|
236
|
+
where: { accountId_userEmail: { accountId, userEmail } }
|
|
237
|
+
});
|
|
238
|
+
if (!row) return false;
|
|
239
|
+
const member = mapAccountMember(row);
|
|
240
|
+
return ACCOUNT_ROLE_HIERARCHY[member.role] >= ACCOUNT_ROLE_HIERARCHY[minimumRole];
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/multi-store/shared-settings-service.ts
|
|
246
|
+
function mapSharedSetting(row) {
|
|
247
|
+
return {
|
|
248
|
+
id: row.id,
|
|
249
|
+
accountId: row.accountId,
|
|
250
|
+
settingKey: row.settingKey,
|
|
251
|
+
settingValue: row.settingValue,
|
|
252
|
+
appliesToStores: Array.isArray(row.appliesToStores) ? row.appliesToStores : null,
|
|
253
|
+
createdAt: row.createdAt,
|
|
254
|
+
updatedAt: row.updatedAt
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function createSharedSettingsService(prisma) {
|
|
258
|
+
return {
|
|
259
|
+
async set(input) {
|
|
260
|
+
const data = {
|
|
261
|
+
settingValue: input.settingValue
|
|
262
|
+
};
|
|
263
|
+
if (input.appliesToStores !== void 0) {
|
|
264
|
+
data.appliesToStores = input.appliesToStores === null ? null : JSON.stringify(input.appliesToStores);
|
|
265
|
+
}
|
|
266
|
+
const row = await prisma.accountSharedSetting.upsert({
|
|
267
|
+
where: {
|
|
268
|
+
accountId_settingKey: {
|
|
269
|
+
accountId: input.accountId,
|
|
270
|
+
settingKey: input.settingKey
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
create: {
|
|
274
|
+
accountId: input.accountId,
|
|
275
|
+
settingKey: input.settingKey,
|
|
276
|
+
settingValue: input.settingValue,
|
|
277
|
+
...input.appliesToStores !== void 0 ? {
|
|
278
|
+
appliesToStores: input.appliesToStores === null ? null : JSON.stringify(input.appliesToStores)
|
|
279
|
+
} : {}
|
|
280
|
+
},
|
|
281
|
+
update: data
|
|
282
|
+
});
|
|
283
|
+
return mapSharedSetting(row);
|
|
284
|
+
},
|
|
285
|
+
async get(accountId, settingKey) {
|
|
286
|
+
const row = await prisma.accountSharedSetting.findUnique({
|
|
287
|
+
where: { accountId_settingKey: { accountId, settingKey } }
|
|
288
|
+
});
|
|
289
|
+
if (!row) return null;
|
|
290
|
+
return mapSharedSetting(row);
|
|
291
|
+
},
|
|
292
|
+
async list(accountId) {
|
|
293
|
+
const rows = await prisma.accountSharedSetting.findMany({
|
|
294
|
+
where: { accountId }
|
|
295
|
+
});
|
|
296
|
+
return rows.map(mapSharedSetting);
|
|
297
|
+
},
|
|
298
|
+
async delete(accountId, settingKey) {
|
|
299
|
+
await prisma.accountSharedSetting.delete({
|
|
300
|
+
where: { accountId_settingKey: { accountId, settingKey } }
|
|
301
|
+
});
|
|
302
|
+
},
|
|
303
|
+
async resolve(accountId, storeId, settingKey, defaultValue) {
|
|
304
|
+
const store = await prisma.accountStore.findUnique({
|
|
305
|
+
where: { id: storeId }
|
|
306
|
+
});
|
|
307
|
+
if (store) {
|
|
308
|
+
const storeSettings = store.storeSettings && typeof store.storeSettings === "object" ? store.storeSettings : {};
|
|
309
|
+
if (settingKey in storeSettings) {
|
|
310
|
+
return storeSettings[settingKey];
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const shared = await prisma.accountSharedSetting.findUnique({
|
|
314
|
+
where: { accountId_settingKey: { accountId, settingKey } }
|
|
315
|
+
});
|
|
316
|
+
if (shared) {
|
|
317
|
+
const appliesToStores = Array.isArray(shared.appliesToStores) ? shared.appliesToStores : null;
|
|
318
|
+
if (appliesToStores === null || appliesToStores.includes(storeId)) {
|
|
319
|
+
return shared.settingValue;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return defaultValue;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/multi-store/account-middleware.ts
|
|
328
|
+
function mapAccountStore2(row) {
|
|
329
|
+
return {
|
|
330
|
+
id: row.id,
|
|
331
|
+
accountId: row.accountId,
|
|
332
|
+
shopDomain: row.shopDomain,
|
|
333
|
+
storeName: row.storeName,
|
|
334
|
+
region: row.region ?? null,
|
|
335
|
+
currency: row.currency ?? null,
|
|
336
|
+
locale: row.locale ?? null,
|
|
337
|
+
timezone: row.timezone ?? null,
|
|
338
|
+
storeSettings: row.storeSettings && typeof row.storeSettings === "object" ? row.storeSettings : {},
|
|
339
|
+
isActive: row.isActive,
|
|
340
|
+
isPrimary: row.isPrimary,
|
|
341
|
+
createdAt: row.createdAt,
|
|
342
|
+
updatedAt: row.updatedAt
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function mapAccount2(row) {
|
|
346
|
+
return {
|
|
347
|
+
id: row.id,
|
|
348
|
+
name: row.name,
|
|
349
|
+
type: row.type,
|
|
350
|
+
isActive: row.isActive,
|
|
351
|
+
createdAt: row.createdAt,
|
|
352
|
+
updatedAt: row.updatedAt
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function mapAccountMember2(row) {
|
|
356
|
+
return {
|
|
357
|
+
id: row.id,
|
|
358
|
+
accountId: row.accountId,
|
|
359
|
+
userEmail: row.userEmail,
|
|
360
|
+
role: row.role,
|
|
361
|
+
allStoresAccess: row.allStoresAccess,
|
|
362
|
+
allowedStoreIds: Array.isArray(row.allowedStoreIds) ? row.allowedStoreIds : [],
|
|
363
|
+
permissions: Array.isArray(row.permissions) ? row.permissions : [],
|
|
364
|
+
createdAt: row.createdAt,
|
|
365
|
+
updatedAt: row.updatedAt
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function createAccountMiddleware(prisma) {
|
|
369
|
+
return {
|
|
370
|
+
async getAccountContext(shopDomain, userEmail) {
|
|
371
|
+
const storeRow = await prisma.accountStore.findUnique({
|
|
372
|
+
where: { shopDomain },
|
|
373
|
+
include: { account: true }
|
|
374
|
+
});
|
|
375
|
+
if (!storeRow) return null;
|
|
376
|
+
const account = mapAccount2(storeRow.account);
|
|
377
|
+
const currentStore = mapAccountStore2(storeRow);
|
|
378
|
+
const storeRows = await prisma.accountStore.findMany({
|
|
379
|
+
where: { accountId: account.id }
|
|
380
|
+
});
|
|
381
|
+
const stores = storeRows.map(mapAccountStore2);
|
|
382
|
+
let member = null;
|
|
383
|
+
if (userEmail) {
|
|
384
|
+
const memberRow = await prisma.accountMember.findUnique({
|
|
385
|
+
where: {
|
|
386
|
+
accountId_userEmail: { accountId: account.id, userEmail }
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
if (memberRow) {
|
|
390
|
+
member = mapAccountMember2(memberRow);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return { account, currentStore, member, stores };
|
|
394
|
+
},
|
|
395
|
+
async validateStoreAccess(accountId, userEmail, storeId) {
|
|
396
|
+
const memberRow = await prisma.accountMember.findUnique({
|
|
397
|
+
where: { accountId_userEmail: { accountId, userEmail } }
|
|
398
|
+
});
|
|
399
|
+
if (!memberRow) return false;
|
|
400
|
+
const member = mapAccountMember2(memberRow);
|
|
401
|
+
if (member.role === "owner" || member.role === "admin") return true;
|
|
402
|
+
if (member.allStoresAccess) return true;
|
|
403
|
+
return member.allowedStoreIds.includes(storeId);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/multi-store/pricing.ts
|
|
409
|
+
import {
|
|
410
|
+
DEFAULT_PRICING_TIERS,
|
|
411
|
+
DEFAULT_BASE_PRICE,
|
|
412
|
+
DEFAULT_INCLUDED_STORES
|
|
413
|
+
} from "@uniforge/platform-core/multi-store";
|
|
414
|
+
function calculateAccountPricing(storeCount, tiers, basePrice) {
|
|
415
|
+
const effectiveTiers = tiers ?? DEFAULT_PRICING_TIERS;
|
|
416
|
+
const effectiveBasePrice = basePrice ?? DEFAULT_BASE_PRICE;
|
|
417
|
+
const includedStores = DEFAULT_INCLUDED_STORES;
|
|
418
|
+
const tierBreakdown = [];
|
|
419
|
+
let additionalStoreCost = 0;
|
|
420
|
+
for (const tier of effectiveTiers) {
|
|
421
|
+
const tierMax = tier.maxStores ?? storeCount;
|
|
422
|
+
const tierStart = tier.minStores;
|
|
423
|
+
const tierEnd = Math.min(tierMax, storeCount);
|
|
424
|
+
if (tierStart > storeCount) {
|
|
425
|
+
tierBreakdown.push({ tier, storeCount: 0, cost: 0 });
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
const storesInTier = tierEnd - tierStart + 1;
|
|
429
|
+
const cost = storesInTier * tier.pricePerStore;
|
|
430
|
+
tierBreakdown.push({ tier, storeCount: storesInTier, cost });
|
|
431
|
+
additionalStoreCost += cost;
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
basePrice: effectiveBasePrice,
|
|
435
|
+
includedStores,
|
|
436
|
+
additionalStoreCost,
|
|
437
|
+
totalMonthlyPrice: effectiveBasePrice + additionalStoreCost,
|
|
438
|
+
tierBreakdown
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
export {
|
|
442
|
+
calculateAccountPricing,
|
|
443
|
+
createAccountMiddleware,
|
|
444
|
+
createAccountService,
|
|
445
|
+
createSharedSettingsService
|
|
446
|
+
};
|
|
447
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/multi-store/account-service.ts","../../src/multi-store/shared-settings-service.ts","../../src/multi-store/account-middleware.ts","../../src/multi-store/pricing.ts"],"sourcesContent":["import type {\n Account,\n AccountStore,\n AccountMember,\n AccountRole,\n AccountType,\n AccountService,\n CreateAccountInput,\n UpdateAccountInput,\n AddStoreInput,\n UpdateStoreInput,\n AddMemberInput,\n UpdateMemberInput,\n} from '@uniforge/platform-core/multi-store';\nimport { ACCOUNT_ROLE_HIERARCHY } from '@uniforge/platform-core/multi-store';\n\nfunction mapAccount(row: any): Account {\n return {\n id: row.id,\n name: row.name,\n type: row.type as AccountType,\n isActive: row.isActive,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapAccountStore(row: any): AccountStore {\n return {\n id: row.id,\n accountId: row.accountId,\n shopDomain: row.shopDomain,\n storeName: row.storeName,\n region: row.region ?? null,\n currency: row.currency ?? null,\n locale: row.locale ?? null,\n timezone: row.timezone ?? null,\n storeSettings:\n row.storeSettings && typeof row.storeSettings === 'object'\n ? (row.storeSettings as Record<string, unknown>)\n : {},\n isActive: row.isActive,\n isPrimary: row.isPrimary,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapAccountMember(row: any): AccountMember {\n return {\n id: row.id,\n accountId: row.accountId,\n userEmail: row.userEmail,\n role: row.role as AccountRole,\n allStoresAccess: row.allStoresAccess,\n allowedStoreIds: Array.isArray(row.allowedStoreIds)\n ? (row.allowedStoreIds as string[])\n : [],\n permissions: Array.isArray(row.permissions)\n ? (row.permissions as string[])\n : [],\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nexport function createAccountService(prisma: any): AccountService {\n return {\n async createAccount(input: CreateAccountInput): Promise<Account> {\n const row = await prisma.account.create({\n data: {\n name: input.name,\n type: input.type,\n },\n });\n return mapAccount(row);\n },\n\n async getAccount(accountId: string): Promise<Account | null> {\n const row = await prisma.account.findUnique({\n where: { id: accountId },\n });\n if (!row) return null;\n return mapAccount(row);\n },\n\n async updateAccount(\n accountId: string,\n input: UpdateAccountInput,\n ): Promise<Account> {\n const data: Record<string, unknown> = {};\n if (input.name !== undefined) {\n data.name = input.name;\n }\n if (input.type !== undefined) {\n data.type = input.type;\n }\n if (input.isActive !== undefined) {\n data.isActive = input.isActive;\n }\n const row = await prisma.account.update({\n where: { id: accountId },\n data,\n });\n return mapAccount(row);\n },\n\n async deleteAccount(accountId: string): Promise<void> {\n await prisma.account.delete({ where: { id: accountId } });\n },\n\n async addStore(input: AddStoreInput): Promise<AccountStore> {\n const data: Record<string, unknown> = {\n accountId: input.accountId,\n shopDomain: input.shopDomain,\n storeName: input.storeName,\n };\n if (input.region !== undefined) {\n data.region = input.region;\n }\n if (input.currency !== undefined) {\n data.currency = input.currency;\n }\n if (input.locale !== undefined) {\n data.locale = input.locale;\n }\n if (input.timezone !== undefined) {\n data.timezone = input.timezone;\n }\n if (input.storeSettings !== undefined) {\n data.storeSettings = input.storeSettings;\n }\n if (input.isPrimary !== undefined) {\n data.isPrimary = input.isPrimary;\n }\n const row = await prisma.accountStore.create({ data });\n return mapAccountStore(row);\n },\n\n async getStore(storeId: string): Promise<AccountStore | null> {\n const row = await prisma.accountStore.findUnique({\n where: { id: storeId },\n });\n if (!row) return null;\n return mapAccountStore(row);\n },\n\n async getStoreByDomain(shopDomain: string): Promise<AccountStore | null> {\n const row = await prisma.accountStore.findUnique({\n where: { shopDomain },\n });\n if (!row) return null;\n return mapAccountStore(row);\n },\n\n async listStores(accountId: string): Promise<AccountStore[]> {\n const rows = await prisma.accountStore.findMany({\n where: { accountId },\n });\n return rows.map(mapAccountStore);\n },\n\n async updateStore(\n storeId: string,\n input: UpdateStoreInput,\n ): Promise<AccountStore> {\n const data: Record<string, unknown> = {};\n if (input.storeName !== undefined) {\n data.storeName = input.storeName;\n }\n if (input.region !== undefined) {\n data.region = input.region;\n }\n if (input.currency !== undefined) {\n data.currency = input.currency;\n }\n if (input.locale !== undefined) {\n data.locale = input.locale;\n }\n if (input.timezone !== undefined) {\n data.timezone = input.timezone;\n }\n if (input.storeSettings !== undefined) {\n data.storeSettings = input.storeSettings;\n }\n if (input.isActive !== undefined) {\n data.isActive = input.isActive;\n }\n if (input.isPrimary !== undefined) {\n data.isPrimary = input.isPrimary;\n }\n const row = await prisma.accountStore.update({\n where: { id: storeId },\n data,\n });\n return mapAccountStore(row);\n },\n\n async removeStore(storeId: string): Promise<void> {\n await prisma.accountStore.delete({ where: { id: storeId } });\n },\n\n async addMember(input: AddMemberInput): Promise<AccountMember> {\n const data: Record<string, unknown> = {\n accountId: input.accountId,\n userEmail: input.userEmail,\n role: input.role,\n };\n if (input.allStoresAccess !== undefined) {\n data.allStoresAccess = input.allStoresAccess;\n }\n if (input.allowedStoreIds !== undefined) {\n data.allowedStoreIds = JSON.stringify(input.allowedStoreIds);\n }\n if (input.permissions !== undefined) {\n data.permissions = JSON.stringify(input.permissions);\n }\n const row = await prisma.accountMember.create({ data });\n return mapAccountMember(row);\n },\n\n async getMember(memberId: string): Promise<AccountMember | null> {\n const row = await prisma.accountMember.findUnique({\n where: { id: memberId },\n });\n if (!row) return null;\n return mapAccountMember(row);\n },\n\n async getMemberByEmail(\n accountId: string,\n userEmail: string,\n ): Promise<AccountMember | null> {\n const row = await prisma.accountMember.findUnique({\n where: { accountId_userEmail: { accountId, userEmail } },\n });\n if (!row) return null;\n return mapAccountMember(row);\n },\n\n async listMembers(accountId: string): Promise<AccountMember[]> {\n const rows = await prisma.accountMember.findMany({\n where: { accountId },\n });\n return rows.map(mapAccountMember);\n },\n\n async updateMember(\n memberId: string,\n input: UpdateMemberInput,\n ): Promise<AccountMember> {\n const data: Record<string, unknown> = {};\n if (input.role !== undefined) {\n data.role = input.role;\n }\n if (input.allStoresAccess !== undefined) {\n data.allStoresAccess = input.allStoresAccess;\n }\n if (input.allowedStoreIds !== undefined) {\n data.allowedStoreIds = JSON.stringify(input.allowedStoreIds);\n }\n if (input.permissions !== undefined) {\n data.permissions = JSON.stringify(input.permissions);\n }\n const row = await prisma.accountMember.update({\n where: { id: memberId },\n data,\n });\n return mapAccountMember(row);\n },\n\n async removeMember(memberId: string): Promise<void> {\n await prisma.accountMember.delete({ where: { id: memberId } });\n },\n\n async canAccessStore(\n accountId: string,\n userEmail: string,\n storeId: string,\n ): Promise<boolean> {\n const row = await prisma.accountMember.findUnique({\n where: { accountId_userEmail: { accountId, userEmail } },\n });\n if (!row) return false;\n const member = mapAccountMember(row);\n if (member.role === 'owner' || member.role === 'admin') return true;\n if (member.allStoresAccess) return true;\n return member.allowedStoreIds.includes(storeId);\n },\n\n async isRoleAtLeast(\n accountId: string,\n userEmail: string,\n minimumRole: AccountRole,\n ): Promise<boolean> {\n const row = await prisma.accountMember.findUnique({\n where: { accountId_userEmail: { accountId, userEmail } },\n });\n if (!row) return false;\n const member = mapAccountMember(row);\n return (\n ACCOUNT_ROLE_HIERARCHY[member.role] >=\n ACCOUNT_ROLE_HIERARCHY[minimumRole]\n );\n },\n };\n}\n","import type {\n AccountSharedSetting,\n SetSharedSettingInput,\n SharedSettingsService,\n} from '@uniforge/platform-core/multi-store';\n\nfunction mapSharedSetting(row: any): AccountSharedSetting {\n return {\n id: row.id,\n accountId: row.accountId,\n settingKey: row.settingKey,\n settingValue: row.settingValue,\n appliesToStores: Array.isArray(row.appliesToStores)\n ? (row.appliesToStores as string[])\n : null,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nexport function createSharedSettingsService(\n prisma: any,\n): SharedSettingsService {\n return {\n async set(input: SetSharedSettingInput): Promise<AccountSharedSetting> {\n const data: Record<string, unknown> = {\n settingValue: input.settingValue,\n };\n if (input.appliesToStores !== undefined) {\n data.appliesToStores =\n input.appliesToStores === null\n ? null\n : JSON.stringify(input.appliesToStores);\n }\n const row = await prisma.accountSharedSetting.upsert({\n where: {\n accountId_settingKey: {\n accountId: input.accountId,\n settingKey: input.settingKey,\n },\n },\n create: {\n accountId: input.accountId,\n settingKey: input.settingKey,\n settingValue: input.settingValue,\n ...(input.appliesToStores !== undefined\n ? {\n appliesToStores:\n input.appliesToStores === null\n ? null\n : JSON.stringify(input.appliesToStores),\n }\n : {}),\n },\n update: data,\n });\n return mapSharedSetting(row);\n },\n\n async get(\n accountId: string,\n settingKey: string,\n ): Promise<AccountSharedSetting | null> {\n const row = await prisma.accountSharedSetting.findUnique({\n where: { accountId_settingKey: { accountId, settingKey } },\n });\n if (!row) return null;\n return mapSharedSetting(row);\n },\n\n async list(accountId: string): Promise<AccountSharedSetting[]> {\n const rows = await prisma.accountSharedSetting.findMany({\n where: { accountId },\n });\n return rows.map(mapSharedSetting);\n },\n\n async delete(accountId: string, settingKey: string): Promise<void> {\n await prisma.accountSharedSetting.delete({\n where: { accountId_settingKey: { accountId, settingKey } },\n });\n },\n\n async resolve<T = unknown>(\n accountId: string,\n storeId: string,\n settingKey: string,\n defaultValue: T,\n ): Promise<T> {\n // 1. Check store-specific override\n const store = await prisma.accountStore.findUnique({\n where: { id: storeId },\n });\n if (store) {\n const storeSettings =\n store.storeSettings && typeof store.storeSettings === 'object'\n ? (store.storeSettings as Record<string, unknown>)\n : {};\n if (settingKey in storeSettings) {\n return storeSettings[settingKey] as T;\n }\n }\n\n // 2. Check account shared setting\n const shared = await prisma.accountSharedSetting.findUnique({\n where: { accountId_settingKey: { accountId, settingKey } },\n });\n if (shared) {\n const appliesToStores = Array.isArray(shared.appliesToStores)\n ? (shared.appliesToStores as string[])\n : null;\n if (\n appliesToStores === null ||\n appliesToStores.includes(storeId)\n ) {\n return shared.settingValue as T;\n }\n }\n\n // 3. Return default\n return defaultValue;\n },\n };\n}\n","import type {\n AccountContext,\n AccountMiddleware,\n AccountRole,\n} from '@uniforge/platform-core/multi-store';\n\nfunction mapAccountStore(row: any) {\n return {\n id: row.id,\n accountId: row.accountId,\n shopDomain: row.shopDomain,\n storeName: row.storeName,\n region: row.region ?? null,\n currency: row.currency ?? null,\n locale: row.locale ?? null,\n timezone: row.timezone ?? null,\n storeSettings:\n row.storeSettings && typeof row.storeSettings === 'object'\n ? (row.storeSettings as Record<string, unknown>)\n : {},\n isActive: row.isActive,\n isPrimary: row.isPrimary,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapAccount(row: any) {\n return {\n id: row.id,\n name: row.name,\n type: row.type as 'individual' | 'enterprise',\n isActive: row.isActive,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapAccountMember(row: any) {\n return {\n id: row.id,\n accountId: row.accountId,\n userEmail: row.userEmail,\n role: row.role as AccountRole,\n allStoresAccess: row.allStoresAccess,\n allowedStoreIds: Array.isArray(row.allowedStoreIds)\n ? (row.allowedStoreIds as string[])\n : [],\n permissions: Array.isArray(row.permissions)\n ? (row.permissions as string[])\n : [],\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nexport function createAccountMiddleware(prisma: any): AccountMiddleware {\n return {\n async getAccountContext(\n shopDomain: string,\n userEmail?: string,\n ): Promise<AccountContext | null> {\n // 1. Find the store by shopDomain, include account\n const storeRow = await prisma.accountStore.findUnique({\n where: { shopDomain },\n include: { account: true },\n });\n if (!storeRow) return null;\n\n const account = mapAccount(storeRow.account);\n const currentStore = mapAccountStore(storeRow);\n\n // 2. Get all stores for the account\n const storeRows = await prisma.accountStore.findMany({\n where: { accountId: account.id },\n });\n const stores = storeRows.map(mapAccountStore);\n\n // 3. Get member if userEmail provided\n let member = null;\n if (userEmail) {\n const memberRow = await prisma.accountMember.findUnique({\n where: {\n accountId_userEmail: { accountId: account.id, userEmail },\n },\n });\n if (memberRow) {\n member = mapAccountMember(memberRow);\n }\n }\n\n return { account, currentStore, member, stores };\n },\n\n async validateStoreAccess(\n accountId: string,\n userEmail: string,\n storeId: string,\n ): Promise<boolean> {\n const memberRow = await prisma.accountMember.findUnique({\n where: { accountId_userEmail: { accountId, userEmail } },\n });\n if (!memberRow) return false;\n\n const member = mapAccountMember(memberRow);\n if (member.role === 'owner' || member.role === 'admin') return true;\n if (member.allStoresAccess) return true;\n return member.allowedStoreIds.includes(storeId);\n },\n };\n}\n","import type {\n AccountPricingTier,\n AccountPricingResult,\n} from '@uniforge/platform-core/multi-store';\nimport {\n DEFAULT_PRICING_TIERS,\n DEFAULT_BASE_PRICE,\n DEFAULT_INCLUDED_STORES,\n} from '@uniforge/platform-core/multi-store';\n\nexport function calculateAccountPricing(\n storeCount: number,\n tiers?: AccountPricingTier[],\n basePrice?: number,\n): AccountPricingResult {\n const effectiveTiers = tiers ?? DEFAULT_PRICING_TIERS;\n const effectiveBasePrice = basePrice ?? DEFAULT_BASE_PRICE;\n const includedStores = DEFAULT_INCLUDED_STORES;\n\n const tierBreakdown: Array<{\n tier: AccountPricingTier;\n storeCount: number;\n cost: number;\n }> = [];\n let additionalStoreCost = 0;\n\n for (const tier of effectiveTiers) {\n const tierMax = tier.maxStores ?? storeCount;\n const tierStart = tier.minStores;\n const tierEnd = Math.min(tierMax, storeCount);\n\n if (tierStart > storeCount) {\n tierBreakdown.push({ tier, storeCount: 0, cost: 0 });\n continue;\n }\n\n const storesInTier = tierEnd - tierStart + 1;\n const cost = storesInTier * tier.pricePerStore;\n\n tierBreakdown.push({ tier, storeCount: storesInTier, cost });\n additionalStoreCost += cost;\n }\n\n return {\n basePrice: effectiveBasePrice,\n includedStores,\n additionalStoreCost,\n totalMonthlyPrice: effectiveBasePrice + additionalStoreCost,\n tierBreakdown,\n };\n}\n"],"mappings":"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","names":["mapAccountStore","mapAccount","mapAccountMember"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TenantMiddlewareConfig, TenantMiddleware, QueryScopeFilter } from '@uniforge/platform-core/multi-tenant';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Multi-tenant middleware implementation.
|
|
5
|
+
*
|
|
6
|
+
* Extracts tenant context from an authenticated session and provides
|
|
7
|
+
* tenant validation for cross-tenant access prevention.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Create a TenantMiddleware instance with optional configuration. */
|
|
11
|
+
declare function createTenantMiddleware(config?: TenantMiddlewareConfig): TenantMiddleware;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Query scoping implementation for multi-tenant data access.
|
|
15
|
+
*
|
|
16
|
+
* Automatically adds shopDomain filters to database queries
|
|
17
|
+
* and validates record ownership.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** Create a QueryScopeFilter that injects shopDomain into where clauses. */
|
|
21
|
+
declare function createQueryScopeFilter(): QueryScopeFilter;
|
|
22
|
+
|
|
23
|
+
export { createQueryScopeFilter, createTenantMiddleware };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TenantMiddlewareConfig, TenantMiddleware, QueryScopeFilter } from '@uniforge/platform-core/multi-tenant';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Multi-tenant middleware implementation.
|
|
5
|
+
*
|
|
6
|
+
* Extracts tenant context from an authenticated session and provides
|
|
7
|
+
* tenant validation for cross-tenant access prevention.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Create a TenantMiddleware instance with optional configuration. */
|
|
11
|
+
declare function createTenantMiddleware(config?: TenantMiddlewareConfig): TenantMiddleware;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Query scoping implementation for multi-tenant data access.
|
|
15
|
+
*
|
|
16
|
+
* Automatically adds shopDomain filters to database queries
|
|
17
|
+
* and validates record ownership.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** Create a QueryScopeFilter that injects shopDomain into where clauses. */
|
|
21
|
+
declare function createQueryScopeFilter(): QueryScopeFilter;
|
|
22
|
+
|
|
23
|
+
export { createQueryScopeFilter, createTenantMiddleware };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/multi-tenant/index.ts
|
|
21
|
+
var multi_tenant_exports = {};
|
|
22
|
+
__export(multi_tenant_exports, {
|
|
23
|
+
createQueryScopeFilter: () => createQueryScopeFilter,
|
|
24
|
+
createTenantMiddleware: () => createTenantMiddleware
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(multi_tenant_exports);
|
|
27
|
+
|
|
28
|
+
// src/multi-tenant/middleware.ts
|
|
29
|
+
function createTenantMiddleware(config) {
|
|
30
|
+
const extractor = config?.extractor;
|
|
31
|
+
return {
|
|
32
|
+
getTenantContext(session, shopContext) {
|
|
33
|
+
if (extractor) {
|
|
34
|
+
return extractor.extract(session, shopContext);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
shopDomain: shopContext.shopDomain,
|
|
38
|
+
session,
|
|
39
|
+
shopContext
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
validateTenant(tenantContext, shopDomain) {
|
|
43
|
+
return tenantContext.shopDomain === shopDomain;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/multi-tenant/query-scoping.ts
|
|
49
|
+
function createQueryScopeFilter() {
|
|
50
|
+
return {
|
|
51
|
+
applyScope(where, options) {
|
|
52
|
+
return {
|
|
53
|
+
where: {
|
|
54
|
+
...where,
|
|
55
|
+
shopDomain: options.shopDomain
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
validateOwnership(record, expectedShopDomain) {
|
|
60
|
+
return record.shopDomain === expectedShopDomain;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
65
|
+
0 && (module.exports = {
|
|
66
|
+
createQueryScopeFilter,
|
|
67
|
+
createTenantMiddleware
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/multi-tenant/index.ts","../../src/multi-tenant/middleware.ts","../../src/multi-tenant/query-scoping.ts"],"sourcesContent":["/**\n * @uniforge/core - Multi-Tenant\n *\n * Tenant isolation middleware and query scoping implementations.\n */\n\nexport { createTenantMiddleware } from './middleware';\nexport { createQueryScopeFilter } from './query-scoping';\n","/**\n * Multi-tenant middleware implementation.\n *\n * Extracts tenant context from an authenticated session and provides\n * tenant validation for cross-tenant access prevention.\n */\n\nimport type {\n Session,\n ShopContext,\n} from '@uniforge/platform-core/auth';\nimport type {\n TenantContext,\n TenantMiddleware,\n TenantMiddlewareConfig,\n} from '@uniforge/platform-core/multi-tenant';\n\n/** Create a TenantMiddleware instance with optional configuration. */\nexport function createTenantMiddleware(\n config?: TenantMiddlewareConfig,\n): TenantMiddleware {\n const extractor = config?.extractor;\n\n return {\n getTenantContext(session: Session, shopContext: ShopContext): TenantContext {\n if (extractor) {\n return extractor.extract(session, shopContext);\n }\n return {\n shopDomain: shopContext.shopDomain,\n session,\n shopContext,\n };\n },\n\n validateTenant(tenantContext: TenantContext, shopDomain: string): boolean {\n return tenantContext.shopDomain === shopDomain;\n },\n };\n}\n","/**\n * Query scoping implementation for multi-tenant data access.\n *\n * Automatically adds shopDomain filters to database queries\n * and validates record ownership.\n */\n\nimport type {\n QueryScopeFilter,\n QueryScopeOptions,\n ScopedQuery,\n} from '@uniforge/platform-core/multi-tenant';\n\n/** Create a QueryScopeFilter that injects shopDomain into where clauses. */\nexport function createQueryScopeFilter(): QueryScopeFilter {\n return {\n applyScope<T extends Record<string, unknown>>(\n where: T,\n options: QueryScopeOptions,\n ): ScopedQuery<T> {\n return {\n where: {\n ...where,\n shopDomain: options.shopDomain,\n },\n };\n },\n\n validateOwnership(\n record: { shopDomain: string },\n expectedShopDomain: string,\n ): boolean {\n return record.shopDomain === expectedShopDomain;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACkBO,SAAS,uBACd,QACkB;AAClB,QAAM,YAAY,QAAQ;AAE1B,SAAO;AAAA,IACL,iBAAiB,SAAkB,aAAyC;AAC1E,UAAI,WAAW;AACb,eAAO,UAAU,QAAQ,SAAS,WAAW;AAAA,MAC/C;AACA,aAAO;AAAA,QACL,YAAY,YAAY;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IAEA,eAAe,eAA8B,YAA6B;AACxE,aAAO,cAAc,eAAe;AAAA,IACtC;AAAA,EACF;AACF;;;ACzBO,SAAS,yBAA2C;AACzD,SAAO;AAAA,IACL,WACE,OACA,SACgB;AAChB,aAAO;AAAA,QACL,OAAO;AAAA,UACL,GAAG;AAAA,UACH,YAAY,QAAQ;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,kBACE,QACA,oBACS;AACT,aAAO,OAAO,eAAe;AAAA,IAC/B;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/multi-tenant/middleware.ts
|
|
2
|
+
function createTenantMiddleware(config) {
|
|
3
|
+
const extractor = config?.extractor;
|
|
4
|
+
return {
|
|
5
|
+
getTenantContext(session, shopContext) {
|
|
6
|
+
if (extractor) {
|
|
7
|
+
return extractor.extract(session, shopContext);
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
shopDomain: shopContext.shopDomain,
|
|
11
|
+
session,
|
|
12
|
+
shopContext
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
validateTenant(tenantContext, shopDomain) {
|
|
16
|
+
return tenantContext.shopDomain === shopDomain;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/multi-tenant/query-scoping.ts
|
|
22
|
+
function createQueryScopeFilter() {
|
|
23
|
+
return {
|
|
24
|
+
applyScope(where, options) {
|
|
25
|
+
return {
|
|
26
|
+
where: {
|
|
27
|
+
...where,
|
|
28
|
+
shopDomain: options.shopDomain
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
validateOwnership(record, expectedShopDomain) {
|
|
33
|
+
return record.shopDomain === expectedShopDomain;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
createQueryScopeFilter,
|
|
39
|
+
createTenantMiddleware
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/multi-tenant/middleware.ts","../../src/multi-tenant/query-scoping.ts"],"sourcesContent":["/**\n * Multi-tenant middleware implementation.\n *\n * Extracts tenant context from an authenticated session and provides\n * tenant validation for cross-tenant access prevention.\n */\n\nimport type {\n Session,\n ShopContext,\n} from '@uniforge/platform-core/auth';\nimport type {\n TenantContext,\n TenantMiddleware,\n TenantMiddlewareConfig,\n} from '@uniforge/platform-core/multi-tenant';\n\n/** Create a TenantMiddleware instance with optional configuration. */\nexport function createTenantMiddleware(\n config?: TenantMiddlewareConfig,\n): TenantMiddleware {\n const extractor = config?.extractor;\n\n return {\n getTenantContext(session: Session, shopContext: ShopContext): TenantContext {\n if (extractor) {\n return extractor.extract(session, shopContext);\n }\n return {\n shopDomain: shopContext.shopDomain,\n session,\n shopContext,\n };\n },\n\n validateTenant(tenantContext: TenantContext, shopDomain: string): boolean {\n return tenantContext.shopDomain === shopDomain;\n },\n };\n}\n","/**\n * Query scoping implementation for multi-tenant data access.\n *\n * Automatically adds shopDomain filters to database queries\n * and validates record ownership.\n */\n\nimport type {\n QueryScopeFilter,\n QueryScopeOptions,\n ScopedQuery,\n} from '@uniforge/platform-core/multi-tenant';\n\n/** Create a QueryScopeFilter that injects shopDomain into where clauses. */\nexport function createQueryScopeFilter(): QueryScopeFilter {\n return {\n applyScope<T extends Record<string, unknown>>(\n where: T,\n options: QueryScopeOptions,\n ): ScopedQuery<T> {\n return {\n where: {\n ...where,\n shopDomain: options.shopDomain,\n },\n };\n },\n\n validateOwnership(\n record: { shopDomain: string },\n expectedShopDomain: string,\n ): boolean {\n return record.shopDomain === expectedShopDomain;\n },\n };\n}\n"],"mappings":";AAkBO,SAAS,uBACd,QACkB;AAClB,QAAM,YAAY,QAAQ;AAE1B,SAAO;AAAA,IACL,iBAAiB,SAAkB,aAAyC;AAC1E,UAAI,WAAW;AACb,eAAO,UAAU,QAAQ,SAAS,WAAW;AAAA,MAC/C;AACA,aAAO;AAAA,QACL,YAAY,YAAY;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IAEA,eAAe,eAA8B,YAA6B;AACxE,aAAO,cAAc,eAAe;AAAA,IACtC;AAAA,EACF;AACF;;;ACzBO,SAAS,yBAA2C;AACzD,SAAO;AAAA,IACL,WACE,OACA,SACgB;AAChB,aAAO;AAAA,QACL,OAAO;AAAA,UACL,GAAG;AAAA,UACH,YAAY,QAAQ;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,kBACE,QACA,oBACS;AACT,aAAO,OAAO,eAAe;AAAA,IAC/B;AAAA,EACF;AACF;","names":[]}
|