@monorise/base 4.1.0 → 4.2.0
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/index.d.ts +27 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,25 @@ declare enum Entity {
|
|
|
5
5
|
interface EntitySchemaMap {
|
|
6
6
|
[key: string]: Record<string, any>;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* @description Configuration for a mutual relationship between two entities.
|
|
10
|
+
* Defines the schema for mutualData validation. Define once, reference from both entity configs.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const enrollmentMutual = createMutualConfig({
|
|
15
|
+
* entities: [Entity.STUDENT, Entity.COURSE],
|
|
16
|
+
* mutualDataSchema: z.object({
|
|
17
|
+
* role: z.enum(['student', 'auditor']),
|
|
18
|
+
* enrolledAt: z.string().datetime(),
|
|
19
|
+
* }),
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
interface MutualConfig<MD extends z.ZodRawShape = z.ZodRawShape> {
|
|
24
|
+
entities: [Entity, Entity];
|
|
25
|
+
mutualDataSchema: z.ZodObject<MD>;
|
|
26
|
+
}
|
|
8
27
|
type DraftEntity<T extends Entity = Entity> = T extends keyof EntitySchemaMap ? EntitySchemaMap[T] : never;
|
|
9
28
|
type NumericFields<T> = {
|
|
10
29
|
[K in keyof T as T[K] extends number ? K : never]?: number;
|
|
@@ -109,6 +128,11 @@ interface MonoriseEntityConfig<T extends Entity = Entity, B extends z.ZodRawShap
|
|
|
109
128
|
* @returns the final state of `mutualData` to be stored in the mutual record. Must be an object.
|
|
110
129
|
*/
|
|
111
130
|
mutualDataProcessor?: (mutualIds: string[], currentMutual: any, customContext?: Record<string, any>) => Record<string, any>;
|
|
131
|
+
/**
|
|
132
|
+
* @description (Optional) Reference to a mutual config created by `createMutualConfig`.
|
|
133
|
+
* Provides mutualData schema validation for create/update operations on this mutual relationship.
|
|
134
|
+
*/
|
|
135
|
+
mutual?: MutualConfig;
|
|
112
136
|
};
|
|
113
137
|
};
|
|
114
138
|
/**
|
|
@@ -320,6 +344,7 @@ declare const createEntityConfig: <T extends Entity, B extends z.ZodRawShape, C
|
|
|
320
344
|
entityType: Entity;
|
|
321
345
|
toMutualIds?: (context: any) => string[];
|
|
322
346
|
mutualDataProcessor?: (mutualIds: string[], currentMutual: any, customContext?: Record<string, any>) => Record<string, any>;
|
|
347
|
+
mutual?: MutualConfig;
|
|
323
348
|
};
|
|
324
349
|
};
|
|
325
350
|
prejoins?: {
|
|
@@ -364,5 +389,6 @@ declare const createEntityConfig: <T extends Entity, B extends z.ZodRawShape, C
|
|
|
364
389
|
};
|
|
365
390
|
} | undefined;
|
|
366
391
|
};
|
|
392
|
+
declare const createMutualConfig: <MD extends z.ZodRawShape>(config: MutualConfig<MD>) => MutualConfig<MD>;
|
|
367
393
|
|
|
368
|
-
export { type CreatedEntity, type DraftEntity, Entity, type EntitySchemaMap, type MonoriseEntityConfig, type NumericFields, createEntityConfig };
|
|
394
|
+
export { type CreatedEntity, type DraftEntity, Entity, type EntitySchemaMap, type MonoriseEntityConfig, type MutualConfig, type NumericFields, createEntityConfig, createMutualConfig };
|
package/dist/index.js
CHANGED
|
@@ -37,8 +37,10 @@ function makeSchema(config) {
|
|
|
37
37
|
var createEntityConfig = (config) => __spreadProps(__spreadValues({}, config), {
|
|
38
38
|
finalSchema: makeSchema(config)
|
|
39
39
|
});
|
|
40
|
+
var createMutualConfig = (config) => config;
|
|
40
41
|
export {
|
|
41
42
|
Entity,
|
|
42
|
-
createEntityConfig
|
|
43
|
+
createEntityConfig,
|
|
44
|
+
createMutualConfig
|
|
43
45
|
};
|
|
44
46
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../types/monorise.type.ts","../utils/index.ts"],"sourcesContent":["import type { z } from 'zod';\n\nexport enum Entity {}\n\nexport interface EntitySchemaMap {\n [key: string]: Record<string, any>;\n}\n\nexport type DraftEntity<T extends Entity = Entity> =\n T extends keyof EntitySchemaMap ? EntitySchemaMap[T] : never;\n\nexport type NumericFields<T> = {\n [K in keyof T as T[K] extends number ? K : never]?: number;\n};\n\nexport type CreatedEntity<T extends Entity = Entity> = {\n entityId: string;\n entityType: string;\n data: T extends keyof EntitySchemaMap ? EntitySchemaMap[T] : never;\n createdAt: string;\n updatedAt: string;\n};\n\n/**\n * @description Configuration for a monorise entity, a shared configuration that is used across frontend and backend.\n * This can be served as a single source of truth for the entity configuration.\n * It is used to define the schema, and mutual relationships between this entity and other entities.\n *\n * @example\n * ```ts\n * const baseSchema = z.object({\n * title: z.string(),\n * }).partial();\n *\n * const createSchema = baseSchema.extend({\n * title: z.string(),\n * })\n *\n * const config = createEntityConfig({\n * name: 'learner',\n * displayName: 'Learner',\n * baseSchema,\n * createSchema,\n * });\n * ```\n */\nexport interface MonoriseEntityConfig<\n T extends Entity = Entity,\n B extends z.ZodRawShape = z.ZodRawShape,\n C extends z.ZodRawShape = z.ZodRawShape,\n M extends z.ZodRawShape = z.ZodRawShape,\n CO extends z.ZodObject<C> | undefined = undefined,\n MO extends z.ZodObject<M> | undefined = undefined,\n> {\n /**\n * @description Name of the entity. Must be in **lower-kebab-case** and **unique** across all entities\n *\n * @example `learner`, `learning-activity`\n */\n name: string | T;\n\n /**\n * @description Display name of the entity. It is not required to be unique\n */\n displayName: string;\n\n /**\n * @description (DEPRECATED) Use `uniqueFields` instead, Monorise should not handle auth mechanism\n * @description (Optional) Specify the authentication method to be used for the entity\n */\n authMethod?: {\n /**\n * @description Authentication method using email\n *\n * Note: The email used for authentication is unique per entity.\n * For example, if `johndoe@mail.com` is used for `learner` entity,\n * it can be reused again on `admin` entity. However, the same email\n * address cannot be repeated for the same entity.\n */\n email: {\n /**\n * @description Number of milliseconds before the token expires\n */\n tokenExpiresIn: number;\n };\n };\n\n /**\n * @description Base schema for the entity\n */\n baseSchema: z.ZodObject<B>;\n\n /**\n * @description Minimal schema required to create an entity\n */\n createSchema?: CO;\n searchableFields?: (keyof B)[];\n uniqueFields?: (keyof B)[];\n\n /**\n * @description Define mutual relationship of this entity with other entities\n */\n mutual?: {\n /**\n * @description Subscribes to update events from specified entities in the array.\n * These events will be used to run prejoin processor.\n */\n subscribes?: { entityType: Entity }[];\n /**\n * @description Virtual schema for mutual relationship. The schema is only used for validation purpose, but these fields are not stored in the database\n */\n mutualSchema: MO;\n\n /**\n * @description Keys of `mutualFields` are fields defined in `mutualSchema`.\n * Each field is a mutual relationship between this entity and another entity.\n */\n mutualFields: {\n [key: string]: {\n entityType: Entity;\n toMutualIds?: (context: any) => string[];\n /**\n * @description (Optional) Custom function to process `mutualData`. If not provided, `mutualData` will be empty.\n *\n * @returns the final state of `mutualData` to be stored in the mutual record. Must be an object.\n */\n mutualDataProcessor?: (\n mutualIds: string[],\n currentMutual: any,\n customContext?: Record<string, any>,\n ) => Record<string, any>;\n };\n };\n\n /**\n * @description (Optional) Better known as tree processor\n * This is used to prejoin entities that are not directly related as mutual.\n * For example, if `learner` entity is related to `course` entity, and `course` entity is related to `module` entity,\n * prejoins can be used to join `learner` and `module` entities.\n * With this, the `learner` entity can access the `module` entity without having to go through the `course` entity,\n * hence reducing the number of queries.\n *\n * DynamoDB best practices: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-normalization.html\n *\n */\n prejoins?: {\n mutualField: string;\n targetEntityType: Entity;\n entityPaths: {\n skipCache?: boolean;\n entityType: Entity;\n processor?: (items: any[], context: Record<string, any>) => any;\n }[];\n }[];\n };\n /**\n * Use this function to perform side effects on the final schema for example refine/superRefine the schema\n *\n * @param schema The final schema of the entity (the combination of `baseSchema`/`createSchema` and `mutualSchema` if specified)\n * @returns void\n *\n * @example\n * ```ts\n * effect: (schema) => {\n * schema.refine(\n * // refinement logic here\n * )\n * }\n */\n effect?: (\n schema: z.ZodObject<z.ZodRawShape>,\n ) => z.ZodEffects<z.ZodObject<z.ZodRawShape>>;\n\n /**\n * @description (Optional) Use tags to create additional access patterns for the entity.\n * Time complexity for retrieving tagged entities is O(1).\n *\n * The following configuration will create a tag named `region` for the `organization` entity grouped by `region`.\n * You would then be able to retrieve all organizations in a specific region by:\n * GET `/core/tag/organization/region?group={region_name}`\n *\n * @example\n *\n * ```ts\n * {\n * name: 'organization',\n * tags: [\n * {\n * name: 'region',\n * processor: (entity) => {\n * return [\n * {\n * group: entity.data.region\n * }\n * ]\n * },\n * }\n * ]\n * }\n * ```\n *\n * @description\n *\n * The following configuration will create a tag named `dob` for the `user` entity sorted by `dob`.\n * You would then be able to retrieve all users sorted by `dob` by:\n * GET `/core/tag/user/dob?start=2000-01-01&end=2020-12-31`\n *\n * @example\n * ```ts\n * {\n * name: 'user',\n * tags: [\n * {\n * name: 'dob',\n * processor: (entity) => {\n * return [\n * {\n * sortValue: entity.data.dob\n * }\n * ]\n * },\n * }\n * ]\n * }\n * ```\n */\n tags?: {\n name: string;\n processor: (entity: { entityId: string; entityType: string; data: Record<string, any>; createdAt: string; updatedAt: string }) => {\n group?: string;\n sortValue?: string;\n }[];\n }[];\n\n /**\n * @description (Optional) Configure a DynamoDB TTL for this entity. When set, `expiresAt`\n * is computed via `processor` on create, and recomputed on every update/upsert. Once past,\n * DynamoDB automatically deletes the item (and its derived index rows, since they all carry\n * the same `expiresAt`).\n *\n * `processor` returning `undefined` means \"no TTL\" for that record. On updates, an `undefined`\n * result leaves any existing `expiresAt` untouched rather than clearing it.\n *\n * @example\n * ```ts\n * // fixed 30-day TTL from creation/each update\n * ttl: {\n * processor: () => Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,\n * }\n * ```\n *\n * @example\n * ```ts\n * // data-driven TTL, eg. expire when a subscription ends\n * ttl: {\n * processor: (entity) => {\n * return entity.data.subscriptionEndsAt\n * ? new Date(entity.data.subscriptionEndsAt)\n * : undefined;\n * },\n * }\n * ```\n */\n ttl?: {\n /**\n * @description Returns the expiry as epoch seconds (absolute) or a `Date`.\n * Return `undefined` for no expiry.\n */\n processor: (entity: {\n entityId: string;\n entityType: string;\n data: Record<string, any>;\n createdAt: string;\n updatedAt: string;\n }) => number | Date | undefined;\n };\n\n /**\n * @description (Optional) Constraints for `adjustEntity` operations.\n * When adjusting numeric fields, these constraints are enforced at the database level.\n * If an adjustment would violate a constraint, the operation is rejected.\n *\n * @example\n * ```ts\n * {\n * adjustmentConstraints: {\n * // Static: same for all entities of this type\n * balance: { min: 0 },\n * credits: { min: 0, max: 10000 },\n *\n * // Dynamic: reads constraint value from entity's own data\n * balance: { minField: 'minBalance' },\n * credits: { min: 0, maxField: 'creditLimit' },\n * }\n * }\n * ```\n */\n adjustmentConstraints?: {\n [fieldName: string]: {\n /** Static minimum value */\n min?: number;\n /** Static maximum value */\n max?: number;\n /** Field name on the entity whose value is used as the minimum (must be a numeric field) */\n minField?: keyof {\n [K in keyof B as B[K] extends z.ZodNumber | z.ZodOptional<z.ZodNumber> ? K : never]: K;\n } extends never ? string : keyof {\n [K in keyof B as B[K] extends z.ZodNumber | z.ZodOptional<z.ZodNumber> ? K : never]: K;\n };\n /** Field name on the entity whose value is used as the maximum (must be a numeric field) */\n maxField?: keyof {\n [K in keyof B as B[K] extends z.ZodNumber | z.ZodOptional<z.ZodNumber> ? K : never]: K;\n } extends never ? string : keyof {\n [K in keyof B as B[K] extends z.ZodNumber | z.ZodOptional<z.ZodNumber> ? K : never]: K;\n };\n };\n };\n}\n","import type { Entity, MonoriseEntityConfig } from '../types/monorise.type';\nimport { z } from 'zod';\n\nfunction makeSchema<\n T extends Entity,\n B extends z.ZodRawShape,\n C extends z.ZodRawShape,\n M extends z.ZodRawShape,\n CO extends z.ZodObject<C> | undefined = undefined,\n MO extends z.ZodObject<M> | undefined = undefined,\n>(config: MonoriseEntityConfig<T, B, C, M, CO, MO>) {\n const { baseSchema, createSchema, mutual, effect } = config;\n const { mutualSchema } = mutual || {};\n\n type FinalSchemaType = CO extends z.AnyZodObject\n ? MO extends z.AnyZodObject\n ? z.ZodObject<MO['shape'] & CO['shape']>\n : CO\n : MO extends z.AnyZodObject\n ? z.ZodObject<MO['shape'] & B>\n : z.ZodObject<B>;\n\n const finalSchema = z.object({\n ...baseSchema.shape,\n ...createSchema?.shape,\n ...mutualSchema?.shape,\n }) as FinalSchemaType;\n\n if (effect) {\n return effect(finalSchema) as z.ZodEffects<FinalSchemaType>;\n }\n\n return finalSchema;\n}\n\nconst createEntityConfig = <\n T extends Entity,\n B extends z.ZodRawShape,\n C extends z.ZodRawShape,\n M extends z.ZodRawShape,\n CO extends z.ZodObject<C> | undefined = undefined,\n MO extends z.ZodObject<M> | undefined = undefined,\n>(\n config: MonoriseEntityConfig<T, B, C, M, CO, MO>,\n) => ({\n ...config,\n finalSchema: makeSchema(config),\n});\n\nexport { createEntityConfig };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAEO,IAAK,SAAL,kBAAKA,YAAL;AAAK,SAAAA;AAAA,GAAA;;;ACDZ,SAAS,SAAS;AAElB,SAAS,WAOP,QAAkD;AAClD,QAAM,EAAE,YAAY,cAAc,QAAQ,OAAO,IAAI;AACrD,QAAM,EAAE,aAAa,IAAI,UAAU,CAAC;AAUpC,QAAM,cAAc,EAAE,OAAO,iDACxB,WAAW,QACX,6CAAc,QACd,6CAAc,MAClB;AAED,MAAI,QAAQ;AACV,WAAO,OAAO,WAAW;AAAA,EAC3B;AAEA,SAAO;AACT;AAEA,IAAM,qBAAqB,CAQzB,WACI,iCACD,SADC;AAAA,EAEJ,aAAa,WAAW,MAAM;AAChC;","names":["Entity"]}
|
|
1
|
+
{"version":3,"sources":["../types/monorise.type.ts","../utils/index.ts"],"sourcesContent":["import type { z } from 'zod';\n\nexport enum Entity {}\n\nexport interface EntitySchemaMap {\n [key: string]: Record<string, any>;\n}\n\n/**\n * @description Configuration for a mutual relationship between two entities.\n * Defines the schema for mutualData validation. Define once, reference from both entity configs.\n *\n * @example\n * ```ts\n * const enrollmentMutual = createMutualConfig({\n * entities: [Entity.STUDENT, Entity.COURSE],\n * mutualDataSchema: z.object({\n * role: z.enum(['student', 'auditor']),\n * enrolledAt: z.string().datetime(),\n * }),\n * });\n * ```\n */\nexport interface MutualConfig<\n MD extends z.ZodRawShape = z.ZodRawShape,\n> {\n entities: [Entity, Entity];\n mutualDataSchema: z.ZodObject<MD>;\n}\n\nexport type DraftEntity<T extends Entity = Entity> =\n T extends keyof EntitySchemaMap ? EntitySchemaMap[T] : never;\n\nexport type NumericFields<T> = {\n [K in keyof T as T[K] extends number ? K : never]?: number;\n};\n\nexport type CreatedEntity<T extends Entity = Entity> = {\n entityId: string;\n entityType: string;\n data: T extends keyof EntitySchemaMap ? EntitySchemaMap[T] : never;\n createdAt: string;\n updatedAt: string;\n};\n\n/**\n * @description Configuration for a monorise entity, a shared configuration that is used across frontend and backend.\n * This can be served as a single source of truth for the entity configuration.\n * It is used to define the schema, and mutual relationships between this entity and other entities.\n *\n * @example\n * ```ts\n * const baseSchema = z.object({\n * title: z.string(),\n * }).partial();\n *\n * const createSchema = baseSchema.extend({\n * title: z.string(),\n * })\n *\n * const config = createEntityConfig({\n * name: 'learner',\n * displayName: 'Learner',\n * baseSchema,\n * createSchema,\n * });\n * ```\n */\nexport interface MonoriseEntityConfig<\n T extends Entity = Entity,\n B extends z.ZodRawShape = z.ZodRawShape,\n C extends z.ZodRawShape = z.ZodRawShape,\n M extends z.ZodRawShape = z.ZodRawShape,\n CO extends z.ZodObject<C> | undefined = undefined,\n MO extends z.ZodObject<M> | undefined = undefined,\n> {\n /**\n * @description Name of the entity. Must be in **lower-kebab-case** and **unique** across all entities\n *\n * @example `learner`, `learning-activity`\n */\n name: string | T;\n\n /**\n * @description Display name of the entity. It is not required to be unique\n */\n displayName: string;\n\n /**\n * @description (DEPRECATED) Use `uniqueFields` instead, Monorise should not handle auth mechanism\n * @description (Optional) Specify the authentication method to be used for the entity\n */\n authMethod?: {\n /**\n * @description Authentication method using email\n *\n * Note: The email used for authentication is unique per entity.\n * For example, if `johndoe@mail.com` is used for `learner` entity,\n * it can be reused again on `admin` entity. However, the same email\n * address cannot be repeated for the same entity.\n */\n email: {\n /**\n * @description Number of milliseconds before the token expires\n */\n tokenExpiresIn: number;\n };\n };\n\n /**\n * @description Base schema for the entity\n */\n baseSchema: z.ZodObject<B>;\n\n /**\n * @description Minimal schema required to create an entity\n */\n createSchema?: CO;\n searchableFields?: (keyof B)[];\n uniqueFields?: (keyof B)[];\n\n /**\n * @description Define mutual relationship of this entity with other entities\n */\n mutual?: {\n /**\n * @description Subscribes to update events from specified entities in the array.\n * These events will be used to run prejoin processor.\n */\n subscribes?: { entityType: Entity }[];\n /**\n * @description Virtual schema for mutual relationship. The schema is only used for validation purpose, but these fields are not stored in the database\n */\n mutualSchema: MO;\n\n /**\n * @description Keys of `mutualFields` are fields defined in `mutualSchema`.\n * Each field is a mutual relationship between this entity and another entity.\n */\n mutualFields: {\n [key: string]: {\n entityType: Entity;\n toMutualIds?: (context: any) => string[];\n /**\n * @description (Optional) Custom function to process `mutualData`. If not provided, `mutualData` will be empty.\n *\n * @returns the final state of `mutualData` to be stored in the mutual record. Must be an object.\n */\n mutualDataProcessor?: (\n mutualIds: string[],\n currentMutual: any,\n customContext?: Record<string, any>,\n ) => Record<string, any>;\n /**\n * @description (Optional) Reference to a mutual config created by `createMutualConfig`.\n * Provides mutualData schema validation for create/update operations on this mutual relationship.\n */\n mutual?: MutualConfig;\n };\n };\n\n /**\n * @description (Optional) Better known as tree processor\n * This is used to prejoin entities that are not directly related as mutual.\n * For example, if `learner` entity is related to `course` entity, and `course` entity is related to `module` entity,\n * prejoins can be used to join `learner` and `module` entities.\n * With this, the `learner` entity can access the `module` entity without having to go through the `course` entity,\n * hence reducing the number of queries.\n *\n * DynamoDB best practices: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-normalization.html\n *\n */\n prejoins?: {\n mutualField: string;\n targetEntityType: Entity;\n entityPaths: {\n skipCache?: boolean;\n entityType: Entity;\n processor?: (items: any[], context: Record<string, any>) => any;\n }[];\n }[];\n };\n /**\n * Use this function to perform side effects on the final schema for example refine/superRefine the schema\n *\n * @param schema The final schema of the entity (the combination of `baseSchema`/`createSchema` and `mutualSchema` if specified)\n * @returns void\n *\n * @example\n * ```ts\n * effect: (schema) => {\n * schema.refine(\n * // refinement logic here\n * )\n * }\n */\n effect?: (\n schema: z.ZodObject<z.ZodRawShape>,\n ) => z.ZodEffects<z.ZodObject<z.ZodRawShape>>;\n\n /**\n * @description (Optional) Use tags to create additional access patterns for the entity.\n * Time complexity for retrieving tagged entities is O(1).\n *\n * The following configuration will create a tag named `region` for the `organization` entity grouped by `region`.\n * You would then be able to retrieve all organizations in a specific region by:\n * GET `/core/tag/organization/region?group={region_name}`\n *\n * @example\n *\n * ```ts\n * {\n * name: 'organization',\n * tags: [\n * {\n * name: 'region',\n * processor: (entity) => {\n * return [\n * {\n * group: entity.data.region\n * }\n * ]\n * },\n * }\n * ]\n * }\n * ```\n *\n * @description\n *\n * The following configuration will create a tag named `dob` for the `user` entity sorted by `dob`.\n * You would then be able to retrieve all users sorted by `dob` by:\n * GET `/core/tag/user/dob?start=2000-01-01&end=2020-12-31`\n *\n * @example\n * ```ts\n * {\n * name: 'user',\n * tags: [\n * {\n * name: 'dob',\n * processor: (entity) => {\n * return [\n * {\n * sortValue: entity.data.dob\n * }\n * ]\n * },\n * }\n * ]\n * }\n * ```\n */\n tags?: {\n name: string;\n processor: (entity: { entityId: string; entityType: string; data: Record<string, any>; createdAt: string; updatedAt: string }) => {\n group?: string;\n sortValue?: string;\n }[];\n }[];\n\n /**\n * @description (Optional) Configure a DynamoDB TTL for this entity. When set, `expiresAt`\n * is computed via `processor` on create, and recomputed on every update/upsert. Once past,\n * DynamoDB automatically deletes the item (and its derived index rows, since they all carry\n * the same `expiresAt`).\n *\n * `processor` returning `undefined` means \"no TTL\" for that record. On updates, an `undefined`\n * result leaves any existing `expiresAt` untouched rather than clearing it.\n *\n * @example\n * ```ts\n * // fixed 30-day TTL from creation/each update\n * ttl: {\n * processor: () => Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,\n * }\n * ```\n *\n * @example\n * ```ts\n * // data-driven TTL, eg. expire when a subscription ends\n * ttl: {\n * processor: (entity) => {\n * return entity.data.subscriptionEndsAt\n * ? new Date(entity.data.subscriptionEndsAt)\n * : undefined;\n * },\n * }\n * ```\n */\n ttl?: {\n /**\n * @description Returns the expiry as epoch seconds (absolute) or a `Date`.\n * Return `undefined` for no expiry.\n */\n processor: (entity: {\n entityId: string;\n entityType: string;\n data: Record<string, any>;\n createdAt: string;\n updatedAt: string;\n }) => number | Date | undefined;\n };\n\n /**\n * @description (Optional) Constraints for `adjustEntity` operations.\n * When adjusting numeric fields, these constraints are enforced at the database level.\n * If an adjustment would violate a constraint, the operation is rejected.\n *\n * @example\n * ```ts\n * {\n * adjustmentConstraints: {\n * // Static: same for all entities of this type\n * balance: { min: 0 },\n * credits: { min: 0, max: 10000 },\n *\n * // Dynamic: reads constraint value from entity's own data\n * balance: { minField: 'minBalance' },\n * credits: { min: 0, maxField: 'creditLimit' },\n * }\n * }\n * ```\n */\n adjustmentConstraints?: {\n [fieldName: string]: {\n /** Static minimum value */\n min?: number;\n /** Static maximum value */\n max?: number;\n /** Field name on the entity whose value is used as the minimum (must be a numeric field) */\n minField?: keyof {\n [K in keyof B as B[K] extends z.ZodNumber | z.ZodOptional<z.ZodNumber> ? K : never]: K;\n } extends never ? string : keyof {\n [K in keyof B as B[K] extends z.ZodNumber | z.ZodOptional<z.ZodNumber> ? K : never]: K;\n };\n /** Field name on the entity whose value is used as the maximum (must be a numeric field) */\n maxField?: keyof {\n [K in keyof B as B[K] extends z.ZodNumber | z.ZodOptional<z.ZodNumber> ? K : never]: K;\n } extends never ? string : keyof {\n [K in keyof B as B[K] extends z.ZodNumber | z.ZodOptional<z.ZodNumber> ? K : never]: K;\n };\n };\n };\n}\n","import type { Entity, MonoriseEntityConfig, MutualConfig } from '../types/monorise.type';\nimport { z } from 'zod';\n\nfunction makeSchema<\n T extends Entity,\n B extends z.ZodRawShape,\n C extends z.ZodRawShape,\n M extends z.ZodRawShape,\n CO extends z.ZodObject<C> | undefined = undefined,\n MO extends z.ZodObject<M> | undefined = undefined,\n>(config: MonoriseEntityConfig<T, B, C, M, CO, MO>) {\n const { baseSchema, createSchema, mutual, effect } = config;\n const { mutualSchema } = mutual || {};\n\n type FinalSchemaType = CO extends z.AnyZodObject\n ? MO extends z.AnyZodObject\n ? z.ZodObject<MO['shape'] & CO['shape']>\n : CO\n : MO extends z.AnyZodObject\n ? z.ZodObject<MO['shape'] & B>\n : z.ZodObject<B>;\n\n const finalSchema = z.object({\n ...baseSchema.shape,\n ...createSchema?.shape,\n ...mutualSchema?.shape,\n }) as FinalSchemaType;\n\n if (effect) {\n return effect(finalSchema) as z.ZodEffects<FinalSchemaType>;\n }\n\n return finalSchema;\n}\n\nconst createEntityConfig = <\n T extends Entity,\n B extends z.ZodRawShape,\n C extends z.ZodRawShape,\n M extends z.ZodRawShape,\n CO extends z.ZodObject<C> | undefined = undefined,\n MO extends z.ZodObject<M> | undefined = undefined,\n>(\n config: MonoriseEntityConfig<T, B, C, M, CO, MO>,\n) => ({\n ...config,\n finalSchema: makeSchema(config),\n});\n\nconst createMutualConfig = <MD extends z.ZodRawShape>(\n config: MutualConfig<MD>,\n) => config;\n\nexport { createEntityConfig, createMutualConfig };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAEO,IAAK,SAAL,kBAAKA,YAAL;AAAK,SAAAA;AAAA,GAAA;;;ACDZ,SAAS,SAAS;AAElB,SAAS,WAOP,QAAkD;AAClD,QAAM,EAAE,YAAY,cAAc,QAAQ,OAAO,IAAI;AACrD,QAAM,EAAE,aAAa,IAAI,UAAU,CAAC;AAUpC,QAAM,cAAc,EAAE,OAAO,iDACxB,WAAW,QACX,6CAAc,QACd,6CAAc,MAClB;AAED,MAAI,QAAQ;AACV,WAAO,OAAO,WAAW;AAAA,EAC3B;AAEA,SAAO;AACT;AAEA,IAAM,qBAAqB,CAQzB,WACI,iCACD,SADC;AAAA,EAEJ,aAAa,WAAW,MAAM;AAChC;AAEA,IAAM,qBAAqB,CACzB,WACG;","names":["Entity"]}
|