@stoker-platform/utils 0.2.1
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/lib/src/access/collection.d.ts +9 -0
- package/lib/src/access/collection.js +59 -0
- package/lib/src/access/document.d.ts +3 -0
- package/lib/src/access/document.js +191 -0
- package/lib/src/access/getCollectionRestrictions.d.ts +7 -0
- package/lib/src/access/getCollectionRestrictions.js +71 -0
- package/lib/src/access/getRecordSubcollections.d.ts +2 -0
- package/lib/src/access/getRecordSubcollections.js +15 -0
- package/lib/src/access/getRelatedCollections.d.ts +2 -0
- package/lib/src/access/getRelatedCollections.js +24 -0
- package/lib/src/access/hasDependencyAccess.d.ts +2 -0
- package/lib/src/access/hasDependencyAccess.js +24 -0
- package/lib/src/access/isPaginationEnabled.d.ts +2 -0
- package/lib/src/access/isPaginationEnabled.js +35 -0
- package/lib/src/access/permissions.d.ts +2 -0
- package/lib/src/access/permissions.js +543 -0
- package/lib/src/access/read/getOne.d.ts +2 -0
- package/lib/src/access/read/getOne.js +19 -0
- package/lib/src/access/read/getSome.d.ts +2 -0
- package/lib/src/access/read/getSome.js +21 -0
- package/lib/src/access/roleHasOperationAccess.d.ts +2 -0
- package/lib/src/access/roleHasOperationAccess.js +7 -0
- package/lib/src/access/write/addRecord.d.ts +2 -0
- package/lib/src/access/write/addRecord.js +40 -0
- package/lib/src/access/write/deleteRecord.d.ts +2 -0
- package/lib/src/access/write/deleteRecord.js +26 -0
- package/lib/src/access/write/updateRecord.d.ts +2 -0
- package/lib/src/access/write/updateRecord.js +61 -0
- package/lib/src/getConfigValue.d.ts +12 -0
- package/lib/src/getConfigValue.js +83 -0
- package/lib/src/getCustomization.d.ts +4 -0
- package/lib/src/getCustomization.js +29 -0
- package/lib/src/getFieldCustomization.d.ts +7 -0
- package/lib/src/getFieldCustomization.js +3 -0
- package/lib/src/main.d.ts +60 -0
- package/lib/src/main.js +60 -0
- package/lib/src/operations/addInitialValues.d.ts +2 -0
- package/lib/src/operations/addInitialValues.js +27 -0
- package/lib/src/operations/addLowercaseFields.d.ts +2 -0
- package/lib/src/operations/addLowercaseFields.js +12 -0
- package/lib/src/operations/addRelationArrays.d.ts +2 -0
- package/lib/src/operations/addRelationArrays.js +60 -0
- package/lib/src/operations/addSystemFields.d.ts +2 -0
- package/lib/src/operations/addSystemFields.js +17 -0
- package/lib/src/operations/getDateRange.d.ts +5 -0
- package/lib/src/operations/getDateRange.js +56 -0
- package/lib/src/operations/getExtendedSchema.d.ts +2 -0
- package/lib/src/operations/getExtendedSchema.js +23 -0
- package/lib/src/operations/getFinalRecord.d.ts +1 -0
- package/lib/src/operations/getFinalRecord.js +11 -0
- package/lib/src/operations/getInputSchema.d.ts +15 -0
- package/lib/src/operations/getInputSchema.js +352 -0
- package/lib/src/operations/getLowercaseFields.d.ts +2 -0
- package/lib/src/operations/getLowercaseFields.js +15 -0
- package/lib/src/operations/getSingleFieldRelations.d.ts +2 -0
- package/lib/src/operations/getSingleFieldRelations.js +27 -0
- package/lib/src/operations/getZodSchema.d.ts +15 -0
- package/lib/src/operations/getZodSchema.js +303 -0
- package/lib/src/operations/isDeleteSentinel.d.ts +1 -0
- package/lib/src/operations/isDeleteSentinel.js +4 -0
- package/lib/src/operations/isSortingEnabled.d.ts +2 -0
- package/lib/src/operations/isSortingEnabled.js +7 -0
- package/lib/src/operations/isValidUniqueFieldValue.d.ts +1 -0
- package/lib/src/operations/isValidUniqueFieldValue.js +25 -0
- package/lib/src/operations/parseDate.d.ts +1 -0
- package/lib/src/operations/parseDate.js +4 -0
- package/lib/src/operations/prepareDenormalized.d.ts +8 -0
- package/lib/src/operations/prepareDenormalized.js +312 -0
- package/lib/src/operations/removeDeleteSentinels.d.ts +2 -0
- package/lib/src/operations/removeDeleteSentinels.js +15 -0
- package/lib/src/operations/removeDeletedFields.d.ts +2 -0
- package/lib/src/operations/removeDeletedFields.js +14 -0
- package/lib/src/operations/removeEmptyStrings.d.ts +2 -0
- package/lib/src/operations/removeEmptyStrings.js +14 -0
- package/lib/src/operations/removePrivateFields.d.ts +2 -0
- package/lib/src/operations/removePrivateFields.js +14 -0
- package/lib/src/operations/removeUndefined.d.ts +2 -0
- package/lib/src/operations/removeUndefined.js +14 -0
- package/lib/src/operations/retryOperation.d.ts +1 -0
- package/lib/src/operations/retryOperation.js +21 -0
- package/lib/src/operations/runHooks.d.ts +17 -0
- package/lib/src/operations/runHooks.js +18 -0
- package/lib/src/operations/sanitizeDownloadFilename.d.ts +1 -0
- package/lib/src/operations/sanitizeDownloadFilename.js +18 -0
- package/lib/src/operations/sanitizeEmailInput.d.ts +5 -0
- package/lib/src/operations/sanitizeEmailInput.js +73 -0
- package/lib/src/operations/updateFieldReference.d.ts +2 -0
- package/lib/src/operations/updateFieldReference.js +14 -0
- package/lib/src/operations/validateRecord.d.ts +2 -0
- package/lib/src/operations/validateRecord.js +18 -0
- package/lib/src/operations/validateStorageName.d.ts +1 -0
- package/lib/src/operations/validateStorageName.js +19 -0
- package/lib/src/schema/getAccessFields.d.ts +2 -0
- package/lib/src/schema/getAccessFields.js +62 -0
- package/lib/src/schema/getCollection.d.ts +2 -0
- package/lib/src/schema/getCollection.js +3 -0
- package/lib/src/schema/getDependencyFields.d.ts +6 -0
- package/lib/src/schema/getDependencyFields.js +22 -0
- package/lib/src/schema/getField.d.ts +2 -0
- package/lib/src/schema/getField.js +3 -0
- package/lib/src/schema/getFieldNames.d.ts +2 -0
- package/lib/src/schema/getFieldNames.js +3 -0
- package/lib/src/schema/getIndexFields.d.ts +9 -0
- package/lib/src/schema/getIndexFields.js +184 -0
- package/lib/src/schema/getInverseRelationType.d.ts +1 -0
- package/lib/src/schema/getInverseRelationType.js +15 -0
- package/lib/src/schema/getPathCollections.d.ts +2 -0
- package/lib/src/schema/getPathCollections.js +12 -0
- package/lib/src/schema/getRecordSystemFields.d.ts +2 -0
- package/lib/src/schema/getRecordSystemFields.js +11 -0
- package/lib/src/schema/getRelationLists.d.ts +5 -0
- package/lib/src/schema/getRelationLists.js +13 -0
- package/lib/src/schema/getSubcollections.d.ts +2 -0
- package/lib/src/schema/getSubcollections.js +9 -0
- package/lib/src/schema/getSystemFieldsSchema.d.ts +2 -0
- package/lib/src/schema/getSystemFieldsSchema.js +52 -0
- package/lib/src/schema/isDependencyField.d.ts +2 -0
- package/lib/src/schema/isDependencyField.js +18 -0
- package/lib/src/schema/isIncludedField.d.ts +2 -0
- package/lib/src/schema/isIncludedField.js +18 -0
- package/lib/src/schema/isRelationField.d.ts +2 -0
- package/lib/src/schema/isRelationField.js +3 -0
- package/lib/src/schema/system-fields.d.ts +2 -0
- package/lib/src/schema/system-fields.js +13 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { collectionAccess, collectionAuthAccess } from "../collection.js";
|
|
2
|
+
import { documentAccess } from "../document.js";
|
|
3
|
+
import { permissionsWriteAccess } from "../permissions.js";
|
|
4
|
+
export const deleteRecordAccessControl = (record, docId, collectionSchema, schema, currentUserId, currentUserPermissions) => {
|
|
5
|
+
const { labels } = collectionSchema;
|
|
6
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
7
|
+
const collectionPermissions = currentUserPermissions.collections?.[labels.collection];
|
|
8
|
+
let granted = true;
|
|
9
|
+
if (!collectionPermissions) {
|
|
10
|
+
throw new Error("PERMISSION_DENIED");
|
|
11
|
+
}
|
|
12
|
+
if (!collectionAccess("Delete", collectionPermissions))
|
|
13
|
+
granted = false;
|
|
14
|
+
if (!documentAccess("Delete", collectionSchema, schema, currentUserId, currentUserPermissions, record))
|
|
15
|
+
granted = false;
|
|
16
|
+
if (collectionSchema.auth && record.User_ID) {
|
|
17
|
+
if (!collectionAuthAccess(collectionPermissions))
|
|
18
|
+
granted = false;
|
|
19
|
+
if (!permissionsWriteAccess("delete", record, docId, collectionSchema, schema, currentUserId, currentUserPermissions)) {
|
|
20
|
+
granted = false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (!granted)
|
|
24
|
+
throw new Error("PERMISSION_DENIED");
|
|
25
|
+
return;
|
|
26
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
|
|
2
|
+
export declare const updateRecordAccessControl: (partial: StokerRecord, originalRecord: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, userOperation?: string, permissions?: StokerPermissions, originalPermissions?: StokerPermissions | undefined) => void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { collectionAccess, collectionAuthAccess, privateFieldAccess, restrictUpdateAccess } from "../collection.js";
|
|
2
|
+
import { documentAccess } from "../document.js";
|
|
3
|
+
import { permissionsWriteAccess } from "../permissions.js";
|
|
4
|
+
import { removeDeleteSentinels } from "../../operations/removeDeleteSentinels.js";
|
|
5
|
+
export const updateRecordAccessControl = (partial, originalRecord, docId, collectionSchema, schema, currentUserId, currentUserPermissions, userOperation, permissions, originalPermissions) => {
|
|
6
|
+
const { labels, fields } = collectionSchema;
|
|
7
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
8
|
+
const collectionPermissions = currentUserPermissions?.collections?.[labels.collection];
|
|
9
|
+
const finalRecord = { ...originalRecord, ...partial };
|
|
10
|
+
removeDeleteSentinels(finalRecord);
|
|
11
|
+
let granted = true;
|
|
12
|
+
let errorDetails = "";
|
|
13
|
+
const logErrors = true;
|
|
14
|
+
if (currentUserId && !collectionPermissions) {
|
|
15
|
+
throw new Error("PERMISSION_DENIED");
|
|
16
|
+
}
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
18
|
+
if (currentUserId && !collectionAccess("Update", collectionPermissions)) {
|
|
19
|
+
granted = false;
|
|
20
|
+
errorDetails = "Authenticated user does not have Update access to this collection";
|
|
21
|
+
}
|
|
22
|
+
if (currentUserId &&
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
24
|
+
(!documentAccess("Update", collectionSchema, schema, currentUserId, currentUserPermissions, originalRecord) ||
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
26
|
+
!documentAccess("Update", collectionSchema, schema, currentUserId, currentUserPermissions, finalRecord))) {
|
|
27
|
+
granted = false;
|
|
28
|
+
errorDetails = "Authenticated user does not have Update access to this document";
|
|
29
|
+
}
|
|
30
|
+
if (userOperation) {
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
32
|
+
if (currentUserId && !collectionAuthAccess(collectionPermissions)) {
|
|
33
|
+
granted = false;
|
|
34
|
+
errorDetails = "Authenticated user does not have Auth access for this collection";
|
|
35
|
+
}
|
|
36
|
+
if (!permissionsWriteAccess("update", finalRecord, docId, collectionSchema, schema, currentUserId, currentUserPermissions, permissions, originalPermissions, originalRecord, userOperation)) {
|
|
37
|
+
errorDetails = "Authenticated user does not have sufficient write access for this record";
|
|
38
|
+
granted = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const field of fields) {
|
|
42
|
+
const value = partial[field.name];
|
|
43
|
+
if (field.access) {
|
|
44
|
+
if (!privateFieldAccess(field, currentUserPermissions) && value !== undefined) {
|
|
45
|
+
errorDetails = `Authenticated user does not have access to field ${field.name}`;
|
|
46
|
+
granted = false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (value !== undefined && !restrictUpdateAccess(field, currentUserPermissions)) {
|
|
50
|
+
errorDetails = `Authenticated user does not have Update access to field ${field.name}`;
|
|
51
|
+
granted = false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!granted) {
|
|
55
|
+
if (logErrors && errorDetails) {
|
|
56
|
+
console.error(`PERMISSION_DENIED: ${errorDetails}`);
|
|
57
|
+
}
|
|
58
|
+
throw new Error("PERMISSION_DENIED");
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GlobalConfig, CollectionCustomization, StokerCollection, AuthConfig, FirebaseConfig, PreloadConfig, MailConfig, CollectionSchema, AdminConfig } from "@stoker-platform/types";
|
|
2
|
+
export declare const clearConfigCache: () => void;
|
|
3
|
+
export declare const tryFunction: (configProperty: unknown, args?: unknown[]) => any;
|
|
4
|
+
export declare const tryPromise: (configProperty: any, args?: unknown[]) => Promise<any>;
|
|
5
|
+
type ConfigPath = [
|
|
6
|
+
"global",
|
|
7
|
+
keyof GlobalConfig,
|
|
8
|
+
(keyof AuthConfig | keyof FirebaseConfig | keyof PreloadConfig | keyof MailConfig | keyof AdminConfig)?,
|
|
9
|
+
...string[]
|
|
10
|
+
] | ["collections", StokerCollection, keyof CollectionSchema, ...string[]];
|
|
11
|
+
export declare const getCachedConfigValue: (config: GlobalConfig | CollectionCustomization, pathArray: ConfigPath, args?: unknown[], overwrite?: boolean) => Promise<any>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import merge from "lodash/merge.js";
|
|
2
|
+
import set from "lodash/set.js";
|
|
3
|
+
const configCache = {
|
|
4
|
+
global: {},
|
|
5
|
+
collections: {},
|
|
6
|
+
};
|
|
7
|
+
export const clearConfigCache = () => {
|
|
8
|
+
configCache.global = {};
|
|
9
|
+
configCache.collections = {};
|
|
10
|
+
};
|
|
11
|
+
export const tryFunction = (configProperty, args) => {
|
|
12
|
+
if (configProperty && typeof configProperty === "function") {
|
|
13
|
+
return args ? configProperty(...args) : configProperty();
|
|
14
|
+
}
|
|
15
|
+
return configProperty;
|
|
16
|
+
};
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
+
export const tryPromise = async (configProperty, args) => {
|
|
19
|
+
let configValue = configProperty;
|
|
20
|
+
if (configProperty && (typeof configProperty === "function" || typeof configProperty.then === "function")) {
|
|
21
|
+
args ? (configValue = await configProperty(...args)) : (configValue = await configProperty());
|
|
22
|
+
}
|
|
23
|
+
return configValue;
|
|
24
|
+
};
|
|
25
|
+
export const getCachedConfigValue = async (config, pathArray, args, overwrite) => {
|
|
26
|
+
/* eslint-disable security/detect-object-injection, @typescript-eslint/no-explicit-any */
|
|
27
|
+
// Validate path array to prevent prototype pollution
|
|
28
|
+
for (const property of pathArray) {
|
|
29
|
+
if (property === "__proto__" || property === "constructor" || property === "prototype") {
|
|
30
|
+
throw new Error("Invalid config path: prototype pollution keys are not allowed");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
let configCacheProperty = configCache;
|
|
34
|
+
let existsInCache = true;
|
|
35
|
+
for (const property of pathArray) {
|
|
36
|
+
if (property === undefined || configCacheProperty[property] === undefined) {
|
|
37
|
+
existsInCache = false;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
configCacheProperty = configCacheProperty[property];
|
|
41
|
+
}
|
|
42
|
+
if (configCacheProperty && existsInCache && !overwrite) {
|
|
43
|
+
return configCacheProperty;
|
|
44
|
+
}
|
|
45
|
+
let modifiedPathArray;
|
|
46
|
+
let configProperty = config;
|
|
47
|
+
let existsInConfig = true;
|
|
48
|
+
pathArray[0] === "collections" ? (modifiedPathArray = pathArray.slice(2)) : (modifiedPathArray = pathArray.slice(1));
|
|
49
|
+
for (const property of modifiedPathArray) {
|
|
50
|
+
if (property === undefined || configProperty[property] === undefined) {
|
|
51
|
+
existsInConfig = false;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
configProperty = configProperty[property];
|
|
55
|
+
}
|
|
56
|
+
let configValue;
|
|
57
|
+
if (existsInConfig)
|
|
58
|
+
configValue = await tryPromise(configProperty, args);
|
|
59
|
+
if (configValue) {
|
|
60
|
+
let currentCache = configCache;
|
|
61
|
+
const cachePartial = {};
|
|
62
|
+
for (let i = 0; i < pathArray.length; i++) {
|
|
63
|
+
const property = pathArray[i];
|
|
64
|
+
if (property === undefined) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Additional check to prevent prototype pollution
|
|
68
|
+
if (property === "__proto__" || property === "constructor" || property === "prototype") {
|
|
69
|
+
throw new Error("Invalid config path: prototype pollution keys are not allowed");
|
|
70
|
+
}
|
|
71
|
+
if (i === pathArray.length - 1) {
|
|
72
|
+
set(cachePartial, pathArray.join("."), configValue);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
currentCache[property] ||= {};
|
|
76
|
+
currentCache = currentCache[property];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
merge(configCache, cachePartial);
|
|
80
|
+
}
|
|
81
|
+
/* eslint-enable security/detect-object-injection, @typescript-eslint/no-explicit-any */
|
|
82
|
+
return configValue;
|
|
83
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const getCustomization = (collections,
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3
|
+
modules, sdk,
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
utilities,
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
context) => {
|
|
8
|
+
const collectionFiles = {};
|
|
9
|
+
for (const collection of collections) {
|
|
10
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
11
|
+
const module = modules[collection];
|
|
12
|
+
const collectionFile = module.default(sdk, utilities, context);
|
|
13
|
+
for (const key in collectionFile) {
|
|
14
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
15
|
+
if (!(key === "custom" || key === "admin" || key === "fields"))
|
|
16
|
+
delete collectionFile[key];
|
|
17
|
+
}
|
|
18
|
+
for (const field of collectionFile.fields) {
|
|
19
|
+
for (const key in field) {
|
|
20
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
21
|
+
if (!(key === "custom" || key === "admin" || key === "name" || key === "formula"))
|
|
22
|
+
delete field[key];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
26
|
+
collectionFiles[collection] = collectionFile;
|
|
27
|
+
}
|
|
28
|
+
return collectionFiles;
|
|
29
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CollectionField, CollectionCustomization } from "@stoker-platform/types";
|
|
2
|
+
export declare const getFieldCustomization: (field: CollectionField, customizationFile: CollectionCustomization) => {
|
|
3
|
+
name: string;
|
|
4
|
+
custom?: import("@stoker-platform/types").FieldCustom;
|
|
5
|
+
admin?: import("@stoker-platform/types").FieldAdmin;
|
|
6
|
+
formula?: (record: import("@stoker-platform/types").StokerRecord) => string | number;
|
|
7
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export * from "./access/collection.js";
|
|
2
|
+
export * from "./access/document.js";
|
|
3
|
+
export { hasDependencyAccess } from "./access/hasDependencyAccess.js";
|
|
4
|
+
export { getRelatedCollections } from "./access/getRelatedCollections.js";
|
|
5
|
+
export { getRecordSubcollections } from "./access/getRecordSubcollections.js";
|
|
6
|
+
export { addRecordAccessControl } from "./access/write/addRecord.js";
|
|
7
|
+
export { updateRecordAccessControl } from "./access/write/updateRecord.js";
|
|
8
|
+
export { deleteRecordAccessControl } from "./access/write/deleteRecord.js";
|
|
9
|
+
export { getOneAccessControl } from "./access/read/getOne.js";
|
|
10
|
+
export { getSomeAccessControl } from "./access/read/getSome.js";
|
|
11
|
+
export { roleHasOperationAccess } from "./access/roleHasOperationAccess.js";
|
|
12
|
+
export { isPaginationEnabled } from "./access/isPaginationEnabled.js";
|
|
13
|
+
export { getAttributeRestrictions, getEntityRestrictions, getEntityParentFilters, } from "./access/getCollectionRestrictions.js";
|
|
14
|
+
export { getCustomization } from "./getCustomization.js";
|
|
15
|
+
export { getFieldCustomization } from "./getFieldCustomization.js";
|
|
16
|
+
export * from "./getConfigValue.js";
|
|
17
|
+
export { isDependencyField } from "./schema/isDependencyField.js";
|
|
18
|
+
export { isIncludedField } from "./schema/isIncludedField.js";
|
|
19
|
+
export { getCollection } from "./schema/getCollection.js";
|
|
20
|
+
export { getDependencyFields } from "./schema/getDependencyFields.js";
|
|
21
|
+
export { getField } from "./schema/getField.js";
|
|
22
|
+
export { getFieldNames } from "./schema/getFieldNames.js";
|
|
23
|
+
export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
|
|
24
|
+
export { getAccessFields } from "./schema/getAccessFields.js";
|
|
25
|
+
export { getSystemFieldsSchema } from "./schema/getSystemFieldsSchema.js";
|
|
26
|
+
export { isRelationField } from "./schema/isRelationField.js";
|
|
27
|
+
export { getPathCollections } from "./schema/getPathCollections.js";
|
|
28
|
+
export { getInverseRelationType } from "./schema/getInverseRelationType.js";
|
|
29
|
+
export { getSubcollections } from "./schema/getSubcollections.js";
|
|
30
|
+
export { getRecordSystemFields } from "./schema/getRecordSystemFields.js";
|
|
31
|
+
export { getRelationLists } from "./schema/getRelationLists.js";
|
|
32
|
+
export { systemFields } from "./schema/system-fields.js";
|
|
33
|
+
export { runHooks } from "./operations/runHooks.js";
|
|
34
|
+
export { addSystemFields } from "./operations/addSystemFields.js";
|
|
35
|
+
export { addRelationArrays } from "./operations/addRelationArrays.js";
|
|
36
|
+
export { getSingleFieldRelations } from "./operations/getSingleFieldRelations.js";
|
|
37
|
+
export { addLowercaseFields } from "./operations/addLowercaseFields.js";
|
|
38
|
+
export { getLowercaseFields } from "./operations/getLowercaseFields.js";
|
|
39
|
+
export { addInitialValues } from "./operations/addInitialValues.js";
|
|
40
|
+
export { getExtendedSchema } from "./operations/getExtendedSchema.js";
|
|
41
|
+
export { getZodSchema as getSchema } from "./operations/getZodSchema.js";
|
|
42
|
+
export { getInputSchema } from "./operations/getInputSchema.js";
|
|
43
|
+
export { validateRecord } from "./operations/validateRecord.js";
|
|
44
|
+
export { prepareDenormalized as addDenormalized } from "./operations/prepareDenormalized.js";
|
|
45
|
+
export { removePrivateFields } from "./operations/removePrivateFields.js";
|
|
46
|
+
export { removeUndefined } from "./operations/removeUndefined.js";
|
|
47
|
+
export { removeEmptyStrings } from "./operations/removeEmptyStrings.js";
|
|
48
|
+
export { getDateRange as getRange } from "./operations/getDateRange.js";
|
|
49
|
+
export { isValidUniqueFieldValue } from "./operations/isValidUniqueFieldValue.js";
|
|
50
|
+
export { retryOperation } from "./operations/retryOperation.js";
|
|
51
|
+
export { isDeleteSentinel } from "./operations/isDeleteSentinel.js";
|
|
52
|
+
export { removeDeleteSentinels } from "./operations/removeDeleteSentinels.js";
|
|
53
|
+
export { updateFieldReference } from "./operations/updateFieldReference.js";
|
|
54
|
+
export { removeDeletedFields } from "./operations/removeDeletedFields.js";
|
|
55
|
+
export { isSortingEnabled } from "./operations/isSortingEnabled.js";
|
|
56
|
+
export { getFinalRecord } from "./operations/getFinalRecord.js";
|
|
57
|
+
export { parseDate } from "./operations/parseDate.js";
|
|
58
|
+
export { sanitizeEmailAddress, sanitizeEmailAddressArray, sanitizeEmailAddressOrArray, sanitizeEmailSubject, sanitizeEmailBody, } from "./operations/sanitizeEmailInput.js";
|
|
59
|
+
export { validateStorageName } from "./operations/validateStorageName.js";
|
|
60
|
+
export { sanitizeDownloadFilename } from "./operations/sanitizeDownloadFilename.js";
|
package/lib/src/main.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export * from "./access/collection.js";
|
|
2
|
+
export * from "./access/document.js";
|
|
3
|
+
export { hasDependencyAccess } from "./access/hasDependencyAccess.js";
|
|
4
|
+
export { getRelatedCollections } from "./access/getRelatedCollections.js";
|
|
5
|
+
export { getRecordSubcollections } from "./access/getRecordSubcollections.js";
|
|
6
|
+
export { addRecordAccessControl } from "./access/write/addRecord.js";
|
|
7
|
+
export { updateRecordAccessControl } from "./access/write/updateRecord.js";
|
|
8
|
+
export { deleteRecordAccessControl } from "./access/write/deleteRecord.js";
|
|
9
|
+
export { getOneAccessControl } from "./access/read/getOne.js";
|
|
10
|
+
export { getSomeAccessControl } from "./access/read/getSome.js";
|
|
11
|
+
export { roleHasOperationAccess } from "./access/roleHasOperationAccess.js";
|
|
12
|
+
export { isPaginationEnabled } from "./access/isPaginationEnabled.js";
|
|
13
|
+
export { getAttributeRestrictions, getEntityRestrictions, getEntityParentFilters, } from "./access/getCollectionRestrictions.js";
|
|
14
|
+
export { getCustomization } from "./getCustomization.js";
|
|
15
|
+
export { getFieldCustomization } from "./getFieldCustomization.js";
|
|
16
|
+
export * from "./getConfigValue.js";
|
|
17
|
+
export { isDependencyField } from "./schema/isDependencyField.js";
|
|
18
|
+
export { isIncludedField } from "./schema/isIncludedField.js";
|
|
19
|
+
export { getCollection } from "./schema/getCollection.js";
|
|
20
|
+
export { getDependencyFields } from "./schema/getDependencyFields.js";
|
|
21
|
+
export { getField } from "./schema/getField.js";
|
|
22
|
+
export { getFieldNames } from "./schema/getFieldNames.js";
|
|
23
|
+
export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
|
|
24
|
+
export { getAccessFields } from "./schema/getAccessFields.js";
|
|
25
|
+
export { getSystemFieldsSchema } from "./schema/getSystemFieldsSchema.js";
|
|
26
|
+
export { isRelationField } from "./schema/isRelationField.js";
|
|
27
|
+
export { getPathCollections } from "./schema/getPathCollections.js";
|
|
28
|
+
export { getInverseRelationType } from "./schema/getInverseRelationType.js";
|
|
29
|
+
export { getSubcollections } from "./schema/getSubcollections.js";
|
|
30
|
+
export { getRecordSystemFields } from "./schema/getRecordSystemFields.js";
|
|
31
|
+
export { getRelationLists } from "./schema/getRelationLists.js";
|
|
32
|
+
export { systemFields } from "./schema/system-fields.js";
|
|
33
|
+
export { runHooks } from "./operations/runHooks.js";
|
|
34
|
+
export { addSystemFields } from "./operations/addSystemFields.js";
|
|
35
|
+
export { addRelationArrays } from "./operations/addRelationArrays.js";
|
|
36
|
+
export { getSingleFieldRelations } from "./operations/getSingleFieldRelations.js";
|
|
37
|
+
export { addLowercaseFields } from "./operations/addLowercaseFields.js";
|
|
38
|
+
export { getLowercaseFields } from "./operations/getLowercaseFields.js";
|
|
39
|
+
export { addInitialValues } from "./operations/addInitialValues.js";
|
|
40
|
+
export { getExtendedSchema } from "./operations/getExtendedSchema.js";
|
|
41
|
+
export { getZodSchema as getSchema } from "./operations/getZodSchema.js";
|
|
42
|
+
export { getInputSchema } from "./operations/getInputSchema.js";
|
|
43
|
+
export { validateRecord } from "./operations/validateRecord.js";
|
|
44
|
+
export { prepareDenormalized as addDenormalized } from "./operations/prepareDenormalized.js";
|
|
45
|
+
export { removePrivateFields } from "./operations/removePrivateFields.js";
|
|
46
|
+
export { removeUndefined } from "./operations/removeUndefined.js";
|
|
47
|
+
export { removeEmptyStrings } from "./operations/removeEmptyStrings.js";
|
|
48
|
+
export { getDateRange as getRange } from "./operations/getDateRange.js";
|
|
49
|
+
export { isValidUniqueFieldValue } from "./operations/isValidUniqueFieldValue.js";
|
|
50
|
+
export { retryOperation } from "./operations/retryOperation.js";
|
|
51
|
+
export { isDeleteSentinel } from "./operations/isDeleteSentinel.js";
|
|
52
|
+
export { removeDeleteSentinels } from "./operations/removeDeleteSentinels.js";
|
|
53
|
+
export { updateFieldReference } from "./operations/updateFieldReference.js";
|
|
54
|
+
export { removeDeletedFields } from "./operations/removeDeletedFields.js";
|
|
55
|
+
export { isSortingEnabled } from "./operations/isSortingEnabled.js";
|
|
56
|
+
export { getFinalRecord } from "./operations/getFinalRecord.js";
|
|
57
|
+
export { parseDate } from "./operations/parseDate.js";
|
|
58
|
+
export { sanitizeEmailAddress, sanitizeEmailAddressArray, sanitizeEmailAddressOrArray, sanitizeEmailSubject, sanitizeEmailBody, } from "./operations/sanitizeEmailInput.js";
|
|
59
|
+
export { validateStorageName } from "./operations/validateStorageName.js";
|
|
60
|
+
export { sanitizeDownloadFilename } from "./operations/sanitizeDownloadFilename.js";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { CollectionSchema, CollectionCustomization, StokerRecord, StokerRole } from "@stoker-platform/types";
|
|
2
|
+
export declare const addInitialValues: (data: StokerRecord, collectionSchema: CollectionSchema, customization: CollectionCustomization, role?: StokerRole) => Promise<void>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { tryPromise } from "../getConfigValue.js";
|
|
2
|
+
import { getField } from "../schema/getField.js";
|
|
3
|
+
import { isRelationField } from "../schema/isRelationField.js";
|
|
4
|
+
import { getLowercaseFields } from "./getLowercaseFields.js";
|
|
5
|
+
export const addInitialValues = async (data, collectionSchema, customization, role) => {
|
|
6
|
+
const { fields } = collectionSchema;
|
|
7
|
+
for (const field of customization.fields) {
|
|
8
|
+
const fieldSchema = getField(fields, field.name);
|
|
9
|
+
if (field.custom?.initialValue && !(role && fieldSchema.access && !fieldSchema.access.includes(role))) {
|
|
10
|
+
data[field.name] = await tryPromise(field.custom.initialValue, [data]);
|
|
11
|
+
const lowercaseFields = getLowercaseFields(collectionSchema, [fieldSchema]);
|
|
12
|
+
if (lowercaseFields.size === 1) {
|
|
13
|
+
data[`${field.name}_Lowercase`] = data[field.name].toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
for (const field of fields) {
|
|
18
|
+
if (!(role && field.access && !field.access.includes(role))) {
|
|
19
|
+
if ("autoIncrement" in field && field.autoIncrement && !data[field.name]) {
|
|
20
|
+
data[field.name] = "Pending";
|
|
21
|
+
}
|
|
22
|
+
if (!isRelationField(field) && field.nullable && data[field.name] === undefined) {
|
|
23
|
+
data[field.name] = null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getLowercaseFields } from "./getLowercaseFields.js";
|
|
2
|
+
export const addLowercaseFields = (collection, data) => {
|
|
3
|
+
const lowercaseFields = getLowercaseFields(collection, collection.fields);
|
|
4
|
+
lowercaseFields.forEach((field) => {
|
|
5
|
+
if (data[field.name]) {
|
|
6
|
+
data[`${field.name}_Lowercase`] = data[field.name].toLowerCase();
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
delete data[`${field.name}_Lowercase`];
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { isDeleteSentinel } from "./isDeleteSentinel.js";
|
|
2
|
+
import { isRelationField } from "../schema/isRelationField.js";
|
|
3
|
+
import { getSingleFieldRelations } from "./getSingleFieldRelations.js";
|
|
4
|
+
import { getField } from "../schema/getField.js";
|
|
5
|
+
import { getLowercaseFields } from "./getLowercaseFields.js";
|
|
6
|
+
export const addRelationArrays = (collection, data, schema) => {
|
|
7
|
+
const { fields } = collection;
|
|
8
|
+
fields.forEach((field) => {
|
|
9
|
+
if (isRelationField(field)) {
|
|
10
|
+
if (data[field.name]) {
|
|
11
|
+
if (!isDeleteSentinel(data[field.name])) {
|
|
12
|
+
data[`${field.name}_Array`] = Object.keys(data[field.name]);
|
|
13
|
+
if (field.includeFields) {
|
|
14
|
+
for (const includeField of field.includeFields) {
|
|
15
|
+
const relationCollection = schema.collections[field.collection];
|
|
16
|
+
const includeFieldSchema = getField(relationCollection.fields, includeField);
|
|
17
|
+
const lowercaseFields = getLowercaseFields(relationCollection, [includeFieldSchema]);
|
|
18
|
+
if (lowercaseFields.size === 1) {
|
|
19
|
+
/* eslint-disable security/detect-object-injection */
|
|
20
|
+
Object.keys(data[field.name]).forEach((key) => {
|
|
21
|
+
if (data[field.name][key][includeField]) {
|
|
22
|
+
data[field.name][key][`${includeField}_Lowercase`] =
|
|
23
|
+
data[field.name][key][includeField].toLowerCase();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
delete data[field.name][key][`${includeField}_Lowercase`];
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
/* eslint-enable security/detect-object-injection */
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
data[`${field.name}_Array`] = data[field.name];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
delete data[`${field.name}_Array`];
|
|
40
|
+
delete data[`${field.name}_Single`];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const singleRelationFields = getSingleFieldRelations(collection, fields);
|
|
45
|
+
singleRelationFields.forEach((field) => {
|
|
46
|
+
if (data[field.name]) {
|
|
47
|
+
if (!isDeleteSentinel(data[field.name])) {
|
|
48
|
+
const id = data[`${field.name}_Array`]?.[0];
|
|
49
|
+
if (id) {
|
|
50
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
51
|
+
const includeFields = data[field.name][id] || {};
|
|
52
|
+
data[`${field.name}_Single`] = { ...includeFields };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
data[`${field.name}_Single`] = data[field.name];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { CollectionsSchema, FirebaseTimestamp, StokerRecord } from "@stoker-platform/types";
|
|
2
|
+
export declare const addSystemFields: (operation: "create" | "update" | "delete", path: string[], data: Partial<StokerRecord>, schema: CollectionsSchema, appName: string, connection: "Online" | "Offline", userId: string, timestamp: FirebaseTimestamp, serverTimestamp: FirebaseTimestamp, retry?: boolean) => StokerRecord;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const addSystemFields = (operation, path, data, schema, appName, connection, userId, timestamp, serverTimestamp, retry) => {
|
|
2
|
+
if (operation == "create") {
|
|
3
|
+
data.Collection_Path = path;
|
|
4
|
+
if (!retry)
|
|
5
|
+
data.Created_At = timestamp;
|
|
6
|
+
data.Saved_At = serverTimestamp;
|
|
7
|
+
data.Created_By = userId || "System";
|
|
8
|
+
}
|
|
9
|
+
data.Last_Write_App = appName;
|
|
10
|
+
if (!retry)
|
|
11
|
+
data.Last_Write_At = timestamp;
|
|
12
|
+
data.Last_Save_At = serverTimestamp;
|
|
13
|
+
data.Last_Write_By = userId || "System";
|
|
14
|
+
data.Last_Write_Connection_Status = connection;
|
|
15
|
+
data.Last_Write_Version = schema.version;
|
|
16
|
+
return data;
|
|
17
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DateTime } from "luxon";
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
3
|
+
export const getDateRange = (range, _timezone) => {
|
|
4
|
+
let start, end = undefined;
|
|
5
|
+
if (typeof range.start === "object") {
|
|
6
|
+
start = range.start;
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
start = new Date();
|
|
10
|
+
let startDateTime = DateTime.fromJSDate(start);
|
|
11
|
+
switch (range.start) {
|
|
12
|
+
case "Today":
|
|
13
|
+
startDateTime = startDateTime.startOf("day");
|
|
14
|
+
break;
|
|
15
|
+
case "Week":
|
|
16
|
+
startDateTime = startDateTime.startOf("week");
|
|
17
|
+
break;
|
|
18
|
+
case "Month":
|
|
19
|
+
startDateTime = startDateTime.startOf("month");
|
|
20
|
+
break;
|
|
21
|
+
case "Year":
|
|
22
|
+
startDateTime = startDateTime.startOf("year");
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
startDateTime = startDateTime.startOf("day");
|
|
26
|
+
}
|
|
27
|
+
if (typeof range.start === "number") {
|
|
28
|
+
startDateTime = startDateTime.plus({ days: range.start });
|
|
29
|
+
}
|
|
30
|
+
if (range.startOffsetDays) {
|
|
31
|
+
startDateTime = startDateTime.plus({ days: range.startOffsetDays });
|
|
32
|
+
}
|
|
33
|
+
if (range.startOffsetHours) {
|
|
34
|
+
startDateTime = startDateTime.plus({ hours: range.startOffsetHours });
|
|
35
|
+
}
|
|
36
|
+
start = startDateTime.toJSDate();
|
|
37
|
+
}
|
|
38
|
+
if (typeof range.end === "object") {
|
|
39
|
+
end = range.end;
|
|
40
|
+
}
|
|
41
|
+
else if (range.end) {
|
|
42
|
+
end = new Date();
|
|
43
|
+
let endDateTime = DateTime.fromJSDate(end);
|
|
44
|
+
if (typeof range.end === "number") {
|
|
45
|
+
endDateTime = endDateTime.plus({ days: range.end });
|
|
46
|
+
}
|
|
47
|
+
if (range.endOffsetDays) {
|
|
48
|
+
endDateTime = endDateTime.plus({ days: range.endOffsetDays });
|
|
49
|
+
}
|
|
50
|
+
if (range.endOffsetHours) {
|
|
51
|
+
endDateTime = endDateTime.plus({ hours: range.endOffsetHours });
|
|
52
|
+
}
|
|
53
|
+
end = endDateTime.toJSDate();
|
|
54
|
+
}
|
|
55
|
+
return { start, end };
|
|
56
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getLowercaseFields } from "./getLowercaseFields.js";
|
|
2
|
+
import { getSingleFieldRelations } from "./getSingleFieldRelations.js";
|
|
3
|
+
import { isRelationField } from "../schema/isRelationField.js";
|
|
4
|
+
export const getExtendedSchema = (collection, fields) => {
|
|
5
|
+
const extendedSchema = [];
|
|
6
|
+
fields.forEach((field) => {
|
|
7
|
+
extendedSchema.push(field.name);
|
|
8
|
+
});
|
|
9
|
+
const lowercaseFields = getLowercaseFields(collection, fields);
|
|
10
|
+
lowercaseFields.forEach((field) => {
|
|
11
|
+
extendedSchema.push(`${field.name}_Lowercase`);
|
|
12
|
+
});
|
|
13
|
+
const singleRelationFields = getSingleFieldRelations(collection, fields);
|
|
14
|
+
singleRelationFields.forEach((field) => {
|
|
15
|
+
extendedSchema.push(`${field.name}_Single`);
|
|
16
|
+
});
|
|
17
|
+
fields.forEach((field) => {
|
|
18
|
+
if (isRelationField(field)) {
|
|
19
|
+
extendedSchema.push(`${field.name}_Array`);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return extendedSchema;
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getFinalRecord: (args: IArguments) => any;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CollectionCustomization, CollectionSchema, CollectionsSchema } from "@stoker-platform/types";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export declare const getInputSchema: (collection: CollectionSchema, schema: CollectionsSchema, customization?: CollectionCustomization, chat?: boolean, updateMany?: boolean) => z.ZodObject<{
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
}, z.ZodTypeAny, "passthrough">> | z.ZodObject<{
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}, "strict", z.ZodTypeAny, {
|
|
12
|
+
[x: string]: any;
|
|
13
|
+
}, {
|
|
14
|
+
[x: string]: any;
|
|
15
|
+
}>;
|