gymmonk-schema 0.21.0 → 0.23.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/exercise.d.ts +2 -1
- package/dist/exercise.d.ts.map +1 -1
- package/dist/exercise.js +21 -2
- package/dist/exercise.js.map +1 -1
- package/dist/platform.d.ts +2 -3
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +2 -3
- package/dist/platform.js.map +1 -1
- package/dist/user.d.ts +12 -3
- package/dist/user.d.ts.map +1 -1
- package/dist/user.js +12 -4
- package/dist/user.js.map +1 -1
- package/dist/workout-plan.d.ts +3 -3
- package/dist/workout-plan.d.ts.map +1 -1
- package/dist/workout-plan.js +17 -2
- package/dist/workout-plan.js.map +1 -1
- package/package.json +1 -1
package/dist/exercise.d.ts
CHANGED
|
@@ -68,6 +68,7 @@ export declare const exerciseSummarySchema: z.ZodObject<{
|
|
|
68
68
|
}>;
|
|
69
69
|
targetArea: z.ZodString;
|
|
70
70
|
thumbnailUrl: z.ZodNullable<z.ZodString>;
|
|
71
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
71
72
|
}, z.core.$strip>;
|
|
72
73
|
export type ExerciseSummary = z.infer<typeof exerciseSummarySchema>;
|
|
73
74
|
export declare const exerciseSchema: z.ZodObject<{
|
|
@@ -122,7 +123,7 @@ export declare const exerciseSchema: z.ZodObject<{
|
|
|
122
123
|
}, z.core.$strip>;
|
|
123
124
|
export type Exercise = z.infer<typeof exerciseSchema>;
|
|
124
125
|
export declare const createExerciseBodySchema: z.ZodObject<{
|
|
125
|
-
centerId: z.ZodString
|
|
126
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
126
127
|
name: z.ZodString;
|
|
127
128
|
description: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
128
129
|
category: z.ZodEnum<{
|
package/dist/exercise.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exercise.d.ts","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,gBAAgB;;;;EAAmD,CAAC;AACjF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,+EAA+E;AAC/E,eAAO,MAAM,aAAa,sLAiBhB,CAAC;AACX,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;EAAwB,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"exercise.d.ts","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,gBAAgB;;;;EAAmD,CAAC;AACjF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,+EAA+E;AAC/E,eAAO,MAAM,aAAa,sLAiBhB,CAAC;AACX,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;EAAwB,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;iBAmBhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIpE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAItD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA8D,CAAC;AACpG,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;iBAKrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|
package/dist/exercise.js
CHANGED
|
@@ -54,10 +54,20 @@ export const exerciseSummarySchema = z.object({
|
|
|
54
54
|
category: exerciseCategorySchema,
|
|
55
55
|
targetArea: z.string(),
|
|
56
56
|
thumbnailUrl: z.string().nullable(),
|
|
57
|
+
/**
|
|
58
|
+
* Who authored this entry: `null` = the PLATFORM library, every gym sees it;
|
|
59
|
+
* a center id = that gym's own, and only its people see it.
|
|
60
|
+
*
|
|
61
|
+
* On the SUMMARY, not just the detail, because the grid is where the
|
|
62
|
+
* distinction has to be visible. An owner scrolling their library needs to
|
|
63
|
+
* know which cards are theirs to edit before tapping one, and a member is
|
|
64
|
+
* entitled to know that a routine came from their gym rather than from us.
|
|
65
|
+
* The detail shape inherits it from here, so there is one definition.
|
|
66
|
+
*/
|
|
67
|
+
centerId: objectIdSchema.nullable(),
|
|
57
68
|
});
|
|
58
69
|
// ─── Detail (full entity) ────────────────────────────────────────────────────
|
|
59
70
|
export const exerciseSchema = exerciseSummarySchema.extend({
|
|
60
|
-
centerId: objectIdSchema.nullable(),
|
|
61
71
|
description: z.string(),
|
|
62
72
|
youtubeId: z.string().nullable(),
|
|
63
73
|
posterUrl: z.string().nullable(),
|
|
@@ -69,7 +79,16 @@ export const exerciseSchema = exerciseSummarySchema.extend({
|
|
|
69
79
|
});
|
|
70
80
|
// ─── Create / update body ────────────────────────────────────────────────────
|
|
71
81
|
export const createExerciseBodySchema = z.object({
|
|
72
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Which library this entry joins. `null` is the PLATFORM library — content
|
|
84
|
+
* the product publishes to every gym — and only platform staff may send it.
|
|
85
|
+
*
|
|
86
|
+
* Nullable rather than optional on purpose: an omitted field would default to
|
|
87
|
+
* the global library, so a client that simply forgot to send a center would
|
|
88
|
+
* silently publish a gym's private exercise to the whole platform. Choosing
|
|
89
|
+
* global has to be something the caller SAYS.
|
|
90
|
+
*/
|
|
91
|
+
centerId: objectIdSchema.nullable(),
|
|
73
92
|
name: z.string().trim().min(1, 'Name is required').max(120),
|
|
74
93
|
description: optionalTrimmedString(4000),
|
|
75
94
|
category: exerciseCategorySchema,
|
package/dist/exercise.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exercise.js","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEvF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC,CAAC;AAGjF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,IAAI,CAAC;IAC3C,QAAQ;IACR,YAAY;IACZ,YAAY;IACZ,MAAM;IACN,WAAW;CACZ,CAAC,CAAC;AAGH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO;IACP,MAAM;IACN,WAAW;IACX,QAAQ;IACR,SAAS;IACT,UAAU;IACV,OAAO;IACP,YAAY;IACZ,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,MAAM;IACN,UAAU;IACV,YAAY;IACZ,WAAW;IACX,QAAQ;CACA,CAAC;AACX,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AAGvD,gFAAgF;AAEhF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;CACzB,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,UAAU,EAAE,gBAAgB;IAC5B,QAAQ,EAAE,sBAAsB;IAChC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAC,MAAM,CAAC;IACzD,
|
|
1
|
+
{"version":3,"file":"exercise.js","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Exercise library\n * ==================================\n * The catalog of exercises. Global entries (centerId null) plus gym-custom ones\n * an owner authors. Difficulty/category/muscle vocabularies are normalised to\n * lowercase; the frontend title-cases for display.\n *\n * @module gymmonk-schema/exercise\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString } from './common.js';\n\n// ─── Enums ───────────────────────────────────────────────────────────────────\n\nexport const difficultySchema = z.enum(['beginner', 'intermediate', 'advanced']);\nexport type Difficulty = z.infer<typeof difficultySchema>;\n\nexport const exerciseCategorySchema = z.enum([\n 'cardio',\n 'upper-body',\n 'lower-body',\n 'core',\n 'full-body',\n]);\nexport type ExerciseCategory = z.infer<typeof exerciseCategorySchema>;\n\n/** Normalised superset of the target-muscle vocabulary used across the app. */\nexport const MUSCLE_GROUPS = [\n 'chest',\n 'back',\n 'shoulders',\n 'biceps',\n 'triceps',\n 'forearms',\n 'quads',\n 'hamstrings',\n 'glutes',\n 'calves',\n 'legs',\n 'core',\n 'obliques',\n 'lower-back',\n 'full-body',\n 'cardio',\n] as const;\nexport const muscleGroupSchema = z.enum(MUSCLE_GROUPS);\nexport type MuscleGroup = z.infer<typeof muscleGroupSchema>;\n\n// ─── Prescribed sets (on the detail view) ────────────────────────────────────\n\nexport const exerciseSetSchema = z.object({\n order: z.number().int().min(1),\n reps: z.string().trim().min(1),\n weight: z.string().trim(),\n tempo: z.string().trim(),\n});\nexport type ExerciseSet = z.infer<typeof exerciseSetSchema>;\n\n// ─── Summary (library card) ──────────────────────────────────────────────────\n\nexport const exerciseSummarySchema = z.object({\n id: objectIdSchema,\n slug: z.string(),\n name: z.string(),\n difficulty: difficultySchema,\n category: exerciseCategorySchema,\n targetArea: z.string(),\n thumbnailUrl: z.string().nullable(),\n /**\n * Who authored this entry: `null` = the PLATFORM library, every gym sees it;\n * a center id = that gym's own, and only its people see it.\n *\n * On the SUMMARY, not just the detail, because the grid is where the\n * distinction has to be visible. An owner scrolling their library needs to\n * know which cards are theirs to edit before tapping one, and a member is\n * entitled to know that a routine came from their gym rather than from us.\n * The detail shape inherits it from here, so there is one definition.\n */\n centerId: objectIdSchema.nullable(),\n});\nexport type ExerciseSummary = z.infer<typeof exerciseSummarySchema>;\n\n// ─── Detail (full entity) ────────────────────────────────────────────────────\n\nexport const exerciseSchema = exerciseSummarySchema.extend({\n description: z.string(),\n youtubeId: z.string().nullable(),\n posterUrl: z.string().nullable(),\n targetMuscles: z.array(muscleGroupSchema),\n sets: z.array(exerciseSetSchema),\n formTips: z.array(z.string()),\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type Exercise = z.infer<typeof exerciseSchema>;\n\n// ─── Create / update body ────────────────────────────────────────────────────\n\nexport const createExerciseBodySchema = z.object({\n /**\n * Which library this entry joins. `null` is the PLATFORM library — content\n * the product publishes to every gym — and only platform staff may send it.\n *\n * Nullable rather than optional on purpose: an omitted field would default to\n * the global library, so a client that simply forgot to send a center would\n * silently publish a gym's private exercise to the whole platform. Choosing\n * global has to be something the caller SAYS.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string().trim().min(1, 'Name is required').max(120),\n description: optionalTrimmedString(4000),\n category: exerciseCategorySchema,\n difficulty: difficultySchema,\n targetArea: optionalTrimmedString(120),\n youtubeId: optionalTrimmedString(40),\n thumbnailUrl: optionalTrimmedString(2000),\n posterUrl: optionalTrimmedString(2000),\n targetMuscles: z.array(muscleGroupSchema).max(16).default([]),\n sets: z.array(exerciseSetSchema).max(20).default([]),\n formTips: z.array(z.string().trim().max(400)).max(20).default([]),\n});\nexport type CreateExerciseBody = z.infer<typeof createExerciseBodySchema>;\n\nexport const updateExerciseBodySchema = createExerciseBodySchema.omit({ centerId: true }).partial();\nexport type UpdateExerciseBody = z.infer<typeof updateExerciseBodySchema>;\n\n// ─── Library query ───────────────────────────────────────────────────────────\n\nexport const exerciseLibraryQuerySchema = z.object({\n centerId: objectIdSchema.optional(),\n category: exerciseCategorySchema.optional(),\n difficulty: difficultySchema.optional(),\n q: optionalTrimmedString(120),\n});\nexport type ExerciseLibraryQuery = z.infer<typeof exerciseLibraryQuerySchema>;\n"]}
|
package/dist/platform.d.ts
CHANGED
|
@@ -70,9 +70,8 @@ export type PlatformUserGym = z.infer<typeof platformUserGymSchema>;
|
|
|
70
70
|
* A row in the platform's people directory.
|
|
71
71
|
*
|
|
72
72
|
* `name` arrives RESOLVED — the backend has already applied the
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* call this person".
|
|
73
|
+
* `firstName lastName` → email fallback chain, so every client renders the same
|
|
74
|
+
* thing and no screen invents its own version of "what do we call this person".
|
|
76
75
|
*
|
|
77
76
|
* `appRoles` and `roles` are BOTH here and they are not the same list.
|
|
78
77
|
* `appRoles` is what is stored on the account and is what an admin can grant or
|
package/dist/platform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;EAUxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;iBAIhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;EAUxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;iBAIhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqB7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;iBASlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,8CAA8C;AAC9C,eAAO,MAAM,2BAA2B;;;;;;iBAOtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAIhF;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB;;;;;iBAElC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;;;;iBAEhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B;;iBAEvC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAIlF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB;;;;iBAOnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,oDAAoD;AACpD,eAAO,MAAM,oBAAoB;;;;;;;;;;iBAM/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgCjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAItE;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB;;;;;;iBAOnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B;;iBAEtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|
package/dist/platform.js
CHANGED
|
@@ -69,9 +69,8 @@ export const platformUserGymSchema = z.object({
|
|
|
69
69
|
* A row in the platform's people directory.
|
|
70
70
|
*
|
|
71
71
|
* `name` arrives RESOLVED — the backend has already applied the
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* call this person".
|
|
72
|
+
* `firstName lastName` → email fallback chain, so every client renders the same
|
|
73
|
+
* thing and no screen invents its own version of "what do we call this person".
|
|
75
74
|
*
|
|
76
75
|
* `appRoles` and `roles` are BOTH here and they are not the same list.
|
|
77
76
|
* `appRoles` is what is stored on the account and is what an admin can grant or
|
package/dist/platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Platform console (superadmin / platform manager)\n * ================================================================\n * The two directories the platform operates GymMonk from: every person with an\n * account, and every gym on the platform.\n *\n * ONE CONSOLE, TWO ROLES. Superadmin and platform manager see the same screens\n * and call the same endpoints. The single difference is DESTRUCTIVE ACTS:\n * `casl-ability#grantPlatformManager` states `cannot('delete', 'User')` and\n * `cannot('delete', 'Organisation')`, while superadmin holds `manage all`. That\n * is deliberately expressed as an ABILITY rather than as two contracts — a\n * second set of types for \"the manager's version of the people list\" would drift\n * from the first the moment either changed, and the client would be deciding\n * what it is allowed to do instead of being told.\n *\n * SCOPE. These are PLATFORM views: unscoped by gym, unscoped by center. No gym\n * role can reach them (see the `GymApproval` subject note in `casl-ability`), so\n * nothing here is filtered by organisation.\n *\n * @module gymmonk-schema/platform\n */\n\nimport { z } from 'zod';\nimport {\n deletedFilterSchema,\n isoDateTimeSchema,\n objectIdSchema,\n optionalTrimmedString,\n} from './common.js';\nimport { organisationApprovalStatusSchema } from './organisation.js';\nimport { appRoleSchema, userStatusSchema } from './user.js';\n\n// ─── Role keys ───────────────────────────────────────────────────────────────\n\n/**\n * Every role the tab-bar switcher understands — the wire contract for \"what\n * hats does this person wear\".\n *\n * The SSOT for a set that was previously written out three times: as a TypeScript\n * union in the backend's `casl-ability.ts`, again in the web client's\n * `shared/config/roles.ts`, and again as the values of the backend's role-snapshot\n * maps. Three copies of a closed set is three chances for one of them to miss a\n * role, and the people directory filters on exactly this set — a filter offering\n * a role the deriver never emits returns a permanently empty list with no error.\n *\n * Note `platform_manager` vs the `manager` APP ROLE (`appRoleSchema`): the app\n * role is what is stored on the user, the role key is what the product calls the\n * hat. `gym_manager` is a different job entirely, which is why neither can be\n * called plain \"manager\" on the wire.\n */\nexport const roleKeySchema = z.enum([\n 'member',\n 'owner',\n 'superadmin',\n 'platform_manager',\n 'moderator',\n 'support_agent',\n 'gym_manager',\n 'trainer',\n 'frontdesk',\n]);\nexport type RoleKey = z.infer<typeof roleKeySchema>;\n\n// ─── People directory ────────────────────────────────────────────────────────\n\n/**\n * The gym a person owns, summarised for a directory row.\n *\n * Present only for owners. It is on the row rather than behind a second request\n * because \"which gym is this?\" is the first question asked about any owner in a\n * support or vetting context, and a directory that makes you open each row to\n * find out is not a directory.\n */\nexport const platformUserGymSchema = z.object({\n id: objectIdSchema,\n name: z.string(),\n approvalStatus: organisationApprovalStatusSchema,\n});\nexport type PlatformUserGym = z.infer<typeof platformUserGymSchema>;\n\n/**\n * A row in the platform's people directory.\n *\n * `name` arrives RESOLVED — the backend has already applied the\n * displayName → firstName lastName → email fallback chain, so every client\n * renders the same thing and no screen invents its own version of \"what do we\n * call this person\".\n *\n * `appRoles` and `roles` are BOTH here and they are not the same list.\n * `appRoles` is what is stored on the account and is what an admin can grant or\n * revoke. `roles` is the full derived set including the gym hats implied by\n * domain records — owning an organisation, holding a staff record, having a\n * member profile. An admin who is shown only `appRoles` cannot tell a plain\n * member from the owner of the platform's largest gym.\n */\nexport const platformUserSchema = z.object({\n id: objectIdSchema,\n name: z.string(),\n email: z.string(),\n /** Raw 10 digits, no `+91` — the country code is display-only. */\n phone: z.string().nullable(),\n avatar: z.string().nullable(),\n /** Granted platform roles. Empty for the overwhelming majority of accounts. */\n appRoles: z.array(appRoleSchema),\n /** Every hat, including the gym roles derived from domain records. */\n roles: z.array(roleKeySchema),\n status: userStatusSchema,\n organisation: platformUserGymSchema.nullable(),\n /**\n * Soft-deleted. The account is retained (deleting an owner would cascade into\n * an organisation, its centres, every member and the payment ledger) but is\n * excluded from every ordinary query. Only a superadmin can set this.\n */\n isDeleted: z.boolean(),\n lastActiveAt: isoDateTimeSchema.nullable(),\n createdAt: isoDateTimeSchema,\n});\nexport type PlatformUser = z.infer<typeof platformUserSchema>;\n\n/**\n * The people-list filter.\n *\n * `role` filters on the DERIVED set, not on `appRoles`, so \"show me every gym\n * owner\" works — owner is never an app role. The derivation is denormalised onto\n * the user (`User.roleSnapshot.roles`), which is what makes this an indexed\n * query rather than a fan-out per candidate row.\n */\nexport const platformUserQuerySchema = z.object({\n page: z.coerce.number().int().min(1).default(1),\n limit: z.coerce.number().int().min(1).max(100).default(20),\n /** Name, email or phone. */\n q: optionalTrimmedString(120),\n role: roleKeySchema.optional(),\n status: userStatusSchema.optional(),\n /** Soft-delete visibility. `only` is the superadmin's restore queue. */\n deleted: deletedFilterSchema.default('exclude'),\n});\nexport type PlatformUserQuery = z.infer<typeof platformUserQuerySchema>;\n\n/** Header counts for the people directory. */\nexport const platformPeopleSummarySchema = z.object({\n total: z.number().int(),\n active: z.number().int(),\n suspended: z.number().int(),\n /** Accounts holding at least one platform app-role. */\n staff: z.number().int(),\n owners: z.number().int(),\n});\nexport type PlatformPeopleSummary = z.infer<typeof platformPeopleSummarySchema>;\n\n// ─── People mutations ────────────────────────────────────────────────────────\n\n/**\n * Suspend or reinstate an account.\n *\n * Only these two values. `deleted` is reached through the delete endpoint (which\n * needs a stronger ability and a typed confirmation), and `inactive` is a\n * lifecycle state the product sets for itself — letting an admin write either\n * one here would put the account into a state no screen explains and no action\n * reverses.\n */\nexport const setUserStatusBodySchema = z.object({\n status: z.enum(['active', 'suspended']),\n});\nexport type SetUserStatusBody = z.infer<typeof setUserStatusBodySchema>;\n\n/**\n * Replace the account's platform roles.\n *\n * A whole-array PUT rather than add/remove deltas: the console shows all four\n * checkboxes at once, so the admin is always looking at the complete intended\n * state, and a delta API would let two admins editing the same person silently\n * merge into a set neither chose.\n */\nexport const setAppRolesBodySchema = z.object({\n appRoles: z.array(appRoleSchema).max(4),\n});\nexport type SetAppRolesBody = z.infer<typeof setAppRolesBodySchema>;\n\n/**\n * Soft-delete an account. Superadmin only.\n *\n * The caller must echo the account's EMAIL back. The same echo-to-confirm guard\n * the member and membership deletions use — it is the one pattern that survives\n * a mis-tap on a phone, where a destructive button sits a thumb's width from a\n * harmless one.\n */\nexport const deletePlatformUserBodySchema = z.object({\n confirmationEmail: z.string().trim().min(1),\n});\nexport type DeletePlatformUserBody = z.infer<typeof deletePlatformUserBodySchema>;\n\n// ─── Platform overview (the console's Dashboard tab) ─────────────────────────\n\n/**\n * One month of platform growth.\n *\n * `label` is rendered SERVER-SIDE, already in IST. Month bucketing is done with\n * an explicit `Asia/Kolkata` timezone in the aggregation, and the label is built\n * from the same bucket — so the client never derives a date. Letting it do so\n * would put a UTC container and an IST phone in different months for five and a\n * half hours every night, which is a hydration mismatch that only reproduces\n * after 18:30 IST.\n */\nexport const platformTrendPointSchema = z.object({\n /** Short month, e.g. `Mar`. Includes the year when the window crosses one. */\n label: z.string(),\n /** Accounts created that month. */\n people: z.number().int(),\n /** Gyms registered that month. */\n gyms: z.number().int(),\n});\nexport type PlatformTrendPoint = z.infer<typeof platformTrendPointSchema>;\n\n/** A gym in the \"biggest on the platform\" table. */\nexport const platformTopGymSchema = z.object({\n id: objectIdSchema,\n name: z.string(),\n memberCount: z.number().int(),\n centerCount: z.number().int(),\n approvalStatus: organisationApprovalStatusSchema,\n});\nexport type PlatformTopGym = z.infer<typeof platformTopGymSchema>;\n\n/**\n * Everything the Dashboard tab renders, in one request.\n *\n * One endpoint rather than six. This screen is the console's landing tab, so its\n * cost is paid on every visit — and six round trips would each carry their own\n * loading state, producing a dashboard that reflows four times before settling.\n * The aggregations run concurrently server-side, where they are cheap.\n */\nexport const platformOverviewSchema = z.object({\n totals: z.object({\n /** Registered gyms, whatever their approval state. */\n gyms: z.number().int(),\n centers: z.number().int(),\n /** People with a member record at a gym — NOT the same as `people`. */\n members: z.number().int(),\n /** Memberships currently live (active or paused, not expired). */\n activeMemberships: z.number().int(),\n /** Every account on GymMonk, members and staff alike. */\n people: z.number().int(),\n /** All money successfully collected across every gym, in whole rupees. */\n revenueInr: z.number().int(),\n }),\n /** Growth, oldest month first. */\n trend: z.array(platformTrendPointSchema),\n gymsByStatus: z.object({\n pending: z.number().int(),\n approved: z.number().int(),\n rejected: z.number().int(),\n }),\n topGyms: z.array(platformTopGymSchema),\n /**\n * What is waiting for a human. Every number here is a link on the dashboard,\n * so a count of zero is a good outcome rather than an empty section.\n */\n attention: z.object({\n pendingGyms: z.number().int(),\n suspendedAccounts: z.number().int(),\n /** Approved gyms that never created a centre, so members cannot join them. */\n gymsWithoutCenters: z.number().int(),\n }),\n});\nexport type PlatformOverview = z.infer<typeof platformOverviewSchema>;\n\n// ─── Gym directory ───────────────────────────────────────────────────────────\n\n/**\n * Header counts for the gyms directory, and the review-queue badge.\n *\n * `pending` was previously the only count returned, which was enough for a badge\n * and nothing else: the Gyms tab shows the whole estate, and a screen that can\n * say \"12 pending\" but not \"of how many\" tells an operator nothing about scale.\n */\nexport const platformGymSummarySchema = z.object({\n total: z.number().int(),\n pending: z.number().int(),\n approved: z.number().int(),\n rejected: z.number().int(),\n /** Centres across every approved gym. */\n centers: z.number().int(),\n});\nexport type PlatformGymSummary = z.infer<typeof platformGymSummarySchema>;\n\n/**\n * Soft-delete a gym. Superadmin only.\n *\n * Echoes the gym's NAME rather than an id — an operator reading a confirmation\n * dialog can verify a name against the row they meant to act on; an id they\n * would paste without reading.\n */\nexport const deletePlatformGymBodySchema = z.object({\n confirmationName: z.string().trim().min(1),\n});\nexport type DeletePlatformGymBody = z.infer<typeof deletePlatformGymBodySchema>;\n"]}
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Platform console (superadmin / platform manager)\n * ================================================================\n * The two directories the platform operates GymMonk from: every person with an\n * account, and every gym on the platform.\n *\n * ONE CONSOLE, TWO ROLES. Superadmin and platform manager see the same screens\n * and call the same endpoints. The single difference is DESTRUCTIVE ACTS:\n * `casl-ability#grantPlatformManager` states `cannot('delete', 'User')` and\n * `cannot('delete', 'Organisation')`, while superadmin holds `manage all`. That\n * is deliberately expressed as an ABILITY rather than as two contracts — a\n * second set of types for \"the manager's version of the people list\" would drift\n * from the first the moment either changed, and the client would be deciding\n * what it is allowed to do instead of being told.\n *\n * SCOPE. These are PLATFORM views: unscoped by gym, unscoped by center. No gym\n * role can reach them (see the `GymApproval` subject note in `casl-ability`), so\n * nothing here is filtered by organisation.\n *\n * @module gymmonk-schema/platform\n */\n\nimport { z } from 'zod';\nimport {\n deletedFilterSchema,\n isoDateTimeSchema,\n objectIdSchema,\n optionalTrimmedString,\n} from './common.js';\nimport { organisationApprovalStatusSchema } from './organisation.js';\nimport { appRoleSchema, userStatusSchema } from './user.js';\n\n// ─── Role keys ───────────────────────────────────────────────────────────────\n\n/**\n * Every role the tab-bar switcher understands — the wire contract for \"what\n * hats does this person wear\".\n *\n * The SSOT for a set that was previously written out three times: as a TypeScript\n * union in the backend's `casl-ability.ts`, again in the web client's\n * `shared/config/roles.ts`, and again as the values of the backend's role-snapshot\n * maps. Three copies of a closed set is three chances for one of them to miss a\n * role, and the people directory filters on exactly this set — a filter offering\n * a role the deriver never emits returns a permanently empty list with no error.\n *\n * Note `platform_manager` vs the `manager` APP ROLE (`appRoleSchema`): the app\n * role is what is stored on the user, the role key is what the product calls the\n * hat. `gym_manager` is a different job entirely, which is why neither can be\n * called plain \"manager\" on the wire.\n */\nexport const roleKeySchema = z.enum([\n 'member',\n 'owner',\n 'superadmin',\n 'platform_manager',\n 'moderator',\n 'support_agent',\n 'gym_manager',\n 'trainer',\n 'frontdesk',\n]);\nexport type RoleKey = z.infer<typeof roleKeySchema>;\n\n// ─── People directory ────────────────────────────────────────────────────────\n\n/**\n * The gym a person owns, summarised for a directory row.\n *\n * Present only for owners. It is on the row rather than behind a second request\n * because \"which gym is this?\" is the first question asked about any owner in a\n * support or vetting context, and a directory that makes you open each row to\n * find out is not a directory.\n */\nexport const platformUserGymSchema = z.object({\n id: objectIdSchema,\n name: z.string(),\n approvalStatus: organisationApprovalStatusSchema,\n});\nexport type PlatformUserGym = z.infer<typeof platformUserGymSchema>;\n\n/**\n * A row in the platform's people directory.\n *\n * `name` arrives RESOLVED — the backend has already applied the\n * `firstName lastName` → email fallback chain, so every client renders the same\n * thing and no screen invents its own version of \"what do we call this person\".\n *\n * `appRoles` and `roles` are BOTH here and they are not the same list.\n * `appRoles` is what is stored on the account and is what an admin can grant or\n * revoke. `roles` is the full derived set including the gym hats implied by\n * domain records — owning an organisation, holding a staff record, having a\n * member profile. An admin who is shown only `appRoles` cannot tell a plain\n * member from the owner of the platform's largest gym.\n */\nexport const platformUserSchema = z.object({\n id: objectIdSchema,\n name: z.string(),\n email: z.string(),\n /** Raw 10 digits, no `+91` — the country code is display-only. */\n phone: z.string().nullable(),\n avatar: z.string().nullable(),\n /** Granted platform roles. Empty for the overwhelming majority of accounts. */\n appRoles: z.array(appRoleSchema),\n /** Every hat, including the gym roles derived from domain records. */\n roles: z.array(roleKeySchema),\n status: userStatusSchema,\n organisation: platformUserGymSchema.nullable(),\n /**\n * Soft-deleted. The account is retained (deleting an owner would cascade into\n * an organisation, its centres, every member and the payment ledger) but is\n * excluded from every ordinary query. Only a superadmin can set this.\n */\n isDeleted: z.boolean(),\n lastActiveAt: isoDateTimeSchema.nullable(),\n createdAt: isoDateTimeSchema,\n});\nexport type PlatformUser = z.infer<typeof platformUserSchema>;\n\n/**\n * The people-list filter.\n *\n * `role` filters on the DERIVED set, not on `appRoles`, so \"show me every gym\n * owner\" works — owner is never an app role. The derivation is denormalised onto\n * the user (`User.roleSnapshot.roles`), which is what makes this an indexed\n * query rather than a fan-out per candidate row.\n */\nexport const platformUserQuerySchema = z.object({\n page: z.coerce.number().int().min(1).default(1),\n limit: z.coerce.number().int().min(1).max(100).default(20),\n /** Name, email or phone. */\n q: optionalTrimmedString(120),\n role: roleKeySchema.optional(),\n status: userStatusSchema.optional(),\n /** Soft-delete visibility. `only` is the superadmin's restore queue. */\n deleted: deletedFilterSchema.default('exclude'),\n});\nexport type PlatformUserQuery = z.infer<typeof platformUserQuerySchema>;\n\n/** Header counts for the people directory. */\nexport const platformPeopleSummarySchema = z.object({\n total: z.number().int(),\n active: z.number().int(),\n suspended: z.number().int(),\n /** Accounts holding at least one platform app-role. */\n staff: z.number().int(),\n owners: z.number().int(),\n});\nexport type PlatformPeopleSummary = z.infer<typeof platformPeopleSummarySchema>;\n\n// ─── People mutations ────────────────────────────────────────────────────────\n\n/**\n * Suspend or reinstate an account.\n *\n * Only these two values. `deleted` is reached through the delete endpoint (which\n * needs a stronger ability and a typed confirmation), and `inactive` is a\n * lifecycle state the product sets for itself — letting an admin write either\n * one here would put the account into a state no screen explains and no action\n * reverses.\n */\nexport const setUserStatusBodySchema = z.object({\n status: z.enum(['active', 'suspended']),\n});\nexport type SetUserStatusBody = z.infer<typeof setUserStatusBodySchema>;\n\n/**\n * Replace the account's platform roles.\n *\n * A whole-array PUT rather than add/remove deltas: the console shows all four\n * checkboxes at once, so the admin is always looking at the complete intended\n * state, and a delta API would let two admins editing the same person silently\n * merge into a set neither chose.\n */\nexport const setAppRolesBodySchema = z.object({\n appRoles: z.array(appRoleSchema).max(4),\n});\nexport type SetAppRolesBody = z.infer<typeof setAppRolesBodySchema>;\n\n/**\n * Soft-delete an account. Superadmin only.\n *\n * The caller must echo the account's EMAIL back. The same echo-to-confirm guard\n * the member and membership deletions use — it is the one pattern that survives\n * a mis-tap on a phone, where a destructive button sits a thumb's width from a\n * harmless one.\n */\nexport const deletePlatformUserBodySchema = z.object({\n confirmationEmail: z.string().trim().min(1),\n});\nexport type DeletePlatformUserBody = z.infer<typeof deletePlatformUserBodySchema>;\n\n// ─── Platform overview (the console's Dashboard tab) ─────────────────────────\n\n/**\n * One month of platform growth.\n *\n * `label` is rendered SERVER-SIDE, already in IST. Month bucketing is done with\n * an explicit `Asia/Kolkata` timezone in the aggregation, and the label is built\n * from the same bucket — so the client never derives a date. Letting it do so\n * would put a UTC container and an IST phone in different months for five and a\n * half hours every night, which is a hydration mismatch that only reproduces\n * after 18:30 IST.\n */\nexport const platformTrendPointSchema = z.object({\n /** Short month, e.g. `Mar`. Includes the year when the window crosses one. */\n label: z.string(),\n /** Accounts created that month. */\n people: z.number().int(),\n /** Gyms registered that month. */\n gyms: z.number().int(),\n});\nexport type PlatformTrendPoint = z.infer<typeof platformTrendPointSchema>;\n\n/** A gym in the \"biggest on the platform\" table. */\nexport const platformTopGymSchema = z.object({\n id: objectIdSchema,\n name: z.string(),\n memberCount: z.number().int(),\n centerCount: z.number().int(),\n approvalStatus: organisationApprovalStatusSchema,\n});\nexport type PlatformTopGym = z.infer<typeof platformTopGymSchema>;\n\n/**\n * Everything the Dashboard tab renders, in one request.\n *\n * One endpoint rather than six. This screen is the console's landing tab, so its\n * cost is paid on every visit — and six round trips would each carry their own\n * loading state, producing a dashboard that reflows four times before settling.\n * The aggregations run concurrently server-side, where they are cheap.\n */\nexport const platformOverviewSchema = z.object({\n totals: z.object({\n /** Registered gyms, whatever their approval state. */\n gyms: z.number().int(),\n centers: z.number().int(),\n /** People with a member record at a gym — NOT the same as `people`. */\n members: z.number().int(),\n /** Memberships currently live (active or paused, not expired). */\n activeMemberships: z.number().int(),\n /** Every account on GymMonk, members and staff alike. */\n people: z.number().int(),\n /** All money successfully collected across every gym, in whole rupees. */\n revenueInr: z.number().int(),\n }),\n /** Growth, oldest month first. */\n trend: z.array(platformTrendPointSchema),\n gymsByStatus: z.object({\n pending: z.number().int(),\n approved: z.number().int(),\n rejected: z.number().int(),\n }),\n topGyms: z.array(platformTopGymSchema),\n /**\n * What is waiting for a human. Every number here is a link on the dashboard,\n * so a count of zero is a good outcome rather than an empty section.\n */\n attention: z.object({\n pendingGyms: z.number().int(),\n suspendedAccounts: z.number().int(),\n /** Approved gyms that never created a centre, so members cannot join them. */\n gymsWithoutCenters: z.number().int(),\n }),\n});\nexport type PlatformOverview = z.infer<typeof platformOverviewSchema>;\n\n// ─── Gym directory ───────────────────────────────────────────────────────────\n\n/**\n * Header counts for the gyms directory, and the review-queue badge.\n *\n * `pending` was previously the only count returned, which was enough for a badge\n * and nothing else: the Gyms tab shows the whole estate, and a screen that can\n * say \"12 pending\" but not \"of how many\" tells an operator nothing about scale.\n */\nexport const platformGymSummarySchema = z.object({\n total: z.number().int(),\n pending: z.number().int(),\n approved: z.number().int(),\n rejected: z.number().int(),\n /** Centres across every approved gym. */\n centers: z.number().int(),\n});\nexport type PlatformGymSummary = z.infer<typeof platformGymSummarySchema>;\n\n/**\n * Soft-delete a gym. Superadmin only.\n *\n * Echoes the gym's NAME rather than an id — an operator reading a confirmation\n * dialog can verify a name against the row they meant to act on; an id they\n * would paste without reading.\n */\nexport const deletePlatformGymBodySchema = z.object({\n confirmationName: z.string().trim().min(1),\n});\nexport type DeletePlatformGymBody = z.infer<typeof deletePlatformGymBodySchema>;\n"]}
|
package/dist/user.d.ts
CHANGED
|
@@ -29,7 +29,6 @@ export declare const meSchema: z.ZodObject<{
|
|
|
29
29
|
email: z.ZodString;
|
|
30
30
|
firstName: z.ZodString;
|
|
31
31
|
lastName: z.ZodNullable<z.ZodString>;
|
|
32
|
-
displayName: z.ZodNullable<z.ZodString>;
|
|
33
32
|
phone: z.ZodNullable<z.ZodString>;
|
|
34
33
|
avatar: z.ZodNullable<z.ZodString>;
|
|
35
34
|
appRoles: z.ZodArray<z.ZodEnum<{
|
|
@@ -49,13 +48,23 @@ export declare const meSchema: z.ZodObject<{
|
|
|
49
48
|
}, z.core.$strip>;
|
|
50
49
|
export type Me = z.infer<typeof meSchema>;
|
|
51
50
|
/**
|
|
52
|
-
* Patch the product-owned identity fields (name/
|
|
51
|
+
* Patch the product-owned identity fields (name/phone/avatar).
|
|
53
52
|
* `email` is auth-owned and never updated here.
|
|
53
|
+
*
|
|
54
|
+
* A user has exactly TWO name fields and no denormalised third one. There used
|
|
55
|
+
* to be a `displayName`, seeded once from the central-auth (Google) name and
|
|
56
|
+
* never recomputed — and because every screen read it FIRST, the name a member
|
|
57
|
+
* typed during onboarding was stored and never shown.
|
|
58
|
+
*
|
|
59
|
+
* The name is submitted as a UNIT: the profile screen edits it in one box and
|
|
60
|
+
* splits on the first space, so a body carrying `firstName` is the complete
|
|
61
|
+
* name and an absent `lastName` means the surname was deleted. The API applies
|
|
62
|
+
* that rule (`shared/routes/user.route`), because `optionalTrimmedString` maps
|
|
63
|
+
* an empty string to `undefined` and the wire cannot say "clear it" otherwise.
|
|
54
64
|
*/
|
|
55
65
|
export declare const updateUserBodySchema: z.ZodObject<{
|
|
56
66
|
firstName: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
57
67
|
lastName: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
58
|
-
displayName: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
59
68
|
phone: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
60
69
|
avatar: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
61
70
|
}, z.core.$strip>;
|
package/dist/user.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,kFAAkF;AAClF,eAAO,MAAM,aAAa;;;;;EAAkE,CAAC;AAC7F,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,gBAAgB;;;;;EAAyD,CAAC;AACvF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAI1D,eAAO,MAAM,QAAQ
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,kFAAkF;AAClF,eAAO,MAAM,aAAa;;;;;EAAkE,CAAC;AAC7F,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,gBAAgB;;;;;EAAyD,CAAC;AACvF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAI1D,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;iBAWnB,CAAC;AACH,MAAM,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAI1C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB;;;;;iBAQ/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAIlE;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B;;;;;;iBAUxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF,+DAA+D;AAC/D,eAAO,MAAM,gCAAgC,EAAE,uBAM9C,CAAC;AAEF,eAAO,MAAM,uCAAuC;;;;;;iBAA0C,CAAC;AAC/F,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,KAAK,CACrD,OAAO,uCAAuC,CAC/C,CAAC;AAIF;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B;;iBAEvC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
|
package/dist/user.js
CHANGED
|
@@ -20,8 +20,6 @@ export const meSchema = z.object({
|
|
|
20
20
|
email: z.string(),
|
|
21
21
|
firstName: z.string(),
|
|
22
22
|
lastName: z.string().nullable(),
|
|
23
|
-
/** Free, user-chosen display name (falls back to first/last at the edge). */
|
|
24
|
-
displayName: z.string().nullable(),
|
|
25
23
|
phone: z.string().nullable(),
|
|
26
24
|
avatar: z.string().nullable(),
|
|
27
25
|
appRoles: z.array(appRoleSchema),
|
|
@@ -31,13 +29,23 @@ export const meSchema = z.object({
|
|
|
31
29
|
});
|
|
32
30
|
// ─── Update the caller's own identity fields ─────────────────────────────────
|
|
33
31
|
/**
|
|
34
|
-
* Patch the product-owned identity fields (name/
|
|
32
|
+
* Patch the product-owned identity fields (name/phone/avatar).
|
|
35
33
|
* `email` is auth-owned and never updated here.
|
|
34
|
+
*
|
|
35
|
+
* A user has exactly TWO name fields and no denormalised third one. There used
|
|
36
|
+
* to be a `displayName`, seeded once from the central-auth (Google) name and
|
|
37
|
+
* never recomputed — and because every screen read it FIRST, the name a member
|
|
38
|
+
* typed during onboarding was stored and never shown.
|
|
39
|
+
*
|
|
40
|
+
* The name is submitted as a UNIT: the profile screen edits it in one box and
|
|
41
|
+
* splits on the first space, so a body carrying `firstName` is the complete
|
|
42
|
+
* name and an absent `lastName` means the surname was deleted. The API applies
|
|
43
|
+
* that rule (`shared/routes/user.route`), because `optionalTrimmedString` maps
|
|
44
|
+
* an empty string to `undefined` and the wire cannot say "clear it" otherwise.
|
|
36
45
|
*/
|
|
37
46
|
export const updateUserBodySchema = z.object({
|
|
38
47
|
firstName: optionalTrimmedString(80),
|
|
39
48
|
lastName: optionalTrimmedString(80),
|
|
40
|
-
displayName: optionalTrimmedString(100),
|
|
41
49
|
phone: z.preprocess((v) => (typeof v === 'string' && v.trim() === '' ? undefined : v), phoneSchema.optional()),
|
|
42
50
|
avatar: optionalTrimmedString(2000),
|
|
43
51
|
});
|
package/dist/user.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.js","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEpG,gFAAgF;AAEhF,kFAAkF;AAClF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;AAG7F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;AAGvF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,cAAc;IAClB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,
|
|
1
|
+
{"version":3,"file":"user.js","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEpG,gFAAgF;AAEhF,kFAAkF;AAClF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;AAG7F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;AAGvF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,cAAc;IAClB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;IAChC,MAAM,EAAE,gBAAgB;IACxB,SAAS,EAAE,iBAAiB;IAC5B,SAAS,EAAE,iBAAiB;CAC7B,CAAC,CAAC;AAGH,gFAAgF;AAEhF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,SAAS,EAAE,qBAAqB,CAAC,EAAE,CAAC;IACpC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,CAAC;IACnC,KAAK,EAAE,CAAC,CAAC,UAAU,CACjB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACjE,WAAW,CAAC,QAAQ,EAAE,CACvB;IACD,MAAM,EAAE,qBAAqB,CAAC,IAAI,CAAC;CACpC,CAAC,CAAC;AAGH,gFAAgF;AAEhF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC;IACpD,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;IACrB,yDAAyD;IACzD,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;IACpB,uCAAuC;IACvC,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE;IACzB,sDAAsD;IACtD,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE;IACxB,2CAA2C;IAC3C,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAAE;CAC/B,CAAC,CAAC;AAGH,+DAA+D;AAC/D,MAAM,CAAC,MAAM,gCAAgC,GAA4B;IACvE,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,IAAI;IACb,YAAY,EAAE,IAAI;IAClB,WAAW,EAAE,IAAI;IACjB,iBAAiB,EAAE,IAAI;CACxB,CAAC;AAEF,MAAM,CAAC,MAAM,uCAAuC,GAAG,6BAA6B,CAAC,OAAO,EAAE,CAAC;AAK/F,gFAAgF;AAEhF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,WAAW,EAAE,iBAAiB;CAC/B,CAAC,CAAC","sourcesContent":["/**\n * gymmonk-schema — Authenticated user identity (\"me\")\n * ===================================================\n * The identity the whole app boots from — the shape of `GET /users/me`, mirrored\n * from the auth-synced `User`. This is the SSOT for the signed-in user's name,\n * avatar, email, phone, platform roles and status; the member/owner profile\n * modules layer product-specific data on top of it.\n *\n * @module gymmonk-schema/user\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString, phoneSchema } from './common.js';\n\n// ─── Platform roles & status ─────────────────────────────────────────────────\n\n/** Platform-wide roles (empty for most users). Distinct from gym owner/member. */\nexport const appRoleSchema = z.enum(['support_agent', 'moderator', 'manager', 'superadmin']);\nexport type AppRole = z.infer<typeof appRoleSchema>;\n\nexport const userStatusSchema = z.enum(['active', 'inactive', 'suspended', 'deleted']);\nexport type UserStatus = z.infer<typeof userStatusSchema>;\n\n// ─── The \"me\" entity ─────────────────────────────────────────────────────────\n\nexport const meSchema = z.object({\n id: objectIdSchema,\n email: z.string(),\n firstName: z.string(),\n lastName: z.string().nullable(),\n phone: z.string().nullable(),\n avatar: z.string().nullable(),\n appRoles: z.array(appRoleSchema),\n status: userStatusSchema,\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type Me = z.infer<typeof meSchema>;\n\n// ─── Update the caller's own identity fields ─────────────────────────────────\n\n/**\n * Patch the product-owned identity fields (name/phone/avatar).\n * `email` is auth-owned and never updated here.\n *\n * A user has exactly TWO name fields and no denormalised third one. There used\n * to be a `displayName`, seeded once from the central-auth (Google) name and\n * never recomputed — and because every screen read it FIRST, the name a member\n * typed during onboarding was stored and never shown.\n *\n * The name is submitted as a UNIT: the profile screen edits it in one box and\n * splits on the first space, so a body carrying `firstName` is the complete\n * name and an absent `lastName` means the surname was deleted. The API applies\n * that rule (`shared/routes/user.route`), because `optionalTrimmedString` maps\n * an empty string to `undefined` and the wire cannot say \"clear it\" otherwise.\n */\nexport const updateUserBodySchema = z.object({\n firstName: optionalTrimmedString(80),\n lastName: optionalTrimmedString(80),\n phone: z.preprocess(\n (v) => (typeof v === 'string' && v.trim() === '' ? undefined : v),\n phoneSchema.optional(),\n ),\n avatar: optionalTrimmedString(2000),\n});\nexport type UpdateUserBody = z.infer<typeof updateUserBodySchema>;\n\n// ─── Notification preferences ────────────────────────────────────────────────\n\n/**\n * What a person wants to be told about.\n *\n * `pauseAll` is a MASTER switch, not a sixth category: it silences everything\n * without the user having to remember which four they had turned on, and\n * un-pausing restores exactly what they had. The dispatcher checks it first\n * (see `notification/gym.dispatch`), so a paused account cannot be woken by a\n * new notification kind added later that nobody thought to gate.\n */\nexport const notificationPreferencesSchema = z.object({\n pauseAll: z.boolean(),\n /** Reminders before a booked or habitual gym session. */\n gymTime: z.boolean(),\n /** The day's assigned workout plan. */\n dailyWorkout: z.boolean(),\n /** Estimated calorie-burn updates through the day. */\n calorieBurn: z.boolean(),\n /** \"Your membership expires in N days\". */\n membershipRenewal: z.boolean(),\n});\nexport type NotificationPreferences = z.infer<typeof notificationPreferencesSchema>;\n\n/** Everything on, nothing paused — what a new account gets. */\nexport const DEFAULT_NOTIFICATION_PREFERENCES: NotificationPreferences = {\n pauseAll: false,\n gymTime: true,\n dailyWorkout: true,\n calorieBurn: true,\n membershipRenewal: true,\n};\n\nexport const updateNotificationPreferencesBodySchema = notificationPreferencesSchema.partial();\nexport type UpdateNotificationPreferencesBody = z.infer<\n typeof updateNotificationPreferencesBodySchema\n>;\n\n// ─── Account deletion ────────────────────────────────────────────────────────\n\n/**\n * A request to erase the account.\n *\n * Recorded, not executed. Deleting a gym owner cascades into the organisation,\n * its centres, every member and staff record, the membership ledger and the\n * payment history — some of which the business is legally required to keep for\n * a period. So the account is marked, signed out and queued for an operator,\n * which is also what \"right to erasure with a verification step\" looks like.\n */\nexport const accountDeletionRequestSchema = z.object({\n requestedAt: isoDateTimeSchema,\n});\nexport type AccountDeletionRequest = z.infer<typeof accountDeletionRequestSchema>;\n"]}
|
package/dist/workout-plan.d.ts
CHANGED
|
@@ -97,7 +97,7 @@ export declare const planDaySchema: z.ZodObject<{
|
|
|
97
97
|
export type PlanDay = z.infer<typeof planDaySchema>;
|
|
98
98
|
export declare const workoutPlanSummarySchema: z.ZodObject<{
|
|
99
99
|
id: z.ZodString;
|
|
100
|
-
centerId: z.ZodString
|
|
100
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
101
101
|
name: z.ZodString;
|
|
102
102
|
description: z.ZodNullable<z.ZodString>;
|
|
103
103
|
goals: z.ZodNullable<z.ZodString>;
|
|
@@ -108,7 +108,7 @@ export declare const workoutPlanSummarySchema: z.ZodObject<{
|
|
|
108
108
|
export type WorkoutPlanSummary = z.infer<typeof workoutPlanSummarySchema>;
|
|
109
109
|
export declare const workoutPlanSchema: z.ZodObject<{
|
|
110
110
|
id: z.ZodString;
|
|
111
|
-
centerId: z.ZodString
|
|
111
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
112
112
|
name: z.ZodString;
|
|
113
113
|
description: z.ZodNullable<z.ZodString>;
|
|
114
114
|
goals: z.ZodNullable<z.ZodString>;
|
|
@@ -152,7 +152,7 @@ export declare const workoutPlanSchema: z.ZodObject<{
|
|
|
152
152
|
}, z.core.$strip>;
|
|
153
153
|
export type WorkoutPlan = z.infer<typeof workoutPlanSchema>;
|
|
154
154
|
export declare const createWorkoutPlanBodySchema: z.ZodObject<{
|
|
155
|
-
centerId: z.ZodString
|
|
155
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
156
156
|
name: z.ZodString;
|
|
157
157
|
description: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
158
158
|
goals: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workout-plan.d.ts","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,uEAAuE;AACvE,eAAO,MAAM,uBAAuB;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;iBAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;iBAY7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD,eAAO,MAAM,wBAAwB;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"workout-plan.d.ts","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,uEAAuE;AACvE,eAAO,MAAM,uBAAuB;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;iBAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;iBAY7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD,eAAO,MAAM,wBAAwB;;;;;;;;;iBAyBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAE5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;iBAetC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;iBAE5B,CAAC;AACb,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|
package/dist/workout-plan.js
CHANGED
|
@@ -46,7 +46,14 @@ export const planDaySchema = z.object({
|
|
|
46
46
|
// ─── Entity ──────────────────────────────────────────────────────────────────
|
|
47
47
|
export const workoutPlanSummarySchema = z.object({
|
|
48
48
|
id: objectIdSchema,
|
|
49
|
-
|
|
49
|
+
/**
|
|
50
|
+
* `null` = a PLATFORM template, offered to every gym; a center id = that
|
|
51
|
+
* gym's own routine, visible only to its people.
|
|
52
|
+
*
|
|
53
|
+
* See `createWorkoutPlanBodySchema.centerId` for why the global case is a
|
|
54
|
+
* null the caller must state rather than a field they may omit.
|
|
55
|
+
*/
|
|
56
|
+
centerId: objectIdSchema.nullable(),
|
|
50
57
|
name: z.string(),
|
|
51
58
|
description: z.string().nullable(),
|
|
52
59
|
/**
|
|
@@ -68,7 +75,15 @@ export const workoutPlanSchema = workoutPlanSummarySchema.extend({
|
|
|
68
75
|
});
|
|
69
76
|
// ─── Create / update body ────────────────────────────────────────────────────
|
|
70
77
|
export const createWorkoutPlanBodySchema = z.object({
|
|
71
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Which library this plan joins. `null` is the PLATFORM template shelf, which
|
|
80
|
+
* only platform staff may write to.
|
|
81
|
+
*
|
|
82
|
+
* Nullable rather than optional: omitting the field would quietly mean
|
|
83
|
+
* "global", so one forgetful client could publish a gym's programming to
|
|
84
|
+
* every competitor on the product. Going global has to be stated.
|
|
85
|
+
*/
|
|
86
|
+
centerId: objectIdSchema.nullable(),
|
|
72
87
|
name: z.string().trim().min(1, 'Plan name is required').max(120),
|
|
73
88
|
description: optionalTrimmedString(2000),
|
|
74
89
|
goals: optionalTrimmedString(400),
|
package/dist/workout-plan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workout-plan.js","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,gFAAgF;AAEhF,uEAAuE;AACvE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,UAAU,EAAE,cAAc;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;CAC3C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,OAAO,EAAE,aAAa;IACtB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAChE,CAAC,CAAC;AAGH,gFAAgF;AAEhF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,cAAc;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,UAAU,EAAE,gBAAgB;IAC5B,QAAQ,EAAE,sBAAsB;IAChC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;CAC1B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,aAAa;IACtB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;CACvC,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,EAAE,EAAE,cAAc;IAClB,QAAQ,EAAE,cAAc;
|
|
1
|
+
{"version":3,"file":"workout-plan.js","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Workout plans (routines)\n * ==========================================\n * A weekly training routine an owner builds from library exercises and assigns\n * to members. Each day carries prescribed exercises (sets / reps / rest). The\n * prescription is stored by exercise ref; the API populates a summary for\n * rendering.\n *\n * @module gymmonk-schema/workout-plan\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString } from './common.js';\nimport { difficultySchema, exerciseCategorySchema } from './exercise.js';\nimport { weekdaySchema } from './shared.js';\n\n// ─── Prescription (stored input) ─────────────────────────────────────────────\n\n/** One exercise slot in a plan day, referencing a library exercise. */\nexport const planExerciseInputSchema = z.object({\n exerciseId: objectIdSchema,\n sets: z.number().int().min(1).max(20),\n reps: z.string().trim().min(1).max(40),\n restSec: z.number().int().min(0).max(3600),\n});\nexport type PlanExerciseInput = z.infer<typeof planExerciseInputSchema>;\n\nexport const workoutPlanDayInputSchema = z.object({\n weekday: weekdaySchema,\n exercises: z.array(planExerciseInputSchema).max(30).default([]),\n});\nexport type WorkoutPlanDayInput = z.infer<typeof workoutPlanDayInputSchema>;\n\n// ─── Populated response shapes ───────────────────────────────────────────────\n\n/** A plan-day exercise with its populated library summary + prescription. */\nexport const planExerciseSchema = z.object({\n exerciseId: objectIdSchema,\n slug: z.string(),\n name: z.string(),\n description: z.string(),\n thumbnailUrl: z.string().nullable(),\n difficulty: difficultySchema,\n category: exerciseCategorySchema,\n targetArea: z.string(),\n sets: z.number().int(),\n reps: z.string(),\n restSec: z.number().int(),\n});\nexport type PlanExercise = z.infer<typeof planExerciseSchema>;\n\nexport const planDaySchema = z.object({\n weekday: weekdaySchema,\n exercises: z.array(planExerciseSchema),\n});\nexport type PlanDay = z.infer<typeof planDaySchema>;\n\n// ─── Entity ──────────────────────────────────────────────────────────────────\n\nexport const workoutPlanSummarySchema = z.object({\n id: objectIdSchema,\n /**\n * `null` = a PLATFORM template, offered to every gym; a center id = that\n * gym's own routine, visible only to its people.\n *\n * See `createWorkoutPlanBodySchema.centerId` for why the global case is a\n * null the caller must state rather than a field they may omit.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string(),\n description: z.string().nullable(),\n /**\n * What the plan is FOR (\"Strength, Endurance\"), as distinct from\n * `description`, the prose blurb on the plan card.\n *\n * `createWorkoutPlanBodySchema` has accepted `goals` from the start but no\n * read shape carried it, so the owner's Goals / Focus field was write-only —\n * and, until the Mongoose model gained the path, not even written. Reading it\n * back is what lets the plan be edited without silently clearing the field.\n */\n goals: z.string().nullable(),\n focusTags: z.array(z.string()),\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type WorkoutPlanSummary = z.infer<typeof workoutPlanSummarySchema>;\n\nexport const workoutPlanSchema = workoutPlanSummarySchema.extend({\n days: z.array(planDaySchema),\n});\nexport type WorkoutPlan = z.infer<typeof workoutPlanSchema>;\n\n// ─── Create / update body ────────────────────────────────────────────────────\n\nexport const createWorkoutPlanBodySchema = z.object({\n /**\n * Which library this plan joins. `null` is the PLATFORM template shelf, which\n * only platform staff may write to.\n *\n * Nullable rather than optional: omitting the field would quietly mean\n * \"global\", so one forgetful client could publish a gym's programming to\n * every competitor on the product. Going global has to be stated.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string().trim().min(1, 'Plan name is required').max(120),\n description: optionalTrimmedString(2000),\n goals: optionalTrimmedString(400),\n focusTags: z.array(z.string().trim().max(40)).max(20).default([]),\n days: z.array(workoutPlanDayInputSchema).max(7).default([]),\n});\nexport type CreateWorkoutPlanBody = z.infer<typeof createWorkoutPlanBodySchema>;\n\nexport const updateWorkoutPlanBodySchema = createWorkoutPlanBodySchema\n .omit({ centerId: true })\n .partial();\nexport type UpdateWorkoutPlanBody = z.infer<typeof updateWorkoutPlanBodySchema>;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gymmonk-schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Shared Zod schemas, enums and domain types for GymMonk (fitness SaaS) — single source of truth (SSOT) consumed by gymmonk-backend and gymmonk-web-client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|