@ttt-productions/ttt-core 0.79.84 → 0.79.85
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/retention.d.ts +6 -0
- package/dist/constants/retention.d.ts.map +1 -1
- package/dist/constants/retention.js +6 -0
- package/dist/constants/retention.js.map +1 -1
- package/dist/doc-schemas/notification-archive-all-jobs.d.ts +1 -0
- package/dist/doc-schemas/notification-archive-all-jobs.d.ts.map +1 -1
- package/dist/doc-schemas/notification-archive-all-jobs.js +6 -0
- package/dist/doc-schemas/notification-archive-all-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/user.d.ts +1 -0
- package/dist/doc-schemas/user.d.ts.map +1 -1
- package/dist/doc-schemas/user.js +5 -0
- package/dist/doc-schemas/user.js.map +1 -1
- package/package.json +5 -5
|
@@ -17,6 +17,12 @@ export declare const ORPHAN_UPLOAD_TTL_HOURS = 24;
|
|
|
17
17
|
export declare const ORPHAN_UPLOAD_DELETE_CAP = 500;
|
|
18
18
|
/** Page size for listing orphan uploads. */
|
|
19
19
|
export declare const ORPHAN_UPLOAD_LIST_PAGE_SIZE = 1000;
|
|
20
|
+
/**
|
|
21
|
+
* Per-run cap on staging objects examined. Kept objects (young, active, archived, held) cost nothing
|
|
22
|
+
* against the delete cap, so this is what bounds a pass over a long kept stretch; two listing pages
|
|
23
|
+
* keep a pass well inside the sweep's function timeout, and the next run resumes after the last one.
|
|
24
|
+
*/
|
|
25
|
+
export declare const ORPHAN_UPLOAD_EXAMINED_CAP: number;
|
|
20
26
|
/** Maximum lookback window for the in-flight upload listener (24 hours). */
|
|
21
27
|
export declare const LISTENER_WINDOW_MS: number;
|
|
22
28
|
/** Stale time for the publicUsers query cache (30 minutes). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retention.d.ts","sourceRoot":"","sources":["../../src/constants/retention.ts"],"names":[],"mappings":"AAIA,gEAAgE;AAChE,eAAO,MAAM,sBAAsB,QAAiB,CAAC;AAIrD,oFAAoF;AACpF,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAElD,oFAAoF;AACpF,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAWpD;yFACyF;AACzF,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAIhD,wFAAwF;AACxF,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,+EAA+E;AAC/E,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAElF;AAID,uFAAuF;AACvF,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,+CAA+C;AAC/C,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,4CAA4C;AAC5C,eAAO,MAAM,4BAA4B,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"retention.d.ts","sourceRoot":"","sources":["../../src/constants/retention.ts"],"names":[],"mappings":"AAIA,gEAAgE;AAChE,eAAO,MAAM,sBAAsB,QAAiB,CAAC;AAIrD,oFAAoF;AACpF,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAElD,oFAAoF;AACpF,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAWpD;yFACyF;AACzF,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAIhD,wFAAwF;AACxF,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,+EAA+E;AAC/E,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAElF;AAID,uFAAuF;AACvF,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,+CAA+C;AAC/C,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,4CAA4C;AAC5C,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,QAAmC,CAAC;AAI3E,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,QAAsB,CAAC;AAItD,+DAA+D;AAC/D,eAAO,MAAM,0BAA0B,QAAiB,CAAC;AAEzD,wDAAwD;AACxD,eAAO,MAAM,uBAAuB,QAAiB,CAAC;AAItD;qFACqF;AACrF,eAAO,MAAM,kCAAkC,QAAY,CAAC"}
|
|
@@ -34,6 +34,12 @@ export const ORPHAN_UPLOAD_TTL_HOURS = 24;
|
|
|
34
34
|
export const ORPHAN_UPLOAD_DELETE_CAP = 500;
|
|
35
35
|
/** Page size for listing orphan uploads. */
|
|
36
36
|
export const ORPHAN_UPLOAD_LIST_PAGE_SIZE = 1000;
|
|
37
|
+
/**
|
|
38
|
+
* Per-run cap on staging objects examined. Kept objects (young, active, archived, held) cost nothing
|
|
39
|
+
* against the delete cap, so this is what bounds a pass over a long kept stretch; two listing pages
|
|
40
|
+
* keep a pass well inside the sweep's function timeout, and the next run resumes after the last one.
|
|
41
|
+
*/
|
|
42
|
+
export const ORPHAN_UPLOAD_EXAMINED_CAP = 2 * ORPHAN_UPLOAD_LIST_PAGE_SIZE;
|
|
37
43
|
// --- Frontend in-flight upload listeners ---
|
|
38
44
|
/** Maximum lookback window for the in-flight upload listener (24 hours). */
|
|
39
45
|
export const LISTENER_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/constants/retention.ts"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,oCAAoC;AAEpC,gEAAgE;AAChE,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC;AAErD,gCAAgC;AAEhC,oFAAoF;AACpF,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC;AAElD,oFAAoF;AACpF,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AAEpD,4DAA4D;AAC5D,4FAA4F;AAC5F,8FAA8F;AAC9F,0FAA0F;AAC1F,+FAA+F;AAC/F,iGAAiG;AACjG,+FAA+F;AAC/F,0BAA0B;AAE1B;yFACyF;AACzF,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,CAAC;AAEhD,MAAM,2BAA2B,GAAG,6BAA6B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAExF,wFAAwF;AACxF,MAAM,UAAU,2BAA2B,CAAC,UAAkB;IAC5D,OAAO,UAAU,GAAG,2BAA2B,CAAC;AAClD,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,yBAAyB,CAAC,UAAkB,EAAE,GAAW;IACvE,OAAO,GAAG,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC;AACvD,CAAC;AAED,gCAAgC;AAEhC,uFAAuF;AACvF,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C,+CAA+C;AAC/C,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAE5C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAEjD,8CAA8C;AAE9C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEtD,yCAAyC;AAEzC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEzD,wDAAwD;AACxD,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEtD,8CAA8C;AAE9C;qFACqF;AACrF,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,GAAG,IAAI,CAAC","sourcesContent":["// Caching, retention, and cleanup TTLs / batch sizes.\n\n// --- Profanity word list cache ---\n\n/** TTL for the in-memory profanity word list cache (1 hour). */\nexport const WORD_LIST_CACHE_TTL_MS = 1000 * 60 * 60;\n\n// --- Pending media archive ---\n\n/** Days after which a terminal pendingMedia doc is moved to pendingMediaArchive. */\nexport const PENDING_MEDIA_ARCHIVE_AFTER_DAYS = 7;\n\n/** Per-run cap on docs archived by the archivePendingMedia scheduled commission. */\nexport const PENDING_MEDIA_ARCHIVE_BATCH_SIZE = 500;\n\n// --- Rejected (moderation-quarantined) media retention ---\n// Bytes a moderation decision rejected are kept at `rejected/{userId}/…` as APPEAL EVIDENCE\n// (the violation's `rejectedFilePath`; owner + admin readable, never served through the media\n// gateway). They are not kept forever: after this window the hold-aware fail-closed sweep\n// deletes them. Fail-closed means a file it cannot prove is out of window — or that carries an\n// active Trust & Safety / legal hold, or a pending appeal — is LEFT IN PLACE, never deleted on a\n// best guess. The appeal window is this same window, so an appeal can only ever be filed while\n// its file is still kept.\n\n/** Days a moderation-rejected upload's quarantined bytes are retained before the\n * hold-aware sweep deletes them — and the days a member has to appeal the rejection. */\nexport const REJECTED_MEDIA_RETENTION_DAYS = 90;\n\nconst REJECTED_MEDIA_RETENTION_MS = REJECTED_MEDIA_RETENTION_DAYS * 24 * 60 * 60 * 1000;\n\n/** The epoch-ms moment the appeal window of a rejection made at `rejectedAt` closes. */\nexport function rejectedMediaAppealDeadline(rejectedAt: number): number {\n return rejectedAt + REJECTED_MEDIA_RETENTION_MS;\n}\n\n/** Whether a rejection made at `rejectedAt` can still be appealed at `now`. */\nexport function isRejectedMediaAppealOpen(rejectedAt: number, now: number): boolean {\n return now < rejectedMediaAppealDeadline(rejectedAt);\n}\n\n// --- Orphan upload cleanup ---\n\n/** TTL in hours after which an orphan storage upload becomes eligible for deletion. */\nexport const ORPHAN_UPLOAD_TTL_HOURS = 24;\n\n/** Per-run cap on orphan storage deletions. */\nexport const ORPHAN_UPLOAD_DELETE_CAP = 500;\n\n/** Page size for listing orphan uploads. */\nexport const ORPHAN_UPLOAD_LIST_PAGE_SIZE = 1000;\n\n// --- Frontend in-flight upload listeners ---\n\n/** Maximum lookback window for the in-flight upload listener (24 hours). */\nexport const LISTENER_WINDOW_MS = 24 * 60 * 60 * 1000;\n\n// --- Public users React Query cache ---\n\n/** Stale time for the publicUsers query cache (30 minutes). */\nexport const PUBLIC_USERS_STALE_TIME_MS = 30 * 60 * 1000;\n\n/** GC time for the publicUsers query cache (1 hour). */\nexport const PUBLIC_USERS_GC_TIME_MS = 60 * 60 * 1000;\n\n// --- Public-entity lookup negative cache ---\n\n/** Stale time for an ABSENT public-lookup document (20 seconds) — short, so a\n * just-created or just-published entity stops reading as missing almost at once. */\nexport const PUBLIC_LOOKUP_ABSENT_STALE_TIME_MS = 20 * 1000;\n"]}
|
|
1
|
+
{"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/constants/retention.ts"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,oCAAoC;AAEpC,gEAAgE;AAChE,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC;AAErD,gCAAgC;AAEhC,oFAAoF;AACpF,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC;AAElD,oFAAoF;AACpF,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AAEpD,4DAA4D;AAC5D,4FAA4F;AAC5F,8FAA8F;AAC9F,0FAA0F;AAC1F,+FAA+F;AAC/F,iGAAiG;AACjG,+FAA+F;AAC/F,0BAA0B;AAE1B;yFACyF;AACzF,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,CAAC;AAEhD,MAAM,2BAA2B,GAAG,6BAA6B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAExF,wFAAwF;AACxF,MAAM,UAAU,2BAA2B,CAAC,UAAkB;IAC5D,OAAO,UAAU,GAAG,2BAA2B,CAAC;AAClD,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,yBAAyB,CAAC,UAAkB,EAAE,GAAW;IACvE,OAAO,GAAG,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC;AACvD,CAAC;AAED,gCAAgC;AAEhC,uFAAuF;AACvF,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C,+CAA+C;AAC/C,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAE5C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,GAAG,4BAA4B,CAAC;AAE3E,8CAA8C;AAE9C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEtD,yCAAyC;AAEzC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEzD,wDAAwD;AACxD,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEtD,8CAA8C;AAE9C;qFACqF;AACrF,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,GAAG,IAAI,CAAC","sourcesContent":["// Caching, retention, and cleanup TTLs / batch sizes.\n\n// --- Profanity word list cache ---\n\n/** TTL for the in-memory profanity word list cache (1 hour). */\nexport const WORD_LIST_CACHE_TTL_MS = 1000 * 60 * 60;\n\n// --- Pending media archive ---\n\n/** Days after which a terminal pendingMedia doc is moved to pendingMediaArchive. */\nexport const PENDING_MEDIA_ARCHIVE_AFTER_DAYS = 7;\n\n/** Per-run cap on docs archived by the archivePendingMedia scheduled commission. */\nexport const PENDING_MEDIA_ARCHIVE_BATCH_SIZE = 500;\n\n// --- Rejected (moderation-quarantined) media retention ---\n// Bytes a moderation decision rejected are kept at `rejected/{userId}/…` as APPEAL EVIDENCE\n// (the violation's `rejectedFilePath`; owner + admin readable, never served through the media\n// gateway). They are not kept forever: after this window the hold-aware fail-closed sweep\n// deletes them. Fail-closed means a file it cannot prove is out of window — or that carries an\n// active Trust & Safety / legal hold, or a pending appeal — is LEFT IN PLACE, never deleted on a\n// best guess. The appeal window is this same window, so an appeal can only ever be filed while\n// its file is still kept.\n\n/** Days a moderation-rejected upload's quarantined bytes are retained before the\n * hold-aware sweep deletes them — and the days a member has to appeal the rejection. */\nexport const REJECTED_MEDIA_RETENTION_DAYS = 90;\n\nconst REJECTED_MEDIA_RETENTION_MS = REJECTED_MEDIA_RETENTION_DAYS * 24 * 60 * 60 * 1000;\n\n/** The epoch-ms moment the appeal window of a rejection made at `rejectedAt` closes. */\nexport function rejectedMediaAppealDeadline(rejectedAt: number): number {\n return rejectedAt + REJECTED_MEDIA_RETENTION_MS;\n}\n\n/** Whether a rejection made at `rejectedAt` can still be appealed at `now`. */\nexport function isRejectedMediaAppealOpen(rejectedAt: number, now: number): boolean {\n return now < rejectedMediaAppealDeadline(rejectedAt);\n}\n\n// --- Orphan upload cleanup ---\n\n/** TTL in hours after which an orphan storage upload becomes eligible for deletion. */\nexport const ORPHAN_UPLOAD_TTL_HOURS = 24;\n\n/** Per-run cap on orphan storage deletions. */\nexport const ORPHAN_UPLOAD_DELETE_CAP = 500;\n\n/** Page size for listing orphan uploads. */\nexport const ORPHAN_UPLOAD_LIST_PAGE_SIZE = 1000;\n\n/**\n * Per-run cap on staging objects examined. Kept objects (young, active, archived, held) cost nothing\n * against the delete cap, so this is what bounds a pass over a long kept stretch; two listing pages\n * keep a pass well inside the sweep's function timeout, and the next run resumes after the last one.\n */\nexport const ORPHAN_UPLOAD_EXAMINED_CAP = 2 * ORPHAN_UPLOAD_LIST_PAGE_SIZE;\n\n// --- Frontend in-flight upload listeners ---\n\n/** Maximum lookback window for the in-flight upload listener (24 hours). */\nexport const LISTENER_WINDOW_MS = 24 * 60 * 60 * 1000;\n\n// --- Public users React Query cache ---\n\n/** Stale time for the publicUsers query cache (30 minutes). */\nexport const PUBLIC_USERS_STALE_TIME_MS = 30 * 60 * 1000;\n\n/** GC time for the publicUsers query cache (1 hour). */\nexport const PUBLIC_USERS_GC_TIME_MS = 60 * 60 * 1000;\n\n// --- Public-entity lookup negative cache ---\n\n/** Stale time for an ABSENT public-lookup document (20 seconds) — short, so a\n * just-created or just-published entity stops reading as missing almost at once. */\nexport const PUBLIC_LOOKUP_ABSENT_STALE_TIME_MS = 20 * 1000;\n"]}
|
|
@@ -37,6 +37,7 @@ export declare const NotificationArchiveAllJobSchema: z.ZodObject<{
|
|
|
37
37
|
}>;
|
|
38
38
|
revision: z.ZodNumber;
|
|
39
39
|
archived: z.ZodNumber;
|
|
40
|
+
notArchived: z.ZodOptional<z.ZodNumber>;
|
|
40
41
|
error: z.ZodNullable<z.ZodString>;
|
|
41
42
|
attemptCount: z.ZodNumber;
|
|
42
43
|
nextAttemptAt: z.ZodNumber;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification-archive-all-jobs.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/notification-archive-all-jobs.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC;;;;;EAA8D,CAAC;AAChH,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAElG;;;GAGG;AACH,eAAO,MAAM,+BAA+B
|
|
1
|
+
{"version":3,"file":"notification-archive-all-jobs.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/notification-archive-all-jobs.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC;;;;;EAA8D,CAAC;AAChH,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAElG;;;GAGG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6C5B,CAAC;AAEjB,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC"}
|
|
@@ -46,6 +46,12 @@ export const NotificationArchiveAllJobSchema = z
|
|
|
46
46
|
revision: z.number().int().nonnegative(),
|
|
47
47
|
/** Monotonic count of cards archived so far. */
|
|
48
48
|
archived: z.number().int().nonnegative(),
|
|
49
|
+
/**
|
|
50
|
+
* Cards the completing drain could not archive — each failed on its own and is still in the list.
|
|
51
|
+
* Set (never summed) when the job completes, because that drain walked the whole active set once.
|
|
52
|
+
* Absent until a job completes with cards left behind (read as 0).
|
|
53
|
+
*/
|
|
54
|
+
notArchived: z.number().int().nonnegative().optional(),
|
|
49
55
|
/** Human-readable failure reason (only on `failed`). */
|
|
50
56
|
error: z.string().nullable(),
|
|
51
57
|
// ── retry / dead-letter bookkeeping (mirrors the fanout ledger) ──
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification-archive-all-jobs.js","sourceRoot":"","sources":["../../src/doc-schemas/notification-archive-all-jobs.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,EAAE;AACF,kFAAkF;AAClF,8EAA8E;AAC9E,gFAAgF;AAChF,iFAAiF;AACjF,qFAAqF;AACrF,sFAAsF;AACtF,oFAAoF;AACpF,2EAA2E;AAC3E,EAAE;AACF,sEAAsE;AAEtE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGhH;;;GAGG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC;KAC7C,MAAM,CAAC;IACN,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,sEAAsE;IACtE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,+FAA+F;IAC/F,QAAQ,EAAE,0BAA0B;IACpC;;;;;OAKG;IACH,eAAe,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACvD,KAAK,EAAE,oCAAoC;IAC3C,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACxC,gDAAgD;IAChD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACxC,wDAAwD;IACxD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,oEAAoE;IACpE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,wFAAwF;IACxF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC7C,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE;IACzB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACxC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC3C;;;;;OAKG;IACH,QAAQ,EAAE,wBAAwB,CAAC,QAAQ,EAAE;CAC9C,CAAC;KACD,WAAW,EAAE,CAAC","sourcesContent":["// Server-owned \"archive all\" job docs — `notificationArchiveAllJobs/{jobId}`.\n//\n// BACKEND-ONLY: Firestore rules deny all client access; the client learns a job's\n// state only through the `getArchiveAllStatus` callable, which reads this doc\n// server-side and returns the `ArchiveAllJobSnapshot` shape. A job replaces the\n// browser clear-all loop: `enqueueArchiveAll` `.create()`s ONE deterministic row\n// (idempotent per user+category+requestId), the bounded scheduled worker drains that\n// ONE category's active cards (PER-TAB SCOPING — never all tabs) reusing the per-card\n// archive helper, and advances `archived` + the terminal `state`. Dead-letter/retry\n// bookkeeping mirrors the fanout ledger; an unresolved job is never TTL'd.\n//\n// See ttt-prod docs/design/notification-system.md (Archive contract).\n\nimport { z } from 'zod';\nimport { NotificationCategorySchema } from '../schemas/notification.js';\nimport { systemRoleSchema } from '../schemas/atoms.js';\nimport { FirestoreTimestampSchema } from './firestore-primitives.js';\n\n/**\n * Job lifecycle state — mirrors `ArchiveAllJobSnapshot['state']` (the poller's union; the\n * callable maps this doc field straight through). `in-progress` is the drain-in-flight\n * state; the three terminals are `complete` (category fully drained), `incomplete`\n * (attempt budget exhausted with cards still active — retry/dead-letter), and `failed`\n * (unexpected fault).\n */\nexport const NotificationArchiveAllJobStateSchema = z.enum(['in-progress', 'complete', 'incomplete', 'failed']);\nexport type NotificationArchiveAllJobState = z.infer<typeof NotificationArchiveAllJobStateSchema>;\n\n/**\n * Persisted archive-all job doc. `.passthrough()` so future additive fields don't fail\n * read-side validation (mirrors the fanout ledger schema).\n */\nexport const NotificationArchiveAllJobSchema = z\n .object({\n schemaVersion: z.literal(1),\n jobId: z.string().min(1),\n /** Owner uid — the ONLY user whose active cards this job archives. */\n userId: z.string().min(1),\n /** The tab/category this job is scoped to (PER-TAB SCOPING — the worker touches only this). */\n category: NotificationCategorySchema,\n /**\n * The enqueuing admin's resolved role, persisted ONLY for admin-category jobs so the\n * worker can reconstruct a faithful `adminReview` actor for each per-card\n * `notification.adminArchived` audit event (enqueue already admin-gated the create, so\n * the authority was verified). Null / absent for personal jobs.\n */\n actorSystemRole: systemRoleSchema.nullable().optional(),\n state: NotificationArchiveAllJobStateSchema,\n /** Monotonic claim revision preventing concurrent inline/scheduled drains. */\n revision: z.number().int().nonnegative(),\n /** Monotonic count of cards archived so far. */\n archived: z.number().int().nonnegative(),\n /** Human-readable failure reason (only on `failed`). */\n error: z.string().nullable(),\n // ── retry / dead-letter bookkeeping (mirrors the fanout ledger) ──\n attemptCount: z.number().int().nonnegative(),\n /** Due-worker predicate: the worker only picks up a job with `nextAttemptAt <= now`. */\n nextAttemptAt: z.number().int().nonnegative(),\n deadLettered: z.boolean(),\n createdAt: z.number().int().nonnegative(),\n updatedAt: z.number().int().nonnegative(),\n completedAt: z.number().int().nullable(),\n deadLetteredAt: z.number().int().nullable(),\n /**\n * Native-TTL reaper stamp (ARCH-105 exception): a real Firestore Timestamp, stamped ONLY\n * on the terminal `complete` branch (30d), so a completed job is reaped and the\n * collection can't grow one dead doc per \"Clear all\" click forever. An UNRESOLVED job\n * (in-progress / incomplete / dead-lettered) is NEVER TTL'd, so the field is absent there.\n */\n expireAt: FirestoreTimestampSchema.optional(),\n })\n .passthrough();\n\nexport type NotificationArchiveAllJob = z.infer<typeof NotificationArchiveAllJobSchema>;\n"]}
|
|
1
|
+
{"version":3,"file":"notification-archive-all-jobs.js","sourceRoot":"","sources":["../../src/doc-schemas/notification-archive-all-jobs.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,EAAE;AACF,kFAAkF;AAClF,8EAA8E;AAC9E,gFAAgF;AAChF,iFAAiF;AACjF,qFAAqF;AACrF,sFAAsF;AACtF,oFAAoF;AACpF,2EAA2E;AAC3E,EAAE;AACF,sEAAsE;AAEtE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGhH;;;GAGG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC;KAC7C,MAAM,CAAC;IACN,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,sEAAsE;IACtE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,+FAA+F;IAC/F,QAAQ,EAAE,0BAA0B;IACpC;;;;;OAKG;IACH,eAAe,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACvD,KAAK,EAAE,oCAAoC;IAC3C,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACxC,gDAAgD;IAChD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACxC;;;;OAIG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IACtD,wDAAwD;IACxD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,oEAAoE;IACpE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,wFAAwF;IACxF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC7C,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE;IACzB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACxC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC3C;;;;;OAKG;IACH,QAAQ,EAAE,wBAAwB,CAAC,QAAQ,EAAE;CAC9C,CAAC;KACD,WAAW,EAAE,CAAC","sourcesContent":["// Server-owned \"archive all\" job docs — `notificationArchiveAllJobs/{jobId}`.\n//\n// BACKEND-ONLY: Firestore rules deny all client access; the client learns a job's\n// state only through the `getArchiveAllStatus` callable, which reads this doc\n// server-side and returns the `ArchiveAllJobSnapshot` shape. A job replaces the\n// browser clear-all loop: `enqueueArchiveAll` `.create()`s ONE deterministic row\n// (idempotent per user+category+requestId), the bounded scheduled worker drains that\n// ONE category's active cards (PER-TAB SCOPING — never all tabs) reusing the per-card\n// archive helper, and advances `archived` + the terminal `state`. Dead-letter/retry\n// bookkeeping mirrors the fanout ledger; an unresolved job is never TTL'd.\n//\n// See ttt-prod docs/design/notification-system.md (Archive contract).\n\nimport { z } from 'zod';\nimport { NotificationCategorySchema } from '../schemas/notification.js';\nimport { systemRoleSchema } from '../schemas/atoms.js';\nimport { FirestoreTimestampSchema } from './firestore-primitives.js';\n\n/**\n * Job lifecycle state — mirrors `ArchiveAllJobSnapshot['state']` (the poller's union; the\n * callable maps this doc field straight through). `in-progress` is the drain-in-flight\n * state; the three terminals are `complete` (category fully drained), `incomplete`\n * (attempt budget exhausted with cards still active — retry/dead-letter), and `failed`\n * (unexpected fault).\n */\nexport const NotificationArchiveAllJobStateSchema = z.enum(['in-progress', 'complete', 'incomplete', 'failed']);\nexport type NotificationArchiveAllJobState = z.infer<typeof NotificationArchiveAllJobStateSchema>;\n\n/**\n * Persisted archive-all job doc. `.passthrough()` so future additive fields don't fail\n * read-side validation (mirrors the fanout ledger schema).\n */\nexport const NotificationArchiveAllJobSchema = z\n .object({\n schemaVersion: z.literal(1),\n jobId: z.string().min(1),\n /** Owner uid — the ONLY user whose active cards this job archives. */\n userId: z.string().min(1),\n /** The tab/category this job is scoped to (PER-TAB SCOPING — the worker touches only this). */\n category: NotificationCategorySchema,\n /**\n * The enqueuing admin's resolved role, persisted ONLY for admin-category jobs so the\n * worker can reconstruct a faithful `adminReview` actor for each per-card\n * `notification.adminArchived` audit event (enqueue already admin-gated the create, so\n * the authority was verified). Null / absent for personal jobs.\n */\n actorSystemRole: systemRoleSchema.nullable().optional(),\n state: NotificationArchiveAllJobStateSchema,\n /** Monotonic claim revision preventing concurrent inline/scheduled drains. */\n revision: z.number().int().nonnegative(),\n /** Monotonic count of cards archived so far. */\n archived: z.number().int().nonnegative(),\n /**\n * Cards the completing drain could not archive — each failed on its own and is still in the list.\n * Set (never summed) when the job completes, because that drain walked the whole active set once.\n * Absent until a job completes with cards left behind (read as 0).\n */\n notArchived: z.number().int().nonnegative().optional(),\n /** Human-readable failure reason (only on `failed`). */\n error: z.string().nullable(),\n // ── retry / dead-letter bookkeeping (mirrors the fanout ledger) ──\n attemptCount: z.number().int().nonnegative(),\n /** Due-worker predicate: the worker only picks up a job with `nextAttemptAt <= now`. */\n nextAttemptAt: z.number().int().nonnegative(),\n deadLettered: z.boolean(),\n createdAt: z.number().int().nonnegative(),\n updatedAt: z.number().int().nonnegative(),\n completedAt: z.number().int().nullable(),\n deadLetteredAt: z.number().int().nullable(),\n /**\n * Native-TTL reaper stamp (ARCH-105 exception): a real Firestore Timestamp, stamped ONLY\n * on the terminal `complete` branch (30d), so a completed job is reaped and the\n * collection can't grow one dead doc per \"Clear all\" click forever. An UNRESOLVED job\n * (in-progress / incomplete / dead-lettered) is NEVER TTL'd, so the field is absent there.\n */\n expireAt: FirestoreTimestampSchema.optional(),\n })\n .passthrough();\n\nexport type NotificationArchiveAllJob = z.infer<typeof NotificationArchiveAllJobSchema>;\n"]}
|
|
@@ -107,6 +107,7 @@ export declare const COLLECTION_SCHEMAS: {
|
|
|
107
107
|
statusReason: z.ZodOptional<z.ZodString>;
|
|
108
108
|
statusReasonAt: z.ZodOptional<z.ZodNumber>;
|
|
109
109
|
safetyLocked: z.ZodOptional<z.ZodBoolean>;
|
|
110
|
+
orphanDeletionClaimedAt: z.ZodOptional<z.ZodNumber>;
|
|
110
111
|
craftSkillChangeMarker: z.ZodOptional<z.ZodNumber>;
|
|
111
112
|
}, z.core.$strip>;
|
|
112
113
|
readonly 'userProfiles/{userId}/privateData/hallLibraryPreferences': z.ZodObject<{
|
|
@@ -4552,6 +4553,7 @@ export declare const COLLECTION_SCHEMAS: {
|
|
|
4552
4553
|
}>;
|
|
4553
4554
|
revision: z.ZodNumber;
|
|
4554
4555
|
archived: z.ZodNumber;
|
|
4556
|
+
notArchived: z.ZodOptional<z.ZodNumber>;
|
|
4555
4557
|
error: z.ZodNullable<z.ZodString>;
|
|
4556
4558
|
attemptCount: z.ZodNumber;
|
|
4557
4559
|
nextAttemptAt: z.ZodNumber;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/registry.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiN7B,eAAO,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/registry.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiN7B,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqQkB,CAAC;AAElD,MAAM,MAAM,wBAAwB,GAAG,MAAM,OAAO,kBAAkB,CAAC;AAEvE;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;CAmBiC,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAOvC,CAAC"}
|
|
@@ -439,6 +439,7 @@ export declare const UserPrivateDataSchema: z.ZodObject<{
|
|
|
439
439
|
statusReason: z.ZodOptional<z.ZodString>;
|
|
440
440
|
statusReasonAt: z.ZodOptional<z.ZodNumber>;
|
|
441
441
|
safetyLocked: z.ZodOptional<z.ZodBoolean>;
|
|
442
|
+
orphanDeletionClaimedAt: z.ZodOptional<z.ZodNumber>;
|
|
442
443
|
craftSkillChangeMarker: z.ZodOptional<z.ZodNumber>;
|
|
443
444
|
}, z.core.$strip>;
|
|
444
445
|
export type UserPrivateData = z.infer<typeof UserPrivateDataSchema>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/user.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgBxB;;yDAEyD;AACzD,eAAO,MAAM,uBAAuB;;;;EAA4C,CAAC;AACjF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;oDACoD;AACpD,eAAO,MAAM,0BAA0B,UAAgD,CAAC;AAExF;;iFAEiF;AACjF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAExE;AAOD,eAAO,MAAM,oBAAoB;;;;EAAoD,CAAC;AACtF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;0EAE0E;AAC1E,eAAO,MAAM,iCAAiC,EAAE,cAA6B,CAAC;AAM9E,eAAO,MAAM,+BAA+B;;;;;;kBAKjC,CAAC;AACZ,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAKxF,eAAO,MAAM,2BAA2B;;;;;;;;kBAM7B,CAAC;AACZ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAqBhF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAe3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmBpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,uBAAuB;;;;;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,sBAAsB;;;;;;;;;;;iBAOjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,2BAA2B;;;;;;iBAMtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwCzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,oBAAoB;;;;;;;;;iBAqB/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB;;;;;iBAalC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;;;GAGG;AACH,eAAO,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/user.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgBxB;;yDAEyD;AACzD,eAAO,MAAM,uBAAuB;;;;EAA4C,CAAC;AACjF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;oDACoD;AACpD,eAAO,MAAM,0BAA0B,UAAgD,CAAC;AAExF;;iFAEiF;AACjF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAExE;AAOD,eAAO,MAAM,oBAAoB;;;;EAAoD,CAAC;AACtF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;0EAE0E;AAC1E,eAAO,MAAM,iCAAiC,EAAE,cAA6B,CAAC;AAM9E,eAAO,MAAM,+BAA+B;;;;;;kBAKjC,CAAC;AACZ,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAKxF,eAAO,MAAM,2BAA2B;;;;;;;;kBAM7B,CAAC;AACZ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAqBhF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAe3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmBpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,uBAAuB;;;;;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,sBAAsB;;;;;;;;;;;iBAOjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,2BAA2B;;;;;;iBAMtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwCzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,oBAAoB;;;;;;;;;iBAqB/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB;;;;;iBAalC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmEhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
|
package/dist/doc-schemas/user.js
CHANGED
|
@@ -281,6 +281,11 @@ export const UserPrivateDataSchema = z.object({
|
|
|
281
281
|
// restricted to the owner's view. Set true while a child-safety/NCII action is
|
|
282
282
|
// pending against the account; the app gates the user accordingly.
|
|
283
283
|
safetyLocked: z.boolean().optional(),
|
|
284
|
+
// Epoch ms when the orphan-registration cleanup decided to delete this uid's login. Written in the
|
|
285
|
+
// cleanup's eligibility transaction BEFORE the Auth delete, and every registration step refuses in
|
|
286
|
+
// its own transaction while it is present, so no registration can complete into a login that is
|
|
287
|
+
// about to be deleted. Backend-only.
|
|
288
|
+
orphanDeletionClaimedAt: z.number().int().nonnegative().optional(),
|
|
284
289
|
// Counts the owner's Craft publishes and deletes. Each one reads this doc and writes the next
|
|
285
290
|
// value inside its own transaction, so two publishes that both counted a free Craft slot write
|
|
286
291
|
// the same document and conflict instead of both landing past the cap (BACKEND-116). Absent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/doc-schemas/user.ts"],"names":[],"mappings":"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","sourcesContent":["// User-related Firestore document SCHEMAS — the single source of truth for the\n// `userProfiles/{uid}` doc, its `privateData/{uid}` subdoc, and craft-skill shapes.\n// (The `publicUsers/{uid}` mirror lives in ./publicUser.) TypeScript types are\n// inferred from these schemas via `z.infer`, so a document's shape and its type\n// cannot drift apart. See docs/design/firestore-schema-registry.md (ttt-prod).\n\nimport { z } from 'zod';\nimport { HALL_WING_TYPE_KEYS } from '../types/content.js';\nimport { MAX_ARTISAN_LOCATION_LENGTH } from '../constants/business.js';\nimport { CRAFT_SKILL_TAG_VALUES } from '../constants/options.js';\nimport { userPrivateDataAgeFieldsShape } from './safety/age.js';\nimport { ContentMediaKindSchema } from './media-assets.js';\nimport { ModerationHiddenBySchema } from './moderation.js';\nimport {\n calendarDateSchema,\n documentIdSegmentSchema,\n} from '../schemas/atoms.js';\nimport { PublicDocumentAcceptanceSchema, PublicDocumentVersionOrNoneSchema } from './public-documents.js';\n\n// The canonical stored media kind — declared once in doc-schemas/media-assets.ts.\nconst mediaKindSchema = ContentMediaKindSchema;\n\n/** The ONE canonical application account status (userProfiles.status is the\n * authoritative value; the chat access projection and the status-reconcile queue\n * derive from the same set). Never re-declare inline. */\nexport const UserAccountStatusSchema = z.enum(['active', 'suspended', 'banned']);\nexport type UserAccountStatus = z.infer<typeof UserAccountStatusSchema>;\n\n/** The status an account holds while no status decision has ever been written: a profile, or a\n * token, with no `status` is an active account. */\nexport const ABSENT_USER_ACCOUNT_STATUS = 'active' as const satisfies UserAccountStatus;\n\n/** A stored `userProfiles.status` read as the account's status: absent is\n * `ABSENT_USER_ACCOUNT_STATUS`; any value outside `UserAccountStatusSchema` throws, so a\n * malformed status is never enforced, compared, or shown as if it were real. */\nexport function parseUserAccountStatus(value: unknown): UserAccountStatus {\n return value === undefined ? ABSENT_USER_ACCOUNT_STATUS : UserAccountStatusSchema.parse(value);\n}\n\n// Craft-skill kind — mandatory choice at upload, no default (see ttt-prod\n// docs/design/profile-and-craft-skills.md). 'original' = the artisan's own original creation;\n// 'mimicOnTtt' = a performance/recreation of work that originated in the TTT community\n// (requires a source reference); 'mimicOffTtt' = a performance/recreation of work from\n// outside TTT (covers covers + public-domain works, no source reference).\nexport const CraftSkillKindSchema = z.enum(['original', 'mimicOnTtt', 'mimicOffTtt']);\nexport type CraftSkillKind = z.infer<typeof CraftSkillKindSchema>;\n\n/** The ONE craft-skill kind that carries a `source` reference. The discriminated\n * CraftSkillSchema arm below and every upload-time validator derive from this named\n * declaration rather than re-quoting the member (ENG-005 / ARCH-102). */\nexport const CRAFT_SKILL_KIND_REQUIRING_SOURCE: CraftSkillKind = 'mimicOnTtt';\n\n// Source reference for a 'mimicOnTtt' skill — the original artisan OR the original work,\n// linked mention-style (id only, no name snapshots, resolved at render per the Display\n// Identity Invariant). 'workProject' is the safe framing today; linking a specific hall\n// item is optional future scope.\nexport const CraftSkillSourceReferenceSchema = z\n .object({\n type: z.enum(['user', 'workProject']),\n id: documentIdSegmentSchema,\n })\n .strict();\nexport type CraftSkillSourceReference = z.infer<typeof CraftSkillSourceReferenceSchema>;\n\n// The agreed attestation recorded on the doc: which statement (keyed by kind) the\n// uploader agreed to, its version, and when (epoch ms, always a number — never a\n// Firestore Timestamp).\nexport const CraftSkillAttestationSchema = z\n .object({\n statementKind: CraftSkillKindSchema,\n statementVersion: z.number().int().min(1),\n agreedAt: z.number(),\n })\n .strict();\nexport type CraftSkillAttestation = z.infer<typeof CraftSkillAttestationSchema>;\n\n// Base craft-skill fields shared across all kinds. The `kind` + `source` relationship is\n// layered on top as a discriminated union so an invalid combination (e.g. a source on an\n// 'original', or a missing source on a 'mimicOnTtt') fails schema validation.\nconst craftSkillBaseShape = {\n id: z.string(),\n name: z.string(),\n mediaAssetId: z.string(),\n // Canonical discipline-tag allowlist — never open strings (DJ ruling 2026-07-13).\n tags: z.array(z.enum(CRAFT_SKILL_TAG_VALUES)),\n createdAt: z.number(),\n type: mediaKindSchema,\n // Moderation visibility flag. Absent/false = visible; true = hidden by the\n // craft-skill hide cascade (report auto-hide or admin action). Mirrored onto\n // every taggedCraftSkills index doc so discovery surfaces can filter it.\n hidden: z.boolean(),\n hiddenBy: ModerationHiddenBySchema.optional(),\n attestation: CraftSkillAttestationSchema,\n};\n\nexport const CraftSkillSchema = z.discriminatedUnion('kind', [\n z.object({\n ...craftSkillBaseShape,\n kind: z.literal('original'),\n }),\n z.object({\n ...craftSkillBaseShape,\n kind: z.literal('mimicOnTtt'),\n // REQUIRED for the on-TTT mimic kind: the linked original artisan or work.\n source: CraftSkillSourceReferenceSchema,\n }),\n z.object({\n ...craftSkillBaseShape,\n kind: z.literal('mimicOffTtt'),\n }),\n]);\nexport type CraftSkill = z.infer<typeof CraftSkillSchema>;\n\nexport const CraftSkillReferenceSchema = z.object({\n craftSkillId: z.string(),\n compositeId: z.string(),\n userId: z.string(),\n craftSkillName: z.string(),\n craftSkillAssetId: z.string(),\n craftSkillType: mediaKindSchema,\n tags: z.array(z.enum(CRAFT_SKILL_TAG_VALUES)),\n createdAt: z.number(),\n // Mirror of CraftSkill.hidden; lets the tag-browse filter hidden skills out.\n hidden: z.boolean(),\n hiddenBy: ModerationHiddenBySchema.optional(),\n // Mirror of CraftSkill.kind so the tag-browse card can render the kind badge without a\n // second read.\n kind: CraftSkillKindSchema,\n // Mirror of CraftSkill.source — present ONLY when kind === 'mimicOnTtt' (the source-doc\n // discriminated union guarantees that invariant on the authoritative side). Lets the\n // browse card render the clickable \"someone performed my work\" source link.\n source: CraftSkillSourceReferenceSchema.optional(),\n});\nexport type CraftSkillReference = z.infer<typeof CraftSkillReferenceSchema>;\n\nexport const MinimalCraftSkillSchema = z.object({\n id: z.string(),\n name: z.string(),\n mediaAssetId: z.string(),\n type: mediaKindSchema,\n});\nexport type MinimalCraftSkill = z.infer<typeof MinimalCraftSkillSchema>;\n\nexport const OwnedWorkProjectSchema = z.object({\n workProjectId: z.string(),\n workingTitle: z.string(),\n workingDescription: z.string(),\n type: z.string(),\n createdOn: z.number(),\n hallWingType: z.enum(HALL_WING_TYPE_KEYS),\n});\nexport type OwnedWorkProject = z.infer<typeof OwnedWorkProjectSchema>;\n\nexport const AssociatedWorkProjectSchema = z.object({\n workProjectId: z.string(),\n workingTitle: z.string(),\n workingDescription: z.string(),\n type: z.string(),\n joinedOn: z.number(),\n});\nexport type AssociatedWorkProject = z.infer<typeof AssociatedWorkProjectSchema>;\n\nexport const FullUserSchema = z.object({\n uid: z.string(),\n displayName: z.string(),\n displayName_lowercase: z.string(),\n // One asset, variants full/medium/small in the mediaAssets registry; URLs\n // are built at render time (media-assets-and-protected-serving.md).\n profilePictureAssetId: z.string().nullable().optional(),\n artisanCreator: z.number().optional(),\n // Cosmetic supporter badge. Set true via the Admin SDK inside the Stripe webhook's\n // pledge-record transaction once the user completes a pledge; rendered on the profile\n // page. Lives here (not publicUsers) because userProfiles/{uid} is already readable by\n // any authenticated user, so other viewers see the badge with no mirror. Not PII.\n // Revoked (→ false) on refund once refunds ship.\n hasPledged: z.boolean().optional(),\n status: UserAccountStatusSchema.optional(),\n // Stamped by the one status writer on every status change: when, and the acting admin/operator\n // uid (a system actor writes its own id). Absent on an account whose status never changed.\n statusUpdatedAt: z.number().optional(),\n // Either the authenticated actor's uid or a stable namespaced system actor\n // identifier (for example `system:autoHashLock`); never null.\n statusUpdatedBy: z.string().min(1).optional(),\n // Chat-edge-rebuild account-access domain (Contract B / round-10 blocker 1): the\n // single ban/unban ordering version + state the chat `accountAccess` sync events key\n // on. Backend-only-writable. Deliberate defaults when ABSENT: a never-touched account\n // is `{ accountAccessVersion: 0, accountAccessState: 'active' }` (NOT banned) — bumped\n // atomically on suspend/ban/unban, which enqueue the accountAccessChanged fanout.\n accountAccessVersion: z.number().optional(),\n accountAccessState: UserAccountStatusSchema.optional(),\n // Moderation: set true by the forceDisplayNameReset callable when an admin resets an\n // abusive display name. The app gates the user into a forced \"pick a new name\" flow until\n // they complete it via setMyDisplayName (which clears this). Backend-only-writable (like `status`).\n displayNameResetRequired: z.boolean().optional(),\n ownedWorkProjects: z.array(OwnedWorkProjectSchema).optional(),\n associatedWorkProjects: z.array(AssociatedWorkProjectSchema).optional(),\n createdAt: z.number(),\n // N3 data-deletion / GDPR erasure: epoch ms when the account-deletion scrub\n // anonymized this profile in place. When set, the identity fields have been\n // scrubbed (displayName → the FORMER_MEMBER_DISPLAY_NAME sentinel) and the\n // account is a tombstone. Backend-only-writable.\n anonymizedAt: z.number().optional(),\n});\nexport type FullUser = z.infer<typeof FullUserSchema>;\n\nexport const UserAgreementsSchema = z.object({\n age: z.boolean().optional(),\n nudity: z.boolean().optional(),\n meet: z.boolean().optional(),\n cookies: z.boolean().optional(),\n terms: z.boolean().optional(),\n agreedOn: z.number().optional(),\n /**\n * The Terms / Privacy versions accepted at registration, read server-side from the live\n * docs at acceptance time — never client-supplied, never a hardcoded constant. Kept for the\n * accounts that recorded them; the current per-document record is\n * `privateData.publicDocumentAcceptance`.\n *\n * `0` is the sentinel for \"registered while no legal document was published\" (a fresh\n * environment's first account). Published versions start at 1, so 0 can never equal a live\n * version — which is deliberate: it keeps the record from claiming consent that never\n * happened, and leaves the version-bump re-acceptance path free to catch the account once\n * real legal content ships.\n */\n termsVersion: z.number().int().nonnegative().optional(),\n privacyVersion: z.number().int().nonnegative().optional(),\n});\nexport type UserAgreements = z.infer<typeof UserAgreementsSchema>;\n\n/**\n * First-visit site-tour state (account-durable, server-written) stored on\n * `privateData/{uid}.siteTour`. A missing `siteTour` field means the member has never\n * handled the tour. Automatic-invitation eligibility is evaluated in this order:\n * 1. `automaticInvitesDisabledAt` present → never invite automatically (\"Don't show\n * this again\");\n * 2. `notTodayDate` equals the member's current LOCAL calendar date → do not invite\n * that day (\"Not today\");\n * 3. `completedVersion` equals `SITE_TOUR_CURRENT_VERSION` → already handled;\n * 4. otherwise → offer the tour.\n * Written ONLY by the `updateSiteTourPreference` callable via the Admin SDK; never\n * client-written. `notTodayDate` is a strict `YYYY-MM-DD` local-date string (same\n * date-string convention as the age cluster's `attestedDateOfBirth`). See\n * docs/design/landing-backstage-guide-and-first-visit-plan.md §10.\n */\nexport const UserSiteTourStateSchema = z.object({\n // The tour version the member completed. The callable stamps SITE_TOUR_CURRENT_VERSION\n // server-side at completion (the version is server-owned, never client-supplied);\n // absent until a completion is recorded.\n completedVersion: z.number().int().optional(),\n // Epoch ms when the tour was completed.\n completedAt: z.number().optional(),\n // The member's LOCAL calendar date (YYYY-MM-DD) recorded by \"Not today\"; the automatic\n // invitation is suppressed for exactly that date, then offered again on a later date.\n notTodayDate: calendarDateSchema.optional(), // 'YYYY-MM-DD'\n // Epoch ms when the member chose \"Don't show this again\" (permanent automatic-invite\n // dismissal). Manual replay from Help ignores this without clearing it.\n automaticInvitesDisabledAt: z.number().optional(),\n});\nexport type UserSiteTourState = z.infer<typeof UserSiteTourStateSchema>;\n\n/**\n * Owner-only account state at `userProfiles/{uid}/privateData/{uid}` (readable\n * only by the owner; never mirrored to publicUsers).\n */\nexport const UserPrivateDataSchema = z.object({\n email: z.string(),\n // Epoch ms when the user applied for news/political posting (not a boolean) so the\n // applicant queue can be ordered/triaged by application date. Mirrors the\n // `artisanCreator?: number` grant-timestamp pattern. Truthy when set, so existing\n // truthiness reads keep working; absent until the user applies.\n isWaitingForNewsApproval: z.number().optional(),\n // Epoch ms when the user attested they are a U.S.-based person while becoming an artisan\n // (required at artisan signup for now). Mirrors the ageAttested attestation pattern; written\n // server-side by becomeArtisanCreator.\n usPersonAttestedAt: z.number().optional(),\n // Non-U.S. artisan-interest \"waitlist\" recorded ONLY for adult accounts when a non-U.S. person\n // asks to be notified once creator signups open in their region. Owner-only, backend-written.\n // `requestedAt` is the immutable first-come-first-serve timestamp; `country`/`region` let signups\n // be opened by jurisdiction as each region's laws clear. Mirrors isWaitingForNewsApproval.\n nonUsArtisanInterest: z\n .object({\n country: z.string().min(1).max(MAX_ARTISAN_LOCATION_LENGTH),\n region: z.string().max(MAX_ARTISAN_LOCATION_LENGTH).optional(),\n requestedAt: z.number(),\n })\n .optional(),\n squareStreetzAgreementsDate: z.number().optional(),\n // The rules-and-agreements `version` in force when the user accepted; 0 when no versioned\n // rules doc existed yet, so a later real version 1 still re-prompts.\n squareStreetzAgreementsVersion: PublicDocumentVersionOrNoneSchema.optional(),\n // The rules-and-agreements version in force when the user accepted the Artisan upgrade's\n // agreement, read server-side in the grant transaction (the grant time is the profile's\n // `artisanCreator` stamp). Same 0 sentinel as `squareStreetzAgreementsVersion`.\n artisanCreatorAgreementsVersion: PublicDocumentVersionOrNoneSchema.optional(),\n // Epoch ms when the user accepted the one-time Hall download acknowledgement\n // (personal offline use only, no redistribution). Written server-side by the\n // acceptHallDownloadAcknowledgement callable; gates the Hall download button.\n hallDownloadAcknowledgedAt: z.number().optional(),\n agreements: UserAgreementsSchema.optional(),\n // The latest accepted version of each public document and the accepted level (see\n // PublicDocumentAcceptanceSchema). Written by registration and the acceptance callable only;\n // the `docsAccepted` claim mirrors `acceptedLevel`. Absent = nothing accepted (level 0).\n publicDocumentAcceptance: PublicDocumentAcceptanceSchema.optional(),\n // First-visit site-tour state (account-durable; the SOLE authority for tour\n // eligibility — no local-storage cache/mirror). Absent = never handled. Written only\n // by the updateSiteTourPreference callable. See UserSiteTourStateSchema above.\n siteTour: UserSiteTourStateSchema.optional(),\n // Moderation: human-readable reason for the current account status (set when an\n // admin suspends/bans the user). Written by the setUserStatus callable via the\n // Admin SDK; readable only by the owner (shown in their restricted view).\n // Cleared when the account is reinstated to 'active'.\n statusReason: z.string().optional(),\n statusReasonAt: z.number().optional(),\n // Trust & Safety (§A8): silent interim safety-lock flag. Backend-only-writable,\n // restricted to the owner's view. Set true while a child-safety/NCII action is\n // pending against the account; the app gates the user accordingly.\n safetyLocked: z.boolean().optional(),\n // Counts the owner's Craft publishes and deletes. Each one reads this doc and writes the next\n // value inside its own transaction, so two publishes that both counted a free Craft slot write\n // the same document and conflict instead of both landing past the cap (BACKEND-116). Absent\n // until the first Craft change (read as 0); a moderation hide never writes it.\n craftSkillChangeMarker: z.number().int().nonnegative().optional(),\n // Trust & Safety (§A7): server-write-only age/registration fields, merged from the\n // standalone age cluster shape (./safety/age.js) so the canonical schema and the\n // age cluster cannot drift.\n ...userPrivateDataAgeFieldsShape,\n});\nexport type UserPrivateData = z.infer<typeof UserPrivateDataSchema>;\n"]}
|
|
1
|
+
{"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/doc-schemas/user.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,oFAAoF;AACpF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAE/E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EACL,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,8BAA8B,EAAE,iCAAiC,EAAE,MAAM,uBAAuB,CAAC;AAE1G,kFAAkF;AAClF,MAAM,eAAe,GAAG,sBAAsB,CAAC;AAE/C;;yDAEyD;AACzD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGjF;oDACoD;AACpD,MAAM,CAAC,MAAM,0BAA0B,GAAG,QAA6C,CAAC;AAExF;;iFAEiF;AACjF,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,uBAAuB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACjG,CAAC;AAED,0EAA0E;AAC1E,8FAA8F;AAC9F,uFAAuF;AACvF,uFAAuF;AACvF,0EAA0E;AAC1E,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC;AAGtF;;0EAE0E;AAC1E,MAAM,CAAC,MAAM,iCAAiC,GAAmB,YAAY,CAAC;AAE9E,yFAAyF;AACzF,uFAAuF;AACvF,wFAAwF;AACxF,iCAAiC;AACjC,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC;KAC7C,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACrC,EAAE,EAAE,uBAAuB;CAC5B,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ,kFAAkF;AAClF,iFAAiF;AACjF,wBAAwB;AACxB,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC;KACzC,MAAM,CAAC;IACN,aAAa,EAAE,oBAAoB;IACnC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;CACrB,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ,yFAAyF;AACzF,yFAAyF;AACzF,8EAA8E;AAC9E,MAAM,mBAAmB,GAAG;IAC1B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,kFAAkF;IAClF,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC7C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,IAAI,EAAE,eAAe;IACrB,2EAA2E;IAC3E,6EAA6E;IAC7E,yEAAyE;IACzE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB,QAAQ,EAAE,wBAAwB,CAAC,QAAQ,EAAE;IAC7C,WAAW,EAAE,2BAA2B;CACzC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAC3D,CAAC,CAAC,MAAM,CAAC;QACP,GAAG,mBAAmB;QACtB,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;KAC5B,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,GAAG,mBAAmB;QACtB,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;QAC7B,2EAA2E;QAC3E,MAAM,EAAE,+BAA+B;KACxC,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,GAAG,mBAAmB;QACtB,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;KAC/B,CAAC;CACH,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;IAC1B,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC7B,cAAc,EAAE,eAAe;IAC/B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC7C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,6EAA6E;IAC7E,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB,QAAQ,EAAE,wBAAwB,CAAC,QAAQ,EAAE;IAC7C,uFAAuF;IACvF,eAAe;IACf,IAAI,EAAE,oBAAoB;IAC1B,wFAAwF;IACxF,qFAAqF;IACrF,4EAA4E;IAC5E,MAAM,EAAE,+BAA+B,CAAC,QAAQ,EAAE;CACnD,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,IAAI,EAAE,eAAe;CACtB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC;CAC1C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;CACrB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE;IACjC,0EAA0E;IAC1E,oEAAoE;IACpE,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACvD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,mFAAmF;IACnF,sFAAsF;IACtF,uFAAuF;IACvF,kFAAkF;IAClF,iDAAiD;IACjD,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAClC,MAAM,EAAE,uBAAuB,CAAC,QAAQ,EAAE;IAC1C,+FAA+F;IAC/F,2FAA2F;IAC3F,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACtC,2EAA2E;IAC3E,8DAA8D;IAC9D,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC7C,iFAAiF;IACjF,qFAAqF;IACrF,sFAAsF;IACtF,uFAAuF;IACvF,kFAAkF;IAClF,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3C,kBAAkB,EAAE,uBAAuB,CAAC,QAAQ,EAAE;IACtD,qFAAqF;IACrF,0FAA0F;IAC1F,oGAAoG;IACpG,wBAAwB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAChD,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC,QAAQ,EAAE;IAC7D,sBAAsB,EAAE,CAAC,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC,QAAQ,EAAE;IACvE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,4EAA4E;IAC5E,4EAA4E;IAC5E,2EAA2E;IAC3E,iDAAiD;IACjD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC/B,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC7B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B;;;;;;;;;;;OAWG;IACH,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IACvD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;CAC1D,CAAC,CAAC;AAGH;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,uFAAuF;IACvF,kFAAkF;IAClF,yCAAyC;IACzC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC7C,wCAAwC;IACxC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,uFAAuF;IACvF,sFAAsF;IACtF,YAAY,EAAE,kBAAkB,CAAC,QAAQ,EAAE,EAAE,eAAe;IAC5D,qFAAqF;IACrF,wEAAwE;IACxE,0BAA0B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClD,CAAC,CAAC;AAGH;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,mFAAmF;IACnF,0EAA0E;IAC1E,kFAAkF;IAClF,gEAAgE;IAChE,wBAAwB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/C,yFAAyF;IACzF,6FAA6F;IAC7F,uCAAuC;IACvC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzC,+FAA+F;IAC/F,8FAA8F;IAC9F,kGAAkG;IAClG,2FAA2F;IAC3F,oBAAoB,EAAE,CAAC;SACpB,MAAM,CAAC;QACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,2BAA2B,CAAC;QAC3D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC,QAAQ,EAAE;QAC9D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;KACxB,CAAC;SACD,QAAQ,EAAE;IACb,2BAA2B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClD,0FAA0F;IAC1F,qEAAqE;IACrE,8BAA8B,EAAE,iCAAiC,CAAC,QAAQ,EAAE;IAC5E,yFAAyF;IACzF,wFAAwF;IACxF,gFAAgF;IAChF,+BAA+B,EAAE,iCAAiC,CAAC,QAAQ,EAAE;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,0BAA0B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjD,UAAU,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC3C,kFAAkF;IAClF,6FAA6F;IAC7F,yFAAyF;IACzF,wBAAwB,EAAE,8BAA8B,CAAC,QAAQ,EAAE;IACnE,4EAA4E;IAC5E,qFAAqF;IACrF,+EAA+E;IAC/E,QAAQ,EAAE,uBAAuB,CAAC,QAAQ,EAAE;IAC5C,gFAAgF;IAChF,+EAA+E;IAC/E,0EAA0E;IAC1E,sDAAsD;IACtD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,gFAAgF;IAChF,+EAA+E;IAC/E,mEAAmE;IACnE,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACpC,mGAAmG;IACnG,mGAAmG;IACnG,gGAAgG;IAChG,qCAAqC;IACrC,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IAClE,8FAA8F;IAC9F,+FAA+F;IAC/F,4FAA4F;IAC5F,+EAA+E;IAC/E,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IACjE,mFAAmF;IACnF,iFAAiF;IACjF,4BAA4B;IAC5B,GAAG,6BAA6B;CACjC,CAAC,CAAC","sourcesContent":["// User-related Firestore document SCHEMAS — the single source of truth for the\n// `userProfiles/{uid}` doc, its `privateData/{uid}` subdoc, and craft-skill shapes.\n// (The `publicUsers/{uid}` mirror lives in ./publicUser.) TypeScript types are\n// inferred from these schemas via `z.infer`, so a document's shape and its type\n// cannot drift apart. See docs/design/firestore-schema-registry.md (ttt-prod).\n\nimport { z } from 'zod';\nimport { HALL_WING_TYPE_KEYS } from '../types/content.js';\nimport { MAX_ARTISAN_LOCATION_LENGTH } from '../constants/business.js';\nimport { CRAFT_SKILL_TAG_VALUES } from '../constants/options.js';\nimport { userPrivateDataAgeFieldsShape } from './safety/age.js';\nimport { ContentMediaKindSchema } from './media-assets.js';\nimport { ModerationHiddenBySchema } from './moderation.js';\nimport {\n calendarDateSchema,\n documentIdSegmentSchema,\n} from '../schemas/atoms.js';\nimport { PublicDocumentAcceptanceSchema, PublicDocumentVersionOrNoneSchema } from './public-documents.js';\n\n// The canonical stored media kind — declared once in doc-schemas/media-assets.ts.\nconst mediaKindSchema = ContentMediaKindSchema;\n\n/** The ONE canonical application account status (userProfiles.status is the\n * authoritative value; the chat access projection and the status-reconcile queue\n * derive from the same set). Never re-declare inline. */\nexport const UserAccountStatusSchema = z.enum(['active', 'suspended', 'banned']);\nexport type UserAccountStatus = z.infer<typeof UserAccountStatusSchema>;\n\n/** The status an account holds while no status decision has ever been written: a profile, or a\n * token, with no `status` is an active account. */\nexport const ABSENT_USER_ACCOUNT_STATUS = 'active' as const satisfies UserAccountStatus;\n\n/** A stored `userProfiles.status` read as the account's status: absent is\n * `ABSENT_USER_ACCOUNT_STATUS`; any value outside `UserAccountStatusSchema` throws, so a\n * malformed status is never enforced, compared, or shown as if it were real. */\nexport function parseUserAccountStatus(value: unknown): UserAccountStatus {\n return value === undefined ? ABSENT_USER_ACCOUNT_STATUS : UserAccountStatusSchema.parse(value);\n}\n\n// Craft-skill kind — mandatory choice at upload, no default (see ttt-prod\n// docs/design/profile-and-craft-skills.md). 'original' = the artisan's own original creation;\n// 'mimicOnTtt' = a performance/recreation of work that originated in the TTT community\n// (requires a source reference); 'mimicOffTtt' = a performance/recreation of work from\n// outside TTT (covers covers + public-domain works, no source reference).\nexport const CraftSkillKindSchema = z.enum(['original', 'mimicOnTtt', 'mimicOffTtt']);\nexport type CraftSkillKind = z.infer<typeof CraftSkillKindSchema>;\n\n/** The ONE craft-skill kind that carries a `source` reference. The discriminated\n * CraftSkillSchema arm below and every upload-time validator derive from this named\n * declaration rather than re-quoting the member (ENG-005 / ARCH-102). */\nexport const CRAFT_SKILL_KIND_REQUIRING_SOURCE: CraftSkillKind = 'mimicOnTtt';\n\n// Source reference for a 'mimicOnTtt' skill — the original artisan OR the original work,\n// linked mention-style (id only, no name snapshots, resolved at render per the Display\n// Identity Invariant). 'workProject' is the safe framing today; linking a specific hall\n// item is optional future scope.\nexport const CraftSkillSourceReferenceSchema = z\n .object({\n type: z.enum(['user', 'workProject']),\n id: documentIdSegmentSchema,\n })\n .strict();\nexport type CraftSkillSourceReference = z.infer<typeof CraftSkillSourceReferenceSchema>;\n\n// The agreed attestation recorded on the doc: which statement (keyed by kind) the\n// uploader agreed to, its version, and when (epoch ms, always a number — never a\n// Firestore Timestamp).\nexport const CraftSkillAttestationSchema = z\n .object({\n statementKind: CraftSkillKindSchema,\n statementVersion: z.number().int().min(1),\n agreedAt: z.number(),\n })\n .strict();\nexport type CraftSkillAttestation = z.infer<typeof CraftSkillAttestationSchema>;\n\n// Base craft-skill fields shared across all kinds. The `kind` + `source` relationship is\n// layered on top as a discriminated union so an invalid combination (e.g. a source on an\n// 'original', or a missing source on a 'mimicOnTtt') fails schema validation.\nconst craftSkillBaseShape = {\n id: z.string(),\n name: z.string(),\n mediaAssetId: z.string(),\n // Canonical discipline-tag allowlist — never open strings (DJ ruling 2026-07-13).\n tags: z.array(z.enum(CRAFT_SKILL_TAG_VALUES)),\n createdAt: z.number(),\n type: mediaKindSchema,\n // Moderation visibility flag. Absent/false = visible; true = hidden by the\n // craft-skill hide cascade (report auto-hide or admin action). Mirrored onto\n // every taggedCraftSkills index doc so discovery surfaces can filter it.\n hidden: z.boolean(),\n hiddenBy: ModerationHiddenBySchema.optional(),\n attestation: CraftSkillAttestationSchema,\n};\n\nexport const CraftSkillSchema = z.discriminatedUnion('kind', [\n z.object({\n ...craftSkillBaseShape,\n kind: z.literal('original'),\n }),\n z.object({\n ...craftSkillBaseShape,\n kind: z.literal('mimicOnTtt'),\n // REQUIRED for the on-TTT mimic kind: the linked original artisan or work.\n source: CraftSkillSourceReferenceSchema,\n }),\n z.object({\n ...craftSkillBaseShape,\n kind: z.literal('mimicOffTtt'),\n }),\n]);\nexport type CraftSkill = z.infer<typeof CraftSkillSchema>;\n\nexport const CraftSkillReferenceSchema = z.object({\n craftSkillId: z.string(),\n compositeId: z.string(),\n userId: z.string(),\n craftSkillName: z.string(),\n craftSkillAssetId: z.string(),\n craftSkillType: mediaKindSchema,\n tags: z.array(z.enum(CRAFT_SKILL_TAG_VALUES)),\n createdAt: z.number(),\n // Mirror of CraftSkill.hidden; lets the tag-browse filter hidden skills out.\n hidden: z.boolean(),\n hiddenBy: ModerationHiddenBySchema.optional(),\n // Mirror of CraftSkill.kind so the tag-browse card can render the kind badge without a\n // second read.\n kind: CraftSkillKindSchema,\n // Mirror of CraftSkill.source — present ONLY when kind === 'mimicOnTtt' (the source-doc\n // discriminated union guarantees that invariant on the authoritative side). Lets the\n // browse card render the clickable \"someone performed my work\" source link.\n source: CraftSkillSourceReferenceSchema.optional(),\n});\nexport type CraftSkillReference = z.infer<typeof CraftSkillReferenceSchema>;\n\nexport const MinimalCraftSkillSchema = z.object({\n id: z.string(),\n name: z.string(),\n mediaAssetId: z.string(),\n type: mediaKindSchema,\n});\nexport type MinimalCraftSkill = z.infer<typeof MinimalCraftSkillSchema>;\n\nexport const OwnedWorkProjectSchema = z.object({\n workProjectId: z.string(),\n workingTitle: z.string(),\n workingDescription: z.string(),\n type: z.string(),\n createdOn: z.number(),\n hallWingType: z.enum(HALL_WING_TYPE_KEYS),\n});\nexport type OwnedWorkProject = z.infer<typeof OwnedWorkProjectSchema>;\n\nexport const AssociatedWorkProjectSchema = z.object({\n workProjectId: z.string(),\n workingTitle: z.string(),\n workingDescription: z.string(),\n type: z.string(),\n joinedOn: z.number(),\n});\nexport type AssociatedWorkProject = z.infer<typeof AssociatedWorkProjectSchema>;\n\nexport const FullUserSchema = z.object({\n uid: z.string(),\n displayName: z.string(),\n displayName_lowercase: z.string(),\n // One asset, variants full/medium/small in the mediaAssets registry; URLs\n // are built at render time (media-assets-and-protected-serving.md).\n profilePictureAssetId: z.string().nullable().optional(),\n artisanCreator: z.number().optional(),\n // Cosmetic supporter badge. Set true via the Admin SDK inside the Stripe webhook's\n // pledge-record transaction once the user completes a pledge; rendered on the profile\n // page. Lives here (not publicUsers) because userProfiles/{uid} is already readable by\n // any authenticated user, so other viewers see the badge with no mirror. Not PII.\n // Revoked (→ false) on refund once refunds ship.\n hasPledged: z.boolean().optional(),\n status: UserAccountStatusSchema.optional(),\n // Stamped by the one status writer on every status change: when, and the acting admin/operator\n // uid (a system actor writes its own id). Absent on an account whose status never changed.\n statusUpdatedAt: z.number().optional(),\n // Either the authenticated actor's uid or a stable namespaced system actor\n // identifier (for example `system:autoHashLock`); never null.\n statusUpdatedBy: z.string().min(1).optional(),\n // Chat-edge-rebuild account-access domain (Contract B / round-10 blocker 1): the\n // single ban/unban ordering version + state the chat `accountAccess` sync events key\n // on. Backend-only-writable. Deliberate defaults when ABSENT: a never-touched account\n // is `{ accountAccessVersion: 0, accountAccessState: 'active' }` (NOT banned) — bumped\n // atomically on suspend/ban/unban, which enqueue the accountAccessChanged fanout.\n accountAccessVersion: z.number().optional(),\n accountAccessState: UserAccountStatusSchema.optional(),\n // Moderation: set true by the forceDisplayNameReset callable when an admin resets an\n // abusive display name. The app gates the user into a forced \"pick a new name\" flow until\n // they complete it via setMyDisplayName (which clears this). Backend-only-writable (like `status`).\n displayNameResetRequired: z.boolean().optional(),\n ownedWorkProjects: z.array(OwnedWorkProjectSchema).optional(),\n associatedWorkProjects: z.array(AssociatedWorkProjectSchema).optional(),\n createdAt: z.number(),\n // N3 data-deletion / GDPR erasure: epoch ms when the account-deletion scrub\n // anonymized this profile in place. When set, the identity fields have been\n // scrubbed (displayName → the FORMER_MEMBER_DISPLAY_NAME sentinel) and the\n // account is a tombstone. Backend-only-writable.\n anonymizedAt: z.number().optional(),\n});\nexport type FullUser = z.infer<typeof FullUserSchema>;\n\nexport const UserAgreementsSchema = z.object({\n age: z.boolean().optional(),\n nudity: z.boolean().optional(),\n meet: z.boolean().optional(),\n cookies: z.boolean().optional(),\n terms: z.boolean().optional(),\n agreedOn: z.number().optional(),\n /**\n * The Terms / Privacy versions accepted at registration, read server-side from the live\n * docs at acceptance time — never client-supplied, never a hardcoded constant. Kept for the\n * accounts that recorded them; the current per-document record is\n * `privateData.publicDocumentAcceptance`.\n *\n * `0` is the sentinel for \"registered while no legal document was published\" (a fresh\n * environment's first account). Published versions start at 1, so 0 can never equal a live\n * version — which is deliberate: it keeps the record from claiming consent that never\n * happened, and leaves the version-bump re-acceptance path free to catch the account once\n * real legal content ships.\n */\n termsVersion: z.number().int().nonnegative().optional(),\n privacyVersion: z.number().int().nonnegative().optional(),\n});\nexport type UserAgreements = z.infer<typeof UserAgreementsSchema>;\n\n/**\n * First-visit site-tour state (account-durable, server-written) stored on\n * `privateData/{uid}.siteTour`. A missing `siteTour` field means the member has never\n * handled the tour. Automatic-invitation eligibility is evaluated in this order:\n * 1. `automaticInvitesDisabledAt` present → never invite automatically (\"Don't show\n * this again\");\n * 2. `notTodayDate` equals the member's current LOCAL calendar date → do not invite\n * that day (\"Not today\");\n * 3. `completedVersion` equals `SITE_TOUR_CURRENT_VERSION` → already handled;\n * 4. otherwise → offer the tour.\n * Written ONLY by the `updateSiteTourPreference` callable via the Admin SDK; never\n * client-written. `notTodayDate` is a strict `YYYY-MM-DD` local-date string (same\n * date-string convention as the age cluster's `attestedDateOfBirth`). See\n * docs/design/landing-backstage-guide-and-first-visit-plan.md §10.\n */\nexport const UserSiteTourStateSchema = z.object({\n // The tour version the member completed. The callable stamps SITE_TOUR_CURRENT_VERSION\n // server-side at completion (the version is server-owned, never client-supplied);\n // absent until a completion is recorded.\n completedVersion: z.number().int().optional(),\n // Epoch ms when the tour was completed.\n completedAt: z.number().optional(),\n // The member's LOCAL calendar date (YYYY-MM-DD) recorded by \"Not today\"; the automatic\n // invitation is suppressed for exactly that date, then offered again on a later date.\n notTodayDate: calendarDateSchema.optional(), // 'YYYY-MM-DD'\n // Epoch ms when the member chose \"Don't show this again\" (permanent automatic-invite\n // dismissal). Manual replay from Help ignores this without clearing it.\n automaticInvitesDisabledAt: z.number().optional(),\n});\nexport type UserSiteTourState = z.infer<typeof UserSiteTourStateSchema>;\n\n/**\n * Owner-only account state at `userProfiles/{uid}/privateData/{uid}` (readable\n * only by the owner; never mirrored to publicUsers).\n */\nexport const UserPrivateDataSchema = z.object({\n email: z.string(),\n // Epoch ms when the user applied for news/political posting (not a boolean) so the\n // applicant queue can be ordered/triaged by application date. Mirrors the\n // `artisanCreator?: number` grant-timestamp pattern. Truthy when set, so existing\n // truthiness reads keep working; absent until the user applies.\n isWaitingForNewsApproval: z.number().optional(),\n // Epoch ms when the user attested they are a U.S.-based person while becoming an artisan\n // (required at artisan signup for now). Mirrors the ageAttested attestation pattern; written\n // server-side by becomeArtisanCreator.\n usPersonAttestedAt: z.number().optional(),\n // Non-U.S. artisan-interest \"waitlist\" recorded ONLY for adult accounts when a non-U.S. person\n // asks to be notified once creator signups open in their region. Owner-only, backend-written.\n // `requestedAt` is the immutable first-come-first-serve timestamp; `country`/`region` let signups\n // be opened by jurisdiction as each region's laws clear. Mirrors isWaitingForNewsApproval.\n nonUsArtisanInterest: z\n .object({\n country: z.string().min(1).max(MAX_ARTISAN_LOCATION_LENGTH),\n region: z.string().max(MAX_ARTISAN_LOCATION_LENGTH).optional(),\n requestedAt: z.number(),\n })\n .optional(),\n squareStreetzAgreementsDate: z.number().optional(),\n // The rules-and-agreements `version` in force when the user accepted; 0 when no versioned\n // rules doc existed yet, so a later real version 1 still re-prompts.\n squareStreetzAgreementsVersion: PublicDocumentVersionOrNoneSchema.optional(),\n // The rules-and-agreements version in force when the user accepted the Artisan upgrade's\n // agreement, read server-side in the grant transaction (the grant time is the profile's\n // `artisanCreator` stamp). Same 0 sentinel as `squareStreetzAgreementsVersion`.\n artisanCreatorAgreementsVersion: PublicDocumentVersionOrNoneSchema.optional(),\n // Epoch ms when the user accepted the one-time Hall download acknowledgement\n // (personal offline use only, no redistribution). Written server-side by the\n // acceptHallDownloadAcknowledgement callable; gates the Hall download button.\n hallDownloadAcknowledgedAt: z.number().optional(),\n agreements: UserAgreementsSchema.optional(),\n // The latest accepted version of each public document and the accepted level (see\n // PublicDocumentAcceptanceSchema). Written by registration and the acceptance callable only;\n // the `docsAccepted` claim mirrors `acceptedLevel`. Absent = nothing accepted (level 0).\n publicDocumentAcceptance: PublicDocumentAcceptanceSchema.optional(),\n // First-visit site-tour state (account-durable; the SOLE authority for tour\n // eligibility — no local-storage cache/mirror). Absent = never handled. Written only\n // by the updateSiteTourPreference callable. See UserSiteTourStateSchema above.\n siteTour: UserSiteTourStateSchema.optional(),\n // Moderation: human-readable reason for the current account status (set when an\n // admin suspends/bans the user). Written by the setUserStatus callable via the\n // Admin SDK; readable only by the owner (shown in their restricted view).\n // Cleared when the account is reinstated to 'active'.\n statusReason: z.string().optional(),\n statusReasonAt: z.number().optional(),\n // Trust & Safety (§A8): silent interim safety-lock flag. Backend-only-writable,\n // restricted to the owner's view. Set true while a child-safety/NCII action is\n // pending against the account; the app gates the user accordingly.\n safetyLocked: z.boolean().optional(),\n // Epoch ms when the orphan-registration cleanup decided to delete this uid's login. Written in the\n // cleanup's eligibility transaction BEFORE the Auth delete, and every registration step refuses in\n // its own transaction while it is present, so no registration can complete into a login that is\n // about to be deleted. Backend-only.\n orphanDeletionClaimedAt: z.number().int().nonnegative().optional(),\n // Counts the owner's Craft publishes and deletes. Each one reads this doc and writes the next\n // value inside its own transaction, so two publishes that both counted a free Craft slot write\n // the same document and conflict instead of both landing past the cap (BACKEND-116). Absent\n // until the first Craft change (read as 0); a moderation hide never writes it.\n craftSkillChangeMarker: z.number().int().nonnegative().optional(),\n // Trust & Safety (§A7): server-write-only age/registration fields, merged from the\n // standalone age cluster shape (./safety/age.js) so the canonical schema and the\n // age cluster cannot drift.\n ...userPrivateDataAgeFieldsShape,\n});\nexport type UserPrivateData = z.infer<typeof UserPrivateDataSchema>;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttt-productions/ttt-core",
|
|
3
|
-
"version": "0.79.
|
|
3
|
+
"version": "0.79.85",
|
|
4
4
|
"description": "Core types, Firestore path constants, and shared constants for TTT Productions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -114,12 +114,12 @@
|
|
|
114
114
|
},
|
|
115
115
|
"dependencies": {
|
|
116
116
|
"@ttt-productions/audit-core": "^0.7.2",
|
|
117
|
-
"@ttt-productions/chat-schemas": "^0.10.
|
|
117
|
+
"@ttt-productions/chat-schemas": "^0.10.6",
|
|
118
118
|
"@ttt-productions/edge-protocol-core": "^0.1.12",
|
|
119
119
|
"@ttt-productions/input-format-core": "^0.1.1",
|
|
120
|
-
"@ttt-productions/media-schemas": "^0.14.
|
|
121
|
-
"@ttt-productions/notification-core": "^0.15.
|
|
122
|
-
"@ttt-productions/report-core": "^0.16.
|
|
120
|
+
"@ttt-productions/media-schemas": "^0.14.10",
|
|
121
|
+
"@ttt-productions/notification-core": "^0.15.16",
|
|
122
|
+
"@ttt-productions/report-core": "^0.16.17",
|
|
123
123
|
"zod": "^4.4.3"
|
|
124
124
|
},
|
|
125
125
|
"author": "DJ (TTT Productions)",
|