@yongdall/core 0.4.5 → 0.5.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/index.d.mts +82 -60
- package/index.mjs +442 -153
- package/index.mjs.map +1 -1
- package/package.json +6 -5
package/index.mjs
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
import { Hook, Search, isFunction } from "@yongdall/common";
|
|
1
|
+
import { Hook, LazyPromise, Search, isFunction } from "@yongdall/common";
|
|
2
2
|
import { Query, Where, afterCreate, afterCreateMany, afterDelete, afterUpdate, beforeCreate, beforeCreateMany, beforeDelete, beforeUpdate, coefficient, decrement, expandModel, getDefinePermission, increment, multiply } from "@yongdall/model";
|
|
3
3
|
import { createKeyStore, createStoreSerializable } from "@yongdall/context";
|
|
4
|
+
import { loadPluginProfiles } from "@yongdall/plugins";
|
|
4
5
|
|
|
5
6
|
//#region packages/core/polyfill.mjs
|
|
6
7
|
if (!Symbol.metadata) Symbol.metadata = Symbol.for("Symbol.metadata");
|
|
7
8
|
|
|
8
9
|
//#endregion
|
|
9
10
|
//#region packages/core/config.mjs
|
|
10
|
-
/** @import {
|
|
11
|
+
/** @import { Realm } from '@yongdall/types' */
|
|
11
12
|
/** @import { BootConfiguration } from '@yongdall/common' */
|
|
12
|
-
/** @type {
|
|
13
|
-
const
|
|
13
|
+
/** @type {Realm} */
|
|
14
|
+
const mainRealm = {
|
|
14
15
|
id: "",
|
|
15
16
|
label: "拥道YongDall",
|
|
16
17
|
single: false,
|
|
17
18
|
providers: {},
|
|
18
19
|
salt: "YongDall"
|
|
19
20
|
};
|
|
21
|
+
/** @deprecated */
|
|
22
|
+
const mainTenant = mainRealm;
|
|
20
23
|
/** @type {BootConfiguration} */
|
|
21
24
|
const bootConfiguration = {
|
|
22
25
|
pages: {},
|
|
@@ -26,16 +29,16 @@ const bootConfiguration = {
|
|
|
26
29
|
};
|
|
27
30
|
/**
|
|
28
31
|
*
|
|
29
|
-
* @param {Partial<Omit<
|
|
32
|
+
* @param {Partial<Omit<Realm, 'id'>>} realm
|
|
30
33
|
* @param {object} boot
|
|
31
34
|
* @returns
|
|
32
35
|
*/
|
|
33
36
|
function initConfig({ label, single, providers, salt }, boot) {
|
|
34
37
|
Object.assign(bootConfiguration, boot);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (salt)
|
|
38
|
-
|
|
38
|
+
mainRealm.label = typeof label === "string" && label || "拥道YongDall";
|
|
39
|
+
mainRealm.single = Boolean(single);
|
|
40
|
+
if (salt) mainRealm.salt = salt;
|
|
41
|
+
mainRealm.providers = Object.fromEntries(Object.entries(typeof providers === "object" && providers || {}).filter(([k, v]) => typeof v === "string" && v));
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
//#endregion
|
|
@@ -60,23 +63,21 @@ function getMenus(type, group = "") {
|
|
|
60
63
|
//#region packages/core/models.mjs
|
|
61
64
|
/** @import { Permission } from '@yongdall/types' */
|
|
62
65
|
/** @import { FieldDefine, Fields, ModelTable, TableDefine } from '@yongdall/model' */
|
|
63
|
-
/** @import {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
getModelPermissionsHooks = [...hooks.get("getModelPermissions").values()].filter((v) => typeof v === "function");
|
|
79
|
-
const modelFields = [...hooks.get("modelExpands").entriesObject()].flatMap(([p, modelId, fields]) => [fields].flatMap((v) => {
|
|
66
|
+
/** @import { ModelProfile } from './types.mjs' */
|
|
67
|
+
const ModelProfilePromise = LazyPromise.try(async function() {
|
|
68
|
+
return await Array.fromAsync(loadPluginProfiles("model", (v) => [v]));
|
|
69
|
+
});
|
|
70
|
+
const modelsPromise = ModelProfilePromise.lazyThen((list) => {
|
|
71
|
+
return Object.fromEntries(list.flatMap((v) => Object.entries(v.models || {})));
|
|
72
|
+
});
|
|
73
|
+
const modelLoadersPromise = ModelProfilePromise.lazyThen((list) => {
|
|
74
|
+
return Object.fromEntries(list.flatMap((v) => Object.entries(v.modelLoaders || {})));
|
|
75
|
+
});
|
|
76
|
+
const getModelPermissionsHooksPromise = ModelProfilePromise.lazyThen((list) => {
|
|
77
|
+
return list.map((v) => v.getModelPermissions).filter((v) => typeof v === "function");
|
|
78
|
+
});
|
|
79
|
+
const modelExpandsPromise = ModelProfilePromise.lazyThen((list) => {
|
|
80
|
+
const modelFields = list.flatMap((v) => Object.entries(v.modelExpands || {})).flatMap(([modelId, fields]) => [fields].flatMap((v) => {
|
|
80
81
|
if (!v || typeof v !== "object" || Array.isArray(v)) return [];
|
|
81
82
|
return Object.entries(v).map(([fieldName, field]) => [
|
|
82
83
|
modelId,
|
|
@@ -91,8 +92,9 @@ hooks.listen(() => {
|
|
|
91
92
|
if (!fields?.length) continue;
|
|
92
93
|
expands[modelId] = Object.fromEntries(fields.map(([, fieldName, field]) => [fieldName, field]));
|
|
93
94
|
}
|
|
94
|
-
|
|
95
|
-
}
|
|
95
|
+
return expands;
|
|
96
|
+
});
|
|
97
|
+
const modelMap = /* @__PURE__ */ new WeakMap();
|
|
96
98
|
/**
|
|
97
99
|
*
|
|
98
100
|
* @param {string | string[]} ident
|
|
@@ -101,9 +103,11 @@ hooks.listen(() => {
|
|
|
101
103
|
async function findModel(ident) {
|
|
102
104
|
const [model, ...collection] = (Array.isArray(ident) ? ident : ident.split(":")).filter(Boolean);
|
|
103
105
|
if (!collection.length) {
|
|
106
|
+
const models = await modelsPromise;
|
|
104
107
|
const define = Object.hasOwn(models, model) && models[model];
|
|
105
108
|
return (typeof define === "object" || typeof define === "function") && define || null;
|
|
106
109
|
}
|
|
110
|
+
const modelLoaders = await modelLoadersPromise;
|
|
107
111
|
const loader = Object.hasOwn(modelLoaders, model) && modelLoaders[model];
|
|
108
112
|
if (typeof loader !== "function") return null;
|
|
109
113
|
const define = await loader(collection);
|
|
@@ -120,13 +124,14 @@ async function getModel(ident) {
|
|
|
120
124
|
const define = modelMap.get(model);
|
|
121
125
|
if (define) return define;
|
|
122
126
|
const modelIdent = Array.isArray(ident) ? ident.join(":") : ident;
|
|
127
|
+
const modelExpands = await modelExpandsPromise;
|
|
123
128
|
const newDefine = expandModel(model, Object.hasOwn(modelExpands, modelIdent) ? modelExpands[modelIdent] : {});
|
|
124
129
|
modelMap.set(model, newDefine);
|
|
125
130
|
return newDefine;
|
|
126
131
|
}
|
|
127
132
|
/** @type {(modelId: string, groupId?: string?) => Promise<Permission[]?>} */
|
|
128
133
|
const getModelPermissions = createKeyStore(async (modelId, groupId) => {
|
|
129
|
-
for (const fn of
|
|
134
|
+
for (const fn of await getModelPermissionsHooksPromise) {
|
|
130
135
|
const permissions = await fn(modelId, groupId);
|
|
131
136
|
if (permissions) return permissions;
|
|
132
137
|
}
|
|
@@ -152,56 +157,129 @@ async function getModelAuthorizationPermissions(modelId, authorization, groupId)
|
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
//#endregion
|
|
155
|
-
//#region packages/core/
|
|
156
|
-
/** @import {
|
|
157
|
-
|
|
160
|
+
//#region packages/core/realm.mjs
|
|
161
|
+
/** @import { Realm } from '@yongdall/types' */
|
|
162
|
+
/** @import { RealmHook } from './types.mjs' */
|
|
163
|
+
const [realmIdGetter, realmIdSetter] = createStoreSerializable("realmStatus", async (realmId) => {
|
|
164
|
+
return { realm: await realmId || null };
|
|
165
|
+
}, (val) => {
|
|
166
|
+
return Promise.resolve(val?.realm || null);
|
|
167
|
+
}, null);
|
|
168
|
+
const hooks$1 = LazyPromise.try(async function() {
|
|
169
|
+
return (await Array.fromAsync(loadPluginProfiles("realm"))).map((v) => v[1]);
|
|
170
|
+
});
|
|
171
|
+
/**
|
|
172
|
+
*
|
|
173
|
+
* @param {string} realmId
|
|
174
|
+
* @returns {Promise<boolean>}
|
|
175
|
+
*/
|
|
176
|
+
async function existRealm(realmId) {
|
|
177
|
+
for (const { exist, load } of await hooks$1) if (typeof exist === "function") {
|
|
178
|
+
if (await exist(realmId)) return true;
|
|
179
|
+
} else if (typeof load === "function") {
|
|
180
|
+
if (await load(realmId)) return true;
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const getters = hooks$1.lazyThen((hooks) => hooks.map((v) => v.get).filter((v) => typeof v === "function"));
|
|
185
|
+
/**
|
|
186
|
+
*
|
|
187
|
+
* @returns {Promise<string?>}
|
|
188
|
+
*/
|
|
189
|
+
async function getCurrentRealm() {
|
|
190
|
+
for (const get of await getters) {
|
|
191
|
+
const realm = await get();
|
|
192
|
+
if (!realm || !await existRealm(realm)) continue;
|
|
193
|
+
return realm;
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
*
|
|
199
|
+
* @returns {Promise<string?>}
|
|
200
|
+
*/
|
|
201
|
+
async function useRealmId() {
|
|
202
|
+
let state = realmIdGetter();
|
|
203
|
+
if (!state) {
|
|
204
|
+
state = getCurrentRealm();
|
|
205
|
+
realmIdSetter(state);
|
|
206
|
+
}
|
|
207
|
+
return state;
|
|
208
|
+
}
|
|
209
|
+
const loaders$1 = hooks$1.lazyThen((hooks) => hooks.map((v) => v.load).filter((v) => typeof v === "function"));
|
|
210
|
+
/**
|
|
211
|
+
*
|
|
212
|
+
* @param {string} realmId
|
|
213
|
+
* @returns {Promise<Realm?>}
|
|
214
|
+
*/
|
|
215
|
+
async function loadRealm(realmId) {
|
|
216
|
+
for (const load of await loaders$1) {
|
|
217
|
+
const realm = await load(realmId);
|
|
218
|
+
if (realm) return realm;
|
|
219
|
+
}
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
/** @deprecated */
|
|
223
|
+
const [oldRealmGetter, oldRealmSetter] = createStoreSerializable("oldRealmStatus", async (state) => {
|
|
158
224
|
if (!state) return null;
|
|
159
225
|
return state;
|
|
160
|
-
}, (
|
|
161
|
-
return
|
|
226
|
+
}, (realm) => {
|
|
227
|
+
return realm ? Promise.resolve(realm) : null;
|
|
162
228
|
}, null);
|
|
163
|
-
|
|
229
|
+
/** @deprecated */
|
|
230
|
+
function getRealmManager() {
|
|
164
231
|
return [...hooks.get("tenantManager").values()].filter(Boolean);
|
|
165
232
|
}
|
|
166
|
-
|
|
233
|
+
/** @deprecated */
|
|
234
|
+
let realmManagers = getRealmManager();
|
|
167
235
|
hooks.listen(() => {
|
|
168
|
-
|
|
236
|
+
realmManagers = getRealmManager();
|
|
169
237
|
}, -1e6);
|
|
170
238
|
/**
|
|
171
|
-
*
|
|
172
|
-
* @returns {Promise<
|
|
239
|
+
* @deprecated
|
|
240
|
+
* @returns {Promise<Realm>}
|
|
173
241
|
*/
|
|
174
|
-
async function
|
|
175
|
-
if (!
|
|
176
|
-
for (const get of
|
|
242
|
+
async function getCurrentOldRealm() {
|
|
243
|
+
if (!realmManagers.length) return mainRealm;
|
|
244
|
+
for (const get of realmManagers) {
|
|
177
245
|
const u = await get();
|
|
178
246
|
if (!u) continue;
|
|
179
247
|
return u;
|
|
180
248
|
}
|
|
181
|
-
throw new Error("[
|
|
249
|
+
throw new Error("[noRealm] 找不到域");
|
|
182
250
|
}
|
|
183
|
-
|
|
184
|
-
|
|
251
|
+
/** @deprecated */
|
|
252
|
+
async function getOldRealm() {
|
|
253
|
+
let state = oldRealmGetter();
|
|
185
254
|
if (!state) {
|
|
186
|
-
state =
|
|
187
|
-
|
|
255
|
+
state = getCurrentOldRealm();
|
|
256
|
+
oldRealmSetter(state);
|
|
188
257
|
}
|
|
189
258
|
return state;
|
|
190
259
|
}
|
|
191
260
|
/**
|
|
192
261
|
*
|
|
193
|
-
* @returns {Promise<
|
|
262
|
+
* @returns {Promise<Realm>}
|
|
194
263
|
*/
|
|
264
|
+
async function useRealm() {
|
|
265
|
+
return useRealmId().then(async (id) => {
|
|
266
|
+
return id && await loadRealm(id) || await getOldRealm();
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
function useSalt() {
|
|
270
|
+
return useRealm().then((r) => r.salt);
|
|
271
|
+
}
|
|
272
|
+
/** @deprecated */
|
|
195
273
|
function useTenant() {
|
|
196
|
-
return
|
|
274
|
+
return useRealm();
|
|
197
275
|
}
|
|
198
276
|
|
|
199
277
|
//#endregion
|
|
200
278
|
//#region packages/core/user.mjs
|
|
201
|
-
/** @import { Permissions,
|
|
279
|
+
/** @import { Permissions, Realm } from '@yongdall/types' */
|
|
202
280
|
/** @import { UserManager, MaybePromise } from './types.mjs' */
|
|
203
281
|
/**
|
|
204
|
-
* @typedef {[result: string | null, UserManager['set'] | null, UserManager['exit'] | null, user: string | null, sUser: string | null]}
|
|
282
|
+
* @typedef {[result: string | null, UserManager['set'] | null, UserManager['exit'] | null, user: string | null, sUser: string | null]} UserState
|
|
205
283
|
*/
|
|
206
284
|
const [userGetter, userSetter] = createStoreSerializable("userStatus", async (state) => {
|
|
207
285
|
if (!state) return null;
|
|
@@ -221,80 +299,70 @@ const [userGetter, userSetter] = createStoreSerializable("userStatus", async (st
|
|
|
221
299
|
sUserId
|
|
222
300
|
]);
|
|
223
301
|
}, null);
|
|
224
|
-
|
|
225
|
-
return
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
302
|
+
const userManagerMap = LazyPromise.try(async function() {
|
|
303
|
+
return await Array.fromAsync(loadPluginProfiles("user"));
|
|
304
|
+
});
|
|
305
|
+
const userManagers = userManagerMap.lazyThen((list) => list.map((v) => v[1]));
|
|
306
|
+
const defaultLogin$1 = userManagers.lazyThen((userMangers) => {
|
|
307
|
+
return userMangers.find((v) => typeof v.login === "function")?.login || null;
|
|
308
|
+
});
|
|
309
|
+
const switchableListPromise = userManagers.lazyThen((userMangers) => {
|
|
231
310
|
const switchableList = userMangers.map((v) => v.switchable).filter(isFunction);
|
|
232
|
-
/** @type {(() => MaybePromise<string?>)[]} */
|
|
233
|
-
const suGets = userMangers.map((v) => v.suGet).filter(isFunction);
|
|
234
|
-
/** @type {[UserManager['get'], UserManager['set'] | null, UserManager['exit'] | null][]} */
|
|
235
|
-
const getLoggedUserFn = [];
|
|
236
|
-
/** @type {Record<string, ((userId: string, password: string) => MaybePromise<number>)[]>} */
|
|
237
|
-
const verifiers = Object.create(null);
|
|
238
|
-
/** @type {Record<string, ((userId: string, password: string?, deadline?: Date?) => MaybePromise<boolean>)[]>} */
|
|
239
|
-
const setVerifiers = Object.create(null);
|
|
240
|
-
const finders = userMangers.map((v) => v.find).filter((v) => typeof v === "function");
|
|
241
|
-
const loaders = userMangers.map((v) => v.load).filter((v) => typeof v === "function");
|
|
242
|
-
const existTesters = userMangers.map((v) => v.exist).filter((v) => typeof v === "function");
|
|
243
|
-
const getPermissions = userMangers.map((v) => v.getPermissions).filter((v) => typeof v === "function");
|
|
244
|
-
const getOrganizationPermissions = userMangers.map((v) => v.getOrganizationPermissions).filter((v) => typeof v === "function");
|
|
245
|
-
const getOrganizationAllPermissions = userMangers.map((v) => v.getOrganizationAllPermissions).filter((v) => typeof v === "function");
|
|
246
|
-
for (const { get, set, exit, find, verify, setVerify } of userMangers) {
|
|
247
|
-
if (typeof get === "function") getLoggedUserFn.push([
|
|
248
|
-
get,
|
|
249
|
-
set || null,
|
|
250
|
-
exit || null
|
|
251
|
-
]);
|
|
252
|
-
if (verify) for (const [k, v] of Object.entries(verify)) {
|
|
253
|
-
const list = verifiers[k];
|
|
254
|
-
if (list) list.push(v);
|
|
255
|
-
else verifiers[k] = [v];
|
|
256
|
-
}
|
|
257
|
-
if (setVerify) for (const [k, v] of Object.entries(setVerify)) {
|
|
258
|
-
const list = setVerifiers[k];
|
|
259
|
-
if (list) list.push(v);
|
|
260
|
-
else setVerifiers[k] = [v];
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
311
|
/**
|
|
264
|
-
* @param {
|
|
312
|
+
* @param {Realm} realm
|
|
265
313
|
* @param {string} user
|
|
266
314
|
* @param {string} sUser
|
|
267
315
|
* @returns {Promise<boolean>}
|
|
268
316
|
*/
|
|
269
|
-
async function switchable(
|
|
317
|
+
return async function switchable(realm, user, sUser) {
|
|
270
318
|
if (!switchableList.length) return false;
|
|
271
319
|
for (const s of switchableList) {
|
|
272
320
|
if (await s(user, sUser)) continue;
|
|
273
321
|
return false;
|
|
274
322
|
}
|
|
275
323
|
return true;
|
|
276
|
-
}
|
|
277
|
-
return {
|
|
278
|
-
defaultLogin,
|
|
279
|
-
switchable,
|
|
280
|
-
suGets,
|
|
281
|
-
getLoggedUserFn,
|
|
282
|
-
finders,
|
|
283
|
-
verifiers,
|
|
284
|
-
setVerifiers,
|
|
285
|
-
loaders,
|
|
286
|
-
existTesters,
|
|
287
|
-
getPermissions,
|
|
288
|
-
getOrganizationPermissions,
|
|
289
|
-
getOrganizationAllPermissions
|
|
290
324
|
};
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
325
|
+
});
|
|
326
|
+
const suGets = userManagers.lazyThen((userMangers) => {
|
|
327
|
+
/** @type {(() => MaybePromise<string?>)[]} */
|
|
328
|
+
return userMangers.map((v) => v.suGet).filter(isFunction);
|
|
329
|
+
});
|
|
330
|
+
const finders$1 = userManagers.lazyThen((userMangers) => {
|
|
331
|
+
return userMangers.map((v) => v.find).filter((v) => typeof v === "function");
|
|
332
|
+
});
|
|
333
|
+
const loaders = userManagers.lazyThen((userMangers) => {
|
|
334
|
+
return userMangers.map((v) => v.load).filter((v) => typeof v === "function");
|
|
335
|
+
});
|
|
336
|
+
const existTesters$1 = userManagers.lazyThen((userMangers) => {
|
|
337
|
+
return userMangers.map((v) => v.exist).filter((v) => typeof v === "function");
|
|
338
|
+
});
|
|
339
|
+
const getPermissions = userManagers.lazyThen((userMangers) => {
|
|
340
|
+
return userMangers.map((v) => v.getPermissions).filter((v) => typeof v === "function");
|
|
341
|
+
});
|
|
342
|
+
const getOrganizationPermissions = userManagers.lazyThen((userMangers) => {
|
|
343
|
+
return userMangers.map((v) => v.getOrganizationPermissions).filter((v) => typeof v === "function");
|
|
344
|
+
});
|
|
345
|
+
const getOrganizationAllPermissions = userManagers.lazyThen((userMangers) => {
|
|
346
|
+
return userMangers.map((v) => v.getOrganizationAllPermissions).filter((v) => typeof v === "function");
|
|
347
|
+
});
|
|
348
|
+
const getLoggedUserFn = userManagers.lazyThen((userMangers) => {
|
|
349
|
+
/** @type {[UserManager['get'], UserManager['set'] | null, UserManager['exit'] | null][]} */
|
|
350
|
+
const getLoggedUserFn = [];
|
|
351
|
+
for (const { get, set, exit } of userMangers) if (typeof get === "function") getLoggedUserFn.push([
|
|
352
|
+
get,
|
|
353
|
+
set || null,
|
|
354
|
+
exit || null
|
|
355
|
+
]);
|
|
356
|
+
return getLoggedUserFn;
|
|
357
|
+
});
|
|
358
|
+
const verifiersPromise = userManagers.lazyThen((userMangers) => {
|
|
359
|
+
const list = userMangers.map((v) => v).flatMap((v) => Object.entries(v.verify || {}));
|
|
360
|
+
return Object.fromEntries(Object.entries(Object.groupBy(list, (v) => v[0])).map(([k, v]) => [k, v?.map((v) => v[1]) || []]));
|
|
361
|
+
});
|
|
362
|
+
const setVerifiersPromise = userManagers.lazyThen((userMangers) => {
|
|
363
|
+
const list = userMangers.map((v) => v).flatMap((v) => Object.entries(v.setVerify || {}));
|
|
364
|
+
return Object.fromEntries(Object.entries(Object.groupBy(list, (v) => v[0])).map(([k, v]) => [k, v?.map((v) => v[1]) || []]));
|
|
365
|
+
});
|
|
298
366
|
/**
|
|
299
367
|
*
|
|
300
368
|
* @param {string} userId
|
|
@@ -302,17 +370,17 @@ hooks.listen(() => {
|
|
|
302
370
|
* @returns {Promise<boolean>}
|
|
303
371
|
*/
|
|
304
372
|
async function existUser(userId, login) {
|
|
305
|
-
for (const fn of existTesters) if (await fn(userId, login)) return true;
|
|
373
|
+
for (const fn of await existTesters$1) if (await fn(userId, login)) return true;
|
|
306
374
|
return false;
|
|
307
375
|
}
|
|
308
376
|
/**
|
|
309
377
|
*
|
|
310
|
-
* @returns {Promise<
|
|
378
|
+
* @returns {Promise<UserState>}
|
|
311
379
|
*/
|
|
312
380
|
async function getLoggedUser() {
|
|
313
|
-
const
|
|
314
|
-
if (
|
|
315
|
-
for (const suGet of suGets) {
|
|
381
|
+
const realm = await useRealm();
|
|
382
|
+
if (realm.single) {
|
|
383
|
+
for (const suGet of await suGets) {
|
|
316
384
|
const suUser = await suGet();
|
|
317
385
|
if (!suUser) continue;
|
|
318
386
|
if (!await existUser(suUser)) continue;
|
|
@@ -338,7 +406,7 @@ async function getLoggedUser() {
|
|
|
338
406
|
let exitUser = null;
|
|
339
407
|
/** @type {string?} */
|
|
340
408
|
let user = null;
|
|
341
|
-
for (const [get, set, exit] of getLoggedUserFn) {
|
|
409
|
+
for (const [get, set, exit] of await getLoggedUserFn) {
|
|
342
410
|
const u = await get();
|
|
343
411
|
if (!u || !await existUser(u)) continue;
|
|
344
412
|
user = u;
|
|
@@ -348,16 +416,16 @@ async function getLoggedUser() {
|
|
|
348
416
|
}
|
|
349
417
|
if (!user) return [
|
|
350
418
|
null,
|
|
351
|
-
defaultLogin,
|
|
419
|
+
await defaultLogin$1,
|
|
352
420
|
null,
|
|
353
421
|
null,
|
|
354
422
|
null
|
|
355
423
|
];
|
|
356
|
-
for (const suGet of suGets) {
|
|
424
|
+
for (const suGet of await suGets) {
|
|
357
425
|
const suUser = await suGet();
|
|
358
426
|
if (!suUser) continue;
|
|
359
427
|
if (!await existUser(suUser)) continue;
|
|
360
|
-
if (await
|
|
428
|
+
if (await (await switchableListPromise)(realm, user, suUser)) continue;
|
|
361
429
|
return [
|
|
362
430
|
null,
|
|
363
431
|
setUser,
|
|
@@ -374,7 +442,7 @@ async function getLoggedUser() {
|
|
|
374
442
|
null
|
|
375
443
|
];
|
|
376
444
|
}
|
|
377
|
-
async function get() {
|
|
445
|
+
async function get$1() {
|
|
378
446
|
let state = userGetter();
|
|
379
447
|
if (!state) {
|
|
380
448
|
state = getLoggedUser();
|
|
@@ -387,8 +455,8 @@ async function get() {
|
|
|
387
455
|
* @returns {Promise<boolean>}
|
|
388
456
|
*/
|
|
389
457
|
function isSingleUser(logged) {
|
|
390
|
-
if (logged) return
|
|
391
|
-
return get().then(([, , , su]) => su ? false :
|
|
458
|
+
if (logged) return useRealm().then((g) => g.single);
|
|
459
|
+
return get$1().then(([, , , su]) => su ? false : useRealm().then((g) => g.single));
|
|
392
460
|
}
|
|
393
461
|
/**
|
|
394
462
|
*
|
|
@@ -396,7 +464,7 @@ function isSingleUser(logged) {
|
|
|
396
464
|
* @returns {Promise<string?>}
|
|
397
465
|
*/
|
|
398
466
|
function getUser(logged) {
|
|
399
|
-
return get().then(([, , , current, su]) => {
|
|
467
|
+
return get$1().then(([, , , current, su]) => {
|
|
400
468
|
if (logged === false) return su;
|
|
401
469
|
if (logged) return current;
|
|
402
470
|
return su || current;
|
|
@@ -418,7 +486,7 @@ function setUser(userId, sudo) {
|
|
|
418
486
|
current,
|
|
419
487
|
null
|
|
420
488
|
];
|
|
421
|
-
if (current || await
|
|
489
|
+
if (current || await useRealm().then((t) => t.single)) return [
|
|
422
490
|
userId,
|
|
423
491
|
set,
|
|
424
492
|
exit,
|
|
@@ -451,7 +519,7 @@ function setUser(userId, sudo) {
|
|
|
451
519
|
current,
|
|
452
520
|
su
|
|
453
521
|
];
|
|
454
|
-
if ((await
|
|
522
|
+
if ((await useRealm()).single) return [
|
|
455
523
|
null,
|
|
456
524
|
set,
|
|
457
525
|
exit,
|
|
@@ -484,7 +552,7 @@ function setUser(userId, sudo) {
|
|
|
484
552
|
*/
|
|
485
553
|
async function findUser(loginName, loginType) {
|
|
486
554
|
const types = new Set([loginType || ""].flat().filter(Boolean));
|
|
487
|
-
for (const fn of finders) {
|
|
555
|
+
for (const fn of await finders$1) {
|
|
488
556
|
const userId = await fn(loginName, types);
|
|
489
557
|
if (userId) return userId;
|
|
490
558
|
}
|
|
@@ -499,6 +567,8 @@ async function findUser(loginName, loginType) {
|
|
|
499
567
|
* @returns {Promise<number>}
|
|
500
568
|
*/
|
|
501
569
|
async function verifyUser(userId, password, type, returnError) {
|
|
570
|
+
const verifiers = await verifiersPromise;
|
|
571
|
+
if (!Object.hasOwn(verifiers, type)) return 0;
|
|
502
572
|
for (const fn of verifiers[type] || []) {
|
|
503
573
|
const res = await fn(userId, password);
|
|
504
574
|
if (res < 0) return returnError ? res : 0;
|
|
@@ -515,13 +585,15 @@ async function verifyUser(userId, password, type, returnError) {
|
|
|
515
585
|
* @returns {Promise<boolean>}
|
|
516
586
|
*/
|
|
517
587
|
async function setUserVerify(userId, type, password, deadline) {
|
|
588
|
+
const setVerifiers = await setVerifiersPromise;
|
|
589
|
+
if (!Object.hasOwn(setVerifiers, type)) return false;
|
|
518
590
|
for (const fn of setVerifiers[type] || []) if (await fn(userId, password, deadline)) return true;
|
|
519
591
|
return false;
|
|
520
592
|
}
|
|
521
593
|
/** @type {(user?: string?) => Promise<Set<string>>} */
|
|
522
594
|
const loadUserPermissions = createKeyStore(async (user) => {
|
|
523
595
|
if (!user) return /* @__PURE__ */ new Set();
|
|
524
|
-
for (const f of getPermissions) {
|
|
596
|
+
for (const f of await getPermissions) {
|
|
525
597
|
const r = await f(user);
|
|
526
598
|
if (r) return new Set(r);
|
|
527
599
|
}
|
|
@@ -553,7 +625,7 @@ async function hasUserPermission(permission, logged) {
|
|
|
553
625
|
/** @type {(user?: string?) => Promise<Set<string>>} */
|
|
554
626
|
const loadUserOrganizationAllPermissions = createKeyStore(async (user) => {
|
|
555
627
|
if (!user) return /* @__PURE__ */ new Set();
|
|
556
|
-
for (const f of getOrganizationAllPermissions) {
|
|
628
|
+
for (const f of await getOrganizationAllPermissions) {
|
|
557
629
|
const r = await f(user);
|
|
558
630
|
if (r) return new Set(r);
|
|
559
631
|
}
|
|
@@ -576,7 +648,7 @@ async function getUserOrganizationAllPermissions(logged) {
|
|
|
576
648
|
/** @type {(user?: string?) => Promise<Record<string, Set<string>>>} */
|
|
577
649
|
const loadUserOrganizationPermissions = createKeyStore(async (user) => {
|
|
578
650
|
if (!user) return Object.create(null);
|
|
579
|
-
for (const f of getOrganizationPermissions) {
|
|
651
|
+
for (const f of await getOrganizationPermissions) {
|
|
580
652
|
const r = await f(user);
|
|
581
653
|
if (r) return Object.assign(Object.create(null), Object.fromEntries(Object.entries(r).map(([k, v]) => [k, new Set(v)])));
|
|
582
654
|
}
|
|
@@ -631,13 +703,17 @@ async function hasUserOrganizationPermissions(permission, organization, logged)
|
|
|
631
703
|
if (!permission) return true;
|
|
632
704
|
return permissions.has(permission);
|
|
633
705
|
}
|
|
706
|
+
const userPluginLoaders = userManagerMap.lazyThen((list) => {
|
|
707
|
+
return list.map(([k, v]) => [k, v?.loadPlugin]).filter(([, v]) => typeof v === "function");
|
|
708
|
+
});
|
|
634
709
|
/**
|
|
635
710
|
*
|
|
636
711
|
* @param {string} userId
|
|
637
712
|
* @returns {Promise<Record<string, any>>}
|
|
638
713
|
*/
|
|
639
714
|
async function loadPluginUser(userId) {
|
|
640
|
-
const
|
|
715
|
+
const loaders = await userPluginLoaders;
|
|
716
|
+
const list2 = await Promise.all(loaders.map(([p, f]) => Promise.all([p, f(userId)])));
|
|
641
717
|
return Object.fromEntries(Object.entries(Object.groupBy(list2, ([k]) => k)).map(([k, l]) => {
|
|
642
718
|
return [k, Object.assign({}, ...l?.map((v) => v[1]) || [])];
|
|
643
719
|
}));
|
|
@@ -649,7 +725,7 @@ async function loadPluginUser(userId) {
|
|
|
649
725
|
*/
|
|
650
726
|
async function loadUser(userId, plugin = false) {
|
|
651
727
|
const [list, plugins, permissions, organizationPermissions] = await Promise.all([
|
|
652
|
-
Promise.all(loaders.map((f) => f(userId))),
|
|
728
|
+
loaders.then((loaders) => Promise.all(loaders.map((f) => f(userId)))),
|
|
653
729
|
plugin ? loadPluginUser(userId) : {},
|
|
654
730
|
loadUserPermissions(userId).then((p) => [...p]),
|
|
655
731
|
loadUserOrganizationPermissions(userId).then((p) => Object.fromEntries(Object.entries(p).map(([k, v]) => [k, [...v]])))
|
|
@@ -662,6 +738,160 @@ async function loadUser(userId, plugin = false) {
|
|
|
662
738
|
});
|
|
663
739
|
}
|
|
664
740
|
|
|
741
|
+
//#endregion
|
|
742
|
+
//#region packages/core/visitor.mjs
|
|
743
|
+
/** @import { VisitorManager } from './types.mjs' */
|
|
744
|
+
/**
|
|
745
|
+
* @typedef {[result: string | null, VisitorManager['set'] | null, VisitorManager['exit'] | null, visitor: string | null]} VisitorState
|
|
746
|
+
*/
|
|
747
|
+
const [visitorGetter, visitorSetter] = createStoreSerializable("visitorStatus", async (state) => {
|
|
748
|
+
if (!state) return null;
|
|
749
|
+
return { visitor: (await state)[3] };
|
|
750
|
+
}, (val) => {
|
|
751
|
+
if (!val) return null;
|
|
752
|
+
const { visitor: visitorId } = val;
|
|
753
|
+
return Promise.resolve([
|
|
754
|
+
null,
|
|
755
|
+
null,
|
|
756
|
+
null,
|
|
757
|
+
visitorId
|
|
758
|
+
]);
|
|
759
|
+
}, null);
|
|
760
|
+
const visitors = LazyPromise.try(async function() {
|
|
761
|
+
return (await Array.fromAsync(loadPluginProfiles("visitor"))).map((v) => v[1]);
|
|
762
|
+
});
|
|
763
|
+
const existTesters = visitors.lazyThen((v) => v.map((v) => v.exist).filter((v) => typeof v === "function"));
|
|
764
|
+
/**
|
|
765
|
+
*
|
|
766
|
+
* @param {string} visitorId
|
|
767
|
+
* @returns {Promise<boolean>}
|
|
768
|
+
*/
|
|
769
|
+
async function existVisitor(visitorId) {
|
|
770
|
+
for (const fn of await existTesters) if (await fn(visitorId)) return true;
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
773
|
+
const getLoggedVisitorFn = visitors.lazyThen((list) => {
|
|
774
|
+
/** @type {[VisitorManager['get'], VisitorManager['set'] | null, VisitorManager['exit'] | null][]} */
|
|
775
|
+
const getLoggedVisitorFn = [];
|
|
776
|
+
for (const { get, set, exit } of list) {
|
|
777
|
+
if (typeof get !== "function") continue;
|
|
778
|
+
getLoggedVisitorFn.push([
|
|
779
|
+
get,
|
|
780
|
+
set || null,
|
|
781
|
+
exit || null
|
|
782
|
+
]);
|
|
783
|
+
}
|
|
784
|
+
return getLoggedVisitorFn;
|
|
785
|
+
});
|
|
786
|
+
const defaultLogin = visitors.lazyThen((v) => v.find((v) => typeof v.login === "function")?.login || null);
|
|
787
|
+
/**
|
|
788
|
+
*
|
|
789
|
+
* @returns {Promise<VisitorState>}
|
|
790
|
+
*/
|
|
791
|
+
async function getLoggedVisitor() {
|
|
792
|
+
/** @type {VisitorManager['set']?} */
|
|
793
|
+
let setVisitor = null;
|
|
794
|
+
/** @type {VisitorManager['exit']?} */
|
|
795
|
+
let exitVisitor = null;
|
|
796
|
+
/** @type {string?} */
|
|
797
|
+
let visitor = null;
|
|
798
|
+
for (const [get, set, exit] of await getLoggedVisitorFn) {
|
|
799
|
+
const u = await get();
|
|
800
|
+
if (!u || !await existVisitor(u)) continue;
|
|
801
|
+
visitor = u;
|
|
802
|
+
setVisitor = set;
|
|
803
|
+
exitVisitor = exit;
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
if (!visitor) return [
|
|
807
|
+
null,
|
|
808
|
+
await defaultLogin,
|
|
809
|
+
null,
|
|
810
|
+
null
|
|
811
|
+
];
|
|
812
|
+
return [
|
|
813
|
+
null,
|
|
814
|
+
setVisitor,
|
|
815
|
+
exitVisitor,
|
|
816
|
+
visitor
|
|
817
|
+
];
|
|
818
|
+
}
|
|
819
|
+
async function get() {
|
|
820
|
+
let state = visitorGetter();
|
|
821
|
+
if (!state) {
|
|
822
|
+
state = getLoggedVisitor();
|
|
823
|
+
visitorSetter(state);
|
|
824
|
+
}
|
|
825
|
+
return state;
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
*
|
|
829
|
+
* @returns {Promise<string?>}
|
|
830
|
+
*/
|
|
831
|
+
function getVisitor() {
|
|
832
|
+
return get().then(([, , , current]) => current);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
*
|
|
836
|
+
* @param {string?} visitorId
|
|
837
|
+
* @returns {Promise<string?>}
|
|
838
|
+
*/
|
|
839
|
+
function setVisitor(visitorId) {
|
|
840
|
+
let state = Promise.resolve(visitorGetter() || getLoggedVisitor());
|
|
841
|
+
state = state.then(async ([, set, exit, current]) => {
|
|
842
|
+
if (!visitorId) {
|
|
843
|
+
if (current && exit) await exit(current);
|
|
844
|
+
return [
|
|
845
|
+
null,
|
|
846
|
+
set,
|
|
847
|
+
exit,
|
|
848
|
+
null
|
|
849
|
+
];
|
|
850
|
+
}
|
|
851
|
+
if (!set) return [
|
|
852
|
+
current,
|
|
853
|
+
set,
|
|
854
|
+
exit,
|
|
855
|
+
current
|
|
856
|
+
];
|
|
857
|
+
if (!await set(visitorId)) return [
|
|
858
|
+
null,
|
|
859
|
+
set,
|
|
860
|
+
exit,
|
|
861
|
+
current
|
|
862
|
+
];
|
|
863
|
+
return [
|
|
864
|
+
visitorId,
|
|
865
|
+
set,
|
|
866
|
+
exit,
|
|
867
|
+
visitorId
|
|
868
|
+
];
|
|
869
|
+
});
|
|
870
|
+
visitorSetter(state);
|
|
871
|
+
return state.then((v) => v[0]);
|
|
872
|
+
}
|
|
873
|
+
const finders = visitors.lazyThen((v) => v.map((v) => v.find).filter((v) => typeof v === "function"));
|
|
874
|
+
/**
|
|
875
|
+
*
|
|
876
|
+
* @param {Record<string, unknown>} loginName
|
|
877
|
+
* @returns {Promise<string>}
|
|
878
|
+
*/
|
|
879
|
+
async function findVisitor(loginName) {
|
|
880
|
+
for (const fn of await finders) {
|
|
881
|
+
const visitorId = await fn(loginName);
|
|
882
|
+
if (visitorId) return visitorId;
|
|
883
|
+
}
|
|
884
|
+
return "";
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
*
|
|
888
|
+
* @param {string} visitorId
|
|
889
|
+
* @returns {Promise<Record<string, any>>}
|
|
890
|
+
*/
|
|
891
|
+
async function loadVisitor(visitorId) {
|
|
892
|
+
return { id: visitorId };
|
|
893
|
+
}
|
|
894
|
+
|
|
665
895
|
//#endregion
|
|
666
896
|
//#region packages/core/permission/createPermissionMatches.mjs
|
|
667
897
|
/** @import { Permission } from '@yongdall/types' */
|
|
@@ -1009,18 +1239,21 @@ async function testPermissions(allPermissions, document) {
|
|
|
1009
1239
|
//#endregion
|
|
1010
1240
|
//#region packages/core/decorators/modelHook.mjs
|
|
1011
1241
|
/** @import { Hooks, ClassDecorator } from '@yongdall/model' */
|
|
1012
|
-
/** @
|
|
1013
|
-
|
|
1242
|
+
/** @import { ModelProfile } from '../types.mjs' */
|
|
1243
|
+
const modelHooksPromise = LazyPromise.try(async function() {
|
|
1014
1244
|
/** @returns {{[K in keyof Hooks]: Record<string, Hooks[K][]>}} */
|
|
1015
1245
|
const modelHooks = Object.create(null);
|
|
1016
|
-
|
|
1246
|
+
const list = await Array.fromAsync(loadPluginProfiles("model", function* ({ modelHook }) {
|
|
1247
|
+
if (!modelHook || typeof modelHook !== "object" || Array.isArray(modelHook)) return;
|
|
1248
|
+
yield* Object.entries(modelHook);
|
|
1249
|
+
}));
|
|
1250
|
+
for (const [model, v] of Object.entries(list)) for (const [name, fn] of Object.entries(v)) {
|
|
1017
1251
|
if (typeof fn !== "function") continue;
|
|
1018
1252
|
const list = modelHooks[name] ||= Object.create(null);
|
|
1019
1253
|
(list[model] ||= []).push(fn);
|
|
1020
1254
|
}
|
|
1021
1255
|
return modelHooks;
|
|
1022
|
-
}
|
|
1023
|
-
const modelHooks = loadHooks();
|
|
1256
|
+
});
|
|
1024
1257
|
/**
|
|
1025
1258
|
*
|
|
1026
1259
|
* @param {Partial<Hooks>} hooks
|
|
@@ -1034,6 +1267,7 @@ function bindModelHooks({ where, beforeCreateMany, afterCreateMany, beforeCreate
|
|
|
1034
1267
|
where: where || (() => {}),
|
|
1035
1268
|
async beforeCreateMany(conn, model, record) {
|
|
1036
1269
|
let data = record;
|
|
1270
|
+
const modelHooks = await modelHooksPromise;
|
|
1037
1271
|
for (const name of names) for (const hook of modelHooks.beforeCreateMany[name] || []) {
|
|
1038
1272
|
if (typeof hook !== "function") continue;
|
|
1039
1273
|
data = await hook(conn, model, data) || data;
|
|
@@ -1043,6 +1277,7 @@ function bindModelHooks({ where, beforeCreateMany, afterCreateMany, beforeCreate
|
|
|
1043
1277
|
},
|
|
1044
1278
|
async afterCreateMany(conn, model, record) {
|
|
1045
1279
|
if (typeof afterCreateMany === "function") await afterCreateMany(conn, model, record);
|
|
1280
|
+
const modelHooks = await modelHooksPromise;
|
|
1046
1281
|
for (const name of names) for (const hook of modelHooks.afterCreateMany[name] || []) {
|
|
1047
1282
|
if (typeof hook !== "function") continue;
|
|
1048
1283
|
await hook(conn, model, record);
|
|
@@ -1050,6 +1285,7 @@ function bindModelHooks({ where, beforeCreateMany, afterCreateMany, beforeCreate
|
|
|
1050
1285
|
},
|
|
1051
1286
|
async beforeCreate(conn, model, record) {
|
|
1052
1287
|
let data = record;
|
|
1288
|
+
const modelHooks = await modelHooksPromise;
|
|
1053
1289
|
for (const name of names) for (const hook of modelHooks.beforeCreate[name] || []) {
|
|
1054
1290
|
if (typeof hook !== "function") continue;
|
|
1055
1291
|
data = await hook(conn, model, data) || data;
|
|
@@ -1059,6 +1295,7 @@ function bindModelHooks({ where, beforeCreateMany, afterCreateMany, beforeCreate
|
|
|
1059
1295
|
},
|
|
1060
1296
|
async afterCreate(conn, model, record) {
|
|
1061
1297
|
if (typeof afterCreate === "function") await afterCreate(conn, model, record);
|
|
1298
|
+
const modelHooks = await modelHooksPromise;
|
|
1062
1299
|
for (const name of names) for (const hook of modelHooks.afterCreate[name] || []) {
|
|
1063
1300
|
if (typeof hook !== "function") continue;
|
|
1064
1301
|
await hook(conn, model, record);
|
|
@@ -1066,6 +1303,7 @@ function bindModelHooks({ where, beforeCreateMany, afterCreateMany, beforeCreate
|
|
|
1066
1303
|
},
|
|
1067
1304
|
async beforeUpdate(conn, model, record, set) {
|
|
1068
1305
|
let data = set;
|
|
1306
|
+
const modelHooks = await modelHooksPromise;
|
|
1069
1307
|
for (const name of names) for (const hook of modelHooks.beforeUpdate[name] || []) {
|
|
1070
1308
|
if (typeof hook !== "function") continue;
|
|
1071
1309
|
data = await hook(conn, model, record, data) || data;
|
|
@@ -1075,12 +1313,14 @@ function bindModelHooks({ where, beforeCreateMany, afterCreateMany, beforeCreate
|
|
|
1075
1313
|
},
|
|
1076
1314
|
async afterUpdate(conn, model, record, oldRecord) {
|
|
1077
1315
|
if (typeof afterUpdate === "function") await afterUpdate(conn, model, record, oldRecord);
|
|
1316
|
+
const modelHooks = await modelHooksPromise;
|
|
1078
1317
|
for (const name of names) for (const hook of modelHooks.afterUpdate[name] || []) {
|
|
1079
1318
|
if (typeof hook !== "function") continue;
|
|
1080
1319
|
await hook(conn, model, record, oldRecord);
|
|
1081
1320
|
}
|
|
1082
1321
|
},
|
|
1083
1322
|
async beforeDelete(conn, model, record, update) {
|
|
1323
|
+
const modelHooks = await modelHooksPromise;
|
|
1084
1324
|
for (const name of names) for (const hook of modelHooks.beforeDelete[name] || []) {
|
|
1085
1325
|
if (typeof hook !== "function") continue;
|
|
1086
1326
|
await hook(conn, model, record, update);
|
|
@@ -1089,6 +1329,7 @@ function bindModelHooks({ where, beforeCreateMany, afterCreateMany, beforeCreate
|
|
|
1089
1329
|
},
|
|
1090
1330
|
async afterDelete(conn, model, record, update) {
|
|
1091
1331
|
if (typeof afterDelete === "function") await afterDelete(conn, model, record, update);
|
|
1332
|
+
const modelHooks = await modelHooksPromise;
|
|
1092
1333
|
for (const name of names) for (const hook of modelHooks.afterDelete[name] || []) {
|
|
1093
1334
|
if (typeof hook !== "function") continue;
|
|
1094
1335
|
await hook(conn, model, record, update);
|
|
@@ -1108,6 +1349,7 @@ function modelHook(...hookNames) {
|
|
|
1108
1349
|
if (!names.length) return;
|
|
1109
1350
|
beforeCreateMany(Model, async (conn, model, record) => {
|
|
1110
1351
|
let data = record;
|
|
1352
|
+
const modelHooks = await modelHooksPromise;
|
|
1111
1353
|
for (const name of names) for (const hook of modelHooks.beforeCreateMany[name] || []) {
|
|
1112
1354
|
if (typeof hook !== "function") continue;
|
|
1113
1355
|
data = await hook(conn, model, data) || data;
|
|
@@ -1115,6 +1357,7 @@ function modelHook(...hookNames) {
|
|
|
1115
1357
|
return data;
|
|
1116
1358
|
});
|
|
1117
1359
|
afterCreateMany(Model, async (conn, model, record) => {
|
|
1360
|
+
const modelHooks = await modelHooksPromise;
|
|
1118
1361
|
for (const name of names) for (const hook of modelHooks.afterCreateMany[name] || []) {
|
|
1119
1362
|
if (typeof hook !== "function") continue;
|
|
1120
1363
|
await hook(conn, model, record);
|
|
@@ -1122,6 +1365,7 @@ function modelHook(...hookNames) {
|
|
|
1122
1365
|
});
|
|
1123
1366
|
beforeCreate(Model, async (conn, model, record) => {
|
|
1124
1367
|
let data = record;
|
|
1368
|
+
const modelHooks = await modelHooksPromise;
|
|
1125
1369
|
for (const name of names) for (const hook of modelHooks.beforeCreate[name] || []) {
|
|
1126
1370
|
if (typeof hook !== "function") continue;
|
|
1127
1371
|
data = await hook(conn, model, data) || data;
|
|
@@ -1129,6 +1373,7 @@ function modelHook(...hookNames) {
|
|
|
1129
1373
|
return data;
|
|
1130
1374
|
});
|
|
1131
1375
|
afterCreate(Model, async (conn, model, record) => {
|
|
1376
|
+
const modelHooks = await modelHooksPromise;
|
|
1132
1377
|
for (const name of names) for (const hook of modelHooks.afterCreate[name] || []) {
|
|
1133
1378
|
if (typeof hook !== "function") continue;
|
|
1134
1379
|
await hook(conn, model, record);
|
|
@@ -1136,6 +1381,7 @@ function modelHook(...hookNames) {
|
|
|
1136
1381
|
});
|
|
1137
1382
|
beforeUpdate(Model, async (conn, model, record, set) => {
|
|
1138
1383
|
let data = set;
|
|
1384
|
+
const modelHooks = await modelHooksPromise;
|
|
1139
1385
|
for (const name of names) for (const hook of modelHooks.beforeUpdate[name] || []) {
|
|
1140
1386
|
if (typeof hook !== "function") continue;
|
|
1141
1387
|
data = await hook(conn, model, record, data) || data;
|
|
@@ -1143,18 +1389,21 @@ function modelHook(...hookNames) {
|
|
|
1143
1389
|
return data;
|
|
1144
1390
|
});
|
|
1145
1391
|
afterUpdate(Model, async (conn, model, record, oldRecord) => {
|
|
1392
|
+
const modelHooks = await modelHooksPromise;
|
|
1146
1393
|
for (const name of names) for (const hook of modelHooks.afterUpdate[name] || []) {
|
|
1147
1394
|
if (typeof hook !== "function") continue;
|
|
1148
1395
|
await hook(conn, model, record, oldRecord);
|
|
1149
1396
|
}
|
|
1150
1397
|
});
|
|
1151
1398
|
beforeDelete(Model, async (conn, model, record, update) => {
|
|
1399
|
+
const modelHooks = await modelHooksPromise;
|
|
1152
1400
|
for (const name of names) for (const hook of modelHooks.beforeDelete[name] || []) {
|
|
1153
1401
|
if (typeof hook !== "function") continue;
|
|
1154
1402
|
await hook(conn, model, record, update);
|
|
1155
1403
|
}
|
|
1156
1404
|
});
|
|
1157
1405
|
afterDelete(Model, async (conn, model, record, update) => {
|
|
1406
|
+
const modelHooks = await modelHooksPromise;
|
|
1158
1407
|
for (const name of names) for (const hook of modelHooks.afterDelete[name] || []) {
|
|
1159
1408
|
if (typeof hook !== "function") continue;
|
|
1160
1409
|
await hook(conn, model, record, update);
|
|
@@ -1167,14 +1416,17 @@ function modelHook(...hookNames) {
|
|
|
1167
1416
|
//#region packages/core/ServerError.mjs
|
|
1168
1417
|
var ServerError = class extends Error {
|
|
1169
1418
|
status = 500;
|
|
1419
|
+
code = "";
|
|
1170
1420
|
/**
|
|
1171
1421
|
*
|
|
1172
|
-
* @param {string} message
|
|
1422
|
+
* @param {string | {code?: string; message: string; status?: number}} message
|
|
1173
1423
|
* @param {number} [status]
|
|
1174
1424
|
*/
|
|
1175
1425
|
constructor(message, status = 500) {
|
|
1176
|
-
super(message);
|
|
1177
|
-
|
|
1426
|
+
super(typeof message === "string" ? message : message.message);
|
|
1427
|
+
const s = typeof message === "object" && message.status || status;
|
|
1428
|
+
this.status = s;
|
|
1429
|
+
this.code = typeof message === "object" && message.code || String(s);
|
|
1178
1430
|
}
|
|
1179
1431
|
};
|
|
1180
1432
|
|
|
@@ -1359,20 +1611,24 @@ function toDocumentFields(fields) {
|
|
|
1359
1611
|
//#endregion
|
|
1360
1612
|
//#region packages/core/enumerations.mjs
|
|
1361
1613
|
/** @import { MaybePromise } from './types.mjs' */
|
|
1362
|
-
/** @type {Record<string, (Record<string, any> | (() => MaybePromise<Record<string, any>[]>))[]
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1614
|
+
/** @type {Promise<Record<string, (Record<string, any> | (() => MaybePromise<Record<string, any>[]>))[]>>} */
|
|
1615
|
+
const enumerationsPromise = LazyPromise.try(async function() {
|
|
1616
|
+
const list = await Array.fromAsync(loadPluginProfiles("enumeration", function* (c) {
|
|
1617
|
+
yield* c && typeof c === "object" && !Array.isArray(c) ? Object.entries(c) : [];
|
|
1618
|
+
}));
|
|
1619
|
+
const groups = Object.groupBy(list, ([k]) => k);
|
|
1620
|
+
return Object.fromEntries(Object.entries(groups).map(([k, v]) => [k, v?.map((v) => v[1]).flat(2) || []]));
|
|
1621
|
+
});
|
|
1368
1622
|
/**
|
|
1369
1623
|
*
|
|
1370
1624
|
* @param {string} name
|
|
1371
1625
|
* @returns {Promise<Record<string, any>[]>}
|
|
1372
1626
|
*/
|
|
1373
1627
|
async function getEnumerations(name) {
|
|
1374
|
-
|
|
1375
|
-
|
|
1628
|
+
const allEnumerations = await enumerationsPromise;
|
|
1629
|
+
if (!Object.hasOwn(allEnumerations, name)) return [];
|
|
1630
|
+
const enumerations = allEnumerations[name].map((v) => typeof v === "function" ? v() : v);
|
|
1631
|
+
return await Promise.all(enumerations).then((v) => v.flat());
|
|
1376
1632
|
}
|
|
1377
1633
|
|
|
1378
1634
|
//#endregion
|
|
@@ -1733,20 +1989,53 @@ async function search2where(fields, and, or, or2) {
|
|
|
1733
1989
|
}, fields, and, or, or2), execWhere, null);
|
|
1734
1990
|
}
|
|
1735
1991
|
|
|
1992
|
+
//#endregion
|
|
1993
|
+
//#region packages/core/safe.mjs
|
|
1994
|
+
/**
|
|
1995
|
+
* 使用 HMAC-SHA256 对一个或多个值进行哈希,使用 salt 作为密钥。
|
|
1996
|
+
* 输出为 base64url 格式。
|
|
1997
|
+
*
|
|
1998
|
+
* @param {string | ArrayBuffer | ArrayBufferView<ArrayBuffer>} salt
|
|
1999
|
+
* @param {string | number} value
|
|
2000
|
+
* @param {...(string | number)} values
|
|
2001
|
+
* @returns {Promise<string>}
|
|
2002
|
+
*/
|
|
2003
|
+
async function hashSHA256(salt, value, ...values) {
|
|
2004
|
+
/** @type {ArrayBuffer | ArrayBufferView<ArrayBuffer>} */
|
|
2005
|
+
let keyBuffer;
|
|
2006
|
+
if (salt instanceof ArrayBuffer || ArrayBuffer.isView(salt)) keyBuffer = salt;
|
|
2007
|
+
else if (typeof salt === "string") keyBuffer = new TextEncoder().encode(salt);
|
|
2008
|
+
else throw new Error("`salt` 参数必须为字符串或 Uint8Array");
|
|
2009
|
+
const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, {
|
|
2010
|
+
name: "HMAC",
|
|
2011
|
+
hash: "SHA-256"
|
|
2012
|
+
}, false, ["sign"]);
|
|
2013
|
+
/** @type {string[]} */
|
|
2014
|
+
let data = [];
|
|
2015
|
+
if (typeof value === "number") data.push(String(value));
|
|
2016
|
+
else if (typeof value === "string") data.push(JSON.stringify(value).slice(1, -1));
|
|
2017
|
+
else throw new Error("`value` 参数必须为字符串或数字");
|
|
2018
|
+
for (const v of values) if (typeof v === "number") data.push(String(v));
|
|
2019
|
+
else if (typeof v === "string") data.push(JSON.stringify(v).slice(1, -1));
|
|
2020
|
+
const messageBuffer = new TextEncoder().encode(data.join("\n"));
|
|
2021
|
+
const signature = await crypto.subtle.sign("HMAC", cryptoKey, messageBuffer);
|
|
2022
|
+
return btoa(String.fromCharCode(...new Uint8Array(signature))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2023
|
+
}
|
|
2024
|
+
|
|
1736
2025
|
//#endregion
|
|
1737
2026
|
//#region packages/core/index.mjs
|
|
1738
2027
|
/**
|
|
1739
2028
|
*
|
|
1740
|
-
* @param {Partial<Omit<
|
|
2029
|
+
* @param {Partial<Omit<Realm, 'id'>>} realm
|
|
1741
2030
|
* @param {object} boot
|
|
1742
2031
|
* @param {Record<string, Partial<Hooks>>} pluginHooks
|
|
1743
2032
|
* @returns
|
|
1744
2033
|
*/
|
|
1745
|
-
function initSystem(
|
|
1746
|
-
initConfig(
|
|
2034
|
+
function initSystem(realm, boot, pluginHooks) {
|
|
2035
|
+
initConfig(realm, boot);
|
|
1747
2036
|
Hook.update(hooks, pluginHooks);
|
|
1748
2037
|
}
|
|
1749
2038
|
|
|
1750
2039
|
//#endregion
|
|
1751
|
-
export { ServerError, bindModelHooks, bootConfiguration, createPermissionMatches, initSystem as default, existUser, filterPermissionDocument, filterPermissionUpdate, filterPermissions, findModel, findUser, getEnumerations, getMenus, getModel, getModelAuthorizationPermissions, getModelPermissions, getUser, getUserOrganizationAllPermissions, getUserOrganizationPermissions, getUserPermissions, hasUserOrganizationPermissions, hasUserPermission, hooks, initConfig, isSingleUser, loadPluginUser, loadUser, loadUserOrganizationAllPermissions, loadUserOrganizationPermissions, loadUserPermissions,
|
|
2040
|
+
export { ServerError, bindModelHooks, bootConfiguration, createPermissionMatches, initSystem as default, existUser, existVisitor, filterPermissionDocument, filterPermissionUpdate, filterPermissions, findModel, findUser, findVisitor, getEnumerations, getMenus, getModel, getModelAuthorizationPermissions, getModelPermissions, getUser, getUserOrganizationAllPermissions, getUserOrganizationPermissions, getUserPermissions, getVisitor, hasUserOrganizationPermissions, hasUserPermission, hashSHA256, hooks, initConfig, isSingleUser, loadPluginUser, loadUser, loadUserOrganizationAllPermissions, loadUserOrganizationPermissions, loadUserPermissions, loadVisitor, mainRealm, mainTenant, modelHook, nestedSetTree, search2where, setUser, setUserVerify, setVisitor, testPermissionConstraints, testPermissions, toDocumentFields, useRealm, useSalt, useTenant, verifyUser };
|
|
1752
2041
|
//# sourceMappingURL=index.mjs.map
|