@ttt-productions/q-core 0.1.3 → 0.1.4
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/constants/media.d.ts +2 -0
- package/dist/constants/media.d.ts.map +1 -1
- package/dist/constants/media.js +8 -0
- package/dist/constants/media.js.map +1 -1
- package/dist/constants/scheduled-jobs.d.ts +1 -1
- package/dist/constants/scheduled-jobs.d.ts.map +1 -1
- package/dist/constants/scheduled-jobs.js +7 -1
- package/dist/constants/scheduled-jobs.js.map +1 -1
- package/dist/doc-schemas/registry.d.ts +2 -0
- package/dist/doc-schemas/registry.d.ts.map +1 -1
- package/dist/doc-schemas/sport-league.d.ts +2 -0
- package/dist/doc-schemas/sport-league.d.ts.map +1 -1
- package/dist/doc-schemas/sport-league.js +9 -0
- package/dist/doc-schemas/sport-league.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,8 @@ export declare const GALLERY_RETIREMENT_PICTURES_PER_RUN = 100;
|
|
|
9
9
|
export declare const STAGING_LIST_PAGE_SIZE = 1000;
|
|
10
10
|
export declare const MAX_STAGING_DELETES_PER_RUN = 500;
|
|
11
11
|
export declare const MAX_STAGING_EXAMINED_PER_RUN: number;
|
|
12
|
+
export declare const MEDIA_SWEEP_BACKOFF_BASE_MS: number;
|
|
13
|
+
export declare const MEDIA_SWEEP_BACKOFF_MAX_MS: number;
|
|
12
14
|
export declare const MAX_V1_PICTURE_CARRY_ATTEMPTS = 3;
|
|
13
15
|
export declare const MAX_STAGING_UPLOAD_PATH_LENGTH = 300;
|
|
14
16
|
//# sourceMappingURL=media.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/constants/media.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAI/C,eAAO,MAAM,yBAAyB,QAAiB,CAAC;AAIxD,eAAO,MAAM,0BAA0B,QAAiB,CAAC;AAIzD,eAAO,MAAM,wBAAwB,QAAe,CAAC;AAIrD,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,eAAO,MAAM,qCAAqC,IAAI,CAAC;AACvD,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAC/C,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAK/C,eAAO,MAAM,4BAA4B,QAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/constants/media.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAI/C,eAAO,MAAM,yBAAyB,QAAiB,CAAC;AAIxD,eAAO,MAAM,0BAA0B,QAAiB,CAAC;AAIzD,eAAO,MAAM,wBAAwB,QAAe,CAAC;AAIrD,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,eAAO,MAAM,qCAAqC,IAAI,CAAC;AACvD,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAC/C,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAK/C,eAAO,MAAM,4BAA4B,QAA6B,CAAC;AAQvE,eAAO,MAAM,2BAA2B,QAAiB,CAAC;AAC1D,eAAO,MAAM,0BAA0B,QAAe,CAAC;AAIvD,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAG/C,eAAO,MAAM,8BAA8B,MAAM,CAAC"}
|
package/dist/constants/media.js
CHANGED
|
@@ -28,6 +28,14 @@ export const MAX_STAGING_DELETES_PER_RUN = 500;
|
|
|
28
28
|
// this is what bounds a pass over a long kept stretch; two listing pages keep the pass well inside
|
|
29
29
|
// the sweep's timeout beside its other passes, and the next run resumes after the last one examined.
|
|
30
30
|
export const MAX_STAGING_EXAMINED_PER_RUN = 2 * STAGING_LIST_PAGE_SIZE;
|
|
31
|
+
// Deferral backoff for the sweep's picture-retirement and stale-upload passes. A row a pass keeps or
|
|
32
|
+
// fails on leaves its scan window as a sweep-state `deferred` entry, next due
|
|
33
|
+
// `min(BASE × 2^(n−1), MAX)` from now with `n` its attempt count: 15 and 30 minutes, 1, 2, 4, 8 and
|
|
34
|
+
// 16 hours, then a day from there on. The base is the sweep's 15-minute cadence, since any shorter
|
|
35
|
+
// delay is simply the next run; the cap bounds how long a released reference or a recovered failure
|
|
36
|
+
// waits to be noticed.
|
|
37
|
+
export const MEDIA_SWEEP_BACKOFF_BASE_MS = 15 * MINUTE_MS;
|
|
38
|
+
export const MEDIA_SWEEP_BACKOFF_MAX_MS = 24 * HOUR_MS;
|
|
31
39
|
// How many times the migration console's picture carry enqueues one source before reporting it as refused by the
|
|
32
40
|
// pipeline.
|
|
33
41
|
export const MAX_V1_PICTURE_CARRY_ATTEMPTS = 3;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/constants/media.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,mGAAmG;AACnG,6CAA6C;AAE7C,MAAM,SAAS,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5B,MAAM,OAAO,GAAG,EAAE,GAAG,SAAS,CAAC;AAE/B,iGAAiG;AACjG,yCAAyC;AACzC,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,+FAA+F;AAC/F,wFAAwF;AACxF,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,SAAS,CAAC;AAExD,oGAAoG;AACpG,oEAAoE;AACpE,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,SAAS,CAAC;AAEzD,6FAA6F;AAC7F,4FAA4F;AAC5F,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,OAAO,CAAC;AAErD,kGAAkG;AAClG,2BAA2B;AAC3B,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AACjD,MAAM,CAAC,MAAM,qCAAqC,GAAG,CAAC,CAAC;AACvD,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,CAAC;AAC/C,MAAM,CAAC,MAAM,mCAAmC,GAAG,GAAG,CAAC;AACvD,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAC3C,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAC/C,4FAA4F;AAC5F,sGAAsG;AACtG,mGAAmG;AACnG,qGAAqG;AACrG,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,GAAG,sBAAsB,CAAC;AAEvE,iHAAiH;AACjH,YAAY;AACZ,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,+FAA+F;AAC/F,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC","sourcesContent":["// Upload pipeline policy: the processing claim, the maintenance sweep's windows and bounds, and the\n// retry ceiling of the migration console's picture carry. The generic claim and lease machinery is\n// media-schemas'; the numbers are Q-Sports'.\n\nconst MINUTE_MS = 60 * 1000;\nconst HOUR_MS = 60 * MINUTE_MS;\n\n// Processing attempts a picture upload gets, the first included. A second attempt exists only to\n// recover a crashed or killed first one.\nexport const MEDIA_PROCESSING_MAX_ATTEMPTS = 2;\n\n// How long a processing claim owns its row before a redelivery may reclaim it. Longer than the\n// processing trigger's timeout, so a live attempt is never reclaimed from under itself.\nexport const MEDIA_PROCESSING_LEASE_MS = 10 * MINUTE_MS;\n\n// An upload still `pending` or `processing` this long after it was accepted, past its lease, has no\n// live attempt left driving it, and the maintenance sweep fails it.\nexport const STALE_PENDING_MEDIA_AGE_MS = 30 * MINUTE_MS;\n\n// A staged object this old with no `pending` or `processing` upload row is abandoned — never\n// accepted, consumed by a signing, or left by a finished upload — and the sweep deletes it.\nexport const ABANDONED_STAGING_AGE_MS = 24 * HOUR_MS;\n\n// The maintenance sweep's per-run bounds (BACKEND-112). Each pass stops at its bound and the next\n// scheduled run continues.\nexport const STALE_PENDING_MEDIA_PAGE_SIZE = 100;\nexport const MAX_STALE_PENDING_MEDIA_PAGES_PER_RUN = 5;\nexport const PICTURE_RETIREMENT_PAGE_SIZE = 50;\nexport const GALLERY_RETIREMENT_PICTURES_PER_RUN = 100;\nexport const STAGING_LIST_PAGE_SIZE = 1000;\nexport const MAX_STAGING_DELETES_PER_RUN = 500;\n// The most staged objects one abandoned-staging pass examines before it stops and saves its\n// position. Kept objects (young, with a live row, unreadable) cost nothing against the delete cap, so\n// this is what bounds a pass over a long kept stretch; two listing pages keep the pass well inside\n// the sweep's timeout beside its other passes, and the next run resumes after the last one examined.\nexport const MAX_STAGING_EXAMINED_PER_RUN = 2 * STAGING_LIST_PAGE_SIZE;\n\n// How many times the migration console's picture carry enqueues one source before reporting it as refused by the\n// pipeline.\nexport const MAX_V1_PICTURE_CARRY_ATTEMPTS = 3;\n\n// The longest staging path a callable accepts: `uploads/{origin}/{uid}/{uuid}` is far shorter.\nexport const MAX_STAGING_UPLOAD_PATH_LENGTH = 300;\n"]}
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/constants/media.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,mGAAmG;AACnG,6CAA6C;AAE7C,MAAM,SAAS,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5B,MAAM,OAAO,GAAG,EAAE,GAAG,SAAS,CAAC;AAE/B,iGAAiG;AACjG,yCAAyC;AACzC,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,+FAA+F;AAC/F,wFAAwF;AACxF,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,SAAS,CAAC;AAExD,oGAAoG;AACpG,oEAAoE;AACpE,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,SAAS,CAAC;AAEzD,6FAA6F;AAC7F,4FAA4F;AAC5F,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,OAAO,CAAC;AAErD,kGAAkG;AAClG,2BAA2B;AAC3B,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AACjD,MAAM,CAAC,MAAM,qCAAqC,GAAG,CAAC,CAAC;AACvD,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,CAAC;AAC/C,MAAM,CAAC,MAAM,mCAAmC,GAAG,GAAG,CAAC;AACvD,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAC3C,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAC/C,4FAA4F;AAC5F,sGAAsG;AACtG,mGAAmG;AACnG,qGAAqG;AACrG,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,GAAG,sBAAsB,CAAC;AAEvE,qGAAqG;AACrG,8EAA8E;AAC9E,oGAAoG;AACpG,mGAAmG;AACnG,oGAAoG;AACpG,uBAAuB;AACvB,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,GAAG,SAAS,CAAC;AAC1D,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,OAAO,CAAC;AAEvD,iHAAiH;AACjH,YAAY;AACZ,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,+FAA+F;AAC/F,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC","sourcesContent":["// Upload pipeline policy: the processing claim, the maintenance sweep's windows and bounds, and the\n// retry ceiling of the migration console's picture carry. The generic claim and lease machinery is\n// media-schemas'; the numbers are Q-Sports'.\n\nconst MINUTE_MS = 60 * 1000;\nconst HOUR_MS = 60 * MINUTE_MS;\n\n// Processing attempts a picture upload gets, the first included. A second attempt exists only to\n// recover a crashed or killed first one.\nexport const MEDIA_PROCESSING_MAX_ATTEMPTS = 2;\n\n// How long a processing claim owns its row before a redelivery may reclaim it. Longer than the\n// processing trigger's timeout, so a live attempt is never reclaimed from under itself.\nexport const MEDIA_PROCESSING_LEASE_MS = 10 * MINUTE_MS;\n\n// An upload still `pending` or `processing` this long after it was accepted, past its lease, has no\n// live attempt left driving it, and the maintenance sweep fails it.\nexport const STALE_PENDING_MEDIA_AGE_MS = 30 * MINUTE_MS;\n\n// A staged object this old with no `pending` or `processing` upload row is abandoned — never\n// accepted, consumed by a signing, or left by a finished upload — and the sweep deletes it.\nexport const ABANDONED_STAGING_AGE_MS = 24 * HOUR_MS;\n\n// The maintenance sweep's per-run bounds (BACKEND-112). Each pass stops at its bound and the next\n// scheduled run continues.\nexport const STALE_PENDING_MEDIA_PAGE_SIZE = 100;\nexport const MAX_STALE_PENDING_MEDIA_PAGES_PER_RUN = 5;\nexport const PICTURE_RETIREMENT_PAGE_SIZE = 50;\nexport const GALLERY_RETIREMENT_PICTURES_PER_RUN = 100;\nexport const STAGING_LIST_PAGE_SIZE = 1000;\nexport const MAX_STAGING_DELETES_PER_RUN = 500;\n// The most staged objects one abandoned-staging pass examines before it stops and saves its\n// position. Kept objects (young, with a live row, unreadable) cost nothing against the delete cap, so\n// this is what bounds a pass over a long kept stretch; two listing pages keep the pass well inside\n// the sweep's timeout beside its other passes, and the next run resumes after the last one examined.\nexport const MAX_STAGING_EXAMINED_PER_RUN = 2 * STAGING_LIST_PAGE_SIZE;\n\n// Deferral backoff for the sweep's picture-retirement and stale-upload passes. A row a pass keeps or\n// fails on leaves its scan window as a sweep-state `deferred` entry, next due\n// `min(BASE × 2^(n−1), MAX)` from now with `n` its attempt count: 15 and 30 minutes, 1, 2, 4, 8 and\n// 16 hours, then a day from there on. The base is the sweep's 15-minute cadence, since any shorter\n// delay is simply the next run; the cap bounds how long a released reference or a recovered failure\n// waits to be noticed.\nexport const MEDIA_SWEEP_BACKOFF_BASE_MS = 15 * MINUTE_MS;\nexport const MEDIA_SWEEP_BACKOFF_MAX_MS = 24 * HOUR_MS;\n\n// How many times the migration console's picture carry enqueues one source before reporting it as refused by the\n// pipeline.\nexport const MAX_V1_PICTURE_CARRY_ATTEMPTS = 3;\n\n// The longest staging path a callable accepts: `uploads/{origin}/{uid}/{uuid}` is far shorter.\nexport const MAX_STAGING_UPLOAD_PATH_LENGTH = 300;\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The `sweepState/{sweepName}` document ids: one per scheduled pass that keeps a rolling cursor
|
|
3
3
|
* (`SweepStateSchema`), so each pass owns exactly one document and its cursor is never shared.
|
|
4
4
|
*/
|
|
5
|
-
export declare const SWEEP_STATE_NAMES: readonly ["reconcilePublicUsers", "orphanRegistrationCleanup", "reconcileAccountStatus"];
|
|
5
|
+
export declare const SWEEP_STATE_NAMES: readonly ["reconcilePublicUsers", "orphanRegistrationCleanup", "reconcileAccountStatus", "pictureRetirement", "stalePendingMedia"];
|
|
6
6
|
export type SweepStateName = (typeof SWEEP_STATE_NAMES)[number];
|
|
7
7
|
/**
|
|
8
8
|
* Most rows one pass holds in its `deferred` set — the rows its cursor moved past without clearing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduled-jobs.d.ts","sourceRoot":"","sources":["../../src/constants/scheduled-jobs.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"scheduled-jobs.d.ts","sourceRoot":"","sources":["../../src/constants/scheduled-jobs.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,oIAMpB,CAAC;AACX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,uEAAuE;AACvE,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,QAAiB,CAAC;AAE3D,iFAAiF;AACjF,eAAO,MAAM,oCAAoC,iBAAiB,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,yBAAyB,QAAsB,CAAC"}
|
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
* The `sweepState/{sweepName}` document ids: one per scheduled pass that keeps a rolling cursor
|
|
4
4
|
* (`SweepStateSchema`), so each pass owns exactly one document and its cursor is never shared.
|
|
5
5
|
*/
|
|
6
|
-
export const SWEEP_STATE_NAMES = [
|
|
6
|
+
export const SWEEP_STATE_NAMES = [
|
|
7
|
+
'reconcilePublicUsers',
|
|
8
|
+
'orphanRegistrationCleanup',
|
|
9
|
+
'reconcileAccountStatus',
|
|
10
|
+
'pictureRetirement',
|
|
11
|
+
'stalePendingMedia',
|
|
12
|
+
];
|
|
7
13
|
/**
|
|
8
14
|
* Most rows one pass holds in its `deferred` set — the rows its cursor moved past without clearing.
|
|
9
15
|
* A row a pass cannot clear is rare, so a full set means something systemic is failing: the signal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduled-jobs.js","sourceRoot":"","sources":["../../src/constants/scheduled-jobs.ts"],"names":[],"mappings":"AAAA,mDAAmD;AAEnD;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,
|
|
1
|
+
{"version":3,"file":"scheduled-jobs.js","sourceRoot":"","sources":["../../src/constants/scheduled-jobs.ts"],"names":[],"mappings":"AAAA,mDAAmD;AAEnD;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,sBAAsB;IACtB,2BAA2B;IAC3B,wBAAwB;IACxB,mBAAmB;IACnB,mBAAmB;CACX,CAAC;AAGX;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAE3C,uEAAuE;AACvE,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE3D,iFAAiF;AACjF,MAAM,CAAC,MAAM,oCAAoC,GAAG,cAAc,CAAC;AAEnE;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC","sourcesContent":["// Scheduled passes that keep a persisted position.\n\n/**\n * The `sweepState/{sweepName}` document ids: one per scheduled pass that keeps a rolling cursor\n * (`SweepStateSchema`), so each pass owns exactly one document and its cursor is never shared.\n */\nexport const SWEEP_STATE_NAMES = [\n 'reconcilePublicUsers',\n 'orphanRegistrationCleanup',\n 'reconcileAccountStatus',\n 'pictureRetirement',\n 'stalePendingMedia',\n] as const;\nexport type SweepStateName = (typeof SWEEP_STATE_NAMES)[number];\n\n/**\n * Most rows one pass holds in its `deferred` set — the rows its cursor moved past without clearing.\n * A row a pass cannot clear is rare, so a full set means something systemic is failing: the signal\n * to stop and report, not to keep growing the list. It also keeps the document a few kilobytes.\n */\nexport const SWEEP_STATE_MAX_DEFERRED = 50;\n\n/** Profiles one `reconcilePublicUsers` pass reads after its cursor. */\nexport const RECONCILE_PUBLIC_USERS_PAGE_SIZE = 200;\n\n/**\n * How long a login may hold no profile after its registration started before the orphan-login\n * cleanup deletes it. A taken name is refused before the login is created, so a registration that\n * does not finish within this window was abandoned.\n */\nexport const ORPHAN_REGISTRATION_GRACE_MS = 30 * 60 * 1000;\n\n/** How often the orphan-login cleanup runs (cron, in the leagues' time zone). */\nexport const ORPHAN_REGISTRATION_CLEANUP_SCHEDULE = '*/15 * * * *';\n\n/**\n * How long a registration-start record lives before its native-TTL policy removes it. Far longer than\n * the grace window, so every abandoned registration is still on the cleanup's work list when it is due.\n */\nexport const REGISTRATION_START_TTL_MS = 24 * 60 * 60 * 1000;\n"]}
|
|
@@ -120,6 +120,8 @@ export declare const COLLECTION_SCHEMAS: {
|
|
|
120
120
|
featuredPictureId: z.ZodOptional<z.ZodString>;
|
|
121
121
|
updatedAt: z.ZodNumber;
|
|
122
122
|
}, z.core.$strip>>;
|
|
123
|
+
teamRevision: z.ZodOptional<z.ZodNumber>;
|
|
124
|
+
gameRevision: z.ZodOptional<z.ZodNumber>;
|
|
123
125
|
createdAt: z.ZodNumber;
|
|
124
126
|
updatedAt: z.ZodNumber;
|
|
125
127
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/registry.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA4C7B,eAAO,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/registry.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA4C7B,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDkB,CAAC;AAElD,MAAM,MAAM,wBAAwB,GAAG,MAAM,OAAO,kBAAkB,CAAC;AAIvE,eAAO,MAAM,wBAAwB;;;;;;;;;;;CAWiC,CAAC;AAGvE,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAO,CAAC"}
|
|
@@ -51,6 +51,8 @@ export declare const SportLeagueSchema: z.ZodObject<{
|
|
|
51
51
|
featuredPictureId: z.ZodOptional<z.ZodString>;
|
|
52
52
|
updatedAt: z.ZodNumber;
|
|
53
53
|
}, z.core.$strip>>;
|
|
54
|
+
teamRevision: z.ZodOptional<z.ZodNumber>;
|
|
55
|
+
gameRevision: z.ZodOptional<z.ZodNumber>;
|
|
54
56
|
createdAt: z.ZodNumber;
|
|
55
57
|
updatedAt: z.ZodNumber;
|
|
56
58
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sport-league.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/sport-league.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,iCAAiC,4CAA4C,CAAC;AAC3F,eAAO,MAAM,mCAAmC,2FAC0C,CAAC;AAE3F;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC,GAAG,OAAO,CAEV;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,SAAS;IACR,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC,EACD,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAOhD;AAGD,eAAO,MAAM,wBAAwB,aAAc,CAAC;AAEpD,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"sport-league.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/sport-league.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,iCAAiC,4CAA4C,CAAC;AAC3F,eAAO,MAAM,mCAAmC,2FAC0C,CAAC;AAE3F;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC,GAAG,OAAO,CAEV;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,SAAS;IACR,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC,EACD,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAOhD;AAGD,eAAO,MAAM,wBAAwB,aAAc,CAAC;AAEpD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgCM,CAAC;AACrC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
|
@@ -50,6 +50,15 @@ export const SportLeagueSchema = z
|
|
|
50
50
|
// The league's picture gallery summary — absent is an empty gallery. Only the picture core
|
|
51
51
|
// writes it; the league callables and the copy action never do.
|
|
52
52
|
pictures: GallerySummarySchema.optional(),
|
|
53
|
+
// Advanced by every team created in the league; absent until the first. Only its changing
|
|
54
|
+
// matters: team creation counts the league's teams in its transaction against
|
|
55
|
+
// MAX_TEAMS_PER_LEAGUE, and a query does not lock against an insert — so each creation writes this
|
|
56
|
+
// document, and two creations at the cap conflict instead of both passing (BACKEND-116).
|
|
57
|
+
teamRevision: countSchema.optional(),
|
|
58
|
+
// Advanced by every game created in the league, a schedule week's included; absent until the
|
|
59
|
+
// first. Only its changing matters, the same way: game creation counts the league's games in its
|
|
60
|
+
// transaction against MAX_GAMES_PER_LEAGUE.
|
|
61
|
+
gameRevision: countSchema.optional(),
|
|
53
62
|
createdAt: epochMsSchema,
|
|
54
63
|
updatedAt: epochMsSchema,
|
|
55
64
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sport-league.js","sourceRoot":"","sources":["../../src/doc-schemas/sport-league.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,iGAAiG;AACjG,gGAAgG;AAChG,0BAA0B;AAE1B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,CAAC,MAAM,iCAAiC,GAAG,yCAAyC,CAAC;AAC3F,MAAM,CAAC,MAAM,mCAAmC,GAC9C,wFAAwF,CAAC;AAE3F;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAG9C;IACC,OAAO,MAAM,CAAC,cAAc,KAAK,CAAC,MAAM,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAOlC,MAAS,EAAE,GAA6B;IACxC,IAAI,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;QAClD,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC,CAAC;IACxG,CAAC;IACD,IAAI,CAAC,8BAA8B,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,kBAAkB,CAAC,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,CAAC;IAC7G,CAAC;AACH,CAAC;AAED,wGAAwG;AACxG,MAAM,CAAC,MAAM,wBAAwB,GAAG,WAAW,CAAC;AAEpD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,MAAM,CAAC;IACN,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,UAAU,EAAE,gBAAgB;IAC5B,UAAU,EAAE,gBAAgB;IAC5B,eAAe,EAAE,kBAAkB;IACnC,aAAa,EAAE,kBAAkB;IACjC,MAAM,EAAE,kBAAkB;IAC1B,8FAA8F;IAC9F,gGAAgG;IAChG,qCAAqC;IACrC,aAAa,EAAE,wBAAwB;IACvC,iBAAiB,EAAE,wBAAwB;IAC3C,gBAAgB,EAAE,wBAAwB;IAC1C,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;IAC3B,gBAAgB,EAAE,sBAAsB,CAAC,QAAQ,EAAE;IACnD,2FAA2F;IAC3F,gEAAgE;IAChE,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACzC,SAAS,EAAE,aAAa;IACxB,SAAS,EAAE,aAAa;CACzB,CAAC;KACD,WAAW,CAAC,oBAAoB,CAAC,CAAC","sourcesContent":["// `sportLeagues/{leagueId}` — one league: its sport, mode, dates, status, playoff cutoffs, and waiver\n// requirement. The admin league callables write its settings, status, and mode; the picture core\n// writes `pictures`. Teams, games, and player stats live in their own collections and are never\n// copied onto the league.\n\nimport { z } from 'zod';\nimport {\n calendarDateSchema,\n countSchema,\n epochMsSchema,\n leagueModeSchema,\n leagueStatusSchema,\n leagueTypeSchema,\n} from './atoms.js';\nimport { GallerySummarySchema } from './gallery.js';\nimport { waiverTemplateIdSchema } from './waiver-template.js';\n\nexport const LEAGUE_DATES_OUT_OF_ORDER_MESSAGE = 'The league cannot end before it starts.';\nexport const WAIVER_REQUIREMENT_MISMATCH_MESSAGE =\n 'Choose a waiver template when the league requires a waiver, and none when it does not.';\n\n/**\n * A league names a waiver template exactly when it requires a waiver, so no reader needs a\n * sentinel for \"no waiver\" and no stale template id survives turning the requirement off.\n */\nexport function hasConsistentWaiverRequirement(league: {\n requiresWaiver: boolean;\n waiverTemplateId?: string | undefined;\n}): boolean {\n return league.requiresWaiver === (league.waiverTemplateId !== undefined);\n}\n\n/**\n * The cross-field rules every league settings shape obeys — the stored document and both callable\n * inputs — so the rule a form shows, the callable enforces, and the copy action validates is one\n * rule.\n */\nexport function refineLeagueSettings<\n T extends {\n leagueStartDate: string;\n leagueEndDate: string;\n requiresWaiver: boolean;\n waiverTemplateId?: string | undefined;\n },\n>(league: T, ctx: z.core.$RefinementCtx<T>): void {\n if (league.leagueEndDate < league.leagueStartDate) {\n ctx.addIssue({ code: 'custom', path: ['leagueEndDate'], message: LEAGUE_DATES_OUT_OF_ORDER_MESSAGE });\n }\n if (!hasConsistentWaiverRequirement(league)) {\n ctx.addIssue({ code: 'custom', path: ['waiverTemplateId'], message: WAIVER_REQUIREMENT_MISMATCH_MESSAGE });\n }\n}\n\n// How many teams reach the playoffs is a count; the callable inputs bound it with `MAX_PLAYOFF_CUTOFF`.\nexport const playoffCutoffCountSchema = countSchema;\n\nexport const SportLeagueSchema = z\n .object({\n leagueTitle: z.string(),\n description: z.string(),\n leagueType: leagueTypeSchema,\n leagueMode: leagueModeSchema,\n leagueStartDate: calendarDateSchema,\n leagueEndDate: calendarDateSchema,\n status: leagueStatusSchema,\n // How many teams reach the playoffs: `playoffCutoff` in a Regular league, the Competitive and\n // Recreational pools' own cutoffs in a Competitive/Recreational one. All three are kept in both\n // modes so a mode switch loses none.\n playoffCutoff: playoffCutoffCountSchema,\n playoffCutoffComp: playoffCutoffCountSchema,\n playoffCutoffRec: playoffCutoffCountSchema,\n requiresWaiver: z.boolean(),\n waiverTemplateId: waiverTemplateIdSchema.optional(),\n // The league's picture gallery summary — absent is an empty gallery. Only the picture core\n // writes it; the league callables and the copy action never do.\n pictures: GallerySummarySchema.optional(),\n createdAt: epochMsSchema,\n updatedAt: epochMsSchema,\n })\n .superRefine(refineLeagueSettings);\nexport type SportLeague = z.infer<typeof SportLeagueSchema>;\n"]}
|
|
1
|
+
{"version":3,"file":"sport-league.js","sourceRoot":"","sources":["../../src/doc-schemas/sport-league.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,iGAAiG;AACjG,gGAAgG;AAChG,0BAA0B;AAE1B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,CAAC,MAAM,iCAAiC,GAAG,yCAAyC,CAAC;AAC3F,MAAM,CAAC,MAAM,mCAAmC,GAC9C,wFAAwF,CAAC;AAE3F;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAG9C;IACC,OAAO,MAAM,CAAC,cAAc,KAAK,CAAC,MAAM,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAOlC,MAAS,EAAE,GAA6B;IACxC,IAAI,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;QAClD,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC,CAAC;IACxG,CAAC;IACD,IAAI,CAAC,8BAA8B,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,kBAAkB,CAAC,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,CAAC;IAC7G,CAAC;AACH,CAAC;AAED,wGAAwG;AACxG,MAAM,CAAC,MAAM,wBAAwB,GAAG,WAAW,CAAC;AAEpD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,MAAM,CAAC;IACN,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,UAAU,EAAE,gBAAgB;IAC5B,UAAU,EAAE,gBAAgB;IAC5B,eAAe,EAAE,kBAAkB;IACnC,aAAa,EAAE,kBAAkB;IACjC,MAAM,EAAE,kBAAkB;IAC1B,8FAA8F;IAC9F,gGAAgG;IAChG,qCAAqC;IACrC,aAAa,EAAE,wBAAwB;IACvC,iBAAiB,EAAE,wBAAwB;IAC3C,gBAAgB,EAAE,wBAAwB;IAC1C,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;IAC3B,gBAAgB,EAAE,sBAAsB,CAAC,QAAQ,EAAE;IACnD,2FAA2F;IAC3F,gEAAgE;IAChE,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACzC,0FAA0F;IAC1F,8EAA8E;IAC9E,mGAAmG;IACnG,yFAAyF;IACzF,YAAY,EAAE,WAAW,CAAC,QAAQ,EAAE;IACpC,6FAA6F;IAC7F,iGAAiG;IACjG,4CAA4C;IAC5C,YAAY,EAAE,WAAW,CAAC,QAAQ,EAAE;IACpC,SAAS,EAAE,aAAa;IACxB,SAAS,EAAE,aAAa;CACzB,CAAC;KACD,WAAW,CAAC,oBAAoB,CAAC,CAAC","sourcesContent":["// `sportLeagues/{leagueId}` — one league: its sport, mode, dates, status, playoff cutoffs, and waiver\n// requirement. The admin league callables write its settings, status, and mode; the picture core\n// writes `pictures`. Teams, games, and player stats live in their own collections and are never\n// copied onto the league.\n\nimport { z } from 'zod';\nimport {\n calendarDateSchema,\n countSchema,\n epochMsSchema,\n leagueModeSchema,\n leagueStatusSchema,\n leagueTypeSchema,\n} from './atoms.js';\nimport { GallerySummarySchema } from './gallery.js';\nimport { waiverTemplateIdSchema } from './waiver-template.js';\n\nexport const LEAGUE_DATES_OUT_OF_ORDER_MESSAGE = 'The league cannot end before it starts.';\nexport const WAIVER_REQUIREMENT_MISMATCH_MESSAGE =\n 'Choose a waiver template when the league requires a waiver, and none when it does not.';\n\n/**\n * A league names a waiver template exactly when it requires a waiver, so no reader needs a\n * sentinel for \"no waiver\" and no stale template id survives turning the requirement off.\n */\nexport function hasConsistentWaiverRequirement(league: {\n requiresWaiver: boolean;\n waiverTemplateId?: string | undefined;\n}): boolean {\n return league.requiresWaiver === (league.waiverTemplateId !== undefined);\n}\n\n/**\n * The cross-field rules every league settings shape obeys — the stored document and both callable\n * inputs — so the rule a form shows, the callable enforces, and the copy action validates is one\n * rule.\n */\nexport function refineLeagueSettings<\n T extends {\n leagueStartDate: string;\n leagueEndDate: string;\n requiresWaiver: boolean;\n waiverTemplateId?: string | undefined;\n },\n>(league: T, ctx: z.core.$RefinementCtx<T>): void {\n if (league.leagueEndDate < league.leagueStartDate) {\n ctx.addIssue({ code: 'custom', path: ['leagueEndDate'], message: LEAGUE_DATES_OUT_OF_ORDER_MESSAGE });\n }\n if (!hasConsistentWaiverRequirement(league)) {\n ctx.addIssue({ code: 'custom', path: ['waiverTemplateId'], message: WAIVER_REQUIREMENT_MISMATCH_MESSAGE });\n }\n}\n\n// How many teams reach the playoffs is a count; the callable inputs bound it with `MAX_PLAYOFF_CUTOFF`.\nexport const playoffCutoffCountSchema = countSchema;\n\nexport const SportLeagueSchema = z\n .object({\n leagueTitle: z.string(),\n description: z.string(),\n leagueType: leagueTypeSchema,\n leagueMode: leagueModeSchema,\n leagueStartDate: calendarDateSchema,\n leagueEndDate: calendarDateSchema,\n status: leagueStatusSchema,\n // How many teams reach the playoffs: `playoffCutoff` in a Regular league, the Competitive and\n // Recreational pools' own cutoffs in a Competitive/Recreational one. All three are kept in both\n // modes so a mode switch loses none.\n playoffCutoff: playoffCutoffCountSchema,\n playoffCutoffComp: playoffCutoffCountSchema,\n playoffCutoffRec: playoffCutoffCountSchema,\n requiresWaiver: z.boolean(),\n waiverTemplateId: waiverTemplateIdSchema.optional(),\n // The league's picture gallery summary — absent is an empty gallery. Only the picture core\n // writes it; the league callables and the copy action never do.\n pictures: GallerySummarySchema.optional(),\n // Advanced by every team created in the league; absent until the first. Only its changing\n // matters: team creation counts the league's teams in its transaction against\n // MAX_TEAMS_PER_LEAGUE, and a query does not lock against an insert — so each creation writes this\n // document, and two creations at the cap conflict instead of both passing (BACKEND-116).\n teamRevision: countSchema.optional(),\n // Advanced by every game created in the league, a schedule week's included; absent until the\n // first. Only its changing matters, the same way: game creation counts the league's games in its\n // transaction against MAX_GAMES_PER_LEAGUE.\n gameRevision: countSchema.optional(),\n createdAt: epochMsSchema,\n updatedAt: epochMsSchema,\n })\n .superRefine(refineLeagueSettings);\nexport type SportLeague = z.infer<typeof SportLeagueSchema>;\n"]}
|